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().
This commit is contained in:
Amaury Denoyelle 2024-11-18 09:53:39 +01:00
parent 886a7c475c
commit 4a94a018f0
2 changed files with 18 additions and 10 deletions

View 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. */

View 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,