Skip to content

Commit 336c669

Browse files
authored
Merge pull request #1626 from balajiv113/subnet-user-v2
Support for configurable network address for user-v2
2 parents 7977464 + fd62a15 commit 336c669

20 files changed

+592
-89
lines changed

cmd/limactl/usernet.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func newUsernetCommand() *cobra.Command {
2222
hostagentCommand.Flags().StringP("endpoint", "e", "", "exposes usernet api(s) on this endpoint")
2323
hostagentCommand.Flags().String("listen-qemu", "", "listen for qemu connections")
2424
hostagentCommand.Flags().String("listen", "", "listen on a Unix socket and receive Bess-compatible FDs as SCM_RIGHTS messages")
25+
hostagentCommand.Flags().String("subnet", "192.168.5.0/24", "sets subnet value for the usernet network")
2526
hostagentCommand.Flags().Int("mtu", 1500, "mtu")
2627
return hostagentCommand
2728
}
@@ -52,6 +53,10 @@ func usernetAction(cmd *cobra.Command, _ []string) error {
5253
if err != nil {
5354
return err
5455
}
56+
subnet, err := cmd.Flags().GetString("subnet")
57+
if err != nil {
58+
return err
59+
}
5560

5661
mtu, err := cmd.Flags().GetInt("mtu")
5762
if err != nil {
@@ -67,5 +72,6 @@ func usernetAction(cmd *cobra.Command, _ []string) error {
6772
Endpoint: endpoint,
6873
QemuSocket: qemuSocket,
6974
FdSocket: fdSocket,
75+
Subnet: subnet,
7076
})
7177
}

examples/experimental/net-user-v2.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ images:
66
- location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img"
77
arch: "aarch64"
88

9+
hostResolver:
10+
hosts:
11+
host.docker.internal: host.lima.internal
912
mounts:
1013
- location: "~"
1114
- location: "/tmp/lima"

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/AlecAivazis/survey/v2 v2.3.7
77
github.com/Code-Hex/vz/v3 v3.0.6
88
github.com/alessio/shellescape v1.4.2
9+
github.com/apparentlymart/go-cidr v1.1.0
910
github.com/balajiv113/fd v0.0.0-20230330094840-143eec500f3e
1011
github.com/cheggaaa/pb/v3 v3.1.4
1112
github.com/containerd/containerd v1.7.5
@@ -54,7 +55,6 @@ require (
5455
github.com/VividCortex/ewma v1.2.0 // indirect
5556
github.com/a8m/envsubst v1.4.2 // indirect
5657
github.com/alecthomas/participle/v2 v2.0.0 // indirect
57-
github.com/apparentlymart/go-cidr v1.1.0 // indirect
5858
github.com/davecgh/go-spew v1.1.1 // indirect
5959
github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e // indirect
6060
github.com/dimchansky/utfbom v1.1.1 // indirect

hack/test-templates.sh

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ INFO "Testing proxy settings are imported"
129129
got=$(limactl shell "$NAME" env | grep FTP_PROXY)
130130
# Expected: FTP_PROXY is set in addition to ftp_proxy, localhost is replaced
131131
# by the gateway address, and the value is set immediately without a restart
132-
expected="FTP_PROXY=http://192.168.5.2:2121"
132+
gatewayIp=$(limactl shell "$NAME" ip route show 0.0.0.0/0 dev eth0 | cut -d\ -f3)
133+
expected="FTP_PROXY=http://${gatewayIp}:2121"
133134
INFO "FTP_PROXY: expected=${expected} got=${got}"
134135
if [ "$got" != "$expected" ]; then
135136
ERROR "proxy environment variable not set to correct value"
@@ -331,10 +332,10 @@ if [[ -n ${CHECKS["user-v2"]} ]]; then
331332
secondvm="$NAME-1"
332333
"${LIMACTL_CREATE[@]}" "$FILE" --name "$secondvm"
333334
limactl start "$secondvm"
334-
guestNewip="$(limactl shell "$secondvm" ip -4 -j addr show dev eth0 | jq -r '.[0].addr_info[0].local')"
335-
INFO "IP of $secondvm is $guestNewip"
335+
secondvmDNS="lima-$secondvm.internal"
336+
INFO "DNS of $secondvm is $secondvmDNS"
336337
set -x
337-
if ! limactl shell "$NAME" ping -c 1 "$guestNewip"; then
338+
if ! limactl shell "$NAME" ping -c 1 "$secondvmDNS"; then
338339
ERROR "Failed to do vm->vm communication via user-v2"
339340
INFO "Stopping \"$secondvm\""
340341
limactl stop "$secondvm"

pkg/cidata/cidata.TEMPLATE.d/boot/09-host-dns-setup.sh

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ if command -v iptables >/dev/null 2>&1; then
1818
# Remove old rules
1919
iptables --table nat --flush ${chain}
2020
# Add rules for the existing ip:port
21-
iptables --table nat --append "${chain}" --destination "${LIMA_CIDATA_SLIRP_DNS}" --protocol udp --dport 53 --jump DNAT \
22-
--to-destination "${LIMA_CIDATA_SLIRP_GATEWAY}:${LIMA_CIDATA_UDP_DNS_LOCAL_PORT}"
23-
iptables --table nat --append "${chain}" --destination "${LIMA_CIDATA_SLIRP_DNS}" --protocol tcp --dport 53 --jump DNAT \
24-
--to-destination "${LIMA_CIDATA_SLIRP_GATEWAY}:${LIMA_CIDATA_TCP_DNS_LOCAL_PORT}"
21+
if [ -n "${LIMA_CIDATA_UDP_DNS_LOCAL_PORT}" ] && [ "${LIMA_CIDATA_UDP_DNS_LOCAL_PORT}" -ne 0 ]; then
22+
iptables --table nat --append "${chain}" --destination "${LIMA_CIDATA_SLIRP_DNS}" --protocol udp --dport 53 --jump DNAT \
23+
--to-destination "${LIMA_CIDATA_SLIRP_GATEWAY}:${LIMA_CIDATA_UDP_DNS_LOCAL_PORT}"
24+
fi
25+
if [ -n "${LIMA_CIDATA_TCP_DNS_LOCAL_PORT}" ] && [ "${LIMA_CIDATA_TCP_DNS_LOCAL_PORT}" -ne 0 ]; then
26+
iptables --table nat --append "${chain}" --destination "${LIMA_CIDATA_SLIRP_DNS}" --protocol tcp --dport 53 --jump DNAT \
27+
--to-destination "${LIMA_CIDATA_SLIRP_GATEWAY}:${LIMA_CIDATA_TCP_DNS_LOCAL_PORT}"
28+
fi
2529
fi

pkg/cidata/cidata.go

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ import (
1212
"strings"
1313
"time"
1414

15-
"github.com/lima-vm/lima/pkg/networks"
16-
1715
"github.com/docker/go-units"
1816
"github.com/lima-vm/lima/pkg/iso9660util"
1917
"github.com/lima-vm/lima/pkg/limayaml"
2018
"github.com/lima-vm/lima/pkg/localpathutil"
19+
"github.com/lima-vm/lima/pkg/networks"
20+
"github.com/lima-vm/lima/pkg/networks/usernet"
2121
"github.com/lima-vm/lima/pkg/osutil"
2222
"github.com/lima-vm/lima/pkg/sshutil"
2323
"github.com/lima-vm/lima/pkg/store/filenames"
@@ -35,7 +35,7 @@ var netLookupIP = func(host string) []net.IP {
3535
return ips
3636
}
3737

38-
func setupEnv(y *limayaml.LimaYAML) (map[string]string, error) {
38+
func setupEnv(y *limayaml.LimaYAML, args TemplateArgs) (map[string]string, error) {
3939
// Start with the proxy variables from the system settings.
4040
env, err := osutil.ProxySettings()
4141
if err != nil {
@@ -74,7 +74,7 @@ func setupEnv(y *limayaml.LimaYAML) (map[string]string, error) {
7474

7575
for _, ip := range netLookupIP(u.Hostname()) {
7676
if ip.IsLoopback() {
77-
newHost := networks.SlirpGateway
77+
newHost := args.SlirpGateway
7878
if u.Port() != "" {
7979
newHost = net.JoinHostPort(newHost, u.Port())
8080
}
@@ -125,11 +125,34 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort
125125
GuestInstallPrefix: *y.GuestInstallPrefix,
126126
Containerd: Containerd{System: *y.Containerd.System, User: *y.Containerd.User},
127127
SlirpNICName: networks.SlirpNICName,
128-
SlirpGateway: networks.SlirpGateway,
129-
SlirpDNS: networks.SlirpDNS,
130-
SlirpIPAddress: networks.SlirpIPAddress,
131-
RosettaEnabled: *y.Rosetta.Enabled,
132-
RosettaBinFmt: *y.Rosetta.BinFmt,
128+
129+
RosettaEnabled: *y.Rosetta.Enabled,
130+
RosettaBinFmt: *y.Rosetta.BinFmt,
131+
}
132+
133+
firstUsernetIndex := limayaml.FirstUsernetIndex(y)
134+
var subnet net.IP
135+
136+
if firstUsernetIndex != -1 {
137+
usernetName := y.Networks[firstUsernetIndex].Lima
138+
subnet, err = usernet.Subnet(usernetName)
139+
if err != nil {
140+
return err
141+
}
142+
args.SlirpGateway = usernet.GatewayIP(subnet)
143+
args.SlirpDNS = usernet.GatewayIP(subnet)
144+
} else {
145+
subnet, err = usernet.ParseSubnet(networks.SlirpNetwork)
146+
if err != nil {
147+
return err
148+
}
149+
args.SlirpGateway = usernet.GatewayIP(subnet)
150+
if *y.VMType == limayaml.VZ {
151+
args.SlirpDNS = usernet.GatewayIP(subnet)
152+
} else {
153+
args.SlirpDNS = usernet.DNSIP(subnet)
154+
}
155+
args.SlirpIPAddress = networks.SlirpIPAddress
133156
}
134157

135158
// change instance id on every boot so network config will be processed again
@@ -222,24 +245,24 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort
222245
})
223246
}
224247

225-
slirpMACAddress := limayaml.MACAddress(instDir)
226-
args.Networks = append(args.Networks, Network{MACAddress: slirpMACAddress, Interface: networks.SlirpNICName})
227-
firstUsernetIndex := limayaml.FirstUsernetIndex(y)
248+
args.Networks = append(args.Networks, Network{MACAddress: limayaml.MACAddress(instDir), Interface: networks.SlirpNICName})
228249
for i, nw := range y.Networks {
229250
if i == firstUsernetIndex {
230251
continue
231252
}
232253
args.Networks = append(args.Networks, Network{MACAddress: nw.MACAddress, Interface: nw.Interface})
233254
}
234255

235-
args.Env, err = setupEnv(y)
256+
args.Env, err = setupEnv(y, args)
236257
if err != nil {
237258
return err
238259
}
239-
if *y.HostResolver.Enabled {
260+
if firstUsernetIndex != -1 || *y.VMType == limayaml.VZ {
261+
args.DNSAddresses = append(args.DNSAddresses, args.SlirpDNS)
262+
} else if *y.HostResolver.Enabled {
240263
args.UDPDNSLocalPort = udpDNSLocalPort
241264
args.TCPDNSLocalPort = tcpDNSLocalPort
242-
args.DNSAddresses = append(args.DNSAddresses, networks.SlirpDNS)
265+
args.DNSAddresses = append(args.DNSAddresses, args.SlirpDNS)
243266
} else if len(y.DNS) > 0 {
244267
for _, addr := range y.DNS {
245268
args.DNSAddresses = append(args.DNSAddresses, addr.String())

pkg/cidata/cidata_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ func TestSetupEnv(t *testing.T) {
4848
t.Run(httpProxy.Host, func(t *testing.T) {
4949
envKey := "http_proxy"
5050
envValue := httpProxy.String()
51-
envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}})
51+
templateArgs := TemplateArgs{SlirpGateway: networks.SlirpGateway}
52+
envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}}, templateArgs)
5253
assert.NilError(t, err)
5354
assert.Equal(t, envs[envKey], strings.ReplaceAll(envValue, httpProxy.Hostname(), networks.SlirpGateway))
5455
})
@@ -58,7 +59,8 @@ func TestSetupEnv(t *testing.T) {
5859
func TestSetupInvalidEnv(t *testing.T) {
5960
envKey := "http_proxy"
6061
envValue := "://localhost:8080"
61-
envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}})
62+
templateArgs := TemplateArgs{SlirpGateway: networks.SlirpGateway}
63+
envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}}, templateArgs)
6264
assert.NilError(t, err)
6365
assert.Equal(t, envs[envKey], envValue)
6466
}

pkg/hostagent/hostagent.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ func (a *HostAgent) Run(ctx context.Context) error {
266266
a.emitEvent(ctx, exitingEv)
267267
}()
268268

269-
if *a.y.HostResolver.Enabled {
269+
firstUsernetIndex := limayaml.FirstUsernetIndex(a.y)
270+
if firstUsernetIndex == -1 && *a.y.HostResolver.Enabled {
270271
hosts := a.y.HostResolver.Hosts
271272
hosts["host.lima.internal"] = networks.SlirpGateway
272273
hosts[fmt.Sprintf("lima-%s", a.instName)] = networks.SlirpIPAddress

pkg/networks/config_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func TestFillDefault(t *testing.T) {
1515
userNet := newYaml.Networks[ModeUserV2]
1616
assert.Equal(t, userNet.Mode, ModeUserV2)
1717
assert.Equal(t, userNet.Interface, "")
18-
assert.DeepEqual(t, userNet.NetMask, net.IP{})
19-
assert.DeepEqual(t, userNet.Gateway, net.IP{})
18+
assert.DeepEqual(t, userNet.NetMask, net.ParseIP("255.255.255.0"))
19+
assert.DeepEqual(t, userNet.Gateway, net.ParseIP("192.168.104.1"))
2020
assert.DeepEqual(t, userNet.DHCPEnd, net.IP{})
2121
}

pkg/networks/const.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@ const (
55
// CIDR is intentionally hardcoded to 192.168.5.0/24, as each of QEMU has its own independent slirp network.
66
SlirpNetwork = "192.168.5.0/24"
77
SlirpGateway = "192.168.5.2"
8-
SlirpDNS = "192.168.5.3"
98
SlirpIPAddress = "192.168.5.15"
109
)

pkg/networks/networks.TEMPLATE.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ group: everyone
2424
networks:
2525
user-v2:
2626
mode: user-v2
27+
gateway: 192.168.104.1
28+
netmask: 255.255.255.0
2729
# user-v2 network is experimental network mode which supports all functionalities of default usernet network and also allows vm -> vm communication.
2830
# Doesn't support configuration of custom gateway; hardcoded to 192.168.5.0/24
2931
shared:

pkg/networks/usernet/client.go

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ import (
1111

1212
gvproxyclient "github.com/containers/gvisor-tap-vsock/pkg/client"
1313
"github.com/containers/gvisor-tap-vsock/pkg/types"
14+
"github.com/lima-vm/lima/pkg/driver"
15+
"github.com/lima-vm/lima/pkg/limayaml"
16+
"github.com/lima-vm/lima/pkg/networks/usernet/dnshosts"
1417
)
1518

1619
type Client struct {
@@ -19,6 +22,23 @@ type Client struct {
1922
client *http.Client
2023
delegate *gvproxyclient.Client
2124
base string
25+
subnet net.IP
26+
}
27+
28+
func (c *Client) ConfigureDriver(driver *driver.BaseDriver) error {
29+
macAddress := limayaml.MACAddress(driver.Instance.Dir)
30+
ipAddress, err := c.ResolveIPAddress(macAddress)
31+
if err != nil {
32+
return err
33+
}
34+
err = c.ResolveAndForwardSSH(ipAddress, driver.SSHLocalPort)
35+
if err != nil {
36+
return err
37+
}
38+
var hosts = driver.Yaml.HostResolver.Hosts
39+
hosts[fmt.Sprintf("lima-%s.internal", driver.Instance.Name)] = ipAddress
40+
err = c.AddDNSHosts(hosts)
41+
return err
2242
}
2343

2444
func (c *Client) UnExposeSSH(sshPort int) error {
@@ -28,30 +48,46 @@ func (c *Client) UnExposeSSH(sshPort int) error {
2848
})
2949
}
3050

31-
func (c *Client) ResolveAndForwardSSH(vmMacAddr string, sshPort int) error {
51+
func (c *Client) AddDNSHosts(hosts map[string]string) error {
52+
hosts["host.lima.internal"] = GatewayIP(c.subnet)
53+
zones := dnshosts.ExtractZones(hosts)
54+
for _, zone := range zones {
55+
err := c.delegate.AddDNS(&zone)
56+
if err != nil {
57+
return err
58+
}
59+
}
60+
return nil
61+
}
62+
63+
func (c *Client) ResolveAndForwardSSH(ipAddr string, sshPort int) error {
64+
err := c.delegate.Expose(&types.ExposeRequest{
65+
Local: fmt.Sprintf("127.0.0.1:%d", sshPort),
66+
Remote: fmt.Sprintf("%s:22", ipAddr),
67+
Protocol: "tcp",
68+
})
69+
if err != nil {
70+
return err
71+
}
72+
return nil
73+
}
74+
75+
func (c *Client) ResolveIPAddress(vmMacAddr string) (string, error) {
3276
timeout := time.After(2 * time.Minute)
3377
ticker := time.NewTicker(500 * time.Millisecond)
3478
for {
3579
select {
3680
case <-timeout:
37-
return errors.New("usernet unable to resolve IP for SSH forwarding")
81+
return "", errors.New("usernet unable to resolve IP for SSH forwarding")
3882
case <-ticker.C:
3983
leases, err := c.leases()
4084
if err != nil {
41-
return err
85+
return "", err
4286
}
4387

4488
for ipAddr, leaseAddr := range leases {
4589
if vmMacAddr == leaseAddr {
46-
err = c.delegate.Expose(&types.ExposeRequest{
47-
Local: fmt.Sprintf("127.0.0.1:%d", sshPort),
48-
Remote: fmt.Sprintf("%s:22", ipAddr),
49-
Protocol: "tcp",
50-
})
51-
if err != nil {
52-
return err
53-
}
54-
return nil
90+
return ipAddr, nil
5591
}
5692
}
5793
}
@@ -75,11 +111,11 @@ func (c *Client) leases() (map[string]string, error) {
75111
return leases, nil
76112
}
77113

78-
func NewClient(endpointSock string) *Client {
79-
return create(endpointSock, "http://lima")
114+
func NewClient(endpointSock string, subnet net.IP) *Client {
115+
return create(endpointSock, subnet, "http://lima")
80116
}
81117

82-
func create(sock string, base string) *Client {
118+
func create(sock string, subnet net.IP, base string) *Client {
83119
client := &http.Client{
84120
Transport: &http.Transport{
85121
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
@@ -92,5 +128,6 @@ func create(sock string, base string) *Client {
92128
client: client,
93129
delegate: delegate,
94130
base: base,
131+
subnet: subnet,
95132
}
96133
}

0 commit comments

Comments
 (0)