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.

Merge branch 'bridge-check-relevant-options-in-vlan-range-grouping'

Danielle Ratson says:

====================
bridge: Check relevant options in VLAN range grouping

The br_vlan_opts_eq_range() function determines if consecutive VLANs can
be grouped together in a range for compact netlink notifications. It
currently checks state, tunnel info, and multicast router configuration,
but misses two categories of per-VLAN options that affect the output:
1. User-visible priv_flags (neigh_suppress, mcast_enabled)
2. Port multicast context options (mcast_max_groups, mcast_n_groups)

When VLANs have different settings for these options, they are incorrectly
grouped into ranges, causing netlink notifications to report only one
VLAN's settings for the entire range.

Fix by checking priv_flags equality, but only for flags that affect netlink
output (BR_VLFLAG_NEIGH_SUPPRESS_ENABLED and BR_VLFLAG_MCAST_ENABLED),
and comparing multicast context options (mcast_max_groups, mcast_n_groups).

Add a test with four test cases for each option, to ensure that VLANs with
different values are not grouped into ranges and VLANs with matching
values are properly grouped together.
====================

Link: https://patch.msgid.link/20260225143956.3995415-1-danieller@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+238 -3
+10
net/bridge/br_private.h
··· 1345 1345 } 1346 1346 1347 1347 static inline bool 1348 + br_multicast_port_ctx_options_equal(const struct net_bridge_mcast_port *pmctx1, 1349 + const struct net_bridge_mcast_port *pmctx2) 1350 + { 1351 + return br_multicast_ngroups_get(pmctx1) == 1352 + br_multicast_ngroups_get(pmctx2) && 1353 + br_multicast_ngroups_get_max(pmctx1) == 1354 + br_multicast_ngroups_get_max(pmctx2); 1355 + } 1356 + 1357 + static inline bool 1348 1358 br_multicast_ctx_matches_vlan_snooping(const struct net_bridge_mcast *brmctx) 1349 1359 { 1350 1360 bool vlan_snooping_enabled;
+23 -3
net/bridge/br_vlan_options.c
··· 43 43 u8 range_mc_rtr = br_vlan_multicast_router(range_end); 44 44 u8 curr_mc_rtr = br_vlan_multicast_router(v_curr); 45 45 46 - return v_curr->state == range_end->state && 47 - __vlan_tun_can_enter_range(v_curr, range_end) && 48 - curr_mc_rtr == range_mc_rtr; 46 + if (v_curr->state != range_end->state) 47 + return false; 48 + 49 + if (!__vlan_tun_can_enter_range(v_curr, range_end)) 50 + return false; 51 + 52 + if (curr_mc_rtr != range_mc_rtr) 53 + return false; 54 + 55 + /* Check user-visible priv_flags that affect output */ 56 + if ((v_curr->priv_flags ^ range_end->priv_flags) & 57 + (BR_VLFLAG_NEIGH_SUPPRESS_ENABLED | BR_VLFLAG_MCAST_ENABLED)) 58 + return false; 59 + 60 + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING 61 + if (!br_vlan_is_master(v_curr) && 62 + !br_multicast_port_ctx_vlan_disabled(&v_curr->port_mcast_ctx) && 63 + !br_multicast_port_ctx_options_equal(&v_curr->port_mcast_ctx, 64 + &range_end->port_mcast_ctx)) 65 + return false; 66 + #endif 67 + 68 + return true; 49 69 } 50 70 51 71 bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v,
+1
tools/testing/selftests/net/Makefile
··· 15 15 big_tcp.sh \ 16 16 bind_bhash.sh \ 17 17 bpf_offload.py \ 18 + bridge_vlan_dump.sh \ 18 19 broadcast_ether_dst.sh \ 19 20 broadcast_pmtu.sh \ 20 21 busy_poll_test.sh \
+204
tools/testing/selftests/net/bridge_vlan_dump.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + # Test bridge VLAN range grouping. VLANs are collapsed into a range entry in 5 + # the dump if they have the same per-VLAN options. These tests verify that 6 + # VLANs with different per-VLAN option values are not grouped together. 7 + 8 + # shellcheck disable=SC1091,SC2034,SC2154,SC2317 9 + source lib.sh 10 + 11 + ALL_TESTS=" 12 + vlan_range_neigh_suppress 13 + vlan_range_mcast_max_groups 14 + vlan_range_mcast_n_groups 15 + vlan_range_mcast_enabled 16 + " 17 + 18 + setup_prepare() 19 + { 20 + setup_ns NS 21 + defer cleanup_all_ns 22 + 23 + ip -n "$NS" link add name br0 type bridge vlan_filtering 1 \ 24 + vlan_default_pvid 0 mcast_snooping 1 mcast_vlan_snooping 1 25 + ip -n "$NS" link set dev br0 up 26 + 27 + ip -n "$NS" link add name dummy0 type dummy 28 + ip -n "$NS" link set dev dummy0 master br0 29 + ip -n "$NS" link set dev dummy0 up 30 + } 31 + 32 + vlan_range_neigh_suppress() 33 + { 34 + RET=0 35 + 36 + # Add two new consecutive VLANs for range grouping test 37 + bridge -n "$NS" vlan add vid 10 dev dummy0 38 + defer bridge -n "$NS" vlan del vid 10 dev dummy0 39 + 40 + bridge -n "$NS" vlan add vid 11 dev dummy0 41 + defer bridge -n "$NS" vlan del vid 11 dev dummy0 42 + 43 + # Configure different neigh_suppress values and verify no range grouping 44 + bridge -n "$NS" vlan set vid 10 dev dummy0 neigh_suppress on 45 + check_err $? "Failed to set neigh_suppress for VLAN 10" 46 + 47 + bridge -n "$NS" vlan set vid 11 dev dummy0 neigh_suppress off 48 + check_err $? "Failed to set neigh_suppress for VLAN 11" 49 + 50 + # Verify VLANs are not shown as a range, but individual entries exist 51 + bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11" 52 + check_fail $? "VLANs with different neigh_suppress incorrectly grouped" 53 + 54 + bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+10$|^\s+10$" 55 + check_err $? "VLAN 10 individual entry not found" 56 + 57 + bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+11$|^\s+11$" 58 + check_err $? "VLAN 11 individual entry not found" 59 + 60 + # Configure same neigh_suppress value and verify range grouping 61 + bridge -n "$NS" vlan set vid 11 dev dummy0 neigh_suppress on 62 + check_err $? "Failed to set neigh_suppress for VLAN 11" 63 + 64 + bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11" 65 + check_err $? "VLANs with same neigh_suppress not grouped" 66 + 67 + log_test "VLAN range grouping with neigh_suppress" 68 + } 69 + 70 + vlan_range_mcast_max_groups() 71 + { 72 + RET=0 73 + 74 + # Add two new consecutive VLANs for range grouping test 75 + bridge -n "$NS" vlan add vid 10 dev dummy0 76 + defer bridge -n "$NS" vlan del vid 10 dev dummy0 77 + 78 + bridge -n "$NS" vlan add vid 11 dev dummy0 79 + defer bridge -n "$NS" vlan del vid 11 dev dummy0 80 + 81 + # Configure different mcast_max_groups values and verify no range grouping 82 + bridge -n "$NS" vlan set vid 10 dev dummy0 mcast_max_groups 100 83 + check_err $? "Failed to set mcast_max_groups for VLAN 10" 84 + 85 + bridge -n "$NS" vlan set vid 11 dev dummy0 mcast_max_groups 200 86 + check_err $? "Failed to set mcast_max_groups for VLAN 11" 87 + 88 + # Verify VLANs are not shown as a range, but individual entries exist 89 + bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11" 90 + check_fail $? "VLANs with different mcast_max_groups incorrectly grouped" 91 + 92 + bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+10$|^\s+10$" 93 + check_err $? "VLAN 10 individual entry not found" 94 + 95 + bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+11$|^\s+11$" 96 + check_err $? "VLAN 11 individual entry not found" 97 + 98 + # Configure same mcast_max_groups value and verify range grouping 99 + bridge -n "$NS" vlan set vid 11 dev dummy0 mcast_max_groups 100 100 + check_err $? "Failed to set mcast_max_groups for VLAN 11" 101 + 102 + bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11" 103 + check_err $? "VLANs with same mcast_max_groups not grouped" 104 + 105 + log_test "VLAN range grouping with mcast_max_groups" 106 + } 107 + 108 + vlan_range_mcast_n_groups() 109 + { 110 + RET=0 111 + 112 + # Add two new consecutive VLANs for range grouping test 113 + bridge -n "$NS" vlan add vid 10 dev dummy0 114 + defer bridge -n "$NS" vlan del vid 10 dev dummy0 115 + 116 + bridge -n "$NS" vlan add vid 11 dev dummy0 117 + defer bridge -n "$NS" vlan del vid 11 dev dummy0 118 + 119 + # Add different numbers of multicast groups to each VLAN 120 + bridge -n "$NS" mdb add dev br0 port dummy0 grp 239.1.1.1 vid 10 121 + check_err $? "Failed to add mdb entry to VLAN 10" 122 + defer bridge -n "$NS" mdb del dev br0 port dummy0 grp 239.1.1.1 vid 10 123 + 124 + bridge -n "$NS" mdb add dev br0 port dummy0 grp 239.1.1.2 vid 10 125 + check_err $? "Failed to add second mdb entry to VLAN 10" 126 + defer bridge -n "$NS" mdb del dev br0 port dummy0 grp 239.1.1.2 vid 10 127 + 128 + bridge -n "$NS" mdb add dev br0 port dummy0 grp 239.1.1.1 vid 11 129 + check_err $? "Failed to add mdb entry to VLAN 11" 130 + defer bridge -n "$NS" mdb del dev br0 port dummy0 grp 239.1.1.1 vid 11 131 + 132 + # Verify VLANs are not shown as a range due to different mcast_n_groups 133 + bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11" 134 + check_fail $? "VLANs with different mcast_n_groups incorrectly grouped" 135 + 136 + bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+10$|^\s+10$" 137 + check_err $? "VLAN 10 individual entry not found" 138 + 139 + bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+11$|^\s+11$" 140 + check_err $? "VLAN 11 individual entry not found" 141 + 142 + # Add another group to VLAN 11 to match VLAN 10's count 143 + bridge -n "$NS" mdb add dev br0 port dummy0 grp 239.1.1.2 vid 11 144 + check_err $? "Failed to add second mdb entry to VLAN 11" 145 + defer bridge -n "$NS" mdb del dev br0 port dummy0 grp 239.1.1.2 vid 11 146 + 147 + bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11" 148 + check_err $? "VLANs with same mcast_n_groups not grouped" 149 + 150 + log_test "VLAN range grouping with mcast_n_groups" 151 + } 152 + 153 + vlan_range_mcast_enabled() 154 + { 155 + RET=0 156 + 157 + # Add two new consecutive VLANs for range grouping test 158 + bridge -n "$NS" vlan add vid 10 dev br0 self 159 + defer bridge -n "$NS" vlan del vid 10 dev br0 self 160 + 161 + bridge -n "$NS" vlan add vid 11 dev br0 self 162 + defer bridge -n "$NS" vlan del vid 11 dev br0 self 163 + 164 + bridge -n "$NS" vlan add vid 10 dev dummy0 165 + defer bridge -n "$NS" vlan del vid 10 dev dummy0 166 + 167 + bridge -n "$NS" vlan add vid 11 dev dummy0 168 + defer bridge -n "$NS" vlan del vid 11 dev dummy0 169 + 170 + # Configure different mcast_snooping for bridge VLANs 171 + # Port VLANs inherit BR_VLFLAG_MCAST_ENABLED from bridge VLANs 172 + bridge -n "$NS" vlan global set dev br0 vid 10 mcast_snooping 1 173 + bridge -n "$NS" vlan global set dev br0 vid 11 mcast_snooping 0 174 + 175 + # Verify port VLANs are not grouped due to different mcast_enabled 176 + bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11" 177 + check_fail $? "VLANs with different mcast_enabled incorrectly grouped" 178 + 179 + bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+10$|^\s+10$" 180 + check_err $? "VLAN 10 individual entry not found" 181 + 182 + bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+11$|^\s+11$" 183 + check_err $? "VLAN 11 individual entry not found" 184 + 185 + # Configure same mcast_snooping and verify range grouping 186 + bridge -n "$NS" vlan global set dev br0 vid 11 mcast_snooping 1 187 + 188 + bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11" 189 + check_err $? "VLANs with same mcast_enabled not grouped" 190 + 191 + log_test "VLAN range grouping with mcast_enabled" 192 + } 193 + 194 + # Verify the newest tested option is supported 195 + if ! bridge vlan help 2>&1 | grep -q "neigh_suppress"; then 196 + echo "SKIP: iproute2 too old, missing per-VLAN neighbor suppression support" 197 + exit "$ksft_skip" 198 + fi 199 + 200 + trap defer_scopes_cleanup EXIT 201 + setup_prepare 202 + tests_run 203 + 204 + exit "$EXIT_STATUS"