]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: delay post handshake frames after accept
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 11 Apr 2023 14:46:03 +0000 (16:46 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 18 Apr 2023 15:08:28 +0000 (17:08 +0200)
When QUIC handshake is completed on our side, some frames are prepared
to be sent :
* HANDSHAKE_DONE
* several NEW_CONNECTION_ID with CIDs allocated

This step was previously executed in quic_conn_io_cb() directly after
CRYPTO frames parsing. This patch delays it to be completed after
accept. Special care have been taken to ensure it is still functional
with 0-RTT activated.

For the moment, this patch should have no impact. However, when
quic_conn thread migration on accept will be implemented, it will be
easier to remap only one CID to the new thread. New CIDs will be
allocated after migration on the new thread.

This should be backported up to 2.7 after a period of observation.

include/haproxy/quic_conn-t.h
src/quic_conn.c

index c8c6f48d33e42cb26a34e17ab9447dd1eb2b1e33..51337b184314da109e114feee5c655be35634a65 100644 (file)
@@ -616,7 +616,7 @@ enum qc_mux_state {
 /* Flags at connection level */
 #define QUIC_FL_CONN_ANTI_AMPLIFICATION_REACHED  (1U << 0)
 #define QUIC_FL_CONN_SPIN_BIT                    (1U << 1) /* Spin bit set by remote peer */
-#define QUIC_FL_CONN_POST_HANDSHAKE_FRAMES_BUILT (1U << 2)
+#define QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS    (1U << 2) /* HANDSHAKE_DONE must be sent */
 #define QUIC_FL_CONN_LISTENER                    (1U << 3)
 #define QUIC_FL_CONN_ACCEPT_REGISTERED           (1U << 4)
 #define QUIC_FL_CONN_TX_MUX_CONTEXT              (1U << 5) /* sending in progress from the MUX layer */
index 2d75e9938b3dc276cabf13c4ca9050f06e081777..74a5f327f10dd4d7914c6ec6900238e81d9e6dd2 100644 (file)
@@ -2459,6 +2459,7 @@ static inline int qc_provide_cdata(struct quic_enc_level *el,
                /* I/O callback switch */
                qc->wait_event.tasklet->process = quic_conn_app_io_cb;
                if (qc_is_listener(ctx->qc)) {
+                       qc->flags |= QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS;
                        qc->state = QUIC_HS_ST_CONFIRMED;
                        /* The connection is ready to be accepted. */
                        quic_accept_push_qc(qc);
@@ -4141,7 +4142,7 @@ static int quic_build_post_handshake_frames(struct quic_conn *qc)
        }
 
        LIST_SPLICE(&qel->pktns->tx.frms, &frm_list);
-       qc->flags |= QUIC_FL_CONN_POST_HANDSHAKE_FRAMES_BUILT;
+       qc->flags &= ~QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS;
 
        ret = 1;
  leave:
@@ -4780,6 +4781,14 @@ int qc_send_mux(struct quic_conn *qc, struct list *frms)
        TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
        BUG_ON(qc->mux_state != QC_MUX_READY); /* Only MUX can uses this function so it must be ready. */
 
+       /* Try to send post handshake frames first unless on 0-RTT. */
+       if ((qc->flags & QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS) &&
+           qc->state >= QUIC_HS_ST_COMPLETE) {
+               struct quic_enc_level *qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP];
+               quic_build_post_handshake_frames(qc);
+               qc_send_app_pkts(qc, &qel->pktns->tx.frms);
+       }
+
        TRACE_STATE("preparing data (from MUX)", QUIC_EV_CONN_TXPKT, qc);
        qc->flags |= QUIC_FL_CONN_TX_MUX_CONTEXT;
        ret = qc_send_app_pkts(qc, frms);
@@ -4967,6 +4976,15 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta
        if (qc_test_fd(qc))
                qc_rcv_buf(qc);
 
+       /* Prepare post-handshake frames
+        * - after connection is instantiated (accept is done)
+        * - handshake state is completed (may not be the case here in 0-RTT)
+        */
+       if ((qc->flags & QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS) && qc->conn &&
+           qc->state >= QUIC_HS_ST_COMPLETE) {
+               quic_build_post_handshake_frames(qc);
+       }
+
        /* Retranmissions */
        if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) {
                TRACE_STATE("retransmission needed", QUIC_EV_CONN_IO_CB, qc);
@@ -5090,10 +5108,6 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
 
        st = qc->state;
        if (st >= QUIC_HS_ST_COMPLETE) {
-               if (!(qc->flags & QUIC_FL_CONN_POST_HANDSHAKE_FRAMES_BUILT) &&
-                   !quic_build_post_handshake_frames(qc))
-                       goto out;
-
                if (!(qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE].tls_ctx.flags &
                           QUIC_FL_TLS_SECRETS_DCD)) {
                        /* Discard the Handshake keys. */