From 3388bd9e9b82df6d7fe79fa4eee7c22a3277624e Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Tue, 21 Jul 2026 06:54:55 +0200 Subject: ipcpd: Add flow overshoot protection to mb-ecn The ECN marks were the only source of congestion information, and going into congestion collapse (dropping a lot of ECN packets and causing loss of signal) was unrecoverable. The sender's slow-start ramp clock now tracks a measured RTT to avoid overshooting into congestion collapse on the previously fixed (14ms) doubling on long-delay (e.g. 100ms) links. The flow allocator now carries a periodic heartbeat/ack to keep RTT estimates up-to-date. The heartbeat also serves as a congestion collapse detector: consecutive heartbeat losses will go into loss recovery, halving the window and pausing Additive Increase until the path is clear. The DT component now has a max_rtt config parameter that serves as a hint for the layer RTT to optimize slow-start for low-latency networks. These two mechanisms follow TCP, however only during slow start up to the first ECN signal and to recover from a total collapse until the ECN signal returns. MB-ECN is still fully RTT-independent in the AI/PD region. A shorter RTT path will just reach its equal fair share faster than a longer RTT path. Signed-off-by: Dimitri Staessens Signed-off-by: Sander Vrijders --- src/ipcpd/unicast/ca.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'src/ipcpd/unicast/ca.c') diff --git a/src/ipcpd/unicast/ca.c b/src/ipcpd/unicast/ca.c index d0ee2f73..f2a65fff 100644 --- a/src/ipcpd/unicast/ca.c +++ b/src/ipcpd/unicast/ca.c @@ -58,7 +58,8 @@ struct { #endif } ca; -int ca_init(enum pol_cong_avoid pol) +int ca_init(enum pol_cong_avoid pol, + uint32_t rtt_ms) { #ifndef IPCP_CA_PER_FLOW size_t i; @@ -71,6 +72,7 @@ int ca_init(enum pol_cong_avoid pol) case CA_MB_ECN: log_dbg("Using multi-bit ECN."); ca.ops = &mb_ecn_ca_ops; + mb_ecn_init(rtt_ms); break; default: return -1; @@ -216,6 +218,29 @@ void ca_ctx_update_ece(void * _ctx, return ca.ops->ctx_update_ece(ctx->pol, ece, cap); } +bool ca_ctx_hb_due(void * _ctx, + uint64_t now) +{ + struct ca_ctx * ctx = _ctx; + + if (ca.ops->ctx_hb_due == NULL) + return false; + + return ca.ops->ctx_hb_due(ctx->pol, now); +} + +void ca_ctx_rtt(void * _ctx, + uint64_t now, + uint64_t rtt) +{ + struct ca_ctx * ctx = _ctx; + + if (ca.ops->ctx_rtt == NULL) + return; + + ca.ops->ctx_rtt(ctx->pol, now, rtt); +} + int ca_calc_ecn(size_t queued, uint8_t * ecn, qoscube_t qc, -- cgit v1.2.3