mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[GH-ISSUE #407] bug(network): guest udev rewrites the random eth0 MAC on cold boot, stale host neighbour makes the proxy 502 for ~40s #105
Labels
No labels
bug
documentation
enhancement
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/AgentENV#105
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @dushulin on GitHub (Oct 21, 2026).
Original GitHub issue: https://github.com/kvcache-ai/AgentENV/issues/407
Summary
On a cold boot, AgentENV attaches
eth0without aguest_mac, so the guest kernel assigns a random MAC. Images that boot systemd (>= 242) withsystemd-udevdthen rewrite that MAC through the stock99-default.link(MACAddressPolicy=persistent). No gratuitous ARP is sent. The host neighbour entry for the VM IP ontap0keeps pointing at the boot-time MAC. Host-to-guest frames are dropped until the guest happens to ARP on its own, or the host entry ages out and is re-resolved.During that window every proxied connection to the sandbox hits the proxy's 5 s connect timeout and returns
502. This happens even though the sandbox was created successfully and had already answered requests. In our reproduction the window lasted about 43 s.Affected component
Firecracker runtime / Network
Environment and verification scope
a27b2db.virtualization_mode = "kvm", Firecracker1.15.1-patch-v1and guest kernelvmlinux-6.1.175(both thedeps_manifest.tomldefaults).pivot-inithand-off ends in systemd as PID 1.How it showed up
502s clustered strictly by image.systemd-udev-trigger.Reproduction (Image A, single sandbox, normalized)
Setup:
ip -timestamp monitor neighrunning in the slot netns.GET /proxy/healthwithe2b-sandbox-id: <id>ande2b-sandbox-port: 49983, sent to the node's API port.t=0is when the create request returned.PUT /network-interfaces/eth0 {"host_dev_name":"tap0","iface_id":"eth0"}(noguest_mac)virtio_net virtio3: Assigned random MAC address <boot-mac>tap0:169.254.0.21 lladdr <boot-mac> REACHABLE204(~1 ms)99-default.link; eth0 becomes<persistent-mac>502, eachtime_total= 5.00 s169.254.0.21 lladdr <boot-mac> STALE(aged out, still the old MAC)PROBE→FAILED→ broadcast re-resolve →lladdr <persistent-mac> REACHABLE204againGuest state afterwards:
Image A only emits mDNS multicast after boot and never ARPs its gateway. The host therefore has to wait for its neighbour entry to age out.
Image B rewrites the MAC the same way: the result is deterministic, derived from the image's machine-id plus
eth0. However, its guest ARPs the gateway 0.7–5.7 s after the rewrite. The host then learns the new MAC (asSTALEwith the new lladdr), and in our runs the window was usually too short to observe a502. Whether a given image is affected depends on whether its guest sends unicast traffic soon after udev runs.Root cause
start_freshattaches eth0 withguest_mac: None. Firecracker therefore does not offerVIRTIO_NET_F_MAC, and virtio_net falls back to a random MAC (addr_assign_type = NET_ADDR_RANDOM). TheNonehas been there since the initial open-source release, so this is not a regression.pivot-initexecs the image's own init after envd is up. For systemd images this startssystemd-udevd.MACAddressPolicy=persistentalso applies to interfaces whose MAC isNET_ADDR_RANDOM. Upstream treats this as intended behaviour (see systemd/systemd#21185), and the logic is unchanged through current releases. A MAC reported asNET_ADDR_PERMis left alone.arp_notify=0). The host keeps unicasting to the old MAC, the guest drops those frames, and SYNs from the proxy are lost. The proxy connect timeout is 5 s, so each attempt ends in502.retrans_time_mstuning ontap0only shortens the final probe phase. TheREACHABLE→STALE→DELAYtime still dominates.Restore and fork paths do not seem to be affected:
vm_state.binwith only ahost_dev_nameoverride. The guest keeps whatever MAC it already had.tap0loses carrier and the kernel flushes its neighbour entries; we observed this asDeleted 169.254.0.21 dev tap0 ...events. A restored guest is therefore resolved again by broadcast ARP.Expected behavior
Once create has returned and envd has answered, the sandbox should stay reachable through the proxy regardless of which init system or udev rules the user image ships.
Proposed fix
Pass a fixed, locally administered unicast MAC (for example
02:fc:00:00:00:05) asguest_macinstart_fresh.VIRTIO_NET_F_MAC, the guest reportsNET_ADDR_PERM, andMACAddressPolicy=persistentleaves the MAC unchanged.tap0and a fixed VM IP (NetworkAddressPlan::vm_ip), so the MAC is only visible on that private link.guest_mac). Firecracker's own CI rootfs works around this by masking99-default.link(resources/chroot.shin firecracker-microvm/firecracker#5364).Compatibility:
Alternatives considered:
tap0: shrinks the window but does not remove it..linkoverride into the guest: intrusive to user rootfs.Proposed verification (not yet executed): cold-boot Image A with the change. Expect
addr_assign_type = 0, the MAC to equal the configured value, a single neighbour entry with no MAC change, and zero502s over a 90 s probe window.Reproduction frequency
Always for Image A; intermittent (race-dependent) for images whose guest ARPs soon after udev runs.
Pre-submission checklist
@dushulin commented on GitHub (Oct 21, 2026):
@yingdi-shan hi~PTAL, thanks
I can give a PR
@yingdi-shan commented on GitHub (Oct 21, 2026):
Maybe we can just set sysctl.net.ipv4.conf.all.arp_notify=1 in the guest kernel parameters to solve this problem?