Exercise the two drop reasons added to ip_tunnel_rcv() and __ip6_tnl_rcv() for the cases they were introduced for, on both GRE and ip6gre:
- a receiver configured with 'iseq' or 'icsum' facing a sender that emits neither reports IP_TUNNEL_CFG_OPTS_MISMATCH, - recreating the tunnel device on the sender resets its outgoing sequence number the way a peer reboot would, and the receiver then reports IP_TUNNEL_OLD_SEQ. A control case, where both endpoints agree on the options, makes sure that no tunnel drop reason is reported when the packets are accepted. The reasons are read from the skb:kfree_skb tracepoint through a dedicated trace instance, so that the test neither disturbs nor depends on anything else using the tracing facility. The test is skipped when that instance cannot be set up. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Anton Danilov <[email protected]> --- tools/testing/selftests/net/Makefile | 1 + tools/testing/selftests/net/config | 1 + .../selftests/net/tunnel_drop_reasons.sh | 228 ++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100755 tools/testing/selftests/net/tunnel_drop_reasons.sh diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 0f5c178bc224..9acf364e8919 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -117,6 +117,7 @@ TEST_PROGS := \ test_vxlan_vnifiltering.sh \ tfo_passive.sh \ traceroute.sh \ + tunnel_drop_reasons.sh \ txtimestamp.sh \ udpgro.sh \ udpgro_bench.sh \ diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index 30d5fcb09a83..281633ff3aa9 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config @@ -14,6 +14,7 @@ CONFIG_CRYPTO_SM4_GENERIC=y CONFIG_DEBUG_INFO_BTF=y CONFIG_DEBUG_INFO_BTF_MODULES=n CONFIG_DUMMY=y +CONFIG_ENABLE_DEFAULT_TRACERS=y CONFIG_GENEVE=m CONFIG_IFB=y CONFIG_INET_DIAG=y diff --git a/tools/testing/selftests/net/tunnel_drop_reasons.sh b/tools/testing/selftests/net/tunnel_drop_reasons.sh new file mode 100755 index 000000000000..eb19967ae7dd --- /dev/null +++ b/tools/testing/selftests/net/tunnel_drop_reasons.sh @@ -0,0 +1,228 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Test the drop reasons reported by the generic tunnel RX path, +# ip_tunnel_rcv() and __ip6_tnl_rcv(). +# +# Two situations are checked, for both GRE and ip6gre: +# +# - the options carried by the packet do not match the tunnel +# configuration, which is reported as IP_TUNNEL_CFG_OPTS_MISMATCH. +# It is triggered here by configuring the receiver with 'iseq' or +# 'icsum' while the sender emits neither. +# +# - the sequence number of the packet is older than the one expected by +# the tunnel, which is reported as IP_TUNNEL_OLD_SEQ. It is +# triggered here by recreating the tunnel device on the sender, which +# resets its outgoing sequence number the same way a peer reboot +# would. +# +# A control case, where both endpoints agree on the options, makes sure +# that no tunnel drop reason is reported when packets are accepted. +# +# Drop reasons are read from the skb:kfree_skb tracepoint. A dedicated +# trace instance is used so that the test does not disturb, and is not +# disturbed by, anything else using the tracing facility. + +source lib.sh + +NS_SND="" +NS_RCV="" +TRACE_DIR="" +TR="" + +SND_V4=10.0.0.1 +RCV_V4=10.0.0.2 +SND_V6=2001:db8::1 +RCV_V6=2001:db8::2 +TUN_SND=192.168.1.1 +TUN_RCV=192.168.1.2 + +cleanup() +{ + if [ -n "$TR" ]; then + echo 0 > "$TR/events/skb/kfree_skb/enable" 2>/dev/null + rmdir "$TR" 2>/dev/null + fi + cleanup_all_ns +} + +trap cleanup EXIT + +setup_tracing() +{ + local dir + + for dir in /sys/kernel/tracing /sys/kernel/debug/tracing; do + if [ -f "$dir/trace" ]; then + TRACE_DIR="$dir" + break + fi + done + [ -n "$TRACE_DIR" ] || return 1 + [ -d "$TRACE_DIR/instances" ] || return 1 + [ -e "$TRACE_DIR/events/skb/kfree_skb" ] || return 1 + + TR="$TRACE_DIR/instances/tunnel_drop_reasons" + mkdir "$TR" 2>/dev/null || return 1 + echo 1 > "$TR/events/skb/kfree_skb/enable" || return 1 +} + +setup_ns_pair() +{ + cleanup_all_ns + setup_ns NS_SND NS_RCV + + ip link add veth_s netns "$NS_SND" type veth \ + peer name veth_r netns "$NS_RCV" + ip -n "$NS_SND" link set veth_s up + ip -n "$NS_RCV" link set veth_r up + + ip -n "$NS_SND" addr add "$SND_V4/24" dev veth_s + ip -n "$NS_RCV" addr add "$RCV_V4/24" dev veth_r + ip -n "$NS_SND" addr add "$SND_V6/64" dev veth_s nodad + ip -n "$NS_RCV" addr add "$RCV_V6/64" dev veth_r nodad +} + +# $1: namespace, $2: local, $3: remote, $4...: tunnel options +add_gre() +{ + local ns=$1 loc=$2 rem=$3 + + shift 3 + ip -n "$ns" link add gre_test type gre local "$loc" remote "$rem" "$@" + ip -n "$ns" link set gre_test up +} + +# $1: namespace, $2: local, $3: remote, $4...: tunnel options +add_ip6gre() +{ + local ns=$1 loc=$2 rem=$3 + + shift 3 + ip -n "$ns" link add gre_test type ip6gre local "$loc" remote "$rem" \ + "$@" + ip -n "$ns" link set gre_test up +} + +addr_tunnels() +{ + ip -n "$NS_SND" addr add "$TUN_SND/24" dev gre_test + ip -n "$NS_RCV" addr add "$TUN_RCV/24" dev gre_test +} + +send_traffic() +{ + ip netns exec "$NS_SND" ping -c 2 -W 1 "$TUN_RCV" >/dev/null 2>&1 + # Let the tracepoint records reach the trace buffer. + sleep 1 +} + +# $1: test name, $2: expected reason, empty if none is expected +check_reason() +{ + local name=$1 want=$2 count + + echo > "$TR/trace" + send_traffic + + if [ -n "$want" ]; then + count=$(grep -c "reason: $want" "$TR/trace") + if [ "$count" -gt 0 ]; then + RET=$ksft_pass + else + RET=$ksft_fail + fi + log_test "$name" "$count dropped" + else + count=$(grep -c "reason: IP_TUNNEL_" "$TR/trace") + if [ "$count" -eq 0 ]; then + RET=$ksft_pass + else + RET=$ksft_fail + fi + log_test "$name" "$count dropped" + fi +} + +test_opts_mismatch() +{ + local proto=$1 opt=$2 + local add=add_gre loc=$SND_V4 rem=$RCV_V4 + + if [ "$proto" = "ip6gre" ]; then + add=add_ip6gre + loc=$SND_V6 + rem=$RCV_V6 + fi + + setup_ns_pair + # The sender emits no option, the receiver expects one. + $add "$NS_SND" "$loc" "$rem" + $add "$NS_RCV" "$rem" "$loc" "$opt" + addr_tunnels + + check_reason "$proto: $opt option mismatch" \ + IP_TUNNEL_CFG_OPTS_MISMATCH +} + +test_old_seq() +{ + local proto=$1 + local add=add_gre loc=$SND_V4 rem=$RCV_V4 + + if [ "$proto" = "ip6gre" ]; then + add=add_ip6gre + loc=$SND_V6 + rem=$RCV_V6 + fi + + setup_ns_pair + $add "$NS_SND" "$loc" "$rem" oseq + $add "$NS_RCV" "$rem" "$loc" iseq + addr_tunnels + + # Raise the sequence number expected by the receiver, then reset the + # one used by the sender, as a peer reboot would do. + send_traffic + ip -n "$NS_SND" link del gre_test + $add "$NS_SND" "$loc" "$rem" oseq + ip -n "$NS_SND" addr add "$TUN_SND/24" dev gre_test + + check_reason "$proto: old sequence number" IP_TUNNEL_OLD_SEQ +} + +test_control() +{ + setup_ns_pair + add_gre "$NS_SND" "$SND_V4" "$RCV_V4" oseq ocsum + add_gre "$NS_RCV" "$RCV_V4" "$SND_V4" iseq icsum + addr_tunnels + + check_reason "gre: matching configuration (control)" "" +} + +if [ "$(id -u)" -ne 0 ]; then + echo "SKIP: need root" + exit "$ksft_skip" +fi + +if ! setup_tracing; then + echo "SKIP: could not set up a trace instance for skb:kfree_skb" + exit "$ksft_skip" +fi + +test_opts_mismatch gre iseq +test_opts_mismatch gre icsum +test_control +test_old_seq gre + +if [ -e /proc/sys/net/ipv6 ]; then + test_opts_mismatch ip6gre iseq + test_old_seq ip6gre +else + log_test_skip "ip6gre: iseq option mismatch" + log_test_skip "ip6gre: old sequence number" +fi + +exit "$EXIT_STATUS" -- 2.47.3

