Repository navigation
fix(sandbox): announce guest MAC changes via arp_notify - #409
Merged
Merged
Conversation
Cold boots attached eth0 without guest_mac, so virtio_net picked a random MAC. Guest images running systemd >= 242 with udevd rewrite such a MAC via 99-default.link (MACAddressPolicy=persistent) without a gratuitous ARP, and the host tap0 neighbour entry kept the boot MAC until it aged out; proxied connects hit the 5s timeout and returned 502 for up to ~40s. A configured MAC is exposed via VIRTIO_NET_F_MAC and reported as NET_ADDR_PERM, which udev leaves alone. Restore paths load the NIC from vm_state.bin and are unchanged. Closes kvcache-ai#407 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
|
✅ OpenCodeReview: Review complete: 0 finding(s) across 1 selected item(s). |
Replace the fixed guest MAC with sysctl.net.ipv4.conf.all.arp_notify=1 on the cold-boot kernel command line. When guest userspace changes eth0's MAC (systemd-udevd's MACAddressPolicy=persistent rewriting the random boot MAC, but also MACAddressPolicy=random or an explicit MACAddress=, which a fixed MAC does not prevent), the guest kernel now sends a gratuitous ARP and the host tap0 neighbour entry follows the new MAC immediately instead of going stale for ~40s. arp_notify is MAXCONF(all, dev), so all=1 covers eth0. The argument is appended in start_fresh rather than DEFAULT_BOOT_ARGS so it also applies when firecracker.boot_args is overridden. Restore and fork are unchanged. Closes kvcache-ai#407 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
yingdi-shan
approved these changes
Oct 22, 2026
yingdi-shan
left a comment
Collaborator
There was a problem hiding this comment.
LGTM. Thanks for your contribution!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
冷启动(
start_fresh)时在 kernel cmdline 的ip=参数之后追加sysctl.net.ipv4.conf.all.arp_notify=1,让 guest 内核在eth0的 MAC 变化时主动发 gratuitous ARP。同时在docs/src/internals/networking.md的 Address Plan 一节补充说明。本 PR 最初的版本是给
eth0配置固定的guest_mac。按 #407 里维护者的建议改为arp_notify,固定 MAC 的改动已撤回,网卡仍是guest_mac = None。对main的净改动只有一个常量、一行append_boot_arg和一段文档。Why
详见 #407,简述如下:
start_fresh添加eth0时没有guest_mac,guest 的 virtio_net 随机分配 MAC。pivot-init交给 systemd(>= 242)后,systemd-udevd按自带的99-default.link(MACAddressPolicy=persistent)把随机 MAC 改写掉,且不发 gratuitous ARP。tap0上169.254.0.21的 neighbour 表项仍指向启动时的 MAC,host 发往 guest 的帧被丢弃。proxy 的连接一直等到 5s connect timeout 后返回502,直到表项老化、重新解析为止(复现中约 43s)。arp_notify的取值是MAXCONF(all, dev),所以all=1对eth0生效。MAC 变化(NETDEV_CHANGEADDR)时 guest 内核发一个 gratuitous ARP,tap0上的表项立即被覆盖成新 MAC,不必等老化。相比固定 MAC:
MACAddressPolicy=random也会改写内核报告为NET_ADDR_PERM的 MAC;.link里显式写MACAddress=同样会改。Related issue
Closes #407
Scope and non-goals
start_fresh追加一个 boot arg。DEFAULT_BOOT_ARGS:配置文件不会叠加config/default.toml,自定义了firecracker.boot_args的部署也需要这个参数。tap0的 neighbour 参数,不往用户 rootfs 注入.link文件,也不加静态 neighbour 表项(理由见 bug(network): guest udev rewrites the random eth0 MAC on cold boot, stale host neighbour makes the proxy 502 for ~40s #407 的 Alternatives considered)。Design and behavior changes
ip=之后、custom extensionextraBootArgs之前,extension 仍可以追加或覆盖。arp_notify打开后,guest 在 link up 和 MAC 变化时各多发一个 gratuitous ARP。这些帧只出现在 slot 私有的 TAP 链路上。Compatibility and operations
firecracker.boot_args的部署同样生效。arp_notify为 1;已有快照不变。sysctl.*形式的 cmdline 需要 guest kernel >= 5.8(默认的vmlinux-6.1.175满足);更老的 guest 内核会忽略这个参数,行为与现在相同。Validation
make fmtmake clippymake test-unit(只跑了其中的cargo test -p agentenv --lib,见下)make -C services test(required whenservices/changes)maketargetCommands and results:
线上验证:在一个下游部署里,把一台节点换成包含此改动的构建做 canary,环境与 #407 相同(KVM,Firecracker
1.15.1-patch-v1,guest kernelvmlinux-6.1.175)。使用 #407 中的 Image A(Ubuntu 24.04,systemd 255),方法与 #407 一致:在 slot netns 里运行ip -timestamp monitor neigh,每 250 ms 请求一次/proxy/health。204之后 154×502(每次 5.00 s,约 43 s)204,最大 9 mstap0neighbourSTALE→FAILED→ 新 MACPROBE/FAILEDarp_notify(all / default / eth0)eth0addr_assign_typeNET_ADDR_SET,已被 udev 改写)修改后,guest 的
/proc/cmdline末尾为... ip=169.254.0.21::169.254.0.22:255.255.255.252:instance:eth0:off:<dns> sysctl.net.ipv4.conf.all.arp_notify=1。16 个并发沙箱的tap0表项都是同一模式:随机 MAC → udev 改写后的 MAC,切换间隔约 1 s。另外在同一台节点上做了一组只改
arp_notify的对照:在 guest 内用ip link set eth0 address ...(与 udev 同样走 rtnetlink)改 MAC。arp_notify=0时 39 s 内 156 次502(每次 5 s),表项经历STALE→PROBE→FAILED后才切到新 MAC;只把all设为 1、eth0保持 0 时,240 次全部204,最大 5 ms,表项立即被覆盖。Skipped checks and reasons:
make test-unit中需要 capability runner 的--ignored测试,以及 Rust 集成测试:本地没有运行(需要 root / KVM 环境)。改动只是一个 boot arg,已用上面的 canary 做了端到端验证。services/,也没有生成代码;不涉及性能。Risks and reviewer notes
sysctl.d把net.ipv4.conf.all.arp_notify显式设回 0,并且在 udev 改写 MAC 之前生效,这个修复就不起作用。默认的 systemd 发行版不会这样配置。src/sandbox/firecracker/sandbox.rs中start_fresh的append_boot_arg调用位置。Checklist