From 8350129930d2d74426b03d2d59d121156c204531 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 21 Sep 2020 03:10:23 +0300 Subject: [PATCH 1/9] net: dsa: deny enslaving 802.1Q upper to VLAN-aware bridge from PRECHANGEUPPER There doesn't seem to be any strong technical reason for doing it this way, but we'll be adding more checks for invalid upper device configurations, and it will be easier to have them all grouped under PRECHANGEUPPER. Tested that it still works: ip link set br0 type bridge vlan_filtering 1 ip link add link swp2 name swp2.100 type vlan id 100 ip link set swp2.100 master br0 [ 20.321312] br0: port 5(swp2.100) entered blocking state [ 20.326711] br0: port 5(swp2.100) entered disabled state Error: dsa_core: Cannot enslave VLAN device into VLAN aware bridge. [ 20.346549] br0: port 5(swp2.100) entered blocking state [ 20.351957] br0: port 5(swp2.100) entered disabled state Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 66a5268398a5..e29899431e07 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1932,9 +1932,14 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb, { struct net_device *dev = netdev_notifier_info_to_dev(ptr); - if (event == NETDEV_CHANGEUPPER) { + switch (event) { + case NETDEV_PRECHANGEUPPER: if (!dsa_slave_dev_check(dev)) return dsa_slave_upper_vlan_check(dev, ptr); + break; + case NETDEV_CHANGEUPPER: + if (!dsa_slave_dev_check(dev)) + return NOTIFY_DONE; return dsa_slave_changeupper(dev, ptr); } From eb46e8da1d2c52963718697d90cc8cddb73425dd Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 21 Sep 2020 03:10:24 +0300 Subject: [PATCH 2/9] net: dsa: rename dsa_slave_upper_vlan_check to something more suggestive We'll be adding a new check in the PRECHANGEUPPER notifier, where we'll need to check some VLAN uppers. It is hard to do that when there is already a function named dsa_slave_upper_vlan_check. So rename this one. Not to mention that this function probably shouldn't have started with "dsa_slave_" in the first place, since the struct net_device argument isn't a DSA slave, but an 8021q upper of one. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index e29899431e07..8ad5bf487181 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1895,9 +1895,9 @@ static int dsa_slave_changeupper(struct net_device *dev, return err; } -static int dsa_slave_upper_vlan_check(struct net_device *dev, - struct netdev_notifier_changeupper_info * - info) +static int +dsa_prevent_bridging_8021q_upper(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) { struct netlink_ext_ack *ext_ack; struct net_device *slave; @@ -1935,7 +1935,7 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb, switch (event) { case NETDEV_PRECHANGEUPPER: if (!dsa_slave_dev_check(dev)) - return dsa_slave_upper_vlan_check(dev, ptr); + return dsa_prevent_bridging_8021q_upper(dev, ptr); break; case NETDEV_CHANGEUPPER: if (!dsa_slave_dev_check(dev)) From 2b13840672340e1698aa0913a088c9dac7df82f7 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 21 Sep 2020 03:10:25 +0300 Subject: [PATCH 3/9] net: dsa: convert check for 802.1Q upper when bridged into PRECHANGEUPPER DSA tries to prevent having a VLAN added by a bridge and by an 802.1Q upper at the same time. It does that by checking the VID in .ndo_vlan_rx_add_vid(), since that's something that the 8021q module calls, via vlan_vid_add(). When a VLAN matches in both subsystems, this check returns -EBUSY. However the vlan_vid_add() function isn't specific to the 8021q module in any way at all. It is simply the kernel's way to tell an interface to add a VLAN to its RX filter and not drop that VLAN. So there's no reason to return -EBUSY when somebody tries to call vlan_vid_add() for a VLAN that was installed by the bridge. The proper behavior is to accept that configuration. So what's wrong is how DSA checks that it has an 8021q upper. It should look at the actual uppers for that, not just assume that the 8021q module was somewhere in the call stack of .ndo_vlan_rx_add_vid(). Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 74 +++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 8ad5bf487181..43763b22fbef 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1240,26 +1240,9 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, /* This API only allows programming tagged, non-PVID VIDs */ .flags = 0, }; - struct bridge_vlan_info info; struct switchdev_trans trans; int ret; - /* Check for a possible bridge VLAN entry now since there is no - * need to emulate the switchdev prepare + commit phase. - */ - if (dp->bridge_dev) { - if (dsa_port_skip_vlan_configuration(dp)) - return 0; - - /* br_vlan_get_info() returns -EINVAL or -ENOENT if the - * device, respectively the VID is not found, returning - * 0 means success, which is a failure for us here. - */ - ret = br_vlan_get_info(dp->bridge_dev, vid, &info); - if (ret == 0) - return -EBUSY; - } - /* User port... */ trans.ph_prepare = true; ret = dsa_port_vlan_add(dp, &vlan, &trans); @@ -1295,24 +1278,6 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, /* This API only allows programming tagged, non-PVID VIDs */ .flags = 0, }; - struct bridge_vlan_info info; - int ret; - - /* Check for a possible bridge VLAN entry now since there is no - * need to emulate the switchdev prepare + commit phase. - */ - if (dp->bridge_dev) { - if (dsa_port_skip_vlan_configuration(dp)) - return 0; - - /* br_vlan_get_info() returns -EINVAL or -ENOENT if the - * device, respectively the VID is not found, returning - * 0 means success, which is a failure for us here. - */ - ret = br_vlan_get_info(dp->bridge_dev, vid, &info); - if (ret == 0) - return -EBUSY; - } /* Do not deprogram the CPU port as it may be shared with other user * ports which can be members of this VLAN as well. @@ -1927,16 +1892,53 @@ dsa_prevent_bridging_8021q_upper(struct net_device *dev, return NOTIFY_DONE; } +static int +dsa_slave_check_8021q_upper(struct net_device *dev, + struct netdev_notifier_changeupper_info *info) +{ + struct dsa_port *dp = dsa_slave_to_port(dev); + struct net_device *br = dp->bridge_dev; + struct bridge_vlan_info br_info; + struct netlink_ext_ack *extack; + int err = NOTIFY_DONE; + u16 vid; + + if (!br) + return NOTIFY_DONE; + + extack = netdev_notifier_info_to_extack(&info->info); + vid = vlan_dev_vlan_id(info->upper_dev); + + /* br_vlan_get_info() returns -EINVAL or -ENOENT if the + * device, respectively the VID is not found, returning + * 0 means success, which is a failure for us here. + */ + err = br_vlan_get_info(br, vid, &br_info); + if (err == 0) { + NL_SET_ERR_MSG_MOD(extack, + "This VLAN is already configured by the bridge"); + return notifier_from_errno(-EBUSY); + } + + return NOTIFY_DONE; +} + static int dsa_slave_netdevice_event(struct notifier_block *nb, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); switch (event) { - case NETDEV_PRECHANGEUPPER: + case NETDEV_PRECHANGEUPPER: { + struct netdev_notifier_changeupper_info *info = ptr; + if (!dsa_slave_dev_check(dev)) return dsa_prevent_bridging_8021q_upper(dev, ptr); + + if (is_vlan_dev(info->upper_dev)) + return dsa_slave_check_8021q_upper(dev, ptr); break; + } case NETDEV_CHANGEUPPER: if (!dsa_slave_dev_check(dev)) return NOTIFY_DONE; From 1ce39f0ee8da0b2d8b5f30bcc9180b8f0148353f Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 21 Sep 2020 03:10:26 +0300 Subject: [PATCH 4/9] net: dsa: convert denying bridge VLAN with existing 8021q upper to PRECHANGEUPPER This is checking for the following order of operations, and makes sure to deny that configuration: ip link add link swp2 name swp2.100 type vlan id 100 ip link add br0 type bridge vlan_filtering 1 ip link set swp2 master br0 bridge vlan add dev swp2 vid 100 Instead of using vlan_for_each(), which looks at the VLAN filters installed with vlan_vid_add(), just track the 8021q uppers. This has the advantage of freeing up the vlan_vid_add() call for actual VLAN filtering. There is another change in this patch. The check is moved in slave.c, from switch.c. I don't think it makes sense to have this 8021q upper check for each switch port that gets notified of that VLAN addition (these include DSA links and CPU ports, we know those can't have 8021q uppers because they don't have a net_device registered for them), so just do it in slave.c, for that one slave interface. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 33 +++++++++++++++++++++++++++++++++ net/dsa/switch.c | 41 ----------------------------------------- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 43763b22fbef..89f03fde760e 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -303,6 +303,28 @@ static int dsa_slave_port_attr_set(struct net_device *dev, return ret; } +/* Must be called under rcu_read_lock() */ +static int +dsa_slave_vlan_check_for_8021q_uppers(struct net_device *slave, + const struct switchdev_obj_port_vlan *vlan) +{ + struct net_device *upper_dev; + struct list_head *iter; + + netdev_for_each_upper_dev_rcu(slave, upper_dev, iter) { + u16 vid; + + if (!is_vlan_dev(upper_dev)) + continue; + + vid = vlan_dev_vlan_id(upper_dev); + if (vid >= vlan->vid_begin && vid <= vlan->vid_end) + return -EBUSY; + } + + return 0; +} + static int dsa_slave_vlan_add(struct net_device *dev, const struct switchdev_obj *obj, struct switchdev_trans *trans) @@ -319,6 +341,17 @@ static int dsa_slave_vlan_add(struct net_device *dev, vlan = *SWITCHDEV_OBJ_PORT_VLAN(obj); + /* Deny adding a bridge VLAN when there is already an 802.1Q upper with + * the same VID. + */ + if (trans->ph_prepare) { + rcu_read_lock(); + err = dsa_slave_vlan_check_for_8021q_uppers(dev, &vlan); + rcu_read_unlock(); + if (err) + return err; + } + err = dsa_port_vlan_add(dp, &vlan, trans); if (err) return err; diff --git a/net/dsa/switch.c b/net/dsa/switch.c index 86c8dc5c32a0..9afef6f0f9df 100644 --- a/net/dsa/switch.c +++ b/net/dsa/switch.c @@ -232,43 +232,6 @@ static int dsa_switch_mdb_del(struct dsa_switch *ds, return 0; } -static int dsa_port_vlan_device_check(struct net_device *vlan_dev, - int vlan_dev_vid, - void *arg) -{ - struct switchdev_obj_port_vlan *vlan = arg; - u16 vid; - - for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid) { - if (vid == vlan_dev_vid) - return -EBUSY; - } - - return 0; -} - -static int dsa_port_vlan_check(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) -{ - const struct dsa_port *dp = dsa_to_port(ds, port); - int err = 0; - - /* Device is not bridged, let it proceed with the VLAN device - * creation. - */ - if (!dp->bridge_dev) - return err; - - /* 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 - * claiming that VID. - */ - return vlan_for_each(dp->slave, dsa_port_vlan_device_check, - (void *)vlan); -} - static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port, struct dsa_notifier_vlan_info *info) { @@ -291,10 +254,6 @@ static int dsa_switch_vlan_prepare(struct dsa_switch *ds, for (port = 0; port < ds->num_ports; port++) { if (dsa_switch_vlan_match(ds, port, info)) { - err = dsa_port_vlan_check(ds, port, info->vlan); - if (err) - return err; - err = ds->ops->port_vlan_prepare(ds, port, info->vlan); if (err) return err; From 707ec383b369b8da9f009c3ab2236b335ec10788 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 21 Sep 2020 03:10:27 +0300 Subject: [PATCH 5/9] net: dsa: refuse configuration in prepare phase of dsa_port_vlan_filtering() The current logic beats me a little bit. The comment that "bridge skips -EOPNOTSUPP, so skip the prepare phase" was introduced in commit fb2dabad69f0 ("net: dsa: support VLAN filtering switchdev attr"). I'm not sure: (a) ok, the bridge skips -EOPNOTSUPP, but, so what, where are we returning -EOPNOTSUPP? (b) even if we are, and I'm just not seeing it, what is the causality relationship between the bridge skipping -EOPNOTSUPP and DSA skipping the prepare phase, and just returning zero? One thing is certain beyond doubt though, and that is that DSA currently refuses VLAN filtering from the "commit" phase instead of "prepare", and that this is not a good thing: ip link add br0 type bridge ip link add br1 type bridge vlan_filtering 1 ip link set swp2 master br0 ip link set swp3 master br1 [ 3790.379389] 001: sja1105 spi0.1: VLAN filtering is a global setting [ 3790.379399] 001: ------------[ cut here ]------------ [ 3790.379403] 001: WARNING: CPU: 1 PID: 515 at net/switchdev/switchdev.c:157 switchdev_port_attr_set_now+0x9c/0xa4 [ 3790.379420] 001: swp3: Commit of attribute (id=6) failed. [ 3790.379533] 001: [] (switchdev_port_attr_set_now) from [] (nbp_vlan_init+0x84/0x148) [ 3790.379544] 001: [] (nbp_vlan_init) from [] (br_add_if+0x514/0x670) [ 3790.379554] 001: [] (br_add_if) from [] (do_setlink+0x38c/0xab0) [ 3790.379565] 001: [] (do_setlink) from [] (__rtnl_newlink+0x44c/0x748) [ 3790.379573] 001: [] (__rtnl_newlink) from [] (rtnl_newlink+0x44/0x60) [ 3790.379580] 001: [] (rtnl_newlink) from [] (rtnetlink_rcv_msg+0x124/0x2f8) [ 3790.379590] 001: [] (rtnetlink_rcv_msg) from [] (netlink_rcv_skb+0xb8/0x110) [ 3790.379806] 001: ---[ end trace 0000000000000002 ]--- [ 3790.379819] 001: sja1105 spi0.1 swp3: failed to initialize vlan filtering on this port So move the current logic that may fail (except ds->ops->port_vlan_filtering, that is way harder) into the prepare stage of the switchdev transaction. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/port.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/dsa/port.c b/net/dsa/port.c index 46c9bf709683..794a03718838 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -232,15 +232,15 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, struct dsa_switch *ds = dp->ds; int err; - /* bridge skips -EOPNOTSUPP, so skip the prepare phase */ - if (switchdev_trans_ph_prepare(trans)) - return 0; + if (switchdev_trans_ph_prepare(trans)) { + if (!ds->ops->port_vlan_filtering) + return -EOPNOTSUPP; - if (!ds->ops->port_vlan_filtering) - return 0; + if (!dsa_port_can_apply_vlan_filtering(dp, vlan_filtering)) + return -EINVAL; - if (!dsa_port_can_apply_vlan_filtering(dp, vlan_filtering)) - return -EINVAL; + return 0; + } if (dsa_port_is_vlan_filtering(dp) == vlan_filtering) return 0; From adb256eb1769dec74b809690f418e8e46bee62a7 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 21 Sep 2020 03:10:28 +0300 Subject: [PATCH 6/9] net: dsa: allow 8021q uppers while the bridge has vlan_filtering=0 When the bridge has VLAN awareness disabled there isn't any duplication of functionality, since the bridge does not process VLAN. Don't deny adding 8021q uppers to DSA switch ports in that case. The switch is supposed to simply pass traffic leaving the VLAN tag as-is, and the stack will happily strip the VLAN tag for all 8021q uppers that exist. We need to ensure that there are no 8021q uppers when the user attempts to enable bridge vlan_filtering. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/port.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- net/dsa/slave.c | 4 ++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/net/dsa/port.c b/net/dsa/port.c index 794a03718838..9a4fb80d2731 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -193,11 +193,44 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) dsa_port_set_state_now(dp, BR_STATE_FORWARDING); } +/* Must be called under rcu_read_lock() */ static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp, bool vlan_filtering) { struct dsa_switch *ds = dp->ds; - int i; + int err, i; + + /* VLAN awareness was off, so the question is "can we turn it on". + * We may have had 8021q uppers, those need to go. Make sure we don't + * enter an inconsistent state: deny changing the VLAN awareness state + * as long as we have 8021q uppers. + */ + if (vlan_filtering && dsa_is_user_port(ds, dp->index)) { + struct net_device *upper_dev, *slave = dp->slave; + struct net_device *br = dp->bridge_dev; + struct list_head *iter; + + netdev_for_each_upper_dev_rcu(slave, upper_dev, iter) { + struct bridge_vlan_info br_info; + u16 vid; + + if (!is_vlan_dev(upper_dev)) + continue; + + vid = vlan_dev_vlan_id(upper_dev); + + /* br_vlan_get_info() returns -EINVAL or -ENOENT if the + * device, respectively the VID is not found, returning + * 0 means success, which is a failure for us here. + */ + err = br_vlan_get_info(br, vid, &br_info); + if (err == 0) { + dev_err(ds->dev, "Must remove upper %s first\n", + upper_dev->name); + return false; + } + } + } if (!ds->vlan_filtering_is_global) return true; @@ -233,10 +266,19 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering, int err; if (switchdev_trans_ph_prepare(trans)) { + bool apply; + if (!ds->ops->port_vlan_filtering) return -EOPNOTSUPP; - if (!dsa_port_can_apply_vlan_filtering(dp, vlan_filtering)) + /* We are called from dsa_slave_switchdev_blocking_event(), + * which is not under rcu_read_lock(), unlike + * dsa_slave_switchdev_event(). + */ + rcu_read_lock(); + apply = dsa_port_can_apply_vlan_filtering(dp, vlan_filtering); + rcu_read_unlock(); + if (!apply) return -EINVAL; return 0; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 89f03fde760e..ad5732c1a4b0 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -344,7 +344,7 @@ static int dsa_slave_vlan_add(struct net_device *dev, /* Deny adding a bridge VLAN when there is already an 802.1Q upper with * the same VID. */ - if (trans->ph_prepare) { + if (trans->ph_prepare && br_vlan_enabled(dp->bridge_dev)) { rcu_read_lock(); err = dsa_slave_vlan_check_for_8021q_uppers(dev, &vlan); rcu_read_unlock(); @@ -1936,7 +1936,7 @@ dsa_slave_check_8021q_upper(struct net_device *dev, int err = NOTIFY_DONE; u16 vid; - if (!br) + if (!br || !br_vlan_enabled(br)) return NOTIFY_DONE; extack = netdev_notifier_info_to_extack(&info->info); From 2209158c9055dbc937673ec09c032505667d839e Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 21 Sep 2020 03:10:29 +0300 Subject: [PATCH 7/9] net: dsa: install VLANs into the master's RX filter too Most DSA switch tags shift the EtherType to the right, causing the master to not parse the VLAN as VLAN. However, not all switches do that (example: tail tags, tag_8021q etc), and if the DSA master has "rx-vlan-filter: on" in ethtool -k, then we have a problem. Therefore, we could populate the VLAN table of the master, just in case (for some switches it will not make a difference), so that network I/O can work even with a VLAN filtering master. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index ad5732c1a4b0..2d52bfba110a 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -329,9 +329,10 @@ static int dsa_slave_vlan_add(struct net_device *dev, const struct switchdev_obj *obj, struct switchdev_trans *trans) { + struct net_device *master = dsa_slave_to_master(dev); struct dsa_port *dp = dsa_slave_to_port(dev); struct switchdev_obj_port_vlan vlan; - int err; + int vid, err; if (obj->orig_dev != dev) return -EOPNOTSUPP; @@ -366,6 +367,12 @@ static int dsa_slave_vlan_add(struct net_device *dev, if (err) return err; + for (vid = vlan.vid_begin; vid <= vlan.vid_end; vid++) { + err = vlan_vid_add(master, htons(ETH_P_8021Q), vid); + if (err) + return err; + } + return 0; } @@ -409,7 +416,10 @@ static int dsa_slave_port_obj_add(struct net_device *dev, static int dsa_slave_vlan_del(struct net_device *dev, const struct switchdev_obj *obj) { + struct net_device *master = dsa_slave_to_master(dev); struct dsa_port *dp = dsa_slave_to_port(dev); + struct switchdev_obj_port_vlan *vlan; + int vid, err; if (obj->orig_dev != dev) return -EOPNOTSUPP; @@ -417,10 +427,19 @@ static int dsa_slave_vlan_del(struct net_device *dev, if (dsa_port_skip_vlan_configuration(dp)) return 0; + vlan = SWITCHDEV_OBJ_PORT_VLAN(obj); + /* Do not deprogram the CPU port as it may be shared with other user * ports which can be members of this VLAN as well. */ - return dsa_port_vlan_del(dp, SWITCHDEV_OBJ_PORT_VLAN(obj)); + err = dsa_port_vlan_del(dp, vlan); + if (err) + return err; + + for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) + vlan_vid_del(master, htons(ETH_P_8021Q), vid); + + return 0; } static int dsa_slave_port_obj_del(struct net_device *dev, @@ -1265,6 +1284,7 @@ static int dsa_slave_get_ts_info(struct net_device *dev, static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid) { + struct net_device *master = dsa_slave_to_master(dev); struct dsa_port *dp = dsa_slave_to_port(dev); struct switchdev_obj_port_vlan vlan = { .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, @@ -1298,12 +1318,13 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, if (ret) return ret; - return 0; + return vlan_vid_add(master, proto, vid); } static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid) { + struct net_device *master = dsa_slave_to_master(dev); struct dsa_port *dp = dsa_slave_to_port(dev); struct switchdev_obj_port_vlan vlan = { .vid_begin = vid, @@ -1311,11 +1332,18 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, /* This API only allows programming tagged, non-PVID VIDs */ .flags = 0, }; + int err; /* Do not deprogram the CPU port as it may be shared with other user * ports which can be members of this VLAN as well. */ - return dsa_port_vlan_del(dp, &vlan); + err = dsa_port_vlan_del(dp, &vlan); + if (err) + return err; + + vlan_vid_del(master, proto, vid); + + return 0; } struct dsa_hw_port { From bbed0bbdddaf46260aeb1a8910a3b32941e321a2 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 21 Sep 2020 03:10:30 +0300 Subject: [PATCH 8/9] net: dsa: tag_8021q: add VLANs to the master interface too The whole purpose of tag_8021q is to send VLAN-tagged traffic to the CPU, from which the driver can decode the source port and switch id. Currently this only works if the VLAN filtering on the master is disabled. Change that by explicitly adding code to tag_8021q.c to add the VLANs corresponding to the tags to the filter of the master interface. Because we now need to call vlan_vid_add, then we also need to hold the RTNL mutex. Propagate that requirement to the callers of dsa_8021q_setup and modify the existing call sites as appropriate. Note that one call path, sja1105_best_effort_vlan_filtering_set -> sja1105_vlan_filtering -> sja1105_setup_8021q_tagging, was already holding this lock. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/sja1105/sja1105_main.c | 7 ++++++- include/linux/dsa/8021q.h | 2 ++ net/dsa/tag_8021q.c | 20 +++++++++++++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 967430e8ceb8..4a298729937b 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -3038,7 +3038,11 @@ static int sja1105_setup(struct dsa_switch *ds) * default, and that means vlan_filtering is 0 since they're not under * a bridge, so it's safe to set up switch tagging at this time. */ - return sja1105_setup_8021q_tagging(ds, true); + rtnl_lock(); + rc = sja1105_setup_8021q_tagging(ds, true); + rtnl_unlock(); + + return rc; } static void sja1105_teardown(struct dsa_switch *ds) @@ -3532,6 +3536,7 @@ static int sja1105_probe(struct spi_device *spi) return -ENOMEM; priv->dsa_8021q_ctx->ops = &sja1105_dsa_8021q_ops; + priv->dsa_8021q_ctx->proto = htons(ETH_P_8021Q); priv->dsa_8021q_ctx->ds = ds; INIT_LIST_HEAD(&priv->dsa_8021q_ctx->crosschip_links); diff --git a/include/linux/dsa/8021q.h b/include/linux/dsa/8021q.h index 2b003ae9fb38..88cd72dfa4e0 100644 --- a/include/linux/dsa/8021q.h +++ b/include/linux/dsa/8021q.h @@ -31,6 +31,8 @@ struct dsa_8021q_context { const struct dsa_8021q_ops *ops; struct dsa_switch *ds; struct list_head crosschip_links; + /* EtherType of RX VID, used for filtering on master interface */ + __be16 proto; }; #define DSA_8021Q_N_SUBVLAN 8 diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c index 5baeb0893950..8e3e8a5b8559 100644 --- a/net/dsa/tag_8021q.c +++ b/net/dsa/tag_8021q.c @@ -215,7 +215,8 @@ static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port, int upstream = dsa_upstream_port(ctx->ds, port); u16 rx_vid = dsa_8021q_rx_vid(ctx->ds, port); u16 tx_vid = dsa_8021q_tx_vid(ctx->ds, port); - int i, err; + struct net_device *master; + int i, err, subvlan; /* The CPU port is implicitly configured by * configuring the front-panel ports @@ -223,6 +224,8 @@ static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port, if (!dsa_is_user_port(ctx->ds, port)) return 0; + master = dsa_to_port(ctx->ds, port)->cpu_dp->master; + /* Add this user port's RX VID to the membership list of all others * (including itself). This is so that bridging will not be hindered. * L2 forwarding rules still take precedence when there are no VLAN @@ -261,6 +264,19 @@ static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port, return err; } + /* Add to the master's RX filter not only @rx_vid, but in fact + * the entire subvlan range, just in case this DSA switch might + * want to use sub-VLANs. + */ + for (subvlan = 0; subvlan < DSA_8021Q_N_SUBVLAN; subvlan++) { + u16 vid = dsa_8021q_rx_vid_subvlan(ctx->ds, port, subvlan); + + if (enabled) + vlan_vid_add(master, ctx->proto, vid); + else + vlan_vid_del(master, ctx->proto, vid); + } + /* Finally apply the TX VID on this port and on the CPU port */ err = dsa_8021q_vid_apply(ctx, port, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED, enabled); @@ -285,6 +301,8 @@ int dsa_8021q_setup(struct dsa_8021q_context *ctx, bool enabled) { int rc, port; + ASSERT_RTNL(); + for (port = 0; port < ctx->ds->num_ports; port++) { rc = dsa_8021q_setup_port(ctx, port, enabled); if (rc < 0) { From 88525fc01cbe70052c4687c1ce29fd08f5c8fcbe Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Mon, 21 Sep 2020 03:10:31 +0300 Subject: [PATCH 9/9] net: dsa: tag_sja1105: add compatibility with hwaccel VLAN tags Check whether there is any hwaccel VLAN tag on RX, and if there is, treat it as the tag_8021q header. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/tag_sja1105.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c index 9b4a4d719291..3710f9daa46d 100644 --- a/net/dsa/tag_sja1105.c +++ b/net/dsa/tag_sja1105.c @@ -72,14 +72,21 @@ static inline bool sja1105_is_meta_frame(const struct sk_buff *skb) static bool sja1105_can_use_vlan_as_tags(const struct sk_buff *skb) { struct vlan_ethhdr *hdr = vlan_eth_hdr(skb); + u16 vlan_tci; if (hdr->h_vlan_proto == htons(ETH_P_SJA1105)) return true; - if (hdr->h_vlan_proto != htons(ETH_P_8021Q)) + if (hdr->h_vlan_proto != htons(ETH_P_8021Q) && + !skb_vlan_tag_present(skb)) return false; - return vid_is_dsa_8021q(ntohs(hdr->h_vlan_TCI) & VLAN_VID_MASK); + if (skb_vlan_tag_present(skb)) + vlan_tci = skb_vlan_tag_get(skb); + else + vlan_tci = ntohs(hdr->h_vlan_TCI); + + return vid_is_dsa_8021q(vlan_tci & VLAN_VID_MASK); } /* This is the first time the tagger sees the frame on RX. @@ -283,7 +290,8 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, hdr = eth_hdr(skb); tpid = ntohs(hdr->h_proto); - is_tagged = (tpid == ETH_P_SJA1105 || tpid == ETH_P_8021Q); + is_tagged = (tpid == ETH_P_SJA1105 || tpid == ETH_P_8021Q || + skb_vlan_tag_present(skb)); is_link_local = sja1105_is_link_local(skb); is_meta = sja1105_is_meta_frame(skb); @@ -292,7 +300,12 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, if (is_tagged) { /* Normal traffic path. */ skb_push_rcsum(skb, ETH_HLEN); - __skb_vlan_pop(skb, &tci); + if (skb_vlan_tag_present(skb)) { + tci = skb_vlan_tag_get(skb); + __vlan_hwaccel_clear_tag(skb); + } else { + __skb_vlan_pop(skb, &tci); + } skb_pull_rcsum(skb, ETH_HLEN); skb_reset_network_header(skb); skb_reset_transport_header(skb);