1*e5382133SAnton Danilov#!/bin/bash 2*e5382133SAnton Danilov# SPDX-License-Identifier: GPL-2.0 3*e5382133SAnton Danilov# 4*e5382133SAnton Danilov# Test that UDP encapsulation (FOU) correctly handles packet resubmit 5*e5382133SAnton Danilov# when packets are delivered via the multicast UDP delivery path. 6*e5382133SAnton Danilov# 7*e5382133SAnton Danilov# When a FOU-encapsulated packet arrives with a multicast destination IP, 8*e5382133SAnton Danilov# __udp4_lib_mcast_deliver() / __udp6_lib_mcast_deliver() must resubmit 9*e5382133SAnton Danilov# it to the inner protocol handler (e.g., GRE) rather than consuming it. 10*e5382133SAnton Danilov# This test verifies both IPv4 and IPv6 paths by creating a FOU/GRETAP 11*e5382133SAnton Danilov# tunnel with a multicast remote address and sending ping through it. 12*e5382133SAnton Danilov# 13*e5382133SAnton Danilov# The early demux optimization can mask this issue by routing packets via 14*e5382133SAnton Danilov# the unicast path (udp[6]_unicast_rcv_skb), so we disable it to force 15*e5382133SAnton Danilov# packets through the multicast delivery function. 16*e5382133SAnton Danilov 17*e5382133SAnton Danilovsource lib.sh 18*e5382133SAnton Danilov 19*e5382133SAnton DanilovNSENDER="" 20*e5382133SAnton DanilovNRECV="" 21*e5382133SAnton Danilov 22*e5382133SAnton DanilovFOU_PORT4=4797 23*e5382133SAnton DanilovFOU_PORT6=4798 24*e5382133SAnton DanilovMCAST4=239.0.0.1 25*e5382133SAnton DanilovMCAST6=ff0e::1 26*e5382133SAnton Danilov 27*e5382133SAnton DanilovTUN4_S=192.168.99.1 28*e5382133SAnton DanilovTUN4_R=192.168.99.2 29*e5382133SAnton DanilovTUN6_S=2001:db8:99::1 30*e5382133SAnton DanilovTUN6_R=2001:db8:99::2 31*e5382133SAnton Danilov 32*e5382133SAnton Danilovcleanup() { 33*e5382133SAnton Danilov cleanup_all_ns 34*e5382133SAnton Danilov} 35*e5382133SAnton Danilov 36*e5382133SAnton Danilovtrap cleanup EXIT 37*e5382133SAnton Danilov 38*e5382133SAnton Danilovsetup_common() { 39*e5382133SAnton Danilov setup_ns NSENDER NRECV 40*e5382133SAnton Danilov 41*e5382133SAnton Danilov # Create veth pair directly inside namespaces to avoid name 42*e5382133SAnton Danilov # collisions with devices in the root namespace. 43*e5382133SAnton Danilov ip link add veth_s netns "$NSENDER" type veth \ 44*e5382133SAnton Danilov peer name veth_r netns "$NRECV" 45*e5382133SAnton Danilov 46*e5382133SAnton Danilov ip -n "$NSENDER" link set veth_s up 47*e5382133SAnton Danilov ip -n "$NRECV" link set veth_r up 48*e5382133SAnton Danilov 49*e5382133SAnton Danilov # Same sysctl controls early demux for both IPv4 and IPv6. 50*e5382133SAnton Danilov ip netns exec "$NRECV" sysctl -wq net.ipv4.ip_early_demux=0 51*e5382133SAnton Danilov} 52*e5382133SAnton Danilov 53*e5382133SAnton Danilovsetup_ipv4() { 54*e5382133SAnton Danilov # IPv4 FOU (CONFIG_NET_FOU) is built in on kernels configured for 55*e5382133SAnton Danilov # these tests, so no module load is needed here. 56*e5382133SAnton Danilov ip -n "$NSENDER" addr add 10.0.0.1/24 dev veth_s 57*e5382133SAnton Danilov ip -n "$NRECV" addr add 10.0.0.2/24 dev veth_r 58*e5382133SAnton Danilov 59*e5382133SAnton Danilov # Join multicast group on receiver 60*e5382133SAnton Danilov ip -n "$NRECV" addr add "$MCAST4/32" dev veth_r autojoin 61*e5382133SAnton Danilov 62*e5382133SAnton Danilov ip -n "$NSENDER" route add 239.0.0.0/8 dev veth_s 63*e5382133SAnton Danilov ip -n "$NRECV" route add 239.0.0.0/8 dev veth_r 64*e5382133SAnton Danilov 65*e5382133SAnton Danilov # Sender: GRETAP with FOU encap (no FOU listener needed on TX side) 66*e5382133SAnton Danilov ip -n "$NSENDER" link add eoudp4 type gretap \ 67*e5382133SAnton Danilov remote "$MCAST4" local 10.0.0.1 \ 68*e5382133SAnton Danilov encap fou encap-sport "$FOU_PORT4" encap-dport "$FOU_PORT4" \ 69*e5382133SAnton Danilov key "$MCAST4" 70*e5382133SAnton Danilov ip -n "$NSENDER" link set eoudp4 up 71*e5382133SAnton Danilov ip -n "$NSENDER" addr add "$TUN4_S/24" dev eoudp4 72*e5382133SAnton Danilov 73*e5382133SAnton Danilov # Receiver: FOU listener + GRETAP 74*e5382133SAnton Danilov ip netns exec "$NRECV" ip fou add port "$FOU_PORT4" ipproto 47 75*e5382133SAnton Danilov ip -n "$NRECV" link add eoudp4 type gretap \ 76*e5382133SAnton Danilov remote "$MCAST4" local 10.0.0.2 \ 77*e5382133SAnton Danilov encap fou encap-sport "$FOU_PORT4" encap-dport "$FOU_PORT4" \ 78*e5382133SAnton Danilov key "$MCAST4" 79*e5382133SAnton Danilov ip -n "$NRECV" link set eoudp4 up 80*e5382133SAnton Danilov ip -n "$NRECV" addr add "$TUN4_R/24" dev eoudp4 81*e5382133SAnton Danilov 82*e5382133SAnton Danilov # Static neigh on sender: ARP replies cannot traverse the 83*e5382133SAnton Danilov # unidirectional multicast tunnel. 84*e5382133SAnton Danilov local recv_mac 85*e5382133SAnton Danilov recv_mac=$(ip -n "$NRECV" link show eoudp4 | awk '/ether/{print $2}') 86*e5382133SAnton Danilov ip -n "$NSENDER" neigh add "$TUN4_R" lladdr "$recv_mac" dev eoudp4 87*e5382133SAnton Danilov} 88*e5382133SAnton Danilov 89*e5382133SAnton Danilovsetup_ipv6() { 90*e5382133SAnton Danilov # Skip cleanly if IPv6 or the fou6 module is not available. 91*e5382133SAnton Danilov [ -e /proc/sys/net/ipv6 ] || return "$ksft_skip" 92*e5382133SAnton Danilov modprobe -q fou6 || return "$ksft_skip" 93*e5382133SAnton Danilov 94*e5382133SAnton Danilov ip -n "$NSENDER" addr add 2001:db8::1/64 dev veth_s nodad 95*e5382133SAnton Danilov ip -n "$NRECV" addr add 2001:db8::2/64 dev veth_r nodad 96*e5382133SAnton Danilov 97*e5382133SAnton Danilov # Join multicast group on receiver 98*e5382133SAnton Danilov ip -n "$NRECV" addr add "$MCAST6/128" dev veth_r autojoin 99*e5382133SAnton Danilov 100*e5382133SAnton Danilov ip -n "$NSENDER" -6 route add ff00::/8 dev veth_s 101*e5382133SAnton Danilov ip -n "$NRECV" -6 route add ff00::/8 dev veth_r 102*e5382133SAnton Danilov 103*e5382133SAnton Danilov # Sender: ip6gretap with FOU encap 104*e5382133SAnton Danilov ip -n "$NSENDER" link add eoudp6 type ip6gretap \ 105*e5382133SAnton Danilov remote "$MCAST6" local 2001:db8::1 \ 106*e5382133SAnton Danilov encap fou encap-sport "$FOU_PORT6" encap-dport "$FOU_PORT6" \ 107*e5382133SAnton Danilov key 42 108*e5382133SAnton Danilov ip -n "$NSENDER" link set eoudp6 up 109*e5382133SAnton Danilov ip -n "$NSENDER" addr add "$TUN6_S/64" dev eoudp6 nodad 110*e5382133SAnton Danilov 111*e5382133SAnton Danilov # Receiver: FOU listener (IPv6) + ip6gretap 112*e5382133SAnton Danilov ip netns exec "$NRECV" ip fou add port "$FOU_PORT6" ipproto 47 -6 113*e5382133SAnton Danilov ip -n "$NRECV" link add eoudp6 type ip6gretap \ 114*e5382133SAnton Danilov remote "$MCAST6" local 2001:db8::2 \ 115*e5382133SAnton Danilov encap fou encap-sport "$FOU_PORT6" encap-dport "$FOU_PORT6" \ 116*e5382133SAnton Danilov key 42 117*e5382133SAnton Danilov ip -n "$NRECV" link set eoudp6 up 118*e5382133SAnton Danilov ip -n "$NRECV" addr add "$TUN6_R/64" dev eoudp6 nodad 119*e5382133SAnton Danilov 120*e5382133SAnton Danilov # Static neigh on sender: neighbor discovery cannot traverse the 121*e5382133SAnton Danilov # unidirectional multicast tunnel. 122*e5382133SAnton Danilov local recv_mac 123*e5382133SAnton Danilov recv_mac=$(ip -n "$NRECV" link show eoudp6 | awk '/ether/{print $2}') 124*e5382133SAnton Danilov ip -n "$NSENDER" neigh add "$TUN6_R" lladdr "$recv_mac" dev eoudp6 125*e5382133SAnton Danilov} 126*e5382133SAnton Danilov 127*e5382133SAnton Danilovget_rx_packets() { 128*e5382133SAnton Danilov local dev="$1" 129*e5382133SAnton Danilov 130*e5382133SAnton Danilov ip -n "$NRECV" -s link show "$dev" | awk '/RX:/{getline; print $2}' 131*e5382133SAnton Danilov} 132*e5382133SAnton Danilov 133*e5382133SAnton Danilovrun_ping_test() { 134*e5382133SAnton Danilov local family="$1" 135*e5382133SAnton Danilov local dev="$2" 136*e5382133SAnton Danilov local dst="$3" 137*e5382133SAnton Danilov local name="$4" 138*e5382133SAnton Danilov local count=100 139*e5382133SAnton Danilov local rx_before rx_after rx_delta 140*e5382133SAnton Danilov 141*e5382133SAnton Danilov # Warmup: let any initial broadcast/ND traffic settle 142*e5382133SAnton Danilov ip netns exec "$NSENDER" ping "$family" -c 1 -W 1 "$dst" \ 143*e5382133SAnton Danilov >/dev/null 2>&1 144*e5382133SAnton Danilov sleep 1 145*e5382133SAnton Danilov 146*e5382133SAnton Danilov rx_before=$(get_rx_packets "$dev") 147*e5382133SAnton Danilov ip netns exec "$NSENDER" ping "$family" -i 0.01 -c $count -W 1 "$dst" \ 148*e5382133SAnton Danilov >/dev/null 2>&1 149*e5382133SAnton Danilov sleep 1 150*e5382133SAnton Danilov rx_after=$(get_rx_packets "$dev") 151*e5382133SAnton Danilov 152*e5382133SAnton Danilov rx_delta=$((rx_after - rx_before)) 153*e5382133SAnton Danilov 154*e5382133SAnton Danilov if [ "$rx_delta" -ge "$count" ]; then 155*e5382133SAnton Danilov RET=$ksft_pass 156*e5382133SAnton Danilov else 157*e5382133SAnton Danilov RET=$ksft_fail 158*e5382133SAnton Danilov fi 159*e5382133SAnton Danilov log_test "$name (received $rx_delta/$count)" 160*e5382133SAnton Danilov} 161*e5382133SAnton Danilov 162*e5382133SAnton Danilovsetup_common 163*e5382133SAnton Danilovsetup_ipv4 164*e5382133SAnton Danilovrun_ping_test -4 eoudp4 "$TUN4_R" "FOU/GRETAP IPv4 multicast encap resubmit" 165*e5382133SAnton Danilov 166*e5382133SAnton Danilovif setup_ipv6; then 167*e5382133SAnton Danilov run_ping_test -6 eoudp6 "$TUN6_R" "FOU/ip6gretap IPv6 multicast encap resubmit" 168*e5382133SAnton Danilovelse 169*e5382133SAnton Danilov log_test_skip "FOU/ip6gretap IPv6 multicast encap resubmit" 170*e5382133SAnton Danilovfi 171*e5382133SAnton Danilov 172*e5382133SAnton Danilovexit "$EXIT_STATUS" 173