From 6ebb8cd26962b9840a912d5fb0ab2d891f7b00e2 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Mon, 11 Aug 2025 20:25:24 +0200 Subject: 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. --- smoketest/scripts/cli/test_interfaces_bonding.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'smoketest/scripts/cli') 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 -- cgit v1.2.3