From 1db0cb7accbf7cbb813d4276e00f79925f1798b4 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Tue, 29 Jun 2021 01:07:48 +0200 Subject: [PATCH] addons: address: remove stale fdb entry for svi (when hwaddress is used) As seen in the example below we are seeing a corner case, first the user /e/n/i is configured without 'hwaddress', then it is used to fix the svi mac address. The current code only checks for the statemanager for old 'hwaddress' attribute but couldn't find any. Now we save the mac addr before updating it, so we can later clear it from the fdb. $ cat a auto eth0 iface eth0 inet dhcp auto bridge iface bridge bridge-vlan-aware yes bridge-ports vx-1000 bridge-stp on bridge-vids 1000 1002 1004 1006 1008 bridge-pvid 1 auto vx-1000 iface vx-1000 vxlan-id 1000 bridge-access 1000 vxlan-local-tunnelip 27.0.0.11 bridge-learning off bridge-arp-nd-suppress on mstpctl-portbpdufilter yes mstpctl-bpduguard yes mtu 9152 auto vlan1000 iface vlan1000 address 45.0.0.2/24 vlan-id 1000 vlan-raw-device bridge address-virtual 00:00:5e:00:01:01 45.0.0.1/24 vrf vrf1 auto vrf1 iface vrf1 vrf-table auto $ $ $ cat b auto eth0 iface eth0 inet dhcp auto bridge iface bridge bridge-vlan-aware yes bridge-ports vx-1000 bridge-stp on bridge-vids 1000 1002 1004 1006 1008 bridge-pvid 1 auto vx-1000 iface vx-1000 vxlan-id 1000 bridge-access 1000 vxlan-local-tunnelip 27.0.0.11 bridge-learning off bridge-arp-nd-suppress on mstpctl-portbpdufilter yes mstpctl-bpduguard yes mtu 9152 auto vlan1000 iface vlan1000 address 45.0.0.2/24 hwaddress 00:02:00:aa:aa:aa vlan-id 1000 vlan-raw-device bridge address-virtual 00:00:5e:00:01:01 45.0.0.1/24 vrf vrf1 auto vrf1 iface vrf1 vrf-table auto $ $ $ rm /etc/network/interfaces ; ln -s `pwd`/a /etc/network/interfaces ; ifreload -a ; rm /etc/network/interfaces ; ln -s `pwd`/b /etc/network/interfaces ; (ifreload -av |& grep vlan | grep 1000) info: bridge: netlink: bridge vlan add vid 1000 dev bridge info: vlan1000: netlink: ip link set dev vlan1000 down info: vlan1000: netlink: ip link set dev vlan1000 address 00:02:00:aa:aa:aa info: vlan1000: netlink: ip link set dev vlan1000 up info: writing '1' to file /proc/sys/net/ipv4/conf/vlan1000/arp_accept info: executing /sbin/bridge fdb del 4a:b3:1e:45:bf:bf dev bridge vlan 1000 self info: executing /sbin/bridge fdb replace 00:02:00:aa:aa:aa dev bridge vlan 1000 self info: executing /sbin/bridge fdb replace 00:00:5e:00:01:01 dev bridge vlan 1000 self $ Signed-off-by: Julien Fortin --- ifupdown2/addons/address.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/ifupdown2/addons/address.py b/ifupdown2/addons/address.py index 50f23d1..85ae086 100644 --- a/ifupdown2/addons/address.py +++ b/ifupdown2/addons/address.py @@ -400,7 +400,7 @@ class address(AddonWithIpBlackList, moduleBase): def _get_hwaddress(self, ifaceobj): return utils.strip_hwaddress(ifaceobj.get_attr_value_first('hwaddress')) - def _process_bridge(self, ifaceobj, up): + def _process_bridge(self, ifaceobj, up, old_mac_addr=None): hwaddress = self._get_hwaddress(ifaceobj) addrs = ifaceobj.get_attr_value_first('address') arp_accept = ifaceobj.get_attr_value_first('arp-accept') @@ -425,13 +425,22 @@ class address(AddonWithIpBlackList, moduleBase): else: self.write_file('/proc/sys/net/ipv4/conf/%s/arp_accept' % ifaceobj.name, arp_accept) if hwaddress and is_vlan_dev_on_vlan_aware_bridge: + if old_mac_addr: + # corner case, first the user's /e/n/i is configured without 'hwaddress', then it is used to fix the svi + # mac address. The current code only checks for the statemanager for old 'hwaddress' attribute but + # couldn't find any. Now we save the mac addr before updating it, so we can later clear it from the fdb. + try: + self.iproute2.bridge_fdb_del(bridgename, old_mac_addr, vlan) + except: + pass if up: # check statemanager to delete the old entry if necessary try: for old_obj in statemanager.statemanager_api.get_ifaceobjs(ifaceobj.name) or []: old_hwaddress = old_obj.get_attr_value_first("hwaddress") if old_hwaddress and utils.mac_str_to_int(old_hwaddress) != utils.mac_str_to_int(hwaddress): - self.iproute2.bridge_fdb_del(bridgename, old_hwaddress, vlan) + if old_hwaddress != old_mac_addr: + self.iproute2.bridge_fdb_del(bridgename, old_hwaddress, vlan) break except Exception: pass @@ -1034,10 +1043,8 @@ class address(AddonWithIpBlackList, moduleBase): try: - self.process_hwaddress(ifaceobj) - # Handle special things on a bridge - self._process_bridge(ifaceobj, True) + self._process_bridge(ifaceobj, True, self.process_hwaddress(ifaceobj)) except Exception as e: self.log_error('%s: %s' % (ifaceobj.name, str(e)), ifaceobj) @@ -1069,6 +1076,8 @@ class address(AddonWithIpBlackList, moduleBase): else: running_hwaddress = None + old_mac_addr = None + if utils.mac_str_to_int(hwaddress) != utils.mac_str_to_int(running_hwaddress): slave_down = False if ifaceobj.link_kind & ifaceLinkKind.BOND: @@ -1079,11 +1088,14 @@ class address(AddonWithIpBlackList, moduleBase): slave_down = True try: self.netlink.link_set_address(ifaceobj.name, hwaddress) + old_mac_addr = running_hwaddress finally: if slave_down: for l in ifaceobj.lowerifaces: self.netlink.link_up(l) + return old_mac_addr + def _down(self, ifaceobj, ifaceobj_getfunc=None): try: if not self.cache.link_exists(ifaceobj.name):