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 {
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 */
#include <stdint.h>
#include <import/eb64tree.h>
+#include <import/ebmbtree.h>
#include <haproxy/buf.h>
#include <haproxy/chunk.h>
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);
* 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;
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 */
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);
}
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++)
/* 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);
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. */
/* 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;
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
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;
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;