summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2025-08-11 20:25:24 +0200
committerChristian Breunig <christian@breunig.cc>2025-08-11 20:25:24 +0200
commit6ebb8cd26962b9840a912d5fb0ab2d891f7b00e2 (patch)
treef7a6c03ad5e2172c2aa514213d172685b04bd418
parent6fa4978e8bd57b3e50357a87eee4d884aba431ef (diff)
downloadvyos-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.py22
-rwxr-xr-xsmoketest/scripts/cli/test_interfaces_bonding.py17
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