]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-quic: define a tx STREAM frame list member
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 18 Nov 2024 08:53:39 +0000 (09:53 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 19 Nov 2024 15:16:48 +0000 (16:16 +0100)
For STREAM emission, MUX QUIC previously used a local list defined under
qcc_io_send(). This was suitable as either all frames were sent, or
emission must be interrupted due to transport congestion or fatal error.
In the latter case, the list was emptied anyway and a new frame list was
built on future qcc_io_send() invokation.

For pacing, MUX QUIC may have to save the frame list if pacing should be
applied across emission. This is necessary to avoid to unnecessarily
rebuilt stream frame list between each paced emission. To support this,
STREAM list is now stored as a member of QCC structure.

Ensure frame list is always deleted, even on QCC release, using newly
defined utility function qcc_tx_frms_free().

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

index 6b2c10e8c510ac930de78ee435df397767c220b2..62ae59bbd5a3aa6bca31b79c2f1270b128abc17f 100644 (file)
@@ -68,6 +68,7 @@ struct qcc {
        struct {
                struct quic_fctl fc; /* stream flow control applied on sending */
                uint64_t buf_in_flight; /* sum of currently allocated Tx buffer sizes */
+               struct list frms; /* list of STREAM frames ready for sent */
        } tx;
 
        uint64_t largest_bidi_r; /* largest remote bidi stream ID opened. */
index 9085859f0ef4907ccd100c004af438e73766c3a7..217c4c9aa8ec30616b40446f3f03c68dc67cd9a3 100644 (file)
@@ -36,6 +36,15 @@ DECLARE_POOL(pool_head_qcs, "qcs", sizeof(struct qcs));
 static void qmux_ctrl_send(struct qc_stream_desc *, uint64_t data, uint64_t offset);
 static void qmux_ctrl_room(struct qc_stream_desc *, uint64_t room);
 
+/* Free <qcc> STREAM frames in Tx list. */
+static void qcc_tx_frms_free(struct qcc *qcc)
+{
+       while (!LIST_ISEMPTY(&qcc->tx.frms)) {
+               struct quic_frame *frm = LIST_ELEM(qcc->tx.frms.n, struct quic_frame *, list);
+               qc_frm_free(qcc->conn->handle.qc, &frm);
+       }
+}
+
 static void qcs_free_ncbuf(struct qcs *qcs, struct ncbuf *ncbuf)
 {
        struct buffer buf;
@@ -2247,7 +2256,7 @@ static int qcs_send(struct qcs *qcs, struct list *frms, uint64_t window_conn)
  */
 static int qcc_io_send(struct qcc *qcc)
 {
-       struct list frms = LIST_HEAD_INIT(frms);
+       struct list *frms = &qcc->tx.frms;
        /* Temporary list for QCS on error. */
        struct list qcs_failed = LIST_HEAD_INIT(qcs_failed);
        struct qcs *qcs, *qcs_tmp, *first_qcs = NULL;
@@ -2341,7 +2350,7 @@ static int qcc_io_send(struct qcc *qcc)
 
                if (!qfctl_rblocked(&qcc->tx.fc) &&
                    !qfctl_rblocked(&qcs->tx.fc) && window_conn > total) {
-                       if ((ret = qcs_send(qcs, &frms, window_conn - total)) < 0) {
+                       if ((ret = qcs_send(qcs, frms, window_conn - total)) < 0) {
                                /* Temporarily remove QCS from send-list. */
                                LIST_DEL_INIT(&qcs->el_send);
                                LIST_APPEND(&qcs_failed, &qcs->el_send);
@@ -2365,7 +2374,7 @@ static int qcc_io_send(struct qcc *qcc)
        /* Retry sending until no frame to send, data rejected or connection
         * flow-control limit reached.
         */
-       while (qcc_send_frames(qcc, &frms) == 0 && !qfctl_rblocked(&qcc->tx.fc)) {
+       while (qcc_send_frames(qcc, frms) == 0 && !qfctl_rblocked(&qcc->tx.fc)) {
                window_conn = qfctl_rcap(&qcc->tx.fc);
                resent = 0;
 
@@ -2383,7 +2392,7 @@ static int qcc_io_send(struct qcc *qcc)
                        BUG_ON(resent > window_conn);
 
                        if (!qfctl_rblocked(&qcs->tx.fc) && window_conn > resent) {
-                               if ((ret = qcs_send(qcs, &frms, window_conn - resent)) < 0) {
+                               if ((ret = qcs_send(qcs, frms, window_conn - resent)) < 0) {
                                        LIST_DEL_INIT(&qcs->el_send);
                                        LIST_APPEND(&qcs_failed, &qcs->el_send);
                                        continue;
@@ -2397,12 +2406,7 @@ static int qcc_io_send(struct qcc *qcc)
 
  sent_done:
        /* Deallocate frames that the transport layer has rejected. */
-       if (!LIST_ISEMPTY(&frms)) {
-               struct quic_frame *frm, *frm2;
-
-               list_for_each_entry_safe(frm, frm2, &frms, list)
-                       qc_frm_free(qcc->conn->handle.qc, &frm);
-       }
+       qcc_tx_frms_free(qcc);
 
        /* Re-insert on-error QCS at the end of the send-list. */
        if (!LIST_ISEMPTY(&qcs_failed)) {
@@ -2722,6 +2726,8 @@ static void qcc_release(struct qcc *qcc)
                qc_frm_free(qcc->conn->handle.qc, &frm);
        }
 
+       qcc_tx_frms_free(qcc);
+
        if (qcc->app_ops && qcc->app_ops->release)
                qcc->app_ops->release(qcc->ctx);
        TRACE_PROTO("application layer released", QMUX_EV_QCC_END, conn);
@@ -2835,6 +2841,7 @@ static void _qcc_init(struct qcc *qcc)
        qcc->app_ops = NULL;
        qcc->streams_by_id = EB_ROOT_UNIQUE;
        LIST_INIT(&qcc->lfctl.frms);
+       LIST_INIT(&qcc->tx.frms);
 }
 
 static int qmux_init(struct connection *conn, struct proxy *prx,