]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ipv4: fib: Allocate fib_info_hash[] during netns initialisation.
authorKuniyuki Iwashima <kuniyu@amazon.com>
Fri, 28 Feb 2025 04:23:19 +0000 (20:23 -0800)
committerJakub Kicinski <kuba@kernel.org>
Mon, 3 Mar 2025 23:04:09 +0000 (15:04 -0800)
We will allocate fib_info_hash[] and fib_info_laddrhash[] for each netns.

Currently, fib_info_hash[] is allocated when the first route is added.

Let's move the first allocation to a new __net_init function.

Note that we must call fib4_semantics_exit() in fib_net_exit_batch()
because ->exit() is called earlier than ->exit_batch().

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://patch.msgid.link/20250228042328.96624-4-kuniyu@amazon.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/ip_fib.h
net/ipv4/fib_frontend.c
net/ipv4/fib_semantics.c

index a113c11ab56b5f6e1659f7a3a454822932892f02..e3864b74e92a6c1e1e1b4bb82017e593b7c2c5f9 100644 (file)
@@ -162,6 +162,8 @@ struct fib_info {
        struct fib_nh           fib_nh[] __counted_by(fib_nhs);
 };
 
+int __net_init fib4_semantics_init(struct net *net);
+void __net_exit fib4_semantics_exit(struct net *net);
 
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 struct fib_rule;
index 6730e2034cf8ee6ba1209d34232d8e310d44d02f..40c062f820f2d17890b11d7cd8374c6bfa475eff 100644 (file)
@@ -1615,9 +1615,15 @@ static int __net_init fib_net_init(struct net *net)
        error = ip_fib_net_init(net);
        if (error < 0)
                goto out;
+
+       error = fib4_semantics_init(net);
+       if (error)
+               goto out_semantics;
+
        error = nl_fib_lookup_init(net);
        if (error < 0)
                goto out_nlfl;
+
        error = fib_proc_init(net);
        if (error < 0)
                goto out_proc;
@@ -1627,6 +1633,8 @@ out:
 out_proc:
        nl_fib_lookup_exit(net);
 out_nlfl:
+       fib4_semantics_exit(net);
+out_semantics:
        rtnl_lock();
        ip_fib_net_exit(net);
        rtnl_unlock();
@@ -1648,6 +1656,9 @@ static void __net_exit fib_net_exit_batch(struct list_head *net_list)
                ip_fib_net_exit(net);
 
        rtnl_unlock();
+
+       list_for_each_entry(net, net_list, exit_list)
+               fib4_semantics_exit(net);
 }
 
 static struct pernet_operations fib_net_ops = {
index 23aae379ba42324add2b787088a2c9b6dba93756..b7e2023bf742d71e1e30ab77766e12e318d8c64d 100644 (file)
@@ -1420,28 +1420,21 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
        }
 #endif
 
-       err = -ENOBUFS;
-
        if (fib_info_cnt >= fib_info_hash_size) {
+               unsigned int new_hash_bits = fib_info_hash_bits + 1;
                struct hlist_head *new_info_hash;
-               unsigned int new_hash_bits;
-
-               if (!fib_info_hash_bits)
-                       new_hash_bits = 4;
-               else
-                       new_hash_bits = fib_info_hash_bits + 1;
 
                new_info_hash = fib_info_hash_alloc(new_hash_bits);
                if (new_info_hash)
                        fib_info_hash_move(new_info_hash, 1 << new_hash_bits);
-
-               if (!fib_info_hash_size)
-                       goto failure;
        }
 
        fi = kzalloc(struct_size(fi, fib_nh, nhs), GFP_KERNEL);
-       if (!fi)
+       if (!fi) {
+               err = -ENOBUFS;
                goto failure;
+       }
+
        fi->fib_metrics = ip_fib_metrics_init(cfg->fc_mx, cfg->fc_mx_len, extack);
        if (IS_ERR(fi->fib_metrics)) {
                err = PTR_ERR(fi->fib_metrics);
@@ -1862,7 +1855,7 @@ int fib_sync_down_addr(struct net_device *dev, __be32 local)
        struct fib_info *fi;
        int ret = 0;
 
-       if (!fib_info_laddrhash || local == 0)
+       if (!local)
                return 0;
 
        head = fib_info_laddrhash_bucket(net, local);
@@ -2264,3 +2257,29 @@ check_saddr:
                        fl4->saddr = inet_select_addr(l3mdev, 0, RT_SCOPE_LINK);
        }
 }
+
+int __net_init fib4_semantics_init(struct net *net)
+{
+       unsigned int hash_bits = 4;
+
+       if (!net_eq(net, &init_net))
+               return 0;
+
+       fib_info_hash = fib_info_hash_alloc(hash_bits);
+       if (!fib_info_hash)
+               return -ENOMEM;
+
+       fib_info_hash_bits = hash_bits;
+       fib_info_hash_size = 1 << hash_bits;
+       fib_info_laddrhash = fib_info_hash + fib_info_hash_size;
+
+       return 0;
+}
+
+void __net_exit fib4_semantics_exit(struct net *net)
+{
+       if (!net_eq(net, &init_net))
+               return;
+
+       fib_info_hash_free(fib_info_hash);
+}