aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorAmerigo Wang <amwang@redhat.com>2012-09-18 12:50:08 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-19 17:23:28 -0400
commitc038a767cd697238b09f7a4ea5a504b4891774e9 (patch)
treec6cbe9f5b641a7f5cc4e1fb520724b77682e9810 /net/ipv6
parent8c4c49df5cfeb8d56e5b85a430c8cbcb86c2ac37 (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.c137
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
73static struct inet_frags nf_frags; 73static struct inet_frags nf_frags;
74static struct netns_frags nf_init_frags;
75 74
76#ifdef CONFIG_SYSCTL 75#ifdef CONFIG_SYSCTL
77static struct ctl_table nf_ct_frag6_sysctl_table[] = { 76static 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
102static struct ctl_table_header *nf_ct_frag6_sysctl_header; 101static 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
125err_reg:
126 if (!net_eq(net, &init_net))
127 kfree(table);
128err_alloc:
129 return -ENOMEM;
130}
131
132static 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
143static int __net_init nf_ct_frag6_sysctl_register(struct net *net)
144{
145 return 0;
146}
147static void __net_exit nf_ct_frags6_sysctl_unregister(struct net *net)
148{
149}
103#endif 150#endif
104 151
105static unsigned int nf_hashfn(struct inet_frag_queue *q) 152static 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
134static 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
141static void nf_ct_frag6_expire(unsigned long data) 181static 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 201static inline struct nf_ct_frag6_queue *fq_find(struct net *net, __be32 id,
162static __inline__ struct nf_ct_frag6_queue * 202 u32 user, struct in6_addr *src,
163fq_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
669static 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
679static 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
685static struct pernet_operations nf_ct_net_ops = {
686 .init = nf_ct_net_init,
687 .exit = nf_ct_net_exit,
688};
689
624int nf_ct_frag6_init(void) 690int 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
652void nf_ct_frag6_cleanup(void) 711void 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}