From 59bf255806cfee4cc62c85509550af88dff17460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= Date: Mon, 28 Mar 2022 12:13:09 +0200 Subject: [PATCH] MINOR: quic: Add closing connection state New received packets after sending CONNECTION_CLOSE frame trigger a new CONNECTION_CLOSE frame to be sent. Each time such a frame is sent we increase the number of packet required to send another CONNECTION_CLOSE frame. Rearm only one time the idle timer when sending a CONNECTION_CLOSE frame. --- include/haproxy/xprt_quic-t.h | 10 ++++++++- src/xprt_quic.c | 41 +++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/include/haproxy/xprt_quic-t.h b/include/haproxy/xprt_quic-t.h index 48128413b..fad3722c8 100644 --- a/include/haproxy/xprt_quic-t.h +++ b/include/haproxy/xprt_quic-t.h @@ -514,8 +514,10 @@ struct quic_rx_strm_frm { #define QUIC_FL_TX_PACKET_PADDING (1UL << 1) /* Flag a sent packet as being in flight. */ #define QUIC_FL_TX_PACKET_IN_FLIGHT (QUIC_FL_TX_PACKET_ACK_ELICITING | QUIC_FL_TX_PACKET_PADDING) +/* Flag a sent packet as containg a CONNECTION_CLOSE frame */ +#define QUIC_FL_TX_PACKET_CC (1UL << 2) /* Flag a sent packet as containg an ACK frame */ -#define QUIC_FL_TX_PACKET_ACK (1UL << 2) +#define QUIC_FL_TX_PACKET_ACK (1UL << 3) /* Structure to store enough information about TX QUIC packets. */ struct quic_tx_packet { @@ -662,6 +664,7 @@ enum qc_mux_state { #define QUIC_FL_CONN_LISTENER (1U << 3) #define QUIC_FL_CONN_ACCEPT_REGISTERED (1U << 4) #define QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ (1U << 6) +#define QUIC_FL_CONN_CLOSING (1U << 29) #define QUIC_FL_CONN_DRAINING (1U << 30) #define QUIC_FL_CONN_IMMEDIATE_CLOSE (1U << 31) struct quic_conn { @@ -754,6 +757,11 @@ struct quic_conn { struct task *idle_timer_task; unsigned int flags; + /* When in closing state, number of packet before sending CC */ + unsigned int nb_pkt_for_cc; + /* When in closing state, number of packet since receiving CC */ + unsigned int nb_pkt_since_cc; + const struct qcc_app_ops *app_ops; }; diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 6fdcae602..6d4262c16 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -3047,6 +3047,24 @@ int qc_send_ppkts(struct qring *qr, struct ssl_sock_ctx *ctx) if (qc->flags & QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ) qc_idle_timer_rearm(qc, 0); } + if (!(qc->flags & QUIC_FL_CONN_CLOSING) && + (pkt->flags & QUIC_FL_TX_PACKET_CC)) { + qc->flags |= QUIC_FL_CONN_CLOSING; + /* RFC 9000 10.2. Immediate Close: + * The closing and draining connection states exist to ensure + * that connections close cleanly and that delayed or reordered + * packets are properly discarded. These states SHOULD persist + * for at least three times the current PTO interval... + * + * Rearm the idle timeout only one time when entering closing + * state. + */ + qc_idle_timer_do_rearm(qc); + if (qc->timer_task) { + task_destroy(qc->timer_task); + qc->timer_task = NULL; + } + } qc->path->in_flight += pkt->in_flight_len; pkt->pktns->tx.in_flight += pkt->in_flight_len; if (pkt->in_flight_len) @@ -4012,6 +4030,10 @@ static struct quic_conn *qc_new_conn(unsigned int version, int ipv4, /* RX part. */ qc->rx.bytes = 0; qc->rx.buf = b_make(buf_area, QUIC_CONN_RX_BUFSZ, 0, 0); + + qc->nb_pkt_for_cc = 1; + qc->nb_pkt_since_cc = 0; + LIST_INIT(&qc->rx.pkt_list); if (!quic_tls_ku_init(qc)) { TRACE_PROTO("Key update initialization failed", QUIC_EV_CONN_INIT, qc); @@ -4852,6 +4874,17 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char *buf, const unsigned char *end, pkt->qc = qc; } + if (qc->flags & QUIC_FL_CONN_CLOSING) { + if (++qc->nb_pkt_since_cc >= qc->nb_pkt_for_cc) { + qc->flags |= QUIC_FL_CONN_IMMEDIATE_CLOSE; + qc->nb_pkt_for_cc++; + qc->nb_pkt_since_cc = 0; + } + /* Skip the entire datagram */ + pkt->len = end - beg; + TRACE_PROTO("Closing state connection", QUIC_EV_CONN_LPKT, pkt->qc); + goto out; + } /* When multiple QUIC packets are coalesced on the same UDP datagram, * they must have the same DCID. @@ -5457,8 +5490,12 @@ static int qc_do_build_pkt(unsigned char *pos, const unsigned char *end, } /* Build a CONNECTION_CLOSE frame if needed. */ - if (cc && !qc_build_frm(&pos, end, &cc_frm, pkt, qc)) - goto no_room; + if (cc) { + if (!qc_build_frm(&pos, end, &cc_frm, pkt, qc)) + goto no_room; + + pkt->flags |= QUIC_FL_TX_PACKET_CC; + } /* Build a PADDING frame if needed. */ if (padding_len) {