diff --git a/doc/etcp_protocol.txt b/doc/etcp_protocol.txt index 2ade3882..99a93ef1 100644 --- a/doc/etcp_protocol.txt +++ b/doc/etcp_protocol.txt @@ -129,6 +129,12 @@ RTT/min_rtt, формула RTO, политика окна и дедлайн ACK Минимальное окно BBR — четыре DATA-фрагмента normalizer; максимальное — bbr_max_cwnd (по умолчанию 1048576). 8192 — нижняя допустимая граница настройки bbr_max_cwnd; транспорт не повышает до неё текущее окно. PROBE_RTT осушает flight до max(4*MSS, 0.5*BDP), выдерживает >=200мс и раунд ACK, затем восстанавливает окно. +RTT-фильтры обновляются при обработке ACK. Короткий минимум принимает меньший достоверный RTT +либо текущее измерение после истечения 5с; RTT=0 означает отсутствие измерения. +Долгий min_rtt принимает короткий минимум, если он не больше прежнего, либо истекли его 10с. +Вместе со значением копируется метка короткого фильтра: повторное использование кеша не задаёт текущее время. +Завершение PROBE_RTT возобновляет короткое окно. Окна истекают строго после своей границы; +hold завершается при достижении срока и завершённом ACK-раунде. Метки RTT и срок hold — полные uint64 TB (100мкс). MSS — размер DATA-фрагмента normalizer без заголовков; начальное окно UDP и STCP равно 4*MSS с верхним лимитом конфига. В PROBE_BW действует дополнительный целевой бюджет очереди 20мс: всё окно, включая резервы ACK и PROBE_UP, ограничивается max(4*MSS, BDP + BW*20мс) по min_rtt. STARTUP/DRAIN не ограничивают окно этой формулой, diff --git a/tests/test_etcp_bbr.c b/tests/test_etcp_bbr.c index 2c7b477b..030098ba 100644 --- a/tests/test_etcp_bbr.c +++ b/tests/test_etcp_bbr.c @@ -373,22 +373,27 @@ static int test_probe_rtt_lifecycle(void) { /* Нулевой младший uint32 срока не означает отсутствие hold; ждать надо полные 200мс. */ static int test_probe_rtt_deadline_wrap(void) { MSEG("PROBE_RTT hold at a zero low-32-bit deadline"); - struct bbr s = {.now_tb=(UINT64_C(1)<<32)-2000}; bbr_init(&s); - s.mode = BBR_PROBE_RTT; s.full_bw_reached = 1; - uint32_t cwnd = 10000, pacing = 0; - struct bbr_rate_sample rs = {.delivered=1000,.interval_us=100000,.rtt_us=20000, - .acked_sacked=1000,.tx_in_flight=1000,.is_app_limited=1}; - bbr_main(&s,&rs,&cwnd,&pacing,1400,1000,0); - DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PROBE_RTT zero deadline: now_tb=%llu deadline_tb=%llu expected_tb=%llu", - (unsigned long long)s.now_tb,(unsigned long long)s.probe_rtt_done_stamp_tb, - (unsigned long long)(UINT64_C(1)<<32)); - if (!s.probe_rtt_done_stamp_tb) FAIL("zero low bits erased the active PROBE_RTT deadline"); - s.now_tb += 1999; rs.prior_delivered = s.delivered; - bbr_main(&s,&rs,&cwnd,&pacing,1400,1000,0); - if (s.mode != BBR_PROBE_RTT || !s.probe_rtt_round_done) FAIL("probe must hold for 200ms even with a complete round"); - s.now_tb++; rs.prior_delivered = s.delivered; - bbr_main(&s,&rs,&cwnd,&pacing,1400,1000,0); - if (s.mode != BBR_PROBE_BW) FAIL("probe did not finish at the 200ms deadline across TB wrap"); + for (unsigned early_round = 0; early_round < 2; early_round++) { + struct bbr s = {.now_tb=(UINT64_C(1)<<32)-2000}; bbr_init(&s); + s.mode = BBR_PROBE_RTT; s.full_bw_reached = 1; + uint32_t cwnd = 10000, pacing = 0; + struct bbr_rate_sample rs = {.delivered=1000,.interval_us=100000,.rtt_us=20000, + .acked_sacked=1000,.tx_in_flight=1000,.is_app_limited=1}; + bbr_main(&s,&rs,&cwnd,&pacing,1400,1000,0); + DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PROBE_RTT zero deadline: now_tb=%llu deadline_tb=%llu expected_tb=%llu early_round=%u", + (unsigned long long)s.now_tb,(unsigned long long)s.probe_rtt_done_stamp_tb, + (unsigned long long)(UINT64_C(1)<<32),early_round); + if (!s.probe_rtt_done_stamp_tb) FAIL("zero low bits erased the active PROBE_RTT deadline"); + s.now_tb += 1999; rs.prior_delivered = early_round ? s.delivered : 0; + bbr_main(&s,&rs,&cwnd,&pacing,1400,1000,0); + if (s.mode != BBR_PROBE_RTT || s.probe_rtt_round_done != early_round) FAIL("probe must wait for both 200ms and a complete round"); + s.now_tb++; + bbr_main(&s,&rs,&cwnd,&pacing,1400,1000,0); + if (s.mode != (early_round ? BBR_PROBE_BW : BBR_PROBE_RTT)) FAIL("probe deadline ignored the ACK-round requirement"); + s.now_tb++; rs.prior_delivered = s.delivered; + bbr_main(&s,&rs,&cwnd,&pacing,1400,1000,0); + if (s.mode != BBR_PROBE_BW) FAIL("probe did not finish with both hold and ACK round complete"); + } PASS(); return 0; }