diff --git a/src/transport_layer/etcp_bbr.c b/src/transport_layer/etcp_bbr.c index 0ef9d4ba..77b51223 100644 --- a/src/transport_layer/etcp_bbr.c +++ b/src/transport_layer/etcp_bbr.c @@ -723,6 +723,7 @@ static void bbr_init_pacing_rate_from_rtt(struct bbr* bbr, uint32_t mss, uint32_ static void bbr_set_pacing_rate(struct bbr* bbr, uint32_t bw, int gain, uint32_t* pacing_rate_out) { + if (!bw) return; // Нет измерения полосы: сохраняем начальное состояние/ставку от достоверного RTT. uint32_t rate = bbr_bw_to_pacing_rate(bw, gain); if (bbr->full_bw_reached || rate > *pacing_rate_out) diff --git a/tests/test_etcp_bbr.c b/tests/test_etcp_bbr.c index 9355447d..53f2c1a9 100644 --- a/tests/test_etcp_bbr.c +++ b/tests/test_etcp_bbr.c @@ -358,9 +358,12 @@ static int test_initial_pacing(void) { const uint32_t sizes[] = {576, 1400}, rtts[] = {20000, 200000}; for (unsigned i = 0; i < 2; i++) for (unsigned j = 0; j < 2; j++) { struct bbr s = { .now_tb = 10000 }; bbr_init(&s); - uint32_t cwnd = 4 * sizes[i], pacing = 123; + uint32_t cwnd = 4 * sizes[i], pacing = 0; struct bbr_rate_sample rs = { .acked_sacked = 16, .delivered = 16, .is_app_limited = 1 }; bbr_main(&s, &rs, &cwnd, &pacing, sizes[i], 0, 0); + if (s.has_seen_rtt || pacing) FAIL("unknown RTT and rate must not fabricate a 1B/s pacing stall"); + pacing = 123; + bbr_main(&s, &rs, &cwnd, &pacing, sizes[i], 0, 0); if (s.has_seen_rtt || pacing != 123) FAIL("unknown RTT must not seed pacing with a guessed duration"); rs.rtt_us = rs.interval_us = rtts[j]; s.now_tb += rtts[j] / 100; bbr_main(&s, &rs, &cwnd, &pacing, sizes[i], 0, 0); diff --git a/tests/test_etcp_stcp.c b/tests/test_etcp_stcp.c index 5ef64c1d..bd06efaa 100644 --- a/tests/test_etcp_stcp.c +++ b/tests/test_etcp_stcp.c @@ -6,6 +6,7 @@ #include "etcp_api.h" #include "etcp_connections.h" #include "etcp_session.h" +#include "etcp_bbr.h" #include "node_conn_direct.h" #include "topo_group.h" #include "topo_node.h" @@ -188,6 +189,22 @@ static void exchange_messages(void) { } if (drained) break; } + if (failed || endpoints[0].received != FULL_MASK || endpoints[1].received != FULL_MASK) { + for (int i = 0; i < 2; i++) { + struct ETCP_CONN* conn = endpoints[i].conn; + DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "Delivery stalled: side=%d phase=%u mask=%04x expected=%04x tx=%u till=%u " + "need=%u send=%d wait=%d receive=%d input=%d unacked=%u", i, phase, endpoints[i].received, FULL_MASK, + conn->next_tx_id, conn->rx_ack_till, conn->last_delivered_id + 1, conn->input_send_q->count, + conn->input_wait_ack->count, conn->recv_q->count, conn->input_queue->count, conn->unacked_bytes); + for (struct ETCP_LINK* link = conn->links; link; link = link->next) + DEBUG_ERROR(DEBUG_CATEGORY_GENERAL, "Delivery path: side=%d link=%u UP=%u rate=%u shaper=%d deadline=%llu now=%llu " + "flight=%u/%u RTT_tb=%u BBR_mode=%u BBR_RTT_us=%u delivered=%llu model_delivered=%u", i, + link->local_link_id, link->link_status, link->bbr_pacing_rate, link->shaper_timer != NULL, + (unsigned long long)link->shaper_load_time_tb, (unsigned long long)get_time_tb(), link->inflight_bytes, + link->inflight_lim_bytes, link->rtt_last, link->bbr->mode, link->bbr->min_rtt_us, + (unsigned long long)link->delivered_bytes, link->bbr->delivered); + } + } CHECK(!failed && endpoints[0].received == FULL_MASK && endpoints[1].received == FULL_MASK); for (int i = 0; i < 2; i++) CHECK(!endpoints[i].conn->input_wait_ack->count && !endpoints[i].conn->input_send_q->count); }