Cover BBR probe drain and transport DATA window consistency
This commit is contained in:
1 parent
519d6e4eaf
commit
92a535e009
2 files changed
+69
-1
No files matched your search
@@ -253,6 +253,33 @@ static int test_probe_rtt(void)
|
||||
PASS(); return 0;
|
||||
}
|
||||
|
||||
/* Длинный канал осушается до половины BDP, затем выдерживает 200мс и полный раунд доставки. */
|
||||
static int test_probe_rtt_lifecycle(void) {
|
||||
MSEG("PROBE_RTT half-BDP drain, hold and window restore");
|
||||
struct bbr s = { .now_tb = 10000 }; bbr_init(&s);
|
||||
s.mode = BBR_PROBE_BW; s.full_bw_reached = 1; s.cycle_idx = BBR_BW_PROBE_CRUISE;
|
||||
s.bw_hi[0] = BW_UNIT; s.min_rtt_us = s.probe_rtt_min_us = 200000; s.has_seen_rtt = 1;
|
||||
s.now_tb += BBR_PROBE_RTT_WIN_MS * 10 + 1;
|
||||
uint32_t cwnd = 400000, pacing = 1000000;
|
||||
struct bbr_rate_sample rs = { .delivered = 20000, .interval_us = 20000, .rtt_us = 200000,
|
||||
.acked_sacked = 1000, .tx_in_flight = 400000 };
|
||||
bbr_main(&s, &rs, &cwnd, &pacing, 1400, 200001, 0);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PROBE_RTT drain: BDP=200000 cwnd=%u timer=%llu", cwnd,
|
||||
(unsigned long long)s.probe_rtt_done_stamp_tb);
|
||||
if (s.mode != BBR_PROBE_RTT || cwnd != 100000) FAIL("probe window must be half of 200000-byte BDP");
|
||||
if (s.probe_rtt_done_stamp_tb) FAIL("probe hold started before flight drained");
|
||||
s.now_tb++; rs.prior_delivered = s.delivered; rs.is_app_limited = 1;
|
||||
bbr_main(&s, &rs, &cwnd, &pacing, 1400, 100000, 0);
|
||||
if (!s.probe_rtt_done_stamp_tb) FAIL("probe hold did not start at half-BDP");
|
||||
s.now_tb += BBR_PROBE_RTT_MS * 10 - 1; rs.prior_delivered = s.delivered;
|
||||
bbr_main(&s, &rs, &cwnd, &pacing, 1400, 100000, 0);
|
||||
if (s.mode != BBR_PROBE_RTT || cwnd != 100000) FAIL("probe ended before 200ms");
|
||||
s.now_tb++; rs.prior_delivered = s.delivered;
|
||||
bbr_main(&s, &rs, &cwnd, &pacing, 1400, 100000, 0);
|
||||
if (s.mode != BBR_PROBE_BW || cwnd < 400000) FAIL("probe did not restore the previous window after hold and round");
|
||||
PASS(); return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR); debug_set_category_level(DEBUG_CATEGORY_DEBUG, DEBUG_LEVEL_INFO);
|
||||
@@ -270,6 +297,7 @@ int main(void)
|
||||
test_loss_cut();
|
||||
test_fast_path();
|
||||
test_probe_rtt();
|
||||
test_probe_rtt_lifecycle();
|
||||
printf("\n=== Results: %d/%d passed, %d failed ===\n", test_passed, test_total, test_failed);
|
||||
return test_failed ? 1 : 0;
|
||||
}
|
||||
@@ -18,6 +18,7 @@ static struct ETCP_CONN* conn;
|
||||
static struct ETCP_LINK *a, *b;
|
||||
static unsigned sends, fail_alloc, fail_send, fail_tx_timer, bbr_calls, saw_cwnd_limited, saw_app_limited;
|
||||
static struct bbr_rate_sample last_sample;
|
||||
static uint32_t last_mss;
|
||||
|
||||
void* __real_uasync_call_soon(struct UASYNC*, void*, timeout_callback_t);
|
||||
void* __wrap_uasync_call_soon(struct UASYNC* loop, void* arg, timeout_callback_t callback) {
|
||||
@@ -49,6 +50,7 @@ void __wrap_bbr_main(struct bbr* model, const struct bbr_rate_sample* sample, ui
|
||||
uint32_t* pacing, uint32_t mss, uint32_t inflight, int limited) {
|
||||
bbr_calls++; saw_cwnd_limited |= !!limited; saw_app_limited |= !!sample->is_app_limited;
|
||||
last_sample = *sample;
|
||||
last_mss = mss;
|
||||
__real_bbr_main(model, sample, cwnd, pacing, mss, inflight, limited);
|
||||
}
|
||||
|
||||
@@ -344,6 +346,44 @@ static void bbr_delivery_clock(void) {
|
||||
teardown();
|
||||
}
|
||||
|
||||
/* Модель и транспорт используют один DATA MSS и одно окно, в том числе ниже 8KiB. */
|
||||
static void bbr_probe_window(void) {
|
||||
setup(); b->link_status = 0; conn->rtt_avg_10 = 10000;
|
||||
etcp_update_mtu(conn);
|
||||
uint32_t minimum = BBR_CWND_MIN_TARGET * conn->normalizer->frag_size;
|
||||
a->rtt_last = 100;
|
||||
a->bbr = u_calloc(1, sizeof(*a->bbr)); CHECK(a->bbr);
|
||||
a->bbr->now_tb = 10000; bbr_init(a->bbr);
|
||||
a->bbr->mode = BBR_PROBE_BW; a->bbr->full_bw_reached = 1; a->bbr->cycle_idx = BBR_BW_PROBE_CRUISE;
|
||||
a->bbr->min_rtt_us = a->bbr->probe_rtt_min_us = 10000; a->bbr->has_seen_rtt = 1;
|
||||
a->bbr->bw_hi[0] = BW_UNIT / 10; a->bbr->now_tb += BBR_PROBE_RTT_WIN_MS * 10 + 1;
|
||||
fill(a, 8, 1000); test_clock_run_for(ua, 200); ack(1);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PROBE_RTT transport: DATA_MSS=%u model_MSS=%u window=%u expected=%u",
|
||||
conn->normalizer->frag_size, last_mss, a->inflight_lim_bytes, minimum);
|
||||
CHECK(last_mss == conn->normalizer->frag_size && a->inflight_lim_bytes == minimum && minimum < INFLIGHT_LIM_MIN);
|
||||
struct INFLIGHT_PACKET* probe = enqueue(1000); CHECK(!request());
|
||||
ack(2); ack(3); ack(4); CHECK(a->bbr->probe_rtt_done_stamp_tb);
|
||||
struct ETCP_DGRAM* pkt = request(); CHECK(pkt && probe->is_app_limited);
|
||||
memory_pool_free(inst.pkt_pool, pkt);
|
||||
test_clock_run_for(ua, 10); a->bbr->now_tb += BBR_PROBE_RTT_MS * 10;
|
||||
ack(probe->seq); CHECK(a->bbr->mode == BBR_PROBE_BW);
|
||||
uint32_t window = a->inflight_lim_bytes;
|
||||
etcp_link_update_inflight_lim(a, 0); CHECK(a->inflight_lim_bytes == window);
|
||||
etcp_link_update_inflight_lim(a, UINT32_MAX); CHECK(a->inflight_lim_bytes == conn->max_inflight);
|
||||
ack_all(); teardown();
|
||||
}
|
||||
|
||||
/* Размер STCP-кадра 65535 не является размером DATA-фрагмента и не задаёт начальное окно. */
|
||||
static void tcp_initial_window(void) {
|
||||
setup();
|
||||
struct ETCP_LINK* link = etcp_link_new(conn, NULL, NULL, 1); CHECK(link && link->is_tcp);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "STCP initial window: frame=%u DATA_MSS=%u window=%u", link->mtu,
|
||||
conn->normalizer->frag_size, link->inflight_lim_bytes);
|
||||
CHECK(link->inflight_lim_bytes == BBR_CWND_MIN_TARGET * conn->normalizer->frag_size);
|
||||
CHECK(link->bbr->init_cwnd == BBR_CWND_MIN_TARGET);
|
||||
teardown();
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR);
|
||||
if (getenv("UTUN_TEST_DEBUG")) debug_set_category_level(DEBUG_CATEGORY_ETCP, DEBUG_LEVEL_DEBUG);
|
||||
@@ -351,7 +391,7 @@ int main(void) {
|
||||
size_t baseline = u_get_allocated_count();
|
||||
void (*cases[])(void) = {selection, boundaries_ack_burst, late_ack_and_migration, lost_ack_and_shrink,
|
||||
grow_and_session, allocation_and_send_failure, removed_link_and_bbr, pacing_reset_close, initial_readiness,
|
||||
config_limits, timer_failure, immediate_send, ack_without_data_pacing, bbr_delivery_clock};
|
||||
config_limits, timer_failure, immediate_send, ack_without_data_pacing, bbr_delivery_clock, bbr_probe_window, tcp_initial_window};
|
||||
for (unsigned i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
|
||||
cases[i](); CHECK(u_get_allocated_count() == baseline);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "PASS ETCP window scenario %u", i);
|
||||
|
||||
Reference in new issue
Block a user