]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: check/backend: support conn reuse with SNI
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 2 Apr 2025 15:48:23 +0000 (17:48 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 3 Apr 2025 15:19:07 +0000 (17:19 +0200)
Support for connection reuse during server checks was implemented
recently. This is activated with the server keyword check-reuse-pool.

Similarly to stream processing via connect_backend(), a connection hash
is calculated when trying to perform reuse for checks. This is necessary
to retrieve for a connection which shares the check connect parameters.
However, idle connections can additionnally be tagged using a
pool-conn-name or SNI under connect_backend(). Check reuse does not test
these values, which prevent to retrieve a matching connection.

Improve this by using "check-sni" value as idle connection hash input
for check reuse. be_calculate_conn_hash() API has been adjusted so that
name value can be passed as input, both when using streams or checks.

Even with the current patch, there is still some scenarii which could
not be covered for checks connection reuse. most notably, when using
dynamic pool-conn-name/SNI value. It is however at least sufficient to
cover simpler cases.

include/haproxy/backend.h
src/backend.c
src/tcpcheck.c

index efceb65ab2c9f6aeaceea6d25a22b035a8cfc558..01b0cbdcbeef4c9e7fe6d5396a2ae42a4523e080 100644 (file)
@@ -49,7 +49,8 @@ int alloc_bind_address(struct sockaddr_storage **ss,
 int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm,
                                struct session *sess,
                                struct sockaddr_storage *src,
-                               struct sockaddr_storage *dst);
+                               struct sockaddr_storage *dst,
+                               struct ist name);
 int be_reuse_connection(int64_t hash, struct session *sess,
                         struct proxy *be, struct server *srv,
                         struct stconn *sc, enum obj_type *target, int not_first_req);
index e49a12d05876b55f62727a01b90224ba95f06c1f..6ae61fa516f63cf9a2220d5e9bea803e92a290c9 100644 (file)
@@ -1553,6 +1553,8 @@ static int be_reuse_mode(struct proxy *be, struct server *srv)
  * - <src> is the bind address if an explicit source address is used.
  * - <dst> is the destination address. Must be set in every cases, except on
  *   reverse HTTP.
+ * - <name> is a string identifier associated to the connection. Set by
+ *   pool-conn-name, also used for SSL SNI matching.
  *
  * Note that all input parameters can be NULL. The only requirement is that
  * it's not possible to have both <srv> and <strm> NULL at the same time.
@@ -1562,9 +1564,9 @@ static int be_reuse_mode(struct proxy *be, struct server *srv)
 int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm,
                                struct session *sess,
                                struct sockaddr_storage *src,
-                               struct sockaddr_storage *dst)
+                               struct sockaddr_storage *dst,
+                               struct ist name)
 {
-       struct proxy *be = srv ? srv->proxy : strm->be;
        struct conn_hash_params hash_params;
 
        /* Caller cannot set both <srv> and <strm> to NULL. */
@@ -1577,17 +1579,9 @@ int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm,
        hash_params.target = srv ? &srv->obj_type : strm->target;
 
        /* 2. pool-conn-name */
-       if (srv && srv->pool_conn_name_expr) {
-               struct sample *name_smp;
-
-               name_smp = sample_fetch_as_type(be, sess, strm,
-                                               SMP_OPT_DIR_REQ | SMP_OPT_FINAL,
-                                               srv->pool_conn_name_expr, SMP_T_STR);
-               if (name_smp) {
-                       hash_params.name_prehash =
-                         conn_hash_prehash(name_smp->data.u.str.area,
-                                           name_smp->data.u.str.data);
-               }
+       if (istlen(name)) {
+               hash_params.name_prehash =
+                 conn_hash_prehash(istptr(name), istlen(name));
        }
 
        /* 3. destination address */
@@ -1808,7 +1802,20 @@ int connect_server(struct stream *s)
        }
        else {
                const int not_first_req = s->txn && s->txn->flags & TX_NOT_FIRST;
-               hash = be_calculate_conn_hash(srv, s, s->sess, bind_addr, s->scb->dst);
+               struct ist name = IST_NULL;
+               struct sample *name_smp;
+
+               if (srv && srv->pool_conn_name_expr) {
+                       name_smp = sample_fetch_as_type(s->be, s->sess, s,
+                                                       SMP_OPT_DIR_REQ | SMP_OPT_FINAL,
+                                                       srv->pool_conn_name_expr, SMP_T_STR);
+                       if (name_smp) {
+                               name = ist2(name_smp->data.u.str.area,
+                                           name_smp->data.u.str.data);
+                       }
+               }
+
+               hash = be_calculate_conn_hash(srv, s, s->sess, bind_addr, s->scb->dst, name);
                err = be_reuse_connection(hash, s->sess, s->be, srv, s->scb,
                                          s->target, not_first_req);
                if (err == SF_ERR_INTERNAL)
index 754f41448ea142671febb1b657190a46fee4d020..5329233a3992dec60633a23d31296b3394f5d9dc 100644 (file)
@@ -1216,7 +1216,7 @@ static inline int tcpcheck_use_nondefault_connect(const struct check *check,
        return check->mux_proto || connect->mux_proto ||
          is_addr(&check->addr) || is_addr(&connect->addr) ||
          check->port || connect->port || connect->port_expr ||
-         check->use_ssl || check->sni || connect->sni || check->alpn_len || connect->alpn_len ||
+         check->use_ssl || check->alpn_len || connect->alpn_len ||
          check->send_proxy || check->via_socks4 ||
          (connect->options & TCPCHK_MASK_OPTS_CONNECT);
 }
@@ -1266,12 +1266,18 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec
 
        if (!(check->state & CHK_ST_AGENT) && check->reuse_pool &&
            !tcpcheck_use_nondefault_connect(check, connect)) {
+               struct ist pool_conn_name = IST_NULL;
                int64_t hash;
                int conn_err;
 
                TRACE_DEVEL("trying connection reuse for check", CHK_EV_TCPCHK_CONN, check);
 
-               hash = be_calculate_conn_hash(s, NULL, check->sess, NULL, NULL);
+               if (connect->sni)
+                       pool_conn_name = ist(connect->sni);
+               else if ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT) && check->sni)
+                       pool_conn_name = ist(check->sni);
+
+               hash = be_calculate_conn_hash(s, NULL, check->sess, NULL, NULL, pool_conn_name);
                conn_err = be_reuse_connection(hash, check->sess, s->proxy, s,
                                               check->sc, &s->obj_type, 0);
                if (conn_err == SF_ERR_INTERNAL) {