diff options
Diffstat (limited to 'include/net/inet_hashtables.h')
| -rw-r--r-- | include/net/inet_hashtables.h | 66 |
1 files changed, 39 insertions, 27 deletions
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 646b6ea7fe26..f50f95968340 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 |
| @@ -130,17 +130,16 @@ struct inet_hashinfo { | |||
| 130 | int port_rover; | 130 | int port_rover; |
| 131 | }; | 131 | }; |
| 132 | 132 | ||
| 133 | static inline int inet_ehashfn(const __u32 laddr, const __u16 lport, | 133 | static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport, |
| 134 | const __u32 faddr, const __u16 fport, | 134 | const __u32 faddr, const __u16 fport) |
| 135 | const int ehash_size) | ||
| 136 | { | 135 | { |
| 137 | int h = (laddr ^ lport) ^ (faddr ^ fport); | 136 | unsigned int h = (laddr ^ lport) ^ (faddr ^ fport); |
| 138 | h ^= h >> 16; | 137 | h ^= h >> 16; |
| 139 | h ^= h >> 8; | 138 | h ^= h >> 8; |
| 140 | return h & (ehash_size - 1); | 139 | return h; |
| 141 | } | 140 | } |
| 142 | 141 | ||
| 143 | static inline int inet_sk_ehashfn(const struct sock *sk, const int ehash_size) | 142 | static inline int inet_sk_ehashfn(const struct sock *sk) |
| 144 | { | 143 | { |
| 145 | const struct inet_sock *inet = inet_sk(sk); | 144 | const struct inet_sock *inet = inet_sk(sk); |
| 146 | const __u32 laddr = inet->rcv_saddr; | 145 | const __u32 laddr = inet->rcv_saddr; |
| @@ -148,7 +147,14 @@ static inline int inet_sk_ehashfn(const struct sock *sk, const int ehash_size) | |||
| 148 | const __u32 faddr = inet->daddr; | 147 | const __u32 faddr = inet->daddr; |
| 149 | const __u16 fport = inet->dport; | 148 | const __u16 fport = inet->dport; |
| 150 | 149 | ||
| 151 | return inet_ehashfn(laddr, lport, faddr, fport, ehash_size); | 150 | return inet_ehashfn(laddr, lport, faddr, fport); |
| 151 | } | ||
| 152 | |||
| 153 | static inline struct inet_ehash_bucket *inet_ehash_bucket( | ||
| 154 | struct inet_hashinfo *hashinfo, | ||
| 155 | unsigned int hash) | ||
| 156 | { | ||
| 157 | return &hashinfo->ehash[hash & (hashinfo->ehash_size - 1)]; | ||
| 152 | } | 158 | } |
| 153 | 159 | ||
| 154 | extern struct inet_bind_bucket * | 160 | extern struct inet_bind_bucket * |
| @@ -235,9 +241,11 @@ static inline void __inet_hash(struct inet_hashinfo *hashinfo, | |||
| 235 | lock = &hashinfo->lhash_lock; | 241 | lock = &hashinfo->lhash_lock; |
| 236 | inet_listen_wlock(hashinfo); | 242 | inet_listen_wlock(hashinfo); |
| 237 | } else { | 243 | } else { |
| 238 | sk->sk_hashent = inet_sk_ehashfn(sk, hashinfo->ehash_size); | 244 | struct inet_ehash_bucket *head; |
| 239 | list = &hashinfo->ehash[sk->sk_hashent].chain; | 245 | sk->sk_hash = inet_sk_ehashfn(sk); |
| 240 | lock = &hashinfo->ehash[sk->sk_hashent].lock; | 246 | head = inet_ehash_bucket(hashinfo, sk->sk_hash); |
| 247 | list = &head->chain; | ||
| 248 | lock = &head->lock; | ||
| 241 | write_lock(lock); | 249 | write_lock(lock); |
| 242 | } | 250 | } |
| 243 | __sk_add_node(sk, list); | 251 | __sk_add_node(sk, list); |
| @@ -268,9 +276,8 @@ static inline void inet_unhash(struct inet_hashinfo *hashinfo, struct sock *sk) | |||
| 268 | inet_listen_wlock(hashinfo); | 276 | inet_listen_wlock(hashinfo); |
| 269 | lock = &hashinfo->lhash_lock; | 277 | lock = &hashinfo->lhash_lock; |
| 270 | } else { | 278 | } else { |
| 271 | struct inet_ehash_bucket *head = &hashinfo->ehash[sk->sk_hashent]; | 279 | lock = &inet_ehash_bucket(hashinfo, sk->sk_hash)->lock; |
| 272 | lock = &head->lock; | 280 | write_lock_bh(lock); |
| 273 | write_lock_bh(&head->lock); | ||
| 274 | } | 281 | } |
| 275 | 282 | ||
| 276 | if (__sk_del_node_init(sk)) | 283 | if (__sk_del_node_init(sk)) |
| @@ -337,23 +344,27 @@ sherry_cache: | |||
| 337 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ | 344 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ |
| 338 | const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr)); | 345 | const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr)); |
| 339 | #endif /* __BIG_ENDIAN */ | 346 | #endif /* __BIG_ENDIAN */ |
| 340 | #define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ | 347 | #define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ |
| 341 | (((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ | 348 | (((__sk)->sk_hash == (__hash)) && \ |
| 349 | ((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ | ||
| 342 | ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ | 350 | ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ |
| 343 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) | 351 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) |
| 344 | #define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ | 352 | #define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ |
| 345 | (((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ | 353 | (((__sk)->sk_hash == (__hash)) && \ |
| 354 | ((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ | ||
| 346 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ | 355 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ |
| 347 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) | 356 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) |
| 348 | #else /* 32-bit arch */ | 357 | #else /* 32-bit arch */ |
| 349 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) | 358 | #define INET_ADDR_COOKIE(__name, __saddr, __daddr) |
| 350 | #define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif) \ | 359 | #define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ |
| 351 | ((inet_sk(__sk)->daddr == (__saddr)) && \ | 360 | (((__sk)->sk_hash == (__hash)) && \ |
| 361 | (inet_sk(__sk)->daddr == (__saddr)) && \ | ||
| 352 | (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ | 362 | (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ |
| 353 | ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ | 363 | ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ |
| 354 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) | 364 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) |
| 355 | #define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif) \ | 365 | #define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ |
| 356 | ((inet_twsk(__sk)->tw_daddr == (__saddr)) && \ | 366 | (((__sk)->sk_hash == (__hash)) && \ |
| 367 | (inet_twsk(__sk)->tw_daddr == (__saddr)) && \ | ||
| 357 | (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ | 368 | (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ |
| 358 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ | 369 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ |
| 359 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) | 370 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) |
| @@ -378,18 +389,19 @@ static inline struct sock * | |||
| 378 | /* Optimize here for direct hit, only listening connections can | 389 | /* Optimize here for direct hit, only listening connections can |
| 379 | * have wildcards anyways. | 390 | * have wildcards anyways. |
| 380 | */ | 391 | */ |
| 381 | const int hash = inet_ehashfn(daddr, hnum, saddr, sport, hashinfo->ehash_size); | 392 | unsigned int hash = inet_ehashfn(daddr, hnum, saddr, sport); |
| 382 | struct inet_ehash_bucket *head = &hashinfo->ehash[hash]; | 393 | struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); |
| 383 | 394 | ||
| 395 | prefetch(head->chain.first); | ||
| 384 | read_lock(&head->lock); | 396 | read_lock(&head->lock); |
| 385 | sk_for_each(sk, node, &head->chain) { | 397 | sk_for_each(sk, node, &head->chain) { |
| 386 | if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif)) | 398 | if (INET_MATCH(sk, hash, acookie, saddr, daddr, ports, dif)) |
| 387 | goto hit; /* You sunk my battleship! */ | 399 | goto hit; /* You sunk my battleship! */ |
| 388 | } | 400 | } |
| 389 | 401 | ||
| 390 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | 402 | /* Must check for a TIME_WAIT'er before going to listener hash. */ |
| 391 | sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { | 403 | sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { |
| 392 | if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif)) | 404 | if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif)) |
| 393 | goto hit; | 405 | goto hit; |
| 394 | } | 406 | } |
| 395 | sk = NULL; | 407 | sk = NULL; |
