mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-25 12:51:21 +01:00
MINOR: quic: Add draining connection state.
As soon as we receive a CONNECTION_CLOSE frame, we must stop sending packets. We add QUIC_FL_CONN_DRAINING connection flag to do so.
This commit is contained in:
parent
eb0d4c40ac
commit
47756809fb
@ -662,6 +662,7 @@ enum qc_mux_state {
|
|||||||
#define QUIC_FL_CONN_LISTENER (1U << 3)
|
#define QUIC_FL_CONN_LISTENER (1U << 3)
|
||||||
#define QUIC_FL_CONN_ACCEPT_REGISTERED (1U << 4)
|
#define QUIC_FL_CONN_ACCEPT_REGISTERED (1U << 4)
|
||||||
#define QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ (1U << 6)
|
#define QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ (1U << 6)
|
||||||
|
#define QUIC_FL_CONN_DRAINING (1U << 30)
|
||||||
#define QUIC_FL_CONN_IMMEDIATE_CLOSE (1U << 31)
|
#define QUIC_FL_CONN_IMMEDIATE_CLOSE (1U << 31)
|
||||||
struct quic_conn {
|
struct quic_conn {
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
|
|||||||
@ -177,6 +177,7 @@ static struct quic_tx_packet *qc_build_pkt(unsigned char **pos, const unsigned c
|
|||||||
struct quic_conn *qc, size_t dglen, int pkt_type,
|
struct quic_conn *qc, size_t dglen, int pkt_type,
|
||||||
int padding, int probe, int cc, int *err);
|
int padding, int probe, int cc, int *err);
|
||||||
static struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int state);
|
static struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int state);
|
||||||
|
static void qc_idle_timer_do_rearm(struct quic_conn *qc);
|
||||||
static void qc_idle_timer_rearm(struct quic_conn *qc, int read);
|
static void qc_idle_timer_rearm(struct quic_conn *qc, int read);
|
||||||
|
|
||||||
/* Only for debug purpose */
|
/* Only for debug purpose */
|
||||||
@ -2576,6 +2577,20 @@ static int qc_parse_pkt_frms(struct quic_rx_packet *pkt, struct ssl_sock_ctx *ct
|
|||||||
break;
|
break;
|
||||||
case QUIC_FT_CONNECTION_CLOSE:
|
case QUIC_FT_CONNECTION_CLOSE:
|
||||||
case QUIC_FT_CONNECTION_CLOSE_APP:
|
case QUIC_FT_CONNECTION_CLOSE_APP:
|
||||||
|
if (!(qc->flags & QUIC_FL_CONN_DRAINING)) {
|
||||||
|
TRACE_PROTO("Entering draining state", QUIC_EV_CONN_PRSHPKT, qc);
|
||||||
|
/* 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 draining
|
||||||
|
* state.
|
||||||
|
*/
|
||||||
|
qc_idle_timer_do_rearm(qc);
|
||||||
|
qc->flags |= QUIC_FL_CONN_DRAINING|QUIC_FL_CONN_IMMEDIATE_CLOSE;
|
||||||
|
}
|
||||||
/* warn the mux to close the connection */
|
/* warn the mux to close the connection */
|
||||||
if (qc->mux_state == QC_MUX_READY) {
|
if (qc->mux_state == QC_MUX_READY) {
|
||||||
qc->qcc->flags |= QC_CF_CC_RECV;
|
qc->qcc->flags |= QC_CF_CC_RECV;
|
||||||
@ -3555,9 +3570,14 @@ static struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned
|
|||||||
if (!qc_treat_rx_pkts(qel, NULL, ctx, 0))
|
if (!qc_treat_rx_pkts(qel, NULL, ctx, 0))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
if ((qc->flags & QUIC_FL_CONN_DRAINING) &&
|
||||||
|
!(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!qc_send_app_pkts(qc, &qel->pktns->tx.frms))
|
if (!qc_send_app_pkts(qc, &qel->pktns->tx.frms))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
out:
|
||||||
return t;
|
return t;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@ -3619,6 +3639,10 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
|
|||||||
if (!qc_treat_rx_pkts(qel, next_qel, ctx, force_ack))
|
if (!qc_treat_rx_pkts(qel, next_qel, ctx, force_ack))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
if ((qc->flags & QUIC_FL_CONN_DRAINING) &&
|
||||||
|
!(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (zero_rtt && next_qel && !MT_LIST_ISEMPTY(&next_qel->rx.pqpkts) &&
|
if (zero_rtt && next_qel && !MT_LIST_ISEMPTY(&next_qel->rx.pqpkts) &&
|
||||||
(next_qel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_SET)) {
|
(next_qel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_SET)) {
|
||||||
qel = next_qel;
|
qel = next_qel;
|
||||||
@ -3676,7 +3700,9 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
|
|||||||
goto next_level;
|
goto next_level;
|
||||||
}
|
}
|
||||||
|
|
||||||
MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
|
out:
|
||||||
|
if (qr)
|
||||||
|
MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
|
||||||
TRACE_LEAVE(QUIC_EV_CONN_IO_CB, qc, &st);
|
TRACE_LEAVE(QUIC_EV_CONN_IO_CB, qc, &st);
|
||||||
return t;
|
return t;
|
||||||
|
|
||||||
@ -4031,21 +4057,27 @@ static int quic_conn_init_timer(struct quic_conn *qc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rearm the idle timer for <qc> QUIC connection. */
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
/* Rearm the idle timer for <qc> QUIC connection depending on <read> boolean
|
/* Rearm the idle timer for <qc> QUIC connection depending on <read> boolean
|
||||||
* which is set to 1 when receiving a packet , and 0 when sending packet
|
* which is set to 1 when receiving a packet , and 0 when sending packet
|
||||||
*/
|
*/
|
||||||
static void qc_idle_timer_rearm(struct quic_conn *qc, int read)
|
static void qc_idle_timer_rearm(struct quic_conn *qc, int read)
|
||||||
{
|
{
|
||||||
unsigned int expire;
|
|
||||||
|
|
||||||
expire = QUIC_MAX(3 * quic_pto(qc), qc->max_idle_timeout);
|
|
||||||
if (read) {
|
if (read) {
|
||||||
qc->flags |= QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ;
|
qc->flags |= QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qc->flags &= ~QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ;
|
qc->flags &= ~QUIC_FL_CONN_IDLE_TIMER_RESTARTED_AFTER_READ;
|
||||||
}
|
}
|
||||||
qc->idle_timer_task->expire = tick_add(now_ms, MS_TO_TICKS(expire));
|
qc_idle_timer_do_rearm(qc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The task handling the idle timeout */
|
/* The task handling the idle timeout */
|
||||||
@ -5551,6 +5583,8 @@ static struct quic_tx_packet *qc_build_pkt(unsigned char **pos,
|
|||||||
pkt->in_flight_len = pkt->len;
|
pkt->in_flight_len = pkt->len;
|
||||||
qc->path->prep_in_flight += pkt->len;
|
qc->path->prep_in_flight += pkt->len;
|
||||||
}
|
}
|
||||||
|
/* Always reset this flags */
|
||||||
|
qc->flags &= ~QUIC_FL_CONN_IMMEDIATE_CLOSE;
|
||||||
if (pkt->flags & QUIC_FL_TX_PACKET_ACK) {
|
if (pkt->flags & QUIC_FL_TX_PACKET_ACK) {
|
||||||
qel->pktns->flags &= ~QUIC_FL_PKTNS_ACK_REQUIRED;
|
qel->pktns->flags &= ~QUIC_FL_PKTNS_ACK_REQUIRED;
|
||||||
qel->pktns->rx.nb_aepkts_since_last_ack = 0;
|
qel->pktns->rx.nb_aepkts_since_last_ack = 0;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user