[PATCH RFC/RFT net-next v2 4/5] net: dsa: deny 8021q uppers on vlan unaware bridged ports

Jonas Gorski
2025-12-01T10:28:53Z

Documentation/networking/switchdev.rst says:

- with VLAN filtering turned off, the bridge will process all ingress
traffic for the port, except for the traffic tagged with a VLAN ID
destined for a VLAN upper.

But DSA currently does not notify drivers about uppers on bridge ports
of a VLAN unaware bridge: Bridged ports on a VLAN unaware bridge will
usually not have filtering enabled and thus do not have
NETIF_F_HW_VLAN_CTAG_FILTER so dsa_user_vlan_rx_add_vid() is never
called.

And if filtering is always on for a driver, then DSA will just call
dsa_port_vlan_add(), in the same way it would for VLANs added to the
bridge. And VLANs programmed to the bridge are supposed to be ignored
while filtering is disabled, so drivers would still not act upon it.

Therefore traffic tagged with the VID will continue to be forwarded to
other ports, and therefore we cannot support VLAN uppers on ports of a
VLAN unaware bridges.

So reject any VLAN uppers for bridged ports of VLAN unaware bridges, and
reject disabling filtering as long as any VLAN uppers on bridged ports
exist.

Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
---
v1 -> v2:
* actually deny VLAN uppers on VLAN-unware bridges
* fix DSA behaviour description for non-filtering bridge ports

net/dsa/port.c | 23 ++++-------------------
net/dsa/user.c | 9 ++++++++-
2 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/net/dsa/port.c b/net/dsa/port.c
index 082573ae6864..d7746885f7e0 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -728,35 +728,20 @@ static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp,
{
struct dsa_switch *ds = dp->ds;
struct dsa_port *other_dp;
- int err;

- /* VLAN awareness was off, so the question is "can we turn it on".
+ /* VLAN awareness was on, so the question is "can we turn it off".
* 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_port_is_user(dp)) {
- struct net_device *br = dsa_port_bridge_dev_get(dp);
+ if (!vlan_filtering && dsa_port_is_user(dp)) {
struct net_device *upper_dev, *user = dp->user;
struct list_head *iter;

netdev_for_each_upper_dev_rcu(user, 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) {
+ if (is_vlan_dev(upper_dev)) {
NL_SET_ERR_MSG_MOD(extack,
- "Must first remove VLAN uppers having VIDs also present in bridge");
+ "Must first remove VLAN uppers from bridged ports");
return false;
}
}
diff --git a/net/dsa/user.c b/net/dsa/user.c
index e8c6452780b0..442cf3b2dc30 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -3167,10 +3167,17 @@ dsa_user_check_8021q_upper(struct net_device *dev,
int err = NOTIFY_DONE;
u16 vid;

- if (!br || !br_vlan_enabled(br))
+ if (!br)
return NOTIFY_DONE;

extack = netdev_notifier_info_to_extack(&info->info);
+
+ if (!br_vlan_enabled(br)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "VLAN uppers not supported with non filtering bridges");
+ return notifier_from_errno(-EBUSY);
+ }
+
vid = vlan_dev_vlan_id(info->upper_dev);

/* br_vlan_get_info() returns -EINVAL or -ENOENT if the
--
2.43.0