diff options
| author | Nataliia Solomko <natalirs1985@gmail.com> | 2025-03-03 15:41:27 +0200 |
|---|---|---|
| committer | Nataliia Solomko <natalirs1985@gmail.com> | 2025-03-12 13:54:38 +0200 |
| commit | 877166b8aef1132f5bad208aee00444819264501 (patch) | |
| tree | c4074aea2889cb1c543095b68b87cf36ca7f0030 | |
| parent | 7de0ab73af90d4d39519f3ba0dec80fb6b9badf5 (diff) | |
| download | vyos-1x-877166b8aef1132f5bad208aee00444819264501.tar.gz vyos-1x-877166b8aef1132f5bad208aee00444819264501.zip | |
T7189: VPP source of the tunnel interface should be checked and configured
Changed priority for VPP interfaces: all VPP interfaces must be configured after Ethernet interfaces
| -rw-r--r-- | interface-definitions/vpp.xml.in | 18 | ||||
| -rw-r--r-- | python/vyos/vpp/config_verify.py | 13 | ||||
| -rw-r--r-- | python/vyos/vpp/utils.py | 37 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_vpp.py | 67 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_gre.py | 11 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_ipip.py | 11 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_vxlan.py | 11 |
7 files changed, 151 insertions, 17 deletions
diff --git a/interface-definitions/vpp.xml.in b/interface-definitions/vpp.xml.in index 150803a0d..e9075588e 100644 --- a/interface-definitions/vpp.xml.in +++ b/interface-definitions/vpp.xml.in @@ -14,7 +14,7 @@ <children> <tagNode name="bonding" owner="${vyos_conf_scripts_dir}/vpp_interfaces_bonding.py"> <properties> - <priority>304</priority> + <priority>324</priority> <help>Bonding Interface/Link Aggregation</help> <constraint> <regex>bond[0-9]+</regex> @@ -112,7 +112,7 @@ </tagNode> <tagNode name="bridge" owner="${vyos_conf_scripts_dir}/vpp_interfaces_bridge.py"> <properties> - <priority>307</priority> + <priority>327</priority> <help>Bridge domain</help> <constraint> <!-- Bridge domain 0 is reserved to vpp default --> @@ -159,7 +159,7 @@ <!-- Disable as geneve interface index in the VPP always 0 and not configured --> <!-- <tagNode name="geneve" owner="${vyos_conf_scripts_dir}/vpp_interfaces_geneve.py"> <properties> - <priority>305</priority> + <priority>325</priority> <help>Generic Network Virtualization Encapsulation (GENEVE) Interface</help> <constraint> <regex>geneve[0-9]+</regex> @@ -179,7 +179,7 @@ <!-- </tagNode> --> <tagNode name="gre" owner="${vyos_conf_scripts_dir}/vpp_interfaces_gre.py"> <properties> - <priority>305</priority> + <priority>325</priority> <help>Generic Network Encapsulation (GRE) Interface</help> <constraint> <regex>gre[0-9]+</regex> @@ -246,7 +246,7 @@ </tagNode> <tagNode name="ipip" owner="${vyos_conf_scripts_dir}/vpp_interfaces_ipip.py"> <properties> - <priority>305</priority> + <priority>325</priority> <help>IP encapsulation tunnel interface</help> <constraint> <regex>ipip[0-9]+</regex> @@ -267,7 +267,7 @@ </tagNode> <tagNode name="loopback" owner="${vyos_conf_scripts_dir}/vpp_interfaces_loopback.py"> <properties> - <priority>305</priority> + <priority>325</priority> <help>Loopback Interface</help> <constraint> <regex>lo[0-9]+</regex> @@ -286,7 +286,7 @@ </tagNode> <tagNode name="vxlan" owner="${vyos_conf_scripts_dir}/vpp_interfaces_vxlan.py"> <properties> - <priority>305</priority> + <priority>325</priority> <help>Virtual Extensible LAN (VXLAN) Interface</help> <constraint> <regex>vxlan[0-9]+</regex> @@ -309,7 +309,7 @@ <tagNode name="xconnect" owner="${vyos_conf_scripts_dir}/vpp_interfaces_xconnect.py"> <properties> <help>Layer 2 cross connect</help> - <priority>305</priority> + <priority>325</priority> <constraint> <regex>xcon[0-9]+</regex> </constraint> @@ -845,7 +845,7 @@ <tagNode name="kernel-interfaces" owner="${vyos_conf_scripts_dir}/vpp_kernel-interfaces.py"> <properties> <help>VPP kernel interface settings</help> - <priority>308</priority> + <priority>328</priority> <valueHelp> <format>vpptapN</format> <description>Kernel interface name</description> diff --git a/python/vyos/vpp/config_verify.py b/python/vyos/vpp/config_verify.py index 6b35858d2..830d4af73 100644 --- a/python/vyos/vpp/config_verify.py +++ b/python/vyos/vpp/config_verify.py @@ -102,6 +102,19 @@ def verify_vpp_remove_xconnect_interface(config: dict): ) +def verify_vpp_tunnel_source_address(config: dict): + from vyos.utils.network import is_intf_addr_assigned + + address = config.get('source_address') + for iface in config.get('vpp_ether_vif_ifaces', []): + if is_intf_addr_assigned(iface, address): + return True + + raise ConfigError( + f'Source address "{address}" is not assigned on any Ethernet or VIF interface!' + ) + + def verify_dev_driver(iface_name: str, driver_type: str) -> bool: # Lists of drivers compatible with DPDK and XDP drivers_dpdk: list[str] = [ diff --git a/python/vyos/vpp/utils.py b/python/vyos/vpp/utils.py index 681d25578..fe08a98b8 100644 --- a/python/vyos/vpp/utils.py +++ b/python/vyos/vpp/utils.py @@ -85,6 +85,43 @@ def cli_ifaces_list(config_instance, mode: str = 'candidate') -> list[str]: return vpp_ifaces +def cli_ethernet_with_vifs_ifaces(config_instance) -> list[str]: + """List of all VPP Ethernet interfaces with VIFs + + Args: + config_instance (VyOS Config): VyOS Config instance + + Returns: + list[str]: list of interfaces + """ + from vyos.configdict import get_interface_dict + + # Read a config + config = config_instance.get_config_dict( + ['vpp'], + key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True, + with_recursive_defaults=True, + ) + + ifaces: list[str] = [] + + # Get a list of Ethernet interfaces + for iface in config.get('settings', {}).get('interface', {}).keys(): + ifaces.append(iface) + + # Add Ethernet interfaces with VIFs + for iface in ifaces: + _, iface_config = get_interface_dict( + config_instance, ['interfaces', 'ethernet'], ifname=iface + ) + ifaces.extend([f'{iface}.{vif}' for vif in iface_config.get('vif', {})]) + ifaces.extend([f'{iface}.{vif_s}' for vif_s in iface_config.get('vif_s', {})]) + + return ifaces + + def vpp_ifaces_list(vpp_api) -> list[dict]: """List interfaces in VPP diff --git a/smoketest/scripts/cli/test_vpp.py b/smoketest/scripts/cli/test_vpp.py index 6c19fbba0..57f47067a 100755 --- a/smoketest/scripts/cli/test_vpp.py +++ b/smoketest/scripts/cli/test_vpp.py @@ -106,6 +106,10 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): self.cli_delete(base_path) self.cli_commit() + # delete address for Ethernet interface + self.cli_delete(['interfaces', 'ethernet', interface, 'address']) + self.cli_commit() + self.assertFalse(os.path.exists(VPP_CONF)) self.assertFalse(process_named_running(PROCESS_NAME)) @@ -170,11 +174,21 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): base_path + ['interfaces', 'vxlan', interface_vxlan, 'source-address', source_address] ) + self.cli_set(base_path + ['interfaces', 'vxlan', interface_vxlan, 'vni', vni]) + + # remote and source address must not be the same + # expect raise ConfigError + self.cli_set( + base_path + + ['interfaces', 'vxlan', interface_vxlan, 'remote', source_address] + ) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_set( base_path + ['interfaces', 'vxlan', interface_vxlan, 'remote', remote_address] ) - self.cli_set(base_path + ['interfaces', 'vxlan', interface_vxlan, 'vni', vni]) self.cli_set( base_path + [ @@ -214,6 +228,23 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): new_source_address, ] ) + + # source address of the tunnel interface should be configured + # expect raise ConfigError + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set( + [ + 'interfaces', + 'ethernet', + interface, + 'vif', + vni, + 'address', + f'{new_source_address}/24', + ] + ) self.cli_commit() # check gre interface after update @@ -274,7 +305,11 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): self.assertFalse(os.path.isdir(f'/sys/class/net/{interface_kernel}')) # delete vxlan interface - self.cli_set(base_path + ['interfaces', 'vxlan', interface_vxlan]) + self.cli_delete(base_path + ['interfaces', 'vxlan', interface_vxlan]) + self.cli_commit() + + # delete vif Ethernet interface + self.cli_delete(['interfaces', 'ethernet', interface, 'vif']) self.cli_commit() def test_03_vpp_gre(self): @@ -302,6 +337,15 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): + ['kernel-interfaces', interface_kernel, 'address', f'{kernel_address}/31'] ) + # source address of the tunnel interface should be configured + # expect raise ConfigError + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set( + ['interfaces', 'ethernet', interface, 'address', f'{source_address}/24'] + ) + # commit changes self.cli_commit() @@ -319,6 +363,10 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): base_path + ['interfaces', 'gre', interface_gre, 'source-address', new_source_address] ) + + self.cli_set( + ['interfaces', 'ethernet', interface, 'address', f'{new_source_address}/24'] + ) self.cli_commit() # check gre interface after update @@ -364,7 +412,7 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): self.assertFalse(os.path.isdir(f'/sys/class/net/{interface_kernel}')) # delete gre interface - self.cli_set(base_path + ['interfaces', 'gre', interface_gre]) + self.cli_delete(base_path + ['interfaces', 'gre', interface_gre]) self.cli_commit() @unittest.skip('Skipping this test geneve index always is 0') @@ -566,7 +614,7 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): self.assertFalse(os.path.isdir(f'/sys/class/net/{interface_kernel}')) # delete loopback interface - self.cli_set(base_path + ['interfaces', 'loopback', interface_loopback]) + self.cli_delete(base_path + ['interfaces', 'loopback', interface_loopback]) self.cli_commit() @unittest.skip('Skipping temporary bonding, sometimes get recursion T7117') @@ -900,6 +948,15 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): new_source_address, ] ) + + # source address of the tunnel interface should be configured + # expect raise ConfigError + with self.assertRaises(ConfigSessionError): + self.cli_commit() + + self.cli_set( + ['interfaces', 'ethernet', interface, 'address', f'{new_source_address}/24'] + ) self.cli_commit() # check ipip interface after update @@ -951,7 +1008,7 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): self.assertFalse(os.path.isdir(f'/sys/class/net/{interface_kernel}')) # delete ipip interface - self.cli_set(base_path + ['interfaces', 'ipip', interface_ipip]) + self.cli_delete(base_path + ['interfaces', 'ipip', interface_ipip]) self.cli_commit() def test_09_vpp_xconnect(self): diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index de7398248..823f3ff4d 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -32,8 +32,9 @@ from vyos.vpp.config_verify import ( verify_vpp_change_kernel_interface, verify_vpp_remove_xconnect_interface, verify_vpp_exists_kernel_interface, + verify_vpp_tunnel_source_address, ) -from vyos.vpp.utils import cli_ifaces_lcp_kernel_list +from vyos.vpp.utils import cli_ifaces_lcp_kernel_list, cli_ethernet_with_vifs_ifaces def get_config(config=None) -> dict: @@ -94,6 +95,9 @@ def get_config(config=None) -> dict: # list of all kernel interfaces `vpp interface xxx kernel-interface xxx` config['candidate_kernel_interfaces'] = cli_ifaces_lcp_kernel_list(conf) + # list of all Ethernet interfaces with vifs + config['vpp_ether_vif_ifaces'] = cli_ethernet_with_vifs_ifaces(conf) + # Dependency config['xconn_members'] = deps_xconnect_dict(conf) if ifname in config['xconn_members']: @@ -130,6 +134,11 @@ def verify(config): f"Required options are missing: {', '.join(missing_keys).replace('_', '-')}" ) + # verify source address and remote address + verify_vpp_tunnel_source_address(config) + if config.get('source_address') == config.get('remote'): + raise ConfigError('Remote address must not be the same as source address') + # check multipoint mode if config.get('mode') == 'point-to-multipoint': # For multipoint mode, remote IP must be 0.0.0.0 diff --git a/src/conf_mode/vpp_interfaces_ipip.py b/src/conf_mode/vpp_interfaces_ipip.py index 2428a9850..c52e7c997 100644 --- a/src/conf_mode/vpp_interfaces_ipip.py +++ b/src/conf_mode/vpp_interfaces_ipip.py @@ -31,8 +31,9 @@ from vyos.vpp.config_verify import ( verify_vpp_change_kernel_interface, verify_vpp_remove_xconnect_interface, verify_vpp_exists_kernel_interface, + verify_vpp_tunnel_source_address, ) -from vyos.vpp.utils import cli_ifaces_lcp_kernel_list +from vyos.vpp.utils import cli_ifaces_lcp_kernel_list, cli_ethernet_with_vifs_ifaces def get_config(config=None) -> dict: @@ -93,6 +94,9 @@ def get_config(config=None) -> dict: # list of all kernel interfaces `vpp interface xxx kernel-interface xxx` config['candidate_kernel_interfaces'] = cli_ifaces_lcp_kernel_list(conf) + # list of all Ethernet interfaces with vifs + config['vpp_ether_vif_ifaces'] = cli_ethernet_with_vifs_ifaces(conf) + # Dependency config['xconn_members'] = deps_xconnect_dict(conf) if ifname in config['xconn_members']: @@ -130,6 +134,11 @@ def verify(config): f"Required options are missing: {', '.join(missing_keys).replace('_', '-')}" ) + # verify source address and remote address + verify_vpp_tunnel_source_address(config) + if config.get('source_address') == config.get('remote'): + raise ConfigError('Remote address must not be the same as source address') + # Change 'vpp interfaces ipip ipipX kernel-interface vpp-tunX' # => 'vpp interfaces ipip ipipX kernel-interface vpp-tunY' # check if we have kernel interface config 'vpp kernel-interface vpp-tunX' diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py index b94b39d6d..963cd90ec 100644 --- a/src/conf_mode/vpp_interfaces_vxlan.py +++ b/src/conf_mode/vpp_interfaces_vxlan.py @@ -33,8 +33,9 @@ from vyos.vpp.config_verify import ( verify_vpp_change_kernel_interface, verify_vpp_remove_xconnect_interface, verify_vpp_exists_kernel_interface, + verify_vpp_tunnel_source_address, ) -from vyos.vpp.utils import cli_ifaces_lcp_kernel_list +from vyos.vpp.utils import cli_ifaces_lcp_kernel_list, cli_ethernet_with_vifs_ifaces def get_config(config=None) -> dict: @@ -95,6 +96,9 @@ def get_config(config=None) -> dict: # list of all kernel interfaces `vpp interface xxx kernel-interface xxx` config['candidate_kernel_interfaces'] = cli_ifaces_lcp_kernel_list(conf) + # list of all Ethernet interfaces with vifs + config['vpp_ether_vif_ifaces'] = cli_ethernet_with_vifs_ifaces(conf) + # Dependency config['xconn_members'] = deps_xconnect_dict(conf) if ifname in config['xconn_members']: @@ -134,6 +138,11 @@ def verify(config): f"Required options are missing: {', '.join(missing_keys).replace('_', '-')}" ) + # verify source address and remote address + verify_vpp_tunnel_source_address(config) + if config.get('source_address') == config.get('remote'): + raise ConfigError('Remote address must not be the same as source address') + # Change 'vpp interfaces vxlan greX kernel-interface vpp-tunX' # => 'vpp interfaces gre vxlanX kernel-interface vpp-tunY' # check if we have kernel interface config 'vpp kernel-interface vpp-tunX' |
