Files
slocker-lite/docs
ceamac ad30f93f77 Retry container-side tap device setup, external process only
A user's log from the real target device showed nsenter'd `ip addr
add ... dev eth0` failing with "Cannot find device" immediately after
network_tap_relay.h's relay had already created it -- confirmed by
hand that retrying the whole session a few times eventually worked.

join_one_network() now retries (bounded, ~500ms, quiet until final
success/give-up) the three steps that touch the just-created container
interface -- IPv4 address, IPv6 address, bringing it up -- via a new
run_with_retry() instead of plain run().

A tempting first fix was investigated and ruled out by direct A/B
testing, not just reasoned about: having the relay itself self-verify
the device is visible (a same-process check, immediately after
creating it, before ever reporting success) was tried first, in
relay_child_main(). It made things categorically worse: the
container-side device became permanently invisible to every external
nsenter afterward, 100% reproducibly (confirmed with a 10-second retry
budget -- never once became visible), on a mechanism that had
otherwise worked correctly and instantly, zero retries needed, on
every real session tested earlier the same day -- including a
from-scratch self-test reproduction that had passed reliably many
times before this one change, and immediately went back to passing
once it was reverted. Root cause not fully understood (something about
forking a subprocess that inherits the tap fd -- deliberately not
O_CLOEXEC -- while still holding it open, immediately after device
creation, appears to corrupt the device's external visibility on this
kernel specifically), but the fix is unambiguous: never add an
internal, same-process/fd-holding self-check to the relay; only the
external, separate-process retry is safe.

network_tap_relay.cpp ends up completely unchanged -- the actual fix
lives entirely in network_join.cpp's own retry. self_test.cpp's own
container-visibility check needed the same external retry treatment,
for the same underlying reason.

Verified as root via the doas rule: three separate real --no-veth
sessions all succeeded getting eth0 on the first attempt (no retries
triggered), and the self-test passes reliably across repeated runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
2026-08-30 19:26:39 +00:00
..