From: Amaury Denoyelle Date: Thu, 12 Nov 2026 09:34:53 +0000 (+0100) Subject: BUG/MEDIUM: quic: limit reject after MUX closure to once per stream X-Git-Tag: v3.5-dev12~33 X-Git-Url: https://git.kaiwu.me/%7B@url%7D?a=commitdiff_plain;h=8de80ccc96000a1780969497c2b00be6eef89c1f;p=haproxy.git BUG/MEDIUM: quic: limit reject after MUX closure to once per stream 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. --- diff --git a/include/haproxy/quic_conn-t.h b/include/haproxy/quic_conn-t.h index 9f7d955df..9870c9938 100644 --- a/include/haproxy/quic_conn-t.h +++ b/include/haproxy/quic_conn-t.h @@ -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 */ diff --git a/src/quic_rx.c b/src/quic_rx.c index cd8244dd0..92d84ef4b 100644 --- a/src/quic_rx.c +++ b/src/quic_rx.c @@ -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;