From: Amaury Denoyelle Date: Mon, 18 Nov 2024 08:53:39 +0000 (+0100) Subject: MINOR: mux-quic: define a tx STREAM frame list member X-Git-Tag: v3.1-dev14~84 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4a94a018f0d5e502b6f1df49721b8e0ecba33844;p=thirdparty%2Fhaproxy.git MINOR: mux-quic: define a tx STREAM frame list member 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(). --- diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index 6b2c10e8c5..62ae59bbd5 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -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. */ diff --git a/src/mux_quic.c b/src/mux_quic.c index 9085859f0e..217c4c9aa8 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -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 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,