MINOR: quic: finalize affinity change as soon as possible
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 26 Apr 2023 15:15:37 +0000 (17:15 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 26 Apr 2023 15:50:16 +0000 (17:50 +0200)
During accept, a quic-conn is rebind to a new thread. This process is
done in two times :
* first on the original thread via qc_set_tid_affinity()
* then on the newly assigned thread via qc_finalize_affinity_rebind()

Most quic_conn operations (I/O tasklet, task and quic_conn FD socket
read) are reactivated ony after the second step. However, there is a
possibility that datagrams are handled before it via quic_dgram_parse()
when using listener sockets. This does not seem to cause any issue but
this may cause unexpected behavior in the future.

To simplify this, qc_finalize_affinity_rebind() will be called both by
qc_xprt_start() and quic_dgram_parse(). Only one invocation will be
performed thanks to the new flag QUIC_FL_CONN_AFFINITY_CHANGED.

This should be backported up to 2.7.

include/haproxy/quic_conn-t.h
src/quic_conn.c
src/xprt_quic.c

index 113cc61..9bd9119 100644 (file)
@@ -628,6 +628,7 @@ enum qc_mux_state {
 #define QUIC_FL_CONN_RETRANS_NEEDED              (1U << 7)
 #define QUIC_FL_CONN_RETRANS_OLD_DATA            (1U << 8) /* retransmission in progress for probing with already sent data */
 #define QUIC_FL_CONN_TLS_ALERT                   (1U << 9)
+#define QUIC_FL_CONN_AFFINITY_CHANGED            (1U << 10) /* qc_finalize_affinity_rebind() must be called to finalize affinity rebind */
 /* gap here */
 #define QUIC_FL_CONN_HALF_OPEN_CNT_DECREMENTED   (1U << 11) /* The half-open connection counter was decremented */
 #define QUIC_FL_CONN_HANDSHAKE_SPEED_UP          (1U << 12) /* Handshake speeding up was done */
index d768022..254ce58 100644 (file)
@@ -8277,6 +8277,9 @@ int quic_dgram_parse(struct quic_dgram *dgram, struct quic_conn *from_qc,
                        dgram->qc = qc;
                }
 
+               if (qc->flags & QUIC_FL_CONN_AFFINITY_CHANGED)
+                       qc_finalize_affinity_rebind(qc);
+
                if (qc_rx_check_closing(qc, pkt)) {
                        /* Skip the entire datagram. */
                        pkt->len = end - pos;
@@ -8541,6 +8544,7 @@ int qc_set_tid_affinity(struct quic_conn *qc, uint new_tid, struct listener *new
        /* Rebinding is considered done when CID points to the new thread. No
         * access should be done to quic-conn instance after it.
         */
+       qc->flags |= QUIC_FL_CONN_AFFINITY_CHANGED;
        HA_ATOMIC_STORE(&conn_id->tid, new_tid);
        qc = NULL;
 
@@ -8561,6 +8565,10 @@ void qc_finalize_affinity_rebind(struct quic_conn *qc)
 {
        TRACE_ENTER(QUIC_EV_CONN_SET_AFFINITY, qc);
 
+       /* This function must not be called twice after an affinity rebind. */
+       BUG_ON(!(qc->flags & QUIC_FL_CONN_AFFINITY_CHANGED));
+       qc->flags &= ~QUIC_FL_CONN_AFFINITY_CHANGED;
+
        /* Reactivate FD polling if connection socket is active. */
        qc_want_recv(qc);
 
index be9b09c..c3b9c6a 100644 (file)
@@ -132,7 +132,8 @@ static int qc_xprt_start(struct connection *conn, void *ctx)
        qc = conn->handle.qc;
        TRACE_ENTER(QUIC_EV_CONN_NEW, qc);
 
-       qc_finalize_affinity_rebind(qc);
+       if (qc->flags & QUIC_FL_CONN_AFFINITY_CHANGED)
+               qc_finalize_affinity_rebind(qc);
 
        /* mux-quic can now be considered ready. */
        qc->mux_state = QC_MUX_READY;