diff options
author | Vladimir Oltean <vladimir.oltean@nxp.com> | 2021-06-27 14:54:25 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-06-28 14:09:03 -0700 |
commit | 0d2cfbd41c4a5a0ca5598d1874b1081138cd64c6 (patch) | |
tree | b2021c2002876daab15b2683a5291fb7c9140537 /net/dsa | |
parent | 69bfac968a06aab5927160f8736485f85c3e8ee8 (diff) | |
download | linux-0d2cfbd41c4a5a0ca5598d1874b1081138cd64c6.tar.bz2 |
net: bridge: ignore switchdev events for LAG ports which didn't request replay
There is a slight inconvenience in the switchdev replay helpers added
recently, and this is when:
ip link add br0 type bridge
ip link add bond0 type bond
ip link set bond0 master br0
bridge vlan add dev bond0 vid 100
ip link set swp0 master bond0
ip link set swp1 master bond0
Since the underlying driver (currently only DSA) asks for a replay of
VLANs when swp0 and swp1 join the LAG because it is bridged, what will
happen is that DSA will try to react twice on the VLAN event for swp0.
This is not really a huge problem right now, because most drivers accept
duplicates since the bridge itself does, but it will become a problem
when we add support for replaying switchdev object deletions.
Let's fix this by adding a blank void *ctx in the replay helpers, which
will be passed on by the bridge in the switchdev notifications. If the
context is NULL, everything is the same as before. But if the context is
populated with a valid pointer, the underlying switchdev driver
(currently DSA) can use the pointer to 'see through' the bridge port
(which in the example above is bond0) and 'know' that the event is only
for a particular physical port offloading that bridge port, and not for
all of them.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r-- | net/dsa/port.c | 6 | ||||
-rw-r--r-- | net/dsa/slave.c | 9 |
2 files changed, 12 insertions, 3 deletions
diff --git a/net/dsa/port.c b/net/dsa/port.c index 5c93f1e1a03d..339781c98de1 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -194,17 +194,17 @@ static int dsa_port_switchdev_sync(struct dsa_port *dp, if (err && err != -EOPNOTSUPP) return err; - err = br_mdb_replay(br, brport_dev, + err = br_mdb_replay(br, brport_dev, dp, &dsa_slave_switchdev_blocking_notifier, extack); if (err && err != -EOPNOTSUPP) return err; - err = br_fdb_replay(br, brport_dev, &dsa_slave_switchdev_notifier); + err = br_fdb_replay(br, brport_dev, dp, &dsa_slave_switchdev_notifier); if (err && err != -EOPNOTSUPP) return err; - err = br_vlan_replay(br, brport_dev, + err = br_vlan_replay(br, brport_dev, dp, &dsa_slave_switchdev_blocking_notifier, extack); if (err && err != -EOPNOTSUPP) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 3692259a025f..2f0d0a6b1f9c 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -278,6 +278,9 @@ static int dsa_slave_port_attr_set(struct net_device *dev, const void *ctx, struct dsa_port *dp = dsa_slave_to_port(dev); int ret; + if (ctx && ctx != dp) + return 0; + switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_STP_STATE: if (!dsa_port_offloads_bridge_port(dp, attr->orig_dev)) @@ -401,6 +404,9 @@ static int dsa_slave_port_obj_add(struct net_device *dev, const void *ctx, struct dsa_port *dp = dsa_slave_to_port(dev); int err; + if (ctx && ctx != dp) + return 0; + switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_MDB: if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) @@ -475,6 +481,9 @@ static int dsa_slave_port_obj_del(struct net_device *dev, const void *ctx, struct dsa_port *dp = dsa_slave_to_port(dev); int err; + if (ctx && ctx != dp) + return 0; + switch (obj->id) { case SWITCHDEV_OBJ_ID_PORT_MDB: if (!dsa_port_offloads_bridge_port(dp, obj->orig_dev)) |