From ec23c669710a1f98fd1bd2095ffb861007374bda Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Wed, 23 Aug 2023 20:14:14 +0200 Subject: vrf: T5428: move helpers to common vyos.utils.network module Helper functions can and will be re-use din different code places. --- python/vyos/utils/network.py | 22 ++++++++++++++++++++++ src/conf_mode/vrf.py | 5 +++-- src/op_mode/neighbor.py | 5 +---- src/op_mode/vrf.py | 21 ++++----------------- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py index 3f9a3ef4b..2f181d8d9 100644 --- a/python/vyos/utils/network.py +++ b/python/vyos/utils/network.py @@ -36,6 +36,10 @@ def get_protocol_by_name(protocol_name): except socket.error: return protocol_name +def interface_exists(interface) -> bool: + import os + return os.path.exists(f'/sys/class/net/{interface}') + def interface_exists_in_netns(interface_name, netns): from vyos.utils.process import rc_cmd rc, out = rc_cmd(f'ip netns exec {netns} ip link show dev {interface_name}') @@ -43,6 +47,24 @@ def interface_exists_in_netns(interface_name, netns): return True return False +def get_vrf_members(vrf: str) -> list: + """ + Get list of interface VRF members + :param vrf: str + :return: list + """ + import json + from vyos.utils.process import cmd + if not interface_exists(vrf): + raise ValueError(f'VRF "{vrf}" does not exist!') + output = cmd(f'ip --json --brief link show master {vrf}') + answer = json.loads(output) + interfaces = [] + for data in answer: + if 'ifname' in data: + interfaces.append(data.get('ifname')) + return interfaces + def get_interface_vrf(interface): """ Returns VRF of given interface """ from vyos.utils.dict import dict_search diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py index be867b208..6ac79b9fa 100755 --- a/src/conf_mode/vrf.py +++ b/src/conf_mode/vrf.py @@ -28,6 +28,7 @@ from vyos.template import render from vyos.template import render_to_string from vyos.utils.dict import dict_search from vyos.utils.network import get_interface_config +from vyos.utils.network import interface_exists from vyos.utils.process import call from vyos.utils.process import cmd from vyos.utils.process import popen @@ -143,7 +144,7 @@ def verify(vrf): raise ConfigError(f'VRF "{name}" table id is mandatory!') # routing table id can't be changed - OS restriction - if os.path.isdir(f'/sys/class/net/{name}'): + if interface_exists(name): tmp = str(dict_search('linkinfo.info_data.table', get_interface_config(name))) if tmp and tmp != vrf_config['table']: raise ConfigError(f'VRF "{name}" table id modification not possible!') @@ -245,7 +246,7 @@ def apply(vrf): for name, config in vrf['name'].items(): table = config['table'] - if not os.path.isdir(f'/sys/class/net/{name}'): + if not interface_exists(name): # For each VRF apart from your default context create a VRF # interface with a separate routing table call(f'ip link add {name} type vrf table {table}') diff --git a/src/op_mode/neighbor.py b/src/op_mode/neighbor.py index 1edeb0045..8b3c45c7c 100755 --- a/src/op_mode/neighbor.py +++ b/src/op_mode/neighbor.py @@ -31,14 +31,11 @@ import sys import typing import vyos.opmode +from vyos.utils.network import interface_exists ArgFamily = typing.Literal['inet', 'inet6'] ArgState = typing.Literal['reachable', 'stale', 'failed', 'permanent'] -def interface_exists(interface): - import os - return os.path.exists(f'/sys/class/net/{interface}') - def get_raw_data(family, interface=None, state=None): from json import loads from vyos.utils.process import cmd diff --git a/src/op_mode/vrf.py b/src/op_mode/vrf.py index 1f0bbbaeb..51032a4b5 100755 --- a/src/op_mode/vrf.py +++ b/src/op_mode/vrf.py @@ -20,11 +20,11 @@ import sys import typing from tabulate import tabulate +from vyos.utils.network import get_vrf_members from vyos.utils.process import cmd import vyos.opmode - def _get_raw_data(name=None): """ If vrf name is not set - get all VRFs @@ -45,21 +45,6 @@ def _get_raw_data(name=None): return data -def _get_vrf_members(vrf: str) -> list: - """ - Get list of interface VRF members - :param vrf: str - :return: list - """ - output = cmd(f'ip --json --brief link show master {vrf}') - answer = json.loads(output) - interfaces = [] - for data in answer: - if 'ifname' in data: - interfaces.append(data.get('ifname')) - return interfaces if len(interfaces) > 0 else ['n/a'] - - def _get_formatted_output(raw_data): data_entries = [] for vrf in raw_data: @@ -67,7 +52,9 @@ def _get_formatted_output(raw_data): state = vrf.get('operstate').lower() hw_address = vrf.get('address') flags = ','.join(vrf.get('flags')).lower() - members = ','.join(_get_vrf_members(name)) + tmp = get_vrf_members(name) + if tmp: members = ','.join(get_vrf_members(name)) + else: members = 'n/a' data_entries.append([name, state, hw_address, flags, members]) headers = ["Name", "State", "MAC address", "Flags", "Interfaces"] -- cgit v1.2.3