MINOR: quic: get rid of ->target quic_conn struct member

The ->li (struct listener *) member of quic_conn struct was replaced by a
->target (struct obj_type *) member by this commit:

    MINOR: quic-be: get rid of ->li quic_conn member

to abstract the connection type (front or back) when implementing QUIC for the
backends. In these cases, ->target was a pointer to the ojb_type of a server
struct. This could not work with the dynamic servers contrary to the listeners
which are not dynamic.

This patch almost reverts the one mentioned above. ->target pointer to obj_type member
is replaced by ->li pointer to listener struct member. As the listener are not
dynamic, this is easy to do this. All one has to do is to replace the
objt_listener(qc->target) statement by qc->li where applicable.

For the backend connection, when needed, this is always qc->conn->target which is
used only when qc->conn is initialized. The only "problematic" case is for
quic_dgram_parse() which takes a pointer to an obj_type as third argument.
But this obj_type is only used to call quic_rx_pkt_parse(). Inside this function
it is used to access the proxy counters of the connection thanks to qc_counters().
So, this obj_type argument may be null for now on with this patch. This is the
reason why qc_counters() is modified to take this into consideration.
This commit is contained in:
Frederic Lecaille 2025-09-09 11:49:33 +02:00
parent 5354c24c76
commit 47bb15ca84
13 changed files with 47 additions and 34 deletions

View File

@ -322,7 +322,7 @@ struct qcc_app_ops;
* with a connection \ * with a connection \
*/ \ */ \
struct eb_root *cids; \ struct eb_root *cids; \
enum obj_type *target; \ struct listener *li; \
/* Idle timer task */ \ /* Idle timer task */ \
struct task *idle_timer_task; \ struct task *idle_timer_task; \
unsigned int idle_expire; \ unsigned int idle_expire; \

View File

@ -173,9 +173,14 @@ static inline void quic_free_ncbuf(struct ncbuf *ncbuf)
static inline void *qc_counters(enum obj_type *o, const struct stats_module *m) static inline void *qc_counters(enum obj_type *o, const struct stats_module *m)
{ {
struct proxy *p; struct proxy *p;
struct listener *l = objt_listener(o); struct listener *l;
struct server *s = objt_server(o); struct server *s;
if (!o)
return NULL;
l = objt_listener(o);
s = objt_server(o);
p = l ? l->bind_conf->frontend : p = l ? l->bind_conf->frontend :
s ? s->proxy : NULL; s ? s->proxy : NULL;

View File

@ -79,8 +79,8 @@ static inline char qc_test_fd(struct quic_conn *qc)
*/ */
static inline int qc_fd(struct quic_conn *qc) static inline int qc_fd(struct quic_conn *qc)
{ {
/* TODO: check this: For backends, qc->fd is always initialized */ /* For backends, qc->fd is always initialized */
return qc_test_fd(qc) ? qc->fd : __objt_listener(qc->target)->rx.fd; return qc_test_fd(qc) ? qc->fd : qc->li->rx.fd;
} }
/* Try to increment <l> handshake current counter. If listener limit is /* Try to increment <l> handshake current counter. If listener limit is

View File

@ -1425,8 +1425,8 @@ static int cli_io_handler_show_fd(struct appctx *appctx)
#if defined(USE_QUIC) #if defined(USE_QUIC)
else if (fdt.iocb == quic_conn_sock_fd_iocb) { else if (fdt.iocb == quic_conn_sock_fd_iocb) {
qc = fdtab[fd].owner; qc = fdtab[fd].owner;
li = qc ? objt_listener(qc->target) : NULL; li = qc ? qc->li : NULL;
sv = qc ? objt_server(qc->target) : NULL; sv = qc ? (qc->conn ? objt_server(qc->conn->target) : NULL) : NULL;
xprt_ctx = qc ? qc->xprt_ctx : NULL; xprt_ctx = qc ? qc->xprt_ctx : NULL;
conn = qc ? qc->conn : NULL; conn = qc ? qc->conn : NULL;
xprt = conn ? conn->xprt : NULL; // in fact it's &ssl_quic xprt = conn ? conn->xprt : NULL; // in fact it's &ssl_quic

View File

@ -181,10 +181,11 @@ static void dump_quic_oneline(struct show_quic_ctx *ctx, struct quic_conn *qc)
char bufaddr[INET6_ADDRSTRLEN], bufport[6]; char bufaddr[INET6_ADDRSTRLEN], bufport[6];
int ret; int ret;
unsigned char cid_len; unsigned char cid_len;
struct listener *l = objt_listener(qc->target); struct listener *l = qc->li;
ret = chunk_appendf(&trash, "%p[%02u]/%-.12s ", qc, ctx->thr, ret = chunk_appendf(&trash, "%p[%02u]/%-.12s ", qc, ctx->thr,
l ? l->bind_conf->frontend->id : __objt_server(qc->target)->id); l ? l->bind_conf->frontend->id :
qc->conn ? __objt_server(qc->conn->target)->id : "UNKNOWN");
chunk_appendf(&trash, "%*s", 36 - ret, " "); /* align output */ chunk_appendf(&trash, "%*s", 36 - ret, " "); /* align output */

View File

@ -749,7 +749,7 @@ static struct quic_conn_closed *qc_new_cc_conn(struct quic_conn *qc)
cc_qc->dcid = qc->dcid; cc_qc->dcid = qc->dcid;
cc_qc->scid = qc->scid; cc_qc->scid = qc->scid;
cc_qc->target = qc->target; cc_qc->li = qc->li;
cc_qc->cids = qc->cids; cc_qc->cids = qc->cids;
cc_qc->idle_timer_task = qc->idle_timer_task; cc_qc->idle_timer_task = qc->idle_timer_task;
@ -1113,7 +1113,7 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
goto err; goto err;
} }
qc->target = target; qc->li = l;
/* Now that quic_conn instance is allocated, quic_conn_release() will /* Now that quic_conn instance is allocated, quic_conn_release() will
* ensure global accounting is decremented. * ensure global accounting is decremented.
*/ */
@ -1418,7 +1418,7 @@ int qc_handle_conn_migration(struct quic_conn *qc,
* used during the handshake, unless the endpoint has acted on a * used during the handshake, unless the endpoint has acted on a
* preferred_address transport parameter from the peer. * preferred_address transport parameter from the peer.
*/ */
if (__objt_listener(qc->target)->bind_conf->quic_params.disable_active_migration) { if (qc->li->bind_conf->quic_params.disable_active_migration) {
TRACE_ERROR("Active migration was disabled, datagram dropped", QUIC_EV_CONN_LPKT, qc); TRACE_ERROR("Active migration was disabled, datagram dropped", QUIC_EV_CONN_LPKT, qc);
goto err; goto err;
} }
@ -1548,8 +1548,8 @@ int quic_conn_release(struct quic_conn *qc)
*/ */
if (MT_LIST_INLIST(&qc->accept_list)) { if (MT_LIST_INLIST(&qc->accept_list)) {
MT_LIST_DELETE(&qc->accept_list); MT_LIST_DELETE(&qc->accept_list);
BUG_ON(__objt_listener(qc->target)->rx.quic_curr_accept == 0); BUG_ON(qc->li->rx.quic_curr_accept == 0);
HA_ATOMIC_DEC(&__objt_listener(qc->target)->rx.quic_curr_accept); HA_ATOMIC_DEC(&qc->li->rx.quic_curr_accept);
} }
/* Subtract last congestion window from global memory counter. */ /* Subtract last congestion window from global memory counter. */
@ -1622,8 +1622,8 @@ int quic_conn_release(struct quic_conn *qc)
/* Connection released before handshake completion. */ /* Connection released before handshake completion. */
if (unlikely(qc->state < QUIC_HS_ST_COMPLETE)) { if (unlikely(qc->state < QUIC_HS_ST_COMPLETE)) {
if (!qc_is_back(qc)) { if (!qc_is_back(qc)) {
BUG_ON(__objt_listener(qc->target)->rx.quic_curr_handshake == 0); BUG_ON(qc->li->rx.quic_curr_handshake == 0);
HA_ATOMIC_DEC(&__objt_listener(qc->target)->rx.quic_curr_handshake); HA_ATOMIC_DEC(&qc->li->rx.quic_curr_handshake);
} }
} }
@ -2031,8 +2031,8 @@ void qc_bind_tid_commit(struct quic_conn *qc, struct listener *new_li)
/* At this point no connection was accounted for yet on this /* At this point no connection was accounted for yet on this
* listener so it's OK to just swap the pointer. * listener so it's OK to just swap the pointer.
*/ */
if (new_li && new_li != __objt_listener(qc->target)) { if (new_li && new_li != qc->li) {
qc->target = &new_li->obj_type; qc->li = new_li;
/* Update GSO conn support based on new listener status. */ /* Update GSO conn support based on new listener status. */
if (HA_ATOMIC_LOAD(&new_li->flags) & LI_F_UDP_GSO_NOTSUPP) if (HA_ATOMIC_LOAD(&new_li->flags) & LI_F_UDP_GSO_NOTSUPP)

View File

@ -1674,7 +1674,9 @@ static inline int quic_token_validate(struct quic_rx_packet *pkt,
goto leave; goto leave;
} }
/* Find the associated connection to the packet <pkt> or create a new one if /* Listener only function.
*
* Find the associated connection to the packet <pkt> or create a new one if
* this is an Initial packet. <dgram> is the datagram containing the packet and * this is an Initial packet. <dgram> is the datagram containing the packet and
* <l> is the listener instance on which it was received. * <l> is the listener instance on which it was received.
* *
@ -2112,7 +2114,8 @@ static int quic_rx_pkt_parse(struct quic_conn *qc, struct quic_rx_packet *pkt,
return 0; return 0;
drop: drop:
HA_ATOMIC_INC(&prx_counters->dropped_pkt); if (prx_counters)
HA_ATOMIC_INC(&prx_counters->dropped_pkt);
drop_silent: drop_silent:
if (!pkt->len) if (!pkt->len)
pkt->len = end - beg; pkt->len = end - beg;
@ -2308,6 +2311,9 @@ static void qc_rx_pkt_handle(struct quic_conn *qc, struct quic_rx_packet *pkt,
* function will thus retrieve the connection from the CID tree or allocate a * function will thus retrieve the connection from the CID tree or allocate a
* new one if possible. <li> is the listener attached to the receiver. * new one if possible. <li> is the listener attached to the receiver.
* *
* Note that for a QUIC backend, <from_qc> is never NULL. <o> is never NULL
* for a QUIC frontend.
*
* Returns 0 on success else non-zero. If an error happens, some packets from * Returns 0 on success else non-zero. If an error happens, some packets from
* the datagram may not have been parsed. * the datagram may not have been parsed.
*/ */

View File

@ -87,7 +87,7 @@ int quic_sock_get_dst(struct connection *conn, struct sockaddr *addr, socklen_t
memcpy(addr, &qc->peer_addr, len); memcpy(addr, &qc->peer_addr, len);
} else { } else {
struct sockaddr_storage *from; struct sockaddr_storage *from;
struct listener *l = objt_listener(qc->target); struct listener *l = qc->li;
/* Return listener address if IP_PKTINFO or friends are not /* Return listener address if IP_PKTINFO or friends are not
* supported by the socket. * supported by the socket.
@ -701,7 +701,7 @@ static int qc_may_use_saddr(struct quic_conn *qc)
* possible. This is not useful if the listening socket is bound to * possible. This is not useful if the listening socket is bound to
* a specific address. It is even prohibited on FreeBSD. * a specific address. It is even prohibited on FreeBSD.
*/ */
return (!is_addr(&__objt_listener(qc->target)->rx.addr) && return (!is_addr(&qc->li->rx.addr) &&
is_addr(&qc->local_addr)); is_addr(&qc->local_addr));
} }
@ -839,7 +839,7 @@ int qc_rcv_buf(struct quic_conn *qc)
struct buffer buf = BUF_NULL; struct buffer buf = BUF_NULL;
unsigned char *dgram_buf; unsigned char *dgram_buf;
ssize_t ret = 0; ssize_t ret = 0;
struct listener *l = objt_listener(qc->target); struct listener *l = qc->li;
/* Do not call this if quic-conn FD is uninitialized. */ /* Do not call this if quic-conn FD is uninitialized. */
BUG_ON(qc->fd < 0); BUG_ON(qc->fd < 0);
@ -948,7 +948,8 @@ int qc_rcv_buf(struct quic_conn *qc)
continue; continue;
} }
quic_dgram_parse(new_dgram, qc, qc->target); quic_dgram_parse(new_dgram, qc, l ? &l->obj_type :
(qc->conn ? &__objt_server(qc->conn->target)->obj_type : NULL));
/* A datagram must always be consumed after quic_parse_dgram(). */ /* A datagram must always be consumed after quic_parse_dgram(). */
BUG_ON(new_dgram->buf); BUG_ON(new_dgram->buf);
} while (ret > 0); } while (ret > 0);
@ -975,7 +976,7 @@ int qc_rcv_buf(struct quic_conn *qc)
void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src, void qc_alloc_fd(struct quic_conn *qc, const struct sockaddr_storage *src,
const struct sockaddr_storage *dst) const struct sockaddr_storage *dst)
{ {
struct listener *l = __objt_listener(qc->target); struct listener *l = qc->li;
struct bind_conf *bc = l->bind_conf; struct bind_conf *bc = l->bind_conf;
struct proxy *p = bc->frontend; struct proxy *p = bc->frontend;
int fd = -1; int fd = -1;
@ -1083,7 +1084,7 @@ struct quic_accept_queue *quic_accept_queues;
void quic_accept_push_qc(struct quic_conn *qc) void quic_accept_push_qc(struct quic_conn *qc)
{ {
struct quic_accept_queue *queue = &quic_accept_queues[tid]; struct quic_accept_queue *queue = &quic_accept_queues[tid];
struct listener *l = __objt_listener(qc->target); struct listener *l = qc->li;
struct li_per_thread *lthr = &l->per_thr[ti->ltid]; struct li_per_thread *lthr = &l->per_thr[ti->ltid];
/* A connection must only be accepted once per instance. */ /* A connection must only be accepted once per instance. */

View File

@ -938,7 +938,7 @@ int qc_ssl_do_hanshake(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
* handshake level CRYPTO data which are validated by the TLS stack. * handshake level CRYPTO data which are validated by the TLS stack.
*/ */
if (!qc_is_back(qc)) { if (!qc_is_back(qc)) {
if (__objt_listener(qc->target)->bind_conf->ssl_conf.early_data && if (qc->li->bind_conf->ssl_conf.early_data &&
(!qc->ael || !qc->ael->tls_ctx.rx.secret)) { (!qc->ael || !qc->ael->tls_ctx.rx.secret)) {
TRACE_PROTO("SSL handshake in progress", TRACE_PROTO("SSL handshake in progress",
QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err); QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err);
@ -982,7 +982,7 @@ int qc_ssl_do_hanshake(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
qc->flags |= QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS; qc->flags |= QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS;
if (!qc_is_back(qc)) { if (!qc_is_back(qc)) {
struct listener *l = __objt_listener(qc->target); struct listener *l = qc->li;
/* I/O callback switch */ /* I/O callback switch */
qc->wait_event.tasklet->process = quic_conn_app_io_cb; qc->wait_event.tasklet->process = quic_conn_app_io_cb;
qc->state = QUIC_HS_ST_CONFIRMED; qc->state = QUIC_HS_ST_CONFIRMED;
@ -1268,7 +1268,7 @@ int qc_alloc_ssl_sock_ctx(struct quic_conn *qc, struct connection *conn)
ctx->qc = qc; ctx->qc = qc;
if (!qc_is_back(qc)) { if (!qc_is_back(qc)) {
struct bind_conf *bc = __objt_listener(qc->target)->bind_conf; struct bind_conf *bc = qc->li->bind_conf;
if (qc_ssl_sess_init(qc, bc->initial_ctx, &ctx->ssl, NULL, 1) == -1) if (qc_ssl_sess_init(qc, bc->initial_ctx, &ctx->ssl, NULL, 1) == -1)
goto err; goto err;

View File

@ -333,7 +333,7 @@ static int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx)
/* Permanently disable UDP GSO for future conns which use current listener/server instance. */ /* Permanently disable UDP GSO for future conns which use current listener/server instance. */
if (!qc_is_back(qc)) { if (!qc_is_back(qc)) {
struct listener *l = __objt_listener(qc->target); struct listener *l = qc->li;
TRACE_ERROR("mark listener UDP GSO as unsupported", QUIC_EV_CONN_SPPKTS, qc, first_pkt); TRACE_ERROR("mark listener UDP GSO as unsupported", QUIC_EV_CONN_SPPKTS, qc, first_pkt);
HA_ATOMIC_OR(&l->flags, LI_F_UDP_GSO_NOTSUPP); HA_ATOMIC_OR(&l->flags, LI_F_UDP_GSO_NOTSUPP);
} }

View File

@ -174,7 +174,7 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
s = __objt_listener(conn->target)->bind_conf; s = __objt_listener(conn->target)->bind_conf;
#ifdef USE_QUIC #ifdef USE_QUIC
else if (qc) else if (qc)
s = __objt_listener(qc->target)->bind_conf; s = qc->li->bind_conf;
#endif /* USE_QUIC */ #endif /* USE_QUIC */
if (!s) { if (!s) {

View File

@ -132,7 +132,7 @@ int ssl_sock_ocsp_stapling_cbk(SSL *ssl, void *arg)
struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index); struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index);
/* null if not a listener */ /* null if not a listener */
li = objt_listener(qc->target); li = qc->li;
} }
#endif #endif

View File

@ -1135,7 +1135,7 @@ static int ssl_tlsext_ticket_key_cb(SSL *s, unsigned char key_name[16], unsigned
ref = __objt_listener(conn->target)->bind_conf->keys_ref; ref = __objt_listener(conn->target)->bind_conf->keys_ref;
#ifdef USE_QUIC #ifdef USE_QUIC
else if (qc) else if (qc)
ref = __objt_listener(qc->target)->bind_conf->keys_ref; ref = qc->li->bind_conf->keys_ref;
#endif #endif
if (!ref) { if (!ref) {
@ -1691,7 +1691,7 @@ int ssl_sock_bind_verifycbk(int ok, X509_STORE_CTX *x_store)
else { else {
qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index); qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index);
BUG_ON(!qc); /* Must never happen */ BUG_ON(!qc); /* Must never happen */
bind_conf = __objt_listener(qc->target)->bind_conf; bind_conf = qc->li->bind_conf;
ctx = qc->xprt_ctx; ctx = qc->xprt_ctx;
} }
#endif #endif