-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests: forwarding: router_mpath_hash: Add a new selftest
Add a selftest that exercises the sysctl added in the previous patches. Test that set/get works as expected; that across seeds we eventually hit all NHs (test_mpath_seed_*); and that a given seed keeps hitting the same NHs even across seed changes (test_mpath_seed_stability_*). Signed-off-by: Petr Machata <[email protected]> Reviewed-by: Ido Schimmel <[email protected]> Reviewed-by: Nikolay Aleksandrov <[email protected]> Reviewed-by: David Ahern <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
- Loading branch information
Showing
2 changed files
with
334 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
333 changes: 333 additions & 0 deletions
333
tools/testing/selftests/net/forwarding/router_mpath_seed.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,333 @@ | ||
#!/bin/bash | ||
# SPDX-License-Identifier: GPL-2.0 | ||
|
||
# +-------------------------+ +-------------------------+ | ||
# | H1 | | H2 | | ||
# | $h1 + | | + $h2 | | ||
# | 192.0.2.1/28 | | | | 192.0.2.34/28 | | ||
# | 2001:db8:1::1/64 | | | | 2001:db8:3::2/64 | | ||
# +-------------------|-----+ +-|-----------------------+ | ||
# | | | ||
# +-------------------|-----+ +-|-----------------------+ | ||
# | R1 | | | | R2 | | ||
# | $rp11 + | | + $rp21 | | ||
# | 192.0.2.2/28 | | 192.0.2.33/28 | | ||
# | 2001:db8:1::2/64 | | 2001:db8:3::1/64 | | ||
# | | | | | ||
# | $rp12 + | | + $rp22 | | ||
# | 192.0.2.17/28 | | | | 192.0.2.18..27/28 | | ||
# | 2001:db8:2::17/64 | | | | 2001:db8:2::18..27/64 | | ||
# +-------------------|-----+ +-|-----------------------+ | ||
# | | | ||
# `----------' | ||
|
||
ALL_TESTS=" | ||
ping_ipv4 | ||
ping_ipv6 | ||
test_mpath_seed_stability_ipv4 | ||
test_mpath_seed_stability_ipv6 | ||
test_mpath_seed_get | ||
test_mpath_seed_ipv4 | ||
test_mpath_seed_ipv6 | ||
" | ||
NUM_NETIFS=6 | ||
source lib.sh | ||
|
||
h1_create() | ||
{ | ||
simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64 | ||
ip -4 route add 192.0.2.32/28 vrf v$h1 nexthop via 192.0.2.2 | ||
ip -6 route add 2001:db8:3::/64 vrf v$h1 nexthop via 2001:db8:1::2 | ||
} | ||
|
||
h1_destroy() | ||
{ | ||
ip -6 route del 2001:db8:3::/64 vrf v$h1 nexthop via 2001:db8:1::2 | ||
ip -4 route del 192.0.2.32/28 vrf v$h1 nexthop via 192.0.2.2 | ||
simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64 | ||
} | ||
|
||
h2_create() | ||
{ | ||
simple_if_init $h2 192.0.2.34/28 2001:db8:3::2/64 | ||
ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.33 | ||
ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:3::1 | ||
} | ||
|
||
h2_destroy() | ||
{ | ||
ip -6 route del 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:3::1 | ||
ip -4 route del 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.33 | ||
simple_if_fini $h2 192.0.2.34/28 2001:db8:3::2/64 | ||
} | ||
|
||
router1_create() | ||
{ | ||
simple_if_init $rp11 192.0.2.2/28 2001:db8:1::2/64 | ||
__simple_if_init $rp12 v$rp11 192.0.2.17/28 2001:db8:2::17/64 | ||
} | ||
|
||
router1_destroy() | ||
{ | ||
__simple_if_fini $rp12 192.0.2.17/28 2001:db8:2::17/64 | ||
simple_if_fini $rp11 192.0.2.2/28 2001:db8:1::2/64 | ||
} | ||
|
||
router2_create() | ||
{ | ||
simple_if_init $rp21 192.0.2.33/28 2001:db8:3::1/64 | ||
__simple_if_init $rp22 v$rp21 192.0.2.18/28 2001:db8:2::18/64 | ||
ip -4 route add 192.0.2.0/28 vrf v$rp21 nexthop via 192.0.2.17 | ||
ip -6 route add 2001:db8:1::/64 vrf v$rp21 nexthop via 2001:db8:2::17 | ||
} | ||
|
||
router2_destroy() | ||
{ | ||
ip -6 route del 2001:db8:1::/64 vrf v$rp21 nexthop via 2001:db8:2::17 | ||
ip -4 route del 192.0.2.0/28 vrf v$rp21 nexthop via 192.0.2.17 | ||
__simple_if_fini $rp22 192.0.2.18/28 2001:db8:2::18/64 | ||
simple_if_fini $rp21 192.0.2.33/28 2001:db8:3::1/64 | ||
} | ||
|
||
nexthops_create() | ||
{ | ||
local i | ||
for i in $(seq 10); do | ||
ip nexthop add id $((1000 + i)) via 192.0.2.18 dev $rp12 | ||
ip nexthop add id $((2000 + i)) via 2001:db8:2::18 dev $rp12 | ||
done | ||
|
||
ip nexthop add id 1000 group $(seq -s / 1001 1010) hw_stats on | ||
ip nexthop add id 2000 group $(seq -s / 2001 2010) hw_stats on | ||
ip -4 route add 192.0.2.32/28 vrf v$rp11 nhid 1000 | ||
ip -6 route add 2001:db8:3::/64 vrf v$rp11 nhid 2000 | ||
} | ||
|
||
nexthops_destroy() | ||
{ | ||
local i | ||
|
||
ip -6 route del 2001:db8:3::/64 vrf v$rp11 nhid 2000 | ||
ip -4 route del 192.0.2.32/28 vrf v$rp11 nhid 1000 | ||
ip nexthop del id 2000 | ||
ip nexthop del id 1000 | ||
|
||
for i in $(seq 10 -1 1); do | ||
ip nexthop del id $((2000 + i)) | ||
ip nexthop del id $((1000 + i)) | ||
done | ||
} | ||
|
||
setup_prepare() | ||
{ | ||
h1=${NETIFS[p1]} | ||
rp11=${NETIFS[p2]} | ||
|
||
rp12=${NETIFS[p3]} | ||
rp22=${NETIFS[p4]} | ||
|
||
rp21=${NETIFS[p5]} | ||
h2=${NETIFS[p6]} | ||
|
||
sysctl_save net.ipv4.fib_multipath_hash_seed | ||
|
||
vrf_prepare | ||
|
||
h1_create | ||
h2_create | ||
router1_create | ||
router2_create | ||
|
||
forwarding_enable | ||
} | ||
|
||
cleanup() | ||
{ | ||
pre_cleanup | ||
|
||
forwarding_restore | ||
|
||
nexthops_destroy | ||
router2_destroy | ||
router1_destroy | ||
h2_destroy | ||
h1_destroy | ||
|
||
vrf_cleanup | ||
|
||
sysctl_restore net.ipv4.fib_multipath_hash_seed | ||
} | ||
|
||
ping_ipv4() | ||
{ | ||
ping_test $h1 192.0.2.34 | ||
} | ||
|
||
ping_ipv6() | ||
{ | ||
ping6_test $h1 2001:db8:3::2 | ||
} | ||
|
||
test_mpath_seed_get() | ||
{ | ||
RET=0 | ||
|
||
local i | ||
for ((i = 0; i < 100; i++)); do | ||
local seed_w=$((999331 * i)) | ||
sysctl -qw net.ipv4.fib_multipath_hash_seed=$seed_w | ||
local seed_r=$(sysctl -n net.ipv4.fib_multipath_hash_seed) | ||
((seed_r == seed_w)) | ||
check_err $? "mpath seed written as $seed_w, but read as $seed_r" | ||
done | ||
|
||
log_test "mpath seed set/get" | ||
} | ||
|
||
nh_stats_snapshot() | ||
{ | ||
local group_id=$1; shift | ||
|
||
ip -j -s -s nexthop show id $group_id | | ||
jq -c '[.[].group_stats | sort_by(.id) | .[].packets]' | ||
} | ||
|
||
get_active_nh() | ||
{ | ||
local s0=$1; shift | ||
local s1=$1; shift | ||
|
||
jq -n --argjson s0 "$s0" --argjson s1 "$s1" -f /dev/stdin <<-"EOF" | ||
[range($s0 | length)] | | ||
map($s1[.] - $s0[.]) | | ||
map(if . > 8 then 1 else 0 end) | | ||
index(1) | ||
EOF | ||
} | ||
|
||
probe_nh() | ||
{ | ||
local group_id=$1; shift | ||
local -a mz=("$@") | ||
|
||
local s0=$(nh_stats_snapshot $group_id) | ||
"${mz[@]}" | ||
local s1=$(nh_stats_snapshot $group_id) | ||
|
||
get_active_nh "$s0" "$s1" | ||
} | ||
|
||
probe_seed() | ||
{ | ||
local group_id=$1; shift | ||
local seed=$1; shift | ||
local -a mz=("$@") | ||
|
||
sysctl -qw net.ipv4.fib_multipath_hash_seed=$seed | ||
probe_nh "$group_id" "${mz[@]}" | ||
} | ||
|
||
test_mpath_seed() | ||
{ | ||
local group_id=$1; shift | ||
local what=$1; shift | ||
local -a mz=("$@") | ||
local ii | ||
|
||
RET=0 | ||
|
||
local -a tally=(0 0 0 0 0 0 0 0 0 0) | ||
for ((ii = 0; ii < 100; ii++)); do | ||
local act=$(probe_seed $group_id $((999331 * ii)) "${mz[@]}") | ||
((tally[act]++)) | ||
done | ||
|
||
local tally_str="${tally[@]}" | ||
for ((ii = 0; ii < ${#tally[@]}; ii++)); do | ||
((tally[ii] > 0)) | ||
check_err $? "NH #$ii not hit, tally='$tally_str'" | ||
done | ||
|
||
log_test "mpath seed $what" | ||
sysctl -qw net.ipv4.fib_multipath_hash_seed=0 | ||
} | ||
|
||
test_mpath_seed_ipv4() | ||
{ | ||
test_mpath_seed 1000 IPv4 \ | ||
$MZ $h1 -A 192.0.2.1 -B 192.0.2.34 -q \ | ||
-p 64 -d 0 -c 10 -t udp | ||
} | ||
|
||
test_mpath_seed_ipv6() | ||
{ | ||
test_mpath_seed 2000 IPv6 \ | ||
$MZ -6 $h1 -A 2001:db8:1::1 -B 2001:db8:3::2 -q \ | ||
-p 64 -d 0 -c 10 -t udp | ||
} | ||
|
||
check_mpath_seed_stability() | ||
{ | ||
local seed=$1; shift | ||
local act_0=$1; shift | ||
local act_1=$1; shift | ||
|
||
((act_0 == act_1)) | ||
check_err $? "seed $seed: active NH moved from $act_0 to $act_1 after seed change" | ||
} | ||
|
||
test_mpath_seed_stability() | ||
{ | ||
local group_id=$1; shift | ||
local what=$1; shift | ||
local -a mz=("$@") | ||
|
||
RET=0 | ||
|
||
local seed_0=0 | ||
local seed_1=3221338814 | ||
local seed_2=3735928559 | ||
|
||
# Initial active NH before touching the seed at all. | ||
local act_ini=$(probe_nh $group_id "${mz[@]}") | ||
|
||
local act_0_0=$(probe_seed $group_id $seed_0 "${mz[@]}") | ||
local act_1_0=$(probe_seed $group_id $seed_1 "${mz[@]}") | ||
local act_2_0=$(probe_seed $group_id $seed_2 "${mz[@]}") | ||
|
||
local act_0_1=$(probe_seed $group_id $seed_0 "${mz[@]}") | ||
local act_1_1=$(probe_seed $group_id $seed_1 "${mz[@]}") | ||
local act_2_1=$(probe_seed $group_id $seed_2 "${mz[@]}") | ||
|
||
check_mpath_seed_stability initial $act_ini $act_0_0 | ||
check_mpath_seed_stability $seed_0 $act_0_0 $act_0_1 | ||
check_mpath_seed_stability $seed_1 $act_1_0 $act_1_1 | ||
check_mpath_seed_stability $seed_2 $act_2_0 $act_2_1 | ||
|
||
log_test "mpath seed stability $what" | ||
sysctl -qw net.ipv4.fib_multipath_hash_seed=0 | ||
} | ||
|
||
test_mpath_seed_stability_ipv4() | ||
{ | ||
test_mpath_seed_stability 1000 IPv4 \ | ||
$MZ $h1 -A 192.0.2.1 -B 192.0.2.34 -q \ | ||
-p 64 -d 0 -c 10 -t udp | ||
} | ||
|
||
test_mpath_seed_stability_ipv6() | ||
{ | ||
test_mpath_seed_stability 2000 IPv6 \ | ||
$MZ -6 $h1 -A 2001:db8:1::1 -B 2001:db8:3::2 -q \ | ||
-p 64 -d 0 -c 10 -t udp | ||
} | ||
|
||
trap cleanup EXIT | ||
|
||
setup_prepare | ||
setup_wait | ||
nexthops_create | ||
|
||
tests_run | ||
|
||
exit $EXIT_STATUS |