[INET]: speedup inet (tcp/dccp) lookups

Arnaldo and I agreed it could be applied now, because I have other
pending patches depending on this one (Thank you Arnaldo)

(The other important patch moves skc_refcnt in a separate cache line,
so that the SMP/NUMA performance doesnt suffer from cache line ping pongs)

1) First some performance data :
--------------------------------

tcp_v4_rcv() wastes a *lot* of time in __inet_lookup_established()

The most time critical code is :

sk_for_each(sk, node, &head->chain) {
     if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif))
         goto hit; /* You sunk my battleship! */
}

The sk_for_each() does use prefetch() hints but only the begining of
"struct sock" is prefetched.

As INET_MATCH first comparison uses inet_sk(__sk)->daddr, wich is far
away from the begining of "struct sock", it has to bring into CPU
cache cold cache line. Each iteration has to use at least 2 cache
lines.

This can be problematic if some chains are very long.

2) The goal
-----------

The idea I had is to change things so that INET_MATCH() may return
FALSE in 99% of cases only using the data already in the CPU cache,
using one cache line per iteration.

3) Description of the patch
---------------------------

Adds a new 'unsigned int skc_hash' field in 'struct sock_common',
filling a 32 bits hole on 64 bits platform.

struct sock_common {
	unsigned short		skc_family;
	volatile unsigned char	skc_state;
	unsigned char		skc_reuse;
	int			skc_bound_dev_if;
	struct hlist_node	skc_node;
	struct hlist_node	skc_bind_node;
	atomic_t		skc_refcnt;
+	unsigned int		skc_hash;
	struct proto		*skc_prot;
};

Store in this 32 bits field the full hash, not masked by (ehash_size -
1) Using this full hash as the first comparison done in INET_MATCH
permits us immediatly skip the element without touching a second cache
line in case of a miss.

Suppress the sk_hashent/tw_hashent fields since skc_hash (aliased to
sk_hash and tw_hash) already contains the slot number if we mask with
(ehash_size - 1)

File include/net/inet_hashtables.h

64 bits platforms :
#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
     (((__sk)->sk_hash == (__hash))
     ((*((__u64 *)&(inet_sk(__sk)->daddr)))== (__cookie))   &&  \
     ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports))   &&  \
     (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))

32bits platforms:
#define TCP_IPV4_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
     (((__sk)->sk_hash == (__hash))                 &&  \
     (inet_sk(__sk)->daddr          == (__saddr))   &&  \
     (inet_sk(__sk)->rcv_saddr      == (__daddr))   &&  \
     (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))


- Adds a prefetch(head->chain.first) in 
__inet_lookup_established()/__tcp_v4_check_established() and 
__inet6_lookup_established()/__tcp_v6_check_established() and 
__dccp_v4_check_established() to bring into cache the first element of the 
list, before the {read|write}_lock(&head->lock);

Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
Acked-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric Dumazet 2005-10-03 14:13:38 -07:00 коммит произвёл David S. Miller
Родитель 399de50bbb
Коммит 81c3d5470e
12 изменённых файлов: 85 добавлений и 69 удалений

Просмотреть файл

@ -372,8 +372,9 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk)
#define inet_v6_ipv6only(__sk) 0 #define inet_v6_ipv6only(__sk) 0
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
#define INET6_MATCH(__sk, __saddr, __daddr, __ports, __dif) \ #define INET6_MATCH(__sk, __hash, __saddr, __daddr, __ports, __dif)\
(((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ (((__sk)->sk_hash == (__hash)) && \
((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
((__sk)->sk_family == AF_INET6) && \ ((__sk)->sk_family == AF_INET6) && \
ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \ ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \
ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \ ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \

Просмотреть файл

@ -71,7 +71,7 @@ enum
TCF_META_ID_SK_SNDBUF, TCF_META_ID_SK_SNDBUF,
TCF_META_ID_SK_ALLOCS, TCF_META_ID_SK_ALLOCS,
TCF_META_ID_SK_ROUTE_CAPS, TCF_META_ID_SK_ROUTE_CAPS,
TCF_META_ID_SK_HASHENT, TCF_META_ID_SK_HASH,
TCF_META_ID_SK_LINGERTIME, TCF_META_ID_SK_LINGERTIME,
TCF_META_ID_SK_ACK_BACKLOG, TCF_META_ID_SK_ACK_BACKLOG,
TCF_META_ID_SK_MAX_ACK_BACKLOG, TCF_META_ID_SK_MAX_ACK_BACKLOG,

Просмотреть файл

@ -26,19 +26,18 @@
struct inet_hashinfo; struct inet_hashinfo;
/* I have no idea if this is a good hash for v6 or not. -DaveM */ /* I have no idea if this is a good hash for v6 or not. -DaveM */
static inline int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport, static inline unsigned int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport,
const struct in6_addr *faddr, const u16 fport, const struct in6_addr *faddr, const u16 fport)
const int ehash_size)
{ {
int hashent = (lport ^ fport); unsigned int hashent = (lport ^ fport);
hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]); hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
hashent ^= hashent >> 16; hashent ^= hashent >> 16;
hashent ^= hashent >> 8; hashent ^= hashent >> 8;
return (hashent & (ehash_size - 1)); return hashent;
} }
static inline int inet6_sk_ehashfn(const struct sock *sk, const int ehash_size) static inline int inet6_sk_ehashfn(const struct sock *sk)
{ {
const struct inet_sock *inet = inet_sk(sk); const struct inet_sock *inet = inet_sk(sk);
const struct ipv6_pinfo *np = inet6_sk(sk); const struct ipv6_pinfo *np = inet6_sk(sk);
@ -46,7 +45,7 @@ static inline int inet6_sk_ehashfn(const struct sock *sk, const int ehash_size)
const struct in6_addr *faddr = &np->daddr; const struct in6_addr *faddr = &np->daddr;
const __u16 lport = inet->num; const __u16 lport = inet->num;
const __u16 fport = inet->dport; const __u16 fport = inet->dport;
return inet6_ehashfn(laddr, lport, faddr, fport, ehash_size); return inet6_ehashfn(laddr, lport, faddr, fport);
} }
/* /*
@ -69,14 +68,14 @@ static inline struct sock *
/* Optimize here for direct hit, only listening connections can /* Optimize here for direct hit, only listening connections can
* have wildcards anyways. * have wildcards anyways.
*/ */
const int hash = inet6_ehashfn(daddr, hnum, saddr, sport, unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport);
hashinfo->ehash_size); struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash);
struct inet_ehash_bucket *head = &hashinfo->ehash[hash];
prefetch(head->chain.first);
read_lock(&head->lock); read_lock(&head->lock);
sk_for_each(sk, node, &head->chain) { sk_for_each(sk, node, &head->chain) {
/* For IPV6 do the cheaper port and family tests first. */ /* For IPV6 do the cheaper port and family tests first. */
if (INET6_MATCH(sk, saddr, daddr, ports, dif)) if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif))
goto hit; /* You sunk my battleship! */ goto hit; /* You sunk my battleship! */
} }
/* Must check for a TIME_WAIT'er before going to listener hash. */ /* Must check for a TIME_WAIT'er before going to listener hash. */

Просмотреть файл

@ -108,7 +108,7 @@ struct inet_hashinfo {
struct inet_bind_hashbucket *bhash; struct inet_bind_hashbucket *bhash;
int bhash_size; int bhash_size;
int ehash_size; unsigned int ehash_size;
/* All sockets in TCP_LISTEN state will be in here. This is the only /* All sockets in TCP_LISTEN state will be in here. This is the only
* table where wildcard'd TCP sockets can exist. Hash function here * table where wildcard'd TCP sockets can exist. Hash function here
@ -130,17 +130,16 @@ struct inet_hashinfo {
int port_rover; int port_rover;
}; };
static inline int inet_ehashfn(const __u32 laddr, const __u16 lport, static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport,
const __u32 faddr, const __u16 fport, const __u32 faddr, const __u16 fport)
const int ehash_size)
{ {
int h = (laddr ^ lport) ^ (faddr ^ fport); unsigned int h = (laddr ^ lport) ^ (faddr ^ fport);
h ^= h >> 16; h ^= h >> 16;
h ^= h >> 8; h ^= h >> 8;
return h & (ehash_size - 1); return h;
} }
static inline int inet_sk_ehashfn(const struct sock *sk, const int ehash_size) static inline int inet_sk_ehashfn(const struct sock *sk)
{ {
const struct inet_sock *inet = inet_sk(sk); const struct inet_sock *inet = inet_sk(sk);
const __u32 laddr = inet->rcv_saddr; const __u32 laddr = inet->rcv_saddr;
@ -148,7 +147,14 @@ static inline int inet_sk_ehashfn(const struct sock *sk, const int ehash_size)
const __u32 faddr = inet->daddr; const __u32 faddr = inet->daddr;
const __u16 fport = inet->dport; const __u16 fport = inet->dport;
return inet_ehashfn(laddr, lport, faddr, fport, ehash_size); return inet_ehashfn(laddr, lport, faddr, fport);
}
static inline struct inet_ehash_bucket *inet_ehash_bucket(
struct inet_hashinfo *hashinfo,
unsigned int hash)
{
return &hashinfo->ehash[hash & (hashinfo->ehash_size - 1)];
} }
extern struct inet_bind_bucket * extern struct inet_bind_bucket *
@ -235,9 +241,11 @@ static inline void __inet_hash(struct inet_hashinfo *hashinfo,
lock = &hashinfo->lhash_lock; lock = &hashinfo->lhash_lock;
inet_listen_wlock(hashinfo); inet_listen_wlock(hashinfo);
} else { } else {
sk->sk_hashent = inet_sk_ehashfn(sk, hashinfo->ehash_size); struct inet_ehash_bucket *head;
list = &hashinfo->ehash[sk->sk_hashent].chain; sk->sk_hash = inet_sk_ehashfn(sk);
lock = &hashinfo->ehash[sk->sk_hashent].lock; head = inet_ehash_bucket(hashinfo, sk->sk_hash);
list = &head->chain;
lock = &head->lock;
write_lock(lock); write_lock(lock);
} }
__sk_add_node(sk, list); __sk_add_node(sk, list);
@ -268,9 +276,8 @@ static inline void inet_unhash(struct inet_hashinfo *hashinfo, struct sock *sk)
inet_listen_wlock(hashinfo); inet_listen_wlock(hashinfo);
lock = &hashinfo->lhash_lock; lock = &hashinfo->lhash_lock;
} else { } else {
struct inet_ehash_bucket *head = &hashinfo->ehash[sk->sk_hashent]; lock = &inet_ehash_bucket(hashinfo, sk->sk_hash)->lock;
lock = &head->lock; write_lock_bh(lock);
write_lock_bh(&head->lock);
} }
if (__sk_del_node_init(sk)) if (__sk_del_node_init(sk))
@ -337,23 +344,27 @@ sherry_cache:
#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ #define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr)); const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr));
#endif /* __BIG_ENDIAN */ #endif /* __BIG_ENDIAN */
#define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ #define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
(((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ (((__sk)->sk_hash == (__hash)) && \
((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \
((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
#define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ #define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
(((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ (((__sk)->sk_hash == (__hash)) && \
((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \
((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
#else /* 32-bit arch */ #else /* 32-bit arch */
#define INET_ADDR_COOKIE(__name, __saddr, __daddr) #define INET_ADDR_COOKIE(__name, __saddr, __daddr)
#define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif) \ #define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif) \
((inet_sk(__sk)->daddr == (__saddr)) && \ (((__sk)->sk_hash == (__hash)) && \
(inet_sk(__sk)->daddr == (__saddr)) && \
(inet_sk(__sk)->rcv_saddr == (__daddr)) && \ (inet_sk(__sk)->rcv_saddr == (__daddr)) && \
((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \ ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
#define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif) \ #define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \
((inet_twsk(__sk)->tw_daddr == (__saddr)) && \ (((__sk)->sk_hash == (__hash)) && \
(inet_twsk(__sk)->tw_daddr == (__saddr)) && \
(inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \
((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
@ -378,18 +389,19 @@ static inline struct sock *
/* Optimize here for direct hit, only listening connections can /* Optimize here for direct hit, only listening connections can
* have wildcards anyways. * have wildcards anyways.
*/ */
const int hash = inet_ehashfn(daddr, hnum, saddr, sport, hashinfo->ehash_size); unsigned int hash = inet_ehashfn(daddr, hnum, saddr, sport);
struct inet_ehash_bucket *head = &hashinfo->ehash[hash]; struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash);
prefetch(head->chain.first);
read_lock(&head->lock); read_lock(&head->lock);
sk_for_each(sk, node, &head->chain) { sk_for_each(sk, node, &head->chain) {
if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif)) if (INET_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
goto hit; /* You sunk my battleship! */ goto hit; /* You sunk my battleship! */
} }
/* Must check for a TIME_WAIT'er before going to listener hash. */ /* Must check for a TIME_WAIT'er before going to listener hash. */
sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif)) if (INET_TW_MATCH(sk, hash, acookie, saddr, daddr, ports, dif))
goto hit; goto hit;
} }
sk = NULL; sk = NULL;

Просмотреть файл

@ -112,6 +112,7 @@ struct inet_timewait_sock {
#define tw_node __tw_common.skc_node #define tw_node __tw_common.skc_node
#define tw_bind_node __tw_common.skc_bind_node #define tw_bind_node __tw_common.skc_bind_node
#define tw_refcnt __tw_common.skc_refcnt #define tw_refcnt __tw_common.skc_refcnt
#define tw_hash __tw_common.skc_hash
#define tw_prot __tw_common.skc_prot #define tw_prot __tw_common.skc_prot
volatile unsigned char tw_substate; volatile unsigned char tw_substate;
/* 3 bits hole, try to pack */ /* 3 bits hole, try to pack */
@ -126,7 +127,6 @@ struct inet_timewait_sock {
/* And these are ours. */ /* And these are ours. */
__u8 tw_ipv6only:1; __u8 tw_ipv6only:1;
/* 31 bits hole, try to pack */ /* 31 bits hole, try to pack */
int tw_hashent;
int tw_timeout; int tw_timeout;
unsigned long tw_ttd; unsigned long tw_ttd;
struct inet_bind_bucket *tw_tb; struct inet_bind_bucket *tw_tb;

Просмотреть файл

@ -99,6 +99,7 @@ struct proto;
* @skc_node: main hash linkage for various protocol lookup tables * @skc_node: main hash linkage for various protocol lookup tables
* @skc_bind_node: bind hash linkage for various protocol lookup tables * @skc_bind_node: bind hash linkage for various protocol lookup tables
* @skc_refcnt: reference count * @skc_refcnt: reference count
* @skc_hash: hash value used with various protocol lookup tables
* @skc_prot: protocol handlers inside a network family * @skc_prot: protocol handlers inside a network family
* *
* This is the minimal network layer representation of sockets, the header * This is the minimal network layer representation of sockets, the header
@ -112,6 +113,7 @@ struct sock_common {
struct hlist_node skc_node; struct hlist_node skc_node;
struct hlist_node skc_bind_node; struct hlist_node skc_bind_node;
atomic_t skc_refcnt; atomic_t skc_refcnt;
unsigned int skc_hash;
struct proto *skc_prot; struct proto *skc_prot;
}; };
@ -139,7 +141,6 @@ struct sock_common {
* @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets * @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets
* @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO) * @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
* @sk_lingertime: %SO_LINGER l_linger setting * @sk_lingertime: %SO_LINGER l_linger setting
* @sk_hashent: hash entry in several tables (e.g. inet_hashinfo.ehash)
* @sk_backlog: always used with the per-socket spinlock held * @sk_backlog: always used with the per-socket spinlock held
* @sk_callback_lock: used with the callbacks in the end of this struct * @sk_callback_lock: used with the callbacks in the end of this struct
* @sk_error_queue: rarely used * @sk_error_queue: rarely used
@ -186,6 +187,7 @@ struct sock {
#define sk_node __sk_common.skc_node #define sk_node __sk_common.skc_node
#define sk_bind_node __sk_common.skc_bind_node #define sk_bind_node __sk_common.skc_bind_node
#define sk_refcnt __sk_common.skc_refcnt #define sk_refcnt __sk_common.skc_refcnt
#define sk_hash __sk_common.skc_hash
#define sk_prot __sk_common.skc_prot #define sk_prot __sk_common.skc_prot
unsigned char sk_shutdown : 2, unsigned char sk_shutdown : 2,
sk_no_check : 2, sk_no_check : 2,
@ -208,7 +210,6 @@ struct sock {
unsigned int sk_allocation; unsigned int sk_allocation;
int sk_sndbuf; int sk_sndbuf;
int sk_route_caps; int sk_route_caps;
int sk_hashent;
unsigned long sk_flags; unsigned long sk_flags;
unsigned long sk_lingertime; unsigned long sk_lingertime;
/* /*

Просмотреть файл

@ -46,7 +46,7 @@ static void __vcc_insert_socket(struct sock *sk)
struct atm_vcc *vcc = atm_sk(sk); struct atm_vcc *vcc = atm_sk(sk);
struct hlist_head *head = &vcc_hash[vcc->vci & struct hlist_head *head = &vcc_hash[vcc->vci &
(VCC_HTABLE_SIZE - 1)]; (VCC_HTABLE_SIZE - 1)];
sk->sk_hashent = vcc->vci & (VCC_HTABLE_SIZE - 1); sk->sk_hash = vcc->vci & (VCC_HTABLE_SIZE - 1);
sk_add_node(sk, head); sk_add_node(sk, head);
} }

Просмотреть файл

@ -62,27 +62,27 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
const int dif = sk->sk_bound_dev_if; const int dif = sk->sk_bound_dev_if;
INET_ADDR_COOKIE(acookie, saddr, daddr) INET_ADDR_COOKIE(acookie, saddr, daddr)
const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport); const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
dccp_hashinfo.ehash_size); struct inet_ehash_bucket *head = inet_ehash_bucket(&dccp_hashinfo, hash);
struct inet_ehash_bucket *head = &dccp_hashinfo.ehash[hash];
const struct sock *sk2; const struct sock *sk2;
const struct hlist_node *node; const struct hlist_node *node;
struct inet_timewait_sock *tw; struct inet_timewait_sock *tw;
prefetch(head->chain.first);
write_lock(&head->lock); write_lock(&head->lock);
/* Check TIME-WAIT sockets first. */ /* Check TIME-WAIT sockets first. */
sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) { sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) {
tw = inet_twsk(sk2); tw = inet_twsk(sk2);
if (INET_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif)) if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
goto not_unique; goto not_unique;
} }
tw = NULL; tw = NULL;
/* And established part... */ /* And established part... */
sk_for_each(sk2, node, &head->chain) { sk_for_each(sk2, node, &head->chain) {
if (INET_MATCH(sk2, acookie, saddr, daddr, ports, dif)) if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
goto not_unique; goto not_unique;
} }
@ -90,7 +90,7 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
* in hash table socket with a funny identity. */ * in hash table socket with a funny identity. */
inet->num = lport; inet->num = lport;
inet->sport = htons(lport); inet->sport = htons(lport);
sk->sk_hashent = hash; sk->sk_hash = hash;
BUG_TRAP(sk_unhashed(sk)); BUG_TRAP(sk_unhashed(sk));
__sk_add_node(sk, &head->chain); __sk_add_node(sk, &head->chain);
sock_prot_inc_use(sk->sk_prot); sock_prot_inc_use(sk->sk_prot);

Просмотреть файл

@ -20,7 +20,7 @@ void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashi
struct inet_bind_hashbucket *bhead; struct inet_bind_hashbucket *bhead;
struct inet_bind_bucket *tb; struct inet_bind_bucket *tb;
/* Unlink from established hashes. */ /* Unlink from established hashes. */
struct inet_ehash_bucket *ehead = &hashinfo->ehash[tw->tw_hashent]; struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, tw->tw_hash);
write_lock(&ehead->lock); write_lock(&ehead->lock);
if (hlist_unhashed(&tw->tw_node)) { if (hlist_unhashed(&tw->tw_node)) {
@ -60,7 +60,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
{ {
const struct inet_sock *inet = inet_sk(sk); const struct inet_sock *inet = inet_sk(sk);
const struct inet_connection_sock *icsk = inet_csk(sk); const struct inet_connection_sock *icsk = inet_csk(sk);
struct inet_ehash_bucket *ehead = &hashinfo->ehash[sk->sk_hashent]; struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, sk->sk_hash);
struct inet_bind_hashbucket *bhead; struct inet_bind_hashbucket *bhead;
/* Step 1: Put TW into bind hash. Original socket stays there too. /* Step 1: Put TW into bind hash. Original socket stays there too.
Note, that any socket with inet->num != 0 MUST be bound in Note, that any socket with inet->num != 0 MUST be bound in
@ -106,7 +106,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat
tw->tw_dport = inet->dport; tw->tw_dport = inet->dport;
tw->tw_family = sk->sk_family; tw->tw_family = sk->sk_family;
tw->tw_reuse = sk->sk_reuse; tw->tw_reuse = sk->sk_reuse;
tw->tw_hashent = sk->sk_hashent; tw->tw_hash = sk->sk_hash;
tw->tw_ipv6only = 0; tw->tw_ipv6only = 0;
tw->tw_prot = sk->sk_prot_creator; tw->tw_prot = sk->sk_prot_creator;
atomic_set(&tw->tw_refcnt, 1); atomic_set(&tw->tw_refcnt, 1);

Просмотреть файл

@ -130,19 +130,20 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
int dif = sk->sk_bound_dev_if; int dif = sk->sk_bound_dev_if;
INET_ADDR_COOKIE(acookie, saddr, daddr) INET_ADDR_COOKIE(acookie, saddr, daddr)
const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport); const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, tcp_hashinfo.ehash_size); unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash]; struct inet_ehash_bucket *head = inet_ehash_bucket(&tcp_hashinfo, hash);
struct sock *sk2; struct sock *sk2;
const struct hlist_node *node; const struct hlist_node *node;
struct inet_timewait_sock *tw; struct inet_timewait_sock *tw;
prefetch(head->chain.first);
write_lock(&head->lock); write_lock(&head->lock);
/* Check TIME-WAIT sockets first. */ /* Check TIME-WAIT sockets first. */
sk_for_each(sk2, node, &(head + tcp_hashinfo.ehash_size)->chain) { sk_for_each(sk2, node, &(head + tcp_hashinfo.ehash_size)->chain) {
tw = inet_twsk(sk2); tw = inet_twsk(sk2);
if (INET_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif)) { if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) {
const struct tcp_timewait_sock *tcptw = tcp_twsk(sk2); const struct tcp_timewait_sock *tcptw = tcp_twsk(sk2);
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
@ -179,7 +180,7 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
/* And established part... */ /* And established part... */
sk_for_each(sk2, node, &head->chain) { sk_for_each(sk2, node, &head->chain) {
if (INET_MATCH(sk2, acookie, saddr, daddr, ports, dif)) if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
goto not_unique; goto not_unique;
} }
@ -188,7 +189,7 @@ unique:
* in hash table socket with a funny identity. */ * in hash table socket with a funny identity. */
inet->num = lport; inet->num = lport;
inet->sport = htons(lport); inet->sport = htons(lport);
sk->sk_hashent = hash; sk->sk_hash = hash;
BUG_TRAP(sk_unhashed(sk)); BUG_TRAP(sk_unhashed(sk));
__sk_add_node(sk, &head->chain); __sk_add_node(sk, &head->chain);
sock_prot_inc_use(sk->sk_prot); sock_prot_inc_use(sk->sk_prot);

Просмотреть файл

@ -209,9 +209,11 @@ static __inline__ void __tcp_v6_hash(struct sock *sk)
lock = &tcp_hashinfo.lhash_lock; lock = &tcp_hashinfo.lhash_lock;
inet_listen_wlock(&tcp_hashinfo); inet_listen_wlock(&tcp_hashinfo);
} else { } else {
sk->sk_hashent = inet6_sk_ehashfn(sk, tcp_hashinfo.ehash_size); unsigned int hash;
list = &tcp_hashinfo.ehash[sk->sk_hashent].chain; sk->sk_hash = hash = inet6_sk_ehashfn(sk);
lock = &tcp_hashinfo.ehash[sk->sk_hashent].lock; hash &= (tcp_hashinfo.ehash_size - 1);
list = &tcp_hashinfo.ehash[hash].chain;
lock = &tcp_hashinfo.ehash[hash].lock;
write_lock(lock); write_lock(lock);
} }
@ -322,13 +324,13 @@ static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
const struct in6_addr *saddr = &np->daddr; const struct in6_addr *saddr = &np->daddr;
const int dif = sk->sk_bound_dev_if; const int dif = sk->sk_bound_dev_if;
const u32 ports = INET_COMBINED_PORTS(inet->dport, lport); const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
const int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport, unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport);
tcp_hashinfo.ehash_size); struct inet_ehash_bucket *head = inet_ehash_bucket(&tcp_hashinfo, hash);
struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash];
struct sock *sk2; struct sock *sk2;
const struct hlist_node *node; const struct hlist_node *node;
struct inet_timewait_sock *tw; struct inet_timewait_sock *tw;
prefetch(head->chain.first);
write_lock(&head->lock); write_lock(&head->lock);
/* Check TIME-WAIT sockets first. */ /* Check TIME-WAIT sockets first. */
@ -365,14 +367,14 @@ static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
/* And established part... */ /* And established part... */
sk_for_each(sk2, node, &head->chain) { sk_for_each(sk2, node, &head->chain) {
if (INET6_MATCH(sk2, saddr, daddr, ports, dif)) if (INET6_MATCH(sk2, hash, saddr, daddr, ports, dif))
goto not_unique; goto not_unique;
} }
unique: unique:
BUG_TRAP(sk_unhashed(sk)); BUG_TRAP(sk_unhashed(sk));
__sk_add_node(sk, &head->chain); __sk_add_node(sk, &head->chain);
sk->sk_hashent = hash; sk->sk_hash = hash;
sock_prot_inc_use(sk->sk_prot); sock_prot_inc_use(sk->sk_prot);
write_unlock(&head->lock); write_unlock(&head->lock);

Просмотреть файл

@ -393,10 +393,10 @@ META_COLLECTOR(int_sk_route_caps)
dst->value = skb->sk->sk_route_caps; dst->value = skb->sk->sk_route_caps;
} }
META_COLLECTOR(int_sk_hashent) META_COLLECTOR(int_sk_hash)
{ {
SKIP_NONLOCAL(skb); SKIP_NONLOCAL(skb);
dst->value = skb->sk->sk_hashent; dst->value = skb->sk->sk_hash;
} }
META_COLLECTOR(int_sk_lingertime) META_COLLECTOR(int_sk_lingertime)
@ -515,7 +515,7 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
[META_ID(SK_FORWARD_ALLOCS)] = META_FUNC(int_sk_fwd_alloc), [META_ID(SK_FORWARD_ALLOCS)] = META_FUNC(int_sk_fwd_alloc),
[META_ID(SK_ALLOCS)] = META_FUNC(int_sk_alloc), [META_ID(SK_ALLOCS)] = META_FUNC(int_sk_alloc),
[META_ID(SK_ROUTE_CAPS)] = META_FUNC(int_sk_route_caps), [META_ID(SK_ROUTE_CAPS)] = META_FUNC(int_sk_route_caps),
[META_ID(SK_HASHENT)] = META_FUNC(int_sk_hashent), [META_ID(SK_HASH)] = META_FUNC(int_sk_hash),
[META_ID(SK_LINGERTIME)] = META_FUNC(int_sk_lingertime), [META_ID(SK_LINGERTIME)] = META_FUNC(int_sk_lingertime),
[META_ID(SK_ACK_BACKLOG)] = META_FUNC(int_sk_ack_bl), [META_ID(SK_ACK_BACKLOG)] = META_FUNC(int_sk_ack_bl),
[META_ID(SK_MAX_ACK_BACKLOG)] = META_FUNC(int_sk_max_ack_bl), [META_ID(SK_MAX_ACK_BACKLOG)] = META_FUNC(int_sk_max_ack_bl),