diff --git a/go.mod b/go.mod index 00041419209..10b50c24d65 100644 --- a/go.mod +++ b/go.mod @@ -139,3 +139,7 @@ require ( // We can't just `require` github.com/inetaf/tcpproxy, as gvisor-tap-vsock // still imports inet.af/tcpproxy: https://github.com/containers/gvisor-tap-vsock/pull/399 replace inet.af/tcpproxy => github.com/inetaf/tcpproxy v0.0.0-20240214030015-3ce58045626c + +// Nested virtualization support is yet to be merged into VZ https://github.com/Code-Hex/vz/pull/159. +// We use our (temporary) fork to add the feature. +replace github.com/Code-Hex/vz/v3 => github.com/lima-vm/vz/v3 v3.0.0-20241008080607-2a22b5e278ee diff --git a/go.sum b/go.sum index 1b45234ce3a..cf364951da5 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkk github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/Code-Hex/go-infinity-channel v1.0.0 h1:M8BWlfDOxq9or9yvF9+YkceoTkDI1pFAqvnP87Zh0Nw= github.com/Code-Hex/go-infinity-channel v1.0.0/go.mod h1:5yUVg/Fqao9dAjcpzoQ33WwfdMWmISOrQloDRn3bsvY= -github.com/Code-Hex/vz/v3 v3.1.0 h1:rcMIbZwPYwf78yXOhK68DZgYMdzxlrdmpDuM+NnGf1I= -github.com/Code-Hex/vz/v3 v3.1.0/go.mod h1:xUfvg1VJ5A6ZQNuzQERwXJ7l2ZdTnY6eCy9CIS6/DYQ= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= @@ -171,6 +169,8 @@ github.com/lima-vm/go-qcow2reader v0.1.2 h1:A9+h9Yg2oWDxmMlE2oJsdd+djaKk+Ge4hawv github.com/lima-vm/go-qcow2reader v0.1.2/go.mod h1:e3p29BzLT8hNh4jbLezdFAHU4eBijf0bm5GilStCRKE= github.com/lima-vm/sshocker v0.3.4 h1:5rn6vMkfqwZSZiBW+Udo505OIRhPB4xbLUDdEnFgWwI= github.com/lima-vm/sshocker v0.3.4/go.mod h1:QT4c7XNmeQTv79h5/8EgiS7U51B9BLenlXV7idCY0tE= +github.com/lima-vm/vz/v3 v3.0.0-20241008080607-2a22b5e278ee h1:USiLYd9WbmtU1mPM0egUMrz9QVpMkblMyKioC2EsWCA= +github.com/lima-vm/vz/v3 v3.0.0-20241008080607-2a22b5e278ee/go.mod h1:WqWQuBbT4SbjO4C4GHG9m9HO8j5jecAmMh4eyVSEbEg= github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 h1:DZMFueDbfz6PNc1GwDRA8+6lBx1TB9UnxDQliCqR73Y= github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2/go.mod h1:SWzULI85WerrFt3u+nIm5F9l7EvxZTKQvd0InF3nmgM= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go index 2ba3534b7ca..ae39921d519 100644 --- a/pkg/limayaml/defaults.go +++ b/pkg/limayaml/defaults.go @@ -735,6 +735,16 @@ func FillDefault(y, d, o *LimaYAML, filePath string) { y.Rosetta.BinFmt = ptr.Of(false) } + if y.NestedVirtualization == nil { + y.NestedVirtualization = d.NestedVirtualization + } + if o.NestedVirtualization != nil { + y.NestedVirtualization = o.NestedVirtualization + } + if y.NestedVirtualization == nil { + y.NestedVirtualization = ptr.Of(false) + } + if y.Plain == nil { y.Plain = d.Plain } diff --git a/pkg/limayaml/defaults_test.go b/pkg/limayaml/defaults_test.go index dd40e667981..c5588c0813a 100644 --- a/pkg/limayaml/defaults_test.go +++ b/pkg/limayaml/defaults_test.go @@ -106,7 +106,8 @@ func TestFillDefault(t *testing.T) { CACertificates: CACertificates{ RemoveDefaults: ptr.Of(false), }, - Plain: ptr.Of(false), + NestedVirtualization: ptr.Of(false), + Plain: ptr.Of(false), } defaultPortForward := PortForward{ @@ -293,6 +294,8 @@ func TestFillDefault(t *testing.T) { BinFmt: ptr.Of(false), } + expect.NestedVirtualization = ptr.Of(false) + FillDefault(&y, &LimaYAML{}, &LimaYAML{}, filePath) assert.DeepEqual(t, &y, &expect, opts...) @@ -420,6 +423,7 @@ func TestFillDefault(t *testing.T) { Enabled: ptr.Of(true), BinFmt: ptr.Of(true), }, + NestedVirtualization: ptr.Of(true), } expect = d @@ -634,6 +638,7 @@ func TestFillDefault(t *testing.T) { Enabled: ptr.Of(false), BinFmt: ptr.Of(false), }, + NestedVirtualization: ptr.Of(false), } y = filledDefaults @@ -690,6 +695,8 @@ func TestFillDefault(t *testing.T) { } expect.Plain = ptr.Of(false) + expect.NestedVirtualization = ptr.Of(false) + FillDefault(&y, &d, &o, filePath) assert.DeepEqual(t, &y, &expect, opts...) } diff --git a/pkg/limayaml/limayaml.go b/pkg/limayaml/limayaml.go index ee02018e3ff..b9fcb10c476 100644 --- a/pkg/limayaml/limayaml.go +++ b/pkg/limayaml/limayaml.go @@ -40,11 +40,12 @@ type LimaYAML struct { DNS []net.IP `yaml:"dns,omitempty" json:"dns,omitempty"` HostResolver HostResolver `yaml:"hostResolver,omitempty" json:"hostResolver,omitempty"` // `useHostResolver` was deprecated in Lima v0.8.1, removed in Lima v0.14.0. Use `hostResolver.enabled` instead. - PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty"` - CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"` - Rosetta Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"` - Plain *bool `yaml:"plain,omitempty" json:"plain,omitempty"` - TimeZone *string `yaml:"timezone,omitempty" json:"timezone,omitempty"` + PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty"` + CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"` + Rosetta Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"` + Plain *bool `yaml:"plain,omitempty" json:"plain,omitempty"` + TimeZone *string `yaml:"timezone,omitempty" json:"timezone,omitempty"` + NestedVirtualization *bool `yaml:"nestedVirtualization,omitempty" json:"nestedVirtualization,omitempty"` } type ( diff --git a/pkg/vz/vm_darwin.go b/pkg/vz/vm_darwin.go index 56faeec9ecb..fb7da0df5a2 100644 --- a/pkg/vz/vm_darwin.go +++ b/pkg/vz/vm_darwin.go @@ -15,6 +15,7 @@ import ( "syscall" "github.com/Code-Hex/vz/v3" + "github.com/coreos/go-semver/semver" "github.com/docker/go-units" "github.com/lima-vm/go-qcow2reader" "github.com/lima-vm/go-qcow2reader/image/raw" @@ -25,6 +26,7 @@ import ( "github.com/lima-vm/lima/pkg/nativeimgutil" "github.com/lima-vm/lima/pkg/networks" "github.com/lima-vm/lima/pkg/networks/usernet" + "github.com/lima-vm/lima/pkg/osutil" "github.com/lima-vm/lima/pkg/store" "github.com/lima-vm/lima/pkg/store/filenames" "github.com/sirupsen/logrus" @@ -234,6 +236,27 @@ func attachPlatformConfig(driver *driver.BaseDriver, vmConfig *vz.VirtualMachine if err != nil { return err } + + // nested virt + if *driver.Instance.Config.NestedVirtualization { + macOSProductVersion, err := osutil.ProductVersion() + if err != nil { + return fmt.Errorf("failed to get macOS product version: %w", err) + } + + if macOSProductVersion.LessThan(*semver.New("15.0.0")) { + return errors.New("nested virtualization requires macOS 15 or newer") + } + + if !vz.IsNestedVirtualizationSupported() { + return errors.New("nested virtualization is not supported on this device") + } + + if err := platformConfig.SetNestedVirtualizationEnabled(true); err != nil { + return fmt.Errorf("cannot enable nested virtualization: %w", err) + } + } + vmConfig.SetPlatformVirtualMachineConfiguration(platformConfig) return nil } diff --git a/pkg/vz/vz_driver_darwin.go b/pkg/vz/vz_driver_darwin.go index 28fa8560b74..0668f7e9cbd 100644 --- a/pkg/vz/vz_driver_darwin.go +++ b/pkg/vz/vz_driver_darwin.go @@ -40,6 +40,7 @@ var knownYamlProperties = []string{ "Mounts", "MountType", "MountInotify", + "NestedVirtualization", "Networks", "OS", "Param",