Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vyos_net_name: T5603: rework the helper not to use biosdevname #3821

Draft
wants to merge 1 commit into
base: current
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ Depends:
at,
rsync,
vyatta-bash,
vyatta-biosdevname,
vyatta-cfg,
vyos-http-api-tools,
vyos-utils,
Expand Down
77 changes: 21 additions & 56 deletions src/helpers/vyos_net_name
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import time
import logging
import logging.handlers
import tempfile

from pathlib import Path
from sys import argv

Expand All @@ -30,18 +31,17 @@ from vyos.utils.boot import boot_configuration_complete
from vyos.utils.locking import Lock
from vyos.migrate import ConfigMigrate


# Define variables
vyos_udev_dir = directories['vyos_udev_dir']
config_path = '/opt/vyatta/etc/config/config.boot'


def is_available(intfs: dict, intf_name: str) -> bool:
"""Check if interface name is already assigned"""
if intf_name in list(intfs.values()):
return False
return True


def find_available(intfs: dict, prefix: str) -> str:
"""Find lowest indexed iterface name that is not assigned"""
index_list = [
Expand All @@ -55,7 +55,6 @@ def find_available(intfs: dict, prefix: str) -> str:

return f'{prefix}{len(index_list)}'


def mod_ifname(ifname: str) -> str:
"""Check interface with names eX and return ifname on the next format eth{ifindex} - 2"""
if re.match('^e[0-9]+$', ifname):
Expand All @@ -68,33 +67,6 @@ def mod_ifname(ifname: str) -> str:

return ifname


def get_biosdevname(ifname: str) -> str:
"""Use legacy vyatta-biosdevname to query for name

This is carried over for compatability only, and will likely be dropped
going forward.
XXX: This throws an error, and likely has for a long time, unnoticed
since vyatta_net_name redirected stderr to /dev/null.
"""
intf = mod_ifname(ifname)

if 'eth' not in intf:
return intf
if os.path.isdir('/proc/xen'):
return intf

time.sleep(1)

try:
biosname = cmd(f'/sbin/biosdevname --policy all_ethN -i {ifname}')
except Exception as e:
logger.error(f'biosdevname error: {e}')
biosname = ''

return intf if biosname == '' else biosname


def leave_rescan_hint(intf_name: str, hwid: str):
"""Write interface information reported by udev

Expand All @@ -116,7 +88,6 @@ def leave_rescan_hint(intf_name: str, hwid: str):
except OSError as e:
logger.critical(f'OSError {e}')


def get_configfile_interfaces() -> dict:
"""Read existing interfaces from config file"""
interfaces: dict = {}
Expand All @@ -136,7 +107,7 @@ def get_configfile_interfaces() -> dict:
config = ConfigTree(config_file)
except Exception:
try:
logger.debug('updating component version string syntax')
logger.debug('Updating component version string syntax')
# this will update the component version string syntax,
# required for updates 1.2 --> 1.3/1.4
with tempfile.NamedTemporaryFile() as fp:
Expand All @@ -161,12 +132,12 @@ def get_configfile_interfaces() -> dict:
for intf in eth_intfs:
path = base + [intf, 'hw-id']
if not config.exists(path):
logger.warning(f"no 'hw-id' entry for {intf}")
logger.warning(f"No 'hw-id' entry for {intf}")
continue
hwid = config.return_value(path)
if hwid in list(interfaces):
logger.warning(
f'multiple entries for {hwid}: {interfaces[hwid]}, {intf}'
f'Multiple entries for {hwid}: {interfaces[hwid]}, {intf}'
)
continue
interfaces[hwid] = intf
Expand All @@ -177,21 +148,20 @@ def get_configfile_interfaces() -> dict:
for intf in wlan_intfs:
path = base + [intf, 'hw-id']
if not config.exists(path):
logger.warning(f"no 'hw-id' entry for {intf}")
logger.warning(f"No 'hw-id' entry for {intf}")
continue
hwid = config.return_value(path)
if hwid in list(interfaces):
logger.warning(
f'multiple entries for {hwid}: {interfaces[hwid]}, {intf}'
f'Multiple entries for {hwid}: {interfaces[hwid]}, {intf}'
)
continue
interfaces[hwid] = intf

logger.debug(f'config file entries: {interfaces}')
logger.debug(f'Config file entries: {interfaces}')

return interfaces


def add_assigned_interfaces(intfs: dict):
"""Add interfaces found by previous invocation of udev rule"""
if not os.path.isdir(vyos_udev_dir):
Expand All @@ -207,38 +177,31 @@ def add_assigned_interfaces(intfs: dict):
continue
intfs[hwid] = intf


def on_boot_event(intf_name: str, hwid: str, predefined: str = '') -> str:
def on_boot_event(intf_name: str, hwid: str, newname: str) -> str:
"""Called on boot by vyos-router: 'coldplug' in vyatta_net_name"""
logger.info(f'lookup {intf_name}, {hwid}')
logger.info(f'Looking up {intf_name}, {hwid}')
interfaces = get_configfile_interfaces()
logger.debug(f'config file interfaces are {interfaces}')
logger.debug(f'Config file interfaces are {interfaces}')

if hwid in list(interfaces):
logger.info(f"use mapping from config file: '{hwid}' -> '{interfaces[hwid]}'")
logger.info(f"Using the mapping from the config file: '{hwid}' -> '{interfaces[hwid]}'")
return interfaces[hwid]

add_assigned_interfaces(interfaces)
logger.debug(f'adding assigned interfaces: {interfaces}')
logger.debug(f'Adding assigned interfaces: {interfaces}')

if predefined:
newname = predefined
logger.info(f"predefined interface name for '{intf_name}' is '{newname}'")
else:
newname = get_biosdevname(intf_name)
logger.info(f"biosdevname returned '{newname}' for '{intf_name}'")
logger.info(f"Predefined interface name for '{intf_name}' is '{newname}'")

if not is_available(interfaces, newname):
prefix = re.sub(r'\d+$', '', newname)
newname = find_available(interfaces, prefix)

logger.info(f"new name for '{intf_name}' is '{newname}'")
logger.info(f"The new name for '{intf_name}' is '{newname}'")

leave_rescan_hint(newname, hwid)

return newname


def hotplug_event():
# Not yet implemented, since interface-rescan will only be run on boot.
pass
Expand All @@ -257,20 +220,22 @@ if __name__ == '__main__':
logger.debug(f'Started with arguments: {argv}')

if len(argv) > 3:
intf_name = argv[1]
hwid = argv[2]
predef_name = argv[3]
else:
predef_name = ''
raise RuntimeError('vyos_net_name helper called without required arguments')

lock = Lock('vyos_net_name')
# Wait 60 seconds for other running scripts to finish
lock.acquire(60)

if not boot_configuration_complete():
res = on_boot_event(argv[1], argv[2], predefined=predef_name)
logger.debug(f'on boot, returned name is {res}')
res = on_boot_event(intf_name, hwid, predef_name)
logger.debug(f'Processed an on-boot event for {intf_name}, assigned name is {res}')
print(res)
else:
logger.debug('boot configuration complete')
logger.debug(f'Called outside of boot-time configuration, exiting')

lock.release()
logger.debug('Finished')
Loading