aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_flowlabel.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_flowlabel.c')
-rw-r--r--net/ipv6/ip6_flowlabel.c101
1 files changed, 74 insertions, 27 deletions
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 2b7d9ee98832..eb7a940310f4 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -62,23 +62,23 @@ static DEFINE_RWLOCK(ip6_fl_lock);
62static DEFINE_RWLOCK(ip6_sk_fl_lock); 62static DEFINE_RWLOCK(ip6_sk_fl_lock);
63 63
64 64
65static __inline__ struct ip6_flowlabel * __fl_lookup(__be32 label) 65static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label)
66{ 66{
67 struct ip6_flowlabel *fl; 67 struct ip6_flowlabel *fl;
68 68
69 for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) { 69 for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) {
70 if (fl->label == label) 70 if (fl->label == label && fl->fl_net == net)
71 return fl; 71 return fl;
72 } 72 }
73 return NULL; 73 return NULL;
74} 74}
75 75
76static struct ip6_flowlabel * fl_lookup(__be32 label) 76static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label)
77{ 77{
78 struct ip6_flowlabel *fl; 78 struct ip6_flowlabel *fl;
79 79
80 read_lock_bh(&ip6_fl_lock); 80 read_lock_bh(&ip6_fl_lock);
81 fl = __fl_lookup(label); 81 fl = __fl_lookup(net, label);
82 if (fl) 82 if (fl)
83 atomic_inc(&fl->users); 83 atomic_inc(&fl->users);
84 read_unlock_bh(&ip6_fl_lock); 84 read_unlock_bh(&ip6_fl_lock);
@@ -88,8 +88,10 @@ static struct ip6_flowlabel * fl_lookup(__be32 label)
88 88
89static void fl_free(struct ip6_flowlabel *fl) 89static void fl_free(struct ip6_flowlabel *fl)
90{ 90{
91 if (fl) 91 if (fl) {
92 release_net(fl->fl_net);
92 kfree(fl->opt); 93 kfree(fl->opt);
94 }
93 kfree(fl); 95 kfree(fl);
94} 96}
95 97
@@ -112,7 +114,6 @@ static void fl_release(struct ip6_flowlabel *fl)
112 time_after(ip6_fl_gc_timer.expires, ttd)) 114 time_after(ip6_fl_gc_timer.expires, ttd))
113 mod_timer(&ip6_fl_gc_timer, ttd); 115 mod_timer(&ip6_fl_gc_timer, ttd);
114 } 116 }
115
116 write_unlock_bh(&ip6_fl_lock); 117 write_unlock_bh(&ip6_fl_lock);
117} 118}
118 119
@@ -148,13 +149,34 @@ static void ip6_fl_gc(unsigned long dummy)
148 if (!sched && atomic_read(&fl_size)) 149 if (!sched && atomic_read(&fl_size))
149 sched = now + FL_MAX_LINGER; 150 sched = now + FL_MAX_LINGER;
150 if (sched) { 151 if (sched) {
151 ip6_fl_gc_timer.expires = sched; 152 mod_timer(&ip6_fl_gc_timer, sched);
152 add_timer(&ip6_fl_gc_timer); 153 }
154 write_unlock(&ip6_fl_lock);
155}
156
157static void ip6_fl_purge(struct net *net)
158{
159 int i;
160
161 write_lock(&ip6_fl_lock);
162 for (i = 0; i <= FL_HASH_MASK; i++) {
163 struct ip6_flowlabel *fl, **flp;
164 flp = &fl_ht[i];
165 while ((fl = *flp) != NULL) {
166 if (fl->fl_net == net && atomic_read(&fl->users) == 0) {
167 *flp = fl->next;
168 fl_free(fl);
169 atomic_dec(&fl_size);
170 continue;
171 }
172 flp = &fl->next;
173 }
153 } 174 }
154 write_unlock(&ip6_fl_lock); 175 write_unlock(&ip6_fl_lock);
155} 176}
156 177
157static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label) 178static struct ip6_flowlabel *fl_intern(struct net *net,
179 struct ip6_flowlabel *fl, __be32 label)
158{ 180{
159 struct ip6_flowlabel *lfl; 181 struct ip6_flowlabel *lfl;
160 182
@@ -165,7 +187,7 @@ static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label)
165 for (;;) { 187 for (;;) {
166 fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; 188 fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK;
167 if (fl->label) { 189 if (fl->label) {
168 lfl = __fl_lookup(fl->label); 190 lfl = __fl_lookup(net, fl->label);
169 if (lfl == NULL) 191 if (lfl == NULL)
170 break; 192 break;
171 } 193 }
@@ -179,7 +201,7 @@ static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label)
179 * done in ipv6_flowlabel_opt - sock is locked, so new entry 201 * done in ipv6_flowlabel_opt - sock is locked, so new entry
180 * with the same label can only appear on another sock 202 * with the same label can only appear on another sock
181 */ 203 */
182 lfl = __fl_lookup(fl->label); 204 lfl = __fl_lookup(net, fl->label);
183 if (lfl != NULL) { 205 if (lfl != NULL) {
184 atomic_inc(&lfl->users); 206 atomic_inc(&lfl->users);
185 write_unlock_bh(&ip6_fl_lock); 207 write_unlock_bh(&ip6_fl_lock);
@@ -298,7 +320,8 @@ static int fl6_renew(struct ip6_flowlabel *fl, unsigned long linger, unsigned lo
298} 320}
299 321
300static struct ip6_flowlabel * 322static struct ip6_flowlabel *
301fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *err_p) 323fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval,
324 int optlen, int *err_p)
302{ 325{
303 struct ip6_flowlabel *fl; 326 struct ip6_flowlabel *fl;
304 int olen; 327 int olen;
@@ -343,6 +366,7 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *
343 } 366 }
344 } 367 }
345 368
369 fl->fl_net = hold_net(net);
346 fl->expires = jiffies; 370 fl->expires = jiffies;
347 err = fl6_renew(fl, freq->flr_linger, freq->flr_expires); 371 err = fl6_renew(fl, freq->flr_linger, freq->flr_expires);
348 if (err) 372 if (err)
@@ -441,6 +465,7 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl,
441int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) 465int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
442{ 466{
443 int err; 467 int err;
468 struct net *net = sock_net(sk);
444 struct ipv6_pinfo *np = inet6_sk(sk); 469 struct ipv6_pinfo *np = inet6_sk(sk);
445 struct in6_flowlabel_req freq; 470 struct in6_flowlabel_req freq;
446 struct ipv6_fl_socklist *sfl1=NULL; 471 struct ipv6_fl_socklist *sfl1=NULL;
@@ -483,7 +508,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
483 read_unlock_bh(&ip6_sk_fl_lock); 508 read_unlock_bh(&ip6_sk_fl_lock);
484 509
485 if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) { 510 if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) {
486 fl = fl_lookup(freq.flr_label); 511 fl = fl_lookup(net, freq.flr_label);
487 if (fl) { 512 if (fl) {
488 err = fl6_renew(fl, freq.flr_linger, freq.flr_expires); 513 err = fl6_renew(fl, freq.flr_linger, freq.flr_expires);
489 fl_release(fl); 514 fl_release(fl);
@@ -496,7 +521,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
496 if (freq.flr_label & ~IPV6_FLOWLABEL_MASK) 521 if (freq.flr_label & ~IPV6_FLOWLABEL_MASK)
497 return -EINVAL; 522 return -EINVAL;
498 523
499 fl = fl_create(&freq, optval, optlen, &err); 524 fl = fl_create(net, &freq, optval, optlen, &err);
500 if (fl == NULL) 525 if (fl == NULL)
501 return err; 526 return err;
502 sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL); 527 sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL);
@@ -518,7 +543,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
518 read_unlock_bh(&ip6_sk_fl_lock); 543 read_unlock_bh(&ip6_sk_fl_lock);
519 544
520 if (fl1 == NULL) 545 if (fl1 == NULL)
521 fl1 = fl_lookup(freq.flr_label); 546 fl1 = fl_lookup(net, freq.flr_label);
522 if (fl1) { 547 if (fl1) {
523recheck: 548recheck:
524 err = -EEXIST; 549 err = -EEXIST;
@@ -559,7 +584,7 @@ release:
559 if (sfl1 == NULL || (err = mem_check(sk)) != 0) 584 if (sfl1 == NULL || (err = mem_check(sk)) != 0)
560 goto done; 585 goto done;
561 586
562 fl1 = fl_intern(fl, freq.flr_label); 587 fl1 = fl_intern(net, fl, freq.flr_label);
563 if (fl1 != NULL) 588 if (fl1 != NULL)
564 goto recheck; 589 goto recheck;
565 590
@@ -586,6 +611,7 @@ done:
586#ifdef CONFIG_PROC_FS 611#ifdef CONFIG_PROC_FS
587 612
588struct ip6fl_iter_state { 613struct ip6fl_iter_state {
614 struct seq_net_private p;
589 int bucket; 615 int bucket;
590}; 616};
591 617
@@ -595,12 +621,15 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq)
595{ 621{
596 struct ip6_flowlabel *fl = NULL; 622 struct ip6_flowlabel *fl = NULL;
597 struct ip6fl_iter_state *state = ip6fl_seq_private(seq); 623 struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
624 struct net *net = seq_file_net(seq);
598 625
599 for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { 626 for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) {
600 if (fl_ht[state->bucket]) { 627 fl = fl_ht[state->bucket];
601 fl = fl_ht[state->bucket]; 628
629 while (fl && fl->fl_net != net)
630 fl = fl->next;
631 if (fl)
602 break; 632 break;
603 }
604 } 633 }
605 return fl; 634 return fl;
606} 635}
@@ -608,12 +637,18 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq)
608static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flowlabel *fl) 637static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flowlabel *fl)
609{ 638{
610 struct ip6fl_iter_state *state = ip6fl_seq_private(seq); 639 struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
640 struct net *net = seq_file_net(seq);
611 641
612 fl = fl->next; 642 fl = fl->next;
643try_again:
644 while (fl && fl->fl_net != net)
645 fl = fl->next;
646
613 while (!fl) { 647 while (!fl) {
614 if (++state->bucket <= FL_HASH_MASK) 648 if (++state->bucket <= FL_HASH_MASK) {
615 fl = fl_ht[state->bucket]; 649 fl = fl_ht[state->bucket];
616 else 650 goto try_again;
651 } else
617 break; 652 break;
618 } 653 }
619 return fl; 654 return fl;
@@ -683,8 +718,8 @@ static const struct seq_operations ip6fl_seq_ops = {
683 718
684static int ip6fl_seq_open(struct inode *inode, struct file *file) 719static int ip6fl_seq_open(struct inode *inode, struct file *file)
685{ 720{
686 return seq_open_private(file, &ip6fl_seq_ops, 721 return seq_open_net(inode, file, &ip6fl_seq_ops,
687 sizeof(struct ip6fl_iter_state)); 722 sizeof(struct ip6fl_iter_state));
688} 723}
689 724
690static const struct file_operations ip6fl_seq_fops = { 725static const struct file_operations ip6fl_seq_fops = {
@@ -692,12 +727,13 @@ static const struct file_operations ip6fl_seq_fops = {
692 .open = ip6fl_seq_open, 727 .open = ip6fl_seq_open,
693 .read = seq_read, 728 .read = seq_read,
694 .llseek = seq_lseek, 729 .llseek = seq_lseek,
695 .release = seq_release_private, 730 .release = seq_release_net,
696}; 731};
697 732
698static int ip6_flowlabel_proc_init(struct net *net) 733static int ip6_flowlabel_proc_init(struct net *net)
699{ 734{
700 if (!proc_net_fops_create(net, "ip6_flowlabel", S_IRUGO, &ip6fl_seq_fops)) 735 if (!proc_net_fops_create(net, "ip6_flowlabel",
736 S_IRUGO, &ip6fl_seq_fops))
701 return -ENOMEM; 737 return -ENOMEM;
702 return 0; 738 return 0;
703} 739}
@@ -717,13 +753,24 @@ static inline void ip6_flowlabel_proc_fini(struct net *net)
717} 753}
718#endif 754#endif
719 755
756static inline void ip6_flowlabel_net_exit(struct net *net)
757{
758 ip6_fl_purge(net);
759 ip6_flowlabel_proc_fini(net);
760}
761
762static struct pernet_operations ip6_flowlabel_net_ops = {
763 .init = ip6_flowlabel_proc_init,
764 .exit = ip6_flowlabel_net_exit,
765};
766
720int ip6_flowlabel_init(void) 767int ip6_flowlabel_init(void)
721{ 768{
722 return ip6_flowlabel_proc_init(&init_net); 769 return register_pernet_subsys(&ip6_flowlabel_net_ops);
723} 770}
724 771
725void ip6_flowlabel_cleanup(void) 772void ip6_flowlabel_cleanup(void)
726{ 773{
727 del_timer(&ip6_fl_gc_timer); 774 del_timer(&ip6_fl_gc_timer);
728 ip6_flowlabel_proc_fini(&init_net); 775 unregister_pernet_subsys(&ip6_flowlabel_net_ops);
729} 776}