On Tue, Oct 27, 2020 at 11:51:15AM +0100, Tobias Waldekranz wrote: > Monitor the following events and notify the driver when: > > - A DSA port joins/leaves a LAG. > - A LAG, made up of DSA ports, joins/leaves a bridge. > - A DSA port in a LAG is enabled/disabled (enabled meaning > "distributing" in 802.3ad LACP terms). > > Each LAG interface to which a DSA port is attached is represented by a > `struct dsa_lag` which is globally reachable from the switch tree and
When you use dsa_broadcast, it is reachable from _all_ switch trees, not from "the" switch tree. This was added to support "islands" of inter-compatible DSA switches separated by other DSA switches with incompatible taggers. Not sure if it was a voluntary decision to use that as opposed to plain dsa_port_notify. Not a problem either way. > from each associated port. > > When a LAG joins a bridge, the DSA subsystem will treat that as each > individual port joining the bridge. The driver may look at the port's > LAG pointer to see if it is associated with any LAG, if that is > required. This is analogue to how switchdev events are replicated out > to all lower devices when reaching e.g. a LAG. > > Signed-off-by: Tobias Waldekranz <tob...@waldekranz.com> > --- > include/net/dsa.h | 68 +++++++++++++++++++++ > net/dsa/dsa2.c | 3 + > net/dsa/dsa_priv.h | 16 +++++ > net/dsa/port.c | 146 +++++++++++++++++++++++++++++++++++++++++++++ > net/dsa/slave.c | 53 ++++++++++++++-- > net/dsa/switch.c | 64 ++++++++++++++++++++ > 6 files changed, 346 insertions(+), 4 deletions(-) > > diff --git a/include/net/dsa.h b/include/net/dsa.h > index 35429a140dfa..58d73eafe891 100644 > --- a/include/net/dsa.h > +++ b/include/net/dsa.h > @@ -145,6 +145,9 @@ struct dsa_switch_tree { > /* List of switch ports */ > struct list_head ports; > > + /* List of configured LAGs */ > + struct list_head lags; > + > /* List of DSA links composing the routing table */ > struct list_head rtable; > }; > @@ -178,6 +181,48 @@ struct dsa_mall_tc_entry { > }; > }; > > +struct dsa_lag { > + struct net_device *dev; > + int id; > + > + struct list_head ports; > + > + /* For multichip systems, we must ensure that each hash bucket > + * is only enabled on a single egress port throughout the > + * whole tree. Or else? I don't really understand this statement. > --- a/net/dsa/port.c > +++ b/net/dsa/port.c > @@ -193,6 +193,152 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct > net_device *br) > dsa_port_set_state_now(dp, BR_STATE_FORWARDING); > } > > +static struct dsa_lag *dsa_lag_get(struct dsa_switch_tree *dst, > + struct net_device *dev) > +{ > + struct dsa_lag *lag; > + unsigned long busy = 0; Reverse Christmas notation please? > + int id; > + > + list_for_each_entry(lag, &dst->lags, list) { > + set_bit(lag->id, &busy); > + > + if (lag->dev == dev) { > + kref_get(&lag->refcount); > + return lag; > + } > + } > + > + id = find_first_zero_bit(&busy, BITS_PER_LONG); > + if (id >= BITS_PER_LONG) > + return ERR_PTR(-ENOSPC); > + > + lag = kzalloc(sizeof(*lag), GFP_KERNEL); > + if (!lag) > + return ERR_PTR(-ENOMEM); > + > + kref_init(&lag->refcount); > + lag->id = id; > + lag->dev = dev; > + INIT_LIST_HEAD(&lag->ports); > + INIT_LIST_HEAD(&lag->tx_ports); > + > + INIT_LIST_HEAD(&lag->list); > + list_add_tail_rcu(&lag->list, &dst->lags); > + return lag; > +} > + > diff --git a/net/dsa/slave.c b/net/dsa/slave.c > index 3bc5ca40c9fb..e5e4f3d096c0 100644 > --- a/net/dsa/slave.c > +++ b/net/dsa/slave.c > @@ -334,7 +334,8 @@ static int dsa_slave_vlan_add(struct net_device *dev, > struct switchdev_obj_port_vlan vlan; > int vid, err; > > - if (obj->orig_dev != dev) > + if (!(obj->orig_dev == dev || > + (dp->lag && obj->orig_dev == dp->lag->dev))) A small comment here maybe? > return -EOPNOTSUPP; > > if (dsa_port_skip_vlan_configuration(dp)) > @@ -421,7 +422,8 @@ static int dsa_slave_vlan_del(struct net_device *dev, > struct switchdev_obj_port_vlan *vlan; > int vid, err; > > - if (obj->orig_dev != dev) > + if (!(obj->orig_dev == dev || > + (dp->lag && obj->orig_dev == dp->lag->dev))) > return -EOPNOTSUPP; > > if (dsa_port_skip_vlan_configuration(dp))