diff options
author | Daniil Baturin <daniil@vyos.io> | 2024-05-10 16:36:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-10 16:36:21 +0200 |
commit | d93aedfe993a6e9868ee88803c2dc981cabdfc15 (patch) | |
tree | 9d1977454f35746adc20df4f7c1b7739f176f3b6 | |
parent | 4960a67e12c1d10a59812f0167f017131a9617b5 (diff) | |
parent | bced1b4ef04f9e1a12c083c08839e4c1a54e2549 (diff) | |
download | vyos-1x-d93aedfe993a6e9868ee88803c2dc981cabdfc15.tar.gz vyos-1x-d93aedfe993a6e9868ee88803c2dc981cabdfc15.zip |
Merge pull request #3441 from vyos/mergify/bp/sagitta/pr-3410
Bond: T6303: add system mac address on interfaces bond (backport #3410)
-rw-r--r-- | interface-definitions/interfaces_bonding.xml.in | 12 | ||||
-rw-r--r-- | python/vyos/ifconfig/bond.py | 38 | ||||
-rw-r--r-- | python/vyos/utils/assertion.py | 4 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bonding.py | 28 | ||||
-rwxr-xr-x | src/conf_mode/interfaces_bonding.py | 11 |
5 files changed, 87 insertions, 6 deletions
diff --git a/interface-definitions/interfaces_bonding.xml.in b/interface-definitions/interfaces_bonding.xml.in index 92c0911db..e6baed590 100644 --- a/interface-definitions/interfaces_bonding.xml.in +++ b/interface-definitions/interfaces_bonding.xml.in @@ -176,6 +176,18 @@ </properties> <defaultValue>0</defaultValue> </leafNode> + <leafNode name="system-mac"> + <properties> + <help>System MAC address for 802.3ad</help> + <valueHelp> + <format>macaddr</format> + <description>MAC address</description> + </valueHelp> + <constraint> + <validator name="mac-address"/> + </constraint> + </properties> + </leafNode> <leafNode name="lacp-rate"> <properties> <help>Rate in which we will ask our link partner to transmit LACPDU packets</help> diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py index c6d0f1cff..b8ea90049 100644 --- a/python/vyos/ifconfig/bond.py +++ b/python/vyos/ifconfig/bond.py @@ -18,6 +18,7 @@ import os from vyos.ifconfig.interface import Interface from vyos.utils.dict import dict_search from vyos.utils.assertion import assert_list +from vyos.utils.assertion import assert_mac from vyos.utils.assertion import assert_positive @Interface.register @@ -54,6 +55,10 @@ class BondIf(Interface): 'validate': lambda v: assert_list(v, ['slow', 'fast']), 'location': '/sys/class/net/{ifname}/bonding/lacp_rate', }, + 'bond_system_mac': { + 'validate': lambda v: assert_mac(v, test_all_zero=False), + 'location': '/sys/class/net/{ifname}/bonding/ad_actor_system', + }, 'bond_miimon': { 'validate': assert_positive, 'location': '/sys/class/net/{ifname}/bonding/miimon' @@ -385,6 +390,24 @@ class BondIf(Interface): """ return self.set_interface('bond_mode', mode) + def set_system_mac(self, mac): + """ + In an AD system, this specifies the mac-address for the actor in + protocol packet exchanges (LACPDUs). The value cannot be NULL or + multicast. It is preferred to have the local-admin bit set for this + mac but driver does not enforce it. If the value is not given then + system defaults to using the masters' mac address as actors' system + address. + + This parameter has effect only in 802.3ad mode and is available through + SysFs interface. + + Example: + >>> from vyos.ifconfig import BondIf + >>> BondIf('bond0').set_system_mac('00:50:ab:cd:ef:01') + """ + return self.set_interface('bond_system_mac', mac) + def update(self, config): """ General helper function which works on a dictionary retrived by get_config_dict(). It's main intention is to consolidate the scattered @@ -426,14 +449,13 @@ class BondIf(Interface): Interface(interface).set_admin_state('up') # Bonding policy/mode - default value, always present - mode = config.get('mode') - self.set_mode(mode) + self.set_mode(config['mode']) # LACPDU transmission rate - default value - if mode == '802.3ad': + if config['mode'] == '802.3ad': self.set_lacp_rate(config.get('lacp_rate')) - if mode not in ['802.3ad', 'balance-tlb', 'balance-alb']: + if config['mode'] not in ['802.3ad', 'balance-tlb', 'balance-alb']: tmp = dict_search('arp_monitor.interval', config) value = tmp if (tmp != None) else '0' self.set_arp_interval(value) @@ -468,6 +490,14 @@ class BondIf(Interface): Interface(interface).flush_addrs() self.add_port(interface) + # Add system mac address for 802.3ad - default address is all zero + # mode is always present (defaultValue) + if config['mode'] == '802.3ad': + mac = '00:00:00:00:00:00' + if 'system_mac' in config: + mac = config['system_mac'] + self.set_system_mac(mac) + # Primary device interface - must be set after 'mode' value = config.get('primary') if value: self.set_primary(value) diff --git a/python/vyos/utils/assertion.py b/python/vyos/utils/assertion.py index 1aaa54dff..c7fa220c3 100644 --- a/python/vyos/utils/assertion.py +++ b/python/vyos/utils/assertion.py @@ -53,7 +53,7 @@ def assert_mtu(mtu, ifname): if (max_mtu and cur_mtu > max_mtu) or cur_mtu > 65536: raise ValueError(f'MTU is too small for interface "{ifname}": {mtu} > {max_mtu}') -def assert_mac(m): +def assert_mac(m, test_all_zero=True): split = m.split(':') size = len(split) @@ -74,7 +74,7 @@ def assert_mac(m): raise ValueError(f'{m} is a multicast MAC address') # overall mac address is not allowed to be 00:00:00:00:00:00 - if sum(octets) == 0: + if test_all_zero and sum(octets) == 0: raise ValueError('00:00:00:00:00:00 is not a valid MAC address') if octets[:5] == (0, 0, 94, 0, 1): diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py index 419de774a..f436424b8 100755 --- a/smoketest/scripts/cli/test_interfaces_bonding.py +++ b/smoketest/scripts/cli/test_interfaces_bonding.py @@ -241,6 +241,34 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase): for member in self._members: self.assertIn(member, slaves) + def test_bonding_system_mac(self): + # configure member interfaces and system-mac + default_system_mac = '00:00:00:00:00:00' # default MAC is all zeroes + system_mac = '00:50:ab:cd:ef:11' + + for interface in self._interfaces: + for option in self._options.get(interface, []): + self.cli_set(self._base_path + [interface] + option.split()) + + self.cli_set(self._base_path + [interface, 'system-mac', system_mac]) + + self.cli_commit() + + # verify config + for interface in self._interfaces: + tmp = read_file(f'/sys/class/net/{interface}/bonding/ad_actor_system') + self.assertIn(tmp, system_mac) + + for interface in self._interfaces: + self.cli_delete(self._base_path + [interface, 'system-mac']) + + self.cli_commit() + + # verify default value + for interface in self._interfaces: + tmp = read_file(f'/sys/class/net/{interface}/bonding/ad_actor_system') + self.assertIn(tmp, default_system_mac) + def test_bonding_evpn_multihoming(self): id = '5' for interface in self._interfaces: diff --git a/src/conf_mode/interfaces_bonding.py b/src/conf_mode/interfaces_bonding.py index 371b219c0..5e5d5fba1 100755 --- a/src/conf_mode/interfaces_bonding.py +++ b/src/conf_mode/interfaces_bonding.py @@ -33,6 +33,7 @@ from vyos.ifconfig import BondIf from vyos.ifconfig.ethernet import EthernetIf from vyos.ifconfig import Section from vyos.template import render_to_string +from vyos.utils.assertion import assert_mac from vyos.utils.dict import dict_search from vyos.utils.dict import dict_to_paths_values from vyos.utils.network import interface_exists @@ -244,6 +245,16 @@ def verify(bond): raise ConfigError('primary interface only works for mode active-backup, ' \ 'transmit-load-balance or adaptive-load-balance') + if 'system_mac' in bond: + if bond['mode'] != '802.3ad': + raise ConfigError('Actor MAC address only available in 802.3ad mode!') + + system_mac = bond['system_mac'] + try: + assert_mac(system_mac, test_all_zero=False) + except: + raise ConfigError(f'Cannot use a multicast MAC address "{system_mac}" as system-mac!') + return None def generate(bond): |