const struct in6_addr *laddr, const u16 lport,
const struct in6_addr *faddr, const __be16 fport)
{
- u32 lhash, fhash;
+ u32 a, b, c;
+
+ /*
+ * 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.
+ */
+
+ 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);
- lhash = (__force u32)laddr->s6_addr32[3];
- fhash = __ipv6_addr_jhash(faddr, tcp_ipv6_hash_secret);
+ 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);
- return lport + __inet6_ehashfn(lhash, 0, fhash, fport,
- inet6_ehash_secret + net_hash_mix(net));
+ 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);