In the tcp_conn structure, we represent IPv4 connections with IPv4-mapped IPv6 addresses in the single address field. However, we have different paths which will calculate different hashes for IPv4 and equivalent IPv4-mapped IPv6 addresses. This will cause problems for some future changes. Make the hash function work the same for these two cases, by always mapping IPv4 addresses into IPv4-mapped addresses before hashing. This involves some ugly temporaries, but later changes should improve this again. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- siphash.c | 1 + tcp.c | 33 +++++++++++++++------------------ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/siphash.c b/siphash.c index 37a6d73..516a508 100644 --- a/siphash.c +++ b/siphash.c @@ -104,6 +104,7 @@ * * Return: the 64-bit hash output */ +/* cppcheck-suppress unusedFunction */ uint64_t siphash_8b(const uint8_t *in, const uint64_t *k) { PREAMBLE(8); diff --git a/tcp.c b/tcp.c index 508d6e9..4645004 100644 --- a/tcp.c +++ b/tcp.c @@ -1315,30 +1315,27 @@ __attribute__((__noinline__)) /* See comment in Makefile */ static unsigned int tcp_hash(const struct ctx *c, int af, const void *addr, in_port_t tap_port, in_port_t sock_port) { + struct { + struct in6_addr addr; + in_port_t tap_port; + in_port_t sock_port; + } __attribute__((__packed__)) in = { + .tap_port = tap_port, + .sock_port = sock_port, + }; uint64_t b = 0; if (af == AF_INET) { - struct { - struct in_addr addr; - in_port_t tap_port; - in_port_t sock_port; - } __attribute__((__packed__)) in = { - *(struct in_addr *)addr, tap_port, sock_port, - }; - - b = siphash_8b((uint8_t *)&in, c->tcp.hash_secret); - } else if (af == AF_INET6) { - struct { - struct in6_addr addr; - in_port_t tap_port; - in_port_t sock_port; - } __attribute__((__packed__)) in = { - *(struct in6_addr *)addr, tap_port, sock_port, - }; + struct in6_addr v4mapped; - b = siphash_20b((uint8_t *)&in, c->tcp.hash_secret); + encode_ip4mapped_ip6(&v4mapped, addr); + in.addr = v4mapped; + } else { + in.addr = *(struct in6_addr *)addr; } + b = siphash_20b((uint8_t *)&in, c->tcp.hash_secret); + return (unsigned int)(b % TCP_HASH_TABLE_SIZE); } -- 2.38.1