Skip to content

Commit cc6c3ff

Browse files
committed
Add networking options for vde_vmnet support
Signed-off-by: Jan Dubois <[email protected]>
1 parent 89202b5 commit cc6c3ff

File tree

4 files changed

+72
-3
lines changed

4 files changed

+72
-3
lines changed

pkg/limayaml/default.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ memory: "4GiB"
3131
# Default: "100GiB"
3232
disk: "100GiB"
3333

34+
network:
35+
# The instance can get a routable IP address from the vmnet framework using
36+
# https://github.com/AkihiroSuda/vde_vmnet. Both vde_switch and vde_vmnet
37+
# daemons must be running before the instance is started. The interface type
38+
# (host, shared, or bridged) is configured in vde_vmnet and not lima.
39+
vde:
40+
# vde_switch socket directory, normally /var/run/vde.ctl
41+
# Default: "" (vmnet is not being used)
42+
url: ""
43+
# MAC address of the instance; lima will pick one based on the instance name,
44+
# so DHCP assigned ip addresses should remain constant over instance restarts.
45+
macAddress: ""
46+
3447
# Expose host directories to the guest
3548
# Default: none
3649
mounts:

pkg/limayaml/limayaml.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type LimaYAML struct {
2020
Containerd Containerd `yaml:"containerd,omitempty"`
2121
Probes []Probe `yaml:"probes,omitempty"`
2222
PortForwards []PortForward `yaml:"portForwards,omitempty"`
23+
Network Network `yaml:"network,omitempty"`
2324
}
2425

2526
type Arch = string
@@ -105,3 +106,11 @@ type PortForward struct {
105106
Proto Proto `yaml:"proto,omitempty"`
106107
Ignore bool `yaml:"ignore,omitempty"`
107108
}
109+
110+
type Network struct {
111+
VDE VDE `yaml:"vde,omitempty"`
112+
}
113+
type VDE struct {
114+
URL string `yaml:"url,omitempty"`
115+
MACAddress string `yaml:"macAddress,omitempty"`
116+
}

pkg/limayaml/validate.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package limayaml
22

33
import (
44
"fmt"
5+
"net"
56
"os"
67
"os/user"
78
"path/filepath"
@@ -163,6 +164,35 @@ func ValidateRaw(y LimaYAML) error {
163164
// Not validating that the various GuestPortRanges and HostPortRanges are not overlapping. Rules will be
164165
// processed sequentially and the first matching rule for a guest port determines forwarding behavior.
165166
}
167+
if y.Network.VDE.URL != "" {
168+
fieldRef := "field `network.vde.url`"
169+
// The field is called VDE.URL in anticipation of QEMU upgrading VDE2 to VDEplug4,
170+
// but right now the only valid value is a path to the vde_switch socket directory.
171+
fi, err := os.Stat(y.Network.VDE.URL)
172+
if err != nil {
173+
return errors.Wrapf(err, "%s %q failed stat", fieldRef, y.Network.VDE.URL)
174+
}
175+
if !fi.IsDir() {
176+
return errors.Wrapf(err, "%s %q is not a directory", fieldRef, y.Network.VDE.URL)
177+
}
178+
ctlSocket := filepath.Join(y.Network.VDE.URL, "ctl")
179+
fi, err = os.Stat(ctlSocket)
180+
if err != nil {
181+
return errors.Wrapf(err, "%s control socket %q failed stat", fieldRef, ctlSocket)
182+
}
183+
if fi.Mode() & os.ModeSocket == 0 {
184+
return errors.Errorf("%s file %q is not a UNIX socket", fieldRef, ctlSocket)
185+
}
186+
}
187+
if y.Network.VDE.MACAddress != "" {
188+
hw, err := net.ParseMAC(y.Network.VDE.MACAddress)
189+
if err != nil {
190+
return errors.Wrap(err,"field `vmnet.mac` invalid")
191+
}
192+
if len(hw) != 6 {
193+
return errors.Errorf("field `vmnet.mac` must be a 48 bit (6 bytes) MAC address; actual length of %q is %d bytes", y.Network.VDE.MACAddress, len(hw))
194+
}
195+
}
166196
return nil
167197
}
168198

pkg/qemu/qemu.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package qemu
22

33
import (
4+
"crypto/sha256"
45
"fmt"
6+
"net"
57
"os"
68
"os/exec"
79
"path/filepath"
@@ -131,6 +133,18 @@ func appendArgsIfNoConflict(args []string, k, v string) []string {
131133
return append(args, k, v)
132134
}
133135

136+
func macAddress(cfg Config) string {
137+
addr := cfg.LimaYAML.Network.VDE.MACAddress
138+
if addr == "" {
139+
sha := sha256.Sum256([]byte(cfg.InstanceDir))
140+
// According to https://gitlab.com/wireshark/wireshark/-/blob/master/manuf
141+
// no well-known MAC addresses start with 0x22.
142+
hw := append(net.HardwareAddr{0x22}, sha[0:5]...)
143+
addr = hw.String()
144+
}
145+
return addr
146+
}
147+
134148
func Cmdline(cfg Config) (string, []string, error) {
135149
y := cfg.LimaYAML
136150
exe, args, err := getExe(y.Arch)
@@ -194,10 +208,13 @@ func Cmdline(cfg Config) (string, []string, error) {
194208
args = append(args, "-cdrom", filepath.Join(cfg.InstanceDir, filenames.CIDataISO))
195209

196210
// Network
211+
if y.Network.VDE.URL != "" {
212+
args = append(args, "-device", fmt.Sprintf("virtio-net-pci,netdev=net0,mac=%s", macAddress(cfg)))
213+
args = append(args, "-netdev", fmt.Sprintf("vde,id=net0,sock=%s", y.Network.VDE.URL))
214+
}
197215
// CIDR is intentionally hardcoded to 192.168.5.0/24, as each of QEMU has its own independent slirp network.
198-
// TODO: enable bridge (with sudo?)
199-
args = append(args, "-net", "nic,model=virtio")
200-
args = append(args, "-net", fmt.Sprintf("user,net=192.168.5.0/24,hostfwd=tcp:127.0.0.1:%d-:22", y.SSH.LocalPort))
216+
args = append(args, "-device", "virtio-net-pci,netdev=net1")
217+
args = append(args, "-netdev", fmt.Sprintf("user,id=net1,net=192.168.5.0/24,hostfwd=tcp:127.0.0.1:%d-:22", y.SSH.LocalPort))
201218

202219
// virtio-rng-pci acceralates starting up the OS, according to https://wiki.gentoo.org/wiki/QEMU/Options
203220
args = append(args, "-device", "virtio-rng-pci")

0 commit comments

Comments
 (0)