diff --git a/doc/configuration.txt b/doc/configuration.txt index 874719d70..cea9c8b93 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -17745,7 +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 + qmux : mode=HTTP side=FE|BE 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 @@ -19323,6 +19323,7 @@ proto a server line : quic : mode=HTTP side=FE|BE mux=QUIC flags=HTX|NO_UPG|FRAMED + qmux : mode=HTTP side=FE|BE mux=QMUX flags=HTX|NO_UPG h2 : mode=HTTP side=FE|BE mux=H2 flags=HTX|HOL_RISK|NO_UPG fcgi : mode=HTTP side=BE mux=FCGI flags=HTX|HOL_RISK|NO_UPG h1 : mode=HTTP side=FE|BE mux=H1 flags=HTX|NO_UPG @@ -19338,6 +19339,10 @@ proto See also "ws" to use an alternative protocol for websocket streams. + 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 targeting this server. They are similar to those used by diff --git a/src/backend.c b/src/backend.c index 64781d5f3..04992e048 100644 --- a/src/backend.c +++ b/src/backend.c @@ -2124,6 +2124,11 @@ int connect_server(struct stream *s) srv_conn->flags |= CO_FL_SOCKS4; } + if (srv && srv->mux_proto && isteq(srv->mux_proto->token, ist("qmux"))) { + srv_conn->flags |= (CO_FL_QSTRM_RECV|CO_FL_QSTRM_SEND); + may_start_mux_now = 0; + } + #if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation) /* if websocket stream, try to update connection ALPN. */ if (unlikely(s->flags & SF_WEBSOCKET) && diff --git a/src/mux_quic.c b/src/mux_quic.c index 17cbea11d..732a33671 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -4684,6 +4684,10 @@ static const struct mux_ops qstrm_ops = { .subscribe = qmux_strm_subscribe, .unsubscribe = qmux_strm_unsubscribe, .wake = qmux_wake, + .avail_streams = qmux_avail_streams, + .used_streams = qmux_used_streams, + .takeover = NULL, /* QUIC takeover support not implemented yet */ + .attach = qmux_strm_attach, .shut = qmux_strm_shut, .ctl = qmux_ctl, .sctl = qmux_sctl, @@ -4693,6 +4697,6 @@ static const struct mux_ops qstrm_ops = { }; static struct mux_proto_list mux_proto_qstrm = - { .token = IST("qmux"), .mode = PROTO_MODE_HTTP, .side = PROTO_SIDE_FE, .mux = &qstrm_ops }; + { .token = IST("qmux"), .mode = PROTO_MODE_HTTP, .side = PROTO_SIDE_BOTH, .mux = &qstrm_ops }; INITCALL1(STG_REGISTER, register_mux_proto, &mux_proto_qstrm); diff --git a/src/server.c b/src/server.c index d6a414710..c14ac0724 100644 --- a/src/server.c +++ b/src/server.c @@ -1453,6 +1453,15 @@ static int srv_parse_proto(char **args, int *cur_arg, memprintf(err, "'%s' : unknown MUX protocol '%s'", args[*cur_arg], args[*cur_arg+1]); return ERR_ALERT | ERR_FATAL; } + + if (newsrv->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; }