Netdev List
 help / color / mirror / Atom feed
* [PATCH net 0/1] ovpn: avoid caching stale IPv6 dst after FIB changes
@ 2026-09-17 10:09 Ralf Lici
  2026-09-17 10:09 ` [PATCH net 1/1] " Ralf Lici
  0 siblings, 1 reply; 10+ messages in thread
From: Ralf Lici @ 2026-09-17 10:09 UTC (permalink / raw)
  To: netdev
  Cc: Antonio Quartulli, Sabrina Dubroca, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel

Hi,

This patch was originally part of a wider ovpn series addressing UDP
route-cache correctness when mutable socket routing properties or peer
endpoint state change while packets are being transmitted [1]. The
ovpn-specific fixes were resubmitted separately after dropping this
patch, which addresses an independent IPv6 FIB race reproduced in ovpn.

During review, Sabrina suggested submitting the patch directly to netdev
rather than through the ovpn pull request because it touches generic
dst_cache code and the underlying late-cookie sampling pattern is not
specific to ovpn. I first sent an RFC describing the race and a possible
kernel-wide solution [2], but it has not received any feedback so far.

After discussing the submission path with Antonio, we decided to post
the concrete ovpn fix directly to netdev. It prevents ovpn from caching
a route if the IPv6 FIB generation changed during lookup, without
attempting the broader network-stack refactoring discussed in the RFC.

[1] https://lore.kernel.org/openvpn-devel/cover.1785308184.git.ralf@mandelbit.com/
[2] https://lore.kernel.org/netdev/20260901122501.482920-1-ralf@mandelbit.com/

Compared with the version previously posted as part of the ovpn series,
this patch has been rebased on current net/main and made independent of
the pending ovpn route-cache and endpoint changes.

Thanks,

Ralf Lici
Mandelbit Srl

---
Ralf Lici (1):
  ovpn: avoid caching stale IPv6 dst after FIB changes

 drivers/net/ovpn/udp.c  | 20 +++++++++++++++++---
 include/net/dst_cache.h | 13 +++++++++++++
 net/core/dst_cache.c    | 19 +++++++++++++++----
 3 files changed, 45 insertions(+), 7 deletions(-)

base-commit: c9151088f1674fd29ff26a20f5fc687acf53a2f0
-- 
2.55.0


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

* [PATCH net 1/1] ovpn: avoid caching stale IPv6 dst after FIB changes
  2026-09-17 10:09 [PATCH net 0/1] ovpn: avoid caching stale IPv6 dst after FIB changes Ralf Lici
@ 2026-09-17 10:09 ` Ralf Lici
  2026-09-17 19:09   ` David Ahern
  0 siblings, 1 reply; 10+ messages in thread
From: Ralf Lici @ 2026-09-17 10:09 UTC (permalink / raw)
  To: netdev
  Cc: Antonio Quartulli, Sabrina Dubroca, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	David Ahern, Ido Schimmel

ovpn stores the IPv6 route used for UDP transmission in a per-peer dst
cache. IPv6 dst validation uses a cookie derived from the route itself,
or, for routes without their own sernum, from the associated fib6 node.

If the IPv6 FIB changes after ip6_dst_lookup_flow returns but before
dst_cache_set_ip6 reads the cookie, ovpn can store an old dst with a new
cookie. Later dst_cache_get_ip6 can then consider that stale dst valid
because the stored cookie matches the updated fib6 node sernum.

Sample the IPv6 FIB generation before and after route lookup, and only
populate ovpn's peer dst cache if the generation did not change while
the lookup was in flight. Also add a dst_cache helper that stores a
caller-provided IPv6 cookie, so the cached dst carries the cookie
sampled from the lookup result instead of one read after a concurrent
FIB update.

The current packet may still be transmitted with the route returned by
the lookup if the FIB changes before TX completion. This patch only
prevents that potentially stale route from being preserved in ovpn's
peer dst cache and reused for later packets.

Fixes: 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)")
Link: https://lore.kernel.org/netdev/20260901122501.482920-1-ralf@mandelbit.com/
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
---
 drivers/net/ovpn/udp.c  | 20 +++++++++++++++++---
 include/net/dst_cache.h | 13 +++++++++++++
 net/core/dst_cache.c    | 19 +++++++++++++++----
 3 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
index 7f69e8890b5b..a28974cc36e8 100644
--- a/drivers/net/ovpn/udp.c
+++ b/drivers/net/ovpn/udp.c
@@ -220,8 +220,10 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 			    struct dst_cache *cache, struct sock *sk,
 			    struct sk_buff *skb)
 {
+	struct net *net = sock_net(sk);
 	struct dst_entry *dst;
-	int ret;
+	int gen0, gen1, ret;
+	u32 cookie;
 
 	struct flowi6 fl = {
 		.saddr = bind->local.ipv6,
@@ -250,7 +252,11 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 		dst_cache_reset(cache);
 	}
 
-	dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL);
+	gen0 = rt_genid_ipv6(net);
+	/* keep the unordered initial generation read before the FIB lookup */
+	smp_rmb();
+
+	dst = ip6_dst_lookup_flow(net, sk, &fl, NULL);
 	if (IS_ERR(dst)) {
 		ret = PTR_ERR(dst);
 		net_dbg_ratelimited("%s: no route to host %pISpc: %d\n",
@@ -258,7 +264,15 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
 				    &bind->remote.in6, ret);
 		goto err;
 	}
-	dst_cache_set_ip6(cache, dst, &fl.saddr);
+
+	cookie = rt6_get_cookie(dst_rt6_info(dst));
+
+	/* keep the FIB and cookie reads before the final generation read */
+	smp_rmb();
+	gen1 = rt_genid_ipv6(net);
+
+	if (likely(gen0 == gen1))
+		dst_cache_set_ip6_cookie(cache, dst, &fl.saddr, cookie);
 
 transmit:
 	/* user IPv6 packets may be larger than the transport interface
diff --git a/include/net/dst_cache.h b/include/net/dst_cache.h
index 1961699598e2..5f9cc4fe926c 100644
--- a/include/net/dst_cache.h
+++ b/include/net/dst_cache.h
@@ -45,6 +45,19 @@ void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
 
 #if IS_ENABLED(CONFIG_IPV6)
 
+/**
+ *	dst_cache_set_ip6_cookie - store ipv6 dst with caller-provided cookie
+ *	@dst_cache: the cache
+ *	@dst: the entry to be cached
+ *	@saddr: the source address to be stored inside the cache
+ *	@cookie: the route validation cookie to store with @dst
+ *
+ *	local BH must be disabled.
+ */
+void dst_cache_set_ip6_cookie(struct dst_cache *dst_cache,
+			      struct dst_entry *dst,
+			      const struct in6_addr *saddr, u32 cookie);
+
 /**
  *	dst_cache_set_ip6 - store the ipv6 dst into the cache
  *	@dst_cache: the cache
diff --git a/net/core/dst_cache.c b/net/core/dst_cache.c
index 9ab4902324e1..76c9fc1b0acf 100644
--- a/net/core/dst_cache.c
+++ b/net/core/dst_cache.c
@@ -117,8 +117,9 @@ void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
 EXPORT_SYMBOL_GPL(dst_cache_set_ip4);
 
 #if IS_ENABLED(CONFIG_IPV6)
-void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
-		       const struct in6_addr *saddr)
+void dst_cache_set_ip6_cookie(struct dst_cache *dst_cache,
+			      struct dst_entry *dst,
+			      const struct in6_addr *saddr, u32 cookie)
 {
 	struct dst_cache_pcpu *idst;
 
@@ -128,11 +129,21 @@ void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
 	local_lock_nested_bh(&dst_cache->cache->bh_lock);
 
 	idst = this_cpu_ptr(dst_cache->cache);
-	dst_cache_per_cpu_dst_set(idst, dst,
-				  rt6_get_cookie(dst_rt6_info(dst)));
+	dst_cache_per_cpu_dst_set(idst, dst, cookie);
 	idst->in6_saddr = *saddr;
 	local_unlock_nested_bh(&dst_cache->cache->bh_lock);
 }
+EXPORT_SYMBOL_GPL(dst_cache_set_ip6_cookie);
+
+void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
+		       const struct in6_addr *saddr)
+{
+	if (!dst_cache->cache)
+		return;
+
+	dst_cache_set_ip6_cookie(dst_cache, dst, saddr,
+				 rt6_get_cookie(dst_rt6_info(dst)));
+}
 EXPORT_SYMBOL_GPL(dst_cache_set_ip6);
 
 struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
-- 
2.55.0


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

* Re: [PATCH net 1/1] ovpn: avoid caching stale IPv6 dst after FIB changes
  2026-09-17 10:09 ` [PATCH net 1/1] " Ralf Lici
@ 2026-09-17 19:09   ` David Ahern
  2026-09-18  6:51     ` Ralf Lici
  0 siblings, 1 reply; 10+ messages in thread
From: David Ahern @ 2026-09-17 19:09 UTC (permalink / raw)
  To: Ralf Lici, netdev
  Cc: Antonio Quartulli, Sabrina Dubroca, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Ido Schimmel

On 9/17/26 4:09 AM, Ralf Lici wrote:
> diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
> index 7f69e8890b5b..a28974cc36e8 100644
> --- a/drivers/net/ovpn/udp.c
> +++ b/drivers/net/ovpn/udp.c
> @@ -250,7 +252,11 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
>  		dst_cache_reset(cache);
>  	}
>  
> -	dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL);
> +	gen0 = rt_genid_ipv6(net);

this detail about routes should not be buried here. rt_genid_ipv6 really
should be local to net/ipv6/route.c


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

* Re: [PATCH net 1/1] ovpn: avoid caching stale IPv6 dst after FIB changes
  2026-09-17 19:09   ` David Ahern
@ 2026-09-18  6:51     ` Ralf Lici
  2026-09-18 18:42       ` David Ahern
  0 siblings, 1 reply; 10+ messages in thread
From: Ralf Lici @ 2026-09-18  6:51 UTC (permalink / raw)
  To: David Ahern
  Cc: netdev, Antonio Quartulli, Sabrina Dubroca, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Ido Schimmel

On Thu, 17 Sep 2026 13:09:10 -0600, David Ahern <dsahern@kernel.org> wrote:
> On 9/17/26 4:09 AM, Ralf Lici wrote:
> > diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
> > index 7f69e8890b5b..a28974cc36e8 100644
> > --- a/drivers/net/ovpn/udp.c
> > +++ b/drivers/net/ovpn/udp.c
> > @@ -250,7 +252,11 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
> >  		dst_cache_reset(cache);
> >  	}
> >  
> > -	dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL);
> > +	gen0 = rt_genid_ipv6(net);
>
> this detail about routes should not be buried here. rt_genid_ipv6 really
> should be local to net/ipv6/route.c
>
>

I agree. Keeping this detail inside the IPv6 routing code is exactly why
I sent the RFC linked from the cover letter, and I would appreciate your
thoughts on the proposed approach:

https://lore.kernel.org/netdev/20260901122501.482920-1-ralf@mandelbit.com/

The pattern of obtaining a dst and only later sampling its validation
cookie when publishing it into a persistent cache is widespread in both
drivers and the networking core. It is racy for IPv6 routes with
rt6_info::sernum == 0, because rt6_get_cookie then reads the current
fib6_node::fn_sernum, not necessarily the value corresponding to the
lookup which returned that dst.

-- 
Ralf Lici
Mandelbit Srl

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

* Re: [PATCH net 1/1] ovpn: avoid caching stale IPv6 dst after FIB changes
  2026-09-18  6:51     ` Ralf Lici
@ 2026-09-18 18:42       ` David Ahern
  2026-09-18 20:27         ` Ralf Lici
  0 siblings, 1 reply; 10+ messages in thread
From: David Ahern @ 2026-09-18 18:42 UTC (permalink / raw)
  To: Ralf Lici
  Cc: netdev, Antonio Quartulli, Sabrina Dubroca, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Ido Schimmel

On 9/18/26 12:51 AM, Ralf Lici wrote:
> On Thu, 17 Sep 2026 13:09:10 -0600, David Ahern <dsahern@kernel.org> wrote:
>> On 9/17/26 4:09 AM, Ralf Lici wrote:
>>> diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
>>> index 7f69e8890b5b..a28974cc36e8 100644
>>> --- a/drivers/net/ovpn/udp.c
>>> +++ b/drivers/net/ovpn/udp.c
>>> @@ -250,7 +252,11 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
>>>  		dst_cache_reset(cache);
>>>  	}
>>>  
>>> -	dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL);
>>> +	gen0 = rt_genid_ipv6(net);
>>
>> this detail about routes should not be buried here. rt_genid_ipv6 really
>> should be local to net/ipv6/route.c
>>
>>
> 
> I agree. Keeping this detail inside the IPv6 routing code is exactly why
> I sent the RFC linked from the cover letter, and I would appreciate your
> thoughts on the proposed approach:
> 
> https://lore.kernel.org/netdev/20260901122501.482920-1-ralf@mandelbit.com/
> 
> The pattern of obtaining a dst and only later sampling its validation
> cookie when publishing it into a persistent cache is widespread in both
> drivers and the networking core. It is racy for IPv6 routes with
> rt6_info::sernum == 0, because rt6_get_cookie then reads the current
> fib6_node::fn_sernum, not necessarily the value corresponding to the
> lookup which returned that dst.
> 

the patch is focused on detecting a genid change at the time the dst is
cached. Why? It can just as easily change immediately after the double
genid check, so you are not really solving the problem.

Staleness is irrelevant until it is used again (ie, genid can change
many times between dst_cache_set and next use). That is the proper time
to recheck the genid and refresh the dst as needed.

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

* Re: [PATCH net 1/1] ovpn: avoid caching stale IPv6 dst after FIB changes
  2026-09-18 18:42       ` David Ahern
@ 2026-09-18 20:27         ` Ralf Lici
  2026-09-28  8:56           ` Ralf Lici
  0 siblings, 1 reply; 10+ messages in thread
From: Ralf Lici @ 2026-09-18 20:27 UTC (permalink / raw)
  To: David Ahern
  Cc: netdev, Antonio Quartulli, Sabrina Dubroca, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Ido Schimmel

On Fri, 18 Sep 2026 12:42:40 -0600, David Ahern <dsahern@kernel.org> wrote:
> On 9/18/26 12:51 AM, Ralf Lici wrote:
> > On Thu, 17 Sep 2026 13:09:10 -0600, David Ahern <dsahern@kernel.org> wrote:
> >> On 9/17/26 4:09 AM, Ralf Lici wrote:
> >>> diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
> >>> index 7f69e8890b5b..a28974cc36e8 100644
> >>> --- a/drivers/net/ovpn/udp.c
> >>> +++ b/drivers/net/ovpn/udp.c
> >>> @@ -250,7 +252,11 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
> >>>  		dst_cache_reset(cache);
> >>>  	}
> >>>  
> >>> -	dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL);
> >>> +	gen0 = rt_genid_ipv6(net);
> >>
> >> this detail about routes should not be buried here. rt_genid_ipv6 really
> >> should be local to net/ipv6/route.c
> >>
> >>
> > 
> > I agree. Keeping this detail inside the IPv6 routing code is exactly why
> > I sent the RFC linked from the cover letter, and I would appreciate your
> > thoughts on the proposed approach:
> > 
> > https://lore.kernel.org/netdev/20260901122501.482920-1-ralf@mandelbit.com/
> > 
> > The pattern of obtaining a dst and only later sampling its validation
> > cookie when publishing it into a persistent cache is widespread in both
> > drivers and the networking core. It is racy for IPv6 routes with
> > rt6_info::sernum == 0, because rt6_get_cookie then reads the current
> > fib6_node::fn_sernum, not necessarily the value corresponding to the
> > lookup which returned that dst.
> > 
>
> the patch is focused on detecting a genid change at the time the dst is
> cached. Why? It can just as easily change immediately after the double
> genid check, so you are not really solving the problem.
>
> Staleness is irrelevant until it is used again (ie, genid can change
> many times between dst_cache_set and next use). That is the proper time
> to recheck the genid and refresh the dst as needed.
>

The double generation check is not intended to guarantee that the dst
cannot become stale after the final read. Its purpose is to ensure that
a pre-change dst is not cached with a post-change cookie. And that is
enough because dst_cache_get_ip6, on the next run, misses the cache if
it's no longer valid.

For example, suppose the lookup returns D0 under cookie C0. If a
relevant FIB change to C1 happens after the final generation read (even
if it happens before dst_cache_set_ip6_cookie) the cache stores (D0, C0).
On the next use, dst_cache_get_ip6 invokes the ipv6 dst check, which
compares the cached C0 with the node's current C1 and rejects the entry.

The problematic sequence is instead:

lookup returns D0 under C0
FIB changes to C1
dst_cache_set_ip6 samples C1 from D0's fib6 node
cache stores (D0, C1)

The reuse-time check then compares the cached C1 with the current C1 and
accepts D0, potentially until another relevant FIB change. The patch
ensures that the saved cookie is either coherent with the lookup or
conservatively old, so the existing check at reuse remains meaningful.

-- 
Ralf Lici
Mandelbit Srl

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

* Re: [PATCH net 1/1] ovpn: avoid caching stale IPv6 dst after FIB changes
  2026-09-18 20:27         ` Ralf Lici
@ 2026-09-28  8:56           ` Ralf Lici
  2026-09-29 14:09             ` David Ahern
  0 siblings, 1 reply; 10+ messages in thread
From: Ralf Lici @ 2026-09-28  8:56 UTC (permalink / raw)
  To: Ralf Lici
  Cc: David Ahern, netdev, Antonio Quartulli, Sabrina Dubroca,
	Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Ido Schimmel

Hi David,

Just following up on this. Does my previous example clarify why storing
an old dst with a new cookie defeats reuse-time validation?

If so, would you prefer that I pursue the kernel-wide lookup-provenance
approach described in the RFC, or keep the fix self-contained in ovpn?
The same late-cookie-sampling pattern is used by several drivers and
callers in the networking core, so I think fixing it generically is the
better architectural choice.

If changing the generic interfaces is not acceptable, I can rework the
patch as an ovpn-local fix, although that would duplicate IPv6 routing
details in the driver and leave the equivalent pattern elsewhere
unchanged.

Thanks,

-- 
Ralf Lici
Mandelbit Srl

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

* Re: [PATCH net 1/1] ovpn: avoid caching stale IPv6 dst after FIB changes
  2026-09-28  8:56           ` Ralf Lici
@ 2026-09-29 14:09             ` David Ahern
  2026-09-29 15:04               ` Ralf Lici
  0 siblings, 1 reply; 10+ messages in thread
From: David Ahern @ 2026-09-29 14:09 UTC (permalink / raw)
  To: Ralf Lici
  Cc: netdev, Antonio Quartulli, Sabrina Dubroca, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Ido Schimmel

On 9/28/26 3:56 AM, Ralf Lici wrote:
> Hi David,
> 
> Just following up on this. Does my previous example clarify why storing
> an old dst with a new cookie defeats reuse-time validation?
> 
> If so, would you prefer that I pursue the kernel-wide lookup-provenance
> approach described in the RFC, or keep the fix self-contained in ovpn?
> The same late-cookie-sampling pattern is used by several drivers and
> callers in the networking core, so I think fixing it generically is the
> better architectural choice.
> 
> If changing the generic interfaces is not acceptable, I can rework the
> patch as an ovpn-local fix, although that would duplicate IPv6 routing
> details in the driver and leave the equivalent pattern elsewhere
> unchanged.
> 

dst's are cached in lots of places. Why does ovpn need internal routing
details that the other places do not?


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

* Re: [PATCH net 1/1] ovpn: avoid caching stale IPv6 dst after FIB changes
  2026-09-29 14:09             ` David Ahern
@ 2026-09-29 15:04               ` Ralf Lici
  2026-10-09  0:33                 ` Antonio Quartulli
  0 siblings, 1 reply; 10+ messages in thread
From: Ralf Lici @ 2026-09-29 15:04 UTC (permalink / raw)
  To: David Ahern
  Cc: netdev, Antonio Quartulli, Sabrina Dubroca, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Ido Schimmel

On Tue, 29 Sep 2026 08:09:46 -0600, David Ahern <dsahern@kernel.org> wrote:
> On 9/28/26 3:56 AM, Ralf Lici wrote:
> > Hi David,
> > 
> > Just following up on this. Does my previous example clarify why storing
> > an old dst with a new cookie defeats reuse-time validation?
> > 
> > If so, would you prefer that I pursue the kernel-wide lookup-provenance
> > approach described in the RFC, or keep the fix self-contained in ovpn?
> > The same late-cookie-sampling pattern is used by several drivers and
> > callers in the networking core, so I think fixing it generically is the
> > better architectural choice.
> > 
> > If changing the generic interfaces is not acceptable, I can rework the
> > patch as an ovpn-local fix, although that would duplicate IPv6 routing
> > details in the driver and leave the equivalent pattern elsewhere
> > unchanged.
> > 
>
> dst's are cached in lots of places. Why does ovpn need internal routing
> details that the other places do not?
>
>

Because, as explained in this thread and in the RFC, there is enough
evidence that the current IPv6 dst-caching pattern is racy. If other
kernel users are expected to live with that race, I cannot force a
generic fix, but I do not think that is a good reason to require ovpn to
do the same.

If you believe the sequence I described is safe, please explain which
invariant makes it so.

-- 
Ralf Lici
Mandelbit Srl

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

* Re: [PATCH net 1/1] ovpn: avoid caching stale IPv6 dst after FIB changes
  2026-09-29 15:04               ` Ralf Lici
@ 2026-10-09  0:33                 ` Antonio Quartulli
  0 siblings, 0 replies; 10+ messages in thread
From: Antonio Quartulli @ 2026-10-09  0:33 UTC (permalink / raw)
  To: Ralf Lici, David Ahern
  Cc: netdev, Sabrina Dubroca, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Ido Schimmel

On 29/09/2026 17:04, Ralf Lici wrote:
> On Tue, 29 Sep 2026 08:09:46 -0600, David Ahern <dsahern@kernel.org> wrote:
>> On 9/28/26 3:56 AM, Ralf Lici wrote:
>>> Hi David,
>>>
>>> Just following up on this. Does my previous example clarify why storing
>>> an old dst with a new cookie defeats reuse-time validation?
>>>
>>> If so, would you prefer that I pursue the kernel-wide lookup-provenance
>>> approach described in the RFC, or keep the fix self-contained in ovpn?
>>> The same late-cookie-sampling pattern is used by several drivers and
>>> callers in the networking core, so I think fixing it generically is the
>>> better architectural choice.
>>>
>>> If changing the generic interfaces is not acceptable, I can rework the
>>> patch as an ovpn-local fix, although that would duplicate IPv6 routing
>>> details in the driver and leave the equivalent pattern elsewhere
>>> unchanged.
>>>
>>
>> dst's are cached in lots of places. Why does ovpn need internal routing
>> details that the other places do not?
>>
>>
> 

Hi David,

ovpn maintainer here: I wanted to back this patch.

You're right that a cached dst can go stale later and that reuse-time
validation handles that. This case is different, because it breaks
reuse-time validation.

dst_cache_set_ip6() samples the cookie itself:

         dst_cache_per_cpu_dst_set(idst, dst,
                                   rt6_get_cookie(dst_rt6_info(dst)));

rt6_get_cookie() only returns a route-tied value when rt->sernum is
non-zero, which happens in ip6_rt_pcpu_alloc() and only for nexthop
routes. Everything else reads the current node generation:

         *cookie = READ_ONCE(fn->fn_sernum);

So if the FIB changes between ip6_dst_lookup_flow() returning D0 and
dst_cache_set_ip6() reading the cookie, we cache D0 with cookie C1. At
reuse dst_check() compares C1 against the node's current C1, they match,
and the stale route is used until the next FIB change.

Which invariant stops that cookie read from seeing a generation newer
than the one the lookup used? If there is one, we'll drop both the patch
and the RFC.

Regarding the layering, I agree. rt_genid_ipv6() does not belong in a 
driver.
That's exactly what the RFC [1] was for, but it's had no feedback so 
far, hence I suggested Ralf to pursue this other path.
The late sampling lives in dst_cache_set_ip6(), not in ovpn.

Happy to confine the IPv6 bits to a helper, or to revive the RFC if
you'd like review it.

Please also note that the workaround we're looking at is already 
implemented by other drivers, which they all could drop if we'd be able 
to provide an IPv6-generic solution.


Please let us know!


[1] 
https://lore.kernel.org/netdev/20260901122501.482920-1-ralf@mandelbit.com/

Thanks,
         Antonio


> Because, as explained in this thread and in the RFC, there is enough
> evidence that the current IPv6 dst-caching pattern is racy. If other
> kernel users are expected to live with that race, I cannot force a
> generic fix, but I do not think that is a good reason to require ovpn to
> do the same.
> 
> If you believe the sequence I described is safe, please explain which
> invariant makes it so.
> 

-- 
Antonio Quartulli
OpenVPN Inc.


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

end of thread, other threads:[~2026-10-09  0:33 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17 10:09 [PATCH net 0/1] ovpn: avoid caching stale IPv6 dst after FIB changes Ralf Lici
2026-09-17 10:09 ` [PATCH net 1/1] " Ralf Lici
2026-09-17 19:09   ` David Ahern
2026-09-18  6:51     ` Ralf Lici
2026-09-18 18:42       ` David Ahern
2026-09-18 20:27         ` Ralf Lici
2026-09-28  8:56           ` Ralf Lici
2026-09-29 14:09             ` David Ahern
2026-09-29 15:04               ` Ralf Lici
2026-10-09  0:33                 ` Antonio Quartulli

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