From 227104e224940de8585fe4760c46b8218c8340e2 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 23 Oct 2026 10:58:38 +0200 Subject: [PATCH] Leave BBR startup after a full round of excessive queue delay --- src/transport_layer/etcp_bbr.c | 18 ++++++++++++++++++ src/transport_layer/etcp_bbr.h | 2 ++ tests/test_etcp_multipath.c | 4 ++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/transport_layer/etcp_bbr.c b/src/transport_layer/etcp_bbr.c index 77b51223..de0c395f 100644 --- a/src/transport_layer/etcp_bbr.c +++ b/src/transport_layer/etcp_bbr.c @@ -282,6 +282,22 @@ static void bbr_check_full_bw_reached(struct bbr* bbr, const struct bbr_rate_sam bbr->full_bw_reached |= bbr->full_bw_now; } +/* Ограничение задержки завершает разгон только после целого раунда с устойчивой очередью. */ +static void bbr_check_startup_delay(struct bbr* bbr, const struct bbr_rate_sample* rs) { + if (bbr->mode != BBR_STARTUP) return; + if (bbr->round_start) { + if (!rs->is_app_limited && bbr->queue_budget_us && bbr->min_rtt_us != UINT32_MAX && + bbr->startup_rtt_min_us != UINT32_MAX && + (uint64_t)bbr->startup_rtt_min_us > (uint64_t)bbr->min_rtt_us + bbr->queue_budget_us) { + DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[L%u] STARTUP delay exit: round_min_us=%u base_us=%u budget_us=%u BW_q16=%u", + bbr->link_id, bbr->startup_rtt_min_us, bbr->min_rtt_us, bbr->queue_budget_us, bbr_max_bw(bbr)); + bbr->full_bw_reached = 1; + } + bbr->startup_rtt_min_us = UINT32_MAX; + } + if (rs->rtt_us && rs->rtt_us < bbr->startup_rtt_min_us) bbr->startup_rtt_min_us = rs->rtt_us; +} + static void bbr_raise_inflight_hi_slope(struct bbr* bbr, uint32_t cwnd, uint32_t mss) { uint32_t growth_this_round = 1U << bbr->bw_probe_up_rounds; @@ -836,6 +852,7 @@ void bbr_init(struct bbr* bbr) bbr->prior_cwnd = 0; bbr->queue_budget_us = BBR_QUEUE_BUDGET_US; bbr->queue_cwnd_cap = 0; + bbr->startup_rtt_min_us = UINT32_MAX; bbr->delivered = 0; bbr->next_rtt_delivered = 0; @@ -926,6 +943,7 @@ void bbr_main(struct bbr* bbr, const struct bbr_rate_sample* rs, bbr_update_ack_aggregation(bbr, rs, cwnd, mss); bbr_check_loss_too_high_in_startup(bbr, rs, mss); bbr_check_full_bw_reached(bbr, rs, sample_bw); + bbr_check_startup_delay(bbr, rs); bbr_check_drain(bbr, rs, sample_bw, mss, inflight_bytes); bbr_update_cycle_phase(bbr, rs, sample_bw, mss, inflight_bytes, is_cwnd_limited, cwnd); diff --git a/src/transport_layer/etcp_bbr.h b/src/transport_layer/etcp_bbr.h index 15ada9f0..5bad8f6b 100644 --- a/src/transport_layer/etcp_bbr.h +++ b/src/transport_layer/etcp_bbr.h @@ -8,6 +8,7 @@ * Транспорт применяет окно с верхним ограничением конфига и не повышает его до собственного минимума. * Целевое окно PROBE_BW включает 2*BDP и ACK-резерв, в PROBE_UP дополнительно 2*MSS. * Общий предел этого окна — max(4*MSS, BW*(min_rtt+queue_budget_us)); init задаёт бюджет 20мс. + * В STARTUP превышение min_rtt+бюджет всеми RTT целого раунда завершает разгон и включает DRAIN. * Это цель по оценке полосы, не гарантия физической задержки: STARTUP/DRAIN, минимум окна, * неизвестная/изменившаяся полоса и очереди вне наблюдаемого пути могут превышать бюджет. */ #pragma once @@ -74,6 +75,7 @@ struct bbr { uint32_t inflight_latest; uint32_t queue_budget_us; // целевое время очереди в PROBE_BW, мкс; init задаёт 20мс, 0 отключает ограничение uint32_t queue_cwnd_cap; // последний предел DATA: max(4*MSS, BW*(min_rtt+budget)); 0 — ограничение не активно + uint32_t startup_rtt_min_us; // минимум достоверных RTT текущего ACK-раунда STARTUP; UINT32_MAX — измерений нет uint8_t mode; uint8_t cycle_idx; uint16_t pacing_gain; diff --git a/tests/test_etcp_multipath.c b/tests/test_etcp_multipath.c index 0d5d00c0..ad483bc5 100644 --- a/tests/test_etcp_multipath.c +++ b/tests/test_etcp_multipath.c @@ -71,12 +71,12 @@ void __wrap_bbr_main(struct bbr* model, const struct bbr_rate_sample* sample, ui const struct dummynet_stats* ds = dummynet_get_stats(channels[p], side); DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "BBR %s mask=%x side=%d path=%u mode=%u cycle=%u sample=%u/%uus rtt=%u " "min_rtt=%u inflight=%u cwnd=%u pace=%u hi=%u lo=%u app=%d limited=%d DATA_MSS=%u " - "bw_q16=%u/%u bw_lo=%u extra=%u/%u budget_us=%u queue_cap=%u queue_max_us=%llu", case_name, enabled_mask, + "bw_q16=%u/%u bw_lo=%u extra=%u/%u budget_us=%u queue_cap=%u queue_max_us=%llu time_ms=%llu measuring=%u", case_name, enabled_mask, side, p, model->mode, model->cycle_idx, sample->delivered, sample->interval_us, sample->rtt_us, model->min_rtt_us, inflight, *cwnd, *pacing, model->inflight_hi, model->inflight_lo, sample->is_app_limited, limited, mss, model->bw_hi[0], model->bw_hi[1], model->bw_lo, model->extra_acked[0], model->extra_acked[1], model->queue_budget_us, model->queue_cwnd_cap, - (unsigned long long)ds->max_queue_delay_us); + (unsigned long long)ds->max_queue_delay_us, (unsigned long long)((now-started)/1000), measuring); } } }