aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-11-30 04:49:27 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-30 15:02:56 -0500
commitce43b03e8889475817d427b1f3724c7e294b76eb (patch)
tree0cd6679992bd810371620fcab52c24ce39a89aa8
parentb02a80674ea3905926c1a942426008d732c47339 (diff)
net: move inet_dport/inet_num in sock_common
commit 68835aba4d9b (net: optimize INET input path further) moved some fields used for tcp/udp sockets lookup in the first cache line of struct sock_common. This patch moves inet_dport/inet_num as well, filling a 32bit hole on 64 bit arches and reducing number of cache line misses in lookups. Also change INET_MATCH()/INET_TW_MATCH() to perform the ports match before addresses match, as this check is more discriminant. Remove the hash check from MATCH() macros because we dont need to re validate the hash value after taking a refcount on socket, and use likely/unlikely compiler hints, as the sk_hash/hash check makes the following conditional tests 100% predicted by cpu. Introduce skc_addrpair/skc_portpair pair values to better document the alignment requirements of the port/addr pairs used in the various MATCH() macros, and remove some casts. The namespace check can also be done at last. This slightly improves TCP/UDP lookup times. IP/TCP early demux needs inet->rx_dst_ifindex and TCP needs inet->min_ttl, lets group them together in same cache line. With help from Ben Hutchings & Joe Perches. Idea of this patch came after Ling Ma proposal to move skc_hash to the beginning of struct sock_common, and should allow him to submit a final version of his patch. My tests show an improvement doing so. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Ben Hutchings <bhutchings@solarflare.com> Cc: Joe Perches <joe@perches.com> Cc: Ling Ma <ling.ma.program@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/ipv6.h32
-rw-r--r--include/net/inet_hashtables.h48
-rw-r--r--include/net/inet_sock.h8
-rw-r--r--include/net/inet_timewait_sock.h7
-rw-r--r--include/net/sock.h25
-rw-r--r--net/ipv4/inet_hashtables.c36
-rw-r--r--net/ipv6/inet6_hashtables.c27
7 files changed, 115 insertions, 68 deletions
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 5e11905a4f0..12729e966dc 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -364,20 +364,22 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk)
364#define inet_v6_ipv6only(__sk) 0 364#define inet_v6_ipv6only(__sk) 0
365#endif /* IS_ENABLED(CONFIG_IPV6) */ 365#endif /* IS_ENABLED(CONFIG_IPV6) */
366 366
367#define INET6_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif)\ 367#define INET6_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif) \
368 (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ 368 ((inet_sk(__sk)->inet_portpair == (__ports)) && \
369 ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \ 369 ((__sk)->sk_family == AF_INET6) && \
370 ((__sk)->sk_family == AF_INET6) && \ 370 ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \
371 ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \ 371 ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \
372 ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \ 372 (!(__sk)->sk_bound_dev_if || \
373 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) 373 ((__sk)->sk_bound_dev_if == (__dif))) && \
374 374 net_eq(sock_net(__sk), (__net)))
375#define INET6_TW_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif) \ 375
376 (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ 376#define INET6_TW_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif) \
377 (*((__portpair *)&(inet_twsk(__sk)->tw_dport)) == (__ports)) && \ 377 ((inet_twsk(__sk)->tw_portpair == (__ports)) && \
378 ((__sk)->sk_family == PF_INET6) && \ 378 ((__sk)->sk_family == AF_INET6) && \
379 (ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_daddr, (__saddr))) && \ 379 ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_daddr, (__saddr)) && \
380 (ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_rcv_saddr, (__daddr))) && \ 380 ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_rcv_saddr, (__daddr)) && \
381 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) 381 (!(__sk)->sk_bound_dev_if || \
382 ((__sk)->sk_bound_dev_if == (__dif))) && \
383 net_eq(sock_net(__sk), (__net)))
382 384
383#endif /* _IPV6_H */ 385#endif /* _IPV6_H */
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 54be0287eb9..d1de4fbd45c 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -299,30 +299,34 @@ typedef __u64 __bitwise __addrpair;
299 (((__force __u64)(__be32)(__daddr)) << 32) | \ 299 (((__force __u64)(__be32)(__daddr)) << 32) | \
300 ((__force __u64)(__be32)(__saddr))); 300 ((__force __u64)(__be32)(__saddr)));
301#endif /* __BIG_ENDIAN */ 301#endif /* __BIG_ENDIAN */
302#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ 302#define INET_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif) \
303 (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ 303 ((inet_sk(__sk)->inet_portpair == (__ports)) && \
304 ((*((__addrpair *)&(inet_sk(__sk)->inet_daddr))) == (__cookie)) && \ 304 (inet_sk(__sk)->inet_addrpair == (__cookie)) && \
305 ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \ 305 (!(__sk)->sk_bound_dev_if || \
306 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) 306 ((__sk)->sk_bound_dev_if == (__dif))) && \
307#define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ 307 net_eq(sock_net(__sk), (__net)))
308 (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ 308#define INET_TW_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif)\
309 ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ 309 ((inet_twsk(__sk)->tw_portpair == (__ports)) && \
310 ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ 310 (inet_twsk(__sk)->tw_addrpair == (__cookie)) && \
311 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) 311 (!(__sk)->sk_bound_dev_if || \
312 ((__sk)->sk_bound_dev_if == (__dif))) && \
313 net_eq(sock_net(__sk), (__net)))
312#else /* 32-bit arch */ 314#else /* 32-bit arch */
313#define INET_ADDR_COOKIE(__name, __saddr, __daddr) 315#define INET_ADDR_COOKIE(__name, __saddr, __daddr)
314#define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ 316#define INET_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif) \
315 (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ 317 ((inet_sk(__sk)->inet_portpair == (__ports)) && \
316 (inet_sk(__sk)->inet_daddr == (__saddr)) && \ 318 (inet_sk(__sk)->inet_daddr == (__saddr)) && \
317 (inet_sk(__sk)->inet_rcv_saddr == (__daddr)) && \ 319 (inet_sk(__sk)->inet_rcv_saddr == (__daddr)) && \
318 ((*((__portpair *)&(inet_sk(__sk)->inet_dport))) == (__ports)) && \ 320 (!(__sk)->sk_bound_dev_if || \
319 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) 321 ((__sk)->sk_bound_dev_if == (__dif))) && \
320#define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ 322 net_eq(sock_net(__sk), (__net)))
321 (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ 323#define INET_TW_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif) \
322 (inet_twsk(__sk)->tw_daddr == (__saddr)) && \ 324 ((inet_twsk(__sk)->tw_portpair == (__ports)) && \
323 (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ 325 (inet_twsk(__sk)->tw_daddr == (__saddr)) && \
324 ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ 326 (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \
325 (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) 327 (!(__sk)->sk_bound_dev_if || \
328 ((__sk)->sk_bound_dev_if == (__dif))) && \
329 net_eq(sock_net(__sk), (__net)))
326#endif /* 64-bit arch */ 330#endif /* 64-bit arch */
327 331
328/* 332/*
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 256c1ed2d69..a4196cbc84e 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -144,9 +144,11 @@ struct inet_sock {
144 /* Socket demultiplex comparisons on incoming packets. */ 144 /* Socket demultiplex comparisons on incoming packets. */
145#define inet_daddr sk.__sk_common.skc_daddr 145#define inet_daddr sk.__sk_common.skc_daddr
146#define inet_rcv_saddr sk.__sk_common.skc_rcv_saddr 146#define inet_rcv_saddr sk.__sk_common.skc_rcv_saddr
147#define inet_addrpair sk.__sk_common.skc_addrpair
148#define inet_dport sk.__sk_common.skc_dport
149#define inet_num sk.__sk_common.skc_num
150#define inet_portpair sk.__sk_common.skc_portpair
147 151
148 __be16 inet_dport;
149 __u16 inet_num;
150 __be32 inet_saddr; 152 __be32 inet_saddr;
151 __s16 uc_ttl; 153 __s16 uc_ttl;
152 __u16 cmsg_flags; 154 __u16 cmsg_flags;
@@ -154,6 +156,7 @@ struct inet_sock {
154 __u16 inet_id; 156 __u16 inet_id;
155 157
156 struct ip_options_rcu __rcu *inet_opt; 158 struct ip_options_rcu __rcu *inet_opt;
159 int rx_dst_ifindex;
157 __u8 tos; 160 __u8 tos;
158 __u8 min_ttl; 161 __u8 min_ttl;
159 __u8 mc_ttl; 162 __u8 mc_ttl;
@@ -170,7 +173,6 @@ struct inet_sock {
170 int uc_index; 173 int uc_index;
171 int mc_index; 174 int mc_index;
172 __be32 mc_addr; 175 __be32 mc_addr;
173 int rx_dst_ifindex;
174 struct ip_mc_socklist __rcu *mc_list; 176 struct ip_mc_socklist __rcu *mc_list;
175 struct inet_cork_full cork; 177 struct inet_cork_full cork;
176}; 178};
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index ba52c830a7a..7d658d57736 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -112,6 +112,11 @@ struct inet_timewait_sock {
112#define tw_net __tw_common.skc_net 112#define tw_net __tw_common.skc_net
113#define tw_daddr __tw_common.skc_daddr 113#define tw_daddr __tw_common.skc_daddr
114#define tw_rcv_saddr __tw_common.skc_rcv_saddr 114#define tw_rcv_saddr __tw_common.skc_rcv_saddr
115#define tw_addrpair __tw_common.skc_addrpair
116#define tw_dport __tw_common.skc_dport
117#define tw_num __tw_common.skc_num
118#define tw_portpair __tw_common.skc_portpair
119
115 int tw_timeout; 120 int tw_timeout;
116 volatile unsigned char tw_substate; 121 volatile unsigned char tw_substate;
117 unsigned char tw_rcv_wscale; 122 unsigned char tw_rcv_wscale;
@@ -119,8 +124,6 @@ struct inet_timewait_sock {
119 /* Socket demultiplex comparisons on incoming packets. */ 124 /* Socket demultiplex comparisons on incoming packets. */
120 /* these three are in inet_sock */ 125 /* these three are in inet_sock */
121 __be16 tw_sport; 126 __be16 tw_sport;
122 __be16 tw_dport;
123 __u16 tw_num;
124 kmemcheck_bitfield_begin(flags); 127 kmemcheck_bitfield_begin(flags);
125 /* And these are ours. */ 128 /* And these are ours. */
126 unsigned int tw_ipv6only : 1, 129 unsigned int tw_ipv6only : 1,
diff --git a/include/net/sock.h b/include/net/sock.h
index c945fba4f54..c4132c1b63a 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -132,6 +132,8 @@ struct net;
132 * @skc_rcv_saddr: Bound local IPv4 addr 132 * @skc_rcv_saddr: Bound local IPv4 addr
133 * @skc_hash: hash value used with various protocol lookup tables 133 * @skc_hash: hash value used with various protocol lookup tables
134 * @skc_u16hashes: two u16 hash values used by UDP lookup tables 134 * @skc_u16hashes: two u16 hash values used by UDP lookup tables
135 * @skc_dport: placeholder for inet_dport/tw_dport
136 * @skc_num: placeholder for inet_num/tw_num
135 * @skc_family: network address family 137 * @skc_family: network address family
136 * @skc_state: Connection state 138 * @skc_state: Connection state
137 * @skc_reuse: %SO_REUSEADDR setting 139 * @skc_reuse: %SO_REUSEADDR setting
@@ -149,16 +151,29 @@ struct net;
149 * for struct sock and struct inet_timewait_sock. 151 * for struct sock and struct inet_timewait_sock.
150 */ 152 */
151struct sock_common { 153struct sock_common {
152 /* skc_daddr and skc_rcv_saddr must be grouped : 154 /* skc_daddr and skc_rcv_saddr must be grouped on a 8 bytes aligned
153 * cf INET_MATCH() and INET_TW_MATCH() 155 * address on 64bit arches : cf INET_MATCH() and INET_TW_MATCH()
154 */ 156 */
155 __be32 skc_daddr; 157 union {
156 __be32 skc_rcv_saddr; 158 unsigned long skc_addrpair;
157 159 struct {
160 __be32 skc_daddr;
161 __be32 skc_rcv_saddr;
162 };
163 };
158 union { 164 union {
159 unsigned int skc_hash; 165 unsigned int skc_hash;
160 __u16 skc_u16hashes[2]; 166 __u16 skc_u16hashes[2];
161 }; 167 };
168 /* skc_dport && skc_num must be grouped as well */
169 union {
170 u32 skc_portpair;
171 struct {
172 __be16 skc_dport;
173 __u16 skc_num;
174 };
175 };
176
162 unsigned short skc_family; 177 unsigned short skc_family;
163 volatile unsigned char skc_state; 178 volatile unsigned char skc_state;
164 unsigned char skc_reuse; 179 unsigned char skc_reuse;
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 7880af97020..fa3ae814871 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -237,12 +237,14 @@ struct sock *__inet_lookup_established(struct net *net,
237 rcu_read_lock(); 237 rcu_read_lock();
238begin: 238begin:
239 sk_nulls_for_each_rcu(sk, node, &head->chain) { 239 sk_nulls_for_each_rcu(sk, node, &head->chain) {
240 if (INET_MATCH(sk, net, hash, acookie, 240 if (sk->sk_hash != hash)
241 saddr, daddr, ports, dif)) { 241 continue;
242 if (likely(INET_MATCH(sk, net, acookie,
243 saddr, daddr, ports, dif))) {
242 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) 244 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt)))
243 goto begintw; 245 goto begintw;
244 if (unlikely(!INET_MATCH(sk, net, hash, acookie, 246 if (unlikely(!INET_MATCH(sk, net, acookie,
245 saddr, daddr, ports, dif))) { 247 saddr, daddr, ports, dif))) {
246 sock_put(sk); 248 sock_put(sk);
247 goto begin; 249 goto begin;
248 } 250 }
@@ -260,14 +262,18 @@ begin:
260begintw: 262begintw:
261 /* Must check for a TIME_WAIT'er before going to listener hash. */ 263 /* Must check for a TIME_WAIT'er before going to listener hash. */
262 sk_nulls_for_each_rcu(sk, node, &head->twchain) { 264 sk_nulls_for_each_rcu(sk, node, &head->twchain) {
263 if (INET_TW_MATCH(sk, net, hash, acookie, 265 if (sk->sk_hash != hash)
264 saddr, daddr, ports, dif)) { 266 continue;
267 if (likely(INET_TW_MATCH(sk, net, acookie,
268 saddr, daddr, ports,
269 dif))) {
265 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { 270 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) {
266 sk = NULL; 271 sk = NULL;
267 goto out; 272 goto out;
268 } 273 }
269 if (unlikely(!INET_TW_MATCH(sk, net, hash, acookie, 274 if (unlikely(!INET_TW_MATCH(sk, net, acookie,
270 saddr, daddr, ports, dif))) { 275 saddr, daddr, ports,
276 dif))) {
271 sock_put(sk); 277 sock_put(sk);
272 goto begintw; 278 goto begintw;
273 } 279 }
@@ -314,10 +320,12 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
314 320
315 /* Check TIME-WAIT sockets first. */ 321 /* Check TIME-WAIT sockets first. */
316 sk_nulls_for_each(sk2, node, &head->twchain) { 322 sk_nulls_for_each(sk2, node, &head->twchain) {
317 tw = inet_twsk(sk2); 323 if (sk2->sk_hash != hash)
324 continue;
318 325
319 if (INET_TW_MATCH(sk2, net, hash, acookie, 326 if (likely(INET_TW_MATCH(sk2, net, acookie,
320 saddr, daddr, ports, dif)) { 327 saddr, daddr, ports, dif))) {
328 tw = inet_twsk(sk2);
321 if (twsk_unique(sk, sk2, twp)) 329 if (twsk_unique(sk, sk2, twp))
322 goto unique; 330 goto unique;
323 else 331 else
@@ -328,8 +336,10 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
328 336
329 /* And established part... */ 337 /* And established part... */
330 sk_nulls_for_each(sk2, node, &head->chain) { 338 sk_nulls_for_each(sk2, node, &head->chain) {
331 if (INET_MATCH(sk2, net, hash, acookie, 339 if (sk2->sk_hash != hash)
332 saddr, daddr, ports, dif)) 340 continue;
341 if (likely(INET_MATCH(sk2, net, acookie,
342 saddr, daddr, ports, dif)))
333 goto not_unique; 343 goto not_unique;
334 } 344 }
335 345
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 73f1a00a96a..dea17fd28e5 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -87,11 +87,13 @@ struct sock *__inet6_lookup_established(struct net *net,
87 rcu_read_lock(); 87 rcu_read_lock();
88begin: 88begin:
89 sk_nulls_for_each_rcu(sk, node, &head->chain) { 89 sk_nulls_for_each_rcu(sk, node, &head->chain) {
90 /* For IPV6 do the cheaper port and family tests first. */ 90 if (sk->sk_hash != hash)
91 if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { 91 continue;
92 if (likely(INET6_MATCH(sk, net, saddr, daddr, ports, dif))) {
92 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) 93 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt)))
93 goto begintw; 94 goto begintw;
94 if (!INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { 95 if (unlikely(!INET6_MATCH(sk, net, saddr, daddr,
96 ports, dif))) {
95 sock_put(sk); 97 sock_put(sk);
96 goto begin; 98 goto begin;
97 } 99 }
@@ -104,12 +106,16 @@ begin:
104begintw: 106begintw:
105 /* Must check for a TIME_WAIT'er before going to listener hash. */ 107 /* Must check for a TIME_WAIT'er before going to listener hash. */
106 sk_nulls_for_each_rcu(sk, node, &head->twchain) { 108 sk_nulls_for_each_rcu(sk, node, &head->twchain) {
107 if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { 109 if (sk->sk_hash != hash)
110 continue;
111 if (likely(INET6_TW_MATCH(sk, net, saddr, daddr,
112 ports, dif))) {
108 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { 113 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) {
109 sk = NULL; 114 sk = NULL;
110 goto out; 115 goto out;
111 } 116 }
112 if (!INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { 117 if (unlikely(!INET6_TW_MATCH(sk, net, saddr, daddr,
118 ports, dif))) {
113 sock_put(sk); 119 sock_put(sk);
114 goto begintw; 120 goto begintw;
115 } 121 }
@@ -236,9 +242,12 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
236 242
237 /* Check TIME-WAIT sockets first. */ 243 /* Check TIME-WAIT sockets first. */
238 sk_nulls_for_each(sk2, node, &head->twchain) { 244 sk_nulls_for_each(sk2, node, &head->twchain) {
239 tw = inet_twsk(sk2); 245 if (sk2->sk_hash != hash)
246 continue;
240 247
241 if (INET6_TW_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) { 248 if (likely(INET6_TW_MATCH(sk2, net, saddr, daddr,
249 ports, dif))) {
250 tw = inet_twsk(sk2);
242 if (twsk_unique(sk, sk2, twp)) 251 if (twsk_unique(sk, sk2, twp))
243 goto unique; 252 goto unique;
244 else 253 else
@@ -249,7 +258,9 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
249 258
250 /* And established part... */ 259 /* And established part... */
251 sk_nulls_for_each(sk2, node, &head->chain) { 260 sk_nulls_for_each(sk2, node, &head->chain) {
252 if (INET6_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) 261 if (sk2->sk_hash != hash)
262 continue;
263 if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif)))
253 goto not_unique; 264 goto not_unique;
254 } 265 }
255 266