IPv4 are now hashed to match equivalent IPv4-mapped IPv6 addresses. This means we can avoid having IPv4 specific paths in the lower level hash and match functions, instead just dealing with the equivalent IPv4-mapped IPv6 addresses. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- tcp.c | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/tcp.c b/tcp.c index dfa73a3..3816a1c 100644 --- a/tcp.c +++ b/tcp.c @@ -1275,23 +1275,16 @@ static int tcp_opt_get(const char *opts, size_t len, uint8_t type_find, /** * tcp_hash_match() - Check if a connection entry matches address and ports * @conn: Connection entry to match against - * @af: Address family, AF_INET or AF_INET6 - * @addr: Remote address, pointer to in_addr or in6_addr + * @addr: Remote address, may be IPv4-mapped * @tap_port: tap-facing port * @sock_port: Socket-facing port * * Return: 1 on match, 0 otherwise */ -static int tcp_hash_match(const struct tcp_conn *conn, int af, const void *addr, +static int tcp_hash_match(const struct tcp_conn *conn, + const struct in6_addr *addr, in_port_t tap_port, in_port_t sock_port) { - struct in6_addr v4mapped; - - if (af == AF_INET) { - encode_ip4mapped_ip6(&v4mapped, addr); - addr = &v4mapped; - } - if (IN6_ARE_ADDR_EQUAL(&conn->a.a6, addr) && conn->tap_port == tap_port && conn->sock_port == sock_port) return 1; @@ -1302,8 +1295,7 @@ static int tcp_hash_match(const struct tcp_conn *conn, int af, const void *addr, /** * tcp_hash() - Calculate hash value for connection given address and ports * @c: Execution context - * @af: Address family, AF_INET or AF_INET6 - * @addr: Remote address, pointer to in_addr or in6_addr + * @addr: Remote address, may be IPv4-mapped * @tap_port: tap-facing port * @sock_port: Socket-facing port * @@ -1312,7 +1304,7 @@ static int tcp_hash_match(const struct tcp_conn *conn, int af, const void *addr, #if TCP_HASH_NOINLINE __attribute__((__noinline__)) /* See comment in Makefile */ #endif -static unsigned int tcp_hash(const struct ctx *c, int af, const void *addr, +static unsigned int tcp_hash(const struct ctx *c, const struct in6_addr *addr, in_port_t tap_port, in_port_t sock_port) { struct { @@ -1320,20 +1312,10 @@ static unsigned int tcp_hash(const struct ctx *c, int af, const void *addr, in_port_t tap_port; in_port_t sock_port; } __attribute__((__packed__)) in = { - .tap_port = tap_port, - .sock_port = sock_port, + *addr, tap_port, sock_port, }; uint64_t b = 0; - if (af == AF_INET) { - struct in6_addr v4mapped; - - 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); @@ -1348,7 +1330,7 @@ static void tcp_hash_insert(const struct ctx *c, struct tcp_conn *conn) { int b; - b = tcp_hash(c, AF_INET6, &conn->a.a6, conn->tap_port, conn->sock_port); + b = tcp_hash(c, &conn->a.a6, conn->tap_port, conn->sock_port); conn->next_index = tc_hash[b] ? tc_hash[b] - tc : -1; tc_hash[b] = conn; conn->hash_bucket = b; @@ -1422,11 +1404,19 @@ static struct tcp_conn *tcp_hash_lookup(const struct ctx *c, int af, const void *addr, in_port_t tap_port, in_port_t sock_port) { - int b = tcp_hash(c, af, addr, tap_port, sock_port); + struct in6_addr v4mapped; struct tcp_conn *conn; + int b; + + if (af == AF_INET) { + encode_ip4mapped_ip6(&v4mapped, addr); + addr = &v4mapped; + } + + b = tcp_hash(c, addr, tap_port, sock_port); for (conn = tc_hash[b]; conn; conn = CONN_OR_NULL(conn->next_index)) { - if (tcp_hash_match(conn, af, addr, tap_port, sock_port)) + if (tcp_hash_match(conn, addr, tap_port, sock_port)) return conn; } -- 2.38.1