Skip to content

fix(firecracker): refuse a colliding tap name instead of silently sharing one - #201

Merged
Shine-neko merged 1 commit into
mainfrom
fix/microvm-tap-collision
Jul 25, 2026
Merged

fix(firecracker): refuse a colliding tap name instead of silently sharing one#201
Shine-neko merged 1 commit into
mainfrom
fix/microvm-tap-collision

Conversation

@Shine-neko

Copy link
Copy Markdown
Contributor

Tap names are derived from a 14-bit hash of the instance id, so two instances can land on the same network slot. The documented consequence was that the second VM would fail to bring its tap up and crash-loop. That is not what happens: TUNSETIFF on an existing interface name succeeds and reuses it. Two guests would end up sharing one tap and one host IP, with nothing reported, and tearing one VM down would delete the other's interface out from under a running workload.

TapDevice::create now refuses a name that already exists, turning silent corruption into a plain boot failure that names the interface and the remedy.

Refusing alone would have made things worse. TapDevice::delete is best-effort — it gives up on EPERM and after exhausting its EBUSY retries — so a teardown can leave an interface behind, and that leftover would then block every future boot hashing to the same slot: a rare silent collision traded for a permanent outage. So a boot first reclaims a tap that exists but belongs to no live instance.

Ownership is established two ways, and a reclaim needs both to agree:

  • the socket directory, which is Ring's inventory of what exists;
  • a /proc scan re-deriving each live firecracker process' tap from its --api-sock argument, which covers a running VM whose socket file was removed.

Anything that cannot be inspected counts as in use. On a host with hidepid the reclaim simply does not happen and the operator gets the manual remedy — failing to reclaim costs one boot, deleting a live VM's interface breaks a running workload.

Two limits worth stating. If the interface is still present after the reclaim attempt (EPERM, no CAP_NET_ADMIN), the boot still fails; a warning now says so explicitly, since create's message alone would read as a hash collision. And the existence check is not atomic with TUNSETIFF — Ring boots instances sequentially within a reconcile tick, so it is not reachable today, but it would need revisiting if boots ever run in parallel.

Cloud Hypervisor is untouched: the VMM creates its own taps there, so Ring does not gate them. That remains a known limitation, now documented in host_net alongside the Firecracker behaviour.

Tests

772 unit tests pass (6 new); cargo fmt and cargo clippy --all-targets are clean. The new tests cover the refusal, the cross-deployment instance inventory, the ownership lookup that protects a live VM, and the cmdline parsing the /proc check relies on. The tap creation path itself needs CAP_NET_ADMIN and is only exercised by the e2e suite, which does not run in CI.

@Shine-neko
Shine-neko merged commit 3ff5248 into main Jul 25, 2026
5 checks passed
@Shine-neko
Shine-neko deleted the fix/microvm-tap-collision branch July 25, 2026 06:52
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.

1 participant