Skip to content

Support for deterministic ip for user-v2 network #1801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions cmd/limactl/usernet.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func newUsernetCommand() *cobra.Command {
hostagentCommand.Flags().String("listen", "", "listen on a Unix socket and receive Bess-compatible FDs as SCM_RIGHTS messages")
hostagentCommand.Flags().String("subnet", "192.168.5.0/24", "sets subnet value for the usernet network")
hostagentCommand.Flags().Int("mtu", 1500, "mtu")
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' ")
return hostagentCommand
}

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

leases, err := cmd.Flags().GetStringToString("leases")
if err != nil {
return err
}

mtu, err := cmd.Flags().GetInt("mtu")
if err != nil {
return err
Expand All @@ -68,10 +74,11 @@ func usernetAction(cmd *cobra.Command, _ []string) error {
os.RemoveAll(fdSocket)

return usernet.StartGVisorNetstack(cmd.Context(), &usernet.GVisorNetstackOpts{
MTU: mtu,
Endpoint: endpoint,
QemuSocket: qemuSocket,
FdSocket: fdSocket,
Subnet: subnet,
MTU: mtu,
Endpoint: endpoint,
QemuSocket: qemuSocket,
FdSocket: fdSocket,
Subnet: subnet,
DefaultLeases: leases,
})
}
16 changes: 14 additions & 2 deletions pkg/networks/usernet/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (c *Client) ResolveIPAddress(vmMacAddr string) (string, error) {
case <-timeout:
return "", errors.New("usernet unable to resolve IP for SSH forwarding")
case <-ticker.C:
leases, err := c.leases()
leases, err := c.Leases()
if err != nil {
return "", err
}
Expand All @@ -94,7 +94,7 @@ func (c *Client) ResolveIPAddress(vmMacAddr string) (string, error) {
}
}

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

func NewClientByName(nwName string) *Client {
endpointSock, err := Sock(nwName, EndpointSock)
if err != nil {
return nil
}
subnet, err := Subnet(nwName)
if err != nil {
return nil
}
return NewClient(endpointSock, subnet)
}

func NewClient(endpointSock string, subnet net.IP) *Client {
return create(endpointSock, subnet, "http://lima")
}
Expand Down
14 changes: 14 additions & 0 deletions pkg/networks/usernet/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ func DNSIP(subnet net.IP) string {
return cidr.Inc(cidr.Inc(cidr.Inc(subnet))).String()
}

// Leases returns a leases file based on network name.
func Leases(name string) (string, error) {
dir, err := dirnames.LimaNetworksDir()
if err != nil {
return "", err
}
sockPath := filepath.Join(filepath.Join(dir, name), "leases.json")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you update docs/internal.md ?

if len(sockPath) >= osutil.UnixPathMax {
return "", fmt.Errorf("usernet leases path %q too long: must be less than UNIX_PATH_MAX=%d characters, but is %d",
sockPath, osutil.UnixPathMax, len(sockPath))
}
return sockPath, nil
}

func netmaskToCidr(baseIP net.IP, netMask net.IP) (net.IP, *net.IPNet, error) {
size, _ := net.IPMask(netMask.To4()).Size()
return net.ParseCIDR(fmt.Sprintf("%s/%d", baseIP.String(), size))
Expand Down
64 changes: 64 additions & 0 deletions pkg/networks/usernet/recoincile.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package usernet
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"

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

leases, err := readLeases(name)
if err != nil {
return err
}

err = lockutil.WithDirLock(usernetDir, func() error {
self, err := os.Executable()
if err != nil {
return err
}
leasesString := mapToCliString(leases)
args := []string{"usernet", "-p", pidFile,
"-e", endpointSock,
"--listen-qemu", qemuSock,
"--listen", fdSock,
"--subnet", subnet.String()}
if leasesString != "" {
args = append(args, "--leases", leasesString)
}
cmd := exec.CommandContext(ctx, self, args...)

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

err = writeLeases(name)
if err != nil {
return err
}

var stdout, stderr bytes.Buffer
cmd := exec.Command("/usr/bin/pkill", "-F", pidFile)
cmd.Stdout = &stdout
Expand All @@ -145,3 +161,51 @@ func Stop(name string) error {
}
return nil
}

func mapToCliString(m map[string]string) string {
var strArr []string
for key, value := range m {
strArr = append(strArr, fmt.Sprintf("%s=%s", key, value))
}
return strings.Join(strArr, ",")
}

func readLeases(name string) (map[string]string, error) {
leasesFile, err := Leases(name)
if err != nil {
return nil, err
}
var leases map[string]string
if _, err := os.Stat(leasesFile); errors.Is(err, os.ErrNotExist) {
return leases, nil
}
file, err := os.Open(leasesFile)
if err != nil {
return nil, err
}
decoder := json.NewDecoder(file)
err = decoder.Decode(&leases)
return leases, err
}

func writeLeases(nwName string) error {
client := NewClientByName(nwName)
leases, err := client.Leases()
if err != nil {
return err
}
leasesFile, err := Leases(nwName)
if err != nil {
return err
}
file, err := os.Create(leasesFile)
if err != nil {
return err
}
encoder := json.NewEncoder(file)
err = encoder.Encode(leases)
if err != nil {
return err
}
return nil
}
16 changes: 2 additions & 14 deletions pkg/qemu/qemu_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func (l *LimaQemuDriver) Start(ctx context.Context) (chan error, error) {
l.vhostCmds = vhostCmds
go func() {
if usernetIndex := limayaml.FirstUsernetIndex(l.Yaml); usernetIndex != -1 {
client := newUsernetClient(l.Yaml.Networks[usernetIndex].Lima)
client := usernet.NewClientByName(l.Yaml.Networks[usernetIndex].Lima)
err := client.ConfigureDriver(l.BaseDriver)
if err != nil {
l.qWaitCh <- err
Expand Down Expand Up @@ -298,7 +298,7 @@ func (l *LimaQemuDriver) killVhosts() error {
func (l *LimaQemuDriver) shutdownQEMU(ctx context.Context, timeout time.Duration, qCmd *exec.Cmd, qWaitCh <-chan error) error {
logrus.Info("Shutting down QEMU with ACPI")
if usernetIndex := limayaml.FirstUsernetIndex(l.Yaml); usernetIndex != -1 {
client := newUsernetClient(l.Yaml.Networks[usernetIndex].Lima)
client := usernet.NewClientByName(l.Yaml.Networks[usernetIndex].Lima)
err := client.UnExposeSSH(l.SSHLocalPort)
if err != nil {
logrus.Warnf("Failed to remove SSH binding for port %d", l.SSHLocalPort)
Expand Down Expand Up @@ -350,18 +350,6 @@ func (l *LimaQemuDriver) killQEMU(_ context.Context, _ time.Duration, qCmd *exec
return errors.Join(qWaitErr, l.killVhosts())
}

func newUsernetClient(nwName string) *usernet.Client {
endpointSock, err := usernet.Sock(nwName, usernet.EndpointSock)
if err != nil {
return nil
}
subnet, err := usernet.Subnet(nwName)
if err != nil {
return nil
}
return usernet.NewClient(endpointSock, subnet)
}

func logPipeRoutine(r io.Reader, header string) {
scanner := bufio.NewScanner(r)
for scanner.Scan() {
Expand Down
10 changes: 1 addition & 9 deletions pkg/vz/vm_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,7 @@ func startUsernet(ctx context.Context, driver *driver.BaseDriver) (*usernet.Clie
return usernet.NewClient(endpointSock, subnetIP), err
}
nwName := driver.Yaml.Networks[firstUsernetIndex].Lima
endpointSock, err := usernet.Sock(nwName, usernet.EndpointSock)
if err != nil {
return nil, err
}
subnetIP, err := usernet.Subnet(nwName)
if err != nil {
return nil, err
}
return usernet.NewClient(endpointSock, subnetIP), nil
return usernet.NewClientByName(nwName), nil
}

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