Skip to content

Commit

Permalink
Merge pull request #3410 from fett0/T6303
Browse files Browse the repository at this point in the history
Bond: T6303: add system mac address on interfaces bond
  • Loading branch information
c-po authored May 10, 2024
2 parents 8fa1cb4 + 314901e commit def74a8
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 6 deletions.
12 changes: 12 additions & 0 deletions interface-definitions/interfaces_bonding.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
38 changes: 34 additions & 4 deletions python/vyos/ifconfig/bond.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
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
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -385,6 +390,24 @@ def set_mode(self, mode):
"""
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
Expand Down Expand Up @@ -426,14 +449,13 @@ def update(self, config):
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)
Expand Down Expand Up @@ -468,6 +490,14 @@ def update(self, config):
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)
Expand Down
4 changes: 2 additions & 2 deletions python/vyos/utils/assertion.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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):
Expand Down
28 changes: 28 additions & 0 deletions smoketest/scripts/cli/test_interfaces_bonding.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,34 @@ def test_bonding_uniq_member_description(self):
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:
Expand Down
11 changes: 11 additions & 0 deletions src/conf_mode/interfaces_bonding.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
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
Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit def74a8

Please sign in to comment.