diff --git a/include/haproxy/quic_conn-t.h b/include/haproxy/quic_conn-t.h index fdeb9dad3..2213a7f77 100644 --- a/include/haproxy/quic_conn-t.h +++ b/include/haproxy/quic_conn-t.h @@ -579,6 +579,7 @@ struct quic_path { size_t mtu; /* Congestion window. */ uint64_t cwnd; + uint64_t mcwnd; /* Minimum congestion window. */ uint64_t min_cwnd; /* Prepared data to be sent (in bytes). */ diff --git a/include/haproxy/quic_conn.h b/include/haproxy/quic_conn.h index 568911052..6806d4fdc 100644 --- a/include/haproxy/quic_conn.h +++ b/include/haproxy/quic_conn.h @@ -538,6 +538,7 @@ static inline void quic_path_init(struct quic_path *path, int ipv4, quic_loss_init(&path->loss); path->mtu = max_dgram_sz; path->cwnd = QUIC_MIN(10 * max_dgram_sz, QUIC_MAX(max_dgram_sz << 1, 14720U)); + path->mcwnd = path->cwnd; path->min_cwnd = max_dgram_sz << 1; path->prep_in_flight = 0; path->in_flight = 0; diff --git a/include/haproxy/quic_loss-t.h b/include/haproxy/quic_loss-t.h index 4fb20847f..8ab41b256 100644 --- a/include/haproxy/quic_loss-t.h +++ b/include/haproxy/quic_loss-t.h @@ -54,6 +54,7 @@ struct quic_loss { unsigned int rtt_min; /* Number of NACKed sent PTO. */ unsigned int pto_count; + unsigned long nb_lost_pkt; }; #endif /* USE_QUIC */ diff --git a/include/haproxy/quic_loss.h b/include/haproxy/quic_loss.h index e4cb82f2c..a5f67d70a 100644 --- a/include/haproxy/quic_loss.h +++ b/include/haproxy/quic_loss.h @@ -38,6 +38,7 @@ static inline void quic_loss_init(struct quic_loss *ql) ql->rtt_var = (QUIC_LOSS_INITIAL_RTT >> 1) << 2; ql->rtt_min = 0; ql->pto_count = 0; + ql->nb_lost_pkt = 0; } /* Return 1 if a persistent congestion is observed for a list of diff --git a/src/quic_cc_cubic.c b/src/quic_cc_cubic.c index 1a5fa4e5b..d22897b37 100644 --- a/src/quic_cc_cubic.c +++ b/src/quic_cc_cubic.c @@ -168,6 +168,7 @@ static inline void quic_cubic_update(struct quic_cc *cc, uint32_t acked) } path->cwnd += inc; + path->mcwnd = QUIC_MAX(path->cwnd, path->mcwnd); leave: TRACE_LEAVE(QUIC_EV_CONN_CC, cc->qc); } @@ -217,6 +218,7 @@ static void quic_cc_cubic_ss_cb(struct quic_cc *cc, struct quic_cc_event *ev) /* Exit to congestion avoidance if slow start threshold is reached. */ if (path->cwnd >= c->ssthresh) c->state = QUIC_CC_ST_CA; + path->mcwnd = QUIC_MAX(path->cwnd, path->mcwnd); break; case QUIC_CC_EVT_LOSS: @@ -309,9 +311,10 @@ static void quic_cc_cubic_state_trace(struct buffer *buf, const struct quic_cc * struct cubic *c = quic_cc_priv(cc); path = container_of(cc, struct quic_path, cc); - chunk_appendf(buf, " state=%s cwnd=%llu ssthresh=%d rpst=%dms", + chunk_appendf(buf, " state=%s cwnd=%llu mcwnd=%llu ssthresh=%d rpst=%dms", quic_cc_state_str(c->state), (unsigned long long)path->cwnd, + (unsigned long long)path->mcwnd, (int)c->ssthresh, !tick_isset(c->recovery_start_time) ? -1 : TICKS_TO_MS(tick_remain(c->recovery_start_time, now_ms))); diff --git a/src/quic_cc_newreno.c b/src/quic_cc_newreno.c index 4d9bf136a..65763d762 100644 --- a/src/quic_cc_newreno.c +++ b/src/quic_cc_newreno.c @@ -87,6 +87,7 @@ static void quic_cc_nr_ss_cb(struct quic_cc *cc, struct quic_cc_event *ev) switch (ev->type) { case QUIC_CC_EVT_ACK: path->cwnd += ev->ack.acked; + path->mcwnd = QUIC_MAX(path->cwnd, path->mcwnd); /* Exit to congestion avoidance if slow start threshold is reached. */ if (path->cwnd > nr->ssthresh) nr->state = QUIC_CC_ST_CA; @@ -123,6 +124,7 @@ static void quic_cc_nr_ca_cb(struct quic_cc *cc, struct quic_cc_event *ev) acked = ev->ack.acked * path->mtu + nr->remain_acked; nr->remain_acked = acked % path->cwnd; path->cwnd += acked / path->cwnd; + path->mcwnd = QUIC_MAX(path->cwnd, path->mcwnd); break; } @@ -182,11 +184,14 @@ static void quic_cc_nr_state_trace(struct buffer *buf, const struct quic_cc *cc) struct nr *nr = quic_cc_priv(cc); path = container_of(cc, struct quic_path, cc); - chunk_appendf(buf, " state=%s cwnd=%llu ssthresh=%ld recovery_start_time=%llu", + chunk_appendf(buf, " state=%s cwnd=%llu mcwnd=%llu ssthresh=%ld rpst=%dms pktloss=%llu", quic_cc_state_str(nr->state), (unsigned long long)path->cwnd, + (unsigned long long)path->mcwnd, (long)nr->ssthresh, - (unsigned long long)nr->recovery_start_time); + !tick_isset(nr->recovery_start_time) ? -1 : + TICKS_TO_MS(tick_remain(nr->recovery_start_time, now_ms)), + (unsigned long long)path->loss.nb_lost_pkt); } static void (*quic_cc_nr_state_cbs[])(struct quic_cc *cc, diff --git a/src/quic_conn.c b/src/quic_conn.c index 2d90ab3ef..d87bf05b6 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -8454,9 +8454,11 @@ static int cli_io_handler_dump_quic(struct appctx *appctx) chunk_appendf(&trash, " [01rtt] rx.ackrng=%-6zu tx.inflight=%-6zu\n", pktns->rx.arngs.sz, pktns->tx.in_flight); - chunk_appendf(&trash, " srtt=%-4u rttvar=%-4u rttmin=%-4u ptoc=%-4u cwnd=%-6llu\n", + chunk_appendf(&trash, " srtt=%-4u rttvar=%-4u rttmin=%-4u ptoc=%-4u cwnd=%-6llu" + " mcwnd=%-6llu lostpkts=%-6llu\n", qc->path->loss.srtt >> 3, qc->path->loss.rtt_var >> 2, - qc->path->loss.rtt_min, qc->path->loss.pto_count, (ullong)qc->path->cwnd); + qc->path->loss.rtt_min, qc->path->loss.pto_count, (ullong)qc->path->cwnd, + (ullong)qc->path->mcwnd, (ullong)qc->path->loss.nb_lost_pkt); /* Streams */ diff --git a/src/quic_loss.c b/src/quic_loss.c index 888b61d5b..a8696e913 100644 --- a/src/quic_loss.c +++ b/src/quic_loss.c @@ -190,6 +190,7 @@ void qc_packet_loss_lookup(struct quic_pktns *pktns, struct quic_conn *qc, (int64_t)largest_acked_pn >= pkt->pn_node.key + QUIC_LOSS_PACKET_THRESHOLD) { eb64_delete(&pkt->pn_node); LIST_APPEND(lost_pkts, &pkt->list); + ql->nb_lost_pkt++; HA_ATOMIC_INC(&qc->prx_counters->lost_pkt); } else {