]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: quic: trigger fast connection closing on process stopping
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 1 Feb 2023 08:28:55 +0000 (09:28 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 20 Feb 2023 10:20:18 +0000 (11:20 +0100)
With previous commit, quic-conn are now handled as jobs to prevent the
termination of haproxy process. This ensures that QUIC connections are
closed when all data are acknowledged by the client and there is no more
active streams.

The quic-conn layer emits a CONNECTION_CLOSE once the MUX has been
released and all streams are acknowledged. Then, the timer is scheduled
to definitely free the connection after the idle timeout period. This
allows to treat late-arriving packets.

Adjust this procedure to deactivate this timer when process stopping is
in progress. In this case, quic-conn timer is set to expire immediately
to free the quic-conn instance as soon as possible. This allows to
quickly close haproxy process.

This should be backported up to 2.7.

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

index 79f806e06c64aa566d347fcb9cd8b5c107709206..ebe3dfd21592eef892b862dfdbf00aff23cce537 100644 (file)
@@ -623,9 +623,9 @@ enum qc_mux_state {
 #define QUIC_FL_CONN_FINALIZED                   (1U << 26) /* QUIC connection finalized (functional, ready to send/receive) */
 #define QUIC_FL_CONN_NOTIFY_CLOSE                (1U << 27) /* MUX notified about quic-conn imminent closure (idle-timeout or CONNECTION_CLOSE emission/reception) */
 #define QUIC_FL_CONN_EXP_TIMER                   (1U << 28) /* timer has expired, quic-conn can be freed */
-#define QUIC_FL_CONN_CLOSING                     (1U << 29)
-#define QUIC_FL_CONN_DRAINING                    (1U << 30)
-#define QUIC_FL_CONN_IMMEDIATE_CLOSE             (1U << 31)
+#define QUIC_FL_CONN_CLOSING                     (1U << 29) /* closing state, entered on CONNECTION_CLOSE emission */
+#define QUIC_FL_CONN_DRAINING                    (1U << 30) /* draining state, entered on CONNECTION_CLOSE reception */
+#define QUIC_FL_CONN_IMMEDIATE_CLOSE             (1U << 31) /* A CONNECTION_CLOSE must be sent */
 
 struct quic_conn {
        const struct quic_version *original_version;
index 8dd2b4846f95a1ed75c2a689b843b4da384a83c8..f40ae25e64947e45cfe9927e365a70deded98487 100644 (file)
@@ -3032,8 +3032,8 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
                                 * Rearm the idle timeout only one time when entering draining
                                 * state.
                                 */
-                               qc_idle_timer_do_rearm(qc);
                                qc->flags |= QUIC_FL_CONN_DRAINING|QUIC_FL_CONN_IMMEDIATE_CLOSE;
+                               qc_idle_timer_do_rearm(qc);
                                qc_notify_close(qc);
                        }
                        break;
@@ -5280,9 +5280,15 @@ static void qc_idle_timer_do_rearm(struct quic_conn *qc)
 {
        unsigned int expire;
 
-       expire = QUIC_MAX(3 * quic_pto(qc), qc->max_idle_timeout);
-       qc->idle_timer_task->expire = tick_add(now_ms, MS_TO_TICKS(expire));
-       task_queue(qc->idle_timer_task);
+       if (stopping && qc->flags & (QUIC_FL_CONN_CLOSING|QUIC_FL_CONN_DRAINING)) {
+               TRACE_STATE("executing idle timer immediately on stopping", QUIC_EV_CONN_IDLE_TIMER, qc);
+               task_wakeup(qc->idle_timer_task, TASK_WOKEN_MSG);
+       }
+       else {
+               expire = QUIC_MAX(3 * quic_pto(qc), qc->max_idle_timeout);
+               qc->idle_timer_task->expire = tick_add(now_ms, MS_TO_TICKS(expire));
+               task_queue(qc->idle_timer_task);
+       }
 }
 
 /* Rearm the idle timer for <qc> QUIC connection depending on <read> boolean
index 9e9258f057f2d1553942688fd9af098488022239..2a4d01e07798028d3f2e91f7d6e5350497a16baf 100644 (file)
@@ -34,6 +34,10 @@ static void quic_close(struct connection *conn, void *xprt_ctx)
                goto leave;
        }
 
+       /* Schedule a CONNECTION_CLOSE emission. If process stopping is in
+        * progress, quic-conn idle-timer will be scheduled immediately after
+        * its emission to ensure an immediate connection closing.
+        */
        qc_check_close_on_released_mux(qc);
  leave:
        TRACE_LEAVE(QUIC_EV_CONN_CLOSE, qc);