mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net 0/2] ipv6: honor rule suppression in raw FIB lookups
@ 2026-11-10 13:16 Leonard Lausen
  2026-11-10 13:16 ` [PATCH net 1/2] " Leonard Lausen
  2026-11-10 13:16 ` [PATCH net 2/2] selftests: netfilter: cover IPv6 FIB rule suppression Leonard Lausen
  0 siblings, 2 replies; 5+ messages in thread
From: Leonard Lausen @ 2026-11-10 13:16 UTC (permalink / raw)
  To: netdev
  Cc: leonard, David Ahern, Ido Schimmel, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Pablo Neira Ayuso, Florian Westphal, Phil Sutter, Shuah Khan,
	Daniel Borkmann, netfilter-devel, coreteam, linux-kselftest,
	linux-kernel

IPv6 raw FIB lookups ignore suppress_prefixlength and suppress_ifgroup
because the suppression callback only examines the dst-based result.
This can make nftables select a suppressed main-table default instead of
a VPN route, causing strict reverse-path filtering to drop VPN replies.

Patch 1 supplies the prefix length and output device from the appropriate
result representation. It preserves reject results: raw lookups can
return success with RTF_REJECT set, whereas dst-based lookups report an
error and skip suppression. Destination-reference handling is unchanged.

Patch 2 extends the existing nft_fib.sh fixture with unicast suppression
and retention checks, plus a loop covering all three terminal reject
route types under both suppression attributes.

The series targets net and is based on v7.4-rc2 (7475ea8b5861).

Validation:
- The original VPN failure was reproduced on unmodified v7.4-rc2 in QEMU
  without kernel instrumentation.
- The final fib6_rules.c compiles without warnings with the laptop's
  existing configuration. Its extracted suppression callback passes 17
  ASan/UBSan checks, including reject results from blackhole nexthops and
  destination-reference handling.
- On the rebuilt v7.4-rc2-based laptop kernel, all ten added selftest
  cases pass and nft_fib.sh exits successfully. A separate twelve-probe
  test confirms that blackhole, unreachable, prohibit and blackhole
  nexthop results remain terminal with no suppression, prefix suppression
  and matching interface-group suppression.

OpenAI Codex assisted with investigation, reproduction, implementation,
testing and these descriptions. The prompts asked it to investigate the
VPN failure, validate on v7.4-rc2, simplify the series and preserve
terminal reject routes. Both patches carry Assisted-by: LLM.

Leonard Lausen (2):
  ipv6: honor rule suppression in raw FIB lookups
  selftests: netfilter: cover IPv6 FIB rule suppression

 net/ipv6/fib6_rules.c                         | 32 ++++++---
 .../selftests/net/netfilter/nft_fib.sh        | 68 +++++++++++++++++++
 2 files changed, 90 insertions(+), 10 deletions(-)


base-commit: 7475ea8b58616b33c04afb976cf0fbaad9dd63fb
-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net 1/2] ipv6: honor rule suppression in raw FIB lookups
  2026-11-10 13:16 [PATCH net 0/2] ipv6: honor rule suppression in raw FIB lookups Leonard Lausen
@ 2026-11-10 13:16 ` Leonard Lausen
  2026-11-14 22:54   ` netdev-bot+sashiko
  2026-11-10 13:16 ` [PATCH net 2/2] selftests: netfilter: cover IPv6 FIB rule suppression Leonard Lausen
  1 sibling, 1 reply; 5+ messages in thread
From: Leonard Lausen @ 2026-11-10 13:16 UTC (permalink / raw)
  To: netdev
  Cc: leonard, David Ahern, Ido Schimmel, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Pablo Neira Ayuso, Florian Westphal, Phil Sutter, Shuah Khan,
	Daniel Borkmann, netfilter-devel, coreteam, linux-kselftest,
	linux-kernel

IPv6 raw FIB lookups populate f6i and nh in fib6_result, but not rt6.
fib6_rule_suppress() only examines rt6, so fib6_lookup() ignores
suppress_prefixlength and suppress_ifgroup.

With a policy rule that suppresses the main-table default route before
looking in a VPN table, an ordinary route lookup selects the VPN while
an nftables FIB lookup returns the suppressed default. Strict reverse-path
filtering can then drop replies arriving over the VPN. Policy-aware BPF
FIB lookups use the same raw lookup path.

Select the suppression inputs according to the lookup callback. For raw
lookups, use the FIB entry's destination prefix length and the selected
nexthop's device. Keep the existing inputs and destination-reference
handling for dst-based lookups.

Preserve raw results marked RTF_REJECT. The rule engine only calls the
suppression callback when the rule action returns zero. Dst-based lookups
return an error for terminal reject routes and therefore skip suppression,
whereas raw lookups can return zero with a rejection encoded in the result.
Suppressing that result would allow a later rule to bypass the rejection.
Check the result flags so blackhole nexthop objects are covered too.

Investigated with AI assistance after VPN failures on a Samsung laptop.
The original bug was reproduced on unmodified v7.4-rc2 in QEMU without
kernel instrumentation. The final fib6_rules.c compiles without warnings
and its extracted suppression callback passes focused ASan/UBSan tests.
On the rebuilt v7.4-rc2-based laptop kernel, all ten added nft_fib.sh
checks pass. Separate probes also preserve all three terminal reject types
and blackhole nexthop results with and without either suppression option.

Fixes: 138118ec96cb ("net/ipv6: Add fib6_lookup")
Link: https://github.com/firewalld/firewalld/issues/1600
Assisted-by: LLM
Signed-off-by: Leonard Lausen <leonard@lausen.nl>
---
 net/ipv6/fib6_rules.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 0ffd7b47a046..e8a44b540291 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -283,19 +283,29 @@ INDIRECT_CALLABLE_SCOPE bool fib6_rule_suppress(struct fib_rule *rule,
 						struct fib_lookup_arg *arg)
 {
 	struct fib6_result *res = arg->result;
-	struct rt6_info *rt = res->rt6;
+	struct rt6_info *rt = NULL;
 	struct net_device *dev = NULL;
-
-	if (!rt)
-		return false;
-
-	if (rt->rt6i_idev)
-		dev = rt->rt6i_idev->dev;
+	int plen;
+
+	if (arg->lookup_ptr == fib6_table_lookup) {
+		/* Raw lookups report reject routes without an error. */
+		if (res->fib6_flags & RTF_REJECT)
+			return false;
+		plen = res->f6i->fib6_dst.plen;
+		dev = res->nh->fib_nh_dev;
+	} else {
+		rt = res->rt6;
+		if (!rt)
+			return false;
+		plen = rt->rt6i_dst.plen;
+		if (rt->rt6i_idev)
+			dev = rt->rt6i_idev->dev;
+	}
 
 	/* do not accept result if the route does
 	 * not meet the required prefix length
 	 */
-	if (rt->rt6i_dst.plen <= rule->suppress_prefixlen)
+	if (plen <= rule->suppress_prefixlen)
 		goto suppress_route;
 
 	/* do not accept result if the route uses a device
@@ -307,8 +317,10 @@ INDIRECT_CALLABLE_SCOPE bool fib6_rule_suppress(struct fib_rule *rule,
 	return false;
 
 suppress_route:
-	ip6_rt_put_flags(rt, flags);
-	res->rt6 = NULL;
+	if (rt) {
+		ip6_rt_put_flags(rt, flags);
+		res->rt6 = NULL;
+	}
 	return true;
 }
 
-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH net 2/2] selftests: netfilter: cover IPv6 FIB rule suppression
  2026-11-10 13:16 [PATCH net 0/2] ipv6: honor rule suppression in raw FIB lookups Leonard Lausen
  2026-11-10 13:16 ` [PATCH net 1/2] " Leonard Lausen
@ 2026-11-10 13:16 ` Leonard Lausen
  2026-11-14 22:55   ` netdev-bot+sashiko
  1 sibling, 1 reply; 5+ messages in thread
From: Leonard Lausen @ 2026-11-10 13:16 UTC (permalink / raw)
  To: netdev
  Cc: leonard, David Ahern, Ido Schimmel, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Pablo Neira Ayuso, Florian Westphal, Phil Sutter, Shuah Khan,
	Daniel Borkmann, netfilter-devel, coreteam, linux-kselftest,
	linux-kernel

Extend nft_fib.sh using its existing namespaces, interfaces and counter
helper to exercise suppress_prefixlength and suppress_ifgroup.

Check that a default route and a route through a matching interface group
are suppressed, while a non-default route and a nonmatching group remain
usable. Also check that blackhole, unreachable and prohibit routes remain
terminal under either suppression attribute despite a usable route in a
later table.

Count an arriving probe only when the nftables FIB result matches the
expected output interface or reject type. Compare this with an ordinary
route lookup, which must select the expected device or fail for a reject
route. Requiring a positive counter avoids treating a missing packet as
proof of correct suppression.

Assisted-by: LLM
Signed-off-by: Leonard Lausen <leonard@lausen.nl>
---
 .../selftests/net/netfilter/nft_fib.sh        | 68 +++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/tools/testing/selftests/net/netfilter/nft_fib.sh b/tools/testing/selftests/net/netfilter/nft_fib.sh
index 04544905c216..02b625794669 100755
--- a/tools/testing/selftests/net/netfilter/nft_fib.sh
+++ b/tools/testing/selftests/net/netfilter/nft_fib.sh
@@ -202,6 +202,38 @@ check_fib_counter() {
 	return 0
 }
 
+# Count and drop probes before the existing RPF rules can log expected failures.
+test_fib_suppress() {
+	local label="$1" expected="$2"
+	local result="${3:-oifname}" err=0
+
+	ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF || return 1
+flush table ip6 filter
+table ip6 filter {
+	chain prerouting {
+		type filter hook prerouting priority -1;
+		ip6 saddr dead:1::99 icmpv6 type echo-request \
+			fib saddr . mark $result "$expected" counter drop
+	}
+}
+EOF
+	ip netns exec "$ns1" ping -6 -c 1 -W 0.1 -q dead:1::1 > /dev/null 2>&1
+	if [ "$result" = type ]; then
+		ip -net "$nsrouter" -6 route get dead:1::99 from dead:1::1 > /dev/null 2>&1 && err=1
+	else
+		ip -net "$nsrouter" -6 route get dead:1::99 from dead:1::1 |
+			grep -q "dev $expected " || err=1
+	fi
+	if check_fib_type_counter_family ip6 1 "$nsrouter" prerouting "$result" "$label" &&
+	   [ "$err" -eq 0 ]; then
+		echo "PASS: $label"
+	else
+		echo "FAIL: $label"
+		ret=1
+		return 1
+	fi
+}
+
 load_ruleset "$nsrouter"
 load_ruleset "$ns1"
 load_ruleset "$ns2"
@@ -724,6 +756,42 @@ test_fib_vrf()
 	check_fib_veth_vrf_type "fib expression address types match (iif in vrf)"
 }
 
+# Test both suppression attributes before the other policy-routing tests.
+# The non-default route and nonmatching group must remain usable.
+ip -net "$nsrouter" -6 route add table 128 default dev veth1 || exit 1
+ip -net "$nsrouter" -6 route add table 129 dead:1::/64 dev veth0 || exit 1
+ip -net "$nsrouter" link set veth1 group 42 || exit 1
+ip -net "$nsrouter" -6 rule add pref 100 to dead:1::99 table 128 suppress_prefixlength 0 || exit 1
+ip -net "$nsrouter" -6 rule add pref 101 to dead:1::99 table 129 || exit 1
+ip netns exec "$nsrouter" nft add table ip6 filter || exit 1
+
+test_fib_suppress "suppress default route" veth0 || ret=1
+ip -net "$nsrouter" -6 route add table 128 dead:1::/64 dev veth1 || exit 1
+test_fib_suppress "retain non-default route" veth1 || ret=1
+ip -net "$nsrouter" -6 rule del pref 100
+ip -net "$nsrouter" -6 rule add pref 100 to dead:1::99 table 128 suppress_ifgroup 42 || exit 1
+test_fib_suppress "suppress matching interface group" veth0 || ret=1
+ip -net "$nsrouter" link set veth1 group 43 || exit 1
+test_fib_suppress "retain nonmatching interface group" veth1 || ret=1
+
+# Reject routes use loopback (group 0) and must remain terminal.
+ip -net "$nsrouter" -6 route flush table 128
+for suppress in suppress_prefixlength suppress_ifgroup; do
+	ip -net "$nsrouter" -6 rule del pref 100
+	ip -net "$nsrouter" -6 rule add pref 100 to dead:1::99 table 128 "$suppress" 0 || exit 1
+	for type in blackhole unreachable prohibit; do
+		ip -net "$nsrouter" -6 route replace "$type" default table 128 || exit 1
+		test_fib_suppress "retain $type ($suppress)" "$type" type || ret=1
+	done
+done
+
+ip -net "$nsrouter" -6 rule del pref 100
+ip -net "$nsrouter" -6 rule del pref 101
+ip -net "$nsrouter" -6 route flush table 128
+ip -net "$nsrouter" -6 route flush table 129
+ip -net "$nsrouter" link set veth1 group 0
+ip netns exec "$nsrouter" nft delete table ip6 filter
+
 ip netns exec "$nsrouter" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null
 ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null
 ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null
-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net 1/2] ipv6: honor rule suppression in raw FIB lookups
  2026-11-10 13:16 ` [PATCH net 1/2] " Leonard Lausen
@ 2026-11-14 22:54   ` netdev-bot+sashiko
  0 siblings, 0 replies; 5+ messages in thread
From: netdev-bot+sashiko @ 2026-11-14 22:54 UTC (permalink / raw)
  To: leonard
  Cc: netdev, dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
	pablo, fw, phil, shuah, daniel, netfilter-devel, coreteam,
	linux-kselftest, linux-kernel

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.

Critical: 0 · High: 0 · Medium: 1 · Low: 0

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] For raw lookups, fib6_rule_suppress() (net/ipv6/fib6_rules.c)
  evaluates suppress_ifgroup against a different nexthop than the dst-…

--

ipv6: honor rule suppression in raw FIB lookups

This patch makes fib6_rule_suppress() apply suppress_prefixlength and
suppress_ifgroup to raw fib6_table_lookup() results. For those results it
takes the prefix length from res->f6i and the device from res->nh. Raw
results marked RTF_REJECT are never suppressed, so a later rule cannot
bypass the rejection.

Link: https://github.com/firewalld/firewalld/issues/1600

> diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
> index 0ffd7b47a0460..e8a44b540291d 100644
> --- a/net/ipv6/fib6_rules.c
> +++ b/net/ipv6/fib6_rules.c
> @@ -283,19 +283,29 @@ INDIRECT_CALLABLE_SCOPE bool fib6_rule_suppress(struct fib_rule *rule,
>  						struct fib_lookup_arg *arg)
>  {
>  	struct fib6_result *res = arg->result;
> -	struct rt6_info *rt = res->rt6;
> +	struct rt6_info *rt = NULL;
>  	struct net_device *dev = NULL;
> -
> -	if (!rt)
> -		return false;
> -
> -	if (rt->rt6i_idev)
> -		dev = rt->rt6i_idev->dev;
> +	int plen;
> +
> +	if (arg->lookup_ptr == fib6_table_lookup) {
> +		/* Raw lookups report reject routes without an error. */
> +		if (res->fib6_flags & RTF_REJECT)
> +			return false;
> +		plen = res->f6i->fib6_dst.plen;
> +		dev = res->nh->fib_nh_dev;

[Severity: Medium]
For multipath routes, is this the same nexthop that the dst-based path
checks?

On the raw path, res->nh is whatever fib6_table_lookup() picked. For
multipath that is usually the first sibling or the first usable member of
the nexthop group. fib6_rule_action_alt() never calls fib6_select_path().

The dst-based path selects the path before it builds the rt6_info whose
rt6i_idev the old code looked at:

net/ipv6/route.c:ip6_pol_route() {
    ...
	fib6_select_path(net, &res, fl6, oif, have_oif_match, skb, strict);
    ...
}

fib6_select_path() then replaces res->nh (and res->f6i for siblings) with
the hash-selected path, which may be on a different device:

net/ipv6/route.c:fib6_select_path() {
    ...
	if (unlikely(match->nh)) {
		nexthop_path_fib6_result(res, fl6->mp_hash);
		return;
	}
    ...
out:
	res->f6i = match;
	res->nh = match->fib6_nh;
}

bpf_ipv6_fib_lookup() runs path selection only after fib6_lookup() has
already made the suppression decision:

net/core/filter.c:bpf_ipv6_fib_lookup() {
    ...
	err = fib6_lookup(net, oif, &fl6, &res, strict);
    ...
	fib6_select_path(net, &res, &fl6, fl6.flowi6_oif,
			 fl6.flowi6_oif != 0, NULL, strict);
    ...
	dev = res.nh->fib_nh_dev;
	params->ifindex = dev->ifindex;
    ...
}

Consider a multipath route whose nexthops are on devices in different
interface groups, plus a rule like "ip -6 rule ... lookup <tbl>
suppress_ifgroup N". Could a flow be suppressed by the ordinary route
lookup but not by the nft fib or BPF raw lookup, or the other way round?

Can bpf_fib_lookup also return a device in the suppressed group that
suppression never evaluated?

That would leave the same raw versus ordinary disagreement the commit
message says this patch removes. suppress_prefixlength does not appear to
be affected, since siblings share one prefix.

> +	} else {
> +		rt = res->rt6;
> +		if (!rt)
> +			return false;
> +		plen = rt->rt6i_dst.plen;
> +		if (rt->rt6i_idev)
> +			dev = rt->rt6i_idev->dev;
> +	}

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261110131638.15004-3-leonard%40lausen.nl

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net 2/2] selftests: netfilter: cover IPv6 FIB rule suppression
  2026-11-10 13:16 ` [PATCH net 2/2] selftests: netfilter: cover IPv6 FIB rule suppression Leonard Lausen
@ 2026-11-14 22:55   ` netdev-bot+sashiko
  0 siblings, 0 replies; 5+ messages in thread
From: netdev-bot+sashiko @ 2026-11-14 22:55 UTC (permalink / raw)
  To: leonard
  Cc: netdev, dsahern, idosch, davem, edumazet, kuba, pabeni, horms,
	pablo, fw, phil, shuah, daniel, netfilter-devel, coreteam,
	linux-kselftest, linux-kernel

Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.

Critical: 0 · High: 0 · Medium: 1 · Low: 1

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] The ICMPv6 neighbour discovery replies that this test itself
  triggers can make the existing logging RPF rule fire, and…
- [Low] The new reject-route checks in nft_fib.sh only create legacy
  reject route types, via `ip -6 route replace $type default table 128`…

--

selftests: netfilter: cover IPv6 FIB rule suppression

This commit extends nft_fib.sh to exercise suppress_prefixlength and
suppress_ifgroup for IPv6 FIB rules. It checks that default routes and
routes through a matching interface group are suppressed. It also checks
that non-default routes and nonmatching groups stay usable, and that
blackhole, unreachable and prohibit routes remain terminal.

> diff --git a/tools/testing/selftests/net/netfilter/nft_fib.sh b/tools/testing/selftests/net/netfilter/nft_fib.sh
> index 04544905c2164..02b6257946694 100755
> --- a/tools/testing/selftests/net/netfilter/nft_fib.sh
> +++ b/tools/testing/selftests/net/netfilter/nft_fib.sh
> @@ -202,6 +202,38 @@ check_fib_counter() {
>  	return 0
>  }
>  
> +# Count and drop probes before the existing RPF rules can log expected failures.
> +test_fib_suppress() {
> +	local label="$1" expected="$2"
> +	local result="${3:-oifname}" err=0
> +
> +	ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF || return 1
> +flush table ip6 filter
> +table ip6 filter {
> +	chain prerouting {
> +		type filter hook prerouting priority -1;
> +		ip6 saddr dead:1::99 icmpv6 type echo-request \
> +			fib saddr . mark $result "$expected" counter drop
> +	}
> +}
> +EOF

[Severity: Medium]

The comment above test_fib_suppress() says probes are dropped before the
existing RPF rules can log expected failures. This chain only matches
echo-request, though.

Can other ICMPv6 packets from dead:1::99 still reach the logging rule that
load_ruleset() installed on nsrouter?

load_ruleset() {
    ...
	        fib saddr . iif oif missing counter log prefix "$netns nft_rpfilter: " drop
    ...
}

In most of the states this block sets up, dead:1::99 does not resolve to
veth0. In "retain non-default route" and "retain nonmatching interface
group" the lookup picks dead:1::/64 dev veth1. In the six reject loop
states, nft_fib6_eval() returns with no oif.

The block itself looks like it produces such a packet:

1. The first ping makes ns1 send an NS from dead:1::99. ndisc_recv_ns() on
   nsrouter creates a NUD_STALE neighbour entry. Sending the NA reply moves
   it to NUD_DELAY with a DELAY_PROBE_TIME (5s) timer.

2. All echo-requests are dropped, so nothing confirms the entry. About 5s
   later neigh_timer_handler() moves it to NUD_PROBE, and nsrouter sends a
   unicast NS to dead:1::99.

3. ns1 answers through ndisc_send_na(). The target is its own address, so
   the NA is sourced from dead:1::99:

   net/ipv6/ndisc.c:ndisc_send_na() {
       ...
	ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
	if (ifp) {
		src_addr = solicited_addr;
       ...
   }

4. The NA does not match the echo-request chain. The RPF rule checks it
   under the current pref 100/101 rules, then logs and drops it. With
   ucast_probes=3, nsrouter retries at about +1s and +2s.

ns1's own NUD probes do not seem to cause this. In the NUD_PROBE state,
ndisc_send_ns() uses the link-local source, and the "to dead:1::99" rules
do not match that. The trigger is nsrouter's NUD_DELAY to NUD_PROBE
transition.

Right after the block, check_drops() greps the global dmesg:

    test_ping 10.0.2.1 dead:2::1 || exit 1
    check_drops

Would this print "FAIL: rpfilter did drop packets" and set ret=1?

That would also hide the later "PASS: fib expression did not cause
unwanted packet drops" message, even when every suppression check passed.
It only happens if the block runs longer than about 5s after the first
probe. That seems plausible on slow or debug kernels such as KASAN or
lockdep builds.

Some possible ways to avoid it:

- Install permanent neighbour entries on both sides while the block runs.
- Temporarily flush or replace the logging inet prerouting rule.
- Also drop nd-neighbor-advert from dead:1::99 in the priority -1 chain.

An accept in the priority -1 chain would not help, because the priority 0
base chain still runs.

[ ... ]

> @@ -724,6 +756,42 @@ test_fib_vrf()

[ ... ]

> +# Reject routes use loopback (group 0) and must remain terminal.
> +ip -net "$nsrouter" -6 route flush table 128
> +for suppress in suppress_prefixlength suppress_ifgroup; do
> +	ip -net "$nsrouter" -6 rule del pref 100
> +	ip -net "$nsrouter" -6 rule add pref 100 to dead:1::99 table 128 "$suppress" 0 || exit 1
> +	for type in blackhole unreachable prohibit; do
> +		ip -net "$nsrouter" -6 route replace "$type" default table 128 || exit 1
> +		test_fib_suppress "retain $type ($suppress)" "$type" type || ret=1
> +	done
> +done

[Severity: Low]

This loop only creates legacy reject route types. Should it also cover a
route that uses a blackhole nexthop object?

The companion commit "ipv6: honor rule suppression in raw FIB lookups"
reads the result flags in fib6_rule_suppress(). Its commit message says
this is so blackhole nexthop objects are covered too:

net/ipv6/fib6_rules.c:fib6_rule_suppress() {
    ...
	if (arg->lookup_ptr == fib6_table_lookup) {
		/* Raw lookups report reject routes without an error. */
		if (res->fib6_flags & RTF_REJECT)
			return false;
    ...
}

Blackhole, unreachable and prohibit routes have RTF_REJECT both in
f6i->fib6_flags and in the result. A blackhole nexthop sets it only in the
result, in __find_rr_leaf():

net/ipv6/route.c:__find_rr_leaf() {
    ...
			if (nexthop_is_blackhole(f6i->nh)) {
				res->fib6_flags = RTF_REJECT;
				res->fib6_type = RTN_BLACKHOLE;
    ...
}

This means the new checks cannot tell res->fib6_flags apart from
res->f6i->fib6_flags.

Suppose the guard were changed to read the FIB entry flags. A blackhole
nexthop default route in table 128 would then be suppressed, and the lookup
would fall through to table 129 (veth0). The tests here would still pass.

Something like this inside the suppress loop might cover it:

    ip -net "$nsrouter" nexthop add id N blackhole
    ip -net "$nsrouter" -6 route replace default nhid N table 128
    test_fib_suppress "retain blackhole nexthop ($suppress)" blackhole type

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261110131638.15004-3-leonard%40lausen.nl

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-11-14 22:55 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-10 13:16 [PATCH net 0/2] ipv6: honor rule suppression in raw FIB lookups Leonard Lausen
2026-11-10 13:16 ` [PATCH net 1/2] " Leonard Lausen
2026-11-14 22:54   ` netdev-bot+sashiko
2026-11-10 13:16 ` [PATCH net 2/2] selftests: netfilter: cover IPv6 FIB rule suppression Leonard Lausen
2026-11-14 22:55   ` netdev-bot+sashiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®