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.
This commit is contained in:
Christopher Faulet 2024-07-04 09:58:12 +02:00
parent b986952a75
commit 1538c4aa82
11 changed files with 40 additions and 26 deletions

View File

@ -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 {

View File

@ -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;
}

View File

@ -52,6 +52,7 @@ enum pr_mode {
PR_MODE_CLI,
PR_MODE_SYSLOG,
PR_MODE_PEERS,
PR_MODE_SPOP,
PR_MODES
} __attribute__((packed));

View File

@ -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 */
/*

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -33,6 +33,7 @@
#include <haproxy/session.h>
#include <haproxy/ssl_sock.h>
#include <haproxy/stconn.h>
#include <haproxy/tcpcheck.h>
#include <haproxy/tools.h>
#include <haproxy/xxhash.h>
@ -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";

View File

@ -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;
}

View File

@ -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;

View File

@ -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);