diff options
| author | Christian Breunig <christian@breunig.cc> | 2025-08-11 20:25:24 +0200 |
|---|---|---|
| committer | Christian Breunig <christian@breunig.cc> | 2025-08-11 20:25:24 +0200 |
| commit | 6ebb8cd26962b9840a912d5fb0ab2d891f7b00e2 (patch) | |
| tree | f7a6c03ad5e2172c2aa514213d172685b04bd418 | |
| parent | 6fa4978e8bd57b3e50357a87eee4d884aba431ef (diff) | |
| download | vyos-1x-6ebb8cd26962b9840a912d5fb0ab2d891f7b00e2.tar.gz vyos-1x-6ebb8cd26962b9840a912d5fb0ab2d891f7b00e2.zip | |
bond: T7571: fix inconsistent MAC address behaviour
After upgrading from VyOS 1.3 to 1.4, there is an inconsistent behavior with
MAC address assignment on bonded interfaces. In VyOS 1.3, bond interfaces used
a hardware MAC address from one of the member interfaces. In 1.4, a synthetic
MAC is used by default - generated by the Linux Kernel.
Oddly, setting mode 802.3ad (which is also the default) temporarily causes the
hardware MAC to be used again - until a reboot, after which the synthetic MAC
returns.
Deleting the mode config again causes the hardware MAC to be used. This
inconsistent behavior has caused issues with MAC-based filtering in networks.
The fix is to retrive the hardware MAC address from the first bond member
interface and use set it explicitly for the bond interface.
| -rw-r--r-- | python/vyos/ifconfig/bond.py | 22 | ||||
| -rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bonding.py | 17 |
2 files changed, 35 insertions, 4 deletions
diff --git a/python/vyos/ifconfig/bond.py b/python/vyos/ifconfig/bond.py index 8a97243c5..ba31ae0c9 100644 --- a/python/vyos/ifconfig/bond.py +++ b/python/vyos/ifconfig/bond.py @@ -485,11 +485,25 @@ class BondIf(Interface): # Add (enslave) interfaces to bond value = dict_search('member.interface', config) + is_first = True for interface in (value or []): - # if we've come here we already verified the interface - # does not have an addresses configured so just flush - # any remaining ones - Interface(interface).flush_addrs() + # Physical bond member interface instance + tmp_if = Interface(interface) + # At this point, we've confirmed that the interface has no + # configured addresses, so we can safely flush any remaining ones. + tmp_if.flush_addrs() + + # T7571: This behavior changed from Linux Kernel 5.4 (used in VyOS 1.3) + # to Kernel 6.6 (starting with VyOS 1.4). Previously, the MAC address of + # the first member interface in a bond was adopted as the bond's default MAC. + # In newer versions, a synthetic MAC address is assigned instead. + # + # Re-assign first underlay MAC address to the bond + if is_first: + self.set_mac(tmp_if.get_mac()) + is_first = False + + # Assign underlaying interface to logical bond self.add_port(interface) # Add system mac address for 802.3ad - default address is all zero diff --git a/smoketest/scripts/cli/test_interfaces_bonding.py b/smoketest/scripts/cli/test_interfaces_bonding.py index 2473bc732..57d245ae6 100755 --- a/smoketest/scripts/cli/test_interfaces_bonding.py +++ b/smoketest/scripts/cli/test_interfaces_bonding.py @@ -62,6 +62,23 @@ class BondingInterfaceTest(BasicInterfaceTest.TestCase): slaves = read_file(f'/sys/class/net/{interface}/bonding/slaves').split() self.assertListEqual(slaves, self._members) + def test_bonding_keep_mac(self): + # T7571: A bond interface should always run from the physical interfaces + # MAC address and not a synthetic one. + base_mac = Interface(self._members[0]).get_mac() + + # configure member interfaces + for interface in self._interfaces: + for option in self._options.get(interface, []): + self.cli_set(self._base_path + [interface] + option.split()) + + self.cli_commit() + + # Verify bond interface MAC address matches the address of it's first member + for interface in self._interfaces: + mac = Interface(interface).get_mac() + self.assertEqual(mac, base_mac) + def test_bonding_remove_member(self): # T2515: when removing a bond member the previously enslaved/member # interface must be in its former admin-up/down state. Here we ensure |
