MINOR: xprt_qstrm/mux-quic: handle extra QMux frames after params

Layer xprt_qstrm is responsible to read the initial QMux transport
parameters frame. However, it could receive more data if some other
frames follow it. This extra content can only be handled by the MUX
layer once initialized.

Theorically, it could have been implemented via MSG_PEEK. However, this
flag is currently ignored by SSL layer. Besides, it is tedious to
implement safely. A new approach has been prefered where the MUX layer
is responsible to retrieve remaining data via xprt_qstrm_rxbuf()
accessor function during its initialization.

Thus, qmux_init() now may retrieve the buffer from xprt_qstrm layer.
This is performed via b_xfer() which will result in a zero copy
transfer. If this happens, tasklet is immediately scheduled to start
demuxing.
This commit is contained in:
Amaury Denoyelle 2026-04-10 09:40:10 +02:00
parent 890831f292
commit fb3b268747
3 changed files with 23 additions and 1 deletions

View File

@ -4,4 +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);
#endif /* _HAPROXY_XPRT_QSTRM_H */

View File

@ -3784,6 +3784,8 @@ 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;
b_alloc(&qcc->tx.qstrm_buf, DB_MUX_TX);
if (!b_size(&qcc->tx.qstrm_buf)) {
@ -3797,6 +3799,11 @@ static int qmux_init(struct connection *conn, struct proxy *prx,
TRACE_ERROR("rx qstrm buf alloc failure", QMUX_EV_QCC_NEW);
goto err;
}
/* Retrieve data if xprt read too much */
xprt_buf = xprt_qstrm_rxbuf(conn->xprt_ctx);
if (unlikely(b_data(xprt_buf)))
b_xfer(&qcc->rx.qstrm_buf, xprt_buf, b_data(xprt_buf));
}
if (conn_is_back(conn)) {
@ -3857,8 +3864,14 @@ static int qmux_init(struct connection *conn, struct proxy *prx,
qcc_reset_idle_start(qcc);
LIST_INIT(&qcc->opening_list);
if (conn_is_quic(conn))
if (conn_is_quic(conn)) {
HA_ATOMIC_STORE(&conn->handle.qc->qcc, qcc);
}
else {
/* Wakeup MUX immediately if data copied from XPRT layer. */
if (unlikely(b_data(&qcc->rx.qstrm_buf)))
tasklet_wakeup(qcc->wait_event.tasklet);
}
/* Register conn as app_ops may use it. */
qcc->conn = conn;

View File

@ -37,6 +37,13 @@ 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)
{
struct xprt_qstrm_ctx *ctx = context;
return &ctx->rxbuf;
}
int conn_recv_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int flag)
{
struct quic_frame frm;