Summary
After upgrading a Proxmox VM from VyOS Stream 2026.03 to current rolling, all ethernet interfaces come up under new names and the existing interfaces ethernet eth0/eth1 configuration no longer applies to any NIC. Remote access is lost.
The VM's NICs have locally administered MACs (Proxmox random MACs). By design, vyos-interface-rescan.py never writes hw-id for these, because is_persistent() rejects them. Before the T3871 rework, this was harmless: the NICs kept their kernel names (eth0, eth1, eth2), which are stable on Proxmox.
The new vyos-net-name-resolve.py treats every ethernet node without hw-id as a "pending" node (the "NIC replaced, hw-id deleted" case). It reserves those names and only reclaims them when there is exactly one pending node and exactly one candidate NIC. With two or more NICs, nothing is reclaimed. The NICs are then given new names that skip the reserved ones, and the config is orphaned.
Environment
- Hypervisor: Proxmox VE, KVM, machine type i440fx, SeaBIOS
- 3x virtio-net NICs with locally administered MACs:
- net0: 62:e3:ae:73:55:76 (eth0, WAN1)
- net1: ea:f1:f4:95:28:21 (eth1, WAN2)
- net2: 12:71:b5:eb:7e:75 (eth2, unconfigured)
- Upgrade path: VyOS Stream 2026.03 -> current rolling (October 2026)
Steps to reproduce
- Create a KVM VM with 2 or more virtio NICs using random (locally administered) MACs.
- Install VyOS Stream 2026.03 (or any image predating the T3871 rework) and configure:
set interfaces ethernet eth0 address 192.0.2.1/29 set interfaces ethernet eth0 description WAN1 set interfaces ethernet eth1 address 192.0.2.9/29 set interfaces ethernet eth1 description WAN2 commit; save
- Confirm that config.boot contains no hw-id for any ethernet interface. This is expected, because rescan skips locally administered MACs.
- Run add system image <current rolling>, then reboot into it.
Expected behaviour
The NICs keep the names eth0, eth1 and eth2, as they did on every boot and upgrade before, and the existing configuration applies.
Actual behaviour
After rebooting into the new image, the ethernet interfaces are effectively recreated. The NICs appear under new interface names with no configuration, and the existing eth0 and eth1 configuration (addresses, descriptions, MTU) is no longer applied to any physical interface. Both WAN links go down and the router is unreachable until the configuration is fixed from the console.
Root cause analysis
In src/system/vyos-net-name-resolve.py:
- get_configfile_interfaces() returns {}, because no node has hw-id.
- get_pending_hwid_nodes() returns {'ethernet': {'eth0', 'eth1'}}.
- match_pending_nodes() sees 2 pending nodes and 3 candidates. This is not 1:1, so it matches nothing.
- compute_bootstrap_plan() reserves eth0 and eth1 (reserved_pending) and assigns the 3 NICs the next free names, ordered by (pcie_distance, MAC). Per the code, the result would be 12:71:... -> eth2, 62:e3:... -> eth3, ea:f1:... -> eth4.
- sync_rescan_hints() leaves hints, but vyos-interface-rescan.py filters these MACs through is_persistent(), so hw-id is never written. The same misnaming therefore repeats on every subsequent boot. It is not a one-off on upgrade.
The resolver cannot tell apart two kinds of node without hw-id:
(a) "hw-id deliberately deleted after a NIC replacement" (the intended pending case), and (b) "hw-id never written because VyOS itself declined to persist a non-persistent MAC".
Case (b) is the default state of any Proxmox/KVM VM with random MACs and more than one configured NIC.
The state after boot can be confirmed in /run/vyos-net-name-resolve.json (eth0 and eth1 under pending_unresolved) and in the journal (the "not unambiguous, leaving pending rather than guessing" warning from match_pending_nodes()).
Suggested fix
Any of:
- If a candidate NIC's current kernel name equals a pending node name and its MAC fails is_persistent(), leave it on that name. The kernel name is the only identity such a NIC has ever had.
- If no hw-id is configured at all, keep the legacy behaviour: do not reserve pending names, and leave kernel names unchanged.
- Share is_persistent() between rescan and resolve, so the resolver never expects a hw-id that rescan will refuse to write.
Workaround
Pin hw-id manually before upgrading:
set interfaces ethernet eth0 hw-id 62:e3:ae:73:55:76 set interfaces ethernet eth1 hw-id ea:f1:f4:95:28:21 set interfaces ethernet eth2 hw-id 12:71:b5:eb:7e:75 commit; save
Related
T3871 (vyos-1x PR #5350, #5405), T2476 (locally administered MACs intentionally not written as hw-id), T9127, T9141