]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: quic: limit reject after MUX closure to once per stream
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 12 Nov 2026 09:34:53 +0000 (10:34 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 12 Nov 2026 13:58:02 +0000 (14:58 +0100)
This patch is a follow-up to the previous one. The objective is to limit
the number of allocated frames after MUX closure for STREAM handling.

Ensures that each stream is closed only once. This is performed by
incrementing the ID stored in the quic_conn structure each time a stream
is rejected. If a non-contiguous ID is received, all intermediary
streams are rejected as well.

Along with the previous patch which ensures that stream IDs higher than
the flow control limit cause an immediate closure, this guarantees that
frame allocation for stream rejection after MUX closure remains low and
bounded.

This must be backported up to 2.6 after a period of observation.

include/haproxy/quic_conn-t.h
src/quic_rx.c

index 9f7d955dfdb81f030acd881e20e07964a37ecac0..9870c9938eb9e29d251ca6a3b215bf082e154cb7 100644 (file)
@@ -388,7 +388,7 @@ struct quic_conn {
                struct buffer buf;
                struct list pkt_list;
 
-               /* first unhandled streams ID, set by MUX after release */
+               /* first unhandled stream IDs, set by MUX on release and then updated by quic-conn */
                uint64_t stream_max_uni;
                uint64_t stream_max_bidi;
                /* first stream IDs, which cannot be opened by the peer due to flow-control, set by MUX after release */
index cd8244dd06dae27ec0783514020a1e1867cca32b..92d84ef4b6f456788a9f87a4847b732f29e72da0 100644 (file)
@@ -1029,7 +1029,7 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
                {
                        struct qf_stream *strm_frm = &frm->stream;
                        const char fin = frm->type & QUIC_STREAM_FRAME_TYPE_FIN_BIT;
-                       uint64_t max, lim;
+                       uint64_t *max, lim;
 
                        /* The upper layer may not be allocated. */
                        if (!qc_is_conn_ready(qc)) {
@@ -1043,15 +1043,15 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
                                }
 
                                if (quic_stream_is_uni(strm_frm->id)) {
-                                       lim = qc->rx.stream_lim_uni;
-                                       max = qc->rx.stream_max_uni;
+                                       lim =  qc->rx.stream_lim_uni;
+                                       max = &qc->rx.stream_max_uni;
                                }
                                else {
-                                       lim = qc->rx.stream_lim_bidi;
-                                       max = qc->rx.stream_max_bidi;
+                                       lim =  qc->rx.stream_lim_bidi;
+                                       max = &qc->rx.stream_max_bidi;
                                }
 
-                               if (strm_frm->id < max) {
+                               if (strm_frm->id < *max) {
                                        TRACE_DATA("Already closed stream", QUIC_EV_CONN_PRSHPKT, qc);
                                }
                                else {
@@ -1067,17 +1067,18 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
                                        }
 
                                        TRACE_DEVEL("No mux for new stream", QUIC_EV_CONN_PRSHPKT, qc);
-                                       if (qc->strm_reject) {
-                                               if (!qc->strm_reject(&qc->ael->pktns->tx.frms, strm_frm->id)) {
+                                       if (!qc->strm_reject) {
+                                               /* This packet will not be acknowledged */
+                                               goto err;
+                                       }
+
+                                       for (; *max <= strm_frm->id; *max += 4) {
+                                               if (!qc->strm_reject(&qc->ael->pktns->tx.frms, *max)) {
                                                        TRACE_ERROR("error on request rejection", QUIC_EV_CONN_PRSHPKT, qc);
                                                        /* This packet will not be acknowledged */
                                                        goto err;
                                                }
                                        }
-                                       else {
-                                               /* This packet will not be acknowledged */
-                                               goto err;
-                                       }
                                }
 
                                break;