aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-11-08 05:17:30 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-08 23:53:05 -0500
commitd4cada4ae1c012815f95fa507eb86a0ae9d607d7 (patch)
tree23cdfb3763c9140ae095bf8095c3e6b16f7b48f3
parentfdcc8aa953a1123a289791dd192090651036d593 (diff)
udp: split sk_hash into two u16 hashes
Union sk_hash with two u16 hashes for udp (no extra memory taken) One 16 bits hash on (local port) value (the previous udp 'hash') One 16 bits hash on (local address, local port) values, initialized but not yet used. This second hash is using jenkin hash for better distribution. Because the 'port' is xored later, a partial hash is performed on local address + net_hash_mix(net) Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/udp.h2
-rw-r--r--include/net/sock.h6
-rw-r--r--net/ipv4/udp.c25
-rw-r--r--net/ipv6/udp.c27
4 files changed, 51 insertions, 9 deletions
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 832361e3e59..5b4b5274e68 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -55,6 +55,8 @@ static inline int udp_hashfn(struct net *net, unsigned num, unsigned mask)
55struct udp_sock { 55struct udp_sock {
56 /* inet_sock has to be the first member */ 56 /* inet_sock has to be the first member */
57 struct inet_sock inet; 57 struct inet_sock inet;
58#define udp_port_hash inet.sk.__sk_common.skc_u16hashes[0]
59#define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1]
58 int pending; /* Any pending frames ? */ 60 int pending; /* Any pending frames ? */
59 unsigned int corkflag; /* Cork is required */ 61 unsigned int corkflag; /* Cork is required */
60 __u16 encap_type; /* Is this an Encapsulation socket? */ 62 __u16 encap_type; /* Is this an Encapsulation socket? */
diff --git a/include/net/sock.h b/include/net/sock.h
index 55de3bd719a..827366b6268 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -109,6 +109,7 @@ struct net;
109 * @skc_refcnt: reference count 109 * @skc_refcnt: reference count
110 * @skc_tx_queue_mapping: tx queue number for this connection 110 * @skc_tx_queue_mapping: tx queue number for this connection
111 * @skc_hash: hash value used with various protocol lookup tables 111 * @skc_hash: hash value used with various protocol lookup tables
112 * @skc_u16hashes: two u16 hash values used by UDP lookup tables
112 * @skc_family: network address family 113 * @skc_family: network address family
113 * @skc_state: Connection state 114 * @skc_state: Connection state
114 * @skc_reuse: %SO_REUSEADDR setting 115 * @skc_reuse: %SO_REUSEADDR setting
@@ -131,7 +132,10 @@ struct sock_common {
131 atomic_t skc_refcnt; 132 atomic_t skc_refcnt;
132 int skc_tx_queue_mapping; 133 int skc_tx_queue_mapping;
133 134
134 unsigned int skc_hash; 135 union {
136 unsigned int skc_hash;
137 __u16 skc_u16hashes[2];
138 };
135 unsigned short skc_family; 139 unsigned short skc_family;
136 volatile unsigned char skc_state; 140 volatile unsigned char skc_state;
137 unsigned char skc_reuse; 141 unsigned char skc_reuse;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index ffc837643a0..af72de1c869 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -138,13 +138,14 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
138 sk_nulls_for_each(sk2, node, &hslot->head) 138 sk_nulls_for_each(sk2, node, &hslot->head)
139 if (net_eq(sock_net(sk2), net) && 139 if (net_eq(sock_net(sk2), net) &&
140 sk2 != sk && 140 sk2 != sk &&
141 (bitmap || sk2->sk_hash == num) && 141 (bitmap || udp_sk(sk2)->udp_port_hash == num) &&
142 (!sk2->sk_reuse || !sk->sk_reuse) && 142 (!sk2->sk_reuse || !sk->sk_reuse) &&
143 (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if 143 (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
144 || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && 144 || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
145 (*saddr_comp)(sk, sk2)) { 145 (*saddr_comp)(sk, sk2)) {
146 if (bitmap) 146 if (bitmap)
147 __set_bit(sk2->sk_hash >> log, bitmap); 147 __set_bit(udp_sk(sk2)->udp_port_hash >> log,
148 bitmap);
148 else 149 else
149 return 1; 150 return 1;
150 } 151 }
@@ -215,7 +216,8 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
215 } 216 }
216found: 217found:
217 inet_sk(sk)->inet_num = snum; 218 inet_sk(sk)->inet_num = snum;
218 sk->sk_hash = snum; 219 udp_sk(sk)->udp_port_hash = snum;
220 udp_sk(sk)->udp_portaddr_hash ^= snum;
219 if (sk_unhashed(sk)) { 221 if (sk_unhashed(sk)) {
220 sk_nulls_add_node_rcu(sk, &hslot->head); 222 sk_nulls_add_node_rcu(sk, &hslot->head);
221 hslot->count++; 223 hslot->count++;
@@ -238,8 +240,19 @@ static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
238 inet1->inet_rcv_saddr == inet2->inet_rcv_saddr)); 240 inet1->inet_rcv_saddr == inet2->inet_rcv_saddr));
239} 241}
240 242
243static unsigned int udp4_portaddr_hash(struct net *net, __be32 saddr,
244 unsigned int port)
245{
246 return jhash_1word(saddr, net_hash_mix(net)) ^ port;
247}
248
241int udp_v4_get_port(struct sock *sk, unsigned short snum) 249int udp_v4_get_port(struct sock *sk, unsigned short snum)
242{ 250{
251 /* precompute partial secondary hash */
252 udp_sk(sk)->udp_portaddr_hash =
253 udp4_portaddr_hash(sock_net(sk),
254 inet_sk(sk)->inet_rcv_saddr,
255 0);
243 return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal); 256 return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal);
244} 257}
245 258
@@ -249,7 +262,7 @@ static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr,
249{ 262{
250 int score = -1; 263 int score = -1;
251 264
252 if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && 265 if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum &&
253 !ipv6_only_sock(sk)) { 266 !ipv6_only_sock(sk)) {
254 struct inet_sock *inet = inet_sk(sk); 267 struct inet_sock *inet = inet_sk(sk);
255 268
@@ -360,7 +373,7 @@ static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk,
360 struct inet_sock *inet = inet_sk(s); 373 struct inet_sock *inet = inet_sk(s);
361 374
362 if (!net_eq(sock_net(s), net) || 375 if (!net_eq(sock_net(s), net) ||
363 s->sk_hash != hnum || 376 udp_sk(s)->udp_port_hash != hnum ||
364 (inet->inet_daddr && inet->inet_daddr != rmt_addr) || 377 (inet->inet_daddr && inet->inet_daddr != rmt_addr) ||
365 (inet->inet_dport != rmt_port && inet->inet_dport) || 378 (inet->inet_dport != rmt_port && inet->inet_dport) ||
366 (inet->inet_rcv_saddr && 379 (inet->inet_rcv_saddr &&
@@ -1050,7 +1063,7 @@ void udp_lib_unhash(struct sock *sk)
1050 if (sk_hashed(sk)) { 1063 if (sk_hashed(sk)) {
1051 struct udp_table *udptable = sk->sk_prot->h.udp_table; 1064 struct udp_table *udptable = sk->sk_prot->h.udp_table;
1052 struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk), 1065 struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk),
1053 sk->sk_hash); 1066 udp_sk(sk)->udp_port_hash);
1054 1067
1055 spin_lock_bh(&hslot->lock); 1068 spin_lock_bh(&hslot->lock);
1056 if (sk_nulls_del_node_init_rcu(sk)) { 1069 if (sk_nulls_del_node_init_rcu(sk)) {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 5bc7cdbf030..1e5fadd997b 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -81,8 +81,30 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
81 return 0; 81 return 0;
82} 82}
83 83
84static unsigned int udp6_portaddr_hash(struct net *net,
85 const struct in6_addr *addr6,
86 unsigned int port)
87{
88 unsigned int hash, mix = net_hash_mix(net);
89
90 if (ipv6_addr_any(addr6))
91 hash = jhash_1word(0, mix);
92 else if (ipv6_addr_type(addr6) == IPV6_ADDR_MAPPED)
93 hash = jhash_1word(addr6->s6_addr32[3], mix);
94 else
95 hash = jhash2(addr6->s6_addr32, 4, mix);
96
97 return hash ^ port;
98}
99
100
84int udp_v6_get_port(struct sock *sk, unsigned short snum) 101int udp_v6_get_port(struct sock *sk, unsigned short snum)
85{ 102{
103 /* precompute partial secondary hash */
104 udp_sk(sk)->udp_portaddr_hash =
105 udp6_portaddr_hash(sock_net(sk),
106 &inet6_sk(sk)->rcv_saddr,
107 0);
86 return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); 108 return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal);
87} 109}
88 110
@@ -94,7 +116,7 @@ static inline int compute_score(struct sock *sk, struct net *net,
94{ 116{
95 int score = -1; 117 int score = -1;
96 118
97 if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && 119 if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum &&
98 sk->sk_family == PF_INET6) { 120 sk->sk_family == PF_INET6) {
99 struct ipv6_pinfo *np = inet6_sk(sk); 121 struct ipv6_pinfo *np = inet6_sk(sk);
100 struct inet_sock *inet = inet_sk(sk); 122 struct inet_sock *inet = inet_sk(sk);
@@ -415,7 +437,8 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk,
415 if (!net_eq(sock_net(s), net)) 437 if (!net_eq(sock_net(s), net))
416 continue; 438 continue;
417 439
418 if (s->sk_hash == num && s->sk_family == PF_INET6) { 440 if (udp_sk(s)->udp_port_hash == num &&
441 s->sk_family == PF_INET6) {
419 struct ipv6_pinfo *np = inet6_sk(s); 442 struct ipv6_pinfo *np = inet6_sk(s);
420 if (inet->inet_dport) { 443 if (inet->inet_dport) {
421 if (inet->inet_dport != rmt_port) 444 if (inet->inet_dport != rmt_port)