diff options
| author | Christian Breunig <christian@breunig.cc> | 2026-10-07 19:56:56 +0200 |
|---|---|---|
| committer | Christian Breunig <christian@breunig.cc> | 2026-10-31 09:58:29 +0000 |
| commit | 9d44e93638ccc189c99305b2b423222b2dab2b9c (patch) | |
| tree | 39bc22ec039c54cceec1e708c5a226391e604325 /python | |
| parent | 5d63400b3d5e7a95014577fdb3b18a78ac57cafe (diff) | |
| download | vyos-1x-9d44e93638ccc189c99305b2b423222b2dab2b9c.tar.gz vyos-1x-9d44e93638ccc189c99305b2b423222b2dab2b9c.zip | |
wwan: T3871: name a modem in the namespace the CLI reads
Anything that was not wireless was named ethN, so an LTE module came up as an
ethernet port: bound, working and invisible, because 'interfaces wwan' looks
at wwanN and nothing else.
Give it its own namespace, keyed on DEVTYPE, and drop what an earlier version
filed under an ethernet name - that entry still matches the modem by path and
would capture it again.
Diffstat (limited to 'python')
| -rw-r--r-- | python/vyos/ifconfig/ifname_store.py | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/python/vyos/ifconfig/ifname_store.py b/python/vyos/ifconfig/ifname_store.py index 2145b8ce0..eadd3994e 100644 --- a/python/vyos/ifconfig/ifname_store.py +++ b/python/vyos/ifconfig/ifname_store.py @@ -133,6 +133,18 @@ def is_wireless(ifname: str, sys_class_net: str = '/sys/class/net') -> bool: return (Path(sys_class_net) / ifname / 'phy80211').exists() +def is_wwan(ifname: str, sys_class_net: str = '/sys/class/net') -> bool: + """A modem, which the CLI addresses as wwanN. An ethernet port carries no + DEVTYPE at all, so this is exact - and it is the same property systemd + matches on in a .link file. + """ + try: + uevent = (Path(sys_class_net) / ifname / 'uevent').read_text() + except OSError: + return False + return 'DEVTYPE=wwan' in uevent.split() + + def read_properties(ifname: str) -> dict: """udev properties for an interface.""" try: @@ -183,6 +195,7 @@ def discover_devices(sys_class_net: str = '/sys/class/net') -> list: 'name': entry.name, 'mac': mac, 'wireless': is_wireless(entry.name, sys_class_net), + 'wwan': is_wwan(entry.name, sys_class_net), 'properties': read_properties(entry.name), }) @@ -303,6 +316,8 @@ def save_store(store: dict, path: Path = None) -> bool: def _prefix_for(device: dict) -> str: + if device.get('wwan'): + return 'wwan' return 'wlan' if device.get('wireless') else 'eth' @@ -323,6 +338,20 @@ def resolve(devices: list, store: dict) -> tuple: entries = store.get('interfaces', {}) seen = store.get('hardware', {}) + # a modem an earlier version filed under an ethernet name. The entry still + # matches it by path, so it would be captured again and stay invisible to + #'interfaces wwan' - drop it and let it be named as what it is. The name + # cannot be recognised on its own, and neither can the key: this one reads + # ID_NET_NAME_PATH=wwp..., but a device falling back to ID_PATH reads + # usb-... like anything else on that bus. + misfiled = {name for name, key in entries.items() + if not name.startswith('wwan') + and any(d.get('wwan') and device_matches(d['properties'], key) + for d in devices)} + if misfiled: + entries = {n: k for n, k in entries.items() if n not in misfiled} + seen = {n: m for n, m in seen.items() if n not in misfiled} + assigned = {} # final name -> device report = {'matched': {}, 'moved': {}, 'replaced': {}, 'bootstrapped': {}} @@ -412,6 +441,13 @@ LINK_DIR = Path('/etc/systemd/network') LINK_PREFIX = '10-vyos-' +def _link_type_for(name: str) -> str: + for prefix in ('wlan', 'wwan'): + if name.startswith(prefix): + return prefix + return 'ether' + + def render_link(name: str, key: str) -> str: """Render a systemd .link file body, matching on the stored property. @@ -424,7 +460,7 @@ def render_link(name: str, key: str) -> str: '# Generated by VyOS - do not edit.\n' "# Interface names are managed via 'interface-mapping.json'.\n" '[Match]\n' - f"Type={'wlan' if name.startswith('wlan') else 'ether'}\n" + f'Type={_link_type_for(name)}\n' f'Property={key}\n' '\n' '[Link]\n' |
