forked from kernel-patches/bpf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests: forwarding: Add a selftest for the new reserved_bits UAPI
Run VXLAN packets through a gateway. Flip individual bits of the packet and/or reserved bits of the gateway, and check that the gateway treats the packets as expected. Signed-off-by: Petr Machata <petrm@nvidia.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> Link: https://patch.msgid.link/388bef3c30ebc887d4e64cd86a362e2df2f2d2e1.1733412063.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
- Loading branch information
Showing
2 changed files
with
353 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
352 changes: 352 additions & 0 deletions
352
tools/testing/selftests/net/forwarding/vxlan_reserved.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,352 @@ | ||
#!/bin/bash | ||
# SPDX-License-Identifier: GPL-2.0 | ||
|
||
# +--------------------+ | ||
# | H1 (vrf) | | ||
# | + $h1 | | ||
# | | 192.0.2.1/28 | | ||
# +----|---------------+ | ||
# | | ||
# +----|--------------------------------+ | ||
# | SW | | | ||
# | +--|------------------------------+ | | ||
# | | + $swp1 BR1 (802.1d) | | | ||
# | | | | | ||
# | | + vx1 (vxlan) | | | ||
# | | local 192.0.2.17 | | | ||
# | | id 1000 dstport $VXPORT | | | ||
# | +---------------------------------+ | | ||
# | | | ||
# | 192.0.2.32/28 via 192.0.2.18 | | ||
# | | | ||
# | + $rp1 | | ||
# | | 192.0.2.17/28 | | ||
# +--|----------------------------------+ | ||
# | | ||
# +--|----------------------------------+ | ||
# | | | | ||
# | + $rp2 | | ||
# | 192.0.2.18/28 | | ||
# | | | ||
# | VRP2 (vrf) | | ||
# +-------------------------------------+ | ||
|
||
: ${VXPORT:=4789} | ||
: ${ALL_TESTS:=" | ||
default_test | ||
plain_test | ||
reserved_0_test | ||
reserved_10_test | ||
reserved_31_test | ||
reserved_56_test | ||
reserved_63_test | ||
"} | ||
|
||
NUM_NETIFS=4 | ||
source lib.sh | ||
|
||
h1_create() | ||
{ | ||
simple_if_init $h1 192.0.2.1/28 | ||
defer simple_if_fini $h1 192.0.2.1/28 | ||
|
||
tc qdisc add dev $h1 clsact | ||
defer tc qdisc del dev $h1 clsact | ||
|
||
tc filter add dev $h1 ingress pref 77 \ | ||
prot ip flower skip_hw ip_proto icmp action drop | ||
defer tc filter del dev $h1 ingress pref 77 | ||
} | ||
|
||
switch_create() | ||
{ | ||
ip_link_add br1 type bridge vlan_filtering 0 mcast_snooping 0 | ||
# Make sure the bridge uses the MAC address of the local port and not | ||
# that of the VxLAN's device. | ||
ip_link_set_addr br1 $(mac_get $swp1) | ||
ip_link_set_up br1 | ||
|
||
ip_link_set_up $rp1 | ||
ip_addr_add $rp1 192.0.2.17/28 | ||
ip_route_add 192.0.2.32/28 nexthop via 192.0.2.18 | ||
|
||
ip_link_set_master $swp1 br1 | ||
ip_link_set_up $swp1 | ||
} | ||
|
||
vrp2_create() | ||
{ | ||
simple_if_init $rp2 192.0.2.18/28 | ||
defer simple_if_fini $rp2 192.0.2.18/28 | ||
} | ||
|
||
setup_prepare() | ||
{ | ||
h1=${NETIFS[p1]} | ||
swp1=${NETIFS[p2]} | ||
|
||
rp1=${NETIFS[p3]} | ||
rp2=${NETIFS[p4]} | ||
|
||
vrf_prepare | ||
defer vrf_cleanup | ||
|
||
forwarding_enable | ||
defer forwarding_restore | ||
|
||
h1_create | ||
switch_create | ||
|
||
vrp2_create | ||
} | ||
|
||
vxlan_header_bytes() | ||
{ | ||
local vni=$1; shift | ||
local -a extra_bits=("$@") | ||
local -a bits | ||
local i | ||
|
||
for ((i=0; i < 64; i++)); do | ||
bits[i]=0 | ||
done | ||
|
||
# Bit 4 is the I flag and is always on. | ||
bits[4]=1 | ||
|
||
for i in ${extra_bits[@]}; do | ||
bits[i]=1 | ||
done | ||
|
||
# Bits 32..55 carry the VNI | ||
local mask=0x800000 | ||
for ((i=0; i < 24; i++)); do | ||
bits[$((i + 32))]=$(((vni & mask) != 0)) | ||
((mask >>= 1)) | ||
done | ||
|
||
local bytes | ||
for ((i=0; i < 8; i++)); do | ||
local byte=0 | ||
local j | ||
for ((j=0; j < 8; j++)); do | ||
local bit=${bits[8 * i + j]} | ||
((byte += bit << (7 - j))) | ||
done | ||
bytes+=$(printf %02x $byte): | ||
done | ||
|
||
echo ${bytes%:} | ||
} | ||
|
||
neg_bytes() | ||
{ | ||
local bytes=$1; shift | ||
|
||
local -A neg=([0]=f [1]=e [2]=d [3]=c [4]=b [5]=a [6]=9 [7]=8 | ||
[8]=7 [9]=6 [a]=5 [b]=4 [c]=3 [d]=2 [e]=1 [f]=0 [:]=:) | ||
local out | ||
local i | ||
|
||
for ((i=0; i < ${#bytes}; i++)); do | ||
local c=${bytes:$i:1} | ||
out+=${neg[$c]} | ||
done | ||
echo $out | ||
} | ||
|
||
vxlan_ping_do() | ||
{ | ||
local count=$1; shift | ||
local dev=$1; shift | ||
local next_hop_mac=$1; shift | ||
local dest_ip=$1; shift | ||
local dest_mac=$1; shift | ||
local vni=$1; shift | ||
local reserved_bits=$1; shift | ||
|
||
local vxlan_header=$(vxlan_header_bytes $vni $reserved_bits) | ||
|
||
$MZ $dev -c $count -d 100msec -q \ | ||
-b $next_hop_mac -B $dest_ip \ | ||
-t udp sp=23456,dp=$VXPORT,p=$(: | ||
)"$vxlan_header:"$( : VXLAN | ||
)"$dest_mac:"$( : ETH daddr | ||
)"00:11:22:33:44:55:"$( : ETH saddr | ||
)"08:00:"$( : ETH type | ||
)"45:"$( : IP version + IHL | ||
)"00:"$( : IP TOS | ||
)"00:54:"$( : IP total length | ||
)"99:83:"$( : IP identification | ||
)"40:00:"$( : IP flags + frag off | ||
)"40:"$( : IP TTL | ||
)"01:"$( : IP proto | ||
)"00:00:"$( : IP header csum | ||
)"$(ipv4_to_bytes 192.0.2.3):"$( : IP saddr | ||
)"$(ipv4_to_bytes 192.0.2.1):"$( : IP daddr | ||
)"08:"$( : ICMP type | ||
)"00:"$( : ICMP code | ||
)"8b:f2:"$( : ICMP csum | ||
)"1f:6a:"$( : ICMP request identifier | ||
)"00:01:"$( : ICMP request seq. number | ||
)"4f:ff:c5:5b:00:00:00:00:"$( : ICMP payload | ||
)"6d:74:0b:00:00:00:00:00:"$( : | ||
)"10:11:12:13:14:15:16:17:"$( : | ||
)"18:19:1a:1b:1c:1d:1e:1f:"$( : | ||
)"20:21:22:23:24:25:26:27:"$( : | ||
)"28:29:2a:2b:2c:2d:2e:2f:"$( : | ||
)"30:31:32:33:34:35:36:37" | ||
} | ||
|
||
vxlan_device_add() | ||
{ | ||
ip_link_add vx1 up type vxlan id 1000 \ | ||
local 192.0.2.17 dstport "$VXPORT" \ | ||
nolearning noudpcsum tos inherit ttl 100 "$@" | ||
ip_link_set_master vx1 br1 | ||
} | ||
|
||
vxlan_all_reserved_bits() | ||
{ | ||
local i | ||
|
||
for ((i=0; i < 64; i++)); do | ||
if ((i == 4 || i >= 32 && i < 56)); then | ||
continue | ||
fi | ||
echo $i | ||
done | ||
} | ||
|
||
vxlan_ping_vanilla() | ||
{ | ||
vxlan_ping_do 10 $rp2 $(mac_get $rp1) 192.0.2.17 $(mac_get $h1) 1000 | ||
} | ||
|
||
vxlan_ping_reserved() | ||
{ | ||
for bit in $(vxlan_all_reserved_bits); do | ||
vxlan_ping_do 1 $rp2 $(mac_get $rp1) \ | ||
192.0.2.17 $(mac_get $h1) 1000 "$bit" | ||
((n++)) | ||
done | ||
} | ||
|
||
vxlan_ping_test() | ||
{ | ||
local what=$1; shift | ||
local get_stat=$1; shift | ||
local expect=$1; shift | ||
|
||
RET=0 | ||
|
||
local t0=$($get_stat) | ||
|
||
"$@" | ||
check_err $? "Failure when running $@" | ||
|
||
local t1=$($get_stat) | ||
local delta=$((t1 - t0)) | ||
|
||
((expect == delta)) | ||
check_err $? "Expected to capture $expect packets, got $delta." | ||
|
||
log_test "$what" | ||
} | ||
|
||
__default_test_do() | ||
{ | ||
local n_allowed_bits=$1; shift | ||
local what=$1; shift | ||
|
||
vxlan_ping_test "$what: clean packets" \ | ||
"tc_rule_stats_get $h1 77 ingress" \ | ||
10 vxlan_ping_vanilla | ||
|
||
local t0=$(link_stats_get vx1 rx errors) | ||
vxlan_ping_test "$what: mangled packets" \ | ||
"tc_rule_stats_get $h1 77 ingress" \ | ||
$n_allowed_bits vxlan_ping_reserved | ||
local t1=$(link_stats_get vx1 rx errors) | ||
|
||
RET=0 | ||
local expect=$((39 - n_allowed_bits)) | ||
local delta=$((t1 - t0)) | ||
((expect == delta)) | ||
check_err $? "Expected $expect error packets, got $delta." | ||
log_test "$what: drops reported" | ||
} | ||
|
||
default_test_do() | ||
{ | ||
vxlan_device_add | ||
__default_test_do 0 "Default" | ||
} | ||
|
||
default_test() | ||
{ | ||
in_defer_scope \ | ||
default_test_do | ||
} | ||
|
||
plain_test_do() | ||
{ | ||
vxlan_device_add reserved_bits 0xf7ffffff000000ff | ||
__default_test_do 0 "reserved_bits 0xf7ffffff000000ff" | ||
} | ||
|
||
plain_test() | ||
{ | ||
in_defer_scope \ | ||
plain_test_do | ||
} | ||
|
||
reserved_test() | ||
{ | ||
local bit=$1; shift | ||
|
||
local allowed_bytes=$(vxlan_header_bytes 0xffffff $bit) | ||
local reserved_bytes=$(neg_bytes $allowed_bytes) | ||
local reserved_bits=${reserved_bytes//:/} | ||
|
||
vxlan_device_add reserved_bits 0x$reserved_bits | ||
__default_test_do 1 "reserved_bits 0x$reserved_bits" | ||
} | ||
|
||
reserved_0_test() | ||
{ | ||
in_defer_scope \ | ||
reserved_test 0 | ||
} | ||
|
||
reserved_10_test() | ||
{ | ||
in_defer_scope \ | ||
reserved_test 10 | ||
} | ||
|
||
reserved_31_test() | ||
{ | ||
in_defer_scope \ | ||
reserved_test 31 | ||
} | ||
|
||
reserved_56_test() | ||
{ | ||
in_defer_scope \ | ||
reserved_test 56 | ||
} | ||
|
||
reserved_63_test() | ||
{ | ||
in_defer_scope \ | ||
reserved_test 63 | ||
} | ||
|
||
trap cleanup EXIT | ||
|
||
setup_prepare | ||
setup_wait | ||
tests_run | ||
|
||
exit $EXIT_STATUS |