Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

bridge: No DEV_PATH_BR_VLAN_UNTAG_HW for dsa foreign

In network setup as below:

fastpath bypass
.----------------------------------------.
/ \
| IP - forwarding |
| / \ v
| / wan ...
| /
| |
| |
| brlan.1
| |
| +-------------------------------+
| | vlan 1 |
| | |
| | brlan (vlan-filtering) |
| | +---------------+
| | | DSA-SWITCH |
| | vlan 1 | |
| | to | |
| | untagged 1 vlan 1 |
| +---------------+---------------+
. / \
----->wlan1 lan0
. .
. ^
^ vlan 1 tagged packets
untagged packets

br_vlan_fill_forward_path_mode() sets DEV_PATH_BR_VLAN_UNTAG_HW when
filling in from brlan.1 towards wlan1. But it should be set to
DEV_PATH_BR_VLAN_UNTAG in this case. Using BR_VLFLAG_ADDED_BY_SWITCHDEV
is not correct. The dsa switchdev adds it as a foreign port.

The same problem for all foreignly added dsa vlans on the bridge.

First add the vlan, trying only native devices.
If this fails, we know this may be a vlan from a foreign device.

Use BR_VLFLAG_TAGGING_BY_SWITCHDEV to make sure DEV_PATH_BR_VLAN_UNTAG_HW
is set only when there if no foreign device involved.

Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: Eric Woudstra <ericwouds@gmail.com>
Link: https://patch.msgid.link/20260317110347.363875-1-ericwouds@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Eric Woudstra and committed by
Paolo Abeni
96450df1 0c450644

+33 -2
+1
include/net/switchdev.h
··· 15 15 #define SWITCHDEV_F_NO_RECURSE BIT(0) 16 16 #define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) 17 17 #define SWITCHDEV_F_DEFER BIT(2) 18 + #define SWITCHDEV_F_NO_FOREIGN BIT(3) 18 19 19 20 enum switchdev_attr_id { 20 21 SWITCHDEV_ATTR_ID_UNDEFINED,
+10
net/bridge/br_private.h
··· 182 182 BR_VLFLAG_MCAST_ENABLED = BIT(2), 183 183 BR_VLFLAG_GLOBAL_MCAST_ENABLED = BIT(3), 184 184 BR_VLFLAG_NEIGH_SUPPRESS_ENABLED = BIT(4), 185 + BR_VLFLAG_TAGGING_BY_SWITCHDEV = BIT(5), 185 186 }; 186 187 187 188 /** ··· 2235 2234 int type); 2236 2235 int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags, 2237 2236 bool changed, struct netlink_ext_ack *extack); 2237 + int br_switchdev_port_vlan_no_foreign_add(struct net_device *dev, u16 vid, u16 flags, 2238 + bool changed, struct netlink_ext_ack *extack); 2238 2239 int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid); 2239 2240 void br_switchdev_init(struct net_bridge *br); 2240 2241 ··· 2316 2313 static inline int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, 2317 2314 u16 flags, bool changed, 2318 2315 struct netlink_ext_ack *extack) 2316 + { 2317 + return -EOPNOTSUPP; 2318 + } 2319 + 2320 + static inline int br_switchdev_port_vlan_no_foreign_add(struct net_device *dev, u16 vid, 2321 + u16 flags, bool changed, 2322 + struct netlink_ext_ack *extack) 2319 2323 { 2320 2324 return -EOPNOTSUPP; 2321 2325 }
+15
net/bridge/br_switchdev.c
··· 190 190 return switchdev_port_obj_add(dev, &v.obj, extack); 191 191 } 192 192 193 + int br_switchdev_port_vlan_no_foreign_add(struct net_device *dev, u16 vid, u16 flags, 194 + bool changed, struct netlink_ext_ack *extack) 195 + { 196 + struct switchdev_obj_port_vlan v = { 197 + .obj.orig_dev = dev, 198 + .obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN, 199 + .obj.flags = SWITCHDEV_F_NO_FOREIGN, 200 + .flags = flags, 201 + .vid = vid, 202 + .changed = changed, 203 + }; 204 + 205 + return switchdev_port_obj_add(dev, &v.obj, extack); 206 + } 207 + 193 208 int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid) 194 209 { 195 210 struct switchdev_obj_port_vlan v = {
+6 -1
net/bridge/br_vlan.c
··· 109 109 /* Try switchdev op first. In case it is not supported, fallback to 110 110 * 8021q add. 111 111 */ 112 + err = br_switchdev_port_vlan_no_foreign_add(dev, v->vid, flags, false, extack); 113 + if (err != -EOPNOTSUPP) { 114 + v->priv_flags |= BR_VLFLAG_ADDED_BY_SWITCHDEV | BR_VLFLAG_TAGGING_BY_SWITCHDEV; 115 + return err; 116 + } 112 117 err = br_switchdev_port_vlan_add(dev, v->vid, flags, false, extack); 113 118 if (err == -EOPNOTSUPP) 114 119 return vlan_vid_add(dev, br->vlan_proto, v->vid); ··· 1496 1491 1497 1492 if (path->bridge.vlan_mode == DEV_PATH_BR_VLAN_TAG) 1498 1493 path->bridge.vlan_mode = DEV_PATH_BR_VLAN_KEEP; 1499 - else if (v->priv_flags & BR_VLFLAG_ADDED_BY_SWITCHDEV) 1494 + else if (v->priv_flags & BR_VLFLAG_TAGGING_BY_SWITCHDEV) 1500 1495 path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG_HW; 1501 1496 else 1502 1497 path->bridge.vlan_mode = DEV_PATH_BR_VLAN_UNTAG;
+1 -1
net/switchdev/switchdev.c
··· 760 760 /* Event is neither on a bridge nor a LAG. Check whether it is on an 761 761 * interface that is in a bridge with us. 762 762 */ 763 - if (!foreign_dev_check_cb) 763 + if (!foreign_dev_check_cb || port_obj_info->obj->flags & SWITCHDEV_F_NO_FOREIGN) 764 764 return err; 765 765 766 766 br = netdev_master_upper_dev_get(dev);