summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Denoyelle <adenoyelle@haproxy.com>2021-11-24 15:32:46 +0100
committerAmaury Denoyelle <adenoyelle@haproxy.com>2021-11-25 11:41:29 +0100
commitd6a352a58b4b890d203fb3dc489317f65a044c0f (patch)
tree3c5c8217149c1f3106adc6d6f39ef4d1a2aae04d
parent42b9f1c6dd6ffbe978112d450bfad5bca812c1b7 (diff)
downloadhaproxy-d6a352a58b4b890d203fb3dc489317f65a044c0f.tar.gz
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.
-rw-r--r--include/haproxy/xprt_quic-t.h14
-rw-r--r--include/haproxy/xprt_quic.h11
-rw-r--r--src/xprt_quic.c44
3 files changed, 54 insertions, 15 deletions
diff --git a/include/haproxy/xprt_quic-t.h b/include/haproxy/xprt_quic-t.h
index ee7b19d34..91188c3c5 100644
--- a/include/haproxy/xprt_quic-t.h
+++ b/include/haproxy/xprt_quic-t.h
@@ -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 */
diff --git a/include/haproxy/xprt_quic.h b/include/haproxy/xprt_quic.h
index 2b59c37a4..018b30422 100644
--- a/include/haproxy/xprt_quic.h
+++ b/include/haproxy/xprt_quic.h
@@ -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 */
diff --git a/src/xprt_quic.c b/src/xprt_quic.c
index c5974052f..c2d753ddc 100644
--- a/src/xprt_quic.c
+++ b/src/xprt_quic.c
@@ -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;