diff options
Diffstat (limited to 'include/net/inet_hashtables.h')
-rw-r--r-- | include/net/inet_hashtables.h | 68 |
1 files changed, 39 insertions, 29 deletions
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 646b6ea7fe26..07840baa9341 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h | |||
@@ -40,7 +40,7 @@ | |||
40 | struct inet_ehash_bucket { | 40 | struct inet_ehash_bucket { |
41 | rwlock_t lock; | 41 | rwlock_t lock; |
42 | struct hlist_head chain; | 42 | struct hlist_head chain; |
43 | } __attribute__((__aligned__(8))); | 43 | }; |
44 | 44 | ||
45 | /* There are a few simple rules, which allow for local port reuse by | 45 | /* There are a few simple rules, which allow for local port reuse by |
46 | * an application. In essence: | 46 | * an application. In essence: |
@@ -108,7 +108,7 @@ struct inet_hashinfo { | |||
108 | struct inet_bind_hashbucket *bhash; | 108 | struct inet_bind_hashbucket *bhash; |
109 | 109 | ||
110 | int bhash_size; | 110 | int bhash_size; |
111 | int ehash_size; | 111 | unsigned int ehash_size; |
112 | 112 | ||
113 | /* All sockets in TCP_LISTEN state will be in here. This is the only | 113 | /* All sockets in TCP_LISTEN state will be in here. This is the only |
114 | * table where wildcard'd TCP sockets can exist. Hash function here | 114 | * table where wildcard'd TCP sockets can exist. Hash function here |
@@ -125,22 +125,19 @@ struct inet_hashinfo { | |||
125 | rwlock_t lhash_lock ____cacheline_aligned; | 125 | rwlock_t lhash_lock ____cacheline_aligned; |
126 | atomic_t lhash_users; | 126 | atomic_t lhash_users; |
127 | wait_queue_head_t lhash_wait; | 127 | wait_queue_head_t lhash_wait; |
128 | spinlock_t portalloc_lock; | ||
129 | kmem_cache_t *bind_bucket_cachep; | 128 | kmem_cache_t *bind_bucket_cachep; |
130 | int port_rover; | ||
131 | }; | 129 | }; |
132 | 130 | ||
133 | static inline int inet_ehashfn(const __u32 laddr, const __u16 lport, | 131 | static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport, |
134 | const __u32 faddr, const __u16 fport, | 132 | const __u32 faddr, const __u16 fport) |
135 | const int ehash_size) | ||
136 | { | 133 | { |
137 | int h = (laddr ^ lport) ^ (faddr ^ fport); | 134 | unsigned int h = (laddr ^ lport) ^ (faddr ^ fport); |
138 | h ^= h >> 16; | 135 | h ^= h >> 16; |
139 | h ^= h >> 8; | 136 | h ^= h >> 8; |
140 | return h & (ehash_size - 1); | 137 | return h; |
141 | } | 138 | } |
142 | 139 | ||
143 | static inline int inet_sk_ehashfn(const struct sock *sk, const int ehash_size) | 140 | static inline int inet_sk_ehashfn(const struct sock *sk) |
144 | { | 141 | { |
145 | const struct inet_sock *inet = inet_sk(sk); | 142 | const struct inet_sock *inet = inet_sk(sk); |
146 | const __u32 laddr = inet->rcv_saddr; | 143 | const __u32 laddr = inet->rcv_saddr; |
@@ -148,7 +145,14 @@ static inline int inet_sk_ehashfn(const struct sock *sk, const int ehash_size) | |||
148 | const __u32 faddr = inet->daddr; | 145 | const __u32 faddr = inet->daddr; |
149 | const __u16 fport = inet->dport; | 146 | const __u16 fport = inet->dport; |
150 | 147 | ||
151 | return inet_ehashfn(laddr, lport, faddr, fport, ehash_size); | 148 | return inet_ehashfn(laddr, lport, faddr, fport); |
149 | } | ||
150 | |||
151 | static inline struct inet_ehash_bucket *inet_ehash_bucket( | ||
152 | struct inet_hashinfo *hashinfo, | ||
153 | unsigned int hash) | ||
154 | { | ||
155 | return &hashinfo->ehash[hash & (hashinfo->ehash_size - 1)]; | ||
152 | } | 156 | } |
153 | 157 | ||
154 | extern struct inet_bind_bucket * | 158 | extern struct inet_bind_bucket * |
@@ -235,9 +239,11 @@ static inline void __inet_hash(struct inet_hashinfo *hashinfo, | |||
235 | lock = &hashinfo->lhash_lock; | 239 | lock = &hashinfo->lhash_lock; |
236 | inet_listen_wlock(hashinfo); | 240 | inet_listen_wlock(hashinfo); |
237 | } else { | 241 | } else { |
238 | sk->sk_hashent = inet_sk_ehashfn(sk, hashinfo->ehash_size); | 242 | struct inet_ehash_bucket *head; |
239 | list = &hashinfo->ehash[sk->sk_hashent].chain; | 243 | sk->sk_hash = inet_sk_ehashfn(sk); |
240 | lock = &hashinfo->ehash[sk->sk_hashent].lock; | 244 | head = inet_ehash_bucket(hashinfo, sk->sk_hash); |
245 | list = &head->chain; | ||
246 | lock = &head->lock; | ||
241 | write_lock(lock); | 247 | write_lock(lock); |
242 | } | 248 | } |
243 | __sk_add_node(sk, list); | 249 | __sk_add_node(sk, list); |
@@ -268,9 +274,8 @@ static inline void inet_unhash(struct inet_hashinfo *hashinfo, struct sock *sk) | |||
268 | inet_listen_wlock(hashinfo); | 274 | inet_listen_wlock(hashinfo); |
269 | lock = &hashinfo->lhash_lock; | 275 | lock = &hashinfo->lhash_lock; |
270 | } else { | 276 | } else { |
271 | struct inet_ehash_bucket *head = &hashinfo->ehash[sk->sk_hashent]; | 277 | lock = &inet_ehash_bucket(hashinfo, sk->sk_hash)->lock; |
272 | lock = &head->lock; | 278 | write_lock_bh(lock); |
273 | write_lock_bh(&head->lock); | ||
274 | } | 279 | } |
275 | 280 | ||
276 | if (__sk_del_node_init(sk)) | 281 | if (__sk_del_node_init(sk)) |
@@ -337,23 +342,27 @@ sherry_cache: | |||
337 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ | 342 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ |
338 | const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr)); | 343 | const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr)); |
339 | #endif /* __BIG_ENDIAN */ | 344 | #endif /* __BIG_ENDIAN */ |
340 | #define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ | 345 | #define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ |
341 | (((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ | 346 | (((__sk)->sk_hash == (__hash)) && \ |
347 | ((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ | ||
342 | ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ | 348 | ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ |
343 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) | 349 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) |
344 | #define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ | 350 | #define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ |
345 | (((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ | 351 | (((__sk)->sk_hash == (__hash)) && \ |
352 | ((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ | ||
346 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ | 353 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ |
347 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) | 354 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) |
348 | #else /* 32-bit arch */ | 355 | #else /* 32-bit arch */ |
349 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) | 356 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) |
350 | #define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif) \ | 357 | #define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ |
351 | ((inet_sk(__sk)->daddr == (__saddr)) && \ | 358 | (((__sk)->sk_hash == (__hash)) && \ |
359 | (inet_sk(__sk)->daddr == (__saddr)) && \ | ||
352 | (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ | 360 | (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ |
353 | ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ | 361 | ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ |
354 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) | 362 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) |
355 | #define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif) \ | 363 | #define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ |
356 | ((inet_twsk(__sk)->tw_daddr == (__saddr)) && \ | 364 | (((__sk)->sk_hash == (__hash)) && \ |
365 | (inet_twsk(__sk)->tw_daddr == (__saddr)) && \ | ||
357 | (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ | 366 | (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ |
358 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ | 367 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ |
359 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) | 368 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) |
@@ -378,18 +387,19 @@ static inline struct sock * | |||
378 | /* Optimize here for direct hit, only listening connections can | 387 | /* Optimize here for direct hit, only listening connections can |
379 | * have wildcards anyways. | 388 | * have wildcards anyways. |
380 | */ | 389 | */ |
381 | const int hash = inet_ehashfn(daddr, hnum, saddr, sport, hashinfo->ehash_size); | 390 | unsigned int hash = inet_ehashfn(daddr, hnum, saddr, sport); |
382 | struct inet_ehash_bucket *head = &hashinfo->ehash[hash]; | 391 | struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); |
383 | 392 | ||
393 | prefetch(head->chain.first); | ||
384 | read_lock(&head->lock); | 394 | read_lock(&head->lock); |
385 | sk_for_each(sk, node, &head->chain) { | 395 | sk_for_each(sk, node, &head->chain) { |
386 | if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif)) | 396 | if (INET_MATCH(sk, hash, acookie, saddr, daddr, ports, dif)) |
387 | goto hit; /* You sunk my battleship! */ | 397 | goto hit; /* You sunk my battleship! */ |
388 | } | 398 | } |
389 | 399 | ||
390 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | 400 | /* Must check for a TIME_WAIT'er before going to listener hash. */ |
391 | sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { | 401 | sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { |
392 | if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif)) | 402 | if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif)) |
393 | goto hit; | 403 | goto hit; |
394 | } | 404 | } |
395 | sk = NULL; | 405 | sk = NULL; |