Skip to content

Commit

Permalink
net: dynamically allocate fqdir structures
Browse files Browse the repository at this point in the history
Following patch will add rcu grace period before fqdir
rhashtable destruction, so we need to dynamically allocate
fqdir structures to not force expensive synchronize_rcu() calls
in netns dismantle path.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed May 26, 2019
1 parent a39aca6 commit 4907abc
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 63 deletions.
17 changes: 14 additions & 3 deletions include/net/inet_frag.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,25 @@ struct inet_frags {
int inet_frags_init(struct inet_frags *);
void inet_frags_fini(struct inet_frags *);

static inline int fqdir_init(struct fqdir *fqdir, struct inet_frags *f,
static inline int fqdir_init(struct fqdir **fqdirp, struct inet_frags *f,
struct net *net)
{
struct fqdir *fqdir = kzalloc(sizeof(*fqdir), GFP_KERNEL);
int res;

if (!fqdir)
return -ENOMEM;
fqdir->f = f;
fqdir->net = net;
atomic_long_set(&fqdir->mem, 0);
return rhashtable_init(&fqdir->rhashtable, &fqdir->f->rhash_params);
res = rhashtable_init(&fqdir->rhashtable, &fqdir->f->rhash_params);
if (res < 0) {
kfree(fqdir);
return res;
}
*fqdirp = fqdir;
return 0;
}

void fqdir_exit(struct fqdir *fqdir);

void inet_frag_kill(struct inet_frag_queue *q);
Expand Down
2 changes: 1 addition & 1 deletion include/net/netns/ieee802154_6lowpan.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct netns_sysctl_lowpan {

struct netns_ieee802154_lowpan {
struct netns_sysctl_lowpan sysctl;
struct fqdir fqdir;
struct fqdir *fqdir;
};

#endif
2 changes: 1 addition & 1 deletion include/net/netns/ipv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ struct netns_ipv4 {

struct inet_peer_base *peers;
struct sock * __percpu *tcp_sk;
struct fqdir fqdir;
struct fqdir *fqdir;
#ifdef CONFIG_NETFILTER
struct xt_table *iptable_filter;
struct xt_table *iptable_mangle;
Expand Down
4 changes: 2 additions & 2 deletions include/net/netns/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct netns_ipv6 {
struct ipv6_devconf *devconf_all;
struct ipv6_devconf *devconf_dflt;
struct inet_peer_base *peers;
struct fqdir fqdir;
struct fqdir *fqdir;
#ifdef CONFIG_NETFILTER
struct xt_table *ip6table_filter;
struct xt_table *ip6table_mangle;
Expand Down Expand Up @@ -116,7 +116,7 @@ struct netns_ipv6 {

#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
struct netns_nf_frag {
struct fqdir fqdir;
struct fqdir *fqdir;
};
#endif

Expand Down
24 changes: 13 additions & 11 deletions net/ieee802154/6lowpan/reassembly.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fq_find(struct net *net, const struct lowpan_802154_cb *cb,
key.src = *src;
key.dst = *dst;

q = inet_frag_find(&ieee802154_lowpan->fqdir, &key);
q = inet_frag_find(ieee802154_lowpan->fqdir, &key);
if (!q)
return NULL;

Expand Down Expand Up @@ -377,11 +377,11 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
table[0].procname = NULL;
}

table[0].data = &ieee802154_lowpan->fqdir.high_thresh;
table[0].extra1 = &ieee802154_lowpan->fqdir.low_thresh;
table[1].data = &ieee802154_lowpan->fqdir.low_thresh;
table[1].extra2 = &ieee802154_lowpan->fqdir.high_thresh;
table[2].data = &ieee802154_lowpan->fqdir.timeout;
table[0].data = &ieee802154_lowpan->fqdir->high_thresh;
table[0].extra1 = &ieee802154_lowpan->fqdir->low_thresh;
table[1].data = &ieee802154_lowpan->fqdir->low_thresh;
table[1].extra2 = &ieee802154_lowpan->fqdir->high_thresh;
table[2].data = &ieee802154_lowpan->fqdir->timeout;

hdr = register_net_sysctl(net, "net/ieee802154/6lowpan", table);
if (hdr == NULL)
Expand Down Expand Up @@ -449,16 +449,18 @@ static int __net_init lowpan_frags_init_net(struct net *net)
net_ieee802154_lowpan(net);
int res;

ieee802154_lowpan->fqdir.high_thresh = IPV6_FRAG_HIGH_THRESH;
ieee802154_lowpan->fqdir.low_thresh = IPV6_FRAG_LOW_THRESH;
ieee802154_lowpan->fqdir.timeout = IPV6_FRAG_TIMEOUT;

res = fqdir_init(&ieee802154_lowpan->fqdir, &lowpan_frags, net);
if (res < 0)
return res;

ieee802154_lowpan->fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH;
ieee802154_lowpan->fqdir->low_thresh = IPV6_FRAG_LOW_THRESH;
ieee802154_lowpan->fqdir->timeout = IPV6_FRAG_TIMEOUT;

res = lowpan_frags_ns_sysctl_register(net);
if (res < 0)
fqdir_exit(&ieee802154_lowpan->fqdir);
fqdir_exit(ieee802154_lowpan->fqdir);
return res;
}

Expand All @@ -468,7 +470,7 @@ static void __net_exit lowpan_frags_exit_net(struct net *net)
net_ieee802154_lowpan(net);

lowpan_frags_ns_sysctl_unregister(net);
fqdir_exit(&ieee802154_lowpan->fqdir);
fqdir_exit(ieee802154_lowpan->fqdir);
}

static struct pernet_operations lowpan_frags_ops = {
Expand Down
1 change: 1 addition & 0 deletions net/ipv4/inet_fragment.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ void fqdir_exit(struct fqdir *fqdir)
fqdir->high_thresh = 0; /* prevent creation of new frags */

rhashtable_free_and_destroy(&fqdir->rhashtable, inet_frags_free_cb, NULL);
kfree(fqdir);
}
EXPORT_SYMBOL(fqdir_exit);

Expand Down
32 changes: 16 additions & 16 deletions net/ipv4/ip_fragment.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ static struct ipq *ip_find(struct net *net, struct iphdr *iph,
};
struct inet_frag_queue *q;

q = inet_frag_find(&net->ipv4.fqdir, &key);
q = inet_frag_find(net->ipv4.fqdir, &key);
if (!q)
return NULL;

Expand Down Expand Up @@ -589,12 +589,12 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net)
goto err_alloc;

}
table[0].data = &net->ipv4.fqdir.high_thresh;
table[0].extra1 = &net->ipv4.fqdir.low_thresh;
table[1].data = &net->ipv4.fqdir.low_thresh;
table[1].extra2 = &net->ipv4.fqdir.high_thresh;
table[2].data = &net->ipv4.fqdir.timeout;
table[3].data = &net->ipv4.fqdir.max_dist;
table[0].data = &net->ipv4.fqdir->high_thresh;
table[0].extra1 = &net->ipv4.fqdir->low_thresh;
table[1].data = &net->ipv4.fqdir->low_thresh;
table[1].extra2 = &net->ipv4.fqdir->high_thresh;
table[2].data = &net->ipv4.fqdir->timeout;
table[3].data = &net->ipv4.fqdir->max_dist;

hdr = register_net_sysctl(net, "net/ipv4", table);
if (!hdr)
Expand Down Expand Up @@ -642,6 +642,9 @@ static int __net_init ipv4_frags_init_net(struct net *net)
{
int res;

res = fqdir_init(&net->ipv4.fqdir, &ip4_frags, net);
if (res < 0)
return res;
/* Fragment cache limits.
*
* The fragment memory accounting code, (tries to) account for
Expand All @@ -656,30 +659,27 @@ static int __net_init ipv4_frags_init_net(struct net *net)
* we will prune down to 3MB, making room for approx 8 big 64K
* fragments 8x128k.
*/
net->ipv4.fqdir.high_thresh = 4 * 1024 * 1024;
net->ipv4.fqdir.low_thresh = 3 * 1024 * 1024;
net->ipv4.fqdir->high_thresh = 4 * 1024 * 1024;
net->ipv4.fqdir->low_thresh = 3 * 1024 * 1024;
/*
* Important NOTE! Fragment queue must be destroyed before MSL expires.
* RFC791 is wrong proposing to prolongate timer each fragment arrival
* by TTL.
*/
net->ipv4.fqdir.timeout = IP_FRAG_TIME;
net->ipv4.fqdir->timeout = IP_FRAG_TIME;

net->ipv4.fqdir.max_dist = 64;
net->ipv4.fqdir->max_dist = 64;

res = fqdir_init(&net->ipv4.fqdir, &ip4_frags, net);
if (res < 0)
return res;
res = ip4_frags_ns_ctl_register(net);
if (res < 0)
fqdir_exit(&net->ipv4.fqdir);
fqdir_exit(net->ipv4.fqdir);
return res;
}

static void __net_exit ipv4_frags_exit_net(struct net *net)
{
ip4_frags_ns_ctl_unregister(net);
fqdir_exit(&net->ipv4.fqdir);
fqdir_exit(net->ipv4.fqdir);
}

static struct pernet_operations ip4_frags_ops = {
Expand Down
4 changes: 2 additions & 2 deletions net/ipv4/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "RAW: inuse %d\n",
sock_prot_inuse_get(net, &raw_prot));
seq_printf(seq, "FRAG: inuse %u memory %lu\n",
atomic_read(&net->ipv4.fqdir.rhashtable.nelems),
frag_mem_limit(&net->ipv4.fqdir));
atomic_read(&net->ipv4.fqdir->rhashtable.nelems),
frag_mem_limit(net->ipv4.fqdir));
return 0;
}

Expand Down
27 changes: 14 additions & 13 deletions net/ipv6/netfilter/nf_conntrack_reasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ static int nf_ct_frag6_sysctl_register(struct net *net)
goto err_alloc;
}

table[0].data = &net->nf_frag.fqdir.timeout;
table[1].data = &net->nf_frag.fqdir.low_thresh;
table[1].extra2 = &net->nf_frag.fqdir.high_thresh;
table[2].data = &net->nf_frag.fqdir.high_thresh;
table[2].extra1 = &net->nf_frag.fqdir.low_thresh;
table[2].extra2 = &init_net.nf_frag.fqdir.high_thresh;
table[0].data = &net->nf_frag.fqdir->timeout;
table[1].data = &net->nf_frag.fqdir->low_thresh;
table[1].extra2 = &net->nf_frag.fqdir->high_thresh;
table[2].data = &net->nf_frag.fqdir->high_thresh;
table[2].extra1 = &net->nf_frag.fqdir->low_thresh;
table[2].extra2 = &init_net.nf_frag.fqdir->high_thresh;

hdr = register_net_sysctl(net, "net/netfilter", table);
if (hdr == NULL)
Expand Down Expand Up @@ -162,7 +162,7 @@ static struct frag_queue *fq_find(struct net *net, __be32 id, u32 user,
};
struct inet_frag_queue *q;

q = inet_frag_find(&net->nf_frag.fqdir, &key);
q = inet_frag_find(net->nf_frag.fqdir, &key);
if (!q)
return NULL;

Expand Down Expand Up @@ -489,23 +489,24 @@ static int nf_ct_net_init(struct net *net)
{
int res;

net->nf_frag.fqdir.high_thresh = IPV6_FRAG_HIGH_THRESH;
net->nf_frag.fqdir.low_thresh = IPV6_FRAG_LOW_THRESH;
net->nf_frag.fqdir.timeout = IPV6_FRAG_TIMEOUT;

res = fqdir_init(&net->nf_frag.fqdir, &nf_frags, net);
if (res < 0)
return res;

net->nf_frag.fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH;
net->nf_frag.fqdir->low_thresh = IPV6_FRAG_LOW_THRESH;
net->nf_frag.fqdir->timeout = IPV6_FRAG_TIMEOUT;

res = nf_ct_frag6_sysctl_register(net);
if (res < 0)
fqdir_exit(&net->nf_frag.fqdir);
fqdir_exit(net->nf_frag.fqdir);
return res;
}

static void nf_ct_net_exit(struct net *net)
{
nf_ct_frags6_sysctl_unregister(net);
fqdir_exit(&net->nf_frag.fqdir);
fqdir_exit(net->nf_frag.fqdir);
}

static struct pernet_operations nf_ct_net_ops = {
Expand Down
4 changes: 2 additions & 2 deletions net/ipv6/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "RAW6: inuse %d\n",
sock_prot_inuse_get(net, &rawv6_prot));
seq_printf(seq, "FRAG6: inuse %u memory %lu\n",
atomic_read(&net->ipv6.fqdir.rhashtable.nelems),
frag_mem_limit(&net->ipv6.fqdir));
atomic_read(&net->ipv6.fqdir->rhashtable.nelems),
frag_mem_limit(net->ipv6.fqdir));
return 0;
}

Expand Down
24 changes: 12 additions & 12 deletions net/ipv6/reassembly.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ fq_find(struct net *net, __be32 id, const struct ipv6hdr *hdr, int iif)
IPV6_ADDR_LINKLOCAL)))
key.iif = 0;

q = inet_frag_find(&net->ipv6.fqdir, &key);
q = inet_frag_find(net->ipv6.fqdir, &key);
if (!q)
return NULL;

Expand Down Expand Up @@ -443,11 +443,11 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net)
goto err_alloc;

}
table[0].data = &net->ipv6.fqdir.high_thresh;
table[0].extra1 = &net->ipv6.fqdir.low_thresh;
table[1].data = &net->ipv6.fqdir.low_thresh;
table[1].extra2 = &net->ipv6.fqdir.high_thresh;
table[2].data = &net->ipv6.fqdir.timeout;
table[0].data = &net->ipv6.fqdir->high_thresh;
table[0].extra1 = &net->ipv6.fqdir->low_thresh;
table[1].data = &net->ipv6.fqdir->low_thresh;
table[1].extra2 = &net->ipv6.fqdir->high_thresh;
table[2].data = &net->ipv6.fqdir->timeout;

hdr = register_net_sysctl(net, "net/ipv6", table);
if (!hdr)
Expand Down Expand Up @@ -510,24 +510,24 @@ static int __net_init ipv6_frags_init_net(struct net *net)
{
int res;

net->ipv6.fqdir.high_thresh = IPV6_FRAG_HIGH_THRESH;
net->ipv6.fqdir.low_thresh = IPV6_FRAG_LOW_THRESH;
net->ipv6.fqdir.timeout = IPV6_FRAG_TIMEOUT;

res = fqdir_init(&net->ipv6.fqdir, &ip6_frags, net);
if (res < 0)
return res;

net->ipv6.fqdir->high_thresh = IPV6_FRAG_HIGH_THRESH;
net->ipv6.fqdir->low_thresh = IPV6_FRAG_LOW_THRESH;
net->ipv6.fqdir->timeout = IPV6_FRAG_TIMEOUT;

res = ip6_frags_ns_sysctl_register(net);
if (res < 0)
fqdir_exit(&net->ipv6.fqdir);
fqdir_exit(net->ipv6.fqdir);
return res;
}

static void __net_exit ipv6_frags_exit_net(struct net *net)
{
ip6_frags_ns_sysctl_unregister(net);
fqdir_exit(&net->ipv6.fqdir);
fqdir_exit(net->ipv6.fqdir);
}

static struct pernet_operations ip6_frags_ops = {
Expand Down

0 comments on commit 4907abc

Please sign in to comment.