selftests: forwarding: Add test for BR_BOOLOPT_FDB_LOCAL_VLAN_0

Add a selftest to check the operation of this newly-introduced bridge
option.

Signed-off-by: Petr Machata <petrm@nvidia.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/62294f96884ab5d341648eef21243fa099a2dee5.1757004393.git.petrm@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Petr Machata 2025-09-04 19:07:27 +02:00 committed by Jakub Kicinski
parent fa57032941
commit dbd9134792
2 changed files with 375 additions and 0 deletions

View File

@ -5,6 +5,7 @@ TEST_PROGS = \
bridge_fdb_learning_limit.sh \
bridge_igmp.sh \
bridge_locked_port.sh \
bridge_fdb_local_vlan_0.sh \
bridge_mdb.sh \
bridge_mdb_host.sh \
bridge_mdb_max.sh \

View File

@ -0,0 +1,374 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# +-----------------------+ +-----------------------+ +-----------------------+
# | H1 (vrf) | | H2 (vrf) | | H3 (vrf) |
# | + $h1 | | + $h2 | | + $h3 |
# | | 192.0.2.1/28 | | | 192.0.2.2/28 | | | 192.0.2.18/28 |
# | | 2001:db8:1::1/64 | | | 2001:db8:1::2/64 | | | 2001:db8:2::2/64 |
# | | | | | | | | |
# +----|------------------+ +----|------------------+ +----|------------------+
# | | |
# +----|-------------------------|-------------------------|------------------+
# | +--|-------------------------|------------------+ | |
# | | + $swp1 + $swp2 | + $swp3 |
# | | | 192.0.2.17/28 |
# | | BR1 (802.1q) | 2001:db8:2::1/64 |
# | | 192.0.2.3/28 | |
# | | 2001:db8:1::3/64 | |
# | +-----------------------------------------------+ SW |
# +---------------------------------------------------------------------------+
#
#shellcheck disable=SC2317 # SC doesn't see our uses of functions.
#shellcheck disable=SC2034 # ... and global variables
ALL_TESTS="
test_d_no_sharing
test_d_sharing
test_q_no_sharing
test_q_sharing
"
NUM_NETIFS=6
source lib.sh
pMAC=00:11:22:33:44:55
bMAC=00:11:22:33:44:66
mMAC=00:11:22:33:44:77
xMAC=00:11:22:33:44:88
host_create()
{
local h=$1; shift
local ipv4=$1; shift
local ipv6=$1; shift
simple_if_init "$h" "$ipv4" "$ipv6"
defer simple_if_fini "$h" "$ipv4" "$ipv6"
ip_route_add vrf "v$h" 192.0.2.16/28 nexthop via 192.0.2.3
ip_route_add vrf "v$h" 2001:db8:2::/64 nexthop via 2001:db8:1::3
}
h3_create()
{
simple_if_init "$h3" 192.0.2.18/28 2001:db8:2::2/64
defer simple_if_fini "$h3" 192.0.2.18/28 2001:db8:2::2/64
ip_route_add vrf "v$h3" 192.0.2.0/28 nexthop via 192.0.2.17
ip_route_add vrf "v$h3" 2001:db8:1::/64 nexthop via 2001:db8:2::1
tc qdisc add dev "$h3" clsact
defer tc qdisc del dev "$h3" clsact
tc filter add dev "$h3" ingress proto ip pref 104 \
flower skip_hw ip_proto udp dst_port 4096 \
action pass
defer tc filter del dev "$h3" ingress proto ip pref 104
tc qdisc add dev "$h2" clsact
defer tc qdisc del dev "$h2" clsact
tc filter add dev "$h2" ingress proto ip pref 104 \
flower skip_hw ip_proto udp dst_port 4096 \
action pass
defer tc filter del dev "$h2" ingress proto ip pref 104
}
switch_create()
{
ip_link_set_up "$swp1"
ip_link_set_up "$swp2"
ip_addr_add "$swp3" 192.0.2.17/28
ip_addr_add "$swp3" 2001:db8:2::1/64
ip_link_set_up "$swp3"
}
setup_prepare()
{
h1=${NETIFS[p1]}
swp1=${NETIFS[p2]}
swp2=${NETIFS[p3]}
h2=${NETIFS[p4]}
swp3=${NETIFS[p5]}
h3=${NETIFS[p6]}
vrf_prepare
defer vrf_cleanup
forwarding_enable
defer forwarding_restore
host_create "$h1" 192.0.2.1/28 2001:db8:1::1/64
host_create "$h2" 192.0.2.2/28 2001:db8:1::2/64
h3_create
switch_create
}
adf_bridge_create()
{
local dev
local mac
ip_link_add br up type bridge vlan_default_pvid 0 "$@"
mac=$(mac_get br)
ip_addr_add br 192.0.2.3/28
ip_addr_add br 2001:db8:1::3/64
bridge_vlan_add dev br vid 1 pvid untagged self
bridge_vlan_add dev br vid 2 self
bridge_vlan_add dev br vid 3 self
for dev in "$swp1" "$swp2"; do
ip_link_set_master "$dev" br
bridge_vlan_add dev "$dev" vid 1 pvid untagged
bridge_vlan_add dev "$dev" vid 2
bridge_vlan_add dev "$dev" vid 3
done
ip_link_set_addr br "$mac"
}
check_fdb_local_vlan_0_support()
{
if ip_link_add XXbr up type bridge vlan_filtering 1 fdb_local_vlan_0 1 \
&>/dev/null; then
return 0
fi
log_test_skip "FDB sharing" \
"iproute 2 or the kernel do not support fdb_local_vlan_0"
}
check_mac_presence()
{
local should_fail=$1; shift
local dev=$1; shift
local vlan=$1; shift
local mac
mac=$(mac_get "$dev")
if ((vlan == 0)); then
vlan=null
fi
bridge -j fdb show dev "$dev" |
jq -e --arg mac "$mac" --argjson vlan "$vlan" \
'.[] | select(.mac == $mac) | select(.vlan == $vlan)' > /dev/null
check_err_fail "$should_fail" $? "FDB dev $dev vid $vlan addr $mac exists"
}
do_sharing_test()
{
local should_fail=$1; shift
local what=$1; shift
local dev
RET=0
for dev in "$swp1" "$swp2" br; do
check_mac_presence 0 "$dev" 0
check_mac_presence "$should_fail" "$dev" 1
check_mac_presence "$should_fail" "$dev" 2
check_mac_presence "$should_fail" "$dev" 3
done
log_test "$what"
}
do_end_to_end_test()
{
local mac=$1; shift
local what=$1; shift
local probe_dev=${1-$h3}; shift
local expect=${1-10}; shift
local t0
local t1
local dd
RET=0
# In mausezahn, use $dev MAC as the destination MAC. In the MAC sharing
# context, that will cause an FDB miss on VLAN 1 and prompt a second
# lookup in VLAN 0.
t0=$(tc_rule_stats_get "$probe_dev" 104 ingress)
$MZ "$h1" -c 10 -p 64 -a own -b "$mac" \
-A 192.0.2.1 -B 192.0.2.18 -t udp "dp=4096,sp=2048" -q
sleep 1
t1=$(tc_rule_stats_get "$probe_dev" 104 ingress)
dd=$((t1 - t0))
((dd == expect))
check_err $? "Expected $expect packets on $probe_dev got $dd"
log_test "$what"
}
do_tests()
{
local should_fail=$1; shift
local what=$1; shift
local swp1_mac
local br_mac
swp1_mac=$(mac_get "$swp1")
br_mac=$(mac_get br)
do_sharing_test "$should_fail" "$what"
do_end_to_end_test "$swp1_mac" "$what: end to end, $swp1 MAC"
do_end_to_end_test "$br_mac" "$what: end to end, br MAC"
}
bridge_standard()
{
local vlan_filtering=$1; shift
if ((vlan_filtering)); then
echo 802.1q
else
echo 802.1d
fi
}
nonexistent_fdb_test()
{
local vlan_filtering=$1; shift
local standard
standard=$(bridge_standard "$vlan_filtering")
# We expect flooding, so $h2 should get the traffic.
do_end_to_end_test "$xMAC" "$standard: Nonexistent FDB" "$h2"
}
misleading_fdb_test()
{
local vlan_filtering=$1; shift
local standard
standard=$(bridge_standard "$vlan_filtering")
defer_scope_push
# Add an FDB entry on VLAN 0. The lookup on VLAN-aware bridge
# shouldn't pick this up even with fdb_local_vlan_0 enabled, so
# the traffic should be flooded. This all holds on
# vlan_filtering bridge, on non-vlan_filtering one the FDB entry
# is expected to be found as usual, no flooding takes place.
#
# Adding only on VLAN 0 is a bit tricky, because bridge is
# trying to be nice and interprets the request as if the FDB
# should be added on each VLAN.
bridge fdb add "$mMAC" dev "$swp1" master
bridge fdb del "$mMAC" dev "$swp1" vlan 1 master
bridge fdb del "$mMAC" dev "$swp1" vlan 2 master
bridge fdb del "$mMAC" dev "$swp1" vlan 3 master
local expect=$((vlan_filtering ? 10 : 0))
do_end_to_end_test "$mMAC" \
"$standard: Lookup of non-local MAC on VLAN 0" \
"$h2" "$expect"
defer_scope_pop
}
change_mac()
{
local dev=$1; shift
local mac=$1; shift
local cur_mac
cur_mac=$(mac_get "$dev")
log_info "Change $dev MAC $cur_mac -> $mac"
ip_link_set_addr "$dev" "$mac"
defer log_info "Change $dev MAC back"
}
do_test_no_sharing()
{
local vlan_filtering=$1; shift
local standard
standard=$(bridge_standard "$vlan_filtering")
adf_bridge_create vlan_filtering "$vlan_filtering"
setup_wait
do_tests 0 "$standard, no FDB sharing"
change_mac "$swp1" "$pMAC"
change_mac br "$bMAC"
do_tests 0 "$standard, no FDB sharing after MAC change"
in_defer_scope check_fdb_local_vlan_0_support || return
log_info "Set fdb_local_vlan_0=1"
ip link set dev br type bridge fdb_local_vlan_0 1
do_tests 1 "$standard, fdb sharing after toggle"
}
do_test_sharing()
{
local vlan_filtering=$1; shift
local standard
standard=$(bridge_standard "$vlan_filtering")
in_defer_scope check_fdb_local_vlan_0_support || return
adf_bridge_create vlan_filtering "$vlan_filtering" fdb_local_vlan_0 1
setup_wait
do_tests 1 "$standard, FDB sharing"
nonexistent_fdb_test "$vlan_filtering"
misleading_fdb_test "$vlan_filtering"
change_mac "$swp1" "$pMAC"
change_mac br "$bMAC"
do_tests 1 "$standard, FDB sharing after MAC change"
log_info "Set fdb_local_vlan_0=0"
ip link set dev br type bridge fdb_local_vlan_0 0
do_tests 0 "$standard, No FDB sharing after toggle"
}
test_d_no_sharing()
{
do_test_no_sharing 0
}
test_d_sharing()
{
do_test_sharing 0
}
test_q_no_sharing()
{
do_test_no_sharing 1
}
test_q_sharing()
{
do_test_sharing 1
}
trap cleanup EXIT
setup_prepare
tests_run