Skip to content

Commit

Permalink
netfilter: conntrack: don't fold port numbers into addresses before h…
Browse files Browse the repository at this point in the history
…ashing

[ Upstream commit eaf9e71 ]

Originally this used jhash2() over tuple and folded the zone id,
the pernet hash value, destination port and l4 protocol number into the
32bit seed value.

When the switch to siphash was done, I used an on-stack temporary
buffer to build a suitable key to be hashed via siphash().

But this showed up as performance regression, so I got rid of
the temporary copy and collected to-be-hashed data in 4 u64 variables.

This makes it easy to build tuples that produce the same hash, which isn't
desirable even though chain lengths are limited.

Switch back to plain siphash, but just like with jhash2(), take advantage
of the fact that most of to-be-hashed data is already in a suitable order.

Use an empty struct as annotation in 'struct nf_conntrack_tuple' to mark
last member that can be used as hash input.

The only remaining data that isn't present in the tuple structure are the
zone identifier and the pernet hash: fold those into the key.

Fixes: d2c806a ("netfilter: conntrack: use siphash_4u64")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Florian Westphal authored and gregkh committed Jul 23, 2023
1 parent e93cbd7 commit 027685f
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 13 deletions.
3 changes: 3 additions & 0 deletions include/net/netfilter/nf_conntrack_tuple.h
Expand Up @@ -67,6 +67,9 @@ struct nf_conntrack_tuple {
/* The protocol. */
u_int8_t protonum;

/* The direction must be ignored for the tuplehash */
struct { } __nfct_hash_offsetend;

/* The direction (for tuplehash) */
u_int8_t dir;
} dst;
Expand Down
20 changes: 7 additions & 13 deletions net/netfilter/nf_conntrack_core.c
Expand Up @@ -211,24 +211,18 @@ static u32 hash_conntrack_raw(const struct nf_conntrack_tuple *tuple,
unsigned int zoneid,
const struct net *net)
{
u64 a, b, c, d;
siphash_key_t key;

get_random_once(&nf_conntrack_hash_rnd, sizeof(nf_conntrack_hash_rnd));

/* The direction must be ignored, handle usable tuplehash members manually */
a = (u64)tuple->src.u3.all[0] << 32 | tuple->src.u3.all[3];
b = (u64)tuple->dst.u3.all[0] << 32 | tuple->dst.u3.all[3];
key = nf_conntrack_hash_rnd;

c = (__force u64)tuple->src.u.all << 32 | (__force u64)tuple->dst.u.all << 16;
c |= tuple->dst.protonum;
key.key[0] ^= zoneid;
key.key[1] ^= net_hash_mix(net);

d = (u64)zoneid << 32 | net_hash_mix(net);

/* IPv4: u3.all[1,2,3] == 0 */
c ^= (u64)tuple->src.u3.all[1] << 32 | tuple->src.u3.all[2];
d += (u64)tuple->dst.u3.all[1] << 32 | tuple->dst.u3.all[2];

return (u32)siphash_4u64(a, b, c, d, &nf_conntrack_hash_rnd);
return siphash((void *)tuple,
offsetofend(struct nf_conntrack_tuple, dst.__nfct_hash_offsetend),
&key);
}

static u32 scale_hash(u32 hash)
Expand Down

0 comments on commit 027685f

Please sign in to comment.