MEDIUM: quic: handle CIDs to rattach received packets to connection

Change the way the CIDs are organized to rattach received packets DCID
to QUIC connection. This is necessary to be able to handle multiple DCID
to one connection.

For this, the quic_connection_id structure has been extended. When
allocated, they are inserted in the receiver CID tree instead of the
quic_conn directly. When receiving a packet, the receiver tree is
inspected to retrieve the quic_connection_id. The quic_connection_id
contains now contains a reference to the QUIC connection.
This commit is contained in:
Amaury Denoyelle 2021-11-24 15:32:46 +01:00
parent 42b9f1c6dd
commit d6a352a58b
3 changed files with 54 additions and 15 deletions

View File

@ -257,12 +257,20 @@ struct quic_cid {
unsigned char len;
};
/* The data structure used to build a set of connection IDs for each connection. */
/* QUIC connection id attached to a QUIC connection.
*
* This structure is used to match received packets DCIDs with the
* corresponding QUIC connection.
*/
struct quic_connection_id {
struct eb64_node seq_num;
uint64_t retire_prior_to;
struct quic_cid cid;
unsigned char stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN];
struct ebmb_node node; /* node for receiver tree, cid.data as key */
struct quic_cid cid; /* CID data */
struct quic_conn *qc; /* QUIC connection using this CID */
};
struct preferred_address {
@ -629,7 +637,7 @@ struct quic_conn {
struct quic_cid odcid;
struct quic_cid dcid; /* DCID of our endpoint - not updated whan a new DCID is used */
struct ebmb_node scid_node;
struct ebmb_node scid_node; /* used only for client side (backend) */
struct quic_cid scid; /* first SCID of our endpoint - not updated when a new SCID is used */
struct eb_root cids; /* tree of quic_connection_id - used to match a received packet DCID with a connection */

View File

@ -29,6 +29,7 @@
#include <stdint.h>
#include <import/eb64tree.h>
#include <import/ebmbtree.h>
#include <haproxy/buf.h>
#include <haproxy/chunk.h>
@ -136,6 +137,13 @@ static inline void free_quic_conn_cids(struct quic_conn *conn)
struct quic_connection_id *cid;
cid = eb64_entry(&node->node, struct quic_connection_id, seq_num);
/* remove the CID from the receiver tree */
HA_RWLOCK_WRLOCK(QUIC_LOCK, &conn->li->rx.cids_lock);
ebmb_delete(&cid->node);
HA_RWLOCK_WRUNLOCK(QUIC_LOCK, &conn->li->rx.cids_lock);
/* remove the CID from the quic_conn tree */
node = eb64_next(node);
eb64_delete(&cid->seq_num);
pool_free(pool_head_quic_connection_id, cid);
@ -163,6 +171,7 @@ static inline void quic_connection_id_to_frm_cpy(struct quic_frame *dst,
* Returns the new CID if succeeded, NULL if not.
*/
static inline struct quic_connection_id *new_quic_cid(struct eb_root *root,
struct quic_conn *qc,
int seq_num)
{
struct quic_connection_id *cid;
@ -179,6 +188,8 @@ static inline struct quic_connection_id *new_quic_cid(struct eb_root *root,
goto err;
}
cid->qc = qc;
cid->seq_num.key = seq_num;
cid->retire_prior_to = 0;
/* insert the allocated CID in the quic_conn tree */

View File

@ -2439,12 +2439,21 @@ static int quic_build_post_handshake_frames(struct quic_conn *qc)
for (i = 1; i < qc->tx.params.active_connection_id_limit; i++) {
struct quic_connection_id *cid;
struct listener *l = __objt_listener(qc->conn->target);
frm = pool_alloc(pool_head_quic_frame);
cid = new_quic_cid(&qc->cids, i);
if (!frm || !cid)
if (!frm)
goto err;
cid = new_quic_cid(&qc->cids, qc, i);
if (!cid)
goto err;
/* insert the allocated CID in the receiver tree */
HA_RWLOCK_WRLOCK(QUIC_LOCK, &l->rx.cids_lock);
ebmb_insert(&l->rx.cids, &cid->node, cid->cid.len);
HA_RWLOCK_WRUNLOCK(QUIC_LOCK, &l->rx.cids_lock);
quic_connection_id_to_frm_cpy(frm, cid);
MT_LIST_APPEND(&qel->pktns->tx.frms, &frm->mt_list);
}
@ -2970,6 +2979,7 @@ static void quic_conn_free(struct quic_conn *conn)
HA_RWLOCK_WRLOCK(QUIC_LOCK, &conn->li->rx.cids_lock);
ebmb_delete(&conn->odcid_node);
ebmb_delete(&conn->scid_node);
HA_RWLOCK_WRUNLOCK(QUIC_LOCK, &conn->li->rx.cids_lock);
for (i = 0; i < QUIC_TLS_ENC_LEVEL_MAX; i++)
@ -3051,6 +3061,7 @@ static struct quic_conn *qc_new_conn(unsigned int version, int ipv4,
/* Initial CID. */
struct quic_connection_id *icid;
char *buf_area;
struct listener *l = NULL;
TRACE_ENTER(QUIC_EV_CONN_INIT);
qc = pool_zalloc(pool_head_quic_conn);
@ -3068,7 +3079,7 @@ static struct quic_conn *qc_new_conn(unsigned int version, int ipv4,
qc->cids = EB_ROOT;
/* QUIC Server (or listener). */
if (server) {
struct listener *l = owner;
l = owner;
HA_ATOMIC_STORE(&qc->state, QUIC_HS_ST_SERVER_INITIAL);
/* Copy the initial DCID. */
@ -3094,12 +3105,19 @@ static struct quic_conn *qc_new_conn(unsigned int version, int ipv4,
/* Initialize the output buffer */
qc->obuf.pos = qc->obuf.data;
icid = new_quic_cid(&qc->cids, 0);
icid = new_quic_cid(&qc->cids, qc, 0);
if (!icid) {
TRACE_PROTO("Could not allocate a new connection ID", QUIC_EV_CONN_INIT);
goto err;
}
/* insert the allocated CID in the receiver tree */
if (server) {
HA_RWLOCK_WRLOCK(QUIC_LOCK, &l->rx.cids_lock);
ebmb_insert(&l->rx.cids, &icid->node, icid->cid.len);
HA_RWLOCK_WRUNLOCK(QUIC_LOCK, &l->rx.cids_lock);
}
/* Select our SCID which is the first CID with 0 as sequence number. */
qc->scid = icid->cid;
@ -3765,10 +3783,6 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char **buf, const unsigned char *end,
HA_RWLOCK_WRLOCK(QUIC_LOCK, &l->rx.cids_lock);
/* Insert the DCID the QUIC client has chosen (only for listeners) */
n = ebmb_insert(&l->rx.odcids, &qc->odcid_node, qc->odcid.len);
if (n == &qc->odcid_node) {
/* Insert our SCID, the connection ID for the QUIC client. */
ebmb_insert(&l->rx.cids, &qc->scid_node, qc->scid.len);
}
HA_RWLOCK_WRUNLOCK(QUIC_LOCK, &l->rx.cids_lock);
/* If the insertion failed, it means that another
@ -3792,15 +3806,20 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char **buf, const unsigned char *end,
node = &qc->odcid_node;
}
else {
if (pkt->type == QUIC_PACKET_TYPE_INITIAL && cids == &l->rx.odcids)
if (pkt->type == QUIC_PACKET_TYPE_INITIAL && cids == &l->rx.odcids) {
qc = ebmb_entry(node, struct quic_conn, odcid_node);
else
qc = ebmb_entry(node, struct quic_conn, scid_node);
}
else {
struct quic_connection_id *cid = ebmb_entry(node, struct quic_connection_id, node);
qc = cid->qc;
}
pkt->qc = qc;
conn_ctx = qc->conn->xprt_ctx;
}
}
else {
struct quic_connection_id *cid;
if (end - *buf < QUIC_CID_LEN) {
TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
goto err;
@ -3813,7 +3832,8 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char **buf, const unsigned char *end,
goto err;
}
qc = ebmb_entry(node, struct quic_conn, scid_node);
cid = ebmb_entry(node, struct quic_connection_id, node);
qc = cid->qc;
conn_ctx = qc->conn->xprt_ctx;
*buf += QUIC_CID_LEN;
pkt->qc = qc;