From 77d37b07b182a3bfd8f70f3f3639a75ddcc32b06 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 20 Apr 2023 19:03:49 +0200 Subject: [PATCH] MINOR: quic: support migrating the listener as well When migrating a quic_conn to another thread, we may need to also switch the listener if the thread belongs to another group. When this happens, the freshly created connection will already have the target listener, so let's just pick it from the connection and use it in qc_set_tid_affinity(). Note that it will be the caller's responsibility to guarantee this. --- include/haproxy/quic_conn.h | 2 +- src/proto_quic.c | 6 +++++- src/quic_conn.c | 15 ++++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/haproxy/quic_conn.h b/include/haproxy/quic_conn.h index 3764dceb9..bfd66c470 100644 --- a/include/haproxy/quic_conn.h +++ b/include/haproxy/quic_conn.h @@ -700,7 +700,7 @@ static inline void quic_handle_stopping(void) } } -int qc_set_tid_affinity(struct quic_conn *qc, uint tid); +int qc_set_tid_affinity(struct quic_conn *qc, uint new_tid, struct listener *new_li); void qc_finalize_affinity_rebind(struct quic_conn *qc); #endif /* USE_QUIC */ diff --git a/src/proto_quic.c b/src/proto_quic.c index 8c263772d..76583298e 100644 --- a/src/proto_quic.c +++ b/src/proto_quic.c @@ -707,10 +707,14 @@ static void quic_disable_listener(struct listener *l) fd_stop_recv(l->rx.fd); } +/* change the connection's thread to . For frontend connections, the + * target is a listener, and the caller is responsible for guaranteeing that + * the listener assigned to the connection is bound to the requested thread. + */ static int quic_set_affinity(struct connection *conn, int new_tid) { struct quic_conn *qc = conn->handle.qc; - return qc_set_tid_affinity(qc, new_tid); + return qc_set_tid_affinity(qc, new_tid, objt_listener(conn->target)); } static int quic_alloc_dghdlrs(void) diff --git a/src/quic_conn.c b/src/quic_conn.c index 314c978c4..b474e7209 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -8391,12 +8391,14 @@ int qc_notify_send(struct quic_conn *qc) } /* Move a QUIC connection and its resources from the current thread to the - * new one . After this call, the connection cannot be dereferenced - * anymore on the current thread. + * new one optionally in association with (since it may need + * to change when migrating to a thread from a different group, otherwise leave + * it NULL). After this call, the connection cannot be dereferenced anymore on + * the current thread. * * Returns 0 on success else non-zero. */ -int qc_set_tid_affinity(struct quic_conn *qc, uint new_tid) +int qc_set_tid_affinity(struct quic_conn *qc, uint new_tid, struct listener *new_li) { struct task *t1 = NULL, *t2 = NULL; struct tasklet *t3 = NULL; @@ -8457,6 +8459,13 @@ int qc_set_tid_affinity(struct quic_conn *qc, uint new_tid) node = eb64_first(&qc->cids); BUG_ON(!node || eb64_next(node)); /* One and only one CID must be present before affinity rebind. */ conn_id = eb64_entry(node, struct quic_connection_id, seq_num); + + /* At this point no connection was accounted for yet on this + * listener so it's OK to just swap the pointer. + */ + if (new_li && new_li != qc->li) + qc->li = new_li; + /* Rebinding is considered done when CID points to the new thread. No * access should be done to quic-conn instance after it. */