From 1ac64c41d7d0b1ccb4f4b496a184ef915833cc66 Mon Sep 17 00:00:00 2001 From: Julien Fortin Date: Fri, 27 May 2022 14:21:06 +0200 Subject: [PATCH] addons: bond: set IFLA_MASTER when updating bond settings On bond creation and update, ifupdown2 directly caches the netlink object sent to the kernel. If the bond already exists it overrides the existing cached object. If the existing bond was enslaved to a bridge, some bridge vlan data would get purged because the new netlink object didn't have the IFLA_MASTER attribute (thus tricking the cache into thinking that the bond got unslaved from the bridge). Here is a snippet of the bond013 /en/i config in the first topology: auto bond013 iface bond013 bond-slaves swp1s3 es-sys-mac 44:38:39:FF:00:02 bridge-vids 101-144 bond-lacp-bypass-allow yes mstpctl-portadminedge yes mstpctl-bpduguard yes And here in the second topology: auto bond013 iface bond013 bond-slaves swp1s3 es-sys-mac 44:38:39:FF:00:01 bridge-vids 201-210 bond-lacp-bypass-allow yes mstpctl-portadminedge yes mstpctl-bpduguard yes Signed-off-by: Julien Fortin --- ifupdown2/addons/bond.py | 7 ++++++- ifupdown2/lib/nlcache.py | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ifupdown2/addons/bond.py b/ifupdown2/addons/bond.py index ddb9134..9eb5916 100644 --- a/ifupdown2/addons/bond.py +++ b/ifupdown2/addons/bond.py @@ -749,11 +749,16 @@ class bond(Addon, moduleBase): link_exists, is_link_up = self.cache.link_exists_and_up(ifname) ifla_info_data = self.get_ifla_bond_attr_from_user_config(ifaceobj, link_exists) ifla_info_data = self.check_miimon_arp(link_exists, ifaceobj, ifla_info_data) + ifla_master = None remove_delay_from_cache = self.check_updown_delay_nl(link_exists, ifaceobj, ifla_info_data) # if link exists: down link if specific attributes are specified if link_exists: + # if bond already exists we need to set IFLA_MASTER to the cached value otherwise + # we might loose some information in the cache due to some optimization. + ifla_master = self.cache.get_link_attribute(ifname, Link.IFLA_MASTER) + # did bond-mode changed? is_link_up, bond_slaves = self.should_update_bond_mode( ifaceobj, @@ -777,7 +782,7 @@ class bond(Addon, moduleBase): self.logger.info('%s: already exists, no change detected' % ifname) else: try: - self.netlink.link_add_bond_with_info_data(ifname, ifla_info_data) + self.netlink.link_add_bond_with_info_data(ifname, ifla_master, ifla_info_data) except Exception as e: # defensive code # if anything happens, we try to set up the bond with the sysfs api diff --git a/ifupdown2/lib/nlcache.py b/ifupdown2/lib/nlcache.py index fe5172e..02aa215 100644 --- a/ifupdown2/lib/nlcache.py +++ b/ifupdown2/lib/nlcache.py @@ -3038,7 +3038,7 @@ class NetlinkListenerWithCache(nllistener.NetlinkManagerWithListener, BaseObject ### - def link_add_bond_with_info_data(self, ifname, ifla_info_data): + def link_add_bond_with_info_data(self, ifname, ifla_master, ifla_info_data): self.logger.info( "%s: netlink: ip link add dev %s type bond (with attributes)" % (ifname, ifname) @@ -3051,6 +3051,10 @@ class NetlinkListenerWithCache(nllistener.NetlinkManagerWithListener, BaseObject link.flags = NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK link.body = struct.pack('Bxxxiii', socket.AF_UNSPEC, 0, 0, 0) link.add_attribute(Link.IFLA_IFNAME, ifname) + + if ifla_master: + link.add_attribute(Link.IFLA_MASTER, ifla_master) + link.add_attribute(Link.IFLA_LINKINFO, { Link.IFLA_INFO_KIND: "bond", Link.IFLA_INFO_DATA: ifla_info_data