summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKuniyuki Iwashima <kuniyu@google.com>2026-06-12 09:32:04 +0300
committerJakub Kicinski <kuba@kernel.org>2026-06-15 21:49:28 +0300
commit64587e936b6526539f5d2cf1bb667c52be937cd7 (patch)
treec527801fc4e7b5bc7686e0004226cf187d061c5a
parente3d202a1ed7c37c3c936d5eeb3abc3a7a713cb95 (diff)
downloadlinux-64587e936b6526539f5d2cf1bb667c52be937cd7.tar.xz
ipv4: fib: Flush all fib_info in fib_table_flush() during netns dismantle.
Even when fib_table_flush() is called with flush_all true, it does not flush all fib_info due to this condition: !(fi->fib_flags & RTNH_F_DEAD) && !fib_props[fa->fa_type].error) This creates an implicit ordering between default_device_exit_batch() and fib_net_exit_batch(). fib_table_flush(flush_all=true) must be called after all devices are NETDEV_UNREGISTERed, which is after nexthop_flush_dev() marks RTNH_F_DEAD. This would cause memory leak if the order were reversed. fib_table_flush() does not skip non-dead error routes when flush_all is true: !flush_all && !(fi->fib_flags & RTNH_F_DEAD) && fib_props[fa->fa_type].error Let's merge the two conditions not to skip all non-dead fib_info during netns dismantle. Note that we could further apply !flush_all to the basic table id check and the rtmsg_fib() call in the loop. Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20260612063225.455191-2-kuniyu@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--net/ipv4/fib_trie.c10
1 files changed, 2 insertions, 8 deletions
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;
}