Skip to content

Commit b0ae1bc

Browse files
committed
Support for lima usernet network
Signed-off-by: Balaji Vijayakumar <[email protected]>
1 parent da0e698 commit b0ae1bc

25 files changed

+1074
-200
lines changed

cmd/limactl/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ func newApp() *cobra.Command {
100100
newEditCommand(),
101101
newFactoryResetCommand(),
102102
newDiskCommand(),
103+
newUsernetCommand(),
103104
)
104105
return rootCmd
105106
}

cmd/limactl/usernet.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"os"
7+
"strconv"
8+
9+
"github.com/lima-vm/lima/pkg/networks/usernet"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
func newUsernetCommand() *cobra.Command {
14+
var hostagentCommand = &cobra.Command{
15+
Use: "usernet",
16+
Short: "run usernet",
17+
Args: cobra.ExactArgs(0),
18+
RunE: usernetAction,
19+
Hidden: true,
20+
}
21+
hostagentCommand.Flags().StringP("pidfile", "p", "", "write pid to file")
22+
hostagentCommand.Flags().StringP("endpoint", "e", "", "exposes usernet api(s) on this endpoint")
23+
hostagentCommand.Flags().String("listen-qemu", "", "listen for qemu connections")
24+
hostagentCommand.Flags().String("listen-fd", "", "listen for fd connections")
25+
hostagentCommand.Flags().Int("mtu", 1500, "mtu")
26+
return hostagentCommand
27+
}
28+
29+
func usernetAction(cmd *cobra.Command, args []string) error {
30+
31+
pidfile, err := cmd.Flags().GetString("pidfile")
32+
if err != nil {
33+
return err
34+
}
35+
if pidfile != "" {
36+
if _, err := os.Stat(pidfile); !errors.Is(err, os.ErrNotExist) {
37+
return fmt.Errorf("pidfile %q already exists", pidfile)
38+
}
39+
if err := os.WriteFile(pidfile, []byte(strconv.Itoa(os.Getpid())+"\n"), 0644); err != nil {
40+
return err
41+
}
42+
defer os.RemoveAll(pidfile)
43+
}
44+
endpoint, err := cmd.Flags().GetString("endpoint")
45+
if err != nil {
46+
return err
47+
}
48+
qemuSocket, err := cmd.Flags().GetString("listen-qemu")
49+
if err != nil {
50+
return err
51+
}
52+
fdSocket, err := cmd.Flags().GetString("listen-fd")
53+
if err != nil {
54+
return err
55+
}
56+
57+
mtu, err := cmd.Flags().GetInt("mtu")
58+
if err != nil {
59+
return err
60+
}
61+
62+
os.RemoveAll(endpoint)
63+
os.RemoveAll(qemuSocket)
64+
os.RemoveAll(fdSocket)
65+
66+
return usernet.StartGVisorNetstack(cmd.Context(), &usernet.GVisorNetstackOpts{
67+
MTU: mtu,
68+
Endpoint: endpoint,
69+
QemuSocket: qemuSocket,
70+
FdSocket: fdSocket,
71+
})
72+
}

examples/experimental/usernet.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Example to run vz instance with lima usernet enabled
2+
vmType: "vz"
3+
images:
4+
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img"
5+
arch: "x86_64"
6+
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"
7+
arch: "aarch64"
8+
9+
mounts:
10+
- location: "~"
11+
- location: "/tmp/lima"
12+
writable: true
13+
mountType: "virtiofs"
14+
networks:
15+
- lima: default

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
github.com/cheggaaa/pb/v3 v3.1.2
1010
github.com/containerd/containerd v1.6.19
1111
github.com/containerd/continuity v0.3.0
12-
github.com/containers/gvisor-tap-vsock v0.5.0
12+
github.com/containers/gvisor-tap-vsock v0.5.1-0.20230220110902-2732d3a55dc7
1313
github.com/coreos/go-semver v0.3.1
1414
github.com/cyphar/filepath-securejoin v0.2.3
1515
github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001
@@ -78,10 +78,13 @@ require (
7878
github.com/json-iterator/go v1.1.12 // indirect
7979
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
8080
github.com/kr/fs v0.1.0 // indirect
81+
github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 // indirect
8182
github.com/magiconair/properties v1.8.7 // indirect
8283
github.com/mailru/easyjson v0.7.6 // indirect
8384
github.com/mattn/go-colorable v0.1.13 // indirect
8485
github.com/mattn/go-runewidth v0.0.12 // indirect
86+
github.com/mdlayher/socket v0.4.0 // indirect
87+
github.com/mdlayher/vsock v1.2.0 // indirect
8588
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
8689
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
8790
github.com/modern-go/reflect2 v1.0.2 // indirect

go.sum

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDG
111111
github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
112112
github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
113113
github.com/containerd/typeurl v0.0.0-20200205145503-b45ef1f1f737/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
114-
github.com/containers/gvisor-tap-vsock v0.5.0 h1:hoCkrfQ96tjek2BtiW1BHy50zAQCzkqeiAQY96y6NLk=
115-
github.com/containers/gvisor-tap-vsock v0.5.0/go.mod h1:jrnI5plQtmys5LEKpXcCCrLqZlrHsozQg0V2Jw1UG74=
114+
github.com/containers/gvisor-tap-vsock v0.5.1-0.20230220110902-2732d3a55dc7 h1:Ej2OTGLHMjcpnGApet9gmEfboe9aTT2eU/civ1Imm6g=
115+
github.com/containers/gvisor-tap-vsock v0.5.1-0.20230220110902-2732d3a55dc7/go.mod h1:RfDVvmr+DHvp6whJVEwrMn+hfTYIPLWlUPJhWXNUsCM=
116116
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
117117
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
118118
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -376,6 +376,8 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
376376
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
377377
github.com/lima-vm/sshocker v0.3.2 h1:o0WqVzcpt6mzVCuqtS3N3O8kwTx6X4SLr4h7YaRISuE=
378378
github.com/lima-vm/sshocker v0.3.2/go.mod h1:9SWN6wob210VM6oJkkzvWQOlHSp/rQLB+0fSEc92zig=
379+
github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 h1:DZMFueDbfz6PNc1GwDRA8+6lBx1TB9UnxDQliCqR73Y=
380+
github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2/go.mod h1:SWzULI85WerrFt3u+nIm5F9l7EvxZTKQvd0InF3nmgM=
379381
github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
380382
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
381383
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -409,6 +411,10 @@ github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZ
409411
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
410412
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 h1:aFkJ6lx4FPip+S+Uw4aTegFMct9shDvP+79PsSxpm3w=
411413
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
414+
github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw=
415+
github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc=
416+
github.com/mdlayher/vsock v1.2.0 h1:klRY9lndjmg6k/QWbX/ucQ3e2JFRm1M7vfG9hijbQ0A=
417+
github.com/mdlayher/vsock v1.2.0/go.mod h1:w4kdSTQB9p1l/WwGmAs0V62qQ869qRYoongwgN+Y1HE=
412418
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
413419
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
414420
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
@@ -444,7 +450,7 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
444450
github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs=
445451
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
446452
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
447-
github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE=
453+
github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=
448454
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
449455
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
450456
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=

pkg/cidata/cidata.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,11 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort
211211

212212
slirpMACAddress := limayaml.MACAddress(instDir)
213213
args.Networks = append(args.Networks, Network{MACAddress: slirpMACAddress, Interface: networks.SlirpNICName})
214-
for _, nw := range y.Networks {
214+
firstUsernetIndex := limayaml.GetFirstUsernetIndex(y)
215+
for i, nw := range y.Networks {
216+
if i == firstUsernetIndex {
217+
continue
218+
}
215219
args.Networks = append(args.Networks, Network{MACAddress: nw.MACAddress, Interface: nw.Interface})
216220
}
217221

pkg/fd/fd.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//go:build !windows
2+
// +build !windows
3+
4+
// This file has been adapted from https://github.com/ftrvxmtrx/fd/blob/master/fd.go
5+
6+
// Package fd provides a simple API to pass file descriptors
7+
// between different OS processes.
8+
//
9+
// It can be useful if you want to inherit network connections
10+
// from another process without closing them.
11+
//
12+
// Example scenario:
13+
//
14+
// 1. Running server receives a "let's upgrade" message
15+
// 2. Server opens a Unix domain socket for the "upgrade"
16+
// 3. Server starts a new copy of itself and passes Unix domain socket name
17+
// 4. New copy starts reading for the socket
18+
// 5. Server sends its state over the socket, also sending the number
19+
// of network connections to inherit, then it sends those connections
20+
// using fd.Put()
21+
// 6. New copy reads the state and inherits connections using fd.Get(),
22+
// checks that everything is OK and sends the "OK" message to the socket
23+
// 7. Server receives "OK" message and kills itself
24+
package fd
25+
26+
import (
27+
"net"
28+
"os"
29+
"syscall"
30+
)
31+
32+
// Get receives single file descriptors from a Unix domain socket.
33+
//
34+
// Num specifies the expected number of file descriptors in one message.
35+
// Internal files' names to be assigned are specified via optional filenames
36+
// argument.
37+
//
38+
// You need to close all files in the returned slice. The slice can be
39+
// non-empty even if this function returns an error.
40+
//
41+
// Use net.FileConn() if you're receiving a network connection.
42+
func Get(via *net.UnixConn, num int, filenames []string) ([]*os.File, error) {
43+
if num < 1 {
44+
return nil, nil
45+
}
46+
47+
// get the underlying socket
48+
viaf, err := via.File()
49+
if err != nil {
50+
return nil, err
51+
}
52+
socket := int(viaf.Fd())
53+
defer viaf.Close()
54+
55+
// recvmsg
56+
buf := make([]byte, syscall.CmsgSpace(num*4))
57+
_, _, _, _, err = syscall.Recvmsg(socket, nil, buf, 0)
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
// parse control msgs
63+
var msgs []syscall.SocketControlMessage
64+
msgs, err = syscall.ParseSocketControlMessage(buf)
65+
66+
// convert fds to files
67+
res := make([]*os.File, 0, len(msgs))
68+
for i := 0; i < len(msgs) && err == nil; i++ {
69+
var fds []int
70+
fds, err = syscall.ParseUnixRights(&msgs[i])
71+
72+
for fi, fd := range fds {
73+
var filename string
74+
if fi < len(filenames) {
75+
filename = filenames[fi]
76+
}
77+
78+
res = append(res, os.NewFile(uintptr(fd), filename))
79+
}
80+
}
81+
82+
return res, err
83+
}
84+
85+
// Put sends file descriptors to Unix domain socket.
86+
//
87+
// Please note that the number of descriptors in one message is limited
88+
// and is rather small.
89+
// Use conn.File() to get a file if you want to put a network connection.
90+
func Put(via *net.UnixConn, files ...*os.File) error {
91+
if len(files) == 0 {
92+
return nil
93+
}
94+
95+
viaf, err := via.File()
96+
if err != nil {
97+
return err
98+
}
99+
socket := int(viaf.Fd())
100+
defer viaf.Close()
101+
102+
fds := make([]int, len(files))
103+
for i := range files {
104+
fds[i] = int(files[i].Fd())
105+
}
106+
107+
rights := syscall.UnixRights(fds...)
108+
return syscall.Sendmsg(socket, nil, rights, nil, 0)
109+
}

pkg/fd/fd_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//go:build linux && darwin
2+
// +build linux,darwin
3+
4+
// This file has been adapted from https://github.com/ftrvxmtrx/fd/blob/master/fd_test.go
5+
6+
package fd
7+
8+
import (
9+
"errors"
10+
"net"
11+
"os"
12+
"sync"
13+
"testing"
14+
)
15+
16+
var SockFilename = "/tmp/sendfd.sock"
17+
18+
func getFD(w *sync.WaitGroup) error {
19+
defer w.Done()
20+
21+
c, err := net.Dial("unix", SockFilename)
22+
if err != nil {
23+
return err
24+
}
25+
defer c.Close()
26+
sendfdConn := c.(*net.UnixConn)
27+
28+
var fs []*os.File
29+
fs, err = Get(sendfdConn, 1, []string{"a file"})
30+
if err != nil {
31+
return err
32+
}
33+
f := fs[0]
34+
defer f.Close()
35+
36+
b := make([]byte, 64)
37+
var n int
38+
n, err = f.Read(b)
39+
if err != nil {
40+
return err
41+
}
42+
43+
if n < 1 {
44+
return errors.New("failed to read the data")
45+
}
46+
return nil
47+
}
48+
49+
func TestPutGet(t *testing.T) {
50+
f, err := os.Open("/dev/urandom")
51+
if err != nil {
52+
t.Fatal(err)
53+
}
54+
defer f.Close()
55+
56+
os.Remove(SockFilename)
57+
l, err := net.Listen("unix", SockFilename)
58+
if err != nil {
59+
t.Fatal(err)
60+
}
61+
defer l.Close()
62+
63+
var w sync.WaitGroup
64+
w.Add(1)
65+
66+
go func() {
67+
err := getFD(&w)
68+
if err != nil {
69+
t.Error(err)
70+
}
71+
}()
72+
73+
var a net.Conn
74+
a, err = l.Accept()
75+
if err != nil {
76+
t.Fatal(err)
77+
}
78+
defer a.Close()
79+
80+
listenConn := a.(*net.UnixConn)
81+
82+
if err = Put(listenConn, f); err != nil {
83+
t.Fatal(err)
84+
}
85+
86+
w.Wait()
87+
}

pkg/fd/fd_windows.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package fd
5+
6+
import (
7+
"errors"
8+
"net"
9+
"os"
10+
)
11+
12+
func Get(via *net.UnixConn, num int, filenames []string) ([]*os.File, error) {
13+
return nil, errors.New("Not supported")
14+
}
15+
16+
func Put(via *net.UnixConn, files ...*os.File) error {
17+
return errors.New("Not supported")
18+
}

0 commit comments

Comments
 (0)