summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-06-15 21:49:31 +0300
committerJakub Kicinski <kuba@kernel.org>2026-06-15 21:49:31 +0300
commitb712e0200fc2ec3fc597ec0f6f278e9b4273bbd1 (patch)
treed70e3ba5c6fc2f63858d14d28018c468a52966e6 /net
parente3d202a1ed7c37c3c936d5eeb3abc3a7a713cb95 (diff)
parent759923cf03b062b5b8cdc770e2819a67ebe1cacd (diff)
downloadlinux-b712e0200fc2ec3fc597ec0f6f278e9b4273bbd1.tar.xz
Merge branch 'ipv4-fib-remove-rtnl-in-fib_net_exit_batch'
Kuniyuki Iwashima says: ==================== ipv4: fib: Remove RTNL in fib_net_exit_batch(). Currently, we flush all IPv4 routes at ->exit_batch() during netns dismantle, which requires an extra RTNL. IPv4 routes are not added from the fast path unlike IPv6, so we can flush routes before default_device_exit_batch(). However, there is implicit ordering between ip_fib_net_exit() and default_device_exit_batch(). This series detangles it and moves ip_fib_net_exit() to ->exit_rtnl() to save the RTNL dance. The same change for IPv6 will need more work. ==================== Link: https://patch.msgid.link/20260612063225.455191-1-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/fib_frontend.c37
-rw-r--r--net/ipv4/fib_trie.c10
2 files changed, 20 insertions, 27 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index ceeb87b13b93..c7d1f31650d7 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -88,7 +88,8 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
if (id == RT_TABLE_LOCAL && !net->ipv4.fib_has_custom_rules)
alias = fib_new_table(net, RT_TABLE_MAIN);
- tb = fib_trie_table(id, alias);
+ if (check_net(net))
+ tb = fib_trie_table(id, alias);
if (!tb)
return NULL;
@@ -1606,7 +1607,7 @@ static void ip_fib_net_exit(struct net *net)
struct fib_table *tb;
hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) {
- hlist_del(&tb->tb_hlist);
+ hlist_del_rcu(&tb->tb_hlist);
fib_table_flush(net, tb, true);
fib_free_table(tb);
}
@@ -1615,9 +1616,6 @@ static void ip_fib_net_exit(struct net *net)
#ifdef CONFIG_IP_MULTIPLE_TABLES
fib4_rules_exit(net);
#endif
-
- kfree(net->ipv4.fib_table_hash);
- fib4_notifier_exit(net);
}
static int __net_init fib_net_init(struct net *net)
@@ -1653,35 +1651,36 @@ out_semantics:
rtnl_net_lock(net);
ip_fib_net_exit(net);
rtnl_net_unlock(net);
+
+ kfree(net->ipv4.fib_table_hash);
+ fib4_notifier_exit(net);
goto out;
}
-static void __net_exit fib_net_exit(struct net *net)
+static void __net_exit fib_net_pre_exit(struct net *net)
{
fib_proc_exit(net);
nl_fib_lookup_exit(net);
}
-static void __net_exit fib_net_exit_batch(struct list_head *net_list)
+static void __net_exit fib_net_exit_rtnl(struct net *net,
+ struct list_head *dev_kill_list)
{
- struct net *net;
-
- rtnl_lock();
- list_for_each_entry(net, net_list, exit_list) {
- __rtnl_net_lock(net);
- ip_fib_net_exit(net);
- __rtnl_net_unlock(net);
- }
- rtnl_unlock();
+ ip_fib_net_exit(net);
+}
- list_for_each_entry(net, net_list, exit_list)
- fib4_semantics_exit(net);
+static void __net_exit fib_net_exit(struct net *net)
+{
+ kfree(net->ipv4.fib_table_hash);
+ fib4_notifier_exit(net);
+ fib4_semantics_exit(net);
}
static struct pernet_operations fib_net_ops = {
.init = fib_net_init,
+ .pre_exit = fib_net_pre_exit,
+ .exit_rtnl = fib_net_exit_rtnl,
.exit = fib_net_exit,
- .exit_batch = fib_net_exit_batch,
};
static const struct rtnl_msg_handler fib_rtnl_msg_handlers[] __initconst = {
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 1308213791f1..07068207b888 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2046,18 +2046,12 @@ int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all)
hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) {
struct fib_info *fi = fa->fa_info;
- if (!fi || tb->tb_id != fa->tb_id ||
- (!(fi->fib_flags & RTNH_F_DEAD) &&
- !fib_props[fa->fa_type].error)) {
+ if (!fi || tb->tb_id != fa->tb_id) {
slen = fa->fa_slen;
continue;
}
- /* When not flushing the entire table, skip error
- * routes that are not marked for deletion.
- */
- if (!flush_all && fib_props[fa->fa_type].error &&
- !(fi->fib_flags & RTNH_F_DEAD)) {
+ if (!flush_all && !(fi->fib_flags & RTNH_F_DEAD)) {
slen = fa->fa_slen;
continue;
}