Skip to content

Commit 1f4ba2b

Browse files
committed
feat(vm): --net tap — attach qemu to a pre-created host TAP (bridged/routed)
Spec.Tap + 'vm run --net tap --tap <ifname>' emit '-netdev tap,id=net0,ifname=<tap>,script=no, downscript=no' instead of user-mode SLIRP; the macOS virtio-net front-end is unchanged (guest just re-DHCPs off the bridge). This is the by-name attach side of the cocoon networking design — same forwarding plane as cocoon's CH/FC VMs when the TAP is on the same bridge/CNI. Darwin-safe (pure qemu args, no netlink). Phase 3a; importing cocoon's network/bridge to AUTO-create the TAP (netlink, linux-only) is the follow-up wiring.
1 parent cd6ac30 commit 1f4ba2b

3 files changed

Lines changed: 22 additions & 3 deletions

File tree

cmd/vm/commands.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,6 @@ func addVMFlags(cmd *cobra.Command) {
9797
cmd.Flags().String("ovmf-vars", "", "OVMF_VARS template (copied per-VM)")
9898
cmd.Flags().Bool("random-smbios", false, "inject a unique Apple SMBIOS identity per VM (serial/MLB/UUID/ROM)")
9999
cmd.Flags().String("vnc-password", "", "set a VNC password (≤8 chars) so macOS Screen Sharing can connect (QEMU password auth)")
100+
cmd.Flags().String("net", "user", "network mode: user (SLIRP + --ssh-port hostfwd) | tap (bridged/routed via --tap)")
101+
cmd.Flags().String("tap", "", "pre-created host TAP ifname for --net tap (e.g. attached to a bridge / cocoon CNI)")
100102
}

cmd/vm/handler.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ type record struct {
7171
MAC string `json:"mac,omitempty"`
7272
SMBIOS *qemu.SMBIOS `json:"smbios,omitempty"`
7373
VNCPass string `json:"vnc_password,omitempty"`
74+
NetMode string `json:"net_mode,omitempty"`
75+
Tap string `json:"tap,omitempty"`
7476
}
7577

7678
func stateDir(cmd *cobra.Command) string {
@@ -148,9 +150,15 @@ func (h *Handler) create(cmd *cobra.Command, image string) (*record, error) {
148150
vnc, _ := cmd.Flags().GetInt("vnc")
149151
ssh, _ := cmd.Flags().GetInt("ssh-port")
150152
vncPass, _ := cmd.Flags().GetString("vnc-password")
153+
netMode, _ := cmd.Flags().GetString("net")
154+
tap, _ := cmd.Flags().GetString("tap")
155+
if netMode == "tap" && tap == "" {
156+
return nil, fmt.Errorf("--net tap requires --tap <ifname>")
157+
}
151158
r := &record{
152159
Name: name, Image: image, ImageDigest: digest, Disk: overlay, OpenCore: oc, OVMFCode: code, OVMFVars: ovmfVars,
153-
CPUs: cpus, Memory: mem, VNCDisp: vnc, SSHPort: ssh, VNCPass: vncPass, Created: time.Now().Format(time.RFC3339),
160+
CPUs: cpus, Memory: mem, VNCDisp: vnc, SSHPort: ssh, VNCPass: vncPass, NetMode: netMode, Tap: tap,
161+
Created: time.Now().Format(time.RFC3339),
154162
}
155163
if random, _ := cmd.Flags().GetBool("random-smbios"); random {
156164
if err := assignSMBIOS(dir, oc, r); err != nil {
@@ -184,6 +192,9 @@ func (h *Handler) launch(dir string, r *record) error {
184192
CPUs: r.CPUs, Memory: r.Memory, VNCDisp: r.VNCDisp, SSHPort: r.SSHPort, MAC: r.MAC, VNCPass: r.VNCPass,
185193
MonSock: filepath.Join(dir, "monitor.sock"), QMPSock: filepath.Join(dir, "qmp.sock"),
186194
}
195+
if r.NetMode == "tap" {
196+
spec.Tap = r.Tap
197+
}
187198
pidfile := filepath.Join(dir, "qemu.pid")
188199
args := append(spec.Args(), "-daemonize", "-pidfile", pidfile)
189200
c := exec.Command("qemu-system-x86_64", args...)

qemu/launch.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type Spec struct {
2828
QMPSock string // optional QMP unix socket
2929
MAC string // optional guest NIC MAC (set to the SMBIOS ROM for --random-smbios)
3030
VNCPass string // optional VNC password (enables QEMU password auth; set via monitor after launch)
31+
Tap string // optional pre-created host TAP ifname; set => bridged/routed (-netdev tap) instead of user-mode
3132
}
3233

3334
// Args returns the qemu-system-x86_64 argument vector for the macOS guest.
@@ -52,9 +53,14 @@ func (s Spec) Args() []string {
5253
"-device", "ide-hd,bus=sata.4,drive=MacHDD",
5354
"-device", "vmware-svga",
5455
}
55-
if s.SSHPort > 0 {
56+
switch {
57+
case s.Tap != "":
58+
// attach to a pre-created host TAP (cocoon's network plane / a bridge owns IP+forwarding);
59+
// the macOS virtio-net front-end is unchanged, the guest just re-DHCPs off the bridge
60+
a = append(a, "-netdev", "tap,id=net0,ifname="+s.Tap+",script=no,downscript=no")
61+
case s.SSHPort > 0:
5662
a = append(a, "-netdev", fmt.Sprintf("user,id=net0,hostfwd=tcp::%d-:22", s.SSHPort))
57-
} else {
63+
default:
5864
a = append(a, "-netdev", "user,id=net0")
5965
}
6066
nic := "virtio-net-pci,netdev=net0,id=net0"

0 commit comments

Comments
 (0)