Skip to content

Commit

Permalink
ipv6/addrconf: allocate a per netns hash table
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Dumazet authored and Jakub Kicinski committed Feb 9, 2022
1 parent b2309a7 commit 21a216a
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 0 deletions.
4 changes: 4 additions & 0 deletions include/net/netns/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
20 changes: 20 additions & 0 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -7172,11 +7179,15 @@ static int __net_init addrconf_init_net(struct net *net)
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);
Expand All @@ -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 = {
Expand Down

0 comments on commit 21a216a

Please sign in to comment.