Skip to content

Commit c9f9d7c

Browse files
authored
Merge pull request #1801 from balajiv113/ip-user-v2
Support for deterministic ip for user-v2 network
2 parents 43720d3 + c0bce3e commit c9f9d7c

File tree

6 files changed

+107
-30
lines changed

6 files changed

+107
-30
lines changed

cmd/limactl/usernet.go

+12-5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func newUsernetCommand() *cobra.Command {
2424
hostagentCommand.Flags().String("listen", "", "listen on a Unix socket and receive Bess-compatible FDs as SCM_RIGHTS messages")
2525
hostagentCommand.Flags().String("subnet", "192.168.5.0/24", "sets subnet value for the usernet network")
2626
hostagentCommand.Flags().Int("mtu", 1500, "mtu")
27+
hostagentCommand.Flags().StringToString("leases", nil, "pass default static leases for startup. Eg: '192.168.104.1=52:55:55:b3:bc:d9,192.168.104.2=5a:94:ef:e4:0c:df' ")
2728
return hostagentCommand
2829
}
2930

@@ -58,6 +59,11 @@ func usernetAction(cmd *cobra.Command, _ []string) error {
5859
return err
5960
}
6061

62+
leases, err := cmd.Flags().GetStringToString("leases")
63+
if err != nil {
64+
return err
65+
}
66+
6167
mtu, err := cmd.Flags().GetInt("mtu")
6268
if err != nil {
6369
return err
@@ -68,10 +74,11 @@ func usernetAction(cmd *cobra.Command, _ []string) error {
6874
os.RemoveAll(fdSocket)
6975

7076
return usernet.StartGVisorNetstack(cmd.Context(), &usernet.GVisorNetstackOpts{
71-
MTU: mtu,
72-
Endpoint: endpoint,
73-
QemuSocket: qemuSocket,
74-
FdSocket: fdSocket,
75-
Subnet: subnet,
77+
MTU: mtu,
78+
Endpoint: endpoint,
79+
QemuSocket: qemuSocket,
80+
FdSocket: fdSocket,
81+
Subnet: subnet,
82+
DefaultLeases: leases,
7683
})
7784
}

pkg/networks/usernet/client.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ func (c *Client) ResolveIPAddress(vmMacAddr string) (string, error) {
8080
case <-timeout:
8181
return "", errors.New("usernet unable to resolve IP for SSH forwarding")
8282
case <-ticker.C:
83-
leases, err := c.leases()
83+
leases, err := c.Leases()
8484
if err != nil {
8585
return "", err
8686
}
@@ -94,7 +94,7 @@ func (c *Client) ResolveIPAddress(vmMacAddr string) (string, error) {
9494
}
9595
}
9696

97-
func (c *Client) leases() (map[string]string, error) {
97+
func (c *Client) Leases() (map[string]string, error) {
9898
res, err := c.client.Get(fmt.Sprintf("%s%s", c.base, "/services/dhcp/leases"))
9999
if err != nil {
100100
return nil, err
@@ -111,6 +111,18 @@ func (c *Client) leases() (map[string]string, error) {
111111
return leases, nil
112112
}
113113

114+
func NewClientByName(nwName string) *Client {
115+
endpointSock, err := Sock(nwName, EndpointSock)
116+
if err != nil {
117+
return nil
118+
}
119+
subnet, err := Subnet(nwName)
120+
if err != nil {
121+
return nil
122+
}
123+
return NewClient(endpointSock, subnet)
124+
}
125+
114126
func NewClient(endpointSock string, subnet net.IP) *Client {
115127
return create(endpointSock, subnet, "http://lima")
116128
}

pkg/networks/usernet/config.go

+14
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,20 @@ func DNSIP(subnet net.IP) string {
103103
return cidr.Inc(cidr.Inc(cidr.Inc(subnet))).String()
104104
}
105105

106+
// Leases returns a leases file based on network name.
107+
func Leases(name string) (string, error) {
108+
dir, err := dirnames.LimaNetworksDir()
109+
if err != nil {
110+
return "", err
111+
}
112+
sockPath := filepath.Join(filepath.Join(dir, name), "leases.json")
113+
if len(sockPath) >= osutil.UnixPathMax {
114+
return "", fmt.Errorf("usernet leases path %q too long: must be less than UNIX_PATH_MAX=%d characters, but is %d",
115+
sockPath, osutil.UnixPathMax, len(sockPath))
116+
}
117+
return sockPath, nil
118+
}
119+
106120
func netmaskToCidr(baseIP net.IP, netMask net.IP) (net.IP, *net.IPNet, error) {
107121
size, _ := net.IPMask(netMask.To4()).Size()
108122
return net.ParseCIDR(fmt.Sprintf("%s/%d", baseIP.String(), size))

pkg/networks/usernet/recoincile.go

+64
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ package usernet
33
import (
44
"bytes"
55
"context"
6+
"encoding/json"
67
"errors"
78
"fmt"
89
"os"
910
"os/exec"
1011
"path"
1112
"path/filepath"
13+
"strings"
1214
"time"
1315

1416
"github.com/lima-vm/lima/pkg/lockutil"
@@ -57,16 +59,25 @@ func Start(ctx context.Context, name string) error {
5759
return err
5860
}
5961

62+
leases, err := readLeases(name)
63+
if err != nil {
64+
return err
65+
}
66+
6067
err = lockutil.WithDirLock(usernetDir, func() error {
6168
self, err := os.Executable()
6269
if err != nil {
6370
return err
6471
}
72+
leasesString := mapToCliString(leases)
6573
args := []string{"usernet", "-p", pidFile,
6674
"-e", endpointSock,
6775
"--listen-qemu", qemuSock,
6876
"--listen", fdSock,
6977
"--subnet", subnet.String()}
78+
if leasesString != "" {
79+
args = append(args, "--leases", leasesString)
80+
}
7081
cmd := exec.CommandContext(ctx, self, args...)
7182

7283
stdoutPath := filepath.Join(usernetDir, fmt.Sprintf("%s.%s.%s.log", "usernet", name, "stdout"))
@@ -119,6 +130,11 @@ func Stop(name string) error {
119130
if pid != 0 {
120131
logrus.Debugf("Stopping usernet daemon")
121132

133+
err = writeLeases(name)
134+
if err != nil {
135+
return err
136+
}
137+
122138
var stdout, stderr bytes.Buffer
123139
cmd := exec.Command("/usr/bin/pkill", "-F", pidFile)
124140
cmd.Stdout = &stdout
@@ -145,3 +161,51 @@ func Stop(name string) error {
145161
}
146162
return nil
147163
}
164+
165+
func mapToCliString(m map[string]string) string {
166+
var strArr []string
167+
for key, value := range m {
168+
strArr = append(strArr, fmt.Sprintf("%s=%s", key, value))
169+
}
170+
return strings.Join(strArr, ",")
171+
}
172+
173+
func readLeases(name string) (map[string]string, error) {
174+
leasesFile, err := Leases(name)
175+
if err != nil {
176+
return nil, err
177+
}
178+
var leases map[string]string
179+
if _, err := os.Stat(leasesFile); errors.Is(err, os.ErrNotExist) {
180+
return leases, nil
181+
}
182+
file, err := os.Open(leasesFile)
183+
if err != nil {
184+
return nil, err
185+
}
186+
decoder := json.NewDecoder(file)
187+
err = decoder.Decode(&leases)
188+
return leases, err
189+
}
190+
191+
func writeLeases(nwName string) error {
192+
client := NewClientByName(nwName)
193+
leases, err := client.Leases()
194+
if err != nil {
195+
return err
196+
}
197+
leasesFile, err := Leases(nwName)
198+
if err != nil {
199+
return err
200+
}
201+
file, err := os.Create(leasesFile)
202+
if err != nil {
203+
return err
204+
}
205+
encoder := json.NewEncoder(file)
206+
err = encoder.Encode(leases)
207+
if err != nil {
208+
return err
209+
}
210+
return nil
211+
}

pkg/qemu/qemu_driver.go

+2-14
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func (l *LimaQemuDriver) Start(ctx context.Context) (chan error, error) {
190190
l.vhostCmds = vhostCmds
191191
go func() {
192192
if usernetIndex := limayaml.FirstUsernetIndex(l.Yaml); usernetIndex != -1 {
193-
client := newUsernetClient(l.Yaml.Networks[usernetIndex].Lima)
193+
client := usernet.NewClientByName(l.Yaml.Networks[usernetIndex].Lima)
194194
err := client.ConfigureDriver(l.BaseDriver)
195195
if err != nil {
196196
l.qWaitCh <- err
@@ -298,7 +298,7 @@ func (l *LimaQemuDriver) killVhosts() error {
298298
func (l *LimaQemuDriver) shutdownQEMU(ctx context.Context, timeout time.Duration, qCmd *exec.Cmd, qWaitCh <-chan error) error {
299299
logrus.Info("Shutting down QEMU with ACPI")
300300
if usernetIndex := limayaml.FirstUsernetIndex(l.Yaml); usernetIndex != -1 {
301-
client := newUsernetClient(l.Yaml.Networks[usernetIndex].Lima)
301+
client := usernet.NewClientByName(l.Yaml.Networks[usernetIndex].Lima)
302302
err := client.UnExposeSSH(l.SSHLocalPort)
303303
if err != nil {
304304
logrus.Warnf("Failed to remove SSH binding for port %d", l.SSHLocalPort)
@@ -350,18 +350,6 @@ func (l *LimaQemuDriver) killQEMU(_ context.Context, _ time.Duration, qCmd *exec
350350
return errors.Join(qWaitErr, l.killVhosts())
351351
}
352352

353-
func newUsernetClient(nwName string) *usernet.Client {
354-
endpointSock, err := usernet.Sock(nwName, usernet.EndpointSock)
355-
if err != nil {
356-
return nil
357-
}
358-
subnet, err := usernet.Subnet(nwName)
359-
if err != nil {
360-
return nil
361-
}
362-
return usernet.NewClient(endpointSock, subnet)
363-
}
364-
365353
func logPipeRoutine(r io.Reader, header string) {
366354
scanner := bufio.NewScanner(r)
367355
for scanner.Scan() {

pkg/vz/vm_darwin.go

+1-9
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,7 @@ func startUsernet(ctx context.Context, driver *driver.BaseDriver) (*usernet.Clie
148148
return usernet.NewClient(endpointSock, subnetIP), err
149149
}
150150
nwName := driver.Yaml.Networks[firstUsernetIndex].Lima
151-
endpointSock, err := usernet.Sock(nwName, usernet.EndpointSock)
152-
if err != nil {
153-
return nil, err
154-
}
155-
subnetIP, err := usernet.Subnet(nwName)
156-
if err != nil {
157-
return nil, err
158-
}
159-
return usernet.NewClient(endpointSock, subnetIP), nil
151+
return usernet.NewClientByName(nwName), nil
160152
}
161153

162154
func createVM(driver *driver.BaseDriver) (*vz.VirtualMachine, error) {

0 commit comments

Comments
 (0)