From fd7a2773b0fb84e11967ab283e9766d9bdb2b6e8 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Fri, 13 Oct 2023 17:27:00 -0400 Subject: [PATCH] kola/qemuexec: allow changing guest network This is useful when you're nesting VMs and you want the first VM to be able to access the host. The default host address that QEMU assigns (e.g. 10.0.2.2, modifiable via the `host=...` netdev knob) doesn't always work because it's not actually an IP address owned by the host, but proxied by QEMU itself. So the source appears to come from localhost, but in some contexts (e.g. iSCSI), we need the host and the guest to agree that the same IP refers to the host. With this, one can start the first VM as usual (e.g. `cosa run`) and the second VM within with e.g. `cosa run --usernet-addr 10.0.3.0/24` and be able to talk back to the outer VM via the valid address 10.0.2.15. To be clear, this can all be done with passthrough QEMU args, so this is just about making it more convenient. --- mantle/cmd/kola/qemuexec.go | 7 +++++-- mantle/platform/machine/qemu/cluster.go | 4 ++-- mantle/platform/machine/qemuiso/cluster.go | 4 ++-- mantle/platform/qemu.go | 7 ++++++- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/mantle/cmd/kola/qemuexec.go b/mantle/cmd/kola/qemuexec.go index 134a1f53b2..93082545ef 100644 --- a/mantle/cmd/kola/qemuexec.go +++ b/mantle/cmd/kola/qemuexec.go @@ -73,6 +73,8 @@ var ( netboot string netbootDir string + + usernetAddr string ) const maxAdditionalNics = 16 @@ -102,6 +104,7 @@ func init() { cmdQemuExec.Flags().StringVarP(&sshCommand, "ssh-command", "x", "", "Command to execute instead of spawning a shell") cmdQemuExec.Flags().StringVarP(&netboot, "netboot", "", "", "Filepath to BOOTP program (e.g. PXELINUX/GRUB binary or iPXE script") cmdQemuExec.Flags().StringVarP(&netbootDir, "netboot-dir", "", "", "Directory to serve over TFTP (default: BOOTP parent dir). If specified, --netboot is relative to this dir.") + cmdQemuExec.Flags().StringVarP(&usernetAddr, "usernet-addr", "", "", "Guest IP network (QEMU default is '10.0.2.0/24')") } func renderFragments(fragments []string, c *conf.Conf) error { @@ -356,11 +359,11 @@ func runQemuExec(cmd *cobra.Command, args []string) error { if cpuCountHost { builder.Processors = -1 } - if usernet { + if usernet || usernetAddr != "" { h := []platform.HostForwardPort{ {Service: "ssh", HostPort: 0, GuestPort: 22}, } - builder.EnableUsermodeNetworking(h) + builder.EnableUsermodeNetworking(h, usernetAddr) } if netboot != "" { builder.SetNetbootP(netboot, netbootDir) diff --git a/mantle/platform/machine/qemu/cluster.go b/mantle/platform/machine/qemu/cluster.go index 6d2a82204b..28d159f015 100644 --- a/mantle/platform/machine/qemu/cluster.go +++ b/mantle/platform/machine/qemu/cluster.go @@ -175,12 +175,12 @@ func (qc *Cluster) NewMachineWithQemuOptions(userdata *conf.UserData, options pl } if len(options.HostForwardPorts) > 0 { - builder.EnableUsermodeNetworking(options.HostForwardPorts) + builder.EnableUsermodeNetworking(options.HostForwardPorts, "") } else { h := []platform.HostForwardPort{ {Service: "ssh", HostPort: 0, GuestPort: 22}, } - builder.EnableUsermodeNetworking(h) + builder.EnableUsermodeNetworking(h, "") } if options.AdditionalNics > 0 { builder.AddAdditionalNics(options.AdditionalNics) diff --git a/mantle/platform/machine/qemuiso/cluster.go b/mantle/platform/machine/qemuiso/cluster.go index b430bb35a6..9223192149 100644 --- a/mantle/platform/machine/qemuiso/cluster.go +++ b/mantle/platform/machine/qemuiso/cluster.go @@ -124,12 +124,12 @@ func (qc *Cluster) NewMachineWithQemuOptions(userdata *conf.UserData, options pl } if len(options.HostForwardPorts) > 0 { - builder.EnableUsermodeNetworking(options.HostForwardPorts) + builder.EnableUsermodeNetworking(options.HostForwardPorts, "") } else { h := []platform.HostForwardPort{ {Service: "ssh", HostPort: 0, GuestPort: 22}, } - builder.EnableUsermodeNetworking(h) + builder.EnableUsermodeNetworking(h, "") } if options.AdditionalNics > 0 { diff --git a/mantle/platform/qemu.go b/mantle/platform/qemu.go index 305cd5cc0f..3a15340505 100644 --- a/mantle/platform/qemu.go +++ b/mantle/platform/qemu.go @@ -478,6 +478,7 @@ type QemuBuilder struct { ignitionRendered bool UsermodeNetworking bool + usermodeNetworkingAddr string RestrictNetworking bool requestedHostForwardPorts []HostForwardPort additionalNics int @@ -599,9 +600,10 @@ func virtio(arch, device, args string) string { // EnableUsermodeNetworking configure forwarding for all requested ports, // via usermode network helpers. -func (builder *QemuBuilder) EnableUsermodeNetworking(h []HostForwardPort) { +func (builder *QemuBuilder) EnableUsermodeNetworking(h []HostForwardPort, usernetAddr string) { builder.UsermodeNetworking = true builder.requestedHostForwardPorts = h + builder.usermodeNetworkingAddr = usernetAddr } func (builder *QemuBuilder) SetNetbootP(filename, dir string) { @@ -637,6 +639,9 @@ func (builder *QemuBuilder) setupNetworking() error { if builder.RestrictNetworking { netdev += ",restrict=on" } + if builder.usermodeNetworkingAddr != "" { + netdev += ",net=" + builder.usermodeNetworkingAddr + } if builder.netbootP != "" { // do an early stat so we fail with a nicer error now instead of in the VM if _, err := os.Stat(filepath.Join(builder.netbootDir, builder.netbootP)); err != nil {