Merge branch 'ip-fix-route-leak-and-unregister_netdevice-stuck'

Kuniyuki Iwashima says:

====================
ip: Fix route leak and unregister_netdevice() stuck.

Jason Zhang fed commit 0346ec2f08 ("ipv6: Prevent
rt6_insert_exception() for dying fib6_info.") to LLM to
find tricks to cause the same symptom:

  unregister_netdevice: waiting for gre6 to become free. Usage count = 4
  ref_tracker: netdev@000000009652f190 has 1/3 users at
       dst_alloc+0x14b/0x490
       ip6_rt_cache_alloc+0x27b/0x670
       __ip6_rt_update_pmtu+0x572/0x850

This series treats them.
====================

Link: https://patch.msgid.link/20261101064418.2055158-1-kuniyu@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni 2026-11-04 15:34:53 +01:00
commit 58fa96691c
2 changed files with 20 additions and 2 deletions

View File

@ -2494,6 +2494,8 @@ ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
if (unlikely(!rt_cache_route(nhc, rth)))
rt_add_uncached_list(rth);
} else {
rt_add_uncached_list(rth);
}
skb_dst_set(skb, &rth->dst);
reason = SKB_NOT_DROPPED_YET;

View File

@ -179,12 +179,20 @@ void rt6_uncached_list_flush_dev(struct net_device *dev)
list_for_each_entry_safe(rt, safe, &ul->head, dst.rt_uncached) {
struct inet6_dev *rt_idev = rt->rt6i_idev;
struct net_device *rt_dev = rt->dst.dev;
struct fib6_info *from;
bool release_fib;
rcu_read_lock();
from = rcu_dereference(rt->from);
release_fib = from && from->fib6_destroying;
rcu_read_unlock();
if (rt_idev &&
(dev ? rt_idev->dev == dev :
READ_ONCE(rt_idev->dev->reg_state) == NETREG_UNREGISTERED)) {
rt->rt6i_idev = in6_dev_get(blackhole_netdev);
in6_dev_put(rt_idev);
release_fib = true;
}
if (dev ? rt_dev == dev :
@ -193,6 +201,12 @@ void rt6_uncached_list_flush_dev(struct net_device *dev)
netdev_ref_replace(rt_dev, blackhole_netdev,
&rt->dst.dev_tracker,
GFP_ATOMIC);
release_fib = true;
}
if (release_fib) {
from = unrcu_pointer(xchg(&rt->from, NULL));
fib6_info_release(from);
}
if (rt->dst.dev == blackhole_netdev &&
@ -3701,9 +3715,10 @@ void fib6_nh_release(struct fib6_nh *fib6_nh)
{
struct rt6_exception_bucket *bucket;
fib6_nh_release_dsts(fib6_nh);
rcu_read_lock();
fib6_nh_flush_exceptions(fib6_nh, NULL);
bucket = fib6_nh_get_excptn_bucket(fib6_nh, NULL);
if (bucket) {
rcu_assign_pointer(fib6_nh->rt6i_exception_bucket, NULL);
@ -3712,7 +3727,6 @@ void fib6_nh_release(struct fib6_nh *fib6_nh)
rcu_read_unlock();
fib6_nh_release_dsts(fib6_nh);
free_percpu(fib6_nh->rt6i_pcpu);
fib_nh_common_release(&fib6_nh->nh_common);
@ -3722,6 +3736,8 @@ void fib6_nh_release_dsts(struct fib6_nh *fib6_nh)
{
int cpu;
fib6_nh_flush_exceptions(fib6_nh, NULL);
if (!fib6_nh->rt6i_pcpu)
return;