diff options
author | David S. Miller <davem@davemloft.net> | 2019-04-30 23:05:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-04-30 23:05:30 -0400 |
commit | 492593010de4a323a7b98dffb0ba6567456b5ba0 (patch) | |
tree | 69566e08f1d74a449e6df3d1444ef89925084780 /net/dsa/switch.c | |
parent | a658a3f2ecbabba60dafa9ba94f12fc25c18474f (diff) | |
parent | 314f76d7a68bab0516aa52877944e6aacfa0fc3f (diff) | |
download | kernel_replicant_linux-492593010de4a323a7b98dffb0ba6567456b5ba0.tar.gz kernel_replicant_linux-492593010de4a323a7b98dffb0ba6567456b5ba0.tar.bz2 kernel_replicant_linux-492593010de4a323a7b98dffb0ba6567456b5ba0.zip |
Merge branch 'dsa-core-vlan'
Vladimir Oltean says:
====================
Improvements to DSA core VLAN manipulation
In preparation of submitting the NXP SJA1105 driver, the Broadcom b53
and Mediatek mt7530 drivers have been found to apply some VLAN
workarounds that are needed in the new driver as well.
Therefore this patchset is mostly simply promoting the DSA driver
workarounds for VLAN to the generic code.
The b53 driver was applying a few workarounds in order to convince DSA
that its vlan_filtering setting is not really per-port. This is now
simply set by the driver via a DSA variable at probe time. The sja1105
driver will be a second user of this.
The mt7530 was also keeping track of when the .port_vlan_filtering
callback was being called. Remove the kept state from this driver
and simplify dealing with vlan_filtering in the generic case.
TODO:
Find the best way to deal generically with the situation described below
(discussion at https://lkml.org/lkml/2019/4/16/1355):
> > +Segregating the switch ports in multiple bridges is supported (e.g. 2 + 2), but
> > +all bridges should have the same level of VLAN awareness (either both have
> > +``vlan_filtering`` 0, or both 1). Also an inevitable limitation of the fact
> > +that VLAN awareness is global at the switch level is that once a bridge with
> > +``vlan_filtering`` enslaves at least one switch port, the other un-bridged
> > +ports are no longer available for standalone traffic termination.
>
> That is quite a limitation that I don't think I had fully grasped until
> reading your different patches. Since enslaving ports into a bridge
> comes after the network device was already made available for use, maybe
> you should force the carrier down or something along those lines as soon
> as a port is enslaved into a bridge with vlan_filtering=1 to make this
> more predictable for the user?
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa/switch.c')
-rw-r--r-- | net/dsa/switch.c | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/net/dsa/switch.c b/net/dsa/switch.c index e1fae969aa73..7d8cd9bc0ecc 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -10,6 +10,7 @@ * (at your option) any later version. */ +#include <linux/if_bridge.h> #include <linux/netdevice.h> #include <linux/notifier.h> #include <linux/if_vlan.h> @@ -71,6 +72,9 @@ static int dsa_switch_bridge_join(struct dsa_switch *ds, static int dsa_switch_bridge_leave(struct dsa_switch *ds, struct dsa_notifier_bridge_info *info) { + bool unset_vlan_filtering = br_vlan_enabled(info->br); + int err, i; + if (ds->index == info->sw_index && ds->ops->port_bridge_leave) ds->ops->port_bridge_leave(ds, info->port, info->br); @@ -78,6 +82,31 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds, ds->ops->crosschip_bridge_leave(ds, info->sw_index, info->port, info->br); + /* If the bridge was vlan_filtering, the bridge core doesn't trigger an + * event for changing vlan_filtering setting upon slave ports leaving + * it. That is a good thing, because that lets us handle it and also + * handle the case where the switch's vlan_filtering setting is global + * (not per port). When that happens, the correct moment to trigger the + * vlan_filtering callback is only when the last port left this bridge. + */ + if (unset_vlan_filtering && ds->vlan_filtering_is_global) { + for (i = 0; i < ds->num_ports; i++) { + if (i == info->port) + continue; + if (dsa_to_port(ds, i)->bridge_dev == info->br) { + unset_vlan_filtering = false; + break; + } + } + } + if (unset_vlan_filtering) { + struct switchdev_trans trans = {0}; + + err = dsa_port_vlan_filtering(&ds->ports[info->port], + false, &trans); + if (err && err != EOPNOTSUPP) + return err; + } return 0; } @@ -196,7 +225,7 @@ static int dsa_port_vlan_check(struct dsa_switch *ds, int port, if (!dp->bridge_dev) return err; - /* dsa_slave_vlan_rx_{add,kill}_vid() cannot use the prepare pharse and + /* dsa_slave_vlan_rx_{add,kill}_vid() cannot use the prepare phase and * already checks whether there is an overlapping bridge VLAN entry * with the same VID, so here we only need to check that if we are * adding a bridge VLAN entry there is not an overlapping VLAN device |