[INET]: speedup inet (tcp/dccp) lookups
authorEric Dumazet <dada1@cosmosbay.com>
Mon, 3 Oct 2005 21:13:38 +0000 (14:13 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 3 Oct 2005 21:13:38 +0000 (14:13 -0700)
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>
12 files changed:
include/linux/ipv6.h
include/linux/tc_ematch/tc_em_meta.h
include/net/inet6_hashtables.h
include/net/inet_hashtables.h
include/net/inet_timewait_sock.h
include/net/sock.h
net/atm/common.c
net/dccp/ipv4.c
net/ipv4/inet_timewait_sock.c
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c
net/sched/em_meta.c

index bb6f88e14061ed6d3543a632aebb7b616fca0a1e..e0b922785d985e5c2a03598303ad011cb0dbc9d4 100644 (file)
@@ -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)) && \
index 081b1ee8516edde81c7583d9248ef760c87b0f3f..e21937cf91d0e4510659566215260b13a9c9b6b8 100644 (file)
@@ -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,
index 03df3b157960cb711bccf0d44fab11127dde1b3b..5a2beed5a7701e0c69d7793a6eb3b60667abd84e 100644 (file)
 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. */
index 646b6ea7fe26f71f703cae6816e2d6a70f092bca..35f49e65e295c9cd89a04d010dbad7700f4a319d 100644 (file)
@@ -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;
index 3b070352e869822a86d137036c6937402096be76..4ade56ef3a4da8894a42978a7663d883219cc3df 100644 (file)
@@ -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;
index 8c48fbecb7cf8fc9e4828a81fdd9a3ca8bd35457..b6440805c4201a81fe58c2846faead77c3a4ca7e 100644 (file)
@@ -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;
        /*
index 801a5813ec60ab54f7dbbecb313e80a53c57c03a..63feea49fb139f6a0e96888c3f4f99c2325ac883 100644 (file)
@@ -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);
 }
 
index 40fe6afacde61b17559f582315c53110fb544fc4..ae088d1347af025359eb09e5a3a606386e66f948 100644 (file)
@@ -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);
index 4d1502a49852e42524ee3cb4f75f34e81212e9fb..f9076ef3a1a810b54ef5671d9620b5960cff8ac0 100644 (file)
@@ -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);
index 13dfb391cdf17a376c301c9f56973db93696c1d6..c85819d8474bba64dc433ca4fd93684bee7421c5 100644 (file)
@@ -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);
index 80643e6b346b97b36466fb23099898de5d7ebda3..d693cb988b78f99407f529e0a956e099e468c6ef 100644 (file)
@@ -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);
 
index 00eae5f9a01aab28d810e333f938de7e735e8dbf..cf68a59fdc5a4d4d6ac2bfbd5b63f99cd4574cee 100644 (file)
@@ -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),