提交 c038a767 编写于 作者: A Amerigo Wang 提交者: David S. Miller

ipv6: add a new namespace for nf_conntrack_reasm

As pointed by Michal, it is necessary to add a new
namespace for nf_conntrack_reasm code, this prepares
for the second patch.

Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Michal Kubeček <mkubecek@suse.cz>
Cc: David Miller <davem@davemloft.net>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: netfilter-devel@vger.kernel.org
Signed-off-by: NCong Wang <amwang@redhat.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 8c4c49df
...@@ -92,6 +92,9 @@ struct net { ...@@ -92,6 +92,9 @@ struct net {
struct netns_xt xt; struct netns_xt xt;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct; struct netns_ct ct;
#endif
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
struct netns_nf_frag nf_frag;
#endif #endif
struct sock *nfnl; struct sock *nfnl;
struct sock *nfnl_stash; struct sock *nfnl_stash;
......
...@@ -71,4 +71,12 @@ struct netns_ipv6 { ...@@ -71,4 +71,12 @@ struct netns_ipv6 {
#endif #endif
#endif #endif
}; };
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
struct netns_nf_frag {
struct netns_sysctl_ipv6 sysctl;
struct netns_frags frags;
};
#endif
#endif #endif
...@@ -71,27 +71,26 @@ struct nf_ct_frag6_queue ...@@ -71,27 +71,26 @@ struct nf_ct_frag6_queue
}; };
static struct inet_frags nf_frags; static struct inet_frags nf_frags;
static struct netns_frags nf_init_frags;
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static struct ctl_table nf_ct_frag6_sysctl_table[] = { static struct ctl_table nf_ct_frag6_sysctl_table[] = {
{ {
.procname = "nf_conntrack_frag6_timeout", .procname = "nf_conntrack_frag6_timeout",
.data = &nf_init_frags.timeout, .data = &init_net.nf_frag.frags.timeout,
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
}, },
{ {
.procname = "nf_conntrack_frag6_low_thresh", .procname = "nf_conntrack_frag6_low_thresh",
.data = &nf_init_frags.low_thresh, .data = &init_net.nf_frag.frags.low_thresh,
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec, .proc_handler = proc_dointvec,
}, },
{ {
.procname = "nf_conntrack_frag6_high_thresh", .procname = "nf_conntrack_frag6_high_thresh",
.data = &nf_init_frags.high_thresh, .data = &init_net.nf_frag.frags.high_thresh,
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec, .proc_handler = proc_dointvec,
...@@ -99,7 +98,55 @@ static struct ctl_table nf_ct_frag6_sysctl_table[] = { ...@@ -99,7 +98,55 @@ static struct ctl_table nf_ct_frag6_sysctl_table[] = {
{ } { }
}; };
static struct ctl_table_header *nf_ct_frag6_sysctl_header; static int __net_init nf_ct_frag6_sysctl_register(struct net *net)
{
struct ctl_table *table;
struct ctl_table_header *hdr;
table = nf_ct_frag6_sysctl_table;
if (!net_eq(net, &init_net)) {
table = kmemdup(table, sizeof(nf_ct_frag6_sysctl_table),
GFP_KERNEL);
if (table == NULL)
goto err_alloc;
table[0].data = &net->ipv6.frags.high_thresh;
table[1].data = &net->ipv6.frags.low_thresh;
table[2].data = &net->ipv6.frags.timeout;
}
hdr = register_net_sysctl(net, "net/netfilter", table);
if (hdr == NULL)
goto err_reg;
net->ipv6.sysctl.frags_hdr = hdr;
return 0;
err_reg:
if (!net_eq(net, &init_net))
kfree(table);
err_alloc:
return -ENOMEM;
}
static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net)
{
struct ctl_table *table;
table = net->nf_frag.sysctl.frags_hdr->ctl_table_arg;
unregister_net_sysctl_table(net->nf_frag.sysctl.frags_hdr);
if (!net_eq(net, &init_net))
kfree(table);
}
#else
static int __net_init nf_ct_frag6_sysctl_register(struct net *net)
{
return 0;
}
static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net)
{
}
#endif #endif
static unsigned int nf_hashfn(struct inet_frag_queue *q) static unsigned int nf_hashfn(struct inet_frag_queue *q)
...@@ -131,13 +178,6 @@ static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq) ...@@ -131,13 +178,6 @@ static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
inet_frag_kill(&fq->q, &nf_frags); inet_frag_kill(&fq->q, &nf_frags);
} }
static void nf_ct_frag6_evictor(void)
{
local_bh_disable();
inet_frag_evictor(&nf_init_frags, &nf_frags);
local_bh_enable();
}
static void nf_ct_frag6_expire(unsigned long data) static void nf_ct_frag6_expire(unsigned long data)
{ {
struct nf_ct_frag6_queue *fq; struct nf_ct_frag6_queue *fq;
...@@ -158,9 +198,9 @@ static void nf_ct_frag6_expire(unsigned long data) ...@@ -158,9 +198,9 @@ static void nf_ct_frag6_expire(unsigned long data)
} }
/* Creation primitives. */ /* Creation primitives. */
static inline struct nf_ct_frag6_queue *fq_find(struct net *net, __be32 id,
static __inline__ struct nf_ct_frag6_queue * u32 user, struct in6_addr *src,
fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst) struct in6_addr *dst)
{ {
struct inet_frag_queue *q; struct inet_frag_queue *q;
struct ip6_create_arg arg; struct ip6_create_arg arg;
...@@ -174,7 +214,7 @@ fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst) ...@@ -174,7 +214,7 @@ fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst)
read_lock_bh(&nf_frags.lock); read_lock_bh(&nf_frags.lock);
hash = inet6_hash_frag(id, src, dst, nf_frags.rnd); hash = inet6_hash_frag(id, src, dst, nf_frags.rnd);
q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash); q = inet_frag_find(&net->nf_frag.frags, &nf_frags, &arg, hash);
local_bh_enable(); local_bh_enable();
if (q == NULL) if (q == NULL)
goto oom; goto oom;
...@@ -312,7 +352,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, ...@@ -312,7 +352,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
fq->q.meat += skb->len; fq->q.meat += skb->len;
if (payload_len > fq->q.max_size) if (payload_len > fq->q.max_size)
fq->q.max_size = payload_len; fq->q.max_size = payload_len;
atomic_add(skb->truesize, &nf_init_frags.mem); atomic_add(skb->truesize, &fq->q.net->mem);
/* The first fragment. /* The first fragment.
* nhoffset is obtained from the first fragment, of course. * nhoffset is obtained from the first fragment, of course.
...@@ -322,7 +362,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, ...@@ -322,7 +362,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
fq->q.last_in |= INET_FRAG_FIRST_IN; fq->q.last_in |= INET_FRAG_FIRST_IN;
} }
write_lock(&nf_frags.lock); write_lock(&nf_frags.lock);
list_move_tail(&fq->q.lru_list, &nf_init_frags.lru_list); list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list);
write_unlock(&nf_frags.lock); write_unlock(&nf_frags.lock);
return 0; return 0;
...@@ -391,7 +431,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) ...@@ -391,7 +431,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
clone->ip_summed = head->ip_summed; clone->ip_summed = head->ip_summed;
NFCT_FRAG6_CB(clone)->orig = NULL; NFCT_FRAG6_CB(clone)->orig = NULL;
atomic_add(clone->truesize, &nf_init_frags.mem); atomic_add(clone->truesize, &fq->q.net->mem);
} }
/* We have to remove fragment header from datagram and to relocate /* We have to remove fragment header from datagram and to relocate
...@@ -415,7 +455,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) ...@@ -415,7 +455,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
head->csum = csum_add(head->csum, fp->csum); head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize; head->truesize += fp->truesize;
} }
atomic_sub(head->truesize, &nf_init_frags.mem); atomic_sub(head->truesize, &fq->q.net->mem);
head->local_df = 1; head->local_df = 1;
head->next = NULL; head->next = NULL;
...@@ -527,6 +567,8 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) ...@@ -527,6 +567,8 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
{ {
struct sk_buff *clone; struct sk_buff *clone;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
struct net *net = skb_dst(skb) ? dev_net(skb_dst(skb)->dev)
: dev_net(skb->dev);
struct frag_hdr *fhdr; struct frag_hdr *fhdr;
struct nf_ct_frag6_queue *fq; struct nf_ct_frag6_queue *fq;
struct ipv6hdr *hdr; struct ipv6hdr *hdr;
...@@ -560,10 +602,13 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) ...@@ -560,10 +602,13 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
hdr = ipv6_hdr(clone); hdr = ipv6_hdr(clone);
fhdr = (struct frag_hdr *)skb_transport_header(clone); fhdr = (struct frag_hdr *)skb_transport_header(clone);
if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) if (atomic_read(&net->nf_frag.frags.mem) > net->nf_frag.frags.high_thresh) {
nf_ct_frag6_evictor(); local_bh_disable();
inet_frag_evictor(&net->nf_frag.frags, &nf_frags);
local_bh_enable();
}
fq = fq_find(fhdr->identification, user, &hdr->saddr, &hdr->daddr); fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr);
if (fq == NULL) { if (fq == NULL) {
pr_debug("Can't find and can't create new queue\n"); pr_debug("Can't find and can't create new queue\n");
goto ret_orig; goto ret_orig;
...@@ -621,8 +666,31 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, ...@@ -621,8 +666,31 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
nf_conntrack_put_reasm(skb); nf_conntrack_put_reasm(skb);
} }
static int nf_ct_net_init(struct net *net)
{
net->nf_frag.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
net->nf_frag.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
net->nf_frag.frags.timeout = IPV6_FRAG_TIMEOUT;
inet_frags_init_net(&net->nf_frag.frags);
return nf_ct_frag6_sysctl_register(net);
}
static void nf_ct_net_exit(struct net *net)
{
nf_ct_frags6_sysctl_unregister(net);
inet_frags_exit_net(&net->nf_frag.frags, &nf_frags);
}
static struct pernet_operations nf_ct_net_ops = {
.init = nf_ct_net_init,
.exit = nf_ct_net_exit,
};
int nf_ct_frag6_init(void) int nf_ct_frag6_init(void)
{ {
int ret = 0;
nf_frags.hashfn = nf_hashfn; nf_frags.hashfn = nf_hashfn;
nf_frags.constructor = ip6_frag_init; nf_frags.constructor = ip6_frag_init;
nf_frags.destructor = NULL; nf_frags.destructor = NULL;
...@@ -631,32 +699,17 @@ int nf_ct_frag6_init(void) ...@@ -631,32 +699,17 @@ int nf_ct_frag6_init(void)
nf_frags.match = ip6_frag_match; nf_frags.match = ip6_frag_match;
nf_frags.frag_expire = nf_ct_frag6_expire; nf_frags.frag_expire = nf_ct_frag6_expire;
nf_frags.secret_interval = 10 * 60 * HZ; nf_frags.secret_interval = 10 * 60 * HZ;
nf_init_frags.timeout = IPV6_FRAG_TIMEOUT;
nf_init_frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
nf_init_frags.low_thresh = IPV6_FRAG_LOW_THRESH;
inet_frags_init_net(&nf_init_frags);
inet_frags_init(&nf_frags); inet_frags_init(&nf_frags);
#ifdef CONFIG_SYSCTL ret = register_pernet_subsys(&nf_ct_net_ops);
nf_ct_frag6_sysctl_header = register_net_sysctl(&init_net, "net/netfilter", if (ret)
nf_ct_frag6_sysctl_table);
if (!nf_ct_frag6_sysctl_header) {
inet_frags_fini(&nf_frags); inet_frags_fini(&nf_frags);
return -ENOMEM;
}
#endif
return 0; return ret;
} }
void nf_ct_frag6_cleanup(void) void nf_ct_frag6_cleanup(void)
{ {
#ifdef CONFIG_SYSCTL unregister_pernet_subsys(&nf_ct_net_ops);
unregister_net_sysctl_table(nf_ct_frag6_sysctl_header);
nf_ct_frag6_sysctl_header = NULL;
#endif
inet_frags_fini(&nf_frags); inet_frags_fini(&nf_frags);
nf_init_frags.low_thresh = 0;
nf_ct_frag6_evictor();
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册