diff options
Diffstat (limited to 'net/ipv4/inet_hashtables.c')
-rw-r--r-- | net/ipv4/inet_hashtables.c | 69 |
1 files changed, 46 insertions, 23 deletions
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 619c63c6948a..48d45008f749 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c | |||
@@ -28,12 +28,14 @@ | |||
28 | * The bindhash mutex for snum's hash chain must be held here. | 28 | * The bindhash mutex for snum's hash chain must be held here. |
29 | */ | 29 | */ |
30 | struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, | 30 | struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, |
31 | struct net *net, | ||
31 | struct inet_bind_hashbucket *head, | 32 | struct inet_bind_hashbucket *head, |
32 | const unsigned short snum) | 33 | const unsigned short snum) |
33 | { | 34 | { |
34 | struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC); | 35 | struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC); |
35 | 36 | ||
36 | if (tb != NULL) { | 37 | if (tb != NULL) { |
38 | tb->ib_net = net; | ||
37 | tb->port = snum; | 39 | tb->port = snum; |
38 | tb->fastreuse = 0; | 40 | tb->fastreuse = 0; |
39 | INIT_HLIST_HEAD(&tb->owners); | 41 | INIT_HLIST_HEAD(&tb->owners); |
@@ -125,7 +127,8 @@ EXPORT_SYMBOL(inet_listen_wlock); | |||
125 | * remote address for the connection. So always assume those are both | 127 | * remote address for the connection. So always assume those are both |
126 | * wildcarded during the search since they can never be otherwise. | 128 | * wildcarded during the search since they can never be otherwise. |
127 | */ | 129 | */ |
128 | static struct sock *inet_lookup_listener_slow(const struct hlist_head *head, | 130 | static struct sock *inet_lookup_listener_slow(struct net *net, |
131 | const struct hlist_head *head, | ||
129 | const __be32 daddr, | 132 | const __be32 daddr, |
130 | const unsigned short hnum, | 133 | const unsigned short hnum, |
131 | const int dif) | 134 | const int dif) |
@@ -137,7 +140,8 @@ static struct sock *inet_lookup_listener_slow(const struct hlist_head *head, | |||
137 | sk_for_each(sk, node, head) { | 140 | sk_for_each(sk, node, head) { |
138 | const struct inet_sock *inet = inet_sk(sk); | 141 | const struct inet_sock *inet = inet_sk(sk); |
139 | 142 | ||
140 | if (inet->num == hnum && !ipv6_only_sock(sk)) { | 143 | if (sk->sk_net == net && inet->num == hnum && |
144 | !ipv6_only_sock(sk)) { | ||
141 | const __be32 rcv_saddr = inet->rcv_saddr; | 145 | const __be32 rcv_saddr = inet->rcv_saddr; |
142 | int score = sk->sk_family == PF_INET ? 1 : 0; | 146 | int score = sk->sk_family == PF_INET ? 1 : 0; |
143 | 147 | ||
@@ -163,7 +167,8 @@ static struct sock *inet_lookup_listener_slow(const struct hlist_head *head, | |||
163 | } | 167 | } |
164 | 168 | ||
165 | /* Optimize the common listener case. */ | 169 | /* Optimize the common listener case. */ |
166 | struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo, | 170 | struct sock *__inet_lookup_listener(struct net *net, |
171 | struct inet_hashinfo *hashinfo, | ||
167 | const __be32 daddr, const unsigned short hnum, | 172 | const __be32 daddr, const unsigned short hnum, |
168 | const int dif) | 173 | const int dif) |
169 | { | 174 | { |
@@ -178,9 +183,9 @@ struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo, | |||
178 | if (inet->num == hnum && !sk->sk_node.next && | 183 | if (inet->num == hnum && !sk->sk_node.next && |
179 | (!inet->rcv_saddr || inet->rcv_saddr == daddr) && | 184 | (!inet->rcv_saddr || inet->rcv_saddr == daddr) && |
180 | (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && | 185 | (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && |
181 | !sk->sk_bound_dev_if) | 186 | !sk->sk_bound_dev_if && sk->sk_net == net) |
182 | goto sherry_cache; | 187 | goto sherry_cache; |
183 | sk = inet_lookup_listener_slow(head, daddr, hnum, dif); | 188 | sk = inet_lookup_listener_slow(net, head, daddr, hnum, dif); |
184 | } | 189 | } |
185 | if (sk) { | 190 | if (sk) { |
186 | sherry_cache: | 191 | sherry_cache: |
@@ -191,7 +196,8 @@ sherry_cache: | |||
191 | } | 196 | } |
192 | EXPORT_SYMBOL_GPL(__inet_lookup_listener); | 197 | EXPORT_SYMBOL_GPL(__inet_lookup_listener); |
193 | 198 | ||
194 | struct sock * __inet_lookup_established(struct inet_hashinfo *hashinfo, | 199 | struct sock * __inet_lookup_established(struct net *net, |
200 | struct inet_hashinfo *hashinfo, | ||
195 | const __be32 saddr, const __be16 sport, | 201 | const __be32 saddr, const __be16 sport, |
196 | const __be32 daddr, const u16 hnum, | 202 | const __be32 daddr, const u16 hnum, |
197 | const int dif) | 203 | const int dif) |
@@ -210,13 +216,15 @@ struct sock * __inet_lookup_established(struct inet_hashinfo *hashinfo, | |||
210 | prefetch(head->chain.first); | 216 | prefetch(head->chain.first); |
211 | read_lock(lock); | 217 | read_lock(lock); |
212 | sk_for_each(sk, node, &head->chain) { | 218 | sk_for_each(sk, node, &head->chain) { |
213 | if (INET_MATCH(sk, hash, acookie, saddr, daddr, ports, dif)) | 219 | if (INET_MATCH(sk, net, hash, acookie, |
220 | saddr, daddr, ports, dif)) | ||
214 | goto hit; /* You sunk my battleship! */ | 221 | goto hit; /* You sunk my battleship! */ |
215 | } | 222 | } |
216 | 223 | ||
217 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | 224 | /* Must check for a TIME_WAIT'er before going to listener hash. */ |
218 | sk_for_each(sk, node, &head->twchain) { | 225 | sk_for_each(sk, node, &head->twchain) { |
219 | if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif)) | 226 | if (INET_TW_MATCH(sk, net, hash, acookie, |
227 | saddr, daddr, ports, dif)) | ||
220 | goto hit; | 228 | goto hit; |
221 | } | 229 | } |
222 | sk = NULL; | 230 | sk = NULL; |
@@ -247,6 +255,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, | |||
247 | struct sock *sk2; | 255 | struct sock *sk2; |
248 | const struct hlist_node *node; | 256 | const struct hlist_node *node; |
249 | struct inet_timewait_sock *tw; | 257 | struct inet_timewait_sock *tw; |
258 | struct net *net = sk->sk_net; | ||
250 | 259 | ||
251 | prefetch(head->chain.first); | 260 | prefetch(head->chain.first); |
252 | write_lock(lock); | 261 | write_lock(lock); |
@@ -255,7 +264,8 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, | |||
255 | sk_for_each(sk2, node, &head->twchain) { | 264 | sk_for_each(sk2, node, &head->twchain) { |
256 | tw = inet_twsk(sk2); | 265 | tw = inet_twsk(sk2); |
257 | 266 | ||
258 | if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) { | 267 | if (INET_TW_MATCH(sk2, net, hash, acookie, |
268 | saddr, daddr, ports, dif)) { | ||
259 | if (twsk_unique(sk, sk2, twp)) | 269 | if (twsk_unique(sk, sk2, twp)) |
260 | goto unique; | 270 | goto unique; |
261 | else | 271 | else |
@@ -266,7 +276,8 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, | |||
266 | 276 | ||
267 | /* And established part... */ | 277 | /* And established part... */ |
268 | sk_for_each(sk2, node, &head->chain) { | 278 | sk_for_each(sk2, node, &head->chain) { |
269 | if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) | 279 | if (INET_MATCH(sk2, net, hash, acookie, |
280 | saddr, daddr, ports, dif)) | ||
270 | goto not_unique; | 281 | goto not_unique; |
271 | } | 282 | } |
272 | 283 | ||
@@ -348,17 +359,18 @@ void __inet_hash(struct inet_hashinfo *hashinfo, struct sock *sk) | |||
348 | } | 359 | } |
349 | EXPORT_SYMBOL_GPL(__inet_hash); | 360 | EXPORT_SYMBOL_GPL(__inet_hash); |
350 | 361 | ||
351 | /* | 362 | int __inet_hash_connect(struct inet_timewait_death_row *death_row, |
352 | * Bind a port for a connect operation and hash it. | 363 | struct sock *sk, |
353 | */ | 364 | int (*check_established)(struct inet_timewait_death_row *, |
354 | int inet_hash_connect(struct inet_timewait_death_row *death_row, | 365 | struct sock *, __u16, struct inet_timewait_sock **), |
355 | struct sock *sk) | 366 | void (*hash)(struct inet_hashinfo *, struct sock *)) |
356 | { | 367 | { |
357 | struct inet_hashinfo *hinfo = death_row->hashinfo; | 368 | struct inet_hashinfo *hinfo = death_row->hashinfo; |
358 | const unsigned short snum = inet_sk(sk)->num; | 369 | const unsigned short snum = inet_sk(sk)->num; |
359 | struct inet_bind_hashbucket *head; | 370 | struct inet_bind_hashbucket *head; |
360 | struct inet_bind_bucket *tb; | 371 | struct inet_bind_bucket *tb; |
361 | int ret; | 372 | int ret; |
373 | struct net *net = sk->sk_net; | ||
362 | 374 | ||
363 | if (!snum) { | 375 | if (!snum) { |
364 | int i, remaining, low, high, port; | 376 | int i, remaining, low, high, port; |
@@ -381,19 +393,19 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row, | |||
381 | * unique enough. | 393 | * unique enough. |
382 | */ | 394 | */ |
383 | inet_bind_bucket_for_each(tb, node, &head->chain) { | 395 | inet_bind_bucket_for_each(tb, node, &head->chain) { |
384 | if (tb->port == port) { | 396 | if (tb->ib_net == net && tb->port == port) { |
385 | BUG_TRAP(!hlist_empty(&tb->owners)); | 397 | BUG_TRAP(!hlist_empty(&tb->owners)); |
386 | if (tb->fastreuse >= 0) | 398 | if (tb->fastreuse >= 0) |
387 | goto next_port; | 399 | goto next_port; |
388 | if (!__inet_check_established(death_row, | 400 | if (!check_established(death_row, sk, |
389 | sk, port, | 401 | port, &tw)) |
390 | &tw)) | ||
391 | goto ok; | 402 | goto ok; |
392 | goto next_port; | 403 | goto next_port; |
393 | } | 404 | } |
394 | } | 405 | } |
395 | 406 | ||
396 | tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, head, port); | 407 | tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, |
408 | net, head, port); | ||
397 | if (!tb) { | 409 | if (!tb) { |
398 | spin_unlock(&head->lock); | 410 | spin_unlock(&head->lock); |
399 | break; | 411 | break; |
@@ -415,7 +427,7 @@ ok: | |||
415 | inet_bind_hash(sk, tb, port); | 427 | inet_bind_hash(sk, tb, port); |
416 | if (sk_unhashed(sk)) { | 428 | if (sk_unhashed(sk)) { |
417 | inet_sk(sk)->sport = htons(port); | 429 | inet_sk(sk)->sport = htons(port); |
418 | __inet_hash_nolisten(hinfo, sk); | 430 | hash(hinfo, sk); |
419 | } | 431 | } |
420 | spin_unlock(&head->lock); | 432 | spin_unlock(&head->lock); |
421 | 433 | ||
@@ -432,17 +444,28 @@ ok: | |||
432 | tb = inet_csk(sk)->icsk_bind_hash; | 444 | tb = inet_csk(sk)->icsk_bind_hash; |
433 | spin_lock_bh(&head->lock); | 445 | spin_lock_bh(&head->lock); |
434 | if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { | 446 | if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { |
435 | __inet_hash_nolisten(hinfo, sk); | 447 | hash(hinfo, sk); |
436 | spin_unlock_bh(&head->lock); | 448 | spin_unlock_bh(&head->lock); |
437 | return 0; | 449 | return 0; |
438 | } else { | 450 | } else { |
439 | spin_unlock(&head->lock); | 451 | spin_unlock(&head->lock); |
440 | /* No definite answer... Walk to established hash table */ | 452 | /* No definite answer... Walk to established hash table */ |
441 | ret = __inet_check_established(death_row, sk, snum, NULL); | 453 | ret = check_established(death_row, sk, snum, NULL); |
442 | out: | 454 | out: |
443 | local_bh_enable(); | 455 | local_bh_enable(); |
444 | return ret; | 456 | return ret; |
445 | } | 457 | } |
446 | } | 458 | } |
459 | EXPORT_SYMBOL_GPL(__inet_hash_connect); | ||
460 | |||
461 | /* | ||
462 | * Bind a port for a connect operation and hash it. | ||
463 | */ | ||
464 | int inet_hash_connect(struct inet_timewait_death_row *death_row, | ||
465 | struct sock *sk) | ||
466 | { | ||
467 | return __inet_hash_connect(death_row, sk, | ||
468 | __inet_check_established, __inet_hash_nolisten); | ||
469 | } | ||
447 | 470 | ||
448 | EXPORT_SYMBOL_GPL(inet_hash_connect); | 471 | EXPORT_SYMBOL_GPL(inet_hash_connect); |