summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorl0crian1 <ryan.claridge13@gmail.com>2025-08-24 18:27:15 -0400
committerl0crian1 <ryan.claridge13@gmail.com>2025-08-24 18:27:15 -0400
commit5176bb18f499f614e24a119fa360fcde9240cbac (patch)
tree0a9a451452b7e1706f03bfc7d27140c7c25a98af
parent9886da9143f5b12e5ef4b10e155639b8c6bfc3be (diff)
downloadvyos-1x-5176bb18f499f614e24a119fa360fcde9240cbac.tar.gz
vyos-1x-5176bb18f499f614e24a119fa360fcde9240cbac.zip
T7741: Fixes for 'show interfaces kernel'
- Added dict_set_nested helper to set a value in a nested dictionary - Modified get_interface_vrf to accept string or dict as argument - Simplified logic using new helper functions
-rw-r--r--python/vyos/utils/dict.py34
-rw-r--r--python/vyos/utils/network.py5
-rwxr-xr-xsrc/op_mode/interfaces.py35
3 files changed, 58 insertions, 16 deletions
diff --git a/python/vyos/utils/dict.py b/python/vyos/utils/dict.py
index ff21f0677..a43430eed 100644
--- a/python/vyos/utils/dict.py
+++ b/python/vyos/utils/dict.py
@@ -211,6 +211,39 @@ def dict_set(key_path, value, dict_object):
dynamic_dict = dynamic_dict[path_list[i]]
dynamic_dict[path_list[len(path_list)-1]] = value
+def dict_set_nested(key_path, value, dict_object):
+ """
+ Set value to Python dictionary (dict_object) using a path to the key
+ delimited by dot ('.'). The key will be added if it does not exist.
+ Missing keys along the path will be created as nested dictionaries.
+
+ Parameters
+ ----------
+ key_path : str
+ Dot-delimited path to the key (e.g. "this.is.a.path").
+ value : any
+ The value to set at the final key in the path.
+ dict_object : dict
+ Dictionary to modify. Will be updated in place.
+
+ Examples
+ --------
+ d = {}
+ dict_set_nested("this.is.a.path", 42, d)
+ # {'this': {'is': {'a': {'path': 42}}}}
+
+ d = {"existing": {"branch": {}}}
+ dict_set_nested("existing.branch.leaf", "value", d)
+ # {'existing': {'branch': {'leaf': 'value'}}}
+ """
+ path_list = key_path.split(".")
+ dynamic_dict = dict_object
+ for i in range(0, len(path_list) - 1):
+ if path_list[i] not in dynamic_dict or not isinstance(dynamic_dict[path_list[i]], dict):
+ dynamic_dict[path_list[i]] = {}
+ dynamic_dict = dynamic_dict[path_list[i]]
+ dynamic_dict[path_list[-1]] = value
+
def dict_delete(key_path, dict_object):
""" Delete key in Python dictionary (dict_object) using path to key delimited by dot (.).
"""
@@ -370,4 +403,3 @@ class FixedDict(dict):
if k not in self._allowed:
raise ConfigError(f'Option "{k}" has no defined default')
super().__setitem__(k, v)
-
diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py
index 0e2cc58cf..93f780d8b 100644
--- a/python/vyos/utils/network.py
+++ b/python/vyos/utils/network.py
@@ -81,7 +81,10 @@ def get_interface_vrf(interface):
""" Returns VRF of given interface """
from vyos.utils.dict import dict_search
from vyos.utils.network import get_interface_config
- tmp = get_interface_config(interface)
+ if isinstance(interface, str):
+ tmp = get_interface_config(interface)
+ elif isinstance(interface, dict):
+ tmp = interface
if dict_search('linkinfo.info_slave_kind', tmp) == 'vrf':
return tmp['master']
return 'default'
diff --git a/src/op_mode/interfaces.py b/src/op_mode/interfaces.py
index b6bbcbbc2..faeb846eb 100755
--- a/src/op_mode/interfaces.py
+++ b/src/op_mode/interfaces.py
@@ -29,8 +29,10 @@ import vyos.opmode
from vyos.ifconfig import Section
from vyos.ifconfig import Interface
from vyos.ifconfig import VRRP
-from vyos.utils.process import cmd
+from vyos.utils.dict import dict_set_nested
+from vyos.utils.network import get_interface_vrf
from vyos.utils.network import interface_exists
+from vyos.utils.process import cmd
from vyos.utils.process import rc_cmd
from vyos.utils.process import call
from vyos.configquery import op_mode_config_dict
@@ -334,11 +336,18 @@ def _format_kernel_data(data, detail):
# Sort interfaces by name
for interface in sorted(data, key=lambda x: x.get('ifname', '')):
+ interface_name = interface.get('ifname', '')
+
+ # Skip VRF interfaces
if interface.get('linkinfo', {}).get('info_kind') == 'vrf':
continue
- elif interface.get('ifname').startswith(('tunl', 'gre', 'erspan', 'pim6reg')):
+ # Skip spawned interfaces
+ elif interface_name.startswith(('tunl', 'gre', 'erspan', 'pim6reg')):
continue
+ master = interface.get('master', 'default')
+ vrf = get_interface_vrf(interface)
+
# Get the device model; ex. Intel Corporation Ethernet Controller I225-V
dev_model = interface.get('parentdev', '')
if 'parentdev' in interface:
@@ -349,7 +358,6 @@ def _format_kernel_data(data, detail):
# Get the IP addresses on interface
ip_list = []
has_global = False
- vrf = 'default'
for ip in interface['addr_info']:
if ip.get('scope') in ('global', 'host'):
@@ -358,25 +366,24 @@ def _format_kernel_data(data, detail):
prefixlen = ip.get('prefixlen', '')
ip_list.append(f"{local}/{prefixlen}")
- if interface.get('ifname').startswith('pod-'):
- podman_vrf[interface.get('ifname')] = {}
- podman_vrf[interface.get('ifname')]['vrf'] = interface.get('master', 'default')
-
- if interface.get('master', '').startswith('pod-'):
- vrf = podman_vrf.get(interface.get('master', '')).get('vrf', 'default')
- elif interface.get('linkinfo', {}).get('info_slave_kind', '') == 'vrf':
- vrf = interface.get('master', 'default')
-
# If no global IP address, add '-'; indicates no IP address on interface
if not has_global:
ip_list.append('-')
+ # Generate a mapping of podman interfaces to their VRF
+ if interface_name.startswith('pod-'):
+ dict_set_nested(f'{interface_name}.vrf', master, podman_vrf)
+
+ # If the veth interface's master is a podman interface, the VRF is the VRF of the podman interface
+ if master.startswith('pod-'):
+ vrf = podman_vrf.get(master).get('vrf', 'default')
+
sl_status = ('A' if not 'UP' in interface['flags'] else 'u') + '/' + ('D' if interface['operstate'] == 'DOWN' else 'u')
# Generate temporary dict to hold data
- tmpInfo['ifname'] = interface.get('ifname', '')
+ tmpInfo['ifname'] = interface_name
tmpInfo['ip'] = ip_list
- tmpInfo['mac'] = interface.get('address', 'n/a') if is_interface_has_mac(interface.get('ifname', '')) else 'n/a'
+ tmpInfo['mac'] = interface.get('address', 'n/a') if is_interface_has_mac(interface_name) else 'n/a'
tmpInfo['mtu'] = interface.get('mtu', '')
tmpInfo['vrf'] = vrf
tmpInfo['status'] = sl_status