From 035d0260f65ad327c5a6a512a37157e96ca50fcf Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Wed, 7 Oct 2026 19:56:49 +0200 Subject: interfaces: T3871: name a card by the card, not only by the slot it sits in The map now records which card each name sat on. A card moved to another slot keeps its name rather than leaving it behind for whatever turns up next, and the slot it vacated does not lend that name out. Where the map and the hardware disagree, the map wins: a card the store already knows, found in a name's slot, takes that name. Only a card nothing knows about, sitting in a slot on record, is treated as a replacement - the one case which can quietly move a configured address onto another cable. --- python/vyos/ifconfig/ifname_store.py | 51 ++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 8 deletions(-) (limited to 'python') diff --git a/python/vyos/ifconfig/ifname_store.py b/python/vyos/ifconfig/ifname_store.py index 9c00810db..f2131a55a 100644 --- a/python/vyos/ifconfig/ifname_store.py +++ b/python/vyos/ifconfig/ifname_store.py @@ -314,7 +314,7 @@ def resolve(devices: list, store: dict) -> tuple: seen = store.get('hardware', {}) assigned = {} # final name -> device - report = {'matched': {}, 'bootstrapped': {}} + report = {'matched': {}, 'moved': {}, 'replaced': {}, 'bootstrapped': {}} # A recorded name stays off-limits even while its slot is empty, so new # hardware cannot inherit an absent interface's name and configuration. @@ -326,13 +326,53 @@ def resolve(devices: list, store: dict) -> tuple: report[bucket][name] = device['mac'] remaining.remove(device) - # whatever card occupies the recorded slot is this interface + # the recorded card in its recorded slot. A name with no card on record + # counts too - a store written before addresses were kept has nothing to + # disagree with, and this is as certain as it gets. for name, key in entries.items(): for device in remaining: - if device_matches(device['properties'], key): + if (device_matches(device['properties'], key) + and seen.get(name, device['mac']) == device['mac']): claim(device, name, 'matched') break + # a card the store already knows about, sitting in this name's slot. The + # cards were rearranged among themselves, or the map was edited by hand - + # either way the map is what decides names, so the slot wins and the + # address on record simply follows. + known = {mac for mac in seen.values() if mac} + for name, key in entries.items(): + if name in assigned: + continue + for device in remaining: + if (device_matches(device['properties'], key) + and device['mac'] in known): + claim(device, name, 'matched') + break + + # the card moved, and nothing the store knows took its place. Its address + # identifies it, so the name follows the card rather than being handed to + # a stranger that happens to have landed in the slot it left. + for name in entries: + if name in assigned or not seen.get(name): + continue + for device in remaining: + if device['mac'] == seen[name]: + claim(device, name, 'moved') + break + + # a different card in the recorded slot: an in-place replacement, or an + # unrelated card that happened to land there once the original was pulled. + # Nothing on the device tells those apart, so the slot decides and it is + # reported and warned about rather than taken silently. + for name, key in entries.items(): + if name in assigned: + continue + for device in remaining: + if device_matches(device['properties'], key): + claim(device, name, 'replaced') + break + # unknown hardware: lowest free name of its type, in hardware order for device in sorted(remaining, key=canonical_sort_key): name = _next_free(reserved | set(assigned), _prefix_for(device)) @@ -351,11 +391,6 @@ def resolve(devices: list, store: dict) -> tuple: if device['mac']: new_hardware[name] = device['mac'] - # a slot which kept its name but changed card hands that interface's - # addresses to different hardware - never silently - report['replaced'] = {name: mac for name, mac in report['matched'].items() - if seen.get(name) and seen[name] != mac} - plan = {device['name']: name for name, device in assigned.items() if device['name'] != name} -- cgit v1.2.3