diff --git a/Makefile b/Makefile index c28556f..af3bc75 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ FLAGS += -DDUAL_STACK_SOCKETS=$(DUAL_STACK_SOCKETS) PASST_SRCS = arch.c arp.c checksum.c conf.c dhcp.c dhcpv6.c icmp.c igmp.c \ isolation.c lineread.c log.c mld.c ndp.c netlink.c packet.c passt.c \ - pasta.c pcap.c siphash.c tap.c tcp.c tcp_splice.c udp.c util.c + pasta.c pcap.c tap.c tcp.c tcp_splice.c udp.c util.c QRAP_SRCS = qrap.c SRCS = $(PASST_SRCS) $(QRAP_SRCS) diff --git a/inany.h b/inany.h index aadb20b..85a18e3 100644 --- a/inany.h +++ b/inany.h @@ -14,8 +14,9 @@ * @v4mapped.zero: All zero-bits for an IPv4 address * @v4mapped.one: All one-bits for an IPv4 address * @v4mapped.a4: If @a6 is an IPv4 mapped address, the IPv4 address + * @u64: As an array of u64s (solely for hashing) * - * @v4mapped shouldn't be accessed except via helpers. + * @v4mapped and @u64 shouldn't be accessed except via helpers. */ union inany_addr { struct in6_addr a6; @@ -24,7 +25,10 @@ union inany_addr { uint8_t one[2]; struct in_addr a4; } v4mapped; + uint32_t u32[4]; }; +static_assert(sizeof(union inany_addr) == sizeof(struct in6_addr)); +static_assert(_Alignof(union inany_addr) == _Alignof(uint32_t)); /** inany_v4 - Extract IPv4 address, if present, from IPv[46] address * @addr: IPv4 or IPv6 address @@ -94,4 +98,15 @@ static inline void inany_from_sockaddr(union inany_addr *aa, in_port_t *port, } } +/** inany_siphash_feed- Fold IPv[46] address into an in-progress siphash + * @state: siphash state + * @aa: inany to hash + */ +static inline void inany_siphash_feed(struct siphash_state *state, + const union inany_addr *aa) +{ + siphash_feed(state, (uint64_t)aa->u32[0] << 32 | aa->u32[1]); + siphash_feed(state, (uint64_t)aa->u32[2] << 32 | aa->u32[3]); +} + #endif /* INANY_H */ diff --git a/siphash.c b/siphash.c deleted file mode 100644 index d2b068c..0000000 --- a/siphash.c +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -/* PASST - Plug A Simple Socket Transport - * for qemu/UNIX domain socket mode - * - * PASTA - Pack A Subtle Tap Abstraction - * for network namespace/tap device mode - * - * siphash.c - SipHash routines - * - * Copyright (c) 2020-2021 Red Hat GmbH - * Author: Stefano Brivio - */ - -#include -#include - -#include "siphash.h" - -/** - * siphash_8b() - Table index or timestamp offset for TCP over IPv4 (8 bytes in) - * @in: Input data (remote address and two ports, or two addresses) - * @k: Hash function key, 128 bits - * - * Return: the 64-bit hash output - */ -/* NOLINTNEXTLINE(clang-diagnostic-unknown-attributes) */ -__attribute__((optimize("-fno-strict-aliasing"))) /* See csum_16b() */ -/* cppcheck-suppress unusedFunction */ -uint64_t siphash_8b(const uint8_t *in, const uint64_t *k) -{ - struct siphash_state state = SIPHASH_INIT(k); - - siphash_feed(&state, *(uint64_t *)in); - - return siphash_final(&state, 8, 0); -} - -/** - * siphash_12b() - Initial sequence number for TCP over IPv4 (12 bytes in) - * @in: Input data (two addresses, two ports) - * @k: Hash function key, 128 bits - * - * Return: the 64-bit hash output - */ -/* NOLINTNEXTLINE(clang-diagnostic-unknown-attributes) */ -__attribute__((optimize("-fno-strict-aliasing"))) /* See csum_16b() */ -/* cppcheck-suppress unusedFunction */ -uint64_t siphash_12b(const uint8_t *in, const uint64_t *k) -{ - struct siphash_state state = SIPHASH_INIT(k); - uint32_t *in32 = (uint32_t *)in; - - siphash_feed(&state, (uint64_t)(*(in32 + 1)) << 32 | *in32); - - return siphash_final(&state, 12, *(in32 + 2)); -} - -/** - * siphash_20b() - Table index for TCP over IPv6 (20 bytes in) - * @in: Input data (remote address, two ports) - * @k: Hash function key, 128 bits - * - * Return: the 64-bit hash output - */ -/* NOLINTNEXTLINE(clang-diagnostic-unknown-attributes) */ -__attribute__((optimize("-fno-strict-aliasing"))) /* See csum_16b() */ -uint64_t siphash_20b(const uint8_t *in, const uint64_t *k) -{ - struct siphash_state state = SIPHASH_INIT(k); - uint32_t *in32 = (uint32_t *)in; - int i; - - for (i = 0; i < 2; i++, in32 += 2) - siphash_feed(&state, (uint64_t)(*(in32 + 1)) << 32 | *in32); - - return siphash_final(&state, 20, *in32); -} - -/** - * siphash_32b() - Timestamp offset for TCP over IPv6 (32 bytes in) - * @in: Input data (two addresses) - * @k: Hash function key, 128 bits - * - * Return: the 64-bit hash output - */ -/* NOLINTNEXTLINE(clang-diagnostic-unknown-attributes) */ -__attribute__((optimize("-fno-strict-aliasing"))) /* See csum_16b() */ -/* cppcheck-suppress unusedFunction */ -uint64_t siphash_32b(const uint8_t *in, const uint64_t *k) -{ - struct siphash_state state = SIPHASH_INIT(k); - uint64_t *in64 = (uint64_t *)in; - int i; - - for (i = 0; i < 4; i++, in64++) - siphash_feed(&state, *in64); - - return siphash_final(&state, 32, 0); -} - -/** - * siphash_36b() - Initial sequence number for TCP over IPv6 (36 bytes in) - * @in: Input data (two addresses, two ports) - * @k: Hash function key, 128 bits - * - * Return: the 64-bit hash output - */ -/* NOLINTNEXTLINE(clang-diagnostic-unknown-attributes) */ -__attribute__((optimize("-fno-strict-aliasing"))) /* See csum_16b() */ -uint64_t siphash_36b(const uint8_t *in, const uint64_t *k) -{ - struct siphash_state state = SIPHASH_INIT(k); - uint32_t *in32 = (uint32_t *)in; - int i; - - for (i = 0; i < 4; i++, in32 += 2) - siphash_feed(&state, (uint64_t)(*(in32 + 1)) << 32 | *in32); - - return siphash_final(&state, 36, *in32); -} diff --git a/tcp.c b/tcp.c index 19baba5..680874f 100644 --- a/tcp.c +++ b/tcp.c @@ -1165,18 +1165,13 @@ static int tcp_hash_match(const struct tcp_tap_conn *conn, static unsigned int tcp_hash(const struct ctx *c, const union inany_addr *faddr, in_port_t eport, in_port_t fport) { - struct { - union inany_addr faddr; - in_port_t eport; - in_port_t fport; - } __attribute__((__packed__)) in = { - *faddr, eport, fport - }; - uint64_t b = 0; + struct siphash_state state = SIPHASH_INIT(c->tcp.hash_secret); + uint64_t hash; - b = siphash_20b((uint8_t *)&in, c->tcp.hash_secret); + inany_siphash_feed(&state, faddr); + hash = siphash_final(&state, 20, (uint64_t)eport << 16 | fport); - return (unsigned int)(b % TCP_HASH_TABLE_SIZE); + return (unsigned int)(hash % TCP_HASH_TABLE_SIZE); } /** @@ -1815,17 +1810,8 @@ static void tcp_clamp_window(const struct ctx *c, struct tcp_tap_conn *conn, static void tcp_seq_init(const struct ctx *c, struct tcp_tap_conn *conn, const struct timespec *now) { + struct siphash_state state = SIPHASH_INIT(c->tcp.hash_secret); union inany_addr aany; - struct { - union inany_addr src; - in_port_t srcport; - union inany_addr dst; - in_port_t dstport; - } __attribute__((__packed__)) in = { - .src = conn->faddr, - .srcport = conn->fport, - .dstport = conn->eport, - }; uint64_t hash; uint32_t ns; @@ -1833,9 +1819,11 @@ static void tcp_seq_init(const struct ctx *c, struct tcp_tap_conn *conn, inany_from_af(&aany, AF_INET, &c->ip4.addr); else inany_from_af(&aany, AF_INET6, &c->ip6.addr); - in.dst = aany; - hash = siphash_36b((uint8_t *)&in, c->tcp.hash_secret); + inany_siphash_feed(&state, &conn->faddr); + inany_siphash_feed(&state, &aany); + hash = siphash_final(&state, 36, + (uint64_t)conn->fport << 16 | conn->eport); /* 32ns ticks, overflows 32 bits every 137s */ ns = (now->tv_sec * 1000000000 + now->tv_nsec) >> 5; diff --git a/tcp_splice.c b/tcp_splice.c index be01908..a572aca 100644 --- a/tcp_splice.c +++ b/tcp_splice.c @@ -52,6 +52,7 @@ #include "passt.h" #include "log.h" #include "tcp_splice.h" +#include "siphash.h" #include "inany.h" #include "tcp_conn.h"