From 1538c4aa820e17b885f34862329512bffcd5e15e Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Thu, 4 Jul 2024 09:58:12 +0200 Subject: [PATCH] MEDIUM: proxy/spoe: Add a SPOP mode The SPOE was significantly lightened. It is now possible to refactor it to use a dedicated multiplexer. The first step is to add a SPOP mode for proxies. The corresponding multiplexer mode is also added. For now, there is no SPOP multiplexer, so it is only declarative. But at the end, the SPOP multiplexer will be automatically selected for servers inside a SPOP backend. The related issue is #2502. --- include/haproxy/connection-t.h | 3 ++- include/haproxy/connection.h | 7 +++---- include/haproxy/proxy-t.h | 1 + include/haproxy/tcpcheck.h | 14 ++++++++++++++ src/cfgparse-listen.c | 1 + src/cfgparse.c | 5 +++++ src/check.c | 2 ++ src/connection.c | 24 ++++++------------------ src/extcheck.c | 1 + src/fcgi-app.c | 2 +- src/proxy.c | 6 ++++-- 11 files changed, 40 insertions(+), 26 deletions(-) diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 83969da06..dba52fa32 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -306,7 +306,8 @@ enum proto_proxy_mode { PROTO_MODE_NONE = 0, PROTO_MODE_TCP = 1 << 0, // must not be changed! PROTO_MODE_HTTP = 1 << 1, // must not be changed! - PROTO_MODE_ANY = PROTO_MODE_TCP | PROTO_MODE_HTTP, + PROTO_MODE_SPOP = 1 << 2, // must not be changed! + PROTO_MODE_ANY = PROTO_MODE_TCP | PROTO_MODE_HTTP | PROTO_MODE_SPOP, }; enum proto_proxy_side { diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index aa61cc71a..dc187eb91 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -722,10 +722,9 @@ static inline int conn_pr_mode_to_proto_mode(int proxy_mode) { int mode; - /* for now we only support TCP and HTTP proto_modes, so we - * consider that if it's not HTTP, then it's TCP - */ - mode = 1 << (proxy_mode == PR_MODE_HTTP); + mode = ((proxy_mode == PR_MODE_HTTP) ? PROTO_MODE_HTTP : + (proxy_mode == PR_MODE_SPOP) ? PROTO_MODE_SPOP : + PROTO_MODE_TCP); return mode; } diff --git a/include/haproxy/proxy-t.h b/include/haproxy/proxy-t.h index 262dc11d5..9bafb22e5 100644 --- a/include/haproxy/proxy-t.h +++ b/include/haproxy/proxy-t.h @@ -52,6 +52,7 @@ enum pr_mode { PR_MODE_CLI, PR_MODE_SYSLOG, PR_MODE_PEERS, + PR_MODE_SPOP, PR_MODES } __attribute__((packed)); diff --git a/include/haproxy/tcpcheck.h b/include/haproxy/tcpcheck.h index 55c564a20..95244a521 100644 --- a/include/haproxy/tcpcheck.h +++ b/include/haproxy/tcpcheck.h @@ -119,6 +119,20 @@ static inline void action_kw_tcp_check_build_list(struct buffer *chk) action_build_list(&tcp_check_keywords.list, chk); } +/* + * Map tcpcheck rules type (TCPCHK_RULES_*) to equivalent proto_proxy_mode (PROTO_MODE_*) + */ +static inline int tcpchk_rules_type_to_proto_mode(int tcpchk_rules_type) +{ + int mode; + + mode = (((tcpchk_rules_type & TCPCHK_RULES_PROTO_CHK) == TCPCHK_RULES_HTTP_CHK) ? PROTO_MODE_HTTP : + (((tcpchk_rules_type & TCPCHK_RULES_PROTO_CHK) == TCPCHK_RULES_SPOP_CHK) ? PROTO_MODE_SPOP : + PROTO_MODE_TCP)); + + return mode; +} + #endif /* _HAPROXY_TCPCHECK_H */ /* diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c index 1f6ddc2ad..2beb9377b 100644 --- a/src/cfgparse-listen.c +++ b/src/cfgparse-listen.c @@ -545,6 +545,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) if (strcmp(args[1], "http") == 0) curproxy->mode = PR_MODE_HTTP; else if (strcmp(args[1], "tcp") == 0) curproxy->mode = PR_MODE_TCP; else if (strcmp(args[1], "log") == 0 && (curproxy->cap & PR_CAP_BE)) curproxy->mode = PR_MODE_SYSLOG; + else if (strcmp(args[1], "spop") == 0 && (curproxy->cap & PR_CAP_BE)) curproxy->mode = PR_MODE_SPOP; else if (strcmp(args[1], "health") == 0) { ha_alert("parsing [%s:%d] : 'mode health' doesn't exist anymore. Please use 'http-request return status 200' instead.\n", file, linenum); err_code |= ERR_ALERT | ERR_FATAL; diff --git a/src/cfgparse.c b/src/cfgparse.c index 2434de2cb..990d2a488 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -2977,6 +2977,11 @@ int check_config_validity() cfgerr += proxy_cfg_ensure_no_http(curproxy); break; + case PR_MODE_SPOP: + cfgerr += proxy_cfg_ensure_no_http(curproxy); + cfgerr += proxy_cfg_ensure_no_log(curproxy); + break; + case PR_MODE_PEERS: case PR_MODES: /* should not happen, bug gcc warn missing switch statement */ diff --git a/src/check.c b/src/check.c index 64464c4f4..40d403b27 100644 --- a/src/check.c +++ b/src/check.c @@ -1826,12 +1826,14 @@ int init_srv_check(struct server *srv) */ if (srv->mux_proto && !srv->check.mux_proto && ((srv->mux_proto->mode == PROTO_MODE_HTTP && check_type == TCPCHK_RULES_HTTP_CHK) || + (srv->mux_proto->mode == PROTO_MODE_SPOP && check_type == TCPCHK_RULES_SPOP_CHK) || (srv->mux_proto->mode == PROTO_MODE_TCP && check_type != TCPCHK_RULES_HTTP_CHK))) { srv->check.mux_proto = srv->mux_proto; } /* test that check proto is valid if explicitly defined */ else if (srv->check.mux_proto && ((srv->check.mux_proto->mode == PROTO_MODE_HTTP && check_type != TCPCHK_RULES_HTTP_CHK) || + (srv->check.mux_proto->mode == PROTO_MODE_SPOP && check_type != TCPCHK_RULES_SPOP_CHK) || (srv->check.mux_proto->mode == PROTO_MODE_TCP && check_type == TCPCHK_RULES_HTTP_CHK))) { ha_alert("config: %s '%s': server '%s' uses an incompatible MUX protocol for the selected check type\n", proxy_type_str(srv->proxy), srv->proxy->id, srv->id); diff --git a/src/connection.c b/src/connection.c index 3fedad9a5..668e626f5 100644 --- a/src/connection.c +++ b/src/connection.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -271,12 +272,7 @@ int conn_install_mux_fe(struct connection *conn, void *ctx) struct ist mux_proto; const char *alpn_str = NULL; int alpn_len = 0; - int mode; - - if (bind_conf->frontend->mode == PR_MODE_HTTP) - mode = PROTO_MODE_HTTP; - else - mode = PROTO_MODE_TCP; + int mode = conn_pr_mode_to_proto_mode(bind_conf->frontend->mode); conn_get_alpn(conn, &alpn_str, &alpn_len); mux_proto = ist2(alpn_str, alpn_len); @@ -326,12 +322,7 @@ int conn_install_mux_be(struct connection *conn, void *ctx, struct session *sess struct ist mux_proto; const char *alpn_str = NULL; int alpn_len = 0; - int mode; - - if (prx->mode == PR_MODE_HTTP) - mode = PROTO_MODE_HTTP; - else - mode = PROTO_MODE_TCP; + int mode = conn_pr_mode_to_proto_mode(prx->mode); conn_get_alpn(conn, &alpn_str, &alpn_len); mux_proto = ist2(alpn_str, alpn_len); @@ -369,12 +360,7 @@ int conn_install_mux_chk(struct connection *conn, void *ctx, struct session *ses struct ist mux_proto; const char *alpn_str = NULL; int alpn_len = 0; - int mode; - - if ((check->tcpcheck_rules->flags & TCPCHK_RULES_PROTO_CHK) == TCPCHK_RULES_HTTP_CHK) - mode = PROTO_MODE_HTTP; - else - mode = PROTO_MODE_TCP; + int mode = tcpchk_rules_type_to_proto_mode(check->tcpcheck_rules->flags); conn_get_alpn(conn, &alpn_str, &alpn_len); mux_proto = ist2(alpn_str, alpn_len); @@ -1811,6 +1797,8 @@ void list_mux_proto(FILE *out) mode = "TCP"; else if (item->mode == PROTO_MODE_HTTP) mode = "HTTP"; + else if (item->mode == PROTO_MODE_SPOP) + mode = "SPOP"; else mode = "NONE"; diff --git a/src/extcheck.c b/src/extcheck.c index 05c53ff9f..f01931b9d 100644 --- a/src/extcheck.c +++ b/src/extcheck.c @@ -348,6 +348,7 @@ int prepare_external_check(struct check *check) case PR_MODE_PEERS: svmode = "peers"; break; case PR_MODE_HTTP: svmode = (s->mux_proto) ? s->mux_proto->token.ptr : "h1"; break; case PR_MODE_TCP: svmode = "tcp"; break; + case PR_MODE_SPOP: svmode = "spop"; break; /* all valid cases must be enumerated above, below is to avoid a warning */ case PR_MODES: svmode = "?"; break; } diff --git a/src/fcgi-app.c b/src/fcgi-app.c index 5790cebcf..b3a9b7c59 100644 --- a/src/fcgi-app.c +++ b/src/fcgi-app.c @@ -642,7 +642,7 @@ static int cfg_fcgi_apps_postparser() struct fcgi_flt_conf *fcgi_conf = find_px_fcgi_conf(px); int nb_fcgi_srv = 0; - if (px->mode == PR_MODE_TCP && fcgi_conf) { + if (px->mode != PR_MODE_HTTP && fcgi_conf) { ha_alert("proxy '%s': FCGI application cannot be used in non-HTTP mode.\n", px->id); err_code |= ERR_ALERT | ERR_FATAL; diff --git a/src/proxy.c b/src/proxy.c index 10cb78025..da589a28e 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -431,6 +431,8 @@ const char *proxy_mode_str(int mode) { return "syslog"; else if (mode == PR_MODE_PEERS) return "peers"; + else if (mode == PR_MODE_SPOP) + return "spop"; else return "unknown"; } @@ -1881,11 +1883,11 @@ void proxy_cond_disable(struct proxy *p) * peers, etc) we must not report them at all as they're not really on * the data plane but on the control plane. */ - if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP || p->mode == PR_MODE_SYSLOG) && !(p->cap & PR_CAP_INT)) + if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP || p->mode == PR_MODE_SYSLOG || p->mode == PR_MODE_SPOP) && !(p->cap & PR_CAP_INT)) ha_warning("Proxy %s stopped (cumulated conns: FE: %lld, BE: %lld).\n", p->id, p->fe_counters.cum_conn, p->be_counters.cum_sess); - if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP) && !(p->cap & PR_CAP_INT)) + if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP || p->mode == PR_MODE_SPOP) && !(p->cap & PR_CAP_INT)) send_log(p, LOG_WARNING, "Proxy %s stopped (cumulated conns: FE: %lld, BE: %lld).\n", p->id, p->fe_counters.cum_conn, p->be_counters.cum_sess);