On 3/18/2021 4:18 PM, Vladimir Oltean wrote: > From: Vladimir Oltean <vladimir.oltean@xxxxxxx> > > DSA currently assumes that the bridge port starts off with this > constellation of bridge port flags: > > - learning on > - unicast flooding on > - multicast flooding on > - broadcast flooding on > > just by virtue of code copy-pasta from the bridge layer (new_nbp). > This was a simple enough strategy thus far, because the 'bridge join' > moment always coincided with the 'bridge port creation' moment. > > But with sandwiched interfaces, such as: > > br0 > | > bond0 > | > swp0 > > it may happen that the user has had time to change the bridge port flags > of bond0 before enslaving swp0 to it. In that case, swp0 will falsely > assume that the bridge port flags are those determined by new_nbp, when > in fact this can happen: > > ip link add br0 type bridge > ip link add bond0 type bond > ip link set bond0 master br0 > ip link set bond0 type bridge_slave learning off > ip link set swp0 master br0 > > Now swp0 has learning enabled, bond0 has learning disabled. Not nice. > > Fix this by "dumpster diving" through the actual bridge port flags with > br_port_flag_is_set, at bridge join time. > > We use this opportunity to split dsa_port_change_brport_flags into two > distinct functions called dsa_port_inherit_brport_flags and > dsa_port_clear_brport_flags, now that the implementation for the two > cases is no longer similar. > > Signed-off-by: Vladimir Oltean <vladimir.oltean@xxxxxxx> > --- > net/dsa/port.c | 123 ++++++++++++++++++++++++++++++++----------------- > 1 file changed, 82 insertions(+), 41 deletions(-) > > diff --git a/net/dsa/port.c b/net/dsa/port.c > index fcbe5b1545b8..346c50467810 100644 > --- a/net/dsa/port.c > +++ b/net/dsa/port.c > @@ -122,26 +122,82 @@ void dsa_port_disable(struct dsa_port *dp) > rtnl_unlock(); > } > > -static void dsa_port_change_brport_flags(struct dsa_port *dp, > - bool bridge_offload) > +static void dsa_port_clear_brport_flags(struct dsa_port *dp, > + struct netlink_ext_ack *extack) > { > struct switchdev_brport_flags flags; > - int flag; > > - flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; > - if (bridge_offload) > - flags.val = flags.mask; > - else > - flags.val = flags.mask & ~BR_LEARNING; > + flags.mask = BR_LEARNING; > + flags.val = 0; > + dsa_port_bridge_flags(dp, flags, extack); Would not you want to use the same for_each_set_bit() loop that dsa_port_change_br_flags() uses, that would be a tad more compact. -- Florian