summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorKuniyuki Iwashima <kuniyu@google.com>2026-10-01 20:47:18 +0000
committerJakub Kicinski <kuba@kernel.org>2026-10-06 15:56:16 -0700
commitf12d2907992db7ba91cc4a1796dce3cffb01318c (patch)
treeda08ba77f9aef9b2ff38e9af9d1c781cf2e3fe84 /include
parentca6854799069778fef446d307935f764cc3d3afb (diff)
ipv6: Batch rt6_uncached_list_flush_dev() in netdev_run_todo().
IPv6 uncached routes are linked to the global per-cpu lists, rt6_uncached_list. When unregistering a netdev, rt6_uncached_list_flush_dev() iterates over the potentially long lists to find uncached routes tied to the device and swap it with blackhole_netdev. Since it is called for every device in dying netns under RTNL, it adds O(N_dev x (N_cpu + N_route)) costs to any batched device unregistration. Let's call it once per batched device unregistration without RTNL. Because it now runs without RTNL, rt->dst.dev and rt->rt6i_idev->dev may transition to NETREG_UNREGISTERED at different times. Thus, we must check that both devices are blackhole_netdev before unlinking the route; otherwise, the remaining device reference would not be flushed when the other device is unregistered. In addition, since netdev_run_todo() runs even when IPv6 is disabled, rt6_uncached_list_flush_dev() must check ipv6_mod_enabled() before touching rt6_uncached_list. Note also that netdev_run_todo() cannot be called before rt6_uncached_list is initialised because: 1. unregister_netdevice_many_notify() panics when dev_boot_phase == 1 (net_dev_init() is subsys_initcall()). 2. the only device registered before fs_initcall_sync() is loopback and loopback_net_init() panics in case of failure. Reported-by: Chris J Arges <carges@cloudflare.com> Closes: https://lore.kernel.org/netdev/20260917-hash-bucket-route-lists-v3-0-30493a37b6eb@cloudflare.com/ Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Tested-by: Chris J Arges <carges@cloudflare.com> Link: https://patch.msgid.link/20261001204752.2572265-7-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'include')
-rw-r--r--include/net/ip6_route.h7
1 files changed, 7 insertions, 0 deletions
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 0f9b7a260d25..b9de335b639a 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -231,6 +231,13 @@ void rt6_multipath_rebalance(struct fib6_info *f6i);
void rt6_uncached_list_add(struct rt6_info *rt);
void rt6_uncached_list_del(struct rt6_info *rt);
+#ifdef CONFIG_IPV6
+void rt6_uncached_list_flush_dev(struct net_device *dev);
+#else
+static inline void rt6_uncached_list_flush_dev(struct net_device *dev)
+{
+}
+#endif
static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb)
{