From: Kuniyuki Iwashima Date: Fri, 28 Feb 2025 04:23:19 +0000 (-0800) Subject: ipv4: fib: Allocate fib_info_hash[] during netns initialisation. X-Git-Tag: v6.15-rc1~160^2~194^2~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cfc47029fa124e5e04411fb1dbd3726db90fd346;p=thirdparty%2Fkernel%2Flinux.git ipv4: fib: Allocate fib_info_hash[] during netns initialisation. 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 Reviewed-by: Eric Dumazet Reviewed-by: David Ahern Link: https://patch.msgid.link/20250228042328.96624-4-kuniyu@amazon.com Signed-off-by: Jakub Kicinski --- diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index a113c11ab56b5..e3864b74e92a6 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -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; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 6730e2034cf8e..40c062f820f2d 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -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 = { diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 23aae379ba423..b7e2023bf742d 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -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); +}