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 <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>
This commit is contained in:
Kuniyuki Iwashima 2025-02-27 20:23:19 -08:00 committed by Jakub Kicinski
parent fa336adc10
commit cfc47029fa
3 changed files with 45 additions and 13 deletions

View 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;

View 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 = {

View 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);
}