diff options
author | Eric Dumazet <edumazet@google.com> | 2022-02-07 20:50:28 -0800 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2022-02-08 20:41:32 -0800 |
commit | 21a216a8fc630161e69eaf02cbebdd1816ff1a13 (patch) | |
tree | 95881822e7dbc13dd7bf9cd87502e98fd03a3f54 | |
parent | b2309a71c1f2fc841feb184195b2e46b2e139bf4 (diff) | |
download | linux-21a216a8fc630161e69eaf02cbebdd1816ff1a13.tar.bz2 |
ipv6/addrconf: allocate a per netns hash table
Add a per netns hash table and a dedicated spinlock,
first step to get rid of the global inet6_addr_lst[] one.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | include/net/netns/ipv6.h | 4 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 20 |
2 files changed, 24 insertions, 0 deletions
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 30cdfc4e1615..755f12001c8b 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -92,6 +92,10 @@ struct netns_ipv6 { struct sock *tcp_sk; struct sock *igmp_sk; struct sock *mc_autojoin_sk; + + struct hlist_head *inet6_addr_lst; + spinlock_t addrconf_hash_lock; + #ifdef CONFIG_IPV6_MROUTE #ifndef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES struct mr_table *mrt6; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ef23e7dc538a..cda9e59cab43 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -7111,6 +7111,13 @@ static int __net_init addrconf_init_net(struct net *net) int err = -ENOMEM; struct ipv6_devconf *all, *dflt; + spin_lock_init(&net->ipv6.addrconf_hash_lock); + net->ipv6.inet6_addr_lst = kcalloc(IN6_ADDR_HSIZE, + sizeof(struct hlist_head), + GFP_KERNEL); + if (!net->ipv6.inet6_addr_lst) + goto err_alloc_addr; + all = kmemdup(&ipv6_devconf, sizeof(ipv6_devconf), GFP_KERNEL); if (!all) goto err_alloc_all; @@ -7172,11 +7179,15 @@ err_reg_all: err_alloc_dflt: kfree(all); err_alloc_all: + kfree(net->ipv6.inet6_addr_lst); +err_alloc_addr: return err; } static void __net_exit addrconf_exit_net(struct net *net) { + int i; + #ifdef CONFIG_SYSCTL __addrconf_sysctl_unregister(net, net->ipv6.devconf_dflt, NETCONFA_IFINDEX_DEFAULT); @@ -7187,6 +7198,15 @@ static void __net_exit addrconf_exit_net(struct net *net) net->ipv6.devconf_dflt = NULL; kfree(net->ipv6.devconf_all); net->ipv6.devconf_all = NULL; + + /* + * Check hash table, then free it. + */ + for (i = 0; i < IN6_ADDR_HSIZE; i++) + WARN_ON_ONCE(!hlist_empty(&net->ipv6.inet6_addr_lst[i])); + + kfree(net->ipv6.inet6_addr_lst); + net->ipv6.inet6_addr_lst = NULL; } static struct pernet_operations addrconf_ops = { |