From 2f8925d4397a4eaf40546ef0ea8ecf5a8d827833 Mon Sep 17 00:00:00 2001 From: Git Sagar Date: Thu, 23 Jul 2026 20:23:54 -0300 Subject: [PATCH] fix: race in parallel wan veth creation cross-wiring namespaces All wan.net.vmix@* instances created their veth pair with the same temporary peer name 'vhost' in the host namespace before moving it into their netns. Parallel starts at boot could steal each other's peer ends, pairing a host-side vn- with another namespace's vhost (mismatched /30s, dead links) or leaving the pair stranded in the host namespace. Use a per-namespace temporary name (vh-) and rename to vhost only after the move, making concurrent creation collision-free. Co-Authored-By: Claude Fable 5 --- nixos/networks/config.nix | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/nixos/networks/config.nix b/nixos/networks/config.nix index 37bf6a9..658b6ac 100644 --- a/nixos/networks/config.nix +++ b/nixos/networks/config.nix @@ -172,6 +172,10 @@ let let wanCfg = cfg // { spaceName = spaceName; }; vethInNSToHost.iface = "vhost"; + # Temporary peer name, unique per namespace. The peer briefly exists in the + # host namespace before being moved; a shared name ("vhost") lets parallel + # wan.net.vmix@* starts steal each other's peer ends, cross-wiring namespaces. + vethInNSToHost.tempIface = "vh-${wanCfg.spaceName}"; vethOnHostToNS.iface = "vn-${wanCfg.spaceName}"; vethOnHostToNS.ipv4.address = calc.cidr.host 1 wanCfg.ipv4.range; vethInNSToHost.ipv4.address = calc.cidr.host 2 wanCfg.ipv4.range; @@ -180,8 +184,9 @@ let portForwardRules = lib.concatStringsSep "\n" (lib.mapAttrsToList (hostIPnPort: nsPort: "iptables -t nat -A PREROUTING -p tcp --dport ${hostIPnPort} -j DNAT --to-destination ${vethInNSToHost.ipv4.address}:${toString nsPort}") wanCfg.forwardPorts); createWanCommands = '' - ip link add ${vethOnHostToNS.iface} type veth peer name ${vethInNSToHost.iface} - ip link set ${vethInNSToHost.iface} netns ${wanCfg.spaceName}.vmix + ip link add ${vethOnHostToNS.iface} type veth peer name ${vethInNSToHost.tempIface} + ip link set ${vethInNSToHost.tempIface} netns ${wanCfg.spaceName}.vmix + ip netns exec ${wanCfg.spaceName}.vmix ip link set ${vethInNSToHost.tempIface} name ${vethInNSToHost.iface} ip address add ${vethOnHostToNS.ipv4.address}/${networkPrefix} dev ${vethOnHostToNS.iface} ip netns exec ${wanCfg.spaceName}.vmix ip address add ${vethInNSToHost.ipv4.address}/${networkPrefix} dev ${vethInNSToHost.iface}