aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/inet_hashtables.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/inet_hashtables.c')
-rw-r--r--net/ipv4/inet_hashtables.c69
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 */
30struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, 30struct 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 */
128static struct sock *inet_lookup_listener_slow(const struct hlist_head *head, 130static 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. */
166struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo, 170struct 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) {
186sherry_cache: 191sherry_cache:
@@ -191,7 +196,8 @@ sherry_cache:
191} 196}
192EXPORT_SYMBOL_GPL(__inet_lookup_listener); 197EXPORT_SYMBOL_GPL(__inet_lookup_listener);
193 198
194struct sock * __inet_lookup_established(struct inet_hashinfo *hashinfo, 199struct 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}
349EXPORT_SYMBOL_GPL(__inet_hash); 360EXPORT_SYMBOL_GPL(__inet_hash);
350 361
351/* 362int __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 *,
354int 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);
442out: 454out:
443 local_bh_enable(); 455 local_bh_enable();
444 return ret; 456 return ret;
445 } 457 }
446} 458}
459EXPORT_SYMBOL_GPL(__inet_hash_connect);
460
461/*
462 * Bind a port for a connect operation and hash it.
463 */
464int 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
448EXPORT_SYMBOL_GPL(inet_hash_connect); 471EXPORT_SYMBOL_GPL(inet_hash_connect);