diff --git a/Makefile b/Makefile index 46da6fbbb..9e861a292 100644 --- a/Makefile +++ b/Makefile @@ -626,7 +626,7 @@ ifneq ($(USE_QUIC),) OPTIONS_OBJS += src/quic_sock.o src/proto_quic.o src/xprt_quic.o src/quic_tls.o \ src/quic_frame.o src/quic_cc.o src/quic_cc_newreno.o src/mux_quic.o \ src/cbuf.o src/qpack-dec.o src/qpack-tbl.o src/h3.o src/qpack-enc.o \ - src/hq_interop.o src/cfgparse-quic.o + src/hq_interop.o src/cfgparse-quic.o src/quic_loss.o endif ifneq ($(USE_LUA),) diff --git a/include/haproxy/quic_loss.h b/include/haproxy/quic_loss.h index ad8908cad..de22ed28b 100644 --- a/include/haproxy/quic_loss.h +++ b/include/haproxy/quic_loss.h @@ -30,13 +30,8 @@ #include #include -#include #include -#include - -#define TRACE_SOURCE &trace_quic - static inline void quic_loss_init(struct quic_loss *ql) { ql->srtt = QUIC_LOSS_INITIAL_RTT << 3; @@ -45,41 +40,6 @@ static inline void quic_loss_init(struct quic_loss *ql) ql->pto_count = 0; } -/* Update QUIC loss information with new measurement and - * on ACK frame receipt which MUST be min(ack->ack_delay, max_ack_delay) - * before the handshake is confirmed. - */ -static inline void quic_loss_srtt_update(struct quic_loss *ql, - unsigned int rtt, unsigned int ack_delay, - struct quic_conn *qc) -{ - TRACE_PROTO("Loss info update", QUIC_EV_CONN_RTTUPDT, qc, &rtt, &ack_delay, ql); - ql->latest_rtt = rtt; - if (!ql->rtt_min) { - /* No previous measurement. */ - ql->srtt = rtt << 3; - /* rttval <- rtt / 2 or 4*rttval <- 2*rtt. */ - ql->rtt_var = rtt << 1; - ql->rtt_min = rtt; - } - else { - int diff; - - ql->rtt_min = QUIC_MIN(rtt, ql->rtt_min); - /* Specific to QUIC (RTT adjustment). */ - if (ack_delay && rtt > ql->rtt_min + ack_delay) - rtt -= ack_delay; - diff = ql->srtt - rtt; - if (diff < 0) - diff = -diff; - /* 4*rttvar = 3*rttvar + |diff| */ - ql->rtt_var += diff - (ql->rtt_var >> 2); - /* 8*srtt = 7*srtt + rtt */ - ql->srtt += rtt - (ql->srtt >> 3); - } - TRACE_PROTO("Loss info update", QUIC_EV_CONN_RTTUPDT, qc,,, ql); -} - /* Return 1 if a persitent congestion is observed for a list of * lost packets sent during period depending on loss information, * the current time and the maximum ACK delay of the connection @@ -102,27 +62,6 @@ static inline int quic_loss_persistent_congestion(struct quic_loss *ql, return period >= congestion_period; } -/* Returns for QUIC connection the first packet number space which - * experienced packet loss, if any or a packet number space with - * TICK_ETERNITY as packet loss time if not. - */ -static inline struct quic_pktns *quic_loss_pktns(struct quic_conn *qc) -{ - enum quic_tls_pktns i; - struct quic_pktns *pktns; - - pktns = &qc->pktns[QUIC_TLS_PKTNS_INITIAL]; - TRACE_PROTO("pktns", QUIC_EV_CONN_SPTO, qc, pktns); - for (i = QUIC_TLS_PKTNS_HANDSHAKE; i < QUIC_TLS_PKTNS_MAX; i++) { - TRACE_PROTO("pktns", QUIC_EV_CONN_SPTO, qc, &qc->pktns[i]); - if (!tick_isset(pktns->tx.loss_time) || - qc->pktns[i].tx.loss_time < pktns->tx.loss_time) - pktns = &qc->pktns[i]; - } - - return pktns; -} - /* Return the PTO associated to packet number space for connection */ static inline unsigned int quic_pto(struct quic_conn *qc) { @@ -132,72 +71,15 @@ static inline unsigned int quic_pto(struct quic_conn *qc) HA_ATOMIC_LOAD(&qc->state) >= QUIC_HS_ST_COMPLETE ? qc->max_ack_delay : 0; } -/* Returns for QUIC connection the first packet number space to - * arm the PTO for if any or a packet number space with TICK_ETERNITY - * as PTO value if not. - */ -static inline struct quic_pktns *quic_pto_pktns(struct quic_conn *qc, - int handshake_completed, - unsigned int *pto) -{ - int i; - unsigned int duration, lpto; - struct quic_loss *ql = &qc->path->loss; - struct quic_pktns *pktns, *p; +void quic_loss_srtt_update(struct quic_loss *ql, + unsigned int rtt, unsigned int ack_delay, + struct quic_conn *qc); - TRACE_ENTER(QUIC_EV_CONN_SPTO, qc); - duration = - (ql->srtt >> 3) + - (QUIC_MAX(ql->rtt_var, QUIC_TIMER_GRANULARITY) << ql->pto_count); +struct quic_pktns *quic_loss_pktns(struct quic_conn *qc); - if (!qc->path->in_flight) { - struct quic_enc_level *hel; - - hel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; - if (hel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_SET) { - pktns = &qc->pktns[QUIC_TLS_PKTNS_HANDSHAKE]; - } - else { - pktns = &qc->pktns[QUIC_TLS_PKTNS_INITIAL]; - } - lpto = tick_add(now_ms, duration); - goto out; - } - - lpto = TICK_ETERNITY; - pktns = p = &qc->pktns[QUIC_TLS_PKTNS_INITIAL]; - - for (i = QUIC_TLS_PKTNS_INITIAL; i < QUIC_TLS_PKTNS_MAX; i++) { - unsigned int tmp_pto; - - if (!qc->pktns[i].tx.in_flight) - continue; - - if (i == QUIC_TLS_PKTNS_01RTT) { - if (!handshake_completed) { - pktns = p; - goto out; - } - - duration += qc->max_ack_delay << ql->pto_count; - } - - p = &qc->pktns[i]; - tmp_pto = tick_add(p->tx.time_of_last_eliciting, duration); - if (!tick_isset(lpto) || tmp_pto < lpto) { - lpto = tmp_pto; - pktns = p; - } - TRACE_PROTO("pktns", QUIC_EV_CONN_SPTO, qc, p); - } - - out: - if (pto) - *pto = lpto; - TRACE_LEAVE(QUIC_EV_CONN_SPTO, qc, pktns, &duration); - - return pktns; -} +struct quic_pktns *quic_pto_pktns(struct quic_conn *qc, + int handshake_completed, + unsigned int *pto); #endif /* USE_QUIC */ #endif /* _PROTO_QUIC_LOSS_H */ diff --git a/src/quic_loss.c b/src/quic_loss.c new file mode 100644 index 000000000..2f6643c7c --- /dev/null +++ b/src/quic_loss.c @@ -0,0 +1,129 @@ +#include + +#include +#include + +#define TRACE_SOURCE &trace_quic + +/* Update QUIC loss information with new measurement and + * on ACK frame receipt which MUST be min(ack->ack_delay, max_ack_delay) + * before the handshake is confirmed. + */ +void quic_loss_srtt_update(struct quic_loss *ql, + unsigned int rtt, unsigned int ack_delay, + struct quic_conn *qc) +{ + TRACE_PROTO("Loss info update", QUIC_EV_CONN_RTTUPDT, qc, &rtt, &ack_delay, ql); + ql->latest_rtt = rtt; + if (!ql->rtt_min) { + /* No previous measurement. */ + ql->srtt = rtt << 3; + /* rttval <- rtt / 2 or 4*rttval <- 2*rtt. */ + ql->rtt_var = rtt << 1; + ql->rtt_min = rtt; + } + else { + int diff; + + ql->rtt_min = QUIC_MIN(rtt, ql->rtt_min); + /* Specific to QUIC (RTT adjustment). */ + if (ack_delay && rtt > ql->rtt_min + ack_delay) + rtt -= ack_delay; + diff = ql->srtt - rtt; + if (diff < 0) + diff = -diff; + /* 4*rttvar = 3*rttvar + |diff| */ + ql->rtt_var += diff - (ql->rtt_var >> 2); + /* 8*srtt = 7*srtt + rtt */ + ql->srtt += rtt - (ql->srtt >> 3); + } + TRACE_PROTO("Loss info update", QUIC_EV_CONN_RTTUPDT, qc,,, ql); +} + +/* Returns for QUIC connection the first packet number space which + * experienced packet loss, if any or a packet number space with + * TICK_ETERNITY as packet loss time if not. + */ +struct quic_pktns *quic_loss_pktns(struct quic_conn *qc) +{ + enum quic_tls_pktns i; + struct quic_pktns *pktns; + + pktns = &qc->pktns[QUIC_TLS_PKTNS_INITIAL]; + TRACE_PROTO("pktns", QUIC_EV_CONN_SPTO, qc, pktns); + for (i = QUIC_TLS_PKTNS_HANDSHAKE; i < QUIC_TLS_PKTNS_MAX; i++) { + TRACE_PROTO("pktns", QUIC_EV_CONN_SPTO, qc, &qc->pktns[i]); + if (!tick_isset(pktns->tx.loss_time) || + qc->pktns[i].tx.loss_time < pktns->tx.loss_time) + pktns = &qc->pktns[i]; + } + + return pktns; +} + +/* Returns for QUIC connection the first packet number space to + * arm the PTO for if any or a packet number space with TICK_ETERNITY + * as PTO value if not. + */ +struct quic_pktns *quic_pto_pktns(struct quic_conn *qc, + int handshake_completed, + unsigned int *pto) +{ + int i; + unsigned int duration, lpto; + struct quic_loss *ql = &qc->path->loss; + struct quic_pktns *pktns, *p; + + TRACE_ENTER(QUIC_EV_CONN_SPTO, qc); + duration = + (ql->srtt >> 3) + + (QUIC_MAX(ql->rtt_var, QUIC_TIMER_GRANULARITY) << ql->pto_count); + + if (!qc->path->in_flight) { + struct quic_enc_level *hel; + + hel = &qc->els[QUIC_TLS_ENC_LEVEL_HANDSHAKE]; + if (hel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_SET) { + pktns = &qc->pktns[QUIC_TLS_PKTNS_HANDSHAKE]; + } + else { + pktns = &qc->pktns[QUIC_TLS_PKTNS_INITIAL]; + } + lpto = tick_add(now_ms, duration); + goto out; + } + + lpto = TICK_ETERNITY; + pktns = p = &qc->pktns[QUIC_TLS_PKTNS_INITIAL]; + + for (i = QUIC_TLS_PKTNS_INITIAL; i < QUIC_TLS_PKTNS_MAX; i++) { + unsigned int tmp_pto; + + if (!qc->pktns[i].tx.in_flight) + continue; + + if (i == QUIC_TLS_PKTNS_01RTT) { + if (!handshake_completed) { + pktns = p; + goto out; + } + + duration += qc->max_ack_delay << ql->pto_count; + } + + p = &qc->pktns[i]; + tmp_pto = tick_add(p->tx.time_of_last_eliciting, duration); + if (!tick_isset(lpto) || tmp_pto < lpto) { + lpto = tmp_pto; + pktns = p; + } + TRACE_PROTO("pktns", QUIC_EV_CONN_SPTO, qc, p); + } + + out: + if (pto) + *pto = lpto; + TRACE_LEAVE(QUIC_EV_CONN_SPTO, qc, pktns, &duration); + + return pktns; +}