diff options
| author | Kuniyuki Iwashima <kuniyu@google.com> | 2026-10-01 20:47:18 +0000 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-10-06 15:56:16 -0700 |
| commit | f12d2907992db7ba91cc4a1796dce3cffb01318c (patch) | |
| tree | da08ba77f9aef9b2ff38e9af9d1c781cf2e3fe84 /include | |
| parent | ca6854799069778fef446d307935f764cc3d3afb (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.h | 7 |
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) { |
