From: Amaury Denoyelle Date: Wed, 19 Feb 2025 14:01:58 +0000 (+0100) Subject: MAJOR: mux-quic: activate QMux for frontend side X-Git-Tag: v3.4-dev8~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=490b465fd1d6965a155973fa796ec1d0656b3059;p=thirdparty%2Fhaproxy.git MAJOR: mux-quic: activate QMux for frontend side To be able to support QMux protocol, xprt_qstrm is activated by the session for transport parameters exchange, prior to the mux layer initialization. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index f4d57874b..874719d70 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -17745,6 +17745,7 @@ proto a bind line : quic : mode=HTTP side=FE|BE mux=QUIC flags=HTX|NO_UPG|FRAMED + qmux : mode=HTTP side=FE mux=QMUX flags=HTX|NO_UPG h2 : mode=HTTP side=FE|BE mux=H2 flags=HTX|HOL_RISK|NO_UPG h1 : mode=HTTP side=FE|BE mux=H1 flags=HTX|NO_UPG none : mode=TCP side=FE|BE mux=PASS flags=NO_UPG @@ -17758,6 +17759,10 @@ proto should be compatible with the multiplexer's protocol to avoid any issue. For instance, if "proto h1" is set, the ALPN should not be set to "h2". + QMux is a subset of QUIC which runs over TCP. It corresponds to the following + draft protocol https://www.ietf.org/archive/id/draft-opik-quic-qmux-01.html. + It is considered experimental in haproxy for now. + quic-cc-algo { cubic | newreno | bbr | nocc }[()] This is a QUIC specific setting to select the congestion control algorithm for any connection attempts to the configured QUIC listeners. They are diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 915818ebd..bbd4212a2 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -358,6 +358,7 @@ enum { MX_FL_NO_UPG = 0x00000004, /* set if mux does not support any upgrade */ MX_FL_FRAMED = 0x00000008, /* mux working on top of a framed transport layer (QUIC) */ MX_FL_REVERSABLE = 0x00000010, /* mux supports connection reversal */ + MX_FL_EXPERIMENTAL = 0x00000020, /* requires experimental support directives */ }; /* PROTO token registration */ diff --git a/src/listener.c b/src/listener.c index 187c0b42c..3da95f7d0 100644 --- a/src/listener.c +++ b/src/listener.c @@ -2631,6 +2631,16 @@ static int bind_parse_proto(char **args, int cur_arg, struct proxy *px, struct b memprintf(err, "'%s' : unknown MUX protocol '%s'", args[cur_arg], args[cur_arg+1]); return ERR_ALERT | ERR_FATAL; } + + if (conf->mux_proto->mux->flags & MX_FL_EXPERIMENTAL) { + if (!experimental_directives_allowed) { + memprintf(err, "'%s' : '%s' protocol is experimental, must be allowed via a global 'expose-experimental-directives'.", + args[cur_arg], args[cur_arg + 1]); + return ERR_ALERT | ERR_FATAL; + } + mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED); + } + return 0; } diff --git a/src/mux_quic.c b/src/mux_quic.c index 8e65a2964..17cbea11d 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -4671,3 +4671,28 @@ static struct mux_proto_list mux_proto_quic = { .token = IST("quic"), .mode = PROTO_MODE_HTTP, .side = PROTO_SIDE_BOTH, .mux = &qmux_ops }; INITCALL1(STG_REGISTER, register_mux_proto, &mux_proto_quic); + +static const struct mux_ops qstrm_ops = { + .init = qmux_init, + .destroy = qmux_destroy, + .detach = qmux_strm_detach, + .rcv_buf = qmux_strm_rcv_buf, + .snd_buf = qmux_strm_snd_buf, + .nego_fastfwd = qmux_strm_nego_ff, + .done_fastfwd = qmux_strm_done_ff, + .resume_fastfwd = qmux_strm_resume_ff, + .subscribe = qmux_strm_subscribe, + .unsubscribe = qmux_strm_unsubscribe, + .wake = qmux_wake, + .shut = qmux_strm_shut, + .ctl = qmux_ctl, + .sctl = qmux_sctl, + .show_sd = qmux_strm_show_sd, + .flags = MX_FL_HTX|MX_FL_NO_UPG|MX_FL_EXPERIMENTAL, + .name = "QMUX", +}; + +static struct mux_proto_list mux_proto_qstrm = + { .token = IST("qmux"), .mode = PROTO_MODE_HTTP, .side = PROTO_SIDE_FE, .mux = &qstrm_ops }; + +INITCALL1(STG_REGISTER, register_mux_proto, &mux_proto_qstrm); diff --git a/src/session.c b/src/session.c index 9d4c6139a..e4b819617 100644 --- a/src/session.c +++ b/src/session.c @@ -241,6 +241,9 @@ int session_accept_fd(struct connection *cli_conn) if (l->bind_conf->options & BC_O_ACC_CIP) cli_conn->flags |= CO_FL_ACCEPT_CIP; + if (l->bind_conf->mux_proto && isteq(l->bind_conf->mux_proto->token, ist("qmux"))) + cli_conn->flags |= (CO_FL_QSTRM_RECV|CO_FL_QSTRM_SEND); + /* Add the handshake pseudo-XPRT */ if (cli_conn->flags & (CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP)) { if (xprt_add_hs(cli_conn) != 0)