Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next v2 0/2] seg6: skip route refcounts in seg6local lookups
@ 2026-10-10 10:10 Yuya Kusakabe
  2026-10-10 10:10 ` [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups Yuya Kusakabe
  2026-10-10 10:10 ` [PATCH net-next v2 2/2] seg6: skip the route refcount in seg6local IPv4 lookups Yuya Kusakabe
  0 siblings, 2 replies; 7+ messages in thread
From: Yuya Kusakabe @ 2026-10-10 10:10 UTC (permalink / raw)
  To: Andrea Mayer, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman
  Cc: netdev, linux-kernel, Yuya Kusakabe

seg6local looks up the nexthop of its IPv6 and IPv4 behaviors from the
RCU read-side section of the receive path, yet takes and drops a route
reference for every packet.  Skip the reference, as ip6_route_input()
and ip_rcv_finish() do.

---
Changes in v2:
- Split the lookup into a noref primitive for the seg6local input
  actions and a refcounted seg6_lookup_nexthop() wrapper, which the BPF
  LWT helpers also call (Andrea Mayer, Sashiko).
- Rebase onto net-next and re-measure.
- Link to v1: https://patch.msgid.link/20261005-seg6-lookup-noref-v1-0-092e84774e80@gmail.com

---
Yuya Kusakabe (2):
      seg6: skip the route refcount in seg6local IPv6 lookups
      seg6: skip the route refcount in seg6local IPv4 lookups

 net/ipv6/seg6_local.c | 58 +++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 42 insertions(+), 16 deletions(-)
---
base-commit: 758fe10f83a655bed0f7b98fcfacdfc3556fb9a1
change-id: 20261004-seg6-lookup-noref-e016495b60ed

Best regards,
--  
Yuya Kusakabe <yuya.kusakabe@gmail.com>


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

* [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups
  2026-10-10 10:10 [PATCH net-next v2 0/2] seg6: skip route refcounts in seg6local lookups Yuya Kusakabe
@ 2026-10-10 10:10 ` Yuya Kusakabe
  2026-10-13 23:58   ` Andrea Mayer
  2026-10-15 14:30   ` Gabriel Goller
  2026-10-10 10:10 ` [PATCH net-next v2 2/2] seg6: skip the route refcount in seg6local IPv4 lookups Yuya Kusakabe
  1 sibling, 2 replies; 7+ messages in thread
From: Yuya Kusakabe @ 2026-10-10 10:10 UTC (permalink / raw)
  To: Andrea Mayer, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman
  Cc: netdev, linux-kernel, Yuya Kusakabe

ip6_route_input() attaches the input route to the skb without taking a
reference, relying on the RCU read-side section of the receive path.
The seg6local input actions run in that same section, either directly
from the seg6local input handler or from a netfilter okfn, yet
seg6_lookup_any_nexthop() takes and drops a route reference for every
packet.

Look the route up with RT6_LOOKUP_F_DST_NOREF, as ip6_route_input()
does, for the input and table lookups of those actions.  Keep
seg6_lookup_nexthop(), which the BPF LWT helpers also call, refcounted:
BPF_PROG_TEST_RUN runs them repeatedly on the same skb and may leave
the RCU read-side section between runs.  Like ip6_route_output_flags(),
it now takes the reference on top of the noref lookup.

Throughput at 0.5% packet loss of 94-byte End packets (two-segment
SRH, no payload), spread by RSS on an ixgbe 82599ES across two 2.30 GHz
Xeon E5-2650 v3 with 10 cores each, offered by TRex and binary-searched
over 10 runs of 10 s, in Mpps:

  queues  cores                   before   after
  1       1                        0.740   0.756  (+2.2%)
  10      10 on the NIC's socket   6.404   6.950  (+8.5%)
  16      10 + 6 on two sockets    6.550  10.124  (+54.6%)

With the default rules, fib6_rule_lookup() tries the local table
first, and the miss takes and drops a reference on ip6_null_entry,
one route shared by every CPU.  At 16 queues that cache line bounces
between the sockets, and ip6_hold_safe() and dst_release() together
take about a third of the cycles.

Assisted-by: LLM
Signed-off-by: Yuya Kusakabe <yuya.kusakabe@gmail.com>
---
 net/ipv6/seg6_local.c | 54 ++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 40 insertions(+), 14 deletions(-)

diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index 0c3d1be7f129..f23330278922 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -318,8 +318,8 @@ static struct ipv6_sr_hdr *advance_nextseg(struct sk_buff *skb,
 }
 
 static int
-seg6_lookup_any_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
-			u32 tbl_id, bool local_delivery, int oif)
+seg6_lookup_any_nexthop_noref(struct sk_buff *skb, struct in6_addr *nhaddr,
+			      u32 tbl_id, bool local_delivery, int oif)
 {
 	struct net *net = dev_net(skb->dev);
 	struct ipv6hdr *hdr = ipv6_hdr(skb);
@@ -342,6 +342,7 @@ seg6_lookup_any_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
 		fl6.flowi6_flags = FLOWI_FLAG_KNOWN_NH;
 
 	if (!tbl_id && !oif) {
+		flags |= RT6_LOOKUP_F_DST_NOREF;
 		dst = ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags);
 	} else if (tbl_id) {
 		struct fib6_table *table;
@@ -350,6 +351,7 @@ seg6_lookup_any_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
 		if (!table)
 			goto out;
 
+		flags |= RT6_LOOKUP_F_DST_NOREF;
 		rt = ip6_pol_route(net, table, oif, &fl6, skb, flags);
 		dst = &rt->dst;
 	} else {
@@ -363,7 +365,7 @@ seg6_lookup_any_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
 		dev_flags |= IFF_LOOPBACK;
 
 	if (dst && (dst_dev(dst)->flags & dev_flags) && !dst->error) {
-		dst_release(dst);
+		ip6_rt_put_flags(dst_rt6_info(dst), flags);
 		dst = NULL;
 	}
 
@@ -372,17 +374,41 @@ seg6_lookup_any_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
 		rt = net->ipv6.ip6_blk_hole_entry;
 		dst = &rt->dst;
 		dst_hold(dst);
+		flags &= ~RT6_LOOKUP_F_DST_NOREF;
 	}
 
 	skb_dst_drop(skb);
-	skb_dst_set(skb, dst);
+	if ((flags & RT6_LOOKUP_F_DST_NOREF) && !dst->rt_uncached_list)
+		skb_dst_set_noref(skb, dst);
+	else
+		skb_dst_set(skb, dst);
 	return dst->error;
 }
 
+static int seg6_lookup_nexthop_noref(struct sk_buff *skb,
+				     struct in6_addr *nhaddr, u32 tbl_id)
+{
+	return seg6_lookup_any_nexthop_noref(skb, nhaddr, tbl_id, false, 0);
+}
+
 int seg6_lookup_nexthop(struct sk_buff *skb,
 			struct in6_addr *nhaddr, u32 tbl_id)
 {
-	return seg6_lookup_any_nexthop(skb, nhaddr, tbl_id, false, 0);
+	int err;
+
+	rcu_read_lock();
+	err = seg6_lookup_nexthop_noref(skb, nhaddr, tbl_id);
+	if (!skb_dst_force(skb)) {
+		struct dst_entry *dst;
+
+		dst = &dev_net(skb->dev)->ipv6.ip6_blk_hole_entry->dst;
+		dst_hold(dst);
+		skb_dst_set(skb, dst);
+		err = dst->error;
+	}
+	rcu_read_unlock();
+
+	return err;
 }
 
 static __u8 seg6_flv_lcblock_octects(const struct seg6_flavors_info *finfo)
@@ -446,7 +472,7 @@ seg6_next_csid_advance_arg(struct sk_buff *skb,
 static int input_action_end_finish(struct sk_buff *skb,
 				   struct seg6_local_lwt *slwt)
 {
-	seg6_lookup_nexthop(skb, NULL, 0);
+	seg6_lookup_nexthop_noref(skb, NULL, 0);
 
 	return dst_input(skb);
 }
@@ -497,7 +523,7 @@ static int end_next_csid_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 static int input_action_end_x_finish(struct sk_buff *skb,
 				     struct seg6_local_lwt *slwt)
 {
-	seg6_lookup_any_nexthop(skb, &slwt->nh6, 0, false, slwt->oif);
+	seg6_lookup_any_nexthop_noref(skb, &slwt->nh6, 0, false, slwt->oif);
 
 	return dst_input(skb);
 }
@@ -939,7 +965,7 @@ static int input_action_end_t(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 		goto drop;
 	}
 
-	seg6_lookup_nexthop(skb, NULL, slwt->table);
+	seg6_lookup_nexthop_noref(skb, NULL, slwt->table);
 
 	return dst_input(skb);
 
@@ -1023,7 +1049,7 @@ static int input_action_end_dx6_finish(struct net *net, struct sock *sk,
 	if (!ipv6_addr_any(&slwt->nh6))
 		nhaddr = &slwt->nh6;
 
-	seg6_lookup_nexthop(skb, nhaddr, 0);
+	seg6_lookup_nexthop_noref(skb, nhaddr, 0);
 
 	return dst_input(skb);
 }
@@ -1383,7 +1409,7 @@ static int input_action_end_dt6(struct sk_buff *skb,
 	/* note: this time we do not need to specify the table because the VRF
 	 * takes care of selecting the correct table.
 	 */
-	seg6_lookup_any_nexthop(skb, NULL, 0, true, 0);
+	seg6_lookup_any_nexthop_noref(skb, NULL, 0, true, 0);
 
 	return dst_input(skb);
 
@@ -1391,7 +1417,7 @@ static int input_action_end_dt6(struct sk_buff *skb,
 #endif
 	skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
-	seg6_lookup_any_nexthop(skb, NULL, slwt->table, true, 0);
+	seg6_lookup_any_nexthop_noref(skb, NULL, slwt->table, true, 0);
 
 	return dst_input(skb);
 
@@ -1446,7 +1472,7 @@ static int input_action_end_b6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 
 	skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
-	seg6_lookup_nexthop(skb, NULL, 0);
+	seg6_lookup_nexthop_noref(skb, NULL, 0);
 
 	return dst_input(skb);
 
@@ -1482,7 +1508,7 @@ static int input_action_end_b6_encap(struct sk_buff *skb,
 
 	skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
-	seg6_lookup_nexthop(skb, NULL, 0);
+	seg6_lookup_nexthop_noref(skb, NULL, 0);
 
 	return dst_input(skb);
 
@@ -1571,7 +1597,7 @@ static int input_action_end_bpf(struct sk_buff *skb,
 	local_unlock_nested_bh(&seg6_bpf_srh_states.bh_lock);
 
 	if (ret != BPF_REDIRECT)
-		seg6_lookup_nexthop(skb, NULL, 0);
+		seg6_lookup_nexthop_noref(skb, NULL, 0);
 
 	return dst_input(skb);
 

-- 
2.50.1


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

* [PATCH net-next v2 2/2] seg6: skip the route refcount in seg6local IPv4 lookups
  2026-10-10 10:10 [PATCH net-next v2 0/2] seg6: skip route refcounts in seg6local lookups Yuya Kusakabe
  2026-10-10 10:10 ` [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups Yuya Kusakabe
@ 2026-10-10 10:10 ` Yuya Kusakabe
  1 sibling, 0 replies; 7+ messages in thread
From: Yuya Kusakabe @ 2026-10-10 10:10 UTC (permalink / raw)
  To: Andrea Mayer, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman
  Cc: netdev, linux-kernel, Yuya Kusakabe

ip_route_input() looks the input route up with ip_route_input_noref()
and then forces a reference on it, which is dropped again when the
packet is transmitted.  End.DX4 and End.DT4 call it from the RCU
read-side section of the receive path, either directly from the
seg6local input handler or from a netfilter okfn, and hand the skb to
dst_input() before leaving that section.

Use ip_route_input_noref(), as ip_rcv_finish() does.

Throughput at 0.5% packet loss of 82-byte IPv4-in-IPv6 UDP packets
(no SRH), spread by RSS on an ixgbe 82599ES across two 10-core Xeon
E5-2650 v3, offered by TRex over 10 runs of 10 s, in Mpps:

  End.DX4
  queues  cores                   before   after
  1       1                        0.791   0.811  (+2.5%)
  10      10 on the NIC's socket   6.118   7.394  (+20.9%)
  16      10 + 6 on two sockets    3.305  10.205  (+208.8%)

  End.DT4
  queues  cores                   before   after
  1       1                        0.481   0.489  (+1.6%)
  10      10 on the NIC's socket   4.328   4.588  (+6.0%)
  16      10 + 6 on two sockets    3.351   7.153  (+113.5%)

Every CPU takes and drops a reference on the same input route, the
one cached on the nexthop.  At 16 queues that cache line bounces
between the sockets, and skb_dst_force() and dst_release() together
take more than half of the cycles for End.DX4 and over 40% for End.DT4.

Assisted-by: LLM
Signed-off-by: Yuya Kusakabe <yuya.kusakabe@gmail.com>
---
 net/ipv6/seg6_local.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index f23330278922..60abd139dbe3 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -1099,7 +1099,7 @@ static int input_action_end_dx4_finish(struct net *net, struct sock *sk,
 
 	skb_dst_drop(skb);
 
-	reason = ip_route_input(skb, nhaddr, iph->saddr, 0, skb->dev);
+	reason = ip_route_input_noref(skb, nhaddr, iph->saddr, 0, skb->dev);
 	if (reason) {
 		kfree_skb_reason(skb, reason);
 		return -EINVAL;
@@ -1325,7 +1325,7 @@ static int input_action_end_dt4(struct sk_buff *skb,
 
 	iph = ip_hdr(skb);
 
-	reason = ip_route_input(skb, iph->daddr, iph->saddr, 0, skb->dev);
+	reason = ip_route_input_noref(skb, iph->daddr, iph->saddr, 0, skb->dev);
 	if (unlikely(reason))
 		goto drop;
 

-- 
2.50.1


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

* Re: [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups
  2026-10-10 10:10 ` [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups Yuya Kusakabe
@ 2026-10-13 23:58   ` Andrea Mayer
  2026-10-15 14:31     ` Yuya Kusakabe
  2026-10-15 14:30   ` Gabriel Goller
  1 sibling, 1 reply; 7+ messages in thread
From: Andrea Mayer @ 2026-10-13 23:58 UTC (permalink / raw)
  To: Yuya Kusakabe
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, netdev, linux-kernel, Andrea Mayer

On Sat, 10 Oct 2026 19:10:39 +0900
Yuya Kusakabe <yuya.kusakabe@gmail.com> wrote:

Hi Yuya,

Thanks for v2. I re-ran the BPF_PROG_TEST_RUN case from v1 on 32-bit ARM
with the changes of v2, and I could not reproduce the use-after-free
anymore.

> ip6_route_input() attaches the input route to the skb without taking a
> reference, relying on the RCU read-side section of the receive path.
> The seg6local input actions run in that same section, either directly
> from the seg6local input handler or from a netfilter okfn, yet
> seg6_lookup_any_nexthop() takes and drops a route reference for every
> packet.

For a packet queued with NFQUEUE, the okfn runs later from nf_reinject(),
under the rcu_read_lock() of the nfnetlink verdict handler. Is "that same
section" accurate for that case?

> [snip]
>  	if (!tbl_id && !oif) {
> +		flags |= RT6_LOOKUP_F_DST_NOREF;
>  		dst = ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags);
> [snip]
> +		flags |= RT6_LOOKUP_F_DST_NOREF;
>  		rt = ip6_pol_route(net, table, oif, &fl6, skb, flags);

With RT6_LOOKUP_F_DST_NOREF, ip6_pol_route() no longer calls
ip6_hold_safe(). If the route it finds is released on another CPU during
the lookup, the packet can be dropped without an ICMP error. Before the
series, when ip6_hold_safe() did not get the reference on the released
route, the packet went to the next policy rule, or to ip6_null_entry and
its ICMPv6 Destination Unreachable. As far as I can see, only packets that
race with the release are affected. It is still a change in behavior, and
it would be worth at least mentioning it in the commit message.

> [snip]
>  int seg6_lookup_nexthop(struct sk_buff *skb,
>  			struct in6_addr *nhaddr, u32 tbl_id)
>  {
> -	return seg6_lookup_any_nexthop(skb, nhaddr, tbl_id, false, 0);
> +	int err;
> +
> +	rcu_read_lock();
> +	err = seg6_lookup_nexthop_noref(skb, nhaddr, tbl_id);
> +	if (!skb_dst_force(skb)) {
> +		struct dst_entry *dst;
> +
> +		dst = &dev_net(skb->dev)->ipv6.ip6_blk_hole_entry->dst;
> +		dst_hold(dst);
> +		skb_dst_set(skb, dst);
> +		err = dst->error;
> +	}
> +	rcu_read_unlock();
> +
> +	return err;
>  }

The split works, and the contract is now in the names. One detail is how
seg6_lookup_nexthop() takes its reference: after the noref lookup, with
skb_dst_force(). Because of this, the BPF LWT helpers are affected by this
race too. Before the series, when ip6_hold_safe() did not get the reference
on the released route, seg6_lookup_nexthop() returned 0 if a later policy
rule had a route, or -ENETUNREACH. Now it can return -EINVAL in both cases.
The Sashiko review points out the second one.

It would be good to keep seg6_lookup_nexthop() unchanged for the BPF
helpers, also while a route is being released. One idea, as a refinement of
the split, could be a common lookup function with a noref argument. For
example, seg6_lookup_any_nexthop_noref() would call it with noref set, and
seg6_lookup_nexthop() with noref clear, keeping the refcounted lookup it
had before the series. What do you think?

> [snip]

Ciao,
Andrea

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

* Re: [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups
  2026-10-10 10:10 ` [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups Yuya Kusakabe
  2026-10-13 23:58   ` Andrea Mayer
@ 2026-10-15 14:30   ` Gabriel Goller
  2026-10-15 14:38     ` Yuya Kusakabe
  1 sibling, 1 reply; 7+ messages in thread
From: Gabriel Goller @ 2026-10-15 14:30 UTC (permalink / raw)
  To: Yuya Kusakabe
  Cc: Andrea Mayer, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, netdev, linux-kernel

Hi Yuya,

> [snip]
> @@ -372,17 +374,41 @@ seg6_lookup_any_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
>  		rt = net->ipv6.ip6_blk_hole_entry;
>  		dst = &rt->dst;
>  		dst_hold(dst);
> +		flags &= ~RT6_LOOKUP_F_DST_NOREF;
>  	}
>  
>  	skb_dst_drop(skb);
> -	skb_dst_set(skb, dst);
> +	if ((flags & RT6_LOOKUP_F_DST_NOREF) && !dst->rt_uncached_list)
> +		skb_dst_set_noref(skb, dst);
> +	else
> +		skb_dst_set(skb, dst);
>  	return dst->error;
>  }
>  
> +static int seg6_lookup_nexthop_noref(struct sk_buff *skb,
> +				     struct in6_addr *nhaddr, u32 tbl_id)
> +{
> +	return seg6_lookup_any_nexthop_noref(skb, nhaddr, tbl_id, false, 0);
> +}
> +
>  int seg6_lookup_nexthop(struct sk_buff *skb,
>  			struct in6_addr *nhaddr, u32 tbl_id)
>  {
> -	return seg6_lookup_any_nexthop(skb, nhaddr, tbl_id, false, 0);
> +	int err;
> +
> +	rcu_read_lock();
> +	err = seg6_lookup_nexthop_noref(skb, nhaddr, tbl_id);
> +	if (!skb_dst_force(skb)) {
> +		struct dst_entry *dst;
> +
> +		dst = &dev_net(skb->dev)->ipv6.ip6_blk_hole_entry->dst;

I think we should use ip6_null_entry instead of ip6_blk_hole_entry here.
Previously this path (failure to acquire the dst ref) was reached through
ip6_pol_route() and ip6_hold_safe(), which uses ip6_null_entry and returns
-ENETUNREACH as an error.
After this patch, the error is triggered here and we use ip6_blk_hole_entry,
which returns -EINVAL.

What do you think?

> +		dst_hold(dst);
> +		skb_dst_set(skb, dst);
> +		err = dst->error;
> +	}
> +	rcu_read_unlock();
> +
> +	return err;
>  }
>  
>  static __u8 seg6_flv_lcblock_octects(const struct seg6_flavors_info *finfo)
> [snip]

Thanks,
Gabriel


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

* Re: [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups
  2026-10-13 23:58   ` Andrea Mayer
@ 2026-10-15 14:31     ` Yuya Kusakabe
  0 siblings, 0 replies; 7+ messages in thread
From: Yuya Kusakabe @ 2026-10-15 14:31 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, netdev, linux-kernel

On Wed, 14 Oct 2026 01:58:19 +0200
Andrea Mayer <andrea.mayer@uniroma2.it> wrote:

> For a packet queued with NFQUEUE, the okfn runs later from nf_reinject(),
> under the rcu_read_lock() of the nfnetlink verdict handler. Is "that same
> section" accurate for that case?

No, it is not.  The lookup and dst_input() still run within one RCU
read-side section, but for a reinjected packet it is the one of the
verdict handler.  v3 will say so in both patches.

> With RT6_LOOKUP_F_DST_NOREF, ip6_pol_route() no longer calls
> ip6_hold_safe(). If the route it finds is released on another CPU during
> the lookup, the packet can be dropped without an ICMP error. Before the
> series, when ip6_hold_safe() did not get the reference on the released
> route, the packet went to the next policy rule, or to ip6_null_entry and
> its ICMPv6 Destination Unreachable. As far as I can see, only packets that
> race with the release are affected. It is still a change in behavior, and
> it would be worth at least mentioning it in the commit message.

Agreed.  v3 will mention it in the 1/2 message, along with the fact
that ip6_route_input() has the same window.

> It would be good to keep seg6_lookup_nexthop() unchanged for the BPF
> helpers, also while a route is being released. One idea, as a refinement of
> the split, could be a common lookup function with a noref argument. For
> example, seg6_lookup_any_nexthop_noref() would call it with noref set, and
> seg6_lookup_nexthop() with noref clear, keeping the refcounted lookup it
> had before the series. What do you think?

That works better.  In v3, seg6_lookup_any_nexthop() will take a noref
argument, seg6_lookup_any_nexthop_noref() will set it for the seg6local
input actions, and seg6_lookup_nexthop() will keep its refcounted
lookup.  The skb_dst_force() fallback goes away, and with it the
-EINVAL that Sashiko pointed out.

pw-bot: cr

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

* Re: [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups
  2026-10-15 14:30   ` Gabriel Goller
@ 2026-10-15 14:38     ` Yuya Kusakabe
  0 siblings, 0 replies; 7+ messages in thread
From: Yuya Kusakabe @ 2026-10-15 14:38 UTC (permalink / raw)
  To: Gabriel Goller
  Cc: Andrea Mayer, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, netdev, linux-kernel

On Thu, 15 Oct 2026 16:30:02 +0200
Gabriel Goller <g.goller@proxmox.com> wrote:

> I think we should use ip6_null_entry instead of ip6_blk_hole_entry here.
> Previously this path (failure to acquire the dst ref) was reached through
> ip6_pol_route() and ip6_hold_safe(), which uses ip6_null_entry and returns
> -ENETUNREACH as an error.
> After this patch, the error is triggered here and we use ip6_blk_hole_entry,
> which returns -EINVAL.
>
> What do you think?

Agreed, the error changes.  v3 will drop this fallback altogether:
following Andrea's suggestion, seg6_lookup_nexthop() will keep its
refcounted lookup, so ip6_hold_safe() handles the failure as before.

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

end of thread, other threads:[~2026-10-15 14:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-10 10:10 [PATCH net-next v2 0/2] seg6: skip route refcounts in seg6local lookups Yuya Kusakabe
2026-10-10 10:10 ` [PATCH net-next v2 1/2] seg6: skip the route refcount in seg6local IPv6 lookups Yuya Kusakabe
2026-10-13 23:58   ` Andrea Mayer
2026-10-15 14:31     ` Yuya Kusakabe
2026-10-15 14:30   ` Gabriel Goller
2026-10-15 14:38     ` Yuya Kusakabe
2026-10-10 10:10 ` [PATCH net-next v2 2/2] seg6: skip the route refcount in seg6local IPv4 lookups Yuya Kusakabe

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