diff mbox series

[nf,2/2] selftests: netfilter: add nft_fib_nexthop test

Message ID 20260519041431.396218-2-jiayuan.chen@linux.dev
State Changes Requested, archived
Delegated to: Florian Westphal
Headers show
Series [nf,1/2] netfilter: nft_fib_ipv6: handle routes via external nexthop | expand

Commit Message

Jiayuan Chen May 19, 2026, 4:14 a.m. UTC
Cover nft_fib6_eval() over three route shapes and reproduce the OOB
caused by the blind &rt->fib6_siblings walk:

  1) single external nexthop (nhid)
  2) external nexthop group (nhid -> group)
  3) old-style multipath (nexthop ... nexthop ...)

After the fix:

  ./nft_fib_nexthop.sh
  Nothing to flush
  PASS: single external nexthop (nhid)
  Flushed 1 nexthops
  PASS: nexthop group (nhid group 1/2)
  Flushed 2 nexthops
  PASS: old-style multipath (fib6_siblings)

Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
 .../testing/selftests/net/netfilter/Makefile  |   1 +
 .../net/netfilter/nft_fib_nexthop.sh          | 104 ++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100755 tools/testing/selftests/net/netfilter/nft_fib_nexthop.sh

Comments

Florian Westphal May 19, 2026, 6:53 p.m. UTC | #1
Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
> Cover nft_fib6_eval() over three route shapes and reproduce the OOB
> caused by the blind &rt->fib6_siblings walk:
> 
>   1) single external nexthop (nhid)
>   2) external nexthop group (nhid -> group)
>   3) old-style multipath (nexthop ... nexthop ...)

https://sashiko.dev/#/patchset/20260519041431.396218-1-jiayuan.chen%40linux.dev

Specifially: 'Does the test need to verify the datapath actually
evaluated correctly?' and
'It looks like the test also sets up an nftables counter rule but doesn't
verify if the rule actually matched any packets.'

I prefer functionality test over 'bug trap' tests.
Jiayuan Chen May 20, 2026, 1:26 a.m. UTC | #2
On 5/20/26 2:53 AM, Florian Westphal wrote:
> Specifially: 'Does the test need to verify the datapath actually
> evaluated correctly?' and
> 'It looks like the test also sets up an nftables counter rule but doesn't
> verify if the rule actually matched any packets.'
>
> I prefer functionality test over 'bug trap' tests.


Agreed -- functional verification is the right approach here.
diff mbox series

Patch

diff --git a/tools/testing/selftests/net/netfilter/Makefile b/tools/testing/selftests/net/netfilter/Makefile
index ee2d1a5254f8..d953ee218c0f 100644
--- a/tools/testing/selftests/net/netfilter/Makefile
+++ b/tools/testing/selftests/net/netfilter/Makefile
@@ -26,6 +26,7 @@  TEST_PROGS := \
 	nft_concat_range.sh \
 	nft_conntrack_helper.sh \
 	nft_fib.sh \
+	nft_fib_nexthop.sh \
 	nft_flowtable.sh \
 	nft_interface_stress.sh \
 	nft_meta.sh \
diff --git a/tools/testing/selftests/net/netfilter/nft_fib_nexthop.sh b/tools/testing/selftests/net/netfilter/nft_fib_nexthop.sh
new file mode 100755
index 000000000000..76f934156c8c
--- /dev/null
+++ b/tools/testing/selftests/net/netfilter/nft_fib_nexthop.sh
@@ -0,0 +1,104 @@ 
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# shellcheck disable=SC2154
+#
+# Exercise nft_fib6_eval()'s sibling/nh enumeration on three route shapes:
+#   1) route via a single external nexthop (nhid)
+#   2) route via an external nexthop group (nhid -> group)
+#   3) route via old-style multipath (nexthop ... nexthop ...)
+#
+# Topology similar to nft_fib.sh, without ns2; two dummy interfaces on
+# nsrouter host the nh devices:
+#
+#   dead:1::99           dead:1::1     dummy0 dead:2::1
+#   ns1 <-----veth----->         nsrouter
+#                                       dummy1 dead:9::1
+
+source lib.sh
+
+ret=0
+
+checktool "nft --version" "run test without nft"
+checktool "ip -V"         "run test without iproute2"
+
+setup_ns nsrouter ns1
+trap cleanup_all_ns EXIT
+
+if ! ip link add veth0 netns "$nsrouter" type veth peer name eth0 netns "$ns1" \
+	> /dev/null 2>&1; then
+	echo "SKIP: No virtual ethernet pair device support in kernel"
+	exit $ksft_skip
+fi
+
+ip -net "$ns1" link set lo up
+ip -net "$ns1" link set eth0 up
+ip -net "$ns1" -6 addr add dead:1::99/64 dev eth0 nodad
+ip -net "$ns1" -6 route add default via dead:1::1
+
+ip -net "$nsrouter" link set lo up
+ip -net "$nsrouter" link set veth0 up
+ip -net "$nsrouter" -6 addr add dead:1::1/64 dev veth0 nodad
+
+if ! ip -net "$nsrouter" link add dummy0 type dummy 2>/dev/null; then
+	echo "SKIP: dummy netdev not available"
+	exit $ksft_skip
+fi
+ip -net "$nsrouter" link set dummy0 up
+ip -net "$nsrouter" -6 addr add dead:2::1/64 dev dummy0 nodad
+
+ip -net "$nsrouter" link add dummy1 type dummy
+ip -net "$nsrouter" link set dummy1 up
+ip -net "$nsrouter" -6 addr add dead:9::1/64 dev dummy1 nodad
+
+ip netns exec "$nsrouter" sysctl -q net.ipv6.conf.all.forwarding=1
+
+load_fib_rule() {
+	ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF
+flush ruleset
+table ip6 t {
+	chain c {
+		type filter hook prerouting priority 0; policy accept;
+		fib daddr . iif oif missing counter
+	}
+}
+EOF
+}
+
+run_scenario() {
+	local what="$1"; shift
+
+	ip -net "$nsrouter" -6 route del dead:dead::/64 2>/dev/null || true
+	ip -net "$nsrouter" -6 nexthop flush 2>/dev/null || true
+
+	"$@" || { echo "SKIP ($what): could not configure route"; return; }
+
+	load_fib_rule || { echo "FAIL ($what): nft load"; ret=1; return; }
+
+	ip netns exec "$ns1" ping -6 -c 1 -W 1 dead:dead::1 \
+		> /dev/null 2>&1 || true
+
+	echo "PASS: $what"
+}
+
+scenario_single_nh() {
+	ip -net "$nsrouter" nexthop add id 1 via dead:2::2 dev dummy0
+	ip -net "$nsrouter" -6 route add dead:dead::/64 nhid 1
+}
+run_scenario "single external nexthop (nhid)" scenario_single_nh
+
+scenario_nh_group() {
+	ip -net "$nsrouter" nexthop add id 1   via dead:2::2 dev dummy0
+	ip -net "$nsrouter" nexthop add id 2   via dead:9::2 dev dummy1
+	ip -net "$nsrouter" nexthop add id 100 group 1/2
+	ip -net "$nsrouter" -6 route   add dead:dead::/64 nhid 100
+}
+run_scenario "nexthop group (nhid group 1/2)" scenario_nh_group
+
+scenario_old_multipath() {
+	ip -net "$nsrouter" -6 route add dead:dead::/64 \
+		nexthop via dead:2::2 dev dummy0 \
+		nexthop via dead:9::2 dev dummy1
+}
+run_scenario "old-style multipath (fib6_siblings)" scenario_old_multipath
+
+exit $ret