selftests: forwarding: bridge_fdb_learning_limit: Add a new selftest
Add a suite covering the fdb_n_learned and fdb_max_learned bridge features, touching all special cases in accounting at least once. Acked-by: Nikolay Aleksandrov <razor@blackwall.org> Signed-off-by: Johannes Nixdorf <jnixdorf-oss@avm.de> Link: https://lore.kernel.org/r/20231016-fdb_limit-v5-5-32cddff87758@avm.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
19297c3ab2
commit
6f84090333
@ -1,6 +1,7 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0+ OR MIT
|
# SPDX-License-Identifier: GPL-2.0+ OR MIT
|
||||||
|
|
||||||
TEST_PROGS = bridge_igmp.sh \
|
TEST_PROGS = bridge_fdb_learning_limit.sh \
|
||||||
|
bridge_igmp.sh \
|
||||||
bridge_locked_port.sh \
|
bridge_locked_port.sh \
|
||||||
bridge_mdb.sh \
|
bridge_mdb.sh \
|
||||||
bridge_mdb_host.sh \
|
bridge_mdb_host.sh \
|
||||||
|
283
tools/testing/selftests/net/forwarding/bridge_fdb_learning_limit.sh
Executable file
283
tools/testing/selftests/net/forwarding/bridge_fdb_learning_limit.sh
Executable file
@ -0,0 +1,283 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
# ShellCheck incorrectly believes that most of the code here is unreachable
|
||||||
|
# because it's invoked by variable name following ALL_TESTS.
|
||||||
|
#
|
||||||
|
# shellcheck disable=SC2317
|
||||||
|
|
||||||
|
ALL_TESTS="check_accounting check_limit"
|
||||||
|
NUM_NETIFS=6
|
||||||
|
source lib.sh
|
||||||
|
|
||||||
|
TEST_MAC_BASE=de:ad:be:ef:42:
|
||||||
|
|
||||||
|
NUM_PKTS=16
|
||||||
|
FDB_LIMIT=8
|
||||||
|
|
||||||
|
FDB_TYPES=(
|
||||||
|
# name is counted? overrides learned?
|
||||||
|
'learned 1 0'
|
||||||
|
'static 0 1'
|
||||||
|
'user 0 1'
|
||||||
|
'extern_learn 0 1'
|
||||||
|
'local 0 1'
|
||||||
|
)
|
||||||
|
|
||||||
|
mac()
|
||||||
|
{
|
||||||
|
printf "${TEST_MAC_BASE}%02x" "$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
H1_DEFAULT_MAC=$(mac 42)
|
||||||
|
|
||||||
|
switch_create()
|
||||||
|
{
|
||||||
|
ip link add dev br0 type bridge
|
||||||
|
|
||||||
|
ip link set dev "$swp1" master br0
|
||||||
|
ip link set dev "$swp2" master br0
|
||||||
|
# swp3 is used to add local MACs, so do not add it to the bridge yet.
|
||||||
|
|
||||||
|
# swp2 is only used for replying when learning on swp1, its MAC should not be learned.
|
||||||
|
ip link set dev "$swp2" type bridge_slave learning off
|
||||||
|
|
||||||
|
ip link set dev br0 up
|
||||||
|
|
||||||
|
ip link set dev "$swp1" up
|
||||||
|
ip link set dev "$swp2" up
|
||||||
|
ip link set dev "$swp3" up
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_destroy()
|
||||||
|
{
|
||||||
|
ip link set dev "$swp3" down
|
||||||
|
ip link set dev "$swp2" down
|
||||||
|
ip link set dev "$swp1" down
|
||||||
|
|
||||||
|
ip link del dev br0
|
||||||
|
}
|
||||||
|
|
||||||
|
h_create()
|
||||||
|
{
|
||||||
|
ip link set "$h1" addr "$H1_DEFAULT_MAC"
|
||||||
|
|
||||||
|
simple_if_init "$h1" 192.0.2.1/24
|
||||||
|
simple_if_init "$h2" 192.0.2.2/24
|
||||||
|
}
|
||||||
|
|
||||||
|
h_destroy()
|
||||||
|
{
|
||||||
|
simple_if_fini "$h1" 192.0.2.1/24
|
||||||
|
simple_if_fini "$h2" 192.0.2.2/24
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_prepare()
|
||||||
|
{
|
||||||
|
h1=${NETIFS[p1]}
|
||||||
|
swp1=${NETIFS[p2]}
|
||||||
|
|
||||||
|
h2=${NETIFS[p3]}
|
||||||
|
swp2=${NETIFS[p4]}
|
||||||
|
|
||||||
|
swp3=${NETIFS[p6]}
|
||||||
|
|
||||||
|
vrf_prepare
|
||||||
|
|
||||||
|
h_create
|
||||||
|
|
||||||
|
switch_create
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup()
|
||||||
|
{
|
||||||
|
pre_cleanup
|
||||||
|
|
||||||
|
switch_destroy
|
||||||
|
|
||||||
|
h_destroy
|
||||||
|
|
||||||
|
vrf_cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_get_n_learned()
|
||||||
|
{
|
||||||
|
ip -d -j link show dev br0 type bridge | \
|
||||||
|
jq '.[]["linkinfo"]["info_data"]["fdb_n_learned"]'
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_get_n_mac()
|
||||||
|
{
|
||||||
|
local mac=${1}
|
||||||
|
|
||||||
|
bridge -j fdb show br br0 | \
|
||||||
|
jq "map(select(.mac == \"${mac}\" and (has(\"vlan\") | not))) | length"
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_fill_learned()
|
||||||
|
{
|
||||||
|
local i
|
||||||
|
|
||||||
|
for i in $(seq 1 "$NUM_PKTS"); do
|
||||||
|
fdb_add learned "$(mac "$i")"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_reset()
|
||||||
|
{
|
||||||
|
bridge fdb flush dev br0
|
||||||
|
|
||||||
|
# Keep the default MAC address of h1 in the table. We set it to a different one when
|
||||||
|
# testing dynamic learning.
|
||||||
|
bridge fdb add "$H1_DEFAULT_MAC" dev "$swp1" master static use
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_add()
|
||||||
|
{
|
||||||
|
local type=$1 mac=$2
|
||||||
|
|
||||||
|
case "$type" in
|
||||||
|
learned)
|
||||||
|
ip link set "$h1" addr "$mac"
|
||||||
|
# Wait for a reply so we implicitly wait until after the forwarding
|
||||||
|
# code finished and the FDB entry was created.
|
||||||
|
PING_COUNT=1 ping_do "$h1" 192.0.2.2
|
||||||
|
check_err $? "Failed to ping another bridge port"
|
||||||
|
ip link set "$h1" addr "$H1_DEFAULT_MAC"
|
||||||
|
;;
|
||||||
|
local)
|
||||||
|
ip link set dev "$swp3" addr "$mac" && ip link set "$swp3" master br0
|
||||||
|
;;
|
||||||
|
static)
|
||||||
|
bridge fdb replace "$mac" dev "$swp1" master static
|
||||||
|
;;
|
||||||
|
user)
|
||||||
|
bridge fdb replace "$mac" dev "$swp1" master static use
|
||||||
|
;;
|
||||||
|
extern_learn)
|
||||||
|
bridge fdb replace "$mac" dev "$swp1" master extern_learn
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
check_err $? "Failed to add a FDB entry of type ${type}"
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_del()
|
||||||
|
{
|
||||||
|
local type=$1 mac=$2
|
||||||
|
|
||||||
|
case "$type" in
|
||||||
|
local)
|
||||||
|
ip link set "$swp3" nomaster
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
bridge fdb del "$mac" dev "$swp1" master
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
check_err $? "Failed to remove a FDB entry of type ${type}"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_accounting_one_type()
|
||||||
|
{
|
||||||
|
local type=$1 is_counted=$2 overrides_learned=$3
|
||||||
|
shift 3
|
||||||
|
RET=0
|
||||||
|
|
||||||
|
fdb_reset
|
||||||
|
fdb_add "$type" "$(mac 0)"
|
||||||
|
learned=$(fdb_get_n_learned)
|
||||||
|
[ "$learned" -ne "$is_counted" ]
|
||||||
|
check_fail $? "Inserted FDB type ${type}: Expected the count ${is_counted}, but got ${learned}"
|
||||||
|
|
||||||
|
fdb_del "$type" "$(mac 0)"
|
||||||
|
learned=$(fdb_get_n_learned)
|
||||||
|
[ "$learned" -ne 0 ]
|
||||||
|
check_fail $? "Removed FDB type ${type}: Expected the count 0, but got ${learned}"
|
||||||
|
|
||||||
|
if [ "$overrides_learned" -eq 1 ]; then
|
||||||
|
fdb_reset
|
||||||
|
fdb_add learned "$(mac 0)"
|
||||||
|
fdb_add "$type" "$(mac 0)"
|
||||||
|
learned=$(fdb_get_n_learned)
|
||||||
|
[ "$learned" -ne "$is_counted" ]
|
||||||
|
check_fail $? "Set a learned entry to FDB type ${type}: Expected the count ${is_counted}, but got ${learned}"
|
||||||
|
fdb_del "$type" "$(mac 0)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_test "FDB accounting interacting with FDB type ${type}"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_accounting()
|
||||||
|
{
|
||||||
|
local type_args learned
|
||||||
|
RET=0
|
||||||
|
|
||||||
|
fdb_reset
|
||||||
|
learned=$(fdb_get_n_learned)
|
||||||
|
[ "$learned" -ne 0 ]
|
||||||
|
check_fail $? "Flushed the FDB table: Expected the count 0, but got ${learned}"
|
||||||
|
|
||||||
|
fdb_fill_learned
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
learned=$(fdb_get_n_learned)
|
||||||
|
[ "$learned" -ne "$NUM_PKTS" ]
|
||||||
|
check_fail $? "Filled the FDB table: Expected the count ${NUM_PKTS}, but got ${learned}"
|
||||||
|
|
||||||
|
log_test "FDB accounting"
|
||||||
|
|
||||||
|
for type_args in "${FDB_TYPES[@]}"; do
|
||||||
|
# This is intentional use of word splitting.
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
check_accounting_one_type $type_args
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
check_limit_one_type()
|
||||||
|
{
|
||||||
|
local type=$1 is_counted=$2
|
||||||
|
local n_mac expected=$((1 - is_counted))
|
||||||
|
RET=0
|
||||||
|
|
||||||
|
fdb_reset
|
||||||
|
fdb_fill_learned
|
||||||
|
|
||||||
|
fdb_add "$type" "$(mac 0)"
|
||||||
|
n_mac=$(fdb_get_n_mac "$(mac 0)")
|
||||||
|
[ "$n_mac" -ne "$expected" ]
|
||||||
|
check_fail $? "Inserted FDB type ${type} at limit: Expected the count ${expected}, but got ${n_mac}"
|
||||||
|
|
||||||
|
log_test "FDB limits interacting with FDB type ${type}"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_limit()
|
||||||
|
{
|
||||||
|
local learned
|
||||||
|
RET=0
|
||||||
|
|
||||||
|
ip link set br0 type bridge fdb_max_learned "$FDB_LIMIT"
|
||||||
|
|
||||||
|
fdb_reset
|
||||||
|
fdb_fill_learned
|
||||||
|
|
||||||
|
learned=$(fdb_get_n_learned)
|
||||||
|
[ "$learned" -ne "$FDB_LIMIT" ]
|
||||||
|
check_fail $? "Filled the limited FDB table: Expected the count ${FDB_LIMIT}, but got ${learned}"
|
||||||
|
|
||||||
|
log_test "FDB limits"
|
||||||
|
|
||||||
|
for type_args in "${FDB_TYPES[@]}"; do
|
||||||
|
# This is intentional use of word splitting.
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
check_limit_one_type $type_args
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
setup_prepare
|
||||||
|
|
||||||
|
tests_run
|
||||||
|
|
||||||
|
exit $EXIT_STATUS
|
Loading…
x
Reference in New Issue
Block a user