]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: quic: Heavy task mode during handshake
authorFrédéric Lécaille <flecaille@haproxy.com>
Tue, 31 Oct 2023 14:04:28 +0000 (15:04 +0100)
committerFrédéric Lécaille <flecaille@haproxy.com>
Thu, 9 Nov 2023 09:32:31 +0000 (10:32 +0100)
Add a new pool for the CRYPTO data frames received in order.
Add ->rx.crypto_frms list to each encryption level to store such frames
when they are received in order from qc_handle_crypto_frm().
Also set the handshake task (qc_conn_io_cb()) in heavy task mode from
this function after having received such frames. When this task
detects that it is set in heavy mode, it calls qc_ssl_provide_all_quic_data()
newly implemented function to provide the CRYPTO data to the TLS task.
Modify quic_conn_enc_level_uninit() to release these CRYPTO frames
when releasing the encryption level they are in relation with.

include/haproxy/quic_frame-t.h
include/haproxy/quic_ssl.h
include/haproxy/quic_tls-t.h
src/quic_conn.c
src/quic_frame.c
src/quic_rx.c
src/quic_ssl.c
src/quic_tls.c

index b2aab70b096200bb6659532101ca1f6288e3a686..5e91f93208aa52ba23d225ccbc08b71fff895c22 100644 (file)
@@ -35,6 +35,7 @@
 #include <haproxy/quic_stream-t.h>
 
 extern struct pool_head *pool_head_quic_frame;
+extern struct pool_head *pool_head_qf_crypto;
 
 /* forward declarations from xprt-quic */
 struct quic_arngs;
@@ -144,6 +145,7 @@ struct qf_stop_sending {
 };
 
 struct qf_crypto {
+       struct list list;
        uint64_t offset;
        uint64_t len;
        const struct quic_enc_level *qel;
index f31cafc3d83f3c4dc89a80962f4bb80fc34e72de..f564770abec23cd2ddab48ca3d8d06393d1fc6b0 100644 (file)
@@ -34,6 +34,7 @@ int qc_ssl_provide_quic_data(struct ncbuf *ncbuf,
                              enum ssl_encryption_level_t level,
                              struct ssl_sock_ctx *ctx,
                              const unsigned char *data, size_t len);
+int qc_ssl_provide_all_quic_data(struct quic_conn *qc, struct ssl_sock_ctx *ctx);
 
 static inline void qc_free_ssl_sock_ctx(struct ssl_sock_ctx **ctx)
 {
index ef3232aea17e7db5423be40b7db9c49bfebe1afe..a83efe2799d9c8e57cbf9df2cdcac390a120d026 100644 (file)
@@ -222,6 +222,8 @@ struct quic_enc_level {
                struct eb_root pkts;
                /* List of QUIC packets with protected header. */
                struct list pqpkts;
+               /* List of crypto frames received in order. */
+               struct list crypto_frms;
        } rx;
 
        /* TX part */
index f25bf4c9ff07456bd7331c98e8200f41248f5036..7515e8d00ee81ffc6d3f792e001f08a05a862232 100644 (file)
@@ -898,12 +898,18 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
        struct quic_conn *qc = context;
        struct buffer *buf = NULL;
        int st;
+       struct tasklet *tl = (struct tasklet *)t;
 
        TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
 
        st = qc->state;
        TRACE_PROTO("connection state", QUIC_EV_CONN_IO_CB, qc, &st);
 
+       if (HA_ATOMIC_LOAD(&tl->state) & TASK_HEAVY) {
+               HA_ATOMIC_AND(&tl->state, ~TASK_HEAVY);
+               qc_ssl_provide_all_quic_data(qc, qc->xprt_ctx);
+       }
+
        /* Retranmissions */
        if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) {
                TRACE_DEVEL("retransmission needed", QUIC_EV_CONN_PHPKTS, qc);
@@ -918,6 +924,11 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
        if (!qc_treat_rx_pkts(qc))
                goto out;
 
+       if (HA_ATOMIC_LOAD(&tl->state) & TASK_HEAVY) {
+               tasklet_wakeup(tl);
+               goto out;
+       }
+
        if (qc->flags & QUIC_FL_CONN_TO_KILL) {
                TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_PHPKTS, qc);
                goto out;
index 0a52b74cb005410754cceace5866ca11ffc9eb7f..61d2c935ec0e0e544071d1f91beb70cf9f07acf7 100644 (file)
@@ -23,6 +23,7 @@
 #include <haproxy/trace.h>
 
 DECLARE_POOL(pool_head_quic_frame, "quic_frame", sizeof(struct quic_frame));
+DECLARE_POOL(pool_head_qf_crypto, "qf_crypto", sizeof(struct qf_crypto));
 
 const char *quic_frame_type_string(enum quic_frame_type ft)
 {
index c921c975130553e17abd2bd20d7d9a0ccfda434b..69067bc4716201b77fb2c7e7c350f061a350a2fb 100644 (file)
@@ -829,13 +829,22 @@ static int qc_handle_crypto_frm(struct quic_conn *qc,
        }
 
        if (crypto_frm->offset == cstream->rx.offset && ncb_is_empty(ncbuf)) {
-               if (!qc_ssl_provide_quic_data(&qel->cstream->rx.ncbuf, qel->level,
-                                             qc->xprt_ctx, crypto_frm->data, crypto_frm->len)) {
-                       // trace already emitted by function above
+               struct qf_crypto *qf_crypto;
+
+               qf_crypto = pool_alloc(pool_head_qf_crypto);
+               if (!qf_crypto) {
+                       TRACE_ERROR("CRYPTO frame allocation failed", QUIC_EV_CONN_PRSHPKT, qc);
                        goto leave;
                }
 
+               qf_crypto->offset = crypto_frm->offset;
+               qf_crypto->len = crypto_frm->len;
+               qf_crypto->data = crypto_frm->data;
+               qf_crypto->qel = qel;
+               LIST_APPEND(&qel->rx.crypto_frms, &qf_crypto->list);
+
                cstream->rx.offset += crypto_frm->len;
+               HA_ATOMIC_OR(&qc->wait_event.tasklet->state, TASK_HEAVY);
                TRACE_DEVEL("increment crypto level offset", QUIC_EV_CONN_PHPKTS, qc, qel);
                goto done;
        }
index 1a0d5d64dfb9cc31eaa54248ddb7251162d08ed6..fc3c26fe765c4f71828f4d0528b9cf9faefef8b9 100644 (file)
@@ -2,6 +2,7 @@
 #include <haproxy/ncbuf.h>
 #include <haproxy/proxy.h>
 #include <haproxy/quic_conn.h>
+#include <haproxy/quic_rx.h>
 #include <haproxy/quic_sock.h>
 #include <haproxy/quic_ssl.h>
 #include <haproxy/quic_tls.h>
@@ -633,6 +634,60 @@ int qc_ssl_provide_quic_data(struct ncbuf *ncbuf,
        return ret;
 }
 
+/* Provide all the stored in order CRYPTO data received from the peer to the TLS.
+ * Return 1 if succeeded, 0 if not.
+ */
+int qc_ssl_provide_all_quic_data(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
+{
+       int ret = 0;
+       struct quic_enc_level *qel;
+
+       TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc);
+       list_for_each_entry(qel, &qc->qel_list, list) {
+               int ssl_ret;
+               struct quic_cstream *cstream = qel->cstream;
+               struct ncbuf *ncbuf;
+               struct qf_crypto *qf_crypto, *qf_back;
+
+               if (!qel->cstream) {
+                       TRACE_DEVEL("no cstream", QUIC_EV_CONN_PHPKTS, qc, qel);
+                       continue;
+               }
+
+               ssl_ret = 1;
+               ncbuf = &cstream->rx.ncbuf;
+               list_for_each_entry_safe(qf_crypto, qf_back, &qel->rx.crypto_frms, list) {
+
+                       ssl_ret = qc_ssl_provide_quic_data(ncbuf, qel->level, ctx,
+                                                          qf_crypto->data, qf_crypto->len);
+                       /* Free this frame asap */
+                       LIST_DELETE(&qf_crypto->list);
+                       pool_free(pool_head_qf_crypto, qf_crypto);
+
+                       if (!ssl_ret) {
+                               TRACE_DEVEL("null ssl_ret", QUIC_EV_CONN_PHPKTS, qc, qel);
+                               break;
+                       }
+
+                       TRACE_DEVEL("buffered crypto data were provided to TLS stack",
+                                               QUIC_EV_CONN_PHPKTS, qc, qel);
+               }
+
+               if (ncb_is_empty(ncbuf)) {
+                       TRACE_DEVEL("freeing crypto buf", QUIC_EV_CONN_PHPKTS, qc, qel);
+                       quic_free_ncbuf(ncbuf);
+               }
+
+               if (!ssl_ret)
+                       goto leave;
+       }
+
+       ret = 1;
+ leave:
+       TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
+       return ret;
+}
+
 /* Try to allocate the <*ssl> SSL session object for <qc> QUIC connection
  * with <ssl_ctx> as SSL context inherited settings. Also set the transport
  * parameters of this session.
index f5ac9d9099c0228086877ec7c5b0293fe7bc2a96..da25632e626050531a7215138e829947112f0cd6 100644 (file)
@@ -114,6 +114,7 @@ void quic_tls_secret_hexdump(struct buffer *buf,
 void quic_conn_enc_level_uninit(struct quic_conn *qc, struct quic_enc_level *qel)
 {
        int i;
+       struct qf_crypto *qf_crypto, *qfback;
 
        TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc);
 
@@ -123,6 +124,12 @@ void quic_conn_enc_level_uninit(struct quic_conn *qc, struct quic_enc_level *qel
                        qel->tx.crypto.bufs[i] = NULL;
                }
        }
+
+       list_for_each_entry_safe(qf_crypto, qfback, &qel->rx.crypto_frms, list) {
+               LIST_DELETE(&qf_crypto->list);
+               pool_free(pool_head_qf_crypto, qf_crypto);
+       }
+
        ha_free(&qel->tx.crypto.bufs);
        quic_cstream_free(qel->cstream);
 
@@ -160,6 +167,7 @@ static int quic_conn_enc_level_init(struct quic_conn *qc,
 
        qel->rx.pkts = EB_ROOT;
        LIST_INIT(&qel->rx.pqpkts);
+       LIST_INIT(&qel->rx.crypto_frms);
 
        /* Allocate only one buffer. */
        /* TODO: use a pool */