diff options
author | Eric Dumazet <edumazet@google.com> | 2012-07-18 04:11:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-18 14:28:46 -0400 |
commit | ddbe503203855939946430e39bae58de11b70b69 (patch) | |
tree | 1605a8d3b14a92819eb8ed47ae5a84c1b66e12f8 /net/sunrpc | |
parent | dc9059512c09d09b99de6cd3a8bc842507934cbb (diff) |
ipv6: add ipv6_addr_hash() helper
Introduce ipv6_addr_hash() helper doing a XOR on all bits
of an IPv6 address, with an optimized x86_64 version.
Use it in flow dissector, as suggested by Andrew McGregor,
to reduce hash collision probabilities in fq_codel (and other
users of flow dissector)
Use it in ip6_tunnel.c and use more bit shuffling, as suggested
by David Laight, as existing hash was ignoring most of them.
Use it in sunrpc and use more bit shuffling, using hash_32().
Use it in net/ipv6/addrconf.c, using hash_32() as well.
As a cleanup, use it in net/ipv4/tcp_metrics.c
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Andrew McGregor <andrewmcgr@gmail.com>
Cc: Dave Taht <dave.taht@gmail.com>
Cc: Tom Herbert <therbert@google.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Cc: Joe Perches <joe@perches.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/svcauth_unix.c | 22 |
1 files changed, 4 insertions, 18 deletions
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 2777fa896645..4d0129203733 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -104,23 +104,9 @@ static void ip_map_put(struct kref *kref) | |||
104 | kfree(im); | 104 | kfree(im); |
105 | } | 105 | } |
106 | 106 | ||
107 | #if IP_HASHBITS == 8 | 107 | static inline int hash_ip6(const struct in6_addr *ip) |
108 | /* hash_long on a 64 bit machine is currently REALLY BAD for | ||
109 | * IP addresses in reverse-endian (i.e. on a little-endian machine). | ||
110 | * So use a trivial but reliable hash instead | ||
111 | */ | ||
112 | static inline int hash_ip(__be32 ip) | ||
113 | { | ||
114 | int hash = (__force u32)ip ^ ((__force u32)ip>>16); | ||
115 | return (hash ^ (hash>>8)) & 0xff; | ||
116 | } | ||
117 | #endif | ||
118 | static inline int hash_ip6(struct in6_addr ip) | ||
119 | { | 108 | { |
120 | return (hash_ip(ip.s6_addr32[0]) ^ | 109 | return hash_32(ipv6_addr_hash(ip), IP_HASHBITS); |
121 | hash_ip(ip.s6_addr32[1]) ^ | ||
122 | hash_ip(ip.s6_addr32[2]) ^ | ||
123 | hash_ip(ip.s6_addr32[3])); | ||
124 | } | 110 | } |
125 | static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) | 111 | static int ip_map_match(struct cache_head *corig, struct cache_head *cnew) |
126 | { | 112 | { |
@@ -301,7 +287,7 @@ static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, | |||
301 | ip.m_addr = *addr; | 287 | ip.m_addr = *addr; |
302 | ch = sunrpc_cache_lookup(cd, &ip.h, | 288 | ch = sunrpc_cache_lookup(cd, &ip.h, |
303 | hash_str(class, IP_HASHBITS) ^ | 289 | hash_str(class, IP_HASHBITS) ^ |
304 | hash_ip6(*addr)); | 290 | hash_ip6(addr)); |
305 | 291 | ||
306 | if (ch) | 292 | if (ch) |
307 | return container_of(ch, struct ip_map, h); | 293 | return container_of(ch, struct ip_map, h); |
@@ -331,7 +317,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, | |||
331 | ip.h.expiry_time = expiry; | 317 | ip.h.expiry_time = expiry; |
332 | ch = sunrpc_cache_update(cd, &ip.h, &ipm->h, | 318 | ch = sunrpc_cache_update(cd, &ip.h, &ipm->h, |
333 | hash_str(ipm->m_class, IP_HASHBITS) ^ | 319 | hash_str(ipm->m_class, IP_HASHBITS) ^ |
334 | hash_ip6(ipm->m_addr)); | 320 | hash_ip6(&ipm->m_addr)); |
335 | if (!ch) | 321 | if (!ch) |
336 | return -ENOMEM; | 322 | return -ENOMEM; |
337 | cache_put(ch, cd); | 323 | cache_put(ch, cd); |