]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic-be: Start asap the mux for 0-RTT
authorFrederic Lecaille <flecaille@haproxy.com>
Sat, 2 Aug 2025 07:53:27 +0000 (09:53 +0200)
committerFrederic Lecaille <flecaille@haproxy.com>
Mon, 4 Aug 2025 17:30:46 +0000 (19:30 +0200)
The mux is created and woken up as soon as possible. This means as soon as
the TX early data encryption level keys are installed. These keys are
installed on the first SSL_do_handshake() call. This call is done as soon
as the connection is created.

This way the mux is able to send 0-RTT packets alongside Initial packets.

src/quic_ssl.c
src/xprt_quic.c

index 88147a161e0ce6e75e12eadd227de268231940b6..b64df7ce2d79647b3f4fdf53c2af0c0e328d09ae 100644 (file)
@@ -977,7 +977,7 @@ static int qc_ssl_provide_quic_data(struct ncbuf *ncbuf,
                                goto leave;
                        }
                }
-               else {
+               else if (qc->mux_state != QC_MUX_READY) {
                        const unsigned char *alpn;
                        size_t alpn_len;
 
@@ -1286,8 +1286,17 @@ int qc_alloc_ssl_sock_ctx(struct quic_conn *qc, struct connection *conn)
                        }
                }
 
-               /* Wakeup the handshake I/O handler tasklet asap to send data */
-               tasklet_wakeup(qc->wait_event.tasklet);
+               /* Wakeup the handshake I/O handler tasklet asap to send data except for
+                * a QUIC client, if the early data encryption level has been initialized.
+                * Some early data will be directly sent by the mux alongside Initial
+                * CRYPTO data.
+                *
+                * Note that a QUIC server never installs its RX early data keys from here
+                * (->eel is always null for a QUIC server during this SSL context
+                * initialization).
+                */
+               if (!qc->eel)
+                       tasklet_wakeup(qc->wait_event.tasklet);
        }
 
        ctx->xprt = xprt_get(XPRT_QUIC);
index 47a8843a3c9e554eaacf44cea9c552bab0829c58..caca9fa16815237731b3f7a67f0b87ac6e801705 100644 (file)
@@ -149,7 +149,7 @@ static int qc_conn_init(struct connection *conn, void **xprt_ctx)
 /* Start the QUIC transport layer */
 static int qc_xprt_start(struct connection *conn, void *ctx)
 {
-       int ret = 0;
+       int ret = -1;
        struct quic_conn *qc;
 
        qc = conn->handle.qc;
@@ -160,7 +160,25 @@ static int qc_xprt_start(struct connection *conn, void *ctx)
                qc->mux_state = QC_MUX_READY;
        }
        else {
-               conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;
+               if (!qc->eel) {
+                       /* Connection without O-RTT */
+                       conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;
+               }
+               else {
+                       struct ssl_sock_ctx *ssl_ctx = ctx;
+
+                       /* Start the mux asap when early data encryption level is available. */
+                       conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN | CO_FL_WAIT_XPRT;
+                       if (conn_create_mux(ssl_ctx->conn, NULL) < 0) {
+                               TRACE_ERROR("mux creation failed", QUIC_EV_CONN_IO_CB, qc, &qc->state);
+                               goto err;
+                       }
+
+                       ssl_ctx->conn->flags &= ~CO_FL_WAIT_XPRT;
+                       qc->mux_state = QC_MUX_READY;
+                       /* Wake up MUX after its creation. Operation similar to TLS+ALPN on TCP stack. */
+                       ssl_ctx->conn->mux->wake(ssl_ctx->conn);
+               }
        }
 
        /* Schedule quic-conn to ensure post handshake frames are emitted. This
@@ -171,9 +189,12 @@ static int qc_xprt_start(struct connection *conn, void *ctx)
                tasklet_wakeup(qc->wait_event.tasklet);
 
        ret = 1;
out:
leave:
        TRACE_LEAVE(QUIC_EV_CONN_NEW, qc);
        return ret;
+ err:
+       TRACE_DEVEL("leaving on error", QUIC_EV_CONN_NEW, qc);
+       goto leave;
 }
 
 static struct ssl_sock_ctx *qc_get_ssl_sock_ctx(struct connection *conn)