From f1ed1de31752892d58719d7afbe10acc7ce19b97 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Wed, 25 Mar 2026 14:14:20 +0100 Subject: [PATCH] MINOR: xprt_qstrm: implement sending of transport parameters This patch implements QMux emission of transport parameters via xprt_qstrm. Similarly to receive, this is performed in conn_send_qstrm() which uses lower xprt snd_buf operation. The connection must first be flagged with CO_FL_QSTRM_SEND to trigger this step. --- include/haproxy/connection-t.h | 2 +- src/xprt_qstrm.c | 47 +++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index f803aaf41..915818ebd 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -130,7 +130,7 @@ enum { CO_FL_OPT_TOS = 0x00000020, /* connection has a special sockopt tos */ - /* unused : 0x00000040 */ + CO_FL_QSTRM_SEND = 0x00000040, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */ CO_FL_QSTRM_RECV = 0x00000080, /* connection uses QMux protocol, needs to exchange transport parameters before starting mux layer */ /* These flags indicate whether the Control and Transport layers are initialized */ diff --git a/src/xprt_qstrm.c b/src/xprt_qstrm.c index 104197dab..ba14a3825 100644 --- a/src/xprt_qstrm.c +++ b/src/xprt_qstrm.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -69,12 +70,56 @@ int conn_recv_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int fla return 0; } +int conn_send_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int flag) +{ + struct quic_frame frm; + unsigned char *pos, *old, *end; + int ret; + + if (!conn_ctrl_ready(conn)) + goto fail; + + frm.type = QUIC_FT_QX_TRANSPORT_PARAMETERS; + frm.qmux_transport_params.params.initial_max_streams_bidi = 100; + frm.qmux_transport_params.params.initial_max_streams_uni = 3; + frm.qmux_transport_params.params.initial_max_stream_data_bidi_local = qmux_stream_rx_bufsz(); + frm.qmux_transport_params.params.initial_max_stream_data_bidi_remote = qmux_stream_rx_bufsz(); + frm.qmux_transport_params.params.initial_max_stream_data_uni = qmux_stream_rx_bufsz(); + + b_reset(&trash); + old = pos = (unsigned char *)b_head(&trash); + end = (unsigned char *)b_wrap(&trash); + ret = qc_build_frm(&frm, &pos, end, NULL); + BUG_ON(!ret); + b_add(&trash, pos - old); + + ret = ctx->ops_lower->snd_buf(conn, ctx->ctx_lower, &trash, b_data(&trash), + NULL, 0, 0); + BUG_ON(!ret || ret != b_data(&trash)); + + conn->flags &= ~flag; + + return 1; + + fail: + conn->flags |= CO_FL_ERROR; + return 0; +} + struct task *xprt_qstrm_io_cb(struct task *t, void *context, unsigned int state) { struct xprt_qstrm_ctx *ctx = context; struct connection *conn = ctx->conn; int ret; + if (conn->flags & CO_FL_QSTRM_SEND) { + if (!conn_send_qstrm(conn, ctx, CO_FL_QSTRM_SEND)) { + ctx->ops_lower->subscribe(conn, ctx->ctx_lower, + SUB_RETRY_SEND, &ctx->wait_event); + goto out; + } + } + if (conn->flags & CO_FL_QSTRM_RECV) { if (!conn_recv_qstrm(conn, ctx, CO_FL_QSTRM_RECV)) { ctx->ops_lower->subscribe(conn, ctx->ctx_lower, @@ -85,7 +130,7 @@ struct task *xprt_qstrm_io_cb(struct task *t, void *context, unsigned int state) out: if ((conn->flags & CO_FL_ERROR) || - !(conn->flags & CO_FL_QSTRM_RECV)) { + !(conn->flags & (CO_FL_QSTRM_RECV|CO_FL_QSTRM_SEND))) { /* MUX will access members from xprt_ctx on init, so create * operation should be called before any members are resetted. */