From: Amaury Denoyelle Date: Wed, 1 Feb 2023 08:28:55 +0000 (+0100) Subject: MEDIUM: quic: trigger fast connection closing on process stopping X-Git-Tag: v2.8-dev5~159 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77ed63106d30e033576a0b6426541df53f1278b6;p=thirdparty%2Fhaproxy.git MEDIUM: quic: trigger fast connection closing on process stopping 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. --- diff --git a/include/haproxy/quic_conn-t.h b/include/haproxy/quic_conn-t.h index 79f806e06c..ebe3dfd215 100644 --- a/include/haproxy/quic_conn-t.h +++ b/include/haproxy/quic_conn-t.h @@ -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; diff --git a/src/quic_conn.c b/src/quic_conn.c index 8dd2b4846f..f40ae25e64 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -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 QUIC connection depending on boolean diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 9e9258f057..2a4d01e077 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -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);