]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-quic: extract code to build STREAM frames list
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 11 Dec 2024 16:53:29 +0000 (17:53 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 18 Dec 2024 08:38:19 +0000 (09:38 +0100)
Extracts code responsible to generate STREAM, RESET_STREAM and
STOP_SENDING frames for each qcs instances registered in qcc send_list.
It is moved from qcc_io_send() to its owned new function
qcc_build_frms().

This commit does not bring functional change. It is a preparatory step
to adapt QUIC MUX send mechanism to allow reusing of qcc frms list
accross qcc_io_send() invokation.

As a side change, qcc_tx_frms_free() is renamed to qcc_clear_frms().
This better highlights its relationship with qcc_build_frms().

This should be bkacported up to 3.1.

src/mux_quic.c

index 59c474e1e8b30daf28d66c5c946f249a937eaeda..b48def292b32454f1732b6fcb433bdb2c34cd380 100644 (file)
@@ -44,15 +44,6 @@ static int qcc_is_pacing_active(const struct connection *conn)
        return !!(qc->path->cc.algo->pacing_rate);
 }
 
-/* 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;
@@ -1357,6 +1348,15 @@ static void qcc_notify_fctl(struct qcc *qcc)
        }
 }
 
+/* Free <qcc> STREAM frames in Tx list. */
+static void qcc_clear_frms(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);
+       }
+}
+
 /* Prepare for the emission of RESET_STREAM on <qcs> with error code <err>. */
 void qcc_reset_stream(struct qcs *qcs, int err)
 {
@@ -2298,61 +2298,29 @@ static int qcs_send(struct qcs *qcs, struct list *frms, uint64_t window_conn)
        return -1;
 }
 
-/* Proceed to sending. Loop through all available streams for the <qcc>
- * instance and try to send as much as possible.
+/* Encode STREAM frames into <qcc> tx frms for streams registered into
+ * send_list. On each error, related stream is removed from send_list and
+ * inserted into <qcs_failed> list.
  *
- * Returns the total of bytes sent to the transport layer.
+ * This functions also serves to emit RESET_STREAM and STOP_SENDING frames. In
+ * this case, frame is emitted immediately without using <qcc> tx frms. If an
+ * error occured during this step, this is considered as fatal. Tx frms is
+ * cleared and 0 is returned.
+ *
+ * Returns the sum of encoded STREAM frames length or 0 if no frame built.
  */
-static int qcc_io_send(struct qcc *qcc)
+static int qcc_build_frms(struct qcc *qcc, struct list *qcs_failed)
 {
        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;
        uint64_t window_conn = qfctl_rcap(&qcc->tx.fc);
-       int ret = 0, ret_sent = 0, total = 0, resent;
-
-       TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn);
-
-       /* TODO if socket in transient error, sending should be temporarily
-        * disabled for all frames. However, checking for send subscription is
-        * not valid as this may be caused by a congestion error which only
-        * apply for STREAM frames.
-        */
-
-       qcc_tx_frms_free(qcc);
+       int ret = 0, total = 0;
 
-       /* Check for transport error. */
-       if (qcc->flags & QC_CF_ERR_CONN || qcc->conn->flags & CO_FL_ERROR) {
-               TRACE_DEVEL("connection on error", QMUX_EV_QCC_SEND, qcc->conn);
-               goto out;
-       }
-
-       /* Check for locally detected connection error. */
-       if (qcc->flags & QC_CF_ERRL) {
-               /* Prepare a CONNECTION_CLOSE if not already done. */
-               if (!(qcc->flags & QC_CF_ERRL_DONE)) {
-                       TRACE_DATA("report a connection error", QMUX_EV_QCC_SEND|QMUX_EV_QCC_ERR, qcc->conn);
-                       quic_set_connection_close(qcc->conn->handle.qc, qcc->err);
-                       qcc->flags |= QC_CF_ERRL_DONE;
-               }
-               goto out;
-       }
+       TRACE_ENTER(QMUX_EV_QCC_END, qcc->conn);
 
-       if (qcc->conn->flags & CO_FL_SOCK_WR_SH) {
-               qcc->conn->flags |= CO_FL_ERROR;
-               TRACE_DEVEL("connection on error", QMUX_EV_QCC_SEND, qcc->conn);
-               goto out;
-       }
+       /* Frames list must first be cleared via qcc_clear_frms(). */
+       BUG_ON(!LIST_ISEMPTY(&qcc->tx.frms));
 
-       if (!LIST_ISEMPTY(&qcc->lfctl.frms)) {
-               if (qcc_send_frames(qcc, &qcc->lfctl.frms, 0)) {
-                       TRACE_DEVEL("flow-control frames rejected by transport, aborting send", QMUX_EV_QCC_SEND, qcc->conn);
-                       goto out;
-               }
-       }
-
-       /* Send STREAM/STOP_SENDING/RESET_STREAM data for registered streams. */
        list_for_each_entry_safe(qcs, qcs_tmp, &qcc->send_list, el_send) {
                /* Check if all QCS were processed. */
                if (qcs == first_qcs)
@@ -2369,7 +2337,7 @@ static int qcc_io_send(struct qcc *qcc)
                 */
                if (qcs->flags & QC_SF_TO_STOP_SENDING) {
                        if (qcs_send_stop_sending(qcs))
-                               goto sent_done;
+                               goto err;
 
                        /* Remove stream from send_list if it had only STOP_SENDING
                         * to send.
@@ -2383,7 +2351,7 @@ static int qcc_io_send(struct qcc *qcc)
 
                if (qcs->flags & QC_SF_TO_RESET) {
                        if (qcs_send_reset(qcs))
-                               goto sent_done;
+                               goto err;
 
                        /* RFC 9000 3.3. Permitted Frame Types
                         *
@@ -2408,7 +2376,7 @@ static int qcc_io_send(struct qcc *qcc)
                        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);
+                               LIST_APPEND(qcs_failed, &qcs->el_send);
                                continue;
                        }
 
@@ -2426,6 +2394,74 @@ static int qcc_io_send(struct qcc *qcc)
                }
        }
 
+       TRACE_LEAVE(QMUX_EV_QCC_SEND, qcc->conn);
+       return total;
+
+ err:
+       qcc_clear_frms(qcc);
+       TRACE_DEVEL("leaving on error", QMUX_EV_QCC_SEND, qcc->conn);
+       return 0;
+}
+
+/* Proceed to sending. Loop through all available streams for the <qcc>
+ * instance and try to send as much as possible.
+ *
+ * Returns the total of bytes sent to the transport layer.
+ */
+static int qcc_io_send(struct qcc *qcc)
+{
+       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;
+       uint64_t window_conn = qfctl_rcap(&qcc->tx.fc);
+       int ret = 0, total = 0, resent;
+
+       TRACE_ENTER(QMUX_EV_QCC_SEND, qcc->conn);
+
+       /* TODO if socket in transient error, sending should be temporarily
+        * disabled for all frames. However, checking for send subscription is
+        * not valid as this may be caused by a congestion error which only
+        * apply for STREAM frames.
+        */
+
+       qcc_clear_frms(qcc);
+
+       /* Check for transport error. */
+       if (qcc->flags & QC_CF_ERR_CONN || qcc->conn->flags & CO_FL_ERROR) {
+               TRACE_DEVEL("connection on error", QMUX_EV_QCC_SEND, qcc->conn);
+               goto out;
+       }
+
+       /* Check for locally detected connection error. */
+       if (qcc->flags & QC_CF_ERRL) {
+               /* Prepare a CONNECTION_CLOSE if not already done. */
+               if (!(qcc->flags & QC_CF_ERRL_DONE)) {
+                       TRACE_DATA("report a connection error", QMUX_EV_QCC_SEND|QMUX_EV_QCC_ERR, qcc->conn);
+                       quic_set_connection_close(qcc->conn->handle.qc, qcc->err);
+                       qcc->flags |= QC_CF_ERRL_DONE;
+               }
+               goto out;
+       }
+
+       if (qcc->conn->flags & CO_FL_SOCK_WR_SH) {
+               qcc->conn->flags |= CO_FL_ERROR;
+               TRACE_DEVEL("connection on error", QMUX_EV_QCC_SEND, qcc->conn);
+               goto out;
+       }
+
+       if (!LIST_ISEMPTY(&qcc->lfctl.frms)) {
+               if (qcc_send_frames(qcc, &qcc->lfctl.frms, 0)) {
+                       TRACE_DEVEL("flow-control frames rejected by transport, aborting send", QMUX_EV_QCC_SEND, qcc->conn);
+                       goto out;
+               }
+       }
+
+       /* Send STREAM/STOP_SENDING/RESET_STREAM data for registered streams. */
+       total = qcc_build_frms(qcc, &qcs_failed);
+       if (!total)
+               goto sent_done;
+
        if (qcc_is_pacing_active(qcc->conn)) {
                if (!LIST_ISEMPTY(frms) && !quic_pacing_expired(&qcc->tx.pacer)) {
                        qcc_wakeup_pacing(qcc);
@@ -2436,7 +2472,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 ((ret_sent = qcc_send_frames(qcc, frms, 1)) == 0 && !qfctl_rblocked(&qcc->tx.fc)) {
+       while ((ret = qcc_send_frames(qcc, frms, 1)) == 0 && !qfctl_rblocked(&qcc->tx.fc)) {
                window_conn = qfctl_rcap(&qcc->tx.fc);
                resent = 0;
 
@@ -2467,7 +2503,7 @@ static int qcc_io_send(struct qcc *qcc)
        }
 
  sent_done:
-       if (ret_sent == 1) {
+       if (ret == 1) {
                /* qcc_send_frames cannot return 1 if pacing not used. */
                BUG_ON(!qcc_is_pacing_active(qcc->conn));
                qcc_wakeup_pacing(qcc);
@@ -2475,7 +2511,7 @@ static int qcc_io_send(struct qcc *qcc)
        }
        else if (!LIST_ISEMPTY(&qcc->tx.frms)) {
                /* Deallocate frames that the transport layer has rejected. */
-               qcc_tx_frms_free(qcc);
+               qcc_clear_frms(qcc);
        }
        else {
                /* Everything sent */
@@ -2761,7 +2797,7 @@ static void qcc_release(struct qcc *qcc)
                qc_frm_free(qcc->conn->handle.qc, &frm);
        }
 
-       qcc_tx_frms_free(qcc);
+       qcc_clear_frms(qcc);
 
        if (qcc->app_ops && qcc->app_ops->release)
                qcc->app_ops->release(qcc->ctx);