OPTIM: connection: progressive hash for conn_calculate_hash()

Some CPU time is needlessly wasted in conn_calculate_hash(), because all
params are first copied into a temporary buffer before computing the
hash on the whole buffer. Instead, let's leverage the XXH progressive
hash update functions to avoid expensive memcpys.
This commit is contained in:
Aurelien DARRAGON 2024-01-25 10:35:39 +01:00
parent 1de149fb6d
commit ea09075f59
2 changed files with 42 additions and 53 deletions

View File

@ -96,12 +96,6 @@ void sockaddr_free(struct sockaddr_storage **sap);
/* connection hash stuff */
uint64_t conn_calculate_hash(const struct conn_hash_params *params);
uint64_t conn_hash_prehash(char *buf, size_t size);
void conn_hash_update(char *buf, size_t *idx,
const void *data, size_t size,
enum conn_hash_params_t *flags,
enum conn_hash_params_t type);
uint64_t conn_hash_digest(char *buf, size_t bufsize,
enum conn_hash_params_t flags);
int conn_reverse(struct connection *conn);

View File

@ -2544,9 +2544,38 @@ static struct cfg_kw_list cfg_kws = {ILH, {
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
/* Generate the hash of a connection with params as input
* Each non-null field of params is taken into account for the hash calcul.
*/
uint64_t conn_hash_prehash(char *buf, size_t size)
{
return XXH64(buf, size, 0);
}
/* Computes <data> hash into <hash>. In the same time, <flags>
* are updated with <type> for the hash header.
*/
static void conn_hash_update(XXH64_state_t *hash,
const void *data, size_t size,
enum conn_hash_params_t *flags,
enum conn_hash_params_t type)
{
XXH64_update(hash, data, size);
*flags |= type;
}
static uint64_t conn_hash_digest(XXH64_state_t *hash,
enum conn_hash_params_t flags)
{
const uint64_t flags_u64 = (uint64_t)flags;
const uint64_t f_hash = XXH64_digest(hash);
return (flags_u64 << CONN_HASH_PAYLOAD_LEN) | CONN_HASH_GET_PAYLOAD(f_hash);
}
/* private function to handle sockaddr as input for connection hash */
static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
char *buf, size_t *idx,
XXH64_state_t *hash,
enum conn_hash_params_t *hash_flags,
enum conn_hash_params_t param_type_addr,
enum conn_hash_params_t param_type_port)
@ -2558,12 +2587,12 @@ static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
case AF_INET:
addr = (struct sockaddr_in *)ss;
conn_hash_update(buf, idx,
conn_hash_update(hash,
&addr->sin_addr, sizeof(addr->sin_addr),
hash_flags, param_type_addr);
if (addr->sin_port) {
conn_hash_update(buf, idx,
conn_hash_update(hash,
&addr->sin_port, sizeof(addr->sin_port),
hash_flags, param_type_port);
}
@ -2573,12 +2602,12 @@ static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
case AF_INET6:
addr6 = (struct sockaddr_in6 *)ss;
conn_hash_update(buf, idx,
conn_hash_update(hash,
&addr6->sin6_addr, sizeof(addr6->sin6_addr),
hash_flags, param_type_addr);
if (addr6->sin6_port) {
conn_hash_update(buf, idx,
conn_hash_update(hash,
&addr6->sin6_port, sizeof(addr6->sin6_port),
hash_flags, param_type_port);
}
@ -2587,76 +2616,42 @@ static void conn_calculate_hash_sockaddr(const struct sockaddr_storage *ss,
}
}
/* Generate the hash of a connection with params as input
* Each non-null field of params is taken into account for the hash calcul.
*/
uint64_t conn_hash_prehash(char *buf, size_t size)
{
return XXH64(buf, size, 0);
}
/* Append <data> into <buf> at <idx> offset in preparation for connection hash
* calcul. <idx> is incremented beyond data <size>. In the same time, <flags>
* are updated with <type> for the hash header.
*/
void conn_hash_update(char *buf, size_t *idx,
const void *data, size_t size,
enum conn_hash_params_t *flags,
enum conn_hash_params_t type)
{
memcpy(&buf[*idx], data, size);
*idx += size;
*flags |= type;
}
uint64_t conn_hash_digest(char *buf, size_t bufsize,
enum conn_hash_params_t flags)
{
const uint64_t flags_u64 = (uint64_t)flags;
const uint64_t hash = XXH64(buf, bufsize, 0);
return (flags_u64 << CONN_HASH_PAYLOAD_LEN) | CONN_HASH_GET_PAYLOAD(hash);
}
uint64_t conn_calculate_hash(const struct conn_hash_params *params)
{
char *buf;
size_t idx = 0;
uint64_t hash = 0;
enum conn_hash_params_t hash_flags = 0;
XXH64_state_t hash;
buf = trash.area;
XXH64_reset(&hash, 0);
conn_hash_update(buf, &idx, &params->target, sizeof(params->target), &hash_flags, 0);
conn_hash_update(&hash, &params->target, sizeof(params->target), &hash_flags, 0);
if (params->sni_prehash) {
conn_hash_update(buf, &idx,
conn_hash_update(&hash,
&params->sni_prehash, sizeof(params->sni_prehash),
&hash_flags, CONN_HASH_PARAMS_TYPE_SNI);
}
if (params->dst_addr) {
conn_calculate_hash_sockaddr(params->dst_addr,
buf, &idx, &hash_flags,
&hash, &hash_flags,
CONN_HASH_PARAMS_TYPE_DST_ADDR,
CONN_HASH_PARAMS_TYPE_DST_PORT);
}
if (params->src_addr) {
conn_calculate_hash_sockaddr(params->src_addr,
buf, &idx, &hash_flags,
&hash, &hash_flags,
CONN_HASH_PARAMS_TYPE_SRC_ADDR,
CONN_HASH_PARAMS_TYPE_SRC_PORT);
}
if (params->proxy_prehash) {
conn_hash_update(buf, &idx,
conn_hash_update(&hash,
&params->proxy_prehash, sizeof(params->proxy_prehash),
&hash_flags, CONN_HASH_PARAMS_TYPE_PROXY);
}
hash = conn_hash_digest(buf, idx, hash_flags);
return hash;
return conn_hash_digest(&hash, hash_flags);
}
/* Reverse a <conn> connection instance. This effectively moves the connection