]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: mux-quic: activate QMux for frontend side
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 19 Feb 2025 14:01:58 +0000 (15:01 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 2 Apr 2026 12:02:05 +0000 (14:02 +0200)
To be able to support QMux protocol, xprt_qstrm is activated by the
session for transport parameters exchange, prior to the mux layer
initialization.

doc/configuration.txt
include/haproxy/connection-t.h
src/listener.c
src/mux_quic.c
src/session.c

index f4d57874b0f2cae270c7b60df7f077b32328d3e3..874719d70b9517c281054ae697db6f941111a59b 100644 (file)
@@ -17745,6 +17745,7 @@ proto <name>
   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 <name>
   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 }[(<args,...>)]
   This is a QUIC specific setting to select the congestion control algorithm
   for any connection attempts to the configured QUIC listeners. They are
index 915818ebd543819dd9433dca4ca0a3ad5bf2615a..bbd4212a2043c30398c3a2655ba57407717b628f 100644 (file)
@@ -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 */
index 187c0b42c6a441f7bbfd3365181c2f7627daf8d8..3da95f7d09f7b2da94912c25bfd630d54bb5f65f 100644 (file)
@@ -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;
 }
 
index 8e65a2964ddd4a5a5020fba9f6acbaeec04ddbd2..17cbea11deb70af53ec6a6408462d0d1773ab7f4 100644 (file)
@@ -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);
index 9d4c6139aafc001294373083f10626580798a23d..e4b819617422aa62a8b5b5d2415acd0bedf19d8b 100644 (file)
@@ -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)