summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2026-10-07 19:56:39 +0200
committerChristian Breunig <christian@breunig.cc>2026-10-31 09:58:29 +0000
commite12776075f2dde8026f523e0d86f327bac7d398c (patch)
tree9f4f94e22d7aa752cef60536680077ce4591a7db /python
parentc73faac7f95ec837da6f964d15cc05ff9ffd2de6 (diff)
downloadvyos-1x-e12776075f2dde8026f523e0d86f327bac7d398c.tar.gz
vyos-1x-e12776075f2dde8026f523e0d86f327bac7d398c.zip
interfaces: T3871: remove the hw-id node and migrate its bindings
The node decides nothing now that the mapping store owns naming, and keeping it would leave two sources of truth free to disagree. Existing bindings are carried into the store by matching each hw-id against the permanent address of the hardware present, so a box named by an older release keeps exactly the names it had. Entries whose hardware is absent are skipped - the configuration may well originate from another machine. The hardware address of an interface is now read off the device rather than from the configuration.
Diffstat (limited to 'python')
-rw-r--r--python/vyos/ifconfig/ethernet.py1
-rw-r--r--python/vyos/ifconfig/ifname_store.py7
-rw-r--r--python/vyos/ifconfig/interface.py21
-rw-r--r--python/vyos/vpp/config_filter.py1
4 files changed, 20 insertions, 10 deletions
diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py
index ab5c8a0b8..41fd6a0b9 100644
--- a/python/vyos/ifconfig/ethernet.py
+++ b/python/vyos/ifconfig/ethernet.py
@@ -114,7 +114,6 @@ class EthernetIf(Interface):
'ring_buffer.rx',
'ring_buffer.tx',
'speed',
- 'hw_id',
]
return bond_allowed_sections
diff --git a/python/vyos/ifconfig/ifname_store.py b/python/vyos/ifconfig/ifname_store.py
index 0d10fd1ef..e6a0876fd 100644
--- a/python/vyos/ifconfig/ifname_store.py
+++ b/python/vyos/ifconfig/ifname_store.py
@@ -121,6 +121,13 @@ def permanent_mac(ifname: str, sys_class_net: str = '/sys/class/net') -> str:
return ''
+def recorded_mac(ifname: str) -> str:
+ """The address naming recorded for this name. It outlives a dataplane
+ taking the port over, which leaves nothing in sysfs to read it from.
+ """
+ return load_store().get('hardware', {}).get(ifname, '')
+
+
def is_wireless(ifname: str, sys_class_net: str = '/sys/class/net') -> bool:
"""Checked via sysfs, not via the - possibly still probe-order - name."""
return (Path(sys_class_net) / ifname / 'phy80211').exists()
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index 692875491..b00bbc18a 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -30,6 +30,8 @@ from vyos.configdict import list_diff
from vyos.configdict import dict_merge
from vyos.configdict import get_vlan_ids
from vyos.defaults import directories
+from vyos.ifconfig.ifname_store import permanent_mac
+from vyos.ifconfig.ifname_store import recorded_mac
from vyos.template import is_ipv4
from vyos.template import is_ipv6
from vyos.template import render
@@ -1823,9 +1825,8 @@ class Interface(Control):
from vyos.pki import load_certificate
from vyos.pki import wrap_private_key
- # The default is a fallback to hw_id which is not present for any interface
- # other then an ethernet interface. Thus we emulate hw_id by reading back the
- # Kernel assigned MAC address
+ # T3871: the template keys the identity off a MAC, which is no
+ # longer a configuration node - read it off the device
if 'hw_id' not in self.config:
self.config['hw_id'] = read_file(f'/sys/class/net/{self.ifname}/address')
render(wpa_supplicant_conf, 'ethernet/wpa_supplicant.conf.j2', self.config)
@@ -1884,12 +1885,16 @@ class Interface(Control):
# method to apply()?
self.config = config
- # Change interface MAC address - re-set to real hardware address (hw-id)
- # if custom mac is removed. Skip if bond member.
+ # A custom MAC wins; removing it restores the hardware address, which
+ # T3871 takes from what naming recorded rather than from a
+ # configuration node. A dataplane which has taken the port over leaves
+ # no device to read it from, so the record is what is left. Neither is
+ # there for a bridge or a tunnel, which is what keeps this a no-op for
+ # them. Skip if bond member.
if 'is_bond_member' not in config:
- mac = config.get('hw_id')
- if 'mac' in config:
- mac = config.get('mac')
+ mac = config.get('mac') or recorded_mac(self.ifname)
+ if not mac and os.path.exists(f'/sys/class/net/{self.ifname}/device'):
+ mac = permanent_mac(self.ifname)
if mac:
self.set_mac(mac)
diff --git a/python/vyos/vpp/config_filter.py b/python/vyos/vpp/config_filter.py
index f6b4aaff2..71c85cce1 100644
--- a/python/vyos/vpp/config_filter.py
+++ b/python/vyos/vpp/config_filter.py
@@ -33,7 +33,6 @@ def iface_filter_eth(config: Config, iface: str) -> None:
'dhcpv6-options',
'disable',
'eapol',
- 'hw-id',
'ip',
'ipv6',
'mac',