]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: New quic_cstream object implementation
authorFrédéric Lécaille <flecaille@haproxy.com>
Fri, 9 Sep 2022 16:05:45 +0000 (18:05 +0200)
committerFrédéric Lécaille <flecaille@haproxy.com>
Thu, 13 Oct 2022 08:12:03 +0000 (10:12 +0200)
Add new quic_cstream struct definition to implement the CRYPTO data stream.
This is a simplication of the qcs object (QUIC streams) for the CRYPTO data
without any information about the flow control. They are not attached to any
tree, but to a QUIC encryption level, one by encryption level except for
the early data encryption level (for 0RTT). A stream descriptor is also allocated
for each CRYPTO data stream.

Must be backported to 2.6

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

index 0e3e2734aa7a11346980a76f3fef464a645d3fc8..24e319d73ece90a11b370e7b18dceb4517321487 100644 (file)
@@ -510,6 +510,21 @@ struct q_buf {
        struct list pkts;
 };
 
+/* Crypto data stream (one by encryption level) */
+struct quic_cstream {
+       struct {
+               uint64_t offset;       /* absolute current base offset of ncbuf */
+               struct ncbuf ncbuf;    /* receive buffer - can handle out-of-order offset frames */
+       } rx;
+       struct {
+               uint64_t offset;      /* last offset of data ready to be sent */
+               uint64_t sent_offset; /* last offset sent by transport layer */
+               struct buffer buf;    /* transmit buffer before sending via xprt */
+       } tx;
+
+       struct qc_stream_desc *desc;
+};
+
 struct quic_enc_level {
        enum ssl_encryption_level_t level;
        struct quic_tls_ctx tls_ctx;
@@ -536,6 +551,8 @@ struct quic_enc_level {
                        uint64_t offset;
                } crypto;
        } tx;
+       /* Crypto data stream */
+       struct quic_cstream *cstream;
        struct quic_pktns *pktns;
 };
 
index 65c584df59c2efc748320275f2726befd3118a21..6fc1e30b3ad77ad82680ade644038770cd388734 100644 (file)
@@ -210,6 +210,7 @@ DECLARE_POOL(pool_head_quic_rx_packet, "quic_rx_packet", sizeof(struct quic_rx_p
 DECLARE_POOL(pool_head_quic_tx_packet, "quic_tx_packet", sizeof(struct quic_tx_packet));
 DECLARE_STATIC_POOL(pool_head_quic_rx_crypto_frm, "quic_rx_crypto_frm", sizeof(struct quic_rx_crypto_frm));
 DECLARE_STATIC_POOL(pool_head_quic_crypto_buf, "quic_crypto_buf", sizeof(struct quic_crypto_buf));
+DECLARE_STATIC_POOL(pool_head_quic_cstream, "quic_cstream", sizeof(struct quic_cstream));
 DECLARE_POOL(pool_head_quic_frame, "quic_frame", sizeof(struct quic_frame));
 DECLARE_STATIC_POOL(pool_head_quic_arng, "quic_arng", sizeof(struct quic_arng_node));
 
@@ -4396,6 +4397,55 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
        return t;
 }
 
+/* Release the memory allocated for <cs> CRYPTO stream */
+void quic_cstream_free(struct quic_cstream *cs)
+{
+       if (!cs) {
+               /* This is the case for ORTT encryption level */
+               return;
+       }
+
+       qc_stream_desc_release(cs->desc);
+       pool_free(pool_head_quic_cstream, cs);
+}
+
+/* Allocate a new QUIC stream for <qc>.
+ * Return it if succeeded, NULL if not.
+ */
+struct quic_cstream *quic_cstream_new(struct quic_conn *qc)
+{
+       struct quic_cstream *cs, *ret_cs = NULL;
+
+       TRACE_ENTER(QUIC_EV_CONN_LPKT, qc);
+       cs = pool_alloc(pool_head_quic_cstream);
+       if (!cs) {
+               TRACE_ERROR("crypto stream allocation failed", QUIC_EV_CONN_INIT, qc);
+               goto leave;
+       }
+
+       cs->rx.offset = 0;
+       cs->rx.ncbuf = NCBUF_NULL;
+       cs->rx.offset = 0;
+
+       cs->tx.offset = 0;
+       cs->tx.sent_offset = 0;
+       cs->tx.buf = BUF_NULL;
+       cs->desc = qc_stream_desc_new((uint64_t)-1, -1, cs, qc);
+       if (!cs->desc) {
+               TRACE_ERROR("crypto stream allocation failed", QUIC_EV_CONN_INIT, qc);
+               goto err;
+       }
+
+       ret_cs = cs;
+ leave:
+       TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc);
+       return ret_cs;
+
+ err:
+       pool_free(pool_head_quic_cstream, cs);
+       goto leave;
+}
+
 /* Uninitialize <qel> QUIC encryption level. Never fails. */
 static void quic_conn_enc_level_uninit(struct quic_conn *qc, struct quic_enc_level *qel)
 {
@@ -4410,6 +4460,7 @@ static void quic_conn_enc_level_uninit(struct quic_conn *qc, struct quic_enc_lev
                }
        }
        ha_free(&qel->tx.crypto.bufs);
+       quic_cstream_free(qel->cstream);
 
        TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc);
 }
@@ -4453,6 +4504,14 @@ static int quic_conn_enc_level_init(struct quic_conn *qc,
 
        qel->tx.crypto.sz = 0;
        qel->tx.crypto.offset = 0;
+       /* No CRYPTO data for early data TLS encryption level */
+       if (level == QUIC_TLS_ENC_LEVEL_EARLY_DATA)
+               qel->cstream = NULL;
+       else {
+               qel->cstream = quic_cstream_new(qc);
+               if (!qel->cstream)
+                       goto err;
+       }
 
        ret = 1;
  leave:
index f88fbfcecefe786ca282303398c2c85dabf5ad7a..692f4d5837121f645fd2cf1e3689a34006ec54fb 100644 (file)
@@ -18,7 +18,8 @@ DECLARE_STATIC_POOL(pool_head_quic_stream_buf, "qc_stream_buf",
 
 
 /* Allocate a new stream descriptor with id <id>. The caller is responsible to
- * store the stream in the appropriate tree.
+ * store the stream in the appropriate tree. -1 special value must be used for
+ * a CRYPTO data stream, the type being ignored.
  *
  * Returns the newly allocated instance on success or else NULL.
  */
@@ -31,9 +32,14 @@ struct qc_stream_desc *qc_stream_desc_new(uint64_t id, enum qcs_type type, void
        if (!stream)
                return NULL;
 
-       stream->by_id.key = id;
-       eb64_insert(&qc->streams_by_id, &stream->by_id);
-       qc->rx.strms[type].nb_streams++;
+       if (id == (uint64_t)-1) {
+               stream->by_id.key = (uint64_t)-1;
+       }
+       else {
+               stream->by_id.key = id;
+               eb64_insert(&qc->streams_by_id, &stream->by_id);
+               qc->rx.strms[type].nb_streams++;
+       }
        stream->qc = qc;
 
        stream->buf = NULL;
@@ -195,7 +201,8 @@ void qc_stream_desc_free(struct qc_stream_desc *stream, int closing)
                qc_release_frm(qc, frm);
        }
 
-       eb64_delete(&stream->by_id);
+       if (stream->by_id.key != (uint64_t)-1)
+               eb64_delete(&stream->by_id);
        pool_free(pool_head_quic_stream_desc, stream);
 }