[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20201123091921.0277d562@ceranb>
Date: Mon, 23 Nov 2020 09:19:21 +0100
From: Ivan Vecera <ivecera@...hat.com>
To: Jarod Wilson <jarod@...hat.com>
Cc: linux-kernel@...r.kernel.org, Jay Vosburgh <j.vosburgh@...il.com>,
Veaceslav Falico <vfalico@...il.com>,
Andy Gospodarek <andy@...yhouse.net>,
"David S. Miller" <davem@...emloft.net>,
Jakub Kicinski <kuba@...nel.org>,
Thomas Davis <tadavis@....gov>, netdev@...r.kernel.org
Subject: Re: [PATCH net] bonding: fix feature flag setting at init time
On Sun, 22 Nov 2020 22:17:16 -0500
Jarod Wilson <jarod@...hat.com> wrote:
> Have run into a case where bond_option_mode_set() gets called before
> hw_features has been filled in, and very bad things happen when
> netdev_change_features() then gets called, because the empty hw_features
> wipes out almost all features. Further reading of netdev feature flag
> documentation suggests drivers aren't supposed to touch wanted_features,
> so this changes bond_option_mode_set() to use netdev_increment_features()
> and &= ~BOND_XFRM_FEATURES on mode changes and then only calling
> netdev_features_change() if there was actually a change of features. This
> specifically fixes bonding on top of mlxsw interfaces, and has been
> regression-tested with ixgbe interfaces. This change also simplifies the
> xfrm-specific code in bond_setup() a little bit as well.
Hi Jarod,
the reason is not correct... The problem is not with empty ->hw_features but
with empty ->wanted_features.
During bond device creation bond_newlink() is called. It calls bond_changelink()
first and afterwards register_netdevice(). The problem is that ->wanted_features
are initialized in register_netdevice() so during bond_changlink() call
->wanted_features is 0. So...
bond_newlink()
-> bond_changelink()
-> __bond_opt_set()
-> bond_option_mode_set()
-> netdev_change_features()
-> __netdev_update_features()
features = netdev_get_wanted_features()
{ dev->features & ~dev->hw_features) | dev->wanted_features }
dev->wanted_features is here zero so the rest of the expression clears a bunch of
bits from dev->features...
In case of mlxsw it is important that NETIF_F_HW_VLAN_CTAG_FILTER bit is cleared in
bonding device because in this case vlan_add_rx_filter_info() does not call
bond_vlan_rx_add_vid() so mlxsw_sp_port_add_vid() is not called as well.
Later this causes a WARN in mlxsw_sp_inetaddr_port_vlan_event() because
instance of mlxsw_sp_port_vlan does not exist as mlxsw_sp_port_add_vid() was not
called.
Btw. it should be enough to call existing snippet in bond_option_mode_set() only
when device is already registered?
E.g.:
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 9abfaae1c6f7..ca4913fee5a9 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -768,11 +768,13 @@ static int bond_option_mode_set(struct bonding *bond,
bond->params.tlb_dynamic_lb = 1;
#ifdef CONFIG_XFRM_OFFLOAD
- if (newval->value == BOND_MODE_ACTIVEBACKUP)
- bond->dev->wanted_features |= BOND_XFRM_FEATURES;
- else
- bond->dev->wanted_features &= ~BOND_XFRM_FEATURES;
- netdev_change_features(bond->dev);
+ if (dev->reg_state == NETREG_REGISTERED) {
+ if (newval->value == BOND_MODE_ACTIVEBACKUP)
+ bond->dev->wanted_features |= BOND_XFRM_FEATURES;
+ else
+ bond->dev->wanted_features &= ~BOND_XFRM_FEATURES;
+ netdev_change_features(bond->dev);
+ }
#endif /* CONFIG_XFRM_OFFLOAD */
Thanks,
Ivan
Powered by blists - more mailing lists