From: Amaury Denoyelle Date: Fri, 28 Mar 2025 16:25:57 +0000 (+0100) Subject: MEDIUM: check: implement check-reuse-pool X-Git-Tag: v3.2-dev9~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f1fb396d714b81d1e42458536afe0ef924c6908f;p=thirdparty%2Fhaproxy.git MEDIUM: check: implement check-reuse-pool Implement the possibility to reuse idle connections when performing server checks. This is done thanks to the recently introduced functions be_calculate_conn_hash() and be_reuse_connection(). One side effect of this change is that be_calculate_conn_hash() can now be called with a NULL stream instance. As such, part of the functions are adjusted accordingly. Note that to simplify configuration, connection reuse is not performed if any specific check connection parameters are defined on the server line or via the tcp-check connect rule. This is performed via newly defined tcpcheck_use_nondefault_connect(). --- diff --git a/include/haproxy/tcpcheck-t.h b/include/haproxy/tcpcheck-t.h index 22310eee0..f01d512eb 100644 --- a/include/haproxy/tcpcheck-t.h +++ b/include/haproxy/tcpcheck-t.h @@ -36,6 +36,7 @@ #define TCPCHK_OPT_IMPLICIT 0x0010 /* Implicit connect */ #define TCPCHK_OPT_SOCKS4 0x0020 /* check the connection via socks4 proxy */ #define TCPCHK_OPT_HAS_DATA 0x0040 /* data should be sent after connection */ +#define TCPCHK_MASK_OPTS_CONNECT 0x0027 /* mask for any options which overrides default connect params */ enum tcpcheck_send_type { TCPCHK_SEND_UNDEF = 0, /* Send is not parsed. */ diff --git a/src/backend.c b/src/backend.c index 4b3eeec2a..80b651510 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1547,11 +1547,14 @@ static int be_reuse_mode(struct proxy *be, struct server *srv) /* Calculate hash to select a matching connection for reuse. Here is the list * of input parameters : * - is the server instance. Can be NULL on dispatch/transparent proxy. - * - is the stream instance. + * - is the stream instance. Can be NULL if no stream is used. * - is the bind address if an explicit source address is used. * - is the destination address. Must be set in every cases, except on * reverse HTTP. * + * Note that all input parameters can be NULL. The only requirement is that + * it's not possible to have both and NULL at the same time. + * * Returns the calculated hash. */ int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm, @@ -1592,7 +1595,7 @@ int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm, hash_params.src_addr = src; /* 5. proxy protocol */ - if (srv && srv->pp_opts & SRV_PP_ENABLED) { + if (strm && srv && srv->pp_opts & SRV_PP_ENABLED) { struct connection *cli_conn = objt_conn(strm_orig(strm)); int proxy_line_ret = make_proxy_line(trash.area, trash.size, srv, cli_conn, strm, sess); @@ -1603,7 +1606,7 @@ int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm, } /* 6. Custom mark, tos? */ - if (strm->flags & (SF_BC_MARK | SF_BC_TOS)) { + if (strm && (strm->flags & (SF_BC_MARK | SF_BC_TOS))) { /* mark: 32bits, tos: 8bits = 40bits * last 2 bits are there to indicate if mark and/or tos are set * total: 42bits: diff --git a/src/tcpcheck.c b/src/tcpcheck.c index a366b9e59..754f41448 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -1206,6 +1207,20 @@ enum tcpcheck_eval_ret tcpcheck_agent_expect_reply(struct check *check, struct t goto out; } +/* Returns true if or rule uses any specific connect options + * which may differ from their underlying server counterparts. + */ +static inline int tcpcheck_use_nondefault_connect(const struct check *check, + const struct tcpcheck_connect *connect) +{ + 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->send_proxy || check->via_socks4 || + (connect->options & TCPCHK_MASK_OPTS_CONNECT); +} + /* Evaluates a TCPCHK_ACT_CONNECT rule. Returns TCPCHK_EVAL_WAIT to wait the * connection establishment, TCPCHK_EVAL_CONTINUE to evaluate the next rule or * TCPCHK_EVAL_STOP if an error occurred. @@ -1249,6 +1264,32 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec check_release_buf(check, &check->bi); check_release_buf(check, &check->bo); + if (!(check->state & CHK_ST_AGENT) && check->reuse_pool && + !tcpcheck_use_nondefault_connect(check, connect)) { + 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); + conn_err = be_reuse_connection(hash, check->sess, s->proxy, s, + check->sc, &s->obj_type, 0); + if (conn_err == SF_ERR_INTERNAL) { + TRACE_ERROR("error during connection reuse", CHK_EV_TCPCHK_CONN|CHK_EV_TCPCHK_ERR, check); + set_server_check_status(check, HCHK_STATUS_SOCKERR, trash.area); + ret = TCPCHK_EVAL_STOP; + goto out; + } + else if (conn_err == SF_ERR_NONE) { + TRACE_STATE("check performed with connection reuse", CHK_EV_TCPCHK_CONN, check); + conn = __sc_conn(check->sc); + conn_set_owner(conn, check->sess, NULL); + /* connection will be reinsert in idle conn pool due to missing conn_set_private(). */ + status = SF_ERR_NONE; + goto skip_connect; + } + } + /* No connection, prepare a new one */ conn = conn_new((s ? &s->obj_type : &proxy->obj_type)); if (!conn) { @@ -1414,6 +1455,7 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec } fail_check: + skip_connect: /* It can return one of : * - SF_ERR_NONE if everything's OK * - SF_ERR_SRVTO if there are no more servers