diff options
author | David S. Miller <davem@davemloft.net> | 2017-06-08 18:43:33 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-06-08 18:43:33 +0300 |
commit | 6c8607eb34369092f2f3bf9f99522ed7555b3a04 (patch) | |
tree | 77bd8a0521da45eac369ac4f4eef19799df23326 /net | |
parent | 7eca9cc53987fc496186e0e5fd1ecd573f5a03a1 (diff) | |
parent | adc3a9ce853cc4a8563ab2d08351bced8cd7d524 (diff) | |
download | linux-6c8607eb34369092f2f3bf9f99522ed7555b3a04.tar.xz |
Merge branch 'dsa-add-cross-chip-VLAN-support'
Vivien Didelot says:
====================
net: dsa: add cross-chip VLAN support
The current code in DSA does not support cross-chip VLAN. This means
that in a multi-chip environment such as this one (similar to ZII Rev B)
[CPU].................... (mdio)
(eth0) | : : :
_|_____ _______ _______
[__sw0__]--[__sw1__]--[__sw2__]
| | | | | | | | |
v v v v v v v v v
p1 p2 p3 p4 p5 p6 p7 p8 p9
adding a VLAN to p9 won't be enough to reach the CPU, until at least one
port of sw0 and sw1 join the VLAN as well and become aware of the VID.
This patchset makes the DSA core program the VLAN on the CPU and DSA
links itself, which brings seamlessly cross-chip VLAN support to DSA.
With this series applied*, the hardware VLAN tables of a 3-switch setup
look like this after adding a VLAN to only one port of the end switch:
# cat /sys/class/net/br0/bridge/default_pvid
42
# cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu
# ip link set up master br0 dev lan6
# cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu
VID FID SID 0 1 2 3 4 5 6
42 1 0 x x x x x = =
VID FID SID 0 1 2 3 4 5 6
42 1 0 x x x x x = =
VID FID SID 0 1 2 3 4 5 6 7 8 9
42 1 0 u x x x x x x x x =
('x' is excluded, 'u' is untagged, '=' is unmodified DSA and CPU ports.)
Completely removing a VLAN entry (which is currently the responsibility
of drivers anyway) is not supported yet since it requires some caching.
(*) the output is shown from this out-of-tree debugfs patch:
https://github.com/vivien/linux/commit/7b61a684b9d6b6a499135a587c7f62a1fddceb8b.patch
Changes in v2:
- canonical incrementation (port++ instead of ++port)
- check CPU and DSA ports before purging a VLAN
- add Reviewed-by tags
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/dsa/switch.c | 30 |
1 files changed, 20 insertions, 10 deletions
diff --git a/net/dsa/switch.c b/net/dsa/switch.c index d8e5c311ee7c..f1029a8d0e20 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -159,19 +159,30 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds, { const struct switchdev_obj_port_vlan *vlan = info->vlan; struct switchdev_trans *trans = info->trans; + DECLARE_BITMAP(members, ds->num_ports); + int port, err; - /* Do not care yet about other switch chips of the fabric */ - if (ds->index != info->sw_index) - return 0; + /* Build a mask of VLAN members */ + bitmap_zero(members, ds->num_ports); + if (ds->index == info->sw_index) + set_bit(info->port, members); + for (port = 0; port < ds->num_ports; port++) + if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) + set_bit(port, members); if (switchdev_trans_ph_prepare(trans)) { if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add) return -EOPNOTSUPP; - return ds->ops->port_vlan_prepare(ds, info->port, vlan, trans); + for_each_set_bit(port, members, ds->num_ports) { + err = ds->ops->port_vlan_prepare(ds, port, vlan, trans); + if (err) + return err; + } } - ds->ops->port_vlan_add(ds, info->port, vlan, trans); + for_each_set_bit(port, members, ds->num_ports) + ds->ops->port_vlan_add(ds, port, vlan, trans); return 0; } @@ -181,14 +192,13 @@ static int dsa_switch_vlan_del(struct dsa_switch *ds, { const struct switchdev_obj_port_vlan *vlan = info->vlan; - /* Do not care yet about other switch chips of the fabric */ - if (ds->index != info->sw_index) - return 0; - if (!ds->ops->port_vlan_del) return -EOPNOTSUPP; - return ds->ops->port_vlan_del(ds, info->port, vlan); + if (ds->index == info->sw_index) + return ds->ops->port_vlan_del(ds, info->port, vlan); + + return 0; } static int dsa_switch_event(struct notifier_block *nb, |