Netdev List
 help / color / mirror / Atom feed
* [PATCH net 0/2] net: bridge: fix vlan range dumps starting with a PVID
@ 2026-07-21 14:09 Nikolay Aleksandrov
  2026-07-21 14:09 ` [PATCH net 1/2] net: bridge: vlan: fix vlan range dumps starting with pvid Nikolay Aleksandrov
  2026-07-21 14:09 ` [PATCH net 2/2] selftests: net: bridge: test ranges with PVID VLAN Nikolay Aleksandrov
  0 siblings, 2 replies; 3+ messages in thread
From: Nikolay Aleksandrov @ 2026-07-21 14:09 UTC (permalink / raw)
  To: netdev
  Cc: Ido Schimmel, davem, edumazet, kuba, pabeni, horms, bridge,
	Nikolay Aleksandrov

Hi,
Patch 01 fixes a bug that can skip dumping VLANs which a part of a range
starting with a PVID VLAN and share the same flags. PVID VLAN should be
always on its own. Patch 02 adds a selftest for this case. More information
can be found in the respective patches.

Thanks,
 Nik

Nikolay Aleksandrov (2):
  net: bridge: vlan: fix vlan range dumps starting with pvid
  selftests: net: bridge: test ranges with PVID VLAN

 net/bridge/br_netlink_tunnel.c                |  3 ++-
 net/bridge/br_private.h                       |  6 +++--
 net/bridge/br_vlan.c                          | 10 ++++----
 net/bridge/br_vlan_options.c                  |  3 +--
 .../testing/selftests/net/bridge_vlan_dump.sh | 23 +++++++++++++++++++
 5 files changed, 36 insertions(+), 9 deletions(-)

-- 
2.47.3


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH net 1/2] net: bridge: vlan: fix vlan range dumps starting with pvid
  2026-07-21 14:09 [PATCH net 0/2] net: bridge: fix vlan range dumps starting with a PVID Nikolay Aleksandrov
@ 2026-07-21 14:09 ` Nikolay Aleksandrov
  2026-07-21 14:09 ` [PATCH net 2/2] selftests: net: bridge: test ranges with PVID VLAN Nikolay Aleksandrov
  1 sibling, 0 replies; 3+ messages in thread
From: Nikolay Aleksandrov @ 2026-07-21 14:09 UTC (permalink / raw)
  To: netdev
  Cc: Ido Schimmel, davem, edumazet, kuba, pabeni, horms, bridge,
	Nikolay Aleksandrov

There is a bug in all range dumps that rely on br_vlan_can_enter_range()
when the PVID is a range starting VLAN, all following VLANs that match
its flags can enter the range, but when the range is filled in only the
PVID VLAN is dumped and the rest of the range is discarded because
br_vlan_fill_vids() checks for the PVID flag. Since the PVID VLAN can
be only one, we need to break ranges around it, the best way to do that
consistently for all is to alter br_vlan_can_enter_range() to take into
account the PVID and return false to break the range when it's matched.

Before the fix:
$ ip l add br0 type bridge vlan_filtering 1
$ ip l add dumdum type dummy
$ ip l set dumdum master br0
$ ip l set br0 up
$ ip l set dumdum up
$ bridge vlan add dev dumdum vid 1 pvid untagged master
$ bridge vlan add dev dumdum vid 2 untagged master
$ bridge vlan show dev dumdum # use legacy dump to show all vlans
port              vlan-id
dumdum            1 PVID Egress Untagged
                  2 Egress Untagged

$ bridge -d vlan show dev dumdum # use the new dump (RTM_GETVLAN)
port              vlan-id
dumdum            1 PVID Egress Untagged
                    state forwarding mcast_router 1

VLAN 2 is missing, and if there are more matching VLANs afterwards
they'd be missing too.

After the fix:
[ same setup steps ]
$ bridge vlan show dev dumdum
port              vlan-id
dumdum            1 PVID Egress Untagged
                  2 Egress Untagged
$ bridge -d vlan show dev dumdum # use the new dump (RTM_GETVLAN)
port              vlan-id
dumdum            1 PVID Egress Untagged
                    state forwarding mcast_router 1
                  2 Egress Untagged
                    state forwarding mcast_router 1

Fixes: 0ab558795184 ("net: bridge: vlan: add rtm range support")
Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org>
---
The change for the tunnel should add a separate notification for a PVID
VLAN which is fine because br_vlan_notify will properly fill in the pvid
flag for that VLAN.

 net/bridge/br_netlink_tunnel.c |  3 ++-
 net/bridge/br_private.h        |  6 ++++--
 net/bridge/br_vlan.c           | 10 ++++++----
 net/bridge/br_vlan_options.c   |  3 +--
 4 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/net/bridge/br_netlink_tunnel.c b/net/bridge/br_netlink_tunnel.c
index 71a12da30004..a713668ea34f 100644
--- a/net/bridge/br_netlink_tunnel.c
+++ b/net/bridge/br_netlink_tunnel.c
@@ -271,7 +271,8 @@ static void __vlan_tunnel_handle_range(const struct net_bridge_port *p,
 	if (!*v_start)
 		goto out_init;
 
-	if (v && curr_change && br_vlan_can_enter_range(v, *v_end)) {
+	if (v && curr_change &&
+	    br_vlan_can_enter_range(v, *v_end, br_get_pvid(vg))) {
 		*v_end = v;
 		return;
 	}
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index d55ea9516e3e..d3880f31edc4 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -1627,7 +1627,8 @@ void br_vlan_notify(const struct net_bridge *br,
 		    u16 vid, u16 vid_range,
 		    int cmd);
 bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
-			     const struct net_bridge_vlan *range_end);
+			     const struct net_bridge_vlan *range_end,
+			     u16 pvid);
 
 void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
 				    struct net_device_path_ctx *ctx,
@@ -1874,7 +1875,8 @@ static inline void br_vlan_notify(const struct net_bridge *br,
 }
 
 static inline bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
-					   const struct net_bridge_vlan *range_end)
+					   const struct net_bridge_vlan *range_end,
+					   u16 pvid)
 {
 	return true;
 }
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 5560afcaaca3..31c1b2cf75d9 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -1982,9 +1982,11 @@ void br_vlan_notify(const struct net_bridge *br,
 
 /* check if v_curr can enter a range ending in range_end */
 bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
-			     const struct net_bridge_vlan *range_end)
+			     const struct net_bridge_vlan *range_end,
+			     u16 pvid)
 {
-	return v_curr->vid - range_end->vid == 1 &&
+	return v_curr->vid != pvid && range_end->vid != pvid &&
+	       v_curr->vid - range_end->vid == 1 &&
 	       range_end->flags == v_curr->flags &&
 	       br_vlan_opts_eq_range(v_curr, range_end);
 }
@@ -2066,8 +2068,8 @@ static int br_vlan_dump_dev(const struct net_device *dev,
 			idx += range_end->vid - range_start->vid + 1;
 
 			range_start = v;
-		} else if (dump_stats || v->vid == pvid ||
-			   !br_vlan_can_enter_range(v, range_end)) {
+		} else if (dump_stats ||
+			   !br_vlan_can_enter_range(v, range_end, pvid)) {
 			u16 vlan_flags = br_vlan_flags(range_start, pvid);
 
 			if (!br_vlan_fill_vids(skb, range_start->vid,
diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c
index fcc200c3e3da..cb0f556ff40d 100644
--- a/net/bridge/br_vlan_options.c
+++ b/net/bridge/br_vlan_options.c
@@ -350,8 +350,7 @@ int br_vlan_process_options(const struct net_bridge *br,
 				continue;
 			}
 
-			if (v->vid == pvid ||
-			    !br_vlan_can_enter_range(v, curr_end)) {
+			if (!br_vlan_can_enter_range(v, curr_end, pvid)) {
 				br_vlan_notify(br, p, curr_start->vid,
 					       curr_end->vid, RTM_NEWVLAN);
 				curr_start = v;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH net 2/2] selftests: net: bridge: test ranges with PVID VLAN
  2026-07-21 14:09 [PATCH net 0/2] net: bridge: fix vlan range dumps starting with a PVID Nikolay Aleksandrov
  2026-07-21 14:09 ` [PATCH net 1/2] net: bridge: vlan: fix vlan range dumps starting with pvid Nikolay Aleksandrov
@ 2026-07-21 14:09 ` Nikolay Aleksandrov
  1 sibling, 0 replies; 3+ messages in thread
From: Nikolay Aleksandrov @ 2026-07-21 14:09 UTC (permalink / raw)
  To: netdev
  Cc: Ido Schimmel, davem, edumazet, kuba, pabeni, horms, bridge,
	Nikolay Aleksandrov

Add a test with PVID VLAN that matches the flags of the VLAN following it
and check if the range is properly dumped. PVID VLAN should be on its own
and all VLANs should be present in the dump.

Signed-off-by: Nikolay Aleksandrov <razor@blackwall.org>
---
 .../testing/selftests/net/bridge_vlan_dump.sh | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/tools/testing/selftests/net/bridge_vlan_dump.sh b/tools/testing/selftests/net/bridge_vlan_dump.sh
index ad66731d2a6f..90e18e2104e3 100755
--- a/tools/testing/selftests/net/bridge_vlan_dump.sh
+++ b/tools/testing/selftests/net/bridge_vlan_dump.sh
@@ -13,6 +13,7 @@ ALL_TESTS="
 	vlan_range_mcast_max_groups
 	vlan_range_mcast_n_groups
 	vlan_range_mcast_enabled
+	vlan_range_pvid
 "
 
 setup_prepare()
@@ -191,6 +192,28 @@ vlan_range_mcast_enabled()
 	log_test "VLAN range grouping with mcast_enabled"
 }
 
+vlan_range_pvid()
+{
+	RET=0
+
+	ip -n "$NS" link set dev br0 type bridge vlan_default_pvid 1
+	check_err $? "Failed to configure default PVID"
+	defer ip -n "$NS" link set dev br0 type bridge vlan_default_pvid 0
+
+	bridge -n "$NS" vlan add vid 2 dev dummy0 untagged
+	check_err $? "Failed to add VLAN 2"
+	defer bridge -n "$NS" vlan del vid 2 dev dummy0
+
+	bridge -n "$NS" -d vlan show dev dummy0 |
+		grep -Eq '(^|[[:space:]])2([[:space:]]|$)'
+	check_err $? "VLAN following PVID is missing from detailed dump"
+
+	bridge -n "$NS" -d vlan show dev dummy0 | grep -q "1-2"
+	check_fail $? "PVID was incorrectly included in a VLAN range"
+
+	log_test "PVID is isolated from VLAN dump ranges"
+}
+
 # Verify the newest tested option is supported
 if ! bridge vlan help 2>&1 | grep -q "neigh_suppress"; then
 	echo "SKIP: iproute2 too old, missing per-VLAN neighbor suppression support"
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-21 14:09 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-21 14:09 [PATCH net 0/2] net: bridge: fix vlan range dumps starting with a PVID Nikolay Aleksandrov
2026-07-21 14:09 ` [PATCH net 1/2] net: bridge: vlan: fix vlan range dumps starting with pvid Nikolay Aleksandrov
2026-07-21 14:09 ` [PATCH net 2/2] selftests: net: bridge: test ranges with PVID VLAN Nikolay Aleksandrov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox