#include <haproxy/quic_rx-t.h>
#include <haproxy/proto_quic.h>
-extern struct quic_cid_tree *quic_cid_trees;
+extern struct quic_cid_tree *quic_fe_cid_trees;
+extern struct quic_cid_tree *quic_be_cid_trees;
-struct quic_connection_id *quic_cid_alloc(void);
+struct quic_connection_id *quic_cid_alloc(enum quic_cid_side side);
int quic_cid_generate_random(struct quic_connection_id *conn_id);
int quic_cid_generate_from_hash(struct quic_connection_id *conn_id, uint64_t hash64);
return _quic_cid_tree_idx(cid->data);
}
+/* Returns the tree instance responsible for <conn_id> storage. */
+static inline struct quic_cid_tree *quic_cid_get_tree(const struct quic_connection_id *conn_id)
+{
+ const int tree_idx = quic_cid_tree_idx(&conn_id->cid);
+ return conn_id->side == QUIC_CID_SIDE_FE ?
+ &quic_fe_cid_trees[tree_idx] : &quic_be_cid_trees[tree_idx];
+}
+
/* Remove <conn_id> from global CID tree as a thread-safe operation. */
static inline void quic_cid_delete(struct quic_connection_id *conn_id)
{
- const uchar idx = quic_cid_tree_idx(&conn_id->cid);
- struct quic_cid_tree __maybe_unused *tree = &quic_cid_trees[idx];
+ struct quic_cid_tree __maybe_unused *tree = quic_cid_get_tree(conn_id);
HA_RWLOCK_WRLOCK(QC_CID_LOCK, &tree->lock);
ebmb_delete(&conn_id->node);
*
* . CID global storage
* CIDs generated by haproxy and reuse by the peer as DCID are stored in a
- * global tree. Tree access must only be done under lock protection.
+ * global tree. Tree access must only be done under lock protection. Separate
+ * trees are used on frontend and backend sides.
*
* . CID global tree splitting
- * To reduce thread contention, global CID tree is in reality split into 256
- * distinct tree instances. Each CID is assigned to a single tree instance
+ * To reduce the thread contention, a global CID tree is in reality splitted
+ * into 256 distinct instances. Each CID is assigned to a single tree instance
* based on its content. Use quic_cid_tree_idx() to retrieve the expected tree
* location for a CID.
*
*/
#define QUIC_CID_TREES_CNT 256
-struct quic_cid_tree *quic_cid_trees;
+struct quic_cid_tree *quic_fe_cid_trees;
+struct quic_cid_tree *quic_be_cid_trees;
/* Initialize the stateless reset token attached to <conn_id> connection ID.
* Returns 1 if succeeded, 0 if not.
*
* Returns the CID or NULL on allocation failure.
*/
-struct quic_connection_id *quic_cid_alloc(void)
+struct quic_connection_id *quic_cid_alloc(enum quic_cid_side side)
{
struct quic_connection_id *conn_id;
HA_ATOMIC_STORE(&conn_id->tid, tid);
conn_id->qc = NULL;
+ conn_id->side = side;
TRACE_LEAVE(QUIC_EV_CONN_TXPKT);
return conn_id;
if (new_tid)
*new_tid = -1;
- tree = &quic_cid_trees[quic_cid_tree_idx(&conn_id->cid)];
+ tree = quic_cid_get_tree(conn_id);
HA_RWLOCK_WRLOCK(QC_CID_LOCK, &tree->lock);
node = ebmb_insert(&tree->root, &conn_id->node, conn_id->cid.len);
if (node != &conn_id->node) {
struct ebmb_node *node;
int ret = 0;
- tree = &quic_cid_trees[_quic_cid_tree_idx(cid)];
+ /* This function is only used on frontend side. */
+ tree = &quic_fe_cid_trees[_quic_cid_tree_idx(cid)];
HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
node = ebmb_lookup(&tree->root, cid, cid_len);
if (node) {
struct ebmb_node *node;
int cid_tid = -1;
- tree = &quic_cid_trees[_quic_cid_tree_idx(cid)];
+ /* This function is only used on frontend side. */
+ tree = &quic_fe_cid_trees[_quic_cid_tree_idx(cid)];
HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
node = ebmb_lookup(&tree->root, cid, cid_len);
if (node) {
orig.len = cid_len;
derive_cid = quic_derive_cid(&orig, cli_addr);
- tree = &quic_cid_trees[quic_cid_tree_idx(&derive_cid)];
+ tree = &quic_fe_cid_trees[quic_cid_tree_idx(&derive_cid)];
HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
node = ebmb_lookup(&tree->root, cid, cid_len);
if (node) {
TRACE_ENTER(QUIC_EV_CONN_RXPKT);
*new_tid = -1;
- /* First look into DCID tree. */
- tree = &quic_cid_trees[_quic_cid_tree_idx(pkt->dcid.data)];
+ /* First look into DCID tree.
+ * This function is only used on frontend side.
+ */
+ tree = &quic_fe_cid_trees[_quic_cid_tree_idx(pkt->dcid.data)];
HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
node = ebmb_lookup(&tree->root, pkt->dcid.data, pkt->dcid.len);
HA_RWLOCK_RDUNLOCK(QC_CID_LOCK, &tree->lock);
- tree = &quic_cid_trees[quic_cid_tree_idx(&derive_cid)];
+ tree = &quic_fe_cid_trees[quic_cid_tree_idx(&derive_cid)];
HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
node = ebmb_lookup(&tree->root, derive_cid.data, derive_cid.len);
}
return ret;
}
-static int quic_alloc_global_cid_tree(void)
+static int quic_alloc_global_fe_cid_tree(void)
+{
+ int i;
+
+ quic_fe_cid_trees = calloc(QUIC_CID_TREES_CNT, sizeof(*quic_fe_cid_trees));
+ if (!quic_fe_cid_trees) {
+ ha_alert("Failed to allocate global quic CIDs trees.\n");
+ return 0;
+ }
+
+ for (i = 0; i < QUIC_CID_TREES_CNT; ++i) {
+ HA_RWLOCK_INIT(&quic_fe_cid_trees[i].lock);
+ quic_fe_cid_trees[i].root = EB_ROOT_UNIQUE;
+ }
+
+ return 1;
+}
+REGISTER_POST_CHECK(quic_alloc_global_fe_cid_tree);
+
+static int quic_deallocate_global_fe_cid_tree(void)
+{
+ ha_free(&quic_fe_cid_trees);
+ return 1;
+}
+REGISTER_POST_DEINIT(quic_deallocate_global_fe_cid_tree);
+
+static int quic_alloc_global_be_cid_tree(void)
{
int i;
- quic_cid_trees = calloc(QUIC_CID_TREES_CNT, sizeof(*quic_cid_trees));
- if (!quic_cid_trees) {
+ quic_be_cid_trees = calloc(QUIC_CID_TREES_CNT, sizeof(*quic_be_cid_trees));
+ if (!quic_be_cid_trees) {
ha_alert("Failed to allocate global quic CIDs trees.\n");
return 0;
}
for (i = 0; i < QUIC_CID_TREES_CNT; ++i) {
- HA_RWLOCK_INIT(&quic_cid_trees[i].lock);
- quic_cid_trees[i].root = EB_ROOT_UNIQUE;
+ HA_RWLOCK_INIT(&quic_be_cid_trees[i].lock);
+ quic_be_cid_trees[i].root = EB_ROOT_UNIQUE;
}
return 1;
}
-REGISTER_POST_CHECK(quic_alloc_global_cid_tree);
+REGISTER_POST_CHECK(quic_alloc_global_be_cid_tree);
-static int quic_deallocate_global_cid_tree(void)
+static int quic_deallocate_global_be_cid_tree(void)
{
- ha_free(&quic_cid_trees);
+ ha_free(&quic_be_cid_trees);
return 1;
}
-REGISTER_POST_DEINIT(quic_deallocate_global_cid_tree);
+REGISTER_POST_DEINIT(quic_deallocate_global_be_cid_tree);