]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-quic: reorganize flow-control frames emission
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 16 May 2022 12:29:59 +0000 (14:29 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 18 May 2022 13:52:44 +0000 (15:52 +0200)
Adjust the mechanism for MAX_STREAMS_BIDI emission. When a bidirectional
stream is removed, current flow-control level is checked. If needed, a
MAX_STREAMS_BIDI frame is generated and inserted in a new list in the
QCS instance. The new frames will be emitted at the start of qc_send().

This has no impact on the current MAX_STREAMS_BIDI behavior. However,
this mechanism is more flexible and will allow to implement quickly
MAX_STREAM_DATA/MAX_DATA emission.

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

index ddd19d380551fca6d1c946aebf263bbbe343aeb7..1135ee2af274bbcbe2bb2d9ec74c8b53693b6033 100644 (file)
@@ -50,6 +50,7 @@ struct qcc {
 
        /* flow-control fields set by us enforced on our side. */
        struct {
+               struct list frms; /* prepared frames related to flow-control  */
                uint64_t ms_bidi_init; /* max initial sub-ID of bidi stream allowed for the peer */
                uint64_t ms_bidi; /* max sub-ID of bidi stream allowed for the peer */
                uint64_t msd_bidi_l; /* initial max-stream-data on local streams */
index 1f15fa76aeb47f8ada9c02acc9dcfc2648a8d74b..54bec78f2c398e75769b9c4bdcba3e27873919dd 100644 (file)
@@ -506,9 +506,35 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
        return 0;
 }
 
-static int qc_is_max_streams_needed(struct qcc *qcc)
+/* Signal the closing of remote stream with id <id>. Flow-control for new
+ * streams may be allocated for the peer if needed.
+ */
+static int qcc_release_remote_stream(struct qcc *qcc, uint64_t id)
 {
-       return qcc->lfctl.cl_bidi_r > qcc->lfctl.ms_bidi_init / 2;
+       struct quic_frame *frm;
+
+       if (quic_stream_is_bidi(id)) {
+               ++qcc->lfctl.cl_bidi_r;
+               if (qcc->lfctl.cl_bidi_r > qcc->lfctl.ms_bidi_init / 2) {
+                       frm = pool_zalloc(pool_head_quic_frame);
+                       BUG_ON(!frm); /* TODO handle this properly */
+
+                       LIST_INIT(&frm->reflist);
+                       frm->type = QUIC_FT_MAX_STREAMS_BIDI;
+                       frm->max_streams_bidi.max_streams = qcc->lfctl.ms_bidi +
+                                                           qcc->lfctl.cl_bidi_r;
+                       LIST_APPEND(&qcc->lfctl.frms, &frm->list);
+                       tasklet_wakeup(qcc->wait_event.tasklet);
+
+                       qcc->lfctl.ms_bidi += qcc->lfctl.cl_bidi_r;
+                       qcc->lfctl.cl_bidi_r = 0;
+               }
+       }
+       else {
+               /* TODO */
+       }
+
+       return 0;
 }
 
 /* detaches the QUIC stream from its QCC and releases it to the QCS pool. */
@@ -519,13 +545,8 @@ static void qcs_destroy(struct qcs *qcs)
 
        TRACE_ENTER(QMUX_EV_QCS_END, conn, qcs);
 
-       if (quic_stream_is_remote(qcs->qcc, id)) {
-               if (quic_stream_is_bidi(id)) {
-                       ++qcs->qcc->lfctl.cl_bidi_r;
-                       if (qc_is_max_streams_needed(qcs->qcc))
-                               tasklet_wakeup(qcs->qcc->wait_event.tasklet);
-               }
-       }
+       if (quic_stream_is_remote(qcs->qcc, id))
+               qcc_release_remote_stream(qcs->qcc, id);
 
        qcs_free(qcs);
 
@@ -584,6 +605,12 @@ static void qc_release(struct qcc *qcc)
                qcs_free(qcs);
        }
 
+       while (!LIST_ISEMPTY(&qcc->lfctl.frms)) {
+               struct quic_frame *frm = LIST_ELEM(&qcc->lfctl.frms, struct quic_frame *, list);
+               LIST_DELETE(&frm->list);
+               pool_free(pool_head_quic_frame, frm);
+       }
+
        pool_free(pool_head_qcc, qcc);
 
        if (conn) {
@@ -858,37 +885,6 @@ static int qc_send_frames(struct qcc *qcc, struct list *frms)
        return 0;
 }
 
-/* Send a MAX_STREAM_BIDI frame to update the limit of bidirectional streams
- * allowed to be opened by the peer. The caller should have first checked if
- * this is required with qc_is_max_streams_needed.
- *
- * Returns 0 on success else non-zero.
- */
-static int qc_send_max_streams(struct qcc *qcc)
-{
-       struct list frms = LIST_HEAD_INIT(frms);
-       struct quic_frame *frm;
-
-       frm = pool_zalloc(pool_head_quic_frame);
-       BUG_ON(!frm); /* TODO handle this properly */
-
-       LIST_INIT(&frm->reflist);
-       frm->type = QUIC_FT_MAX_STREAMS_BIDI;
-       frm->max_streams_bidi.max_streams = qcc->lfctl.ms_bidi +
-                                           qcc->lfctl.cl_bidi_r;
-       TRACE_DEVEL("sending MAX_STREAMS frame", QMUX_EV_SEND_FRM, qcc->conn, NULL, frm);
-       LIST_APPEND(&frms, &frm->list);
-
-       if (qc_send_frames(qcc, &frms))
-               return 1;
-
-       /* save the new limit if the frame has been send. */
-       qcc->lfctl.ms_bidi += qcc->lfctl.cl_bidi_r;
-       qcc->lfctl.cl_bidi_r = 0;
-
-       return 0;
-}
-
 /* Used internally by qc_send function. Proceed to send for <qcs>. This will
  * transfer data from qcs buffer to its quic_stream counterpart. A STREAM frame
  * is then generated and inserted in <frms> list. <qcc_max_data> is the current
@@ -966,8 +962,12 @@ static int qc_send(struct qcc *qcc)
                return 0;
        }
 
-       if (qc_is_max_streams_needed(qcc))
-               qc_send_max_streams(qcc);
+       if (!LIST_ISEMPTY(&qcc->lfctl.frms)) {
+               if (qc_send_frames(qcc, &qcc->lfctl.frms)) {
+                       TRACE_DEVEL("flow-control frames rejected by transport, aborting send", QMUX_EV_QCC_SEND, qcc->conn);
+                       goto out;
+               }
+       }
 
        if (qcc->flags & QC_CF_BLK_MFCTL)
                return 0;
@@ -1213,6 +1213,7 @@ static int qc_init(struct connection *conn, struct proxy *prx,
        qcc->strms[QCS_SRV_UNI].rx.max_data = lparams->initial_max_stream_data_uni;
        qcc->strms[QCS_SRV_UNI].tx.max_data = 0;
 
+       LIST_INIT(&qcc->lfctl.frms);
        qcc->lfctl.ms_bidi = qcc->lfctl.ms_bidi_init = lparams->initial_max_streams_bidi;
        qcc->lfctl.msd_bidi_l = lparams->initial_max_stream_data_bidi_local;
        qcc->lfctl.msd_bidi_r = lparams->initial_max_stream_data_bidi_remote;