tcp: improve inet6_ehashfn() entropy
Instead of only using the 32 low order bits of the local address, use all of them. Xor net_hash_mix(net) with the 32 high order bits of the local address so that we can use __jhash_mix() three times. If we were hashing 4 extra bytes, we would need one __jhash_final() which is a bit expensive. Using net_hash_mix() at the beginning allows better register allocation. We no longer use a cascade of two jhash and inet6_ehash_secret, this was dubious/weak. Add a comment explaining why @lport is not part of the jhash computation. $ scripts/bloat-o-meter -t vmlinux.0 vmlinux.1 add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-24 (-24) Function old new delta inet6_ehashfn 330 306 -24 Total: Before=24855958, After=24855934, chg -0.00% Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Simon Horman <horms@kernel.org> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com> Link: https://patch.msgid.link/20260313120346.3378811-1-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>master
parent
6a33a70626
commit
854587e69e
|
|
@ -35,13 +35,43 @@ u32 inet6_ehashfn(const struct net *net,
|
|||
const struct in6_addr *laddr, const u16 lport,
|
||||
const struct in6_addr *faddr, const __be16 fport)
|
||||
{
|
||||
u32 lhash, fhash;
|
||||
u32 a, b, c;
|
||||
|
||||
lhash = (__force u32)laddr->s6_addr32[3];
|
||||
fhash = __ipv6_addr_jhash(faddr, tcp_ipv6_hash_secret);
|
||||
/*
|
||||
* Please look at jhash() implementation for reference.
|
||||
* Hash laddr + faddr + lport/fport + net_hash_mix.
|
||||
* Notes:
|
||||
* We combine laddr[0] (high order 32 bits of local address)
|
||||
* with net_hash_mix() to avoid using __jhash_final(a, b, c).
|
||||
*
|
||||
* We do not include JHASH_INITVAL + 36 contribution
|
||||
* to initial values of a, b, c.
|
||||
*/
|
||||
|
||||
return lport + __inet6_ehashfn(lhash, 0, fhash, fport,
|
||||
inet6_ehash_secret + net_hash_mix(net));
|
||||
a = b = c = tcp_ipv6_hash_secret;
|
||||
|
||||
a += (__force u32)laddr->s6_addr32[0] ^ net_hash_mix(net);
|
||||
b += (__force u32)laddr->s6_addr32[1];
|
||||
c += (__force u32)laddr->s6_addr32[2];
|
||||
__jhash_mix(a, b, c);
|
||||
|
||||
a += (__force u32)laddr->s6_addr32[3];
|
||||
b += (__force u32)faddr->s6_addr32[0];
|
||||
c += (__force u32)faddr->s6_addr32[1];
|
||||
__jhash_mix(a, b, c);
|
||||
|
||||
a += (__force u32)faddr->s6_addr32[2];
|
||||
b += (__force u32)faddr->s6_addr32[3];
|
||||
c += (__force u32)fport;
|
||||
__jhash_mix(a, b, c);
|
||||
|
||||
/* Note: We need to add @lport instead of fully hashing it.
|
||||
* See commits 9544d60a2605 ("inet: change lport contribution
|
||||
* to inet_ehashfn() and inet6_ehashfn()") and d4438ce68bf1
|
||||
* ("inet: call inet6_ehashfn() once from inet6_hash_connect()")
|
||||
* for references.
|
||||
*/
|
||||
return lport + c;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(inet6_ehashfn);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue