diff options
author | Amerigo Wang <amwang@redhat.com> | 2012-09-18 12:50:08 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-09-19 17:23:28 -0400 |
commit | c038a767cd697238b09f7a4ea5a504b4891774e9 (patch) | |
tree | c6cbe9f5b641a7f5cc4e1fb520724b77682e9810 /net/ipv6 | |
parent | 8c4c49df5cfeb8d56e5b85a430c8cbcb86c2ac37 (diff) |
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: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_reasm.c | 137 |
1 files changed, 95 insertions, 42 deletions
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index f94fb3ac2a79..f40f327ccc0c 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
@@ -71,27 +71,26 @@ struct nf_ct_frag6_queue | |||
71 | }; | 71 | }; |
72 | 72 | ||
73 | static struct inet_frags nf_frags; | 73 | static struct inet_frags nf_frags; |
74 | static struct netns_frags nf_init_frags; | ||
75 | 74 | ||
76 | #ifdef CONFIG_SYSCTL | 75 | #ifdef CONFIG_SYSCTL |
77 | static struct ctl_table nf_ct_frag6_sysctl_table[] = { | 76 | static struct ctl_table nf_ct_frag6_sysctl_table[] = { |
78 | { | 77 | { |
79 | .procname = "nf_conntrack_frag6_timeout", | 78 | .procname = "nf_conntrack_frag6_timeout", |
80 | .data = &nf_init_frags.timeout, | 79 | .data = &init_net.nf_frag.frags.timeout, |
81 | .maxlen = sizeof(unsigned int), | 80 | .maxlen = sizeof(unsigned int), |
82 | .mode = 0644, | 81 | .mode = 0644, |
83 | .proc_handler = proc_dointvec_jiffies, | 82 | .proc_handler = proc_dointvec_jiffies, |
84 | }, | 83 | }, |
85 | { | 84 | { |
86 | .procname = "nf_conntrack_frag6_low_thresh", | 85 | .procname = "nf_conntrack_frag6_low_thresh", |
87 | .data = &nf_init_frags.low_thresh, | 86 | .data = &init_net.nf_frag.frags.low_thresh, |
88 | .maxlen = sizeof(unsigned int), | 87 | .maxlen = sizeof(unsigned int), |
89 | .mode = 0644, | 88 | .mode = 0644, |
90 | .proc_handler = proc_dointvec, | 89 | .proc_handler = proc_dointvec, |
91 | }, | 90 | }, |
92 | { | 91 | { |
93 | .procname = "nf_conntrack_frag6_high_thresh", | 92 | .procname = "nf_conntrack_frag6_high_thresh", |
94 | .data = &nf_init_frags.high_thresh, | 93 | .data = &init_net.nf_frag.frags.high_thresh, |
95 | .maxlen = sizeof(unsigned int), | 94 | .maxlen = sizeof(unsigned int), |
96 | .mode = 0644, | 95 | .mode = 0644, |
97 | .proc_handler = proc_dointvec, | 96 | .proc_handler = proc_dointvec, |
@@ -99,7 +98,55 @@ static struct ctl_table nf_ct_frag6_sysctl_table[] = { | |||
99 | { } | 98 | { } |
100 | }; | 99 | }; |
101 | 100 | ||
102 | static struct ctl_table_header *nf_ct_frag6_sysctl_header; | 101 | static int __net_init nf_ct_frag6_sysctl_register(struct net *net) |
102 | { | ||
103 | struct ctl_table *table; | ||
104 | struct ctl_table_header *hdr; | ||
105 | |||
106 | table = nf_ct_frag6_sysctl_table; | ||
107 | if (!net_eq(net, &init_net)) { | ||
108 | table = kmemdup(table, sizeof(nf_ct_frag6_sysctl_table), | ||
109 | GFP_KERNEL); | ||
110 | if (table == NULL) | ||
111 | goto err_alloc; | ||
112 | |||
113 | table[0].data = &net->ipv6.frags.high_thresh; | ||
114 | table[1].data = &net->ipv6.frags.low_thresh; | ||
115 | table[2].data = &net->ipv6.frags.timeout; | ||
116 | } | ||
117 | |||
118 | hdr = register_net_sysctl(net, "net/netfilter", table); | ||
119 | if (hdr == NULL) | ||
120 | goto err_reg; | ||
121 | |||
122 | net->ipv6.sysctl.frags_hdr = hdr; | ||
123 | return 0; | ||
124 | |||
125 | err_reg: | ||
126 | if (!net_eq(net, &init_net)) | ||
127 | kfree(table); | ||
128 | err_alloc: | ||
129 | return -ENOMEM; | ||
130 | } | ||
131 | |||
132 | static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net) | ||
133 | { | ||
134 | struct ctl_table *table; | ||
135 | |||
136 | table = net->nf_frag.sysctl.frags_hdr->ctl_table_arg; | ||
137 | unregister_net_sysctl_table(net->nf_frag.sysctl.frags_hdr); | ||
138 | if (!net_eq(net, &init_net)) | ||
139 | kfree(table); | ||
140 | } | ||
141 | |||
142 | #else | ||
143 | static int __net_init nf_ct_frag6_sysctl_register(struct net *net) | ||
144 | { | ||
145 | return 0; | ||
146 | } | ||
147 | static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net) | ||
148 | { | ||
149 | } | ||
103 | #endif | 150 | #endif |
104 | 151 | ||
105 | static unsigned int nf_hashfn(struct inet_frag_queue *q) | 152 | 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 | inet_frag_kill(&fq->q, &nf_frags); | 178 | inet_frag_kill(&fq->q, &nf_frags); |
132 | } | 179 | } |
133 | 180 | ||
134 | static void nf_ct_frag6_evictor(void) | ||
135 | { | ||
136 | local_bh_disable(); | ||
137 | inet_frag_evictor(&nf_init_frags, &nf_frags); | ||
138 | local_bh_enable(); | ||
139 | } | ||
140 | |||
141 | static void nf_ct_frag6_expire(unsigned long data) | 181 | static void nf_ct_frag6_expire(unsigned long data) |
142 | { | 182 | { |
143 | struct nf_ct_frag6_queue *fq; | 183 | struct nf_ct_frag6_queue *fq; |
@@ -158,9 +198,9 @@ out: | |||
158 | } | 198 | } |
159 | 199 | ||
160 | /* Creation primitives. */ | 200 | /* Creation primitives. */ |
161 | 201 | static inline struct nf_ct_frag6_queue *fq_find(struct net *net, __be32 id, | |
162 | static __inline__ struct nf_ct_frag6_queue * | 202 | u32 user, struct in6_addr *src, |
163 | fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst) | 203 | struct in6_addr *dst) |
164 | { | 204 | { |
165 | struct inet_frag_queue *q; | 205 | struct inet_frag_queue *q; |
166 | struct ip6_create_arg arg; | 206 | struct ip6_create_arg arg; |
@@ -174,7 +214,7 @@ fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst) | |||
174 | read_lock_bh(&nf_frags.lock); | 214 | read_lock_bh(&nf_frags.lock); |
175 | hash = inet6_hash_frag(id, src, dst, nf_frags.rnd); | 215 | hash = inet6_hash_frag(id, src, dst, nf_frags.rnd); |
176 | 216 | ||
177 | q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash); | 217 | q = inet_frag_find(&net->nf_frag.frags, &nf_frags, &arg, hash); |
178 | local_bh_enable(); | 218 | local_bh_enable(); |
179 | if (q == NULL) | 219 | if (q == NULL) |
180 | goto oom; | 220 | goto oom; |
@@ -312,7 +352,7 @@ found: | |||
312 | fq->q.meat += skb->len; | 352 | fq->q.meat += skb->len; |
313 | if (payload_len > fq->q.max_size) | 353 | if (payload_len > fq->q.max_size) |
314 | fq->q.max_size = payload_len; | 354 | fq->q.max_size = payload_len; |
315 | atomic_add(skb->truesize, &nf_init_frags.mem); | 355 | atomic_add(skb->truesize, &fq->q.net->mem); |
316 | 356 | ||
317 | /* The first fragment. | 357 | /* The first fragment. |
318 | * nhoffset is obtained from the first fragment, of course. | 358 | * nhoffset is obtained from the first fragment, of course. |
@@ -322,7 +362,7 @@ found: | |||
322 | fq->q.last_in |= INET_FRAG_FIRST_IN; | 362 | fq->q.last_in |= INET_FRAG_FIRST_IN; |
323 | } | 363 | } |
324 | write_lock(&nf_frags.lock); | 364 | write_lock(&nf_frags.lock); |
325 | list_move_tail(&fq->q.lru_list, &nf_init_frags.lru_list); | 365 | list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list); |
326 | write_unlock(&nf_frags.lock); | 366 | write_unlock(&nf_frags.lock); |
327 | return 0; | 367 | return 0; |
328 | 368 | ||
@@ -391,7 +431,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) | |||
391 | clone->ip_summed = head->ip_summed; | 431 | clone->ip_summed = head->ip_summed; |
392 | 432 | ||
393 | NFCT_FRAG6_CB(clone)->orig = NULL; | 433 | NFCT_FRAG6_CB(clone)->orig = NULL; |
394 | atomic_add(clone->truesize, &nf_init_frags.mem); | 434 | atomic_add(clone->truesize, &fq->q.net->mem); |
395 | } | 435 | } |
396 | 436 | ||
397 | /* We have to remove fragment header from datagram and to relocate | 437 | /* 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 | head->csum = csum_add(head->csum, fp->csum); | 455 | head->csum = csum_add(head->csum, fp->csum); |
416 | head->truesize += fp->truesize; | 456 | head->truesize += fp->truesize; |
417 | } | 457 | } |
418 | atomic_sub(head->truesize, &nf_init_frags.mem); | 458 | atomic_sub(head->truesize, &fq->q.net->mem); |
419 | 459 | ||
420 | head->local_df = 1; | 460 | head->local_df = 1; |
421 | head->next = NULL; | 461 | head->next = NULL; |
@@ -527,6 +567,8 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |||
527 | { | 567 | { |
528 | struct sk_buff *clone; | 568 | struct sk_buff *clone; |
529 | struct net_device *dev = skb->dev; | 569 | struct net_device *dev = skb->dev; |
570 | struct net *net = skb_dst(skb) ? dev_net(skb_dst(skb)->dev) | ||
571 | : dev_net(skb->dev); | ||
530 | struct frag_hdr *fhdr; | 572 | struct frag_hdr *fhdr; |
531 | struct nf_ct_frag6_queue *fq; | 573 | struct nf_ct_frag6_queue *fq; |
532 | struct ipv6hdr *hdr; | 574 | struct ipv6hdr *hdr; |
@@ -560,10 +602,13 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |||
560 | hdr = ipv6_hdr(clone); | 602 | hdr = ipv6_hdr(clone); |
561 | fhdr = (struct frag_hdr *)skb_transport_header(clone); | 603 | fhdr = (struct frag_hdr *)skb_transport_header(clone); |
562 | 604 | ||
563 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) | 605 | if (atomic_read(&net->nf_frag.frags.mem) > net->nf_frag.frags.high_thresh) { |
564 | nf_ct_frag6_evictor(); | 606 | local_bh_disable(); |
607 | inet_frag_evictor(&net->nf_frag.frags, &nf_frags); | ||
608 | local_bh_enable(); | ||
609 | } | ||
565 | 610 | ||
566 | fq = fq_find(fhdr->identification, user, &hdr->saddr, &hdr->daddr); | 611 | fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr); |
567 | if (fq == NULL) { | 612 | if (fq == NULL) { |
568 | pr_debug("Can't find and can't create new queue\n"); | 613 | pr_debug("Can't find and can't create new queue\n"); |
569 | goto ret_orig; | 614 | goto ret_orig; |
@@ -621,8 +666,31 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | |||
621 | nf_conntrack_put_reasm(skb); | 666 | nf_conntrack_put_reasm(skb); |
622 | } | 667 | } |
623 | 668 | ||
669 | static int nf_ct_net_init(struct net *net) | ||
670 | { | ||
671 | net->nf_frag.frags.high_thresh = IPV6_FRAG_HIGH_THRESH; | ||
672 | net->nf_frag.frags.low_thresh = IPV6_FRAG_LOW_THRESH; | ||
673 | net->nf_frag.frags.timeout = IPV6_FRAG_TIMEOUT; | ||
674 | inet_frags_init_net(&net->nf_frag.frags); | ||
675 | |||
676 | return nf_ct_frag6_sysctl_register(net); | ||
677 | } | ||
678 | |||
679 | static void nf_ct_net_exit(struct net *net) | ||
680 | { | ||
681 | nf_ct_frags6_sysctl_unregister(net); | ||
682 | inet_frags_exit_net(&net->nf_frag.frags, &nf_frags); | ||
683 | } | ||
684 | |||
685 | static struct pernet_operations nf_ct_net_ops = { | ||
686 | .init = nf_ct_net_init, | ||
687 | .exit = nf_ct_net_exit, | ||
688 | }; | ||
689 | |||
624 | int nf_ct_frag6_init(void) | 690 | int nf_ct_frag6_init(void) |
625 | { | 691 | { |
692 | int ret = 0; | ||
693 | |||
626 | nf_frags.hashfn = nf_hashfn; | 694 | nf_frags.hashfn = nf_hashfn; |
627 | nf_frags.constructor = ip6_frag_init; | 695 | nf_frags.constructor = ip6_frag_init; |
628 | nf_frags.destructor = NULL; | 696 | nf_frags.destructor = NULL; |
@@ -631,32 +699,17 @@ int nf_ct_frag6_init(void) | |||
631 | nf_frags.match = ip6_frag_match; | 699 | nf_frags.match = ip6_frag_match; |
632 | nf_frags.frag_expire = nf_ct_frag6_expire; | 700 | nf_frags.frag_expire = nf_ct_frag6_expire; |
633 | nf_frags.secret_interval = 10 * 60 * HZ; | 701 | nf_frags.secret_interval = 10 * 60 * HZ; |
634 | nf_init_frags.timeout = IPV6_FRAG_TIMEOUT; | ||
635 | nf_init_frags.high_thresh = IPV6_FRAG_HIGH_THRESH; | ||
636 | nf_init_frags.low_thresh = IPV6_FRAG_LOW_THRESH; | ||
637 | inet_frags_init_net(&nf_init_frags); | ||
638 | inet_frags_init(&nf_frags); | 702 | inet_frags_init(&nf_frags); |
639 | 703 | ||
640 | #ifdef CONFIG_SYSCTL | 704 | ret = register_pernet_subsys(&nf_ct_net_ops); |
641 | nf_ct_frag6_sysctl_header = register_net_sysctl(&init_net, "net/netfilter", | 705 | if (ret) |
642 | nf_ct_frag6_sysctl_table); | ||
643 | if (!nf_ct_frag6_sysctl_header) { | ||
644 | inet_frags_fini(&nf_frags); | 706 | inet_frags_fini(&nf_frags); |
645 | return -ENOMEM; | ||
646 | } | ||
647 | #endif | ||
648 | 707 | ||
649 | return 0; | 708 | return ret; |
650 | } | 709 | } |
651 | 710 | ||
652 | void nf_ct_frag6_cleanup(void) | 711 | void nf_ct_frag6_cleanup(void) |
653 | { | 712 | { |
654 | #ifdef CONFIG_SYSCTL | 713 | unregister_pernet_subsys(&nf_ct_net_ops); |
655 | unregister_net_sysctl_table(nf_ct_frag6_sysctl_header); | ||
656 | nf_ct_frag6_sysctl_header = NULL; | ||
657 | #endif | ||
658 | inet_frags_fini(&nf_frags); | 714 | inet_frags_fini(&nf_frags); |
659 | |||
660 | nf_init_frags.low_thresh = 0; | ||
661 | nf_ct_frag6_evictor(); | ||
662 | } | 715 | } |