diff options
| -rw-r--r-- | python/vyos/vpp/config_verify.py | 29 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_vpp.py | 23 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_bonding.py | 9 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_bridge.py | 11 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_xconnect.py | 9 |
5 files changed, 66 insertions, 15 deletions
diff --git a/python/vyos/vpp/config_verify.py b/python/vyos/vpp/config_verify.py index c93a647f9..b32544a40 100644 --- a/python/vyos/vpp/config_verify.py +++ b/python/vyos/vpp/config_verify.py @@ -62,6 +62,35 @@ def verify_vpp_tunnel_source_address(config: dict): ) +def verify_member_conflicts(iface, config, current_type): + """ + Check that a member interface is not already used by another interface type. + + Args: + iface (str): interface name to check + config (dict): configuration dictionary + current_type (str): the membership type being assigned + to the interface ('bridge', 'bond', or 'xconn') + + Raises: + ConfigError: If the interface is already a member of a conflicting interface type. + """ + iface_type_map = { + 'bridge': 'bridge', + 'bond': 'bonding', + 'xconn': 'xconnect', + } + for iface_type, label in iface_type_map.items(): + if iface_type == current_type: + continue + members = config.get(f'{iface_type}_members', {}).get(iface) + if members: + raise ConfigError( + f'Interface {iface} cannot be a member of {iface_type_map[current_type]} ' + f'because it already belongs to {label} interface(s): {", ".join(members)}.' + ) + + def create_cpu_error_message(cpus_required: int, cpus_available: int = None) -> str: cpu_info = get_cpus() logical_cores = sum( diff --git a/smoketest/scripts/cli/test_vpp.py b/smoketest/scripts/cli/test_vpp.py index a98b5ff0b..108741790 100755 --- a/smoketest/scripts/cli/test_vpp.py +++ b/smoketest/scripts/cli/test_vpp.py @@ -543,6 +543,19 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): self.assertRegex(out, r'\s*eth1\s+\d+\s+\d+') self.assertRegex(out, r'\s*vxlan_tunnel23\s+\d+\s+\d+') + # Cannot add members of bridge interface to cross-connect + # expect raise ConfigError + self.cli_set( + interfaces_path + ['xconnect', 'vppxcon1', 'member', 'interface', interface] + ) + self.cli_set( + interfaces_path + + ['xconnect', 'vppxcon1', 'member', 'interface', interface_vxlan] + ) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(interfaces_path + ['xconnect']) + # Add Loopback BVI to the bridge self.cli_set(interfaces_path + ['loopback', f'vpplo{vni}']) self.cli_set( @@ -653,6 +666,16 @@ class TestVPP(VyOSUnitTestSHIM.TestCase): for required_string in required_str_list: self.assertIn(required_string, out) + # Cannot add members of cross-connect interface to bond/bridge + # expect raise ConfigError + self.cli_set( + interfaces_path + + ['bonding', 'vppbond1', 'member', 'interface', interface_vxlan] + ) + with self.assertRaises(ConfigSessionError): + self.cli_commit() + self.cli_delete(interfaces_path + ['bonding']) + # delete xconnect interface self.cli_delete(xconn_path + [interface_xconnect]) self.cli_commit() diff --git a/src/conf_mode/vpp_interfaces_bonding.py b/src/conf_mode/vpp_interfaces_bonding.py index 46252c635..51272c087 100644 --- a/src/conf_mode/vpp_interfaces_bonding.py +++ b/src/conf_mode/vpp_interfaces_bonding.py @@ -29,6 +29,7 @@ from vyos.ifconfig.vpp import VPPBondInterface from vyos.vpp.config_deps import deps_bond_dict from vyos.vpp.config_deps import deps_bridge_dict from vyos.vpp.config_deps import deps_xconnect_dict +from vyos.vpp.config_verify import verify_member_conflicts from vyos.vpp.config_verify import verify_vpp_remove_bridge_interface from vyos.vpp.config_verify import verify_vpp_remove_xconnect_interface from vyos.vpp.utils import cli_ifaces_list @@ -168,13 +169,7 @@ def verify(config): f'Interface {iface} cannot be a member of multiple bonding interfaces: {", ".join(bond_members)}' ) - # Interface cannot be a member of a bridge and a bond at the same time - bridge_members = config['bridge_members'].get(iface) - if bridge_members: - raise ConfigError( - f'Interface {iface} cannot be a member of a bond because ' - f'it already belongs to bridge interface: {", ".join(bridge_members)}.' - ) + verify_member_conflicts(iface, config, 'bond') if mtu := config.get('mtu'): mtu = int(mtu) diff --git a/src/conf_mode/vpp_interfaces_bridge.py b/src/conf_mode/vpp_interfaces_bridge.py index 162345e6e..25fad5e5b 100644 --- a/src/conf_mode/vpp_interfaces_bridge.py +++ b/src/conf_mode/vpp_interfaces_bridge.py @@ -24,6 +24,8 @@ from vyos.utils.process import is_systemd_service_active from vyos.ifconfig.vpp import VPPBridgeInterface from vyos.vpp.config_deps import deps_bond_dict from vyos.vpp.config_deps import deps_bridge_dict +from vyos.vpp.config_deps import deps_xconnect_dict +from vyos.vpp.config_verify import verify_member_conflicts def get_config(config=None) -> dict: @@ -67,6 +69,7 @@ def get_config(config=None) -> dict: config['bond_members'] = deps_bond_dict(conf) config['bridge_members'] = deps_bridge_dict(conf) + config['xconn_members'] = deps_xconnect_dict(conf) return config @@ -104,13 +107,7 @@ def verify(config): f'Interface {member} is added to more than one bridge: {", ".join(bridge_members)}' ) - # Interface cannot be a member of a bridge and a bond at the same time - bond_members = config['bond_members'].get(member) - if bond_members: - raise ConfigError( - f'Interface {member} cannot be a member of a bridge ' - f'because it already belongs to bonding interface: {", ".join(bond_members)}.' - ) + verify_member_conflicts(member, config, 'bridge') # Check if BVI is already defined, only one BVI per bridge domain is allowed if 'bvi' in member_config: diff --git a/src/conf_mode/vpp_interfaces_xconnect.py b/src/conf_mode/vpp_interfaces_xconnect.py index 090d913b0..91fa27c1b 100644 --- a/src/conf_mode/vpp_interfaces_xconnect.py +++ b/src/conf_mode/vpp_interfaces_xconnect.py @@ -22,7 +22,10 @@ from vyos.configdict import get_interface_dict from vyos.utils.process import is_systemd_service_active from vyos.ifconfig.vpp import VPPXconnectInterface +from vyos.vpp.config_deps import deps_bond_dict +from vyos.vpp.config_deps import deps_bridge_dict from vyos.vpp.config_deps import deps_xconnect_dict +from vyos.vpp.config_verify import verify_member_conflicts from vyos.vpp.utils import cli_ifaces_list @@ -59,6 +62,8 @@ def get_config(config=None) -> dict: if effective_config: config.update({'effective': effective_config}) + config['bond_members'] = deps_bond_dict(conf) + config['bridge_members'] = deps_bridge_dict(conf) config['xconn_members'] = deps_xconnect_dict(conf) config['vpp_ifaces'] = cli_ifaces_list(conf, 'candidate') @@ -78,7 +83,7 @@ def verify(config): if len(config.get('member', {}).get('interface')) != 2: raise ConfigError('Cross connect requires 2 members') - not_allowed_prefixes = ('vppbond', 'vppbridge', 'vpplo') + not_allowed_prefixes = ('vppbond', 'vppbr', 'vpplo') for iface in config.get('member', {}).get('interface', []): # Ensure the interface is allowed as xconnect member if iface.startswith(not_allowed_prefixes): @@ -94,6 +99,8 @@ def verify(config): f'Interface {iface} added to more than one xconnect: {", ".join(xconn_members)}' ) + verify_member_conflicts(iface, config, 'xconn') + def generate(config): pass |
