diff options
Diffstat (limited to 'net/ipv6/ip6_flowlabel.c')
-rw-r--r-- | net/ipv6/ip6_flowlabel.c | 72 |
1 files changed, 56 insertions, 16 deletions
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 2b7d9ee9883..78d1d913e36 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -62,23 +62,23 @@ static DEFINE_RWLOCK(ip6_fl_lock); | |||
62 | static DEFINE_RWLOCK(ip6_sk_fl_lock); | 62 | static DEFINE_RWLOCK(ip6_sk_fl_lock); |
63 | 63 | ||
64 | 64 | ||
65 | static __inline__ struct ip6_flowlabel * __fl_lookup(__be32 label) | 65 | static 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 | ||
76 | static struct ip6_flowlabel * fl_lookup(__be32 label) | 76 | static 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 | ||
89 | static void fl_free(struct ip6_flowlabel *fl) | 89 | static 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 | } | 153 | } |
154 | write_unlock(&ip6_fl_lock); | 154 | write_unlock(&ip6_fl_lock); |
155 | } | 155 | } |
156 | 156 | ||
157 | static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label) | 157 | static 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 | } | ||
174 | } | ||
175 | write_unlock(&ip6_fl_lock); | ||
176 | } | ||
177 | |||
178 | static 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 | ||
300 | static struct ip6_flowlabel * | 322 | static struct ip6_flowlabel * |
301 | fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *err_p) | 323 | fl_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, | |||
441 | int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) | 465 | int 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) { |
523 | recheck: | 548 | recheck: |
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 | ||
@@ -717,13 +742,28 @@ static inline void ip6_flowlabel_proc_fini(struct net *net) | |||
717 | } | 742 | } |
718 | #endif | 743 | #endif |
719 | 744 | ||
745 | static inline void ip6_flowlabel_net_exit(struct net *net) | ||
746 | { | ||
747 | ip6_fl_purge(net); | ||
748 | } | ||
749 | |||
750 | static struct pernet_operations ip6_flowlabel_net_ops = { | ||
751 | .exit = ip6_flowlabel_net_exit, | ||
752 | }; | ||
753 | |||
720 | int ip6_flowlabel_init(void) | 754 | int ip6_flowlabel_init(void) |
721 | { | 755 | { |
756 | int err; | ||
757 | |||
758 | err = register_pernet_subsys(&ip6_flowlabel_net_ops); | ||
759 | if (err) | ||
760 | return err; | ||
722 | return ip6_flowlabel_proc_init(&init_net); | 761 | return ip6_flowlabel_proc_init(&init_net); |
723 | } | 762 | } |
724 | 763 | ||
725 | void ip6_flowlabel_cleanup(void) | 764 | void ip6_flowlabel_cleanup(void) |
726 | { | 765 | { |
727 | del_timer(&ip6_fl_gc_timer); | 766 | del_timer(&ip6_fl_gc_timer); |
767 | unregister_pernet_subsys(&ip6_flowlabel_net_ops); | ||
728 | ip6_flowlabel_proc_fini(&init_net); | 768 | ip6_flowlabel_proc_fini(&init_net); |
729 | } | 769 | } |