From 4dd224b5ef35300b4b240ccfed33c312bd3a6bcb Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 24 Mar 2026 16:58:48 +0100 Subject: [PATCH] MINOR: xprt_qstrm: define new xprt module for QMux protocol Define a new XPRT layer for the new QMux protocol. Its role will be to perform the initial exchange of transport parameters. On completion, contrary to XPRT handshake, xprt_qstrm will first init the MUX and then removes itself. This will be necessary so that the parameters can be retrieved by the MUX during its initialization. This patch only declares the new xprt_qstrm along with basic operations. Future commits will implement the proper reception/emission steps. --- Makefile | 2 +- include/haproxy/connection-t.h | 1 + src/xprt_qstrm.c | 118 +++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/xprt_qstrm.c diff --git a/Makefile b/Makefile index 44d014784..41aab3e37 100644 --- a/Makefile +++ b/Makefile @@ -670,7 +670,7 @@ OPTIONS_OBJS += src/mux_quic.o src/h3.o src/quic_rx.o src/quic_tx.o \ src/quic_cc_nocc.o src/quic_cc.o src/quic_pacing.o \ src/h3_stats.o src/quic_stats.o src/qpack-enc.o \ src/qpack-tbl.o src/quic_cc_drs.o src/quic_fctl.o \ - src/quic_enc.o src/mux_quic_qstrm.o + src/quic_enc.o src/mux_quic_qstrm.o src/xprt_qstrm.o endif ifneq ($(USE_QUIC_OPENSSL_COMPAT:0=),) diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 0d7a589fc..2b8927b82 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -345,6 +345,7 @@ enum { XPRT_SSL = 1, XPRT_HANDSHAKE = 2, XPRT_QUIC = 3, + XPRT_QSTRM = 4, XPRT_ENTRIES /* must be last one */ }; diff --git a/src/xprt_qstrm.c b/src/xprt_qstrm.c new file mode 100644 index 000000000..8fccacfb7 --- /dev/null +++ b/src/xprt_qstrm.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct xprt_qstrm_ctx { + struct connection *conn; + struct wait_event *subs; + struct wait_event wait_event; + + const struct xprt_ops *ops_lower; + void *ctx_lower; + + struct quic_transport_params lparams; + struct quic_transport_params rparams; +}; + +DECLARE_STATIC_TYPED_POOL(xprt_qstrm_ctx_pool, "xprt_qstrm_ctx", struct xprt_qstrm_ctx); + +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; + + out: + if (conn->flags & CO_FL_ERROR) { + /* MUX will access members from xprt_ctx on init, so create + * operation should be called before any members are resetted. + */ + ret = conn_create_mux(conn, NULL); + BUG_ON(ret); + + conn->xprt_ctx = ctx->ctx_lower; + conn->xprt = ctx->ops_lower; + conn->mux->wake(conn); + + tasklet_free(ctx->wait_event.tasklet); + pool_free(xprt_qstrm_ctx_pool, ctx); + t = NULL; + } + + return t; +} + +static int xprt_qstrm_add_xprt(struct connection *conn, void *xprt_ctx, + void *ctx_lower, const struct xprt_ops *ops_lower, + void **ctx_older, const struct xprt_ops **ops_older) +{ + struct xprt_qstrm_ctx *ctx = xprt_ctx; + BUG_ON(ctx_older || ops_older); + + ctx->ctx_lower = ctx_lower; + ctx->ops_lower = ops_lower; + + return 0; +} + +static int xprt_qstrm_init(struct connection *conn, void **xprt_ctx) +{ + struct xprt_qstrm_ctx *ctx; + BUG_ON(*xprt_ctx); + + ctx = pool_alloc(xprt_qstrm_ctx_pool); + if (!ctx) { + conn->err_code = CO_ER_SSL_NO_MEM; + return -1; + } + + ctx->conn = conn; + ctx->wait_event.tasklet = tasklet_new(); + if (!ctx->wait_event.tasklet) { + conn->err_code = CO_ER_SSL_NO_MEM; + pool_free(xprt_qstrm_ctx_pool, ctx); + return -1; + } + ctx->wait_event.tasklet->process = xprt_qstrm_io_cb; + ctx->wait_event.tasklet->context = ctx; + ctx->wait_event.events = 0; + + ctx->ctx_lower = NULL; + ctx->ops_lower = NULL; + + *xprt_ctx = ctx; + + return 0; +} + +static int xprt_qstrm_start(struct connection *conn, void *xprt_ctx) +{ + struct xprt_qstrm_ctx *ctx = xprt_ctx; + tasklet_wakeup(ctx->wait_event.tasklet); + return 0; +} + +static void xprt_qstrm_close(struct connection *conn, void *xprt_ctx) +{ + /* TODO not implemented */ + ABORT_NOW(); +} + +struct xprt_ops xprt_qstrm = { + .add_xprt = xprt_qstrm_add_xprt, + .init = xprt_qstrm_init, + .start = xprt_qstrm_start, + .close = xprt_qstrm_close, + .name = "qstrm", +}; + +static void __xprt_qstrm_init(void) +{ + xprt_register(XPRT_QSTRM, &xprt_qstrm); +} +INITCALL0(STG_REGISTER, __xprt_qstrm_init);