Add a selftest to verify that FOU-encapsulated packets addressed to a
multicast destination are correctly resubmitted to the inner protocol
handler (GRE) via the UDP multicast delivery path.

The test creates two network namespaces connected by a veth pair with
a FOU/GRETAP tunnel using a multicast remote address (239.0.0.1).
Ping is sent through the tunnel and received packets are counted on
the receiver's tunnel interface.

A static neighbor entry is configured on the sender because ARP
replies from the receiver cannot traverse the unidirectional multicast
tunnel back to the sender.

The early demux optimization (net.ipv4.ip_early_demux) is disabled on
the receiver to force packets through __udp4_lib_mcast_deliver(),
which is the code path being tested.

Signed-off-by: Anton Danilov <[email protected]>
Assisted-by: Claude:claude-opus-4-6
---
 tools/testing/selftests/net/Makefile          |   1 +
 .../testing/selftests/net/fou_mcast_encap.sh  | 112 ++++++++++++++++++
 2 files changed, 113 insertions(+)
 create mode 100755 tools/testing/selftests/net/fou_mcast_encap.sh

diff --git a/tools/testing/selftests/net/Makefile 
b/tools/testing/selftests/net/Makefile
index 708d960ae07d..7e9ae937cffa 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -39,6 +39,7 @@ TEST_PROGS := \
        fib_rule_tests.sh \
        fib_tests.sh \
        fin_ack_lat.sh \
+       fou_mcast_encap.sh \
        fq_band_pktlimit.sh \
        gre_gso.sh \
        gre_ipv6_lladdr.sh \
diff --git a/tools/testing/selftests/net/fou_mcast_encap.sh 
b/tools/testing/selftests/net/fou_mcast_encap.sh
new file mode 100755
index 000000000000..8db9633f4c28
--- /dev/null
+++ b/tools/testing/selftests/net/fou_mcast_encap.sh
@@ -0,0 +1,112 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test that UDP encapsulation (FOU) correctly handles packet resubmit
+# when packets are delivered via the multicast UDP delivery path.
+#
+# When a FOU-encapsulated packet arrives with a multicast destination IP,
+# __udp4_lib_mcast_deliver() must resubmit it to the inner protocol
+# handler (e.g., GRE) rather than consuming it. This test verifies that
+# by creating a FOU/GRETAP tunnel with a multicast remote address and
+# sending ping through it.
+#
+# The early demux optimization can mask this issue by routing packets via
+# the unicast path (udp_unicast_rcv_skb), so we disable it to force
+# packets through __udp4_lib_mcast_deliver().
+
+source lib.sh
+
+NSENDER=""
+NRECV=""
+
+cleanup() {
+       cleanup_all_ns
+}
+
+trap cleanup EXIT
+
+setup() {
+       setup_ns NSENDER NRECV
+
+       ip link add veth_s type veth peer name veth_r
+       ip link set veth_s netns "$NSENDER"
+       ip link set veth_r netns "$NRECV"
+
+       ip -n "$NSENDER" addr add 10.0.0.1/24 dev veth_s
+       ip -n "$NSENDER" link set veth_s up
+
+       ip -n "$NRECV" addr add 10.0.0.2/24 dev veth_r
+       ip -n "$NRECV" link set veth_r up
+
+       # Disable early demux to force multicast delivery path
+       ip netns exec "$NRECV" sysctl -wq net.ipv4.ip_early_demux=0
+
+       # Join multicast group on receiver
+       ip -n "$NRECV" addr add 239.0.0.1/32 dev veth_r autojoin
+
+       # Multicast routes
+       ip -n "$NRECV" route add 239.0.0.0/8 dev veth_r
+       ip -n "$NSENDER" route add 239.0.0.0/8 dev veth_s
+
+       # Sender: GRETAP with FOU encap (no FOU listener needed on TX side)
+       ip -n "$NSENDER" link add eoudp0 type gretap \
+               remote 239.0.0.1 local 10.0.0.1 \
+               encap fou encap-sport 4797 encap-dport 4797 \
+               key 239.0.0.1
+       ip -n "$NSENDER" link set eoudp0 up
+       ip -n "$NSENDER" addr add 192.168.99.1/24 dev eoudp0
+
+       # Receiver: FOU listener + GRETAP
+       ip netns exec "$NRECV" ip fou add port 4797 ipproto 47
+       ip -n "$NRECV" link add eoudp0 type gretap \
+               remote 239.0.0.1 local 10.0.0.2 \
+               encap fou encap-sport 4797 encap-dport 4797 \
+               key 239.0.0.1
+       ip -n "$NRECV" link set eoudp0 up
+       ip -n "$NRECV" addr add 192.168.99.2/24 dev eoudp0
+
+       # Static neigh entry on sender: ARP replies cannot traverse the
+       # multicast tunnel back, so pre-populate the neighbor cache.
+       local recv_mac
+       recv_mac=$(ip -n "$NRECV" link show eoudp0 | awk '/ether/{print $2}')
+       ip -n "$NSENDER" neigh add 192.168.99.2 lladdr "$recv_mac" dev eoudp0
+}
+
+get_rx_packets() {
+       ip -n "$NRECV" -s link show eoudp0 | awk '/RX:/{getline; print $2}'
+}
+
+test_fou_mcast_encap() {
+       local count=100
+       local rx_before
+       local rx_after
+       local rx_delta
+
+       # Warmup: let any initial broadcast/ARP traffic settle
+       ip netns exec "$NSENDER" ping -c 1 -W 1 192.168.99.2 >/dev/null 2>&1
+       sleep 1
+
+       rx_before=$(get_rx_packets)
+       ip netns exec "$NSENDER" ping -c $count -W 1 192.168.99.2 >/dev/null 
2>&1
+       sleep 1
+       rx_after=$(get_rx_packets)
+
+       rx_delta=$((rx_after - rx_before))
+
+       if [ "$rx_delta" -ge "$count" ]; then
+               echo "PASS: received $rx_delta/$count packets via multicast 
FOU/GRETAP"
+               return "$ksft_pass"
+       elif [ "$rx_delta" -gt 0 ]; then
+               echo "FAIL: only $rx_delta/$count packets received (partial 
delivery)"
+               return "$ksft_fail"
+       else
+               echo "FAIL: 0/$count packets received (multicast encap resubmit 
broken)"
+               return "$ksft_fail"
+       fi
+}
+
+echo "TEST: FOU/GRETAP multicast encapsulation resubmit"
+
+setup
+test_fou_mcast_encap
+exit $?
-- 
2.47.3


Reply via email to