From 953dfa46656221b9c466991021ba71d1c8d96980 Mon Sep 17 00:00:00 2001 From: Balaji Vijayakumar Date: Thu, 15 Jun 2023 18:44:58 +0530 Subject: [PATCH] Support for configurable network address for user-v2 Signed-off-by: Balaji Vijayakumar --- cmd/limactl/usernet.go | 6 + examples/experimental/net-user-v2.yaml | 5 + go.mod | 16 +- go.sum | 32 ++-- hack/test-example.sh | 9 +- pkg/cidata/cidata.go | 44 ++++-- pkg/cidata/cidata_test.go | 6 +- pkg/cidata/template.go | 27 ++-- pkg/networks/config_test.go | 4 +- pkg/networks/const.go | 1 - pkg/networks/networks.TEMPLATE.yaml | 2 + pkg/networks/usernet/client.go | 67 ++++++-- pkg/networks/usernet/config.go | 62 ++++++++ pkg/networks/usernet/config_test.go | 45 ++++++ pkg/networks/usernet/dns.go | 82 ++++++++++ pkg/networks/usernet/dns_test.go | 206 +++++++++++++++++++++++++ pkg/networks/usernet/gvproxy.go | 23 ++- pkg/networks/usernet/recoincile.go | 8 +- pkg/qemu/qemu_driver.go | 11 +- pkg/vz/vm_darwin.go | 15 +- 20 files changed, 585 insertions(+), 86 deletions(-) create mode 100644 pkg/networks/usernet/config_test.go create mode 100644 pkg/networks/usernet/dns.go create mode 100644 pkg/networks/usernet/dns_test.go diff --git a/cmd/limactl/usernet.go b/cmd/limactl/usernet.go index 6a1b608baa42..40428a221082 100644 --- a/cmd/limactl/usernet.go +++ b/cmd/limactl/usernet.go @@ -22,6 +22,7 @@ func newUsernetCommand() *cobra.Command { hostagentCommand.Flags().StringP("endpoint", "e", "", "exposes usernet api(s) on this endpoint") hostagentCommand.Flags().String("listen-qemu", "", "listen for qemu connections") 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") return hostagentCommand } @@ -52,6 +53,10 @@ func usernetAction(cmd *cobra.Command, _ []string) error { if err != nil { return err } + subnet, err := cmd.Flags().GetString("subnet") + if err != nil { + return err + } mtu, err := cmd.Flags().GetInt("mtu") if err != nil { @@ -67,5 +72,6 @@ func usernetAction(cmd *cobra.Command, _ []string) error { Endpoint: endpoint, QemuSocket: qemuSocket, FdSocket: fdSocket, + Subnet: subnet, }) } diff --git a/examples/experimental/net-user-v2.yaml b/examples/experimental/net-user-v2.yaml index 70747d6f1322..851e8b7ed651 100644 --- a/examples/experimental/net-user-v2.yaml +++ b/examples/experimental/net-user-v2.yaml @@ -6,6 +6,11 @@ images: - location: "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-arm64.img" arch: "aarch64" +hostResolver: + # Marking enabled false will make use of system dns / inbuilt dns resolver of usernet for user-v2 network + enabled: false + hosts: + host.docker.internal: host.lima.internal mounts: - location: "~" - location: "/tmp/lima" diff --git a/go.mod b/go.mod index 5b595d7ce478..192242b01e6a 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,12 @@ require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/Code-Hex/vz/v3 v3.0.6 github.com/alessio/shellescape v1.4.1 + github.com/apparentlymart/go-cidr v1.1.0 github.com/balajiv113/fd v0.0.0-20230330094840-143eec500f3e github.com/cheggaaa/pb/v3 v3.1.2 github.com/containerd/containerd v1.7.2 github.com/containerd/continuity v0.4.1 - github.com/containers/gvisor-tap-vsock v0.6.1 + github.com/containers/gvisor-tap-vsock v0.6.2-0.20230615101539-7bc474d2c840 github.com/coreos/go-semver v0.3.1 github.com/cpuguy83/go-md2man/v2 v2.0.2 github.com/cyphar/filepath-securejoin v0.2.3 @@ -37,7 +38,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/xorcare/pointer v1.2.2 - golang.org/x/sync v0.2.0 + golang.org/x/sync v0.3.0 golang.org/x/sys v0.9.0 gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 gopkg.in/yaml.v3 v3.0.1 @@ -54,7 +55,6 @@ require ( github.com/VividCortex/ewma v1.2.0 // indirect github.com/a8m/envsubst v1.4.2 // indirect github.com/alecthomas/participle/v2 v2.0.0 // indirect - github.com/apparentlymart/go-cidr v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/digitalocean/go-libvirt v0.0.0-20220804181439-8648fbde413e // indirect github.com/dimchansky/utfbom v1.1.1 // indirect @@ -88,8 +88,8 @@ require ( github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-runewidth v0.0.12 // indirect - github.com/mdlayher/socket v0.4.0 // indirect - github.com/mdlayher/vsock v1.2.0 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/mdlayher/vsock v1.2.1 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -103,12 +103,12 @@ require ( github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.7.0 // indirect - golang.org/x/crypto v0.9.0 // indirect + golang.org/x/crypto v0.10.0 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/term v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.9.1 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect diff --git a/go.sum b/go.sum index e6580b7be02a..17957a3f78b9 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ github.com/containerd/containerd v1.7.2 h1:UF2gdONnxO8I6byZXDi5sXWiWvlW3D/sci7dT github.com/containerd/containerd v1.7.2/go.mod h1:afcz74+K10M/+cjGHIVQrCt3RAQhUSCAjJ9iMYhhkuI= github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= -github.com/containers/gvisor-tap-vsock v0.6.1 h1:FaLOl4CE13Q8PgG89MfAaFx/B0AK/akHaR6pR2nvLUY= -github.com/containers/gvisor-tap-vsock v0.6.1/go.mod h1:L6sgnuJhMaLT9dNi0fOEoloLQnaVgLXP5oEFTVvq8Dw= +github.com/containers/gvisor-tap-vsock v0.6.2-0.20230615101539-7bc474d2c840 h1:Tn0cnI7gGTRDuOi9Y4y8cOqjS5CmKINI9VUVTUjO0Xw= +github.com/containers/gvisor-tap-vsock v0.6.2-0.20230615101539-7bc474d2c840/go.mod h1:NtXJX69jW1R1htfQcPUQTINwT/iD74zp7NzUVXYempY= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= @@ -211,10 +211,10 @@ github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 h1:aFkJ6lx4FPip+S+Uw4aTegFMct9shDvP+79PsSxpm3w= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= -github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= -github.com/mdlayher/vsock v1.2.0 h1:klRY9lndjmg6k/QWbX/ucQ3e2JFRm1M7vfG9hijbQ0A= -github.com/mdlayher/vsock v1.2.0/go.mod h1:w4kdSTQB9p1l/WwGmAs0V62qQ869qRYoongwgN+Y1HE= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= +github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= @@ -235,7 +235,7 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo/v2 v2.4.0 h1:+Ig9nvqgS5OBSACXNk15PLdp0U9XPYROt9CFzVdFGIs= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= @@ -280,7 +280,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -300,8 +300,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -346,8 +346,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181021155630-eda9bb28ed51/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -387,16 +387,16 @@ golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/hack/test-example.sh b/hack/test-example.sh index d924e30b5097..9a79d6d27dd8 100755 --- a/hack/test-example.sh +++ b/hack/test-example.sh @@ -126,7 +126,8 @@ INFO "Testing proxy settings are imported" got=$(limactl shell "$NAME" env | grep FTP_PROXY) # Expected: FTP_PROXY is set in addition to ftp_proxy, localhost is replaced # by the gateway address, and the value is set immediately without a restart -expected="FTP_PROXY=http://192.168.5.2:2121" +gatewayIp=$(limactl shell "$NAME" ip route show 0.0.0.0/0 dev eth0 | cut -d\ -f3) +expected="FTP_PROXY=http://${gatewayIp}:2121" INFO "FTP_PROXY: expected=${expected} got=${got}" if [ "$got" != "$expected" ]; then ERROR "proxy environment variable not set to correct value" @@ -327,10 +328,10 @@ if [[ -n ${CHECKS["user-v2"]} ]]; then INFO "Testing user-v2 network" secondvm="$NAME-1" "${LIMACTL_CREATE_AND_START[@]}" "$FILE" --name "$secondvm" - guestNewip="$(limactl shell "$secondvm" ip -4 -j addr show dev eth0 | jq -r '.[0].addr_info[0].local')" - INFO "IP of $secondvm is $guestNewip" + secondvmDNS="lima-$secondvm.internal" + INFO "DNS of $secondvm is $secondvmDNS" set -x - if ! limactl shell "$NAME" ping -c 1 "$guestNewip"; then + if ! limactl shell "$NAME" ping -c 1 "$secondvmDNS"; then ERROR "Failed to do vm->vm communication via user-v2" INFO "Stopping \"$secondvm\"" limactl stop "$secondvm" diff --git a/pkg/cidata/cidata.go b/pkg/cidata/cidata.go index 819422e5b2e6..f1b34cf5f79e 100644 --- a/pkg/cidata/cidata.go +++ b/pkg/cidata/cidata.go @@ -12,6 +12,8 @@ import ( "strings" "time" + "github.com/lima-vm/lima/pkg/networks/usernet" + "github.com/lima-vm/lima/pkg/networks" "github.com/docker/go-units" @@ -35,7 +37,7 @@ var netLookupIP = func(host string) []net.IP { return ips } -func setupEnv(y *limayaml.LimaYAML) (map[string]string, error) { +func setupEnv(y *limayaml.LimaYAML, args TemplateArgs) (map[string]string, error) { // Start with the proxy variables from the system settings. env, err := osutil.ProxySettings() if err != nil { @@ -74,7 +76,7 @@ func setupEnv(y *limayaml.LimaYAML) (map[string]string, error) { for _, ip := range netLookupIP(u.Hostname()) { if ip.IsLoopback() { - newHost := networks.SlirpGateway + newHost := args.SlirpGateway if u.Port() != "" { newHost = net.JoinHostPort(newHost, u.Port()) } @@ -123,13 +125,35 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort UID: uid, Containerd: Containerd{System: *y.Containerd.System, User: *y.Containerd.User}, SlirpNICName: networks.SlirpNICName, - SlirpGateway: networks.SlirpGateway, - SlirpDNS: networks.SlirpDNS, - SlirpIPAddress: networks.SlirpIPAddress, RosettaEnabled: *y.Rosetta.Enabled, RosettaBinFmt: *y.Rosetta.BinFmt, } + firstUsernetIndex := limayaml.FirstUsernetIndex(y) + var subnet net.IP + + if firstUsernetIndex != -1 { + usernetName := y.Networks[firstUsernetIndex].Lima + subnet, err = usernet.Subnet(usernetName) + if err != nil { + return err + } + args.SlirpGateway = usernet.GatewayIP(subnet) + args.SlirpDNS = usernet.GatewayIP(subnet) + } else { + subnet, err = usernet.ParseSubnet(networks.SlirpNetwork) + if err != nil { + return err + } + args.SlirpGateway = usernet.GatewayIP(subnet) + if *y.VMType == limayaml.VZ { + args.SlirpDNS = usernet.GatewayIP(subnet) + } else { + args.SlirpDNS = usernet.DNSIP(subnet) + } + args.SlirpIPAddress = networks.SlirpIPAddress + } + // change instance id on every boot so network config will be processed again args.IID = fmt.Sprintf("iid-%d", time.Now().Unix()) @@ -209,9 +233,7 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort }) } - slirpMACAddress := limayaml.MACAddress(instDir) - args.Networks = append(args.Networks, Network{MACAddress: slirpMACAddress, Interface: networks.SlirpNICName}) - firstUsernetIndex := limayaml.FirstUsernetIndex(y) + args.Networks = append(args.Networks, Network{MACAddress: limayaml.MACAddress(instDir), Interface: networks.SlirpNICName}) for i, nw := range y.Networks { if i == firstUsernetIndex { continue @@ -219,14 +241,16 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort args.Networks = append(args.Networks, Network{MACAddress: nw.MACAddress, Interface: nw.Interface}) } - args.Env, err = setupEnv(y) + args.Env, err = setupEnv(y, args) if err != nil { return err } if *y.HostResolver.Enabled { args.UDPDNSLocalPort = udpDNSLocalPort args.TCPDNSLocalPort = tcpDNSLocalPort - args.DNSAddresses = append(args.DNSAddresses, networks.SlirpDNS) + args.DNSAddresses = append(args.DNSAddresses, args.SlirpDNS) + } else if firstUsernetIndex != -1 || *y.VMType == limayaml.VZ { + args.DNSAddresses = append(args.DNSAddresses, args.SlirpDNS) } else if len(y.DNS) > 0 { for _, addr := range y.DNS { args.DNSAddresses = append(args.DNSAddresses, addr.String()) diff --git a/pkg/cidata/cidata_test.go b/pkg/cidata/cidata_test.go index 2ff729dfc8fc..6b62df3c4b59 100644 --- a/pkg/cidata/cidata_test.go +++ b/pkg/cidata/cidata_test.go @@ -48,7 +48,8 @@ func TestSetupEnv(t *testing.T) { t.Run(httpProxy.Host, func(t *testing.T) { envKey := "http_proxy" envValue := httpProxy.String() - envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}}) + templateArgs := TemplateArgs{SlirpGateway: networks.SlirpGateway} + envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}}, templateArgs) assert.NilError(t, err) assert.Equal(t, envs[envKey], strings.ReplaceAll(envValue, httpProxy.Hostname(), networks.SlirpGateway)) }) @@ -58,7 +59,8 @@ func TestSetupEnv(t *testing.T) { func TestSetupInvalidEnv(t *testing.T) { envKey := "http_proxy" envValue := "://localhost:8080" - envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}}) + templateArgs := TemplateArgs{SlirpGateway: networks.SlirpGateway} + envs, err := setupEnv(&limayaml.LimaYAML{PropagateProxyEnv: pointer.Bool(false), Env: map[string]string{envKey: envValue}}, templateArgs) assert.NilError(t, err) assert.Equal(t, envs[envKey], envValue) } diff --git a/pkg/cidata/template.go b/pkg/cidata/template.go index 37703e6860e2..d9f0a1a7b40e 100644 --- a/pkg/cidata/template.go +++ b/pkg/cidata/template.go @@ -50,19 +50,20 @@ type Disk struct { Device string } type TemplateArgs struct { - Name string // instance name - IID string // instance id - User string // user name - UID int - SSHPubKeys []string - Mounts []Mount - MountType string - Disks []Disk - Containerd Containerd - Networks []Network - SlirpNICName string - SlirpGateway string - SlirpDNS string + Name string // instance name + IID string // instance id + User string // user name + UID int + SSHPubKeys []string + Mounts []Mount + MountType string + Disks []Disk + Containerd Containerd + Networks []Network + SlirpNICName string + SlirpGateway string + SlirpDNS string + //Deprecated SlirpIPAddress string UDPDNSLocalPort int TCPDNSLocalPort int diff --git a/pkg/networks/config_test.go b/pkg/networks/config_test.go index 7c8ff0e9786e..956d3a351154 100644 --- a/pkg/networks/config_test.go +++ b/pkg/networks/config_test.go @@ -15,7 +15,7 @@ func TestFillDefault(t *testing.T) { userNet := newYaml.Networks[ModeUserV2] assert.Equal(t, userNet.Mode, ModeUserV2) assert.Equal(t, userNet.Interface, "") - assert.DeepEqual(t, userNet.NetMask, net.IP{}) - assert.DeepEqual(t, userNet.Gateway, net.IP{}) + assert.DeepEqual(t, userNet.NetMask, net.ParseIP("255.255.255.0")) + assert.DeepEqual(t, userNet.Gateway, net.ParseIP("192.168.104.1")) assert.DeepEqual(t, userNet.DHCPEnd, net.IP{}) } diff --git a/pkg/networks/const.go b/pkg/networks/const.go index b1aa47ed3c64..16671fd6208a 100644 --- a/pkg/networks/const.go +++ b/pkg/networks/const.go @@ -5,6 +5,5 @@ const ( // CIDR is intentionally hardcoded to 192.168.5.0/24, as each of QEMU has its own independent slirp network. SlirpNetwork = "192.168.5.0/24" SlirpGateway = "192.168.5.2" - SlirpDNS = "192.168.5.3" SlirpIPAddress = "192.168.5.15" ) diff --git a/pkg/networks/networks.TEMPLATE.yaml b/pkg/networks/networks.TEMPLATE.yaml index 0916473fa5c3..41540adf2957 100644 --- a/pkg/networks/networks.TEMPLATE.yaml +++ b/pkg/networks/networks.TEMPLATE.yaml @@ -24,6 +24,8 @@ group: everyone networks: user-v2: mode: user-v2 + gateway: 192.168.104.1 + netmask: 255.255.255.0 # user-v2 network is experimental network mode which supports all functionalities of default usernet network and also allows vm -> vm communication. # Doesn't support configuration of custom gateway; hardcoded to 192.168.5.0/24 shared: diff --git a/pkg/networks/usernet/client.go b/pkg/networks/usernet/client.go index 2187038f1e89..eb5312664ea1 100644 --- a/pkg/networks/usernet/client.go +++ b/pkg/networks/usernet/client.go @@ -9,6 +9,9 @@ import ( "net/http" "time" + "github.com/lima-vm/lima/pkg/driver" + "github.com/lima-vm/lima/pkg/limayaml" + gvproxyclient "github.com/containers/gvisor-tap-vsock/pkg/client" "github.com/containers/gvisor-tap-vsock/pkg/types" ) @@ -19,6 +22,23 @@ type Client struct { client *http.Client delegate *gvproxyclient.Client base string + subnet net.IP +} + +func (c *Client) ConfigureDriver(driver *driver.BaseDriver) error { + macAddress := limayaml.MACAddress(driver.Instance.Dir) + ipAddress, err := c.ResolveIPAddress(macAddress) + if err != nil { + return err + } + err = c.ResolveAndForwardSSH(ipAddress, driver.SSHLocalPort) + if err != nil { + return err + } + var hosts = driver.Yaml.HostResolver.Hosts + hosts[fmt.Sprintf("lima-%s.internal", driver.Instance.Name)] = ipAddress + err = c.AddDNSHosts(hosts) + return err } func (c *Client) UnExposeSSH(sshPort int) error { @@ -28,30 +48,46 @@ func (c *Client) UnExposeSSH(sshPort int) error { }) } -func (c *Client) ResolveAndForwardSSH(vmMacAddr string, sshPort int) error { +func (c *Client) AddDNSHosts(hosts map[string]string) error { + hosts["host.lima.internal"] = GatewayIP(c.subnet) + zones := extractZones(hosts) + for _, zone := range zones { + err := c.delegate.AddDNS(&zone) + if err != nil { + return err + } + } + return nil +} + +func (c *Client) ResolveAndForwardSSH(ipAddr string, sshPort int) error { + err := c.delegate.Expose(&types.ExposeRequest{ + Local: fmt.Sprintf("127.0.0.1:%d", sshPort), + Remote: fmt.Sprintf("%s:22", ipAddr), + Protocol: "tcp", + }) + if err != nil { + return err + } + return nil +} + +func (c *Client) ResolveIPAddress(vmMacAddr string) (string, error) { timeout := time.After(2 * time.Minute) ticker := time.NewTicker(500 * time.Millisecond) for { select { case <-timeout: - return errors.New("usernet unable to resolve IP for SSH forwarding") + return "", errors.New("usernet unable to resolve IP for SSH forwarding") case <-ticker.C: leases, err := c.leases() if err != nil { - return err + return "", err } for ipAddr, leaseAddr := range leases { if vmMacAddr == leaseAddr { - err = c.delegate.Expose(&types.ExposeRequest{ - Local: fmt.Sprintf("127.0.0.1:%d", sshPort), - Remote: fmt.Sprintf("%s:22", ipAddr), - Protocol: "tcp", - }) - if err != nil { - return err - } - return nil + return ipAddr, nil } } } @@ -75,11 +111,11 @@ func (c *Client) leases() (map[string]string, error) { return leases, nil } -func NewClient(endpointSock string) *Client { - return create(endpointSock, "http://lima") +func NewClient(endpointSock string, subnet net.IP) *Client { + return create(endpointSock, subnet, "http://lima") } -func create(sock string, base string) *Client { +func create(sock string, subnet net.IP, base string) *Client { client := &http.Client{ Transport: &http.Transport{ DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { @@ -92,5 +128,6 @@ func create(sock string, base string) *Client { client: client, delegate: delegate, base: base, + subnet: subnet, } } diff --git a/pkg/networks/usernet/config.go b/pkg/networks/usernet/config.go index d97cc18d8a83..021329913766 100644 --- a/pkg/networks/usernet/config.go +++ b/pkg/networks/usernet/config.go @@ -2,8 +2,12 @@ package usernet import ( "fmt" + "net" "path/filepath" + "github.com/apparentlymart/go-cidr/cidr" + "github.com/lima-vm/lima/pkg/networks" + "github.com/lima-vm/lima/pkg/store/dirnames" ) @@ -37,3 +41,61 @@ func PIDFile(name string) (string, error) { } return filepath.Join(dir, name, fmt.Sprintf("usernet_%s.pid", name)), nil } + +// SubnetCIDR returns a subnet in form of net.IPNet for the given network name. +func SubnetCIDR(name string) (*net.IPNet, error) { + config, err := networks.Config() + if err != nil { + return nil, err + } + err = config.Check(name) + if err != nil { + return nil, err + } + _, ipNet, err := netmaskToCidr(config.Networks[name].Gateway, config.Networks[name].NetMask) + if err != nil { + return nil, err + } + return ipNet, err +} + +// Subnet returns a subnet net.IP for the given network name. +func Subnet(name string) (net.IP, error) { + config, err := networks.Config() + if err != nil { + return nil, err + } + err = config.Check(name) + if err != nil { + return nil, err + } + _, ipNet, err := netmaskToCidr(config.Networks[name].Gateway, config.Networks[name].NetMask) + if err != nil { + return nil, err + } + return ipNet.IP, err +} + +// ParseSubnet converts subnet string to net.IP +func ParseSubnet(subnet string) (net.IP, error) { + subnetIP, _, err := net.ParseCIDR(subnet) + if err != nil { + return nil, err + } + return subnetIP, nil +} + +// GatewayIP returns the 2nd IP for the given subnet +func GatewayIP(subnet net.IP) string { + return cidr.Inc(cidr.Inc(subnet)).String() +} + +// DNSIP returns the 3rd IP for the given subnet +func DNSIP(subnet net.IP) string { + return cidr.Inc(cidr.Inc(cidr.Inc(subnet))).String() +} + +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)) +} diff --git a/pkg/networks/usernet/config_test.go b/pkg/networks/usernet/config_test.go new file mode 100644 index 000000000000..3375b6728ddf --- /dev/null +++ b/pkg/networks/usernet/config_test.go @@ -0,0 +1,45 @@ +package usernet + +import ( + "net" + "testing" + + "github.com/lima-vm/lima/pkg/networks" + + "gotest.tools/v3/assert" +) + +func TestUsernetConfig(t *testing.T) { + + t.Run("parse subnet", func(t *testing.T) { + subnet, err := ParseSubnet(networks.SlirpNetwork) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, subnet.String(), "192.168.5.0") + }) + + t.Run("verify dns ip", func(t *testing.T) { + subnet, _, err := net.ParseCIDR(networks.SlirpNetwork) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, DNSIP(subnet), "192.168.5.3") + }) + + t.Run("verify gateway ip", func(t *testing.T) { + subnet, _, err := net.ParseCIDR(networks.SlirpNetwork) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, GatewayIP(subnet), "192.168.5.2") + }) + + t.Run("verify subnet via config ip", func(t *testing.T) { + subnet, err := Subnet("user-v2") + if err != nil { + t.Fatal(err) + } + assert.Equal(t, subnet.String(), "192.168.104.0") + }) +} diff --git a/pkg/networks/usernet/dns.go b/pkg/networks/usernet/dns.go new file mode 100644 index 000000000000..9b38140c0c10 --- /dev/null +++ b/pkg/networks/usernet/dns.go @@ -0,0 +1,82 @@ +package usernet + +import ( + "net" + "strings" + + "github.com/containers/gvisor-tap-vsock/pkg/types" +) + +func extractZones(hosts hostMap) (zones []types.Zone) { + list := make(map[string]types.Zone) + + for host := range hosts { + h := zoneHost(host) + + zone := types.Zone{Name: h.name()} + if existingZone, ok := list[h.name()]; ok { + zone = existingZone + } + + if h.recordName() == "" { + if zone.DefaultIP == nil { + zone.DefaultIP = hosts.hostIP(host) + } + } else { + zone.Records = append(zone.Records, types.Record{ + Name: h.recordName(), + IP: hosts.hostIP(host), + }) + } + + list[h.name()] = zone + } + + for _, zone := range list { + zones = append(zones, zone) + } + return +} + +type hostMap map[string]string + +func (z hostMap) hostIP(host string) net.IP { + for { + // check if host entry exists + h, ok := z[host] + if !ok || h == "" { + return nil + } + + // if it's a valid ip, return + if ip := net.ParseIP(h); ip != nil { + return ip + } + + // otherwise, a string i.e. another host + // loop through the process again. + host = h + } +} + +type zoneHost string + +func (z zoneHost) name() string { + i := z.dotIndex() + if i < 0 { + return string(z) + } + return string(z)[i+1:] + "." +} + +func (z zoneHost) recordName() string { + i := z.dotIndex() + if i < 0 { + return "" + } + return string(z)[:i] +} + +func (z zoneHost) dotIndex() int { + return strings.LastIndex(string(z), ".") +} diff --git a/pkg/networks/usernet/dns_test.go b/pkg/networks/usernet/dns_test.go new file mode 100644 index 000000000000..db0367f298a4 --- /dev/null +++ b/pkg/networks/usernet/dns_test.go @@ -0,0 +1,206 @@ +package usernet + +import ( + "fmt" + "net" + "sort" + "testing" + + "github.com/containers/gvisor-tap-vsock/pkg/types" +) + +func Test_hostsMapIP(t *testing.T) { + hosts := hostMap{} + hosts["sample"] = "1.1.1.1" + hosts["another.sample"] = "1.2.2.1" + hosts["google.com"] = "8.8.8.8" + hosts["google.ae"] = "google.com" + hosts["google.ie"] = "google.ae" + + tests := []struct { + host string + want net.IP + }{ + {host: "sample", want: net.ParseIP("1.1.1.1")}, + {host: "another.sample", want: net.ParseIP("1.2.2.1")}, + {host: "google.com", want: net.ParseIP("8.8.8.8")}, + {host: "google.ae", want: net.ParseIP("8.8.8.8")}, + {host: "google.ie", want: net.ParseIP("8.8.8.8")}, + {host: "google.sample", want: nil}, + } + for i, tt := range tests { + t.Run(fmt.Sprint(i), func(t *testing.T) { + got := hosts.hostIP(tt.host) + if !got.Equal(tt.want) { + t.Errorf("hostsMapIP() = %v, want %v", got, tt.want) + return + } + }) + } +} + +func Test_zoneHost(t *testing.T) { + type val struct { + name string + recordName string + } + tests := []struct { + host zoneHost + want val + }{ + {}, // test for empty value as well + {host: "sample", want: val{name: "sample"}}, + {host: "another.sample", want: val{name: "sample.", recordName: "another"}}, + {host: "another.sample.com", want: val{name: "com.", recordName: "another.sample"}}, + {host: "a.c", want: val{name: "c.", recordName: "a"}}, + {host: "a.b.c.d", want: val{name: "d.", recordName: "a.b.c"}}, + } + for i, tt := range tests { + t.Run(fmt.Sprint(i), func(t *testing.T) { + got := val{ + name: tt.host.name(), + recordName: tt.host.recordName(), + } + if got != tt.want { + t.Errorf("host = %+v, want %+v", got, tt.want) + return + } + }) + } +} + +func Test_extractZones(t *testing.T) { + equalZones := func(za, zb []types.Zone) bool { + find := func(list []types.Zone, name string) (types.Zone, bool) { + for _, z := range list { + if z.Name == name { + return z, true + } + } + return types.Zone{}, false + } + equal := func(a, b types.Zone) bool { + if a.Name != b.Name { + return false + } + if !a.DefaultIP.Equal(b.DefaultIP) { + return false + } + for i := range a.Records { + a, b := a.Records[i], b.Records[i] + if !a.IP.Equal(b.IP) { + return false + } + if a.Name != b.Name { + return false + } + } + + return true + } + + for _, a := range za { + b, ok := find(zb, a.Name) + if !ok { + return false + } + if !equal(a, b) { + return false + } + } + return true + } + + hosts := hostMap{ + "google.com": "8.8.4.4", + "local.google.com": "8.8.8.8", + "google.ae": "google.com", + "localhost": "127.0.0.1", + "host.lima.internal": "192.168.5.2", + "host.docker.internal": "host.lima.internal", + } + + tests := []struct { + wantZones []types.Zone + }{ + { + wantZones: []types.Zone{ + { + Name: "ae.", + Records: []types.Record{ + {Name: "google", IP: net.ParseIP("8.8.4.4")}, + }, + }, + { + Name: "com.", + Records: []types.Record{ + {Name: "google", IP: net.ParseIP("8.8.4.4")}, + {Name: "local.google", IP: net.ParseIP("8.8.8.8")}, + }, + }, + { + Name: "internal.", + Records: []types.Record{ + {Name: "host.docker", IP: net.ParseIP("192.168.5.2")}, + {Name: "host.lima", IP: net.ParseIP("192.168.5.2")}, + }, + }, + { + Name: "localhost", + DefaultIP: net.ParseIP("127.0.0.1"), + }, + }, + }, + } + + for i, tt := range tests { + t.Run(fmt.Sprint(i), func(t *testing.T) { + gotZones := extractZones(hosts) + for _, zone := range gotZones { + sort.Sort(recordSorter(zone.Records)) + } + sort.Sort(zoneSorter(gotZones)) + + if !equalZones(gotZones, tt.wantZones) { + t.Errorf("extractZones() = %+v, want %+v", gotZones, tt.wantZones) + } + }) + } +} + +var _ sort.Interface = (recordSorter)(nil) +var _ sort.Interface = (zoneSorter)(nil) + +type recordSorter []types.Record + +// Len implements sort.Interface +func (r recordSorter) Len() int { + return len(r) +} + +// Less implements sort.Interface +func (r recordSorter) Less(i int, j int) bool { + return r[i].Name < r[j].Name +} + +// Swap implements sort.Interface +func (r recordSorter) Swap(i int, j int) { + r[i], r[j] = r[j], r[i] +} + +type zoneSorter []types.Zone + +// Len implements sort.Interface +func (z zoneSorter) Len() int { + return len(z) +} + +// Less implements sort.Interface +func (z zoneSorter) Less(i int, j int) bool { + return z[i].Name < z[j].Name +} + +// Swap implements sort.Interface +func (z zoneSorter) Swap(i int, j int) { + z[i], z[j] = z[j], z[i] +} diff --git a/pkg/networks/usernet/gvproxy.go b/pkg/networks/usernet/gvproxy.go index 6a5f8eae4379..eb45bdbc72ee 100644 --- a/pkg/networks/usernet/gvproxy.go +++ b/pkg/networks/usernet/gvproxy.go @@ -11,8 +11,6 @@ import ( "strings" "time" - "github.com/lima-vm/lima/pkg/networks" - "github.com/balajiv113/fd" "github.com/containers/gvisor-tap-vsock/pkg/transport" "github.com/containers/gvisor-tap-vsock/pkg/types" @@ -28,6 +26,8 @@ type GVisorNetstackOpts struct { FdSocket string Endpoint string + Subnet string + Async bool DefaultLeases map[string]string @@ -40,13 +40,20 @@ var ( func StartGVisorNetstack(ctx context.Context, gVisorOpts *GVisorNetstackOpts) error { opts = gVisorOpts + ip, err := ParseSubnet(opts.Subnet) + if err != nil { + return err + } + gatewayIP := GatewayIP(ip) + leases := map[string]string{} if opts.DefaultLeases != nil { for k, v := range opts.DefaultLeases { leases[k] = v } } - leases[networks.SlirpGateway] = "5a:94:ef:e4:0c:df" + leases[gatewayIP] = "5a:94:ef:e4:0c:df" + // The way gvisor-tap-vsock implemented slirp is different from tradition SLIRP, // - GatewayIP handling all request, also answers DNS queries // - based on NAT configuration, gateway forwards and translates calls to host @@ -56,21 +63,21 @@ func StartGVisorNetstack(ctx context.Context, gVisorOpts *GVisorNetstackOpts) er config := types.Configuration{ Debug: false, MTU: opts.MTU, - Subnet: networks.SlirpNetwork, - GatewayIP: networks.SlirpDNS, + Subnet: opts.Subnet, + GatewayIP: gatewayIP, GatewayMacAddress: "5a:94:ef:e4:0c:dd", DHCPStaticLeases: leases, Forwards: map[string]string{}, DNS: []types.Zone{}, DNSSearchDomains: searchDomains(), NAT: map[string]string{ - networks.SlirpGateway: "127.0.0.1", + gatewayIP: "127.0.0.1", }, - GatewayVirtualIPs: []string{networks.SlirpGateway}, + GatewayVirtualIPs: []string{gatewayIP}, } groupErrs, ctx := errgroup.WithContext(ctx) - err := run(ctx, groupErrs, &config) + err = run(ctx, groupErrs, &config) if err != nil { return err } diff --git a/pkg/networks/usernet/recoincile.go b/pkg/networks/usernet/recoincile.go index 115bd9fe5341..a6131dc3522e 100644 --- a/pkg/networks/usernet/recoincile.go +++ b/pkg/networks/usernet/recoincile.go @@ -53,6 +53,11 @@ func Start(ctx context.Context, name string) error { return err } + subnet, err := SubnetCIDR(name) + if err != nil { + return err + } + err = lockutil.WithDirLock(usernetDir, func() error { self, err := os.Executable() if err != nil { @@ -61,7 +66,8 @@ func Start(ctx context.Context, name string) error { args := []string{"usernet", "-p", pidFile, "-e", endpointSock, "--listen-qemu", qemuSock, - "--listen", fdSock} + "--listen", fdSock, + "--subnet", subnet.String()} cmd := exec.CommandContext(ctx, self, args...) stdoutPath := filepath.Join(usernetDir, fmt.Sprintf("%s.%s.%s.log", "usernet", name, "stdout")) diff --git a/pkg/qemu/qemu_driver.go b/pkg/qemu/qemu_driver.go index a6c71b1897c6..3891fc7d12bb 100644 --- a/pkg/qemu/qemu_driver.go +++ b/pkg/qemu/qemu_driver.go @@ -101,7 +101,10 @@ func (l *LimaQemuDriver) Start(ctx context.Context) (chan error, error) { go func() { if usernetIndex := limayaml.FirstUsernetIndex(l.Yaml); usernetIndex != -1 { client := newUsernetClient(l.Yaml.Networks[usernetIndex].Lima) - err = client.ResolveAndForwardSSH(limayaml.MACAddress(l.Instance.Dir), l.SSHLocalPort) + err := client.ConfigureDriver(l.BaseDriver) + if err != nil { + l.qWaitCh <- err + } } }() return l.qWaitCh, nil @@ -251,7 +254,11 @@ func newUsernetClient(nwName string) *usernet.Client { if err != nil { return nil } - return usernet.NewClient(endpointSock) + subnet, err := usernet.Subnet(nwName) + if err != nil { + return nil + } + return usernet.NewClient(endpointSock, subnet) } func logPipeRoutine(r io.Reader, header string) { diff --git a/pkg/vz/vm_darwin.go b/pkg/vz/vm_darwin.go index 2d08e5e5915b..42aec600bd42 100644 --- a/pkg/vz/vm_darwin.go +++ b/pkg/vz/vm_darwin.go @@ -96,7 +96,7 @@ func startVM(ctx context.Context, driver *driver.BaseDriver) (*virtualMachineWra filesToRemove[pidFile] = struct{}{} logrus.Info("[VZ] - vm state change: running") - err := usernetClient.ResolveAndForwardSSH(limayaml.MACAddress(driver.Instance.Dir), driver.SSHLocalPort) + err := usernetClient.ConfigureDriver(driver) if err != nil { errCh <- err } @@ -133,17 +133,24 @@ func startUsernet(ctx context.Context, driver *driver.BaseDriver) (*usernet.Clie DefaultLeases: map[string]string{ networks.SlirpIPAddress: limayaml.MACAddress(driver.Instance.Dir), }, + Subnet: networks.SlirpNetwork, }) if err != nil { return nil, err } - return usernet.NewClient(endpointSock), nil + subnetIP, err := usernet.ParseSubnet(networks.SlirpNetwork) + return usernet.NewClient(endpointSock, subnetIP), nil } - endpointSock, err := usernet.Sock(driver.Yaml.Networks[firstUsernetIndex].Lima, usernet.EndpointSock) + nwName := driver.Yaml.Networks[firstUsernetIndex].Lima + endpointSock, err := usernet.Sock(nwName, usernet.EndpointSock) if err != nil { return nil, err } - return usernet.NewClient(endpointSock), nil + subnetIP, err := usernet.Subnet(nwName) + if err != nil { + return nil, err + } + return usernet.NewClient(endpointSock, subnetIP), nil } func createVM(driver *driver.BaseDriver) (*vz.VirtualMachine, error) {