diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 32d5a60f9..dd52bd3a7 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -466,6 +467,28 @@ struct conn_stream { void *ctx; /* mux-specific context */ }; +/* Hash header flag reflecting the input parameters present + * CAUTION! Always update CONN_HASH_PARAMS_TYPE_COUNT when adding a new entry. + */ +enum conn_hash_params_t { + /* to remove as soon as one useful parameter is present */ + CONN_HASH_DUMMY_PARAM, +}; +#define CONN_HASH_PARAMS_TYPE_COUNT 1 + +#define CONN_HASH_PAYLOAD_LEN \ + (((sizeof(((struct connection *)0)->hash)) * 8) - CONN_HASH_PARAMS_TYPE_COUNT) + +#define CONN_HASH_GET_PAYLOAD(hash) \ + (((hash) << CONN_HASH_PARAMS_TYPE_COUNT) >> CONN_HASH_PARAMS_TYPE_COUNT) + +/* To avoid overflow, dynamically sized parameters must be pre-hashed. Their + * hashed will then be reused as input for the generation of the final + * connection hash. + */ +struct conn_hash_params { +}; + /* This structure describes a connection with its methods and data. * A connection may be performed to proxy or server via a local or remote * socket, and can also be made to an internal applet. It can support diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index 03e7e2efd..a7a83b1c0 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -1115,6 +1115,39 @@ static inline int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct return 0; } +/* Generate the hash of a connection with params as input + * Each non-null field of params is taken into account for the hash calcul. + */ +XXH64_hash_t conn_calculate_hash(const struct conn_hash_params *params); + +static inline XXH64_hash_t conn_hash_prehash(char *buf, size_t size) +{ + return XXH64(buf, size, 0); +} + +/* Append into at offset in preparation for connection hash + * calcul. is incremented beyond data . In the same time, + * are updated with for the hash header. + */ +static inline 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; +} + +static inline XXH64_hash_t conn_hash_digest(char *buf, size_t bufsize, + enum conn_hash_params_t flags) +{ + const uint64_t flags_u64 = (uint64_t)flags; + const XXH64_hash_t hash = XXH64(buf, bufsize, 0); + + return (flags_u64 << CONN_HASH_PAYLOAD_LEN) | CONN_HASH_GET_PAYLOAD(hash); +} + #endif /* _HAPROXY_CONNECTION_H */ /* diff --git a/src/backend.c b/src/backend.c index c7fb3496d..4b2c9f827 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1247,6 +1247,11 @@ int connect_server(struct stream *s) int init_mux = 0; int err; int64_t hash = 0; + struct conn_hash_params hash_params; + + /* first, set unique connection parameters and then calculate hash */ + memset(&hash_params, 0, sizeof(hash_params)); + hash = conn_calculate_hash(&hash_params); /* This will catch some corner cases such as lying connections resulting from * retries or connect timeouts but will rarely trigger. @@ -1672,6 +1677,8 @@ skip_reuse: } } + srv_conn->hash = hash; + return SF_ERR_NONE; /* connection is OK */ } diff --git a/src/connection.c b/src/connection.c index fc605f986..f5dbffbc1 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1411,3 +1411,16 @@ static struct cfg_kw_list cfg_kws = {ILH, { }}; INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws); + +XXH64_hash_t conn_calculate_hash(const struct conn_hash_params *params) +{ + char *buf; + size_t idx = 0; + XXH64_hash_t hash = 0; + enum conn_hash_params_t hash_flags = 0; + + buf = trash.area; + + hash = conn_hash_digest(buf, idx, hash_flags); + return hash; +}