MINOR: quic: refactor qc_new_conn() prototype

The objective of this patch is to streamline qc_new_conn() usage so that
it is similar for frontend and backend sides.

Previously, several parameters were set only for frontend connections.
These arguments are replaced by a single quic_rx_packet argument, which
represents the INITIAL packet triggering the connection allocation on
the server side. For a QUIC client endpoint, it remains NULL. This usage
is consider more explicit.

As a minor change, <target> is moved as the first argument of the
function. This is considered useful as this argument determines whether
the connection is a frontend or backend entry.

Along with these changes, qc_new_conn() documentation has been reworded
so that it is now up-to-date with the newest usage.
This commit is contained in:
Amaury Denoyelle 2025-11-12 11:35:25 +01:00
parent 49edaca513
commit 133f100467
4 changed files with 43 additions and 46 deletions

View File

@ -64,13 +64,12 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta
void quic_conn_closed_err_count_inc(struct quic_conn *qc, struct quic_frame *frm); void quic_conn_closed_err_count_inc(struct quic_conn *qc, struct quic_frame *frm);
int qc_h3_request_reject(struct quic_conn *qc, uint64_t id); int qc_h3_request_reject(struct quic_conn *qc, uint64_t id);
struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, struct quic_conn *qc_new_conn(void *target, int ipv4,
struct quic_cid *dcid, struct quic_cid *scid, const struct quic_rx_packet *initial_pkt,
const struct quic_cid *token_odcid, const struct quic_cid *token_odcid,
struct quic_connection_id *conn_id, struct quic_connection_id *conn_id,
struct sockaddr_storage *local_addr, struct sockaddr_storage *local_addr,
struct sockaddr_storage *peer_addr, struct sockaddr_storage *peer_addr);
int token, void *owner);
int quic_build_post_handshake_frames(struct quic_conn *qc, int quic_build_post_handshake_frames(struct quic_conn *qc,
struct list *to_frms_list); struct list *to_frms_list);
const struct quic_version *qc_supported_version(uint32_t version); const struct quic_version *qc_supported_version(uint32_t version);

View File

@ -1093,32 +1093,32 @@ struct task *qc_process_timer(struct task *task, void *ctx, unsigned int state)
return task; return task;
} }
/* Allocate a new QUIC connection with <version> as QUIC version. <ipv4> /* Allocate a new QUIC connection. <target> represents the internal connection
* boolean is set to 1 for IPv4 connection, 0 for IPv6. <server> is set to 1 * endpoint, either a listener for a server-side connection or a server on
* for QUIC servers (or haproxy listeners), 0 for QUIC clients. * client side. <ipv4> boolean is set to 1 for IPv4 connection or 0 for IPv6.
* <dcid> is the destination connection ID, <scid> is the source connection ID. *
* This latter <scid> CID as the same value on the wire as the one for <conn_id> * On server side, <initial_pkt> must points to the client INITIAL packet which
* which is the first CID of this connection but a different internal * initiate this connection allocation. It is used as a source to determine the
* representation used to build * QUIC version used and to populate the first set of CIDs. <token_odcid>
* NEW_CONNECTION_ID frames. This is the responsibility of the caller to insert * represents the associated Retry token from the INITIAL packet.
* <conn_id> in the CIDs tree for this connection (qc->cids). *
* <token> is a boolean denoting if a token was received for this connection * On client side, both <initial_pkt> and <token_odcid> must be NULL. In this
* from an Initial packet. * case, the version is hardcoded to QUICv1. A random CID will be generated to
* <token_odcid> is the original destination connection ID which was embedded * be used as DCID of the first INITIAL packet sent to the server.
* into the Retry token sent to the client before instantiated this connection. *
* Parameter <conn_id> must be set to the CID generated locally. It will serve
* to identify the connection when datagrams dispatch is performed.
*
* Endpoints addresses are specified via <local_addr> and <peer_addr>. * Endpoints addresses are specified via <local_addr> and <peer_addr>.
* Returns the connection if succeeded, NULL if not. *
* For QUIC clients, <dcid>, <scid> and <token_odcid> must be null, and <token> * Returns the newly allocated quic_conn instance on success or NULL on error.
* value must be 0. This is the responsibility of the caller to ensure this is
* the case.
*/ */
struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4, struct quic_conn *qc_new_conn(void *target, int ipv4,
struct quic_cid *dcid, struct quic_cid *scid, const struct quic_rx_packet *initial_pkt,
const struct quic_cid *token_odcid, const struct quic_cid *token_odcid,
struct quic_connection_id *conn_id, struct quic_connection_id *conn_id,
struct sockaddr_storage *local_addr, struct sockaddr_storage *local_addr,
struct sockaddr_storage *peer_addr, struct sockaddr_storage *peer_addr)
int token, void *target)
{ {
struct quic_conn *qc = NULL; struct quic_conn *qc = NULL;
struct listener *l = objt_listener(target); struct listener *l = objt_listener(target);
@ -1221,6 +1221,7 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
} }
*qc->cids = EB_ROOT; *qc->cids = EB_ROOT;
qc->next_cid_seq_num = 0; qc->next_cid_seq_num = 0;
qc->scid = conn_id->cid;
/* QUIC Server (or listener). */ /* QUIC Server (or listener). */
if (l) { if (l) {
@ -1233,13 +1234,13 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
qc->flags |= QUIC_FL_CONN_UDP_GSO_EIO; qc->flags |= QUIC_FL_CONN_UDP_GSO_EIO;
/* Mark this connection as having not received any token when 0-RTT is enabled. */ /* Mark this connection as having not received any token when 0-RTT is enabled. */
if (l->bind_conf->ssl_conf.early_data && !token) if (l->bind_conf->ssl_conf.early_data && !initial_pkt->token_len)
qc->flags |= QUIC_FL_CONN_NO_TOKEN_RCVD; qc->flags |= QUIC_FL_CONN_NO_TOKEN_RCVD;
qc->state = QUIC_HS_ST_SERVER_INITIAL; qc->state = QUIC_HS_ST_SERVER_INITIAL;
/* Copy the client original DCID. */ /* Copy the client original DCID. */
qc->odcid = *dcid; qc->odcid = initial_pkt->dcid;
/* Copy the packet SCID to reuse it as DCID for sending */ /* Copy the packet SCID to reuse it as DCID for sending */
qc->dcid = *scid; qc->dcid = initial_pkt->scid;
} }
/* QUIC Client (outgoing connection to servers) */ /* QUIC Client (outgoing connection to servers) */
else { else {
@ -1250,19 +1251,16 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
qc->state = QUIC_HS_ST_CLIENT_INITIAL; qc->state = QUIC_HS_ST_CLIENT_INITIAL;
/* This is the original connection ID from the peer server /* Randomly generate the first DCID used for the first INITIAL
* point of view. * packet sent by our endpoint as client and save it as ODCID.
* It will be replaced by a peer chosen value.
*/ */
if (RAND_bytes(qc->dcid.data, sizeof(qc->dcid.data)) != 1) if (RAND_bytes(qc->dcid.data, sizeof(qc->dcid.data)) != 1)
goto err; goto err;
qc->dcid.len = sizeof(qc->dcid.data); qc->dcid.len = sizeof(qc->dcid.data);
qc->odcid = qc->dcid;
memcpy(&qc->odcid, qc->dcid.data, sizeof(qc->dcid.data));
qc->odcid.len = qc->dcid.len;
dcid = &qc->dcid;
} }
qc->err = quic_err_transport(QC_ERR_NO_ERROR); qc->err = quic_err_transport(QC_ERR_NO_ERROR);
/* Listener only: if connection is instantiated due to an INITIAL packet with an /* Listener only: if connection is instantiated due to an INITIAL packet with an
@ -1300,15 +1298,14 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
_HA_ATOMIC_INC(&jobs); _HA_ATOMIC_INC(&jobs);
} }
/* Select our SCID which is the first CID with 0 as sequence number. */
qc->scid = conn_id->cid;
if (!qc_enc_level_alloc(qc, &qc->ipktns, &qc->iel, ssl_encryption_initial)) { if (!qc_enc_level_alloc(qc, &qc->ipktns, &qc->iel, ssl_encryption_initial)) {
TRACE_ERROR("Could not initialize an encryption level", QUIC_EV_CONN_INIT, qc); TRACE_ERROR("Could not initialize an encryption level", QUIC_EV_CONN_INIT, qc);
goto err; goto err;
} }
qc->original_version = qv; qc->original_version = initial_pkt ?
initial_pkt->version : quic_version_1;
qc->negotiated_version = NULL; qc->negotiated_version = NULL;
qc->tps_tls_ext = (qc->original_version->num & 0xff000000) == 0xff000000 ? qc->tps_tls_ext = (qc->original_version->num & 0xff000000) == 0xff000000 ?
TLS_EXTENSION_QUIC_TRANSPORT_PARAMETERS_DRAFT: TLS_EXTENSION_QUIC_TRANSPORT_PARAMETERS_DRAFT:
@ -1385,7 +1382,10 @@ struct quic_conn *qc_new_conn(const struct quic_version *qv, int ipv4,
!quic_conn_init_idle_timer_task(qc, prx)) !quic_conn_init_idle_timer_task(qc, prx))
goto err; goto err;
if (!qc_new_isecs(qc, &qc->iel->tls_ctx, qc->original_version, dcid->data, dcid->len, !!l)) /* INITIAL secrets are derived from the DCID of the INITIAL packet.
* This corresponds to quic_conn <odcid> field.
*/
if (!qc_new_isecs(qc, &qc->iel->tls_ctx, qc->original_version, qc->odcid.data, qc->odcid.len, !!l))
goto err; goto err;
/* Counters initialization */ /* Counters initialization */

View File

@ -1825,9 +1825,8 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
pool_free(pool_head_quic_connection_id, conn_id); pool_free(pool_head_quic_connection_id, conn_id);
} }
else { else {
qc = qc_new_conn(pkt->version, ipv4, &pkt->dcid, &pkt->scid, &token_odcid, qc = qc_new_conn(l, ipv4, pkt, &token_odcid,
conn_id, &dgram->daddr, &pkt->saddr, conn_id, &dgram->daddr, &pkt->saddr);
!!pkt->token_len, l);
if (qc == NULL) { if (qc == NULL) {
quic_cid_delete(conn_id); /* Removes CID from global tree as it points to a NULL qc. */ quic_cid_delete(conn_id); /* Removes CID from global tree as it points to a NULL qc. */
pool_free(pool_head_quic_connection_id, conn_id); pool_free(pool_head_quic_connection_id, conn_id);

View File

@ -162,8 +162,7 @@ static int qc_conn_init(struct connection *conn, void **xprt_ctx)
goto out; goto out;
} }
qc = qc_new_conn(quic_version_1, ipv4, NULL, NULL, NULL, qc = qc_new_conn(srv, ipv4, NULL, NULL, conn_id, NULL, &srv->addr);
conn_id, NULL, &srv->addr, 0, srv);
if (!qc) { if (!qc) {
pool_free(pool_head_quic_connection_id, conn_id); pool_free(pool_head_quic_connection_id, conn_id);
goto out; goto out;