On Tue, May 5, 2020 at 3:42 PM Jay Vosburgh <jay.vosbu...@canonical.com> wrote: > > Cong Wang <xiyou.wangc...@gmail.com> wrote: > > >syzbot managed to trigger a recursive NETDEV_FEAT_CHANGE event > >between bonding master and slave. I managed to find a reproducer > >for this: > > > > ip li set bond0 up > > ifenslave bond0 eth0 > > brctl addbr br0 > > ethtool -K eth0 lro off > > brctl addif br0 bond0 > > ip li set br0 up > > Presumably this is tied to the LRO feature being special in > netdev_sync_lower_features (via NETIF_F_UPPER_DISABLES), but why doesn't > LRO become disabled and stop the recursion once the test > > if (!(features & feature) && (lower->features & feature)) { > > no longer evalutes to true (in theory)?
Good point! Actually the LRO feature fails to disable: [ 62.559537] netdevice: bond0: failed to disable 0x0000000000008000 on eth0! ... [ 78.312003] netdevice: eth0: failed to disable LRO! It seems we should only skip netdev_update_features() for such case, like below. Note __netdev_update_features() intentionally returns -1 for this failure, so I am afraid we just have to live with it. diff --git a/net/core/dev.c b/net/core/dev.c index 522288177bbd..8040b07214fa 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -8907,11 +8907,13 @@ static void netdev_sync_lower_features(struct net_device *upper, netdev_dbg(upper, "Disabling feature %pNF on lower dev %s.\n", &feature, lower->name); lower->wanted_features &= ~feature; - netdev_update_features(lower); + __netdev_update_features(lower); if (unlikely(lower->features & feature)) netdev_WARN(upper, "failed to disable %pNF on %s!\n", &feature, lower->name); + else + netdev_update_features(lower); } } }