summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorKuniyuki Iwashima <kuniyu@google.com>2026-06-29 18:10:56 +0000
committerPaolo Abeni <pabeni@redhat.com>2026-07-01 18:42:33 +0200
commit763a9437101b9f6210bcfbfd72ce51eb90b7a56e (patch)
tree1eaba4a065d200a0cb65b6e3c56999e458da2ea7 /net
parent4b8f5c974d14dc955b4252c02d5e4f185ddc9b23 (diff)
downloadlinux-next-763a9437101b9f6210bcfbfd72ce51eb90b7a56e.tar.gz
linux-next-763a9437101b9f6210bcfbfd72ce51eb90b7a56e.zip
ipv4: fib: Drop RTNL annotation for net->ipv4.fib_table_hash[].
fib_newrule() will drop RTNL except for the first IPv4 rule. net->ipv4.fib_table_hash[] will be read with no protection, but this is fine because fib_table is not destroyed until netns dismantle except for the merged main/local table. fib_unmerge() will continue to be called under RTNL, so other readers (fib_flush() and fib_info_notify_update()) just have to care about the concurrent hlist_add(). IPv6 and IPMR/IP6MR also take this strategy and use RCU helpers to avoid data race against concurrent hlist_add(). Let's not use lockdep_rtnl_is_held() and rcu_dereference_rtnl() for net->ipv4.fib_table_hash[]. Note that commit a7e53531234d ("fib_trie: Make fib_table rcu safe") started to use the _safe version in fib_flush(), but it is not needed thanks to RTNL. Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260629181226.1929658-5-kuniyu@google.com Reviewed-by: Ido Schimmel <idosch@nvidia.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/fib_frontend.c23
-rw-r--r--net/ipv4/fib_trie.c3
2 files changed, 14 insertions, 12 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 336d70649eb9..54eb72695093 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -126,24 +126,28 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
}
EXPORT_SYMBOL_GPL(fib_new_table);
-/* caller must hold either rtnl or rcu read lock */
struct fib_table *fib_get_table(struct net *net, u32 id)
{
- struct fib_table *tb;
+ struct fib_table *tb = NULL;
struct hlist_head *head;
unsigned int h;
if (id == 0)
id = RT_TABLE_MAIN;
h = id & (FIB_TABLE_HASHSZ - 1);
-
head = &net->ipv4.fib_table_hash[h];
- hlist_for_each_entry_rcu(tb, head, tb_hlist,
- lockdep_rtnl_is_held()) {
+
+ /* fib_table is not destroyed until ip_fib_net_exit()
+ * except for the merged main/local table.
+ * fib_unmerge() is called under RTNL, so other readers
+ * under RTNL (e.g. fib_flush(), fib_info_notify_update())
+ * can safely traverse the list with rcu_dereference_raw().
+ */
+ hlist_for_each_entry_rcu(tb, head, tb_hlist, true)
if (tb->tb_id == id)
- return tb;
- }
- return NULL;
+ break;
+
+ return tb;
}
#endif /* CONFIG_IP_MULTIPLE_TABLES */
@@ -206,10 +210,9 @@ void fib_flush(struct net *net)
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
struct hlist_head *head = &net->ipv4.fib_table_hash[h];
- struct hlist_node *tmp;
struct fib_table *tb;
- hlist_for_each_entry_safe(tb, tmp, head, tb_hlist)
+ hlist_for_each_entry_rcu(tb, head, tb_hlist, true)
flushed += fib_table_flush(net, tb, false);
}
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index e11dc86ceda0..d1d342d7148e 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2137,8 +2137,7 @@ void fib_info_notify_update(struct net *net, struct nl_info *info)
struct hlist_head *head = &net->ipv4.fib_table_hash[h];
struct fib_table *tb;
- hlist_for_each_entry_rcu(tb, head, tb_hlist,
- lockdep_rtnl_is_held())
+ hlist_for_each_entry_rcu(tb, head, tb_hlist, true)
__fib_info_notify_update(net, tb, info);
}
}