Skip to content

fix: CNI guest MAC for macOS VMs - #26

Merged
CMGS merged 3 commits into
cocoonstack:masterfrom
czmDeRepository:codex/fix-cni-guest-mac
Aug 20, 2026
Merged

fix: CNI guest MAC for macOS VMs#26
CMGS merged 3 commits into
cocoonstack:masterfrom
czmDeRepository:codex/fix-cni-guest-mac

Conversation

@czmDeRepository

@czmDeRepository czmDeRepository commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Use the MAC address returned by CNI as the guest NIC MAC in --net cni mode.
  • Preserve the randomly generated SMBIOS ROM identity.
  • Keep user, TAP, and bridge networking behavior unchanged.
  • Update documentation and comments for the CNI-specific behavior.

Bug trigger path

  1. Create or run a macOS VM with --net cni --random-smbios.
  2. prepareOpenCore generates an SMBIOS identity and initially sets record.MAC from the SMBIOS ROM.
  3. CNI creates eth0 and returns its MAC in cfgs[0].MAC.
  4. The previous implementation preferred the populated record.MAC, discarding the CNI-provided MAC.
  5. When macspoofchk is enabled, frames whose source MAC does not match the address assigned to eth0 are dropped.
  6. QEMU therefore sent DHCP traffic with the wrong source MAC, preventing the guest from obtaining a LAN address.

Root cause

The CNI provider already returns the authoritative eth0 MAC through cfgs[0].MAC, but the existing code preferred the SMBIOS-derived value stored in record.MAC.

The SMBIOS ROM is a valid guest NIC MAC for user, TAP, and bridge networking. In CNI mode, the guest NIC must instead use the MAC assigned to eth0 when macspoofchk is enabled.

Fix

Use the CNI-provided MAC directly in CNI mode:

mac = cfgs[0].MAC
if r.NetMode != netCNI {
    mac = cmp.Or(r.MAC, mac)
}

Persist the selected MAC during network provisioning:

r.MAC = mac

This resolves the mismatch at creation time without launch-time namespace inspection, shell commands, or JSON parsing.

The resulting behavior is:

  • CNI mode uses the MAC assigned to CNI eth0.
  • User, TAP, and bridge modes continue to prefer the SMBIOS ROM MAC.
  • The SMBIOS ROM identity remains unchanged.
  • CNI clones receive their own CNI-assigned runtime MAC instead of reusing the source VM's MAC on the same L2 network.

Validation

Static checks

  • go test ./...
  • GOOS=linux go vet ./...
  • GOOS=darwin go vet ./...
  • CGO_ENABLED=0 go build ./...
  • git diff --check

Runtime validation

Confirmed that the target CNI configuration enables macspoofchk.

A real macOS VM was started with:

--net cni --random-smbios

The runtime validation confirmed that:

  • record.MAC matched the CNI namespace's eth0 MAC.
  • The QEMU guest NIC used the same MAC.
  • The macOS guest's en0 used the same MAC.
  • The SMBIOS ROM identity remained unchanged.
  • The matching nftables spoof-check allow rule was installed.
  • The guest successfully obtained a CNI/LAN address.
  • Authenticated SSH access to the guest succeeded.

The temporary validation VM and its networking resources were removed after the test.

Read the live eth0 MAC from the CNI network namespace before constructing the QEMU spec. This keeps guest frames aligned with the address allowed by macspoofchk while retaining the SMBIOS ROM identity.
cmgs-simular

This comment was marked as off-topic.

@CMGS
CMGS dismissed cmgs-simular’s stale review August 20, 2026 07:52

posted from the wrong account; re-posted below

@CMGS CMGS left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

direction is right — cocoon's own ch/fc contract is guest mac == eth0 mac (hypervisor/cloudhypervisor/create.go feeds cfg.MAC to the guest nic, clonehints tells users to set eth0 to nc.MAC), so macos should follow. but the fix re-implements a value cocoon already hands us, see inline. should shrink to ~4 lines.

two more things:

  • the root cause only bites with macspoofchk: true in the conflist; tc mirred doesn't care about src mac otherwise. please confirm the deployed conflist actually sets it, and do one real run before merge: --net cni --random-smbios → guest gets a tor ip + ssh works, nft list ruleset shows the spoofcheck rule. build/vet/tests aren't the acceptance here.
  • cocoon-vk in the pr body is an internal hostname, drop it.

fwiw build / vet linux+darwin / gofmt / tests all green on db11908.

Comment thread cmd/vm/net_linux.go Outdated
Comment thread cmd/vm/net_linux.go Outdated
Comment thread cmd/vm/lifecycle.go Outdated
Comment thread cmd/vm/lifecycle.go Outdated
Comment thread docs/networking.md Outdated
Comment thread cmd/vm/net_linux_test.go Outdated
@CMGS
CMGS merged commit 57a21cf into cocoonstack:master Aug 20, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants