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.
This commit is contained in:
Amaury Denoyelle 2026-03-24 16:58:48 +01:00
parent 782894f5b8
commit 4dd224b5ef
3 changed files with 120 additions and 1 deletions

View file

@ -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=),)

View file

@ -345,6 +345,7 @@ enum {
XPRT_SSL = 1,
XPRT_HANDSHAKE = 2,
XPRT_QUIC = 3,
XPRT_QSTRM = 4,
XPRT_ENTRIES /* must be last one */
};

118
src/xprt_qstrm.c Normal file
View file

@ -0,0 +1,118 @@
#include <haproxy/api.h>
#include <haproxy/buf.h>
#include <haproxy/connection.h>
#include <haproxy/fd.h>
#include <haproxy/global.h>
#include <haproxy/pool.h>
#include <haproxy/quic_frame.h>
#include <haproxy/quic_tp-t.h>
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);