From: Amaury Denoyelle Date: Thu, 23 Apr 2026 13:36:08 +0000 (+0200) Subject: MINOR: mux_quic/xprt_qstrm: simplify Rx buffer transfer X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=64b7ef7971bbf0150859f681aaf6ba68c7c0b53c;p=thirdparty%2Fhaproxy.git MINOR: mux_quic/xprt_qstrm: simplify Rx buffer transfer When xprt_qstrm layer is completed, MUX layer is started. Rx buffer from the XPRT layer is transferred to the MUX so that it can handle any extra data following the transport parameters first frame. Since previous commit, QCC Rx buffer is dynamically allocated only when needed. However, qmux_init() must still allocate it when there is data to be transferred from the XPRT layer. As a result, code has been over extended to continue to support this case. This patch simplifies xprt_qstrm API for the Rx buffer transfer. Buffer content and remaining record length can now be retrieved via the single function xprt_qstrm_xfer_rxbuf(). If the buffer is empty, nothing is performed and XPRT layer will release it. If not empty, MUX will take ownership of the buffer from the XPRT layer. --- diff --git a/include/haproxy/xprt_qstrm.h b/include/haproxy/xprt_qstrm.h index 5a992f21f..f8af655b8 100644 --- a/include/haproxy/xprt_qstrm.h +++ b/include/haproxy/xprt_qstrm.h @@ -4,7 +4,6 @@ const struct quic_transport_params *xprt_qstrm_lparams(const void *context); const struct quic_transport_params *xprt_qstrm_rparams(const void *context); -struct buffer *xprt_qstrm_rxbuf(const void *context); -size_t xprt_qstrm_rxrlen(const void *context); +size_t xprt_qstrm_xfer_rxbuf(const void *context, struct buffer *out); #endif /* _HAPROXY_XPRT_QSTRM_H */ diff --git a/src/mux_quic.c b/src/mux_quic.c index d2a1e6e3a..127ff048b 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -3847,25 +3847,13 @@ static int qmux_init(struct connection *conn, struct proxy *prx, } if (!conn_is_quic(conn)) { - struct buffer *xprt_buf; - qcc->tx.qstrm_buf = BUF_NULL; qcc->rx.qstrm_buf = BUF_NULL; - /* Retrieve data if xprt read too much */ - xprt_buf = xprt_qstrm_rxbuf(conn->xprt_ctx); - if (unlikely(b_data(xprt_buf))) { - b_alloc(&qcc->rx.qstrm_buf, DB_MUX_RX); - if (!b_size(&qcc->rx.qstrm_buf)) { - TRACE_ERROR("rx qstrm buf alloc failure", QMUX_EV_QCC_NEW); - goto err; - } - b_xfer(&qcc->rx.qstrm_buf, xprt_buf, b_data(xprt_buf)); - qcc->rx.rlen = xprt_qstrm_rxrlen(conn->xprt_ctx); - } - else { - qcc->rx.rlen = 0; - } + /* Rx buffer is transfered from xprt layer - necessary if too many data where read */ + qcc->rx.rlen = xprt_qstrm_xfer_rxbuf(conn->xprt_ctx, &qcc->rx.qstrm_buf); + /* Cannot have a non empty record with an empty buffer. */ + BUG_ON(qcc->rx.rlen && !b_data(&qcc->rx.qstrm_buf)); } if (conn_is_back(conn)) { diff --git a/src/xprt_qstrm.c b/src/xprt_qstrm.c index 6dcac7725..a03f455a8 100644 --- a/src/xprt_qstrm.c +++ b/src/xprt_qstrm.c @@ -39,16 +39,16 @@ const struct quic_transport_params *xprt_qstrm_rparams(const void *context) return &ctx->rparams; } -/* Returns RX buffer as mutable to allow zero-copy by the caller. */ -struct buffer *xprt_qstrm_rxbuf(void *context) +/* Transfer Rx buffer into . */ +size_t xprt_qstrm_xfer_rxbuf(void *context, struct buffer *out) { struct xprt_qstrm_ctx *ctx = context; - return &ctx->rxbuf; -} -size_t xprt_qstrm_rxrlen(const void *context) -{ - const struct xprt_qstrm_ctx *ctx = context; + if (b_data(&ctx->rxbuf)) { + *out = ctx->rxbuf; + ctx->rxbuf = BUF_NULL; + } + return ctx->rxrlen; } @@ -221,6 +221,10 @@ struct task *xprt_qstrm_io_cb(struct task *t, void *context, unsigned int state) conn->xprt_ctx = ctx->ctx_lower; conn->xprt = ctx->ops_lower; + /* MUX layer is responsible to retrieve any remaining data in + * the Rx buffer prior to reset it. + */ + BUG_ON(b_data(&ctx->rxbuf)); b_free(&ctx->rxbuf); b_free(&ctx->txbuf);