[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:
Родитель
399de50bbb
Коммит
81c3d5470e
|
@ -372,8 +372,9 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk)
|
|||
#define inet_v6_ipv6only(__sk) 0
|
||||
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
|
||||
|
||||
#define INET6_MATCH(__sk, __saddr, __daddr, __ports, __dif) \
|
||||
(((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
|
||||
#define INET6_MATCH(__sk, __hash, __saddr, __daddr, __ports, __dif)\
|
||||
(((__sk)->sk_hash == (__hash)) && \
|
||||
((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
|
||||
((__sk)->sk_family == AF_INET6) && \
|
||||
ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \
|
||||
ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \
|
||||
|
|
|
@ -71,7 +71,7 @@ enum
|
|||
TCF_META_ID_SK_SNDBUF,
|
||||
TCF_META_ID_SK_ALLOCS,
|
||||
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_ACK_BACKLOG,
|
||||
TCF_META_ID_SK_MAX_ACK_BACKLOG,
|
||||
|
|
|
@ -26,19 +26,18 @@
|
|||
struct inet_hashinfo;
|
||||
|
||||
/* 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,
|
||||
const struct in6_addr *faddr, const u16 fport,
|
||||
const int ehash_size)
|
||||
static inline unsigned int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport,
|
||||
const struct in6_addr *faddr, const u16 fport)
|
||||
{
|
||||
int hashent = (lport ^ fport);
|
||||
unsigned int hashent = (lport ^ fport);
|
||||
|
||||
hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
|
||||
hashent ^= hashent >> 16;
|
||||
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 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 __u16 lport = inet->num;
|
||||
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
|
||||
* have wildcards anyways.
|
||||
*/
|
||||
const int hash = inet6_ehashfn(daddr, hnum, saddr, sport,
|
||||
hashinfo->ehash_size);
|
||||
struct inet_ehash_bucket *head = &hashinfo->ehash[hash];
|
||||
unsigned int hash = inet6_ehashfn(daddr, hnum, saddr, sport);
|
||||
struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash);
|
||||
|
||||
prefetch(head->chain.first);
|
||||
read_lock(&head->lock);
|
||||
sk_for_each(sk, node, &head->chain) {
|
||||
/* 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! */
|
||||
}
|
||||
/* Must check for a TIME_WAIT'er before going to listener hash. */
|
||||
|
|
|
@ -108,7 +108,7 @@ struct inet_hashinfo {
|
|||
struct inet_bind_hashbucket *bhash;
|
||||
|
||||
int bhash_size;
|
||||
int ehash_size;
|
||||
unsigned int ehash_size;
|
||||
|
||||
/* 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
|
||||
|
@ -130,17 +130,16 @@ struct inet_hashinfo {
|
|||
int port_rover;
|
||||
};
|
||||
|
||||
static inline int inet_ehashfn(const __u32 laddr, const __u16 lport,
|
||||
const __u32 faddr, const __u16 fport,
|
||||
const int ehash_size)
|
||||
static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport,
|
||||
const __u32 faddr, const __u16 fport)
|
||||
{
|
||||
int h = (laddr ^ lport) ^ (faddr ^ fport);
|
||||
unsigned int h = (laddr ^ lport) ^ (faddr ^ fport);
|
||||
h ^= h >> 16;
|
||||
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 __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 __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 *
|
||||
|
@ -235,9 +241,11 @@ static inline void __inet_hash(struct inet_hashinfo *hashinfo,
|
|||
lock = &hashinfo->lhash_lock;
|
||||
inet_listen_wlock(hashinfo);
|
||||
} else {
|
||||
sk->sk_hashent = inet_sk_ehashfn(sk, hashinfo->ehash_size);
|
||||
list = &hashinfo->ehash[sk->sk_hashent].chain;
|
||||
lock = &hashinfo->ehash[sk->sk_hashent].lock;
|
||||
struct inet_ehash_bucket *head;
|
||||
sk->sk_hash = inet_sk_ehashfn(sk);
|
||||
head = inet_ehash_bucket(hashinfo, sk->sk_hash);
|
||||
list = &head->chain;
|
||||
lock = &head->lock;
|
||||
write_lock(lock);
|
||||
}
|
||||
__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);
|
||||
lock = &hashinfo->lhash_lock;
|
||||
} else {
|
||||
struct inet_ehash_bucket *head = &hashinfo->ehash[sk->sk_hashent];
|
||||
lock = &head->lock;
|
||||
write_lock_bh(&head->lock);
|
||||
lock = &inet_ehash_bucket(hashinfo, sk->sk_hash)->lock;
|
||||
write_lock_bh(lock);
|
||||
}
|
||||
|
||||
if (__sk_del_node_init(sk))
|
||||
|
@ -337,23 +344,27 @@ sherry_cache:
|
|||
#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
|
||||
const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr));
|
||||
#endif /* __BIG_ENDIAN */
|
||||
#define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
|
||||
(((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \
|
||||
#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))))
|
||||
#define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\
|
||||
(((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \
|
||||
#define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
|
||||
(((__sk)->sk_hash == (__hash)) && \
|
||||
((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \
|
||||
((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
|
||||
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
|
||||
#else /* 32-bit arch */
|
||||
#define INET_ADDR_COOKIE(__name, __saddr, __daddr)
|
||||
#define INET_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif) \
|
||||
((inet_sk(__sk)->daddr == (__saddr)) && \
|
||||
#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif) \
|
||||
(((__sk)->sk_hash == (__hash)) && \
|
||||
(inet_sk(__sk)->daddr == (__saddr)) && \
|
||||
(inet_sk(__sk)->rcv_saddr == (__daddr)) && \
|
||||
((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
|
||||
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
|
||||
#define INET_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif) \
|
||||
((inet_twsk(__sk)->tw_daddr == (__saddr)) && \
|
||||
#define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \
|
||||
(((__sk)->sk_hash == (__hash)) && \
|
||||
(inet_twsk(__sk)->tw_daddr == (__saddr)) && \
|
||||
(inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \
|
||||
((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
|
||||
(!((__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
|
||||
* have wildcards anyways.
|
||||
*/
|
||||
const int hash = inet_ehashfn(daddr, hnum, saddr, sport, hashinfo->ehash_size);
|
||||
struct inet_ehash_bucket *head = &hashinfo->ehash[hash];
|
||||
unsigned int hash = inet_ehashfn(daddr, hnum, saddr, sport);
|
||||
struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash);
|
||||
|
||||
prefetch(head->chain.first);
|
||||
read_lock(&head->lock);
|
||||
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! */
|
||||
}
|
||||
|
||||
/* Must check for a TIME_WAIT'er before going to listener hash. */
|
||||
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;
|
||||
}
|
||||
sk = NULL;
|
||||
|
|
|
@ -112,6 +112,7 @@ struct inet_timewait_sock {
|
|||
#define tw_node __tw_common.skc_node
|
||||
#define tw_bind_node __tw_common.skc_bind_node
|
||||
#define tw_refcnt __tw_common.skc_refcnt
|
||||
#define tw_hash __tw_common.skc_hash
|
||||
#define tw_prot __tw_common.skc_prot
|
||||
volatile unsigned char tw_substate;
|
||||
/* 3 bits hole, try to pack */
|
||||
|
@ -126,7 +127,6 @@ struct inet_timewait_sock {
|
|||
/* And these are ours. */
|
||||
__u8 tw_ipv6only:1;
|
||||
/* 31 bits hole, try to pack */
|
||||
int tw_hashent;
|
||||
int tw_timeout;
|
||||
unsigned long tw_ttd;
|
||||
struct inet_bind_bucket *tw_tb;
|
||||
|
|
|
@ -99,6 +99,7 @@ struct proto;
|
|||
* @skc_node: main hash linkage for various protocol lookup tables
|
||||
* @skc_bind_node: bind hash linkage for various protocol lookup tables
|
||||
* @skc_refcnt: reference count
|
||||
* @skc_hash: hash value used with various protocol lookup tables
|
||||
* @skc_prot: protocol handlers inside a network family
|
||||
*
|
||||
* 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_bind_node;
|
||||
atomic_t skc_refcnt;
|
||||
unsigned int skc_hash;
|
||||
struct proto *skc_prot;
|
||||
};
|
||||
|
||||
|
@ -139,7 +141,6 @@ struct sock_common {
|
|||
* @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets
|
||||
* @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO)
|
||||
* @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_callback_lock: used with the callbacks in the end of this struct
|
||||
* @sk_error_queue: rarely used
|
||||
|
@ -186,6 +187,7 @@ struct sock {
|
|||
#define sk_node __sk_common.skc_node
|
||||
#define sk_bind_node __sk_common.skc_bind_node
|
||||
#define sk_refcnt __sk_common.skc_refcnt
|
||||
#define sk_hash __sk_common.skc_hash
|
||||
#define sk_prot __sk_common.skc_prot
|
||||
unsigned char sk_shutdown : 2,
|
||||
sk_no_check : 2,
|
||||
|
@ -208,7 +210,6 @@ struct sock {
|
|||
unsigned int sk_allocation;
|
||||
int sk_sndbuf;
|
||||
int sk_route_caps;
|
||||
int sk_hashent;
|
||||
unsigned long sk_flags;
|
||||
unsigned long sk_lingertime;
|
||||
/*
|
||||
|
|
|
@ -46,7 +46,7 @@ static void __vcc_insert_socket(struct sock *sk)
|
|||
struct atm_vcc *vcc = atm_sk(sk);
|
||||
struct hlist_head *head = &vcc_hash[vcc->vci &
|
||||
(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);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,27 +62,27 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
|
|||
const int dif = sk->sk_bound_dev_if;
|
||||
INET_ADDR_COOKIE(acookie, saddr, daddr)
|
||||
const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
|
||||
const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport,
|
||||
dccp_hashinfo.ehash_size);
|
||||
struct inet_ehash_bucket *head = &dccp_hashinfo.ehash[hash];
|
||||
unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
|
||||
struct inet_ehash_bucket *head = inet_ehash_bucket(&dccp_hashinfo, hash);
|
||||
const struct sock *sk2;
|
||||
const struct hlist_node *node;
|
||||
struct inet_timewait_sock *tw;
|
||||
|
||||
prefetch(head->chain.first);
|
||||
write_lock(&head->lock);
|
||||
|
||||
/* Check TIME-WAIT sockets first. */
|
||||
sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) {
|
||||
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;
|
||||
}
|
||||
tw = NULL;
|
||||
|
||||
/* And established part... */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
|
|||
* in hash table socket with a funny identity. */
|
||||
inet->num = lport;
|
||||
inet->sport = htons(lport);
|
||||
sk->sk_hashent = hash;
|
||||
sk->sk_hash = hash;
|
||||
BUG_TRAP(sk_unhashed(sk));
|
||||
__sk_add_node(sk, &head->chain);
|
||||
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_bucket *tb;
|
||||
/* 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);
|
||||
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_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;
|
||||
/* Step 1: Put TW into bind hash. Original socket stays there too.
|
||||
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_family = sk->sk_family;
|
||||
tw->tw_reuse = sk->sk_reuse;
|
||||
tw->tw_hashent = sk->sk_hashent;
|
||||
tw->tw_hash = sk->sk_hash;
|
||||
tw->tw_ipv6only = 0;
|
||||
tw->tw_prot = sk->sk_prot_creator;
|
||||
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;
|
||||
INET_ADDR_COOKIE(acookie, saddr, daddr)
|
||||
const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
|
||||
const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, tcp_hashinfo.ehash_size);
|
||||
struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash];
|
||||
unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
|
||||
struct inet_ehash_bucket *head = inet_ehash_bucket(&tcp_hashinfo, hash);
|
||||
struct sock *sk2;
|
||||
const struct hlist_node *node;
|
||||
struct inet_timewait_sock *tw;
|
||||
|
||||
prefetch(head->chain.first);
|
||||
write_lock(&head->lock);
|
||||
|
||||
/* Check TIME-WAIT sockets first. */
|
||||
sk_for_each(sk2, node, &(head + tcp_hashinfo.ehash_size)->chain) {
|
||||
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);
|
||||
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... */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -188,7 +189,7 @@ unique:
|
|||
* in hash table socket with a funny identity. */
|
||||
inet->num = lport;
|
||||
inet->sport = htons(lport);
|
||||
sk->sk_hashent = hash;
|
||||
sk->sk_hash = hash;
|
||||
BUG_TRAP(sk_unhashed(sk));
|
||||
__sk_add_node(sk, &head->chain);
|
||||
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;
|
||||
inet_listen_wlock(&tcp_hashinfo);
|
||||
} else {
|
||||
sk->sk_hashent = inet6_sk_ehashfn(sk, tcp_hashinfo.ehash_size);
|
||||
list = &tcp_hashinfo.ehash[sk->sk_hashent].chain;
|
||||
lock = &tcp_hashinfo.ehash[sk->sk_hashent].lock;
|
||||
unsigned int hash;
|
||||
sk->sk_hash = hash = inet6_sk_ehashfn(sk);
|
||||
hash &= (tcp_hashinfo.ehash_size - 1);
|
||||
list = &tcp_hashinfo.ehash[hash].chain;
|
||||
lock = &tcp_hashinfo.ehash[hash].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 int dif = sk->sk_bound_dev_if;
|
||||
const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
|
||||
const int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport,
|
||||
tcp_hashinfo.ehash_size);
|
||||
struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[hash];
|
||||
unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, inet->dport);
|
||||
struct inet_ehash_bucket *head = inet_ehash_bucket(&tcp_hashinfo, hash);
|
||||
struct sock *sk2;
|
||||
const struct hlist_node *node;
|
||||
struct inet_timewait_sock *tw;
|
||||
|
||||
prefetch(head->chain.first);
|
||||
write_lock(&head->lock);
|
||||
|
||||
/* Check TIME-WAIT sockets first. */
|
||||
|
@ -365,14 +367,14 @@ static int __tcp_v6_check_established(struct sock *sk, const __u16 lport,
|
|||
|
||||
/* And established part... */
|
||||
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;
|
||||
}
|
||||
|
||||
unique:
|
||||
BUG_TRAP(sk_unhashed(sk));
|
||||
__sk_add_node(sk, &head->chain);
|
||||
sk->sk_hashent = hash;
|
||||
sk->sk_hash = hash;
|
||||
sock_prot_inc_use(sk->sk_prot);
|
||||
write_unlock(&head->lock);
|
||||
|
||||
|
|
|
@ -393,10 +393,10 @@ META_COLLECTOR(int_sk_route_caps)
|
|||
dst->value = skb->sk->sk_route_caps;
|
||||
}
|
||||
|
||||
META_COLLECTOR(int_sk_hashent)
|
||||
META_COLLECTOR(int_sk_hash)
|
||||
{
|
||||
SKIP_NONLOCAL(skb);
|
||||
dst->value = skb->sk->sk_hashent;
|
||||
dst->value = skb->sk->sk_hash;
|
||||
}
|
||||
|
||||
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_ALLOCS)] = META_FUNC(int_sk_alloc),
|
||||
[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_ACK_BACKLOG)] = META_FUNC(int_sk_ack_bl),
|
||||
[META_ID(SK_MAX_ACK_BACKLOG)] = META_FUNC(int_sk_max_ack_bl),
|
||||
|
|
Загрузка…
Ссылка в новой задаче