Environment
- Hardware: Intel NUC6i7KYK, onboard NIC = Intel I219-LM (PCI, e1000e driver), secondary NIC = USB-C/Thunderbolt-attached Ethernet adapter
- VyOS: 2026.07.21-1151-rolling
- Both interfaces have explicit hw-id bindings in config.boot (eth0 bound to the onboard MAC, eth1 bound to the adapter MAC, both confirmed present)
Summary
After a reboot with both NICs connected, the onboard NIC failed to appear as eth0. It was invisible to show interfaces and stuck at a udev temporary name (e2) in ip link show. The same boot had worked correctly the boot before, with no config or image change in between. Root cause was traced via journalctl -b to a boot-time race, not a config problem.
Root cause
- With net.ifnames=0/biosdevname=0, the kernel assigns ethN names itself at device-registration time, on a simple first-available basis. This allocation is not synchronized with udev's own rename logic.
- VyOS renames interfaces to their persistent hw-id-bound name through a two-phase udev process. 62-temporary-interface-rename.rules renames a new device to a temp name (e<ifindex>), then 65-vyos-net.rules calls vyos_net_name <tempname> <mac>, which looks up the MAC in config.boot and returns the real name for udev to apply.
- USB/Thunderbolt enumeration timing varies from boot to boot. If the adapter's device registration happens in the brief window after the onboard NIC's eth0 name is freed (temp-renamed away) but before udev's final rename back to eth0 completes, the adapter can transiently grab the freed eth0 slot at the kernel level. The onboard NIC's subsequent rename-to-eth0 then collides and silently fails, even though vyos_net_name printed eth0 successfully. The script only decides the target name; it has no visibility into whether udev's actual rename succeeded. The onboard NIC is left permanently stuck on its temporary eN name until the next reboot.
- Separately, vyos_net_name crashes with an unhandled IndexError if invoked before a device's MAC address ($attr{address}) is populated in sysfs. This was observed for the adapter's first add event: USB NICs often populate their MAC asynchronously after device registration, via a control transfer. The script does on_boot_event(argv[1], argv[2], ...) with no bounds check, so a missing MAC arg crashes the process outright instead of retrying or failing gracefully.
Evidence (journalctl -b, filtered to vyos_net_name)
Jul 28 18:07:17 vyos vyos_net_name[814]: Started with arguments: ['/lib/udev/vyos_net_name', 'e2', '00:1f:c6:9b:e3:7a']
Jul 28 18:07:17 vyos vyos_net_name[824]: Started with arguments: ['/lib/udev/vyos_net_name', 'e3']
Jul 28 18:07:17 vyos vyos_net_name[814]: lookup e2, 00:1f:c6:9b:e3:7a
Jul 28 18:07:17 vyos vyos_net_name[814]: use mapping from config file: '00:1f:c6:9b:e3:7a' -> 'eth0'
Jul 28 18:07:17 vyos vyos_net_name[814]: on boot, returned name is eth0
Jul 28 18:07:17 vyos vyos_net_name[814]: Finished
Jul 28 18:07:18 vyos vyos_net_name[993]: Started with arguments: ['/lib/udev/vyos_net_name', 'eth0', '94:05:bb:1e:16:82']
Jul 28 18:07:18 vyos vyos_net_name[993]: use mapping from config file: '94:05:bb:1e:16:82' -> 'eth1'
Jul 28 18:07:18 vyos vyos_net_name[993]: Finished
PID 824 gets no arguments after the temp name (e3, no MAC) and produces no further log lines, meaning it crashed. PID 993, one second later, reports its current name as eth0 (the adapter momentarily holding the name the onboard NIC was also trying to claim), consistent with the collision described above.
Steps to reproduce
Not reliably deterministic. It depends on USB/Thunderbolt enumeration timing relative to onboard NIC udev processing. It occurred once in normal use (a working boot followed by a failing boot, with no changes in between), and was confirmed as boot-timing-dependent by rebooting with the USB/Thunderbolt adapter physically disconnected, which resolved it every time.
Expected behavior
Both interfaces reliably get their hw-id-bound names (eth0, eth1) on every boot, regardless of relative device-enumeration timing.
Actual behavior
The onboard NIC intermittently fails to be renamed to its configured name and is left on a udev temporary name (eN), invisible to show interfaces and unusable until the next reboot. Even then the fix isn't guaranteed, since the race is probabilistic.
Suggested directions for a fix
- Harden vyos_net_name against a missing or empty MAC argument (retry or defer rather than crashing).
- Consider whether the final MAC-to-name rename can be made atomic or collision-safe with respect to the kernel's own default ethN allocation. For example, always renaming through a guaranteed-unique intermediate name for every device before any final rename is attempted, rather than relying on a race-prone shared temp-name freeing and reclaiming window.