]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipv4: fib: Flush all fib_info in fib_table_flush() during netns dismantle.
authorKuniyuki Iwashima <kuniyu@google.com>
Fri, 12 Jun 2026 06:32:04 +0000 (06:32 +0000)
committerJakub Kicinski <kuba@kernel.org>
Mon, 15 Jun 2026 18:49:28 +0000 (11:49 -0700)
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>
net/ipv4/fib_trie.c

index 1308213791f19d58764d6b6753acccbee404c29f..07068207b888519373969773840eae5d32079d6b 100644 (file)
@@ -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;
                        }