Skip to content

[Bug Report] guest VM exits on first TX when its tap is down or was replaced (EIO from writev treated as fatal) #1239

Description

@rogelioRuiz

A guest VM exits permanently the first time a TX write to its tap fails with EIO. Any transient host-side condition that leaves the tap down (or replaced) at that moment kills the guest.

Repro (v0.6.0, x86_64, single-node k3s):

  1. Create a sandbox from a template with a memory snapshot (the resume path transmits within ~300ms of boot; a cold-boot guest reproduces too, just needs guest traffic).
  2. On the node, set the sandbox tap down before the guest transmits:
    ip link set z<sandbox-ip> down
    
  3. Guest transmits. /data/log/CubeVmm/vmm.log:
    net: tx: failed writing to tap: Input/output error (os error 5)
    Error running worker: HandleEvent(Error processing TX queue: NetQueuePair(WriteTap(Os { code: 5, ... })))
    VM exit event
    
    The VM is gone. From the API side the sandbox shows running briefly, then envd stops answering and the session is lost.

Where: hypervisor/net_util/src/queue_pair.rs, TxVirtio::process_desc_chain. EAGAIN is retried, but every other errno from writev returns NetQueuePairError::WriteTap, which tears down the net worker thread and exits the VM.

Why we hit it in production: an external tap GC on the node deleted idle pooled taps (NO-CARRIER, not bound to any sandbox — indistinguishable from leaked ones from outside network-agent). Two things then compound:

  1. network-agent GetTapFile hands out fds without checking the netdevice still exists or is up. TUNSETIFF on a deleted tap name does not fail — it silently creates a fresh admin-DOWN device with no TC filter/MTU/ARP, so the guest boots against a dead tap (network-agent/internal/service/tap_fd_provider.go, the openTapFdByName reopen path).
  2. The first guest TX gets EIO and the hypervisor kills the VM instead of dropping the frame.

Physical NICs drop frames when the link is down and the guest network stack retransmits; a transiently unready host tap should degrade to packet loss, not VM death.

Happy to send patches: (a) drop EIO'd TX frames (count + sampled log, keep EAGAIN retry and other errnos fatal), (b) verify the tap netdevice (exists / same ifindex / up, one netlink read per sandbox create) before every fd handoff in GetTapFile, (c) a --tap-init-num flag so the pool size (including 0) can be set without editing the packaged config.toml.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions