Reproduce premature ACKs before their absolute deadline

This commit is contained in:
evgeny committed 2026-10-24 14:43:03 +02:00
1 parent 2b74d2bf4f
commit c8051619c1
2 files changed
+31 -2

No files matched your search

+2 -1
View File
@@ -1056,7 +1056,8 @@ test_etcp_multipath_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=etcp_dump_pkt_sec
test_stcp_sigpipe_SOURCES = test_stcp_sigpipe.c
test_stcp_sigpipe_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_etcp_windows_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_etcp_windows_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=get_time_tb -Wl,--wrap=etcp_encrypt_send -Wl,--wrap=memory_pool_alloc_impl \
test_etcp_windows_LDFLAGS = $(test_clock_ldflags) -Wl,--wrap=get_time_tb -Wl,--wrap=get_time_us \
-Wl,--wrap=etcp_encrypt_send -Wl,--wrap=memory_pool_alloc_impl \
-Wl,--wrap=bbr_main -Wl,--wrap=uasync_set_timeout -Wl,--wrap=uasync_call_soon -Wl,--wrap=ll_alloc_lldgram \
-Wl,--wrap=u_malloc_impl -Wl,--wrap=u_calloc_impl -Wl,--wrap=u_realloc_impl -Wl,--wrap=random_bytes
+29 -1
View File
@@ -33,13 +33,21 @@ static uint32_t last_mss;
static unsigned fail_rx_message_at, fail_tx_inflight, fail_normalizer_timer, fail_normalizer_waiter, fail_session_timer_at;
static unsigned no_alloc, unexpected_alloc, fail_rng, session_sends, received, receive_action;
static uint8_t received_values[8];
static unsigned ack_clock_active, capture_ack_timer, fail_ack_timer;
static uint64_t ack_now_us;
static timeout_callback_t captured_ack_callback;
static void* captured_ack_arg;
/* Фиксируем только TB на время синхронной проверки pacer; uasync при этих часах не опрашивается. */
uint64_t __real_get_time_tb(void);
uint64_t __wrap_get_time_tb(void) {
if (ack_clock_active) return ack_now_us / 100;
return pacer_clock_active ? pacer_now_tb : __real_get_time_tb();
}
uint64_t __real_get_time_us(void);
uint64_t __wrap_get_time_us(void) { return ack_clock_active ? ack_now_us : __real_get_time_us(); }
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) {
if (fail_normalizer_timer && conn && arg == conn->normalizer) { fail_normalizer_timer--; return NULL; }
@@ -52,6 +60,8 @@ void* __wrap_uasync_call_soon(struct UASYNC* loop, void* arg, timeout_callback_t
void* __real_uasync_set_timeout(struct UASYNC*, int, void*, timeout_callback_t, const char*);
void* __wrap_uasync_set_timeout(struct UASYNC* loop, int delay, void* arg, timeout_callback_t callback, const char* name) {
if (capture_ack_timer && !strcmp(name, "etcp_ack_resp")) { captured_ack_callback = callback; captured_ack_arg = arg; }
if (fail_ack_timer && !strcmp(name, "etcp_ack_resp")) { fail_ack_timer--; return NULL; }
if (capture_shaper && name && !strcmp(name, "etcp_shaper")) {
shaper_arm_count++; captured_shaper_delay = delay;
captured_shaper_callback = callback; captured_shaper_arg = arg;
@@ -152,6 +162,8 @@ static void setup(void) {
fail_rx_message_at = fail_tx_inflight = fail_normalizer_timer = fail_normalizer_waiter = fail_session_timer_at = 0;
no_alloc = unexpected_alloc = fail_rng = session_sends = received = receive_action = 0;
memset(received_values, 0, sizeof(received_values));
ack_clock_active = capture_ack_timer = fail_ack_timer = 0;
captured_ack_callback = NULL; captured_ack_arg = NULL;
last_sent_link = NULL; last_sent_request = last_sent_payload = 0;
ua = uasync_create(); CHECK(ua);
inst.ua = ua; inst.node_id = 1; inst.config = &cfg; cfg.global.bbr_max_cwnd = INFLIGHT_LIM_MAX;
@@ -175,6 +187,7 @@ static void setup(void) {
}
static void teardown(void) {
ack_clock_active = 0;
check_accounting();
etcp_connection_close(conn); conn = NULL;
uasync_poll(ua, 0);
@@ -1124,6 +1137,21 @@ static void independent_attempt_acks(void) {
check_accounting(); teardown();
}
/* Посторонний wake не снимает задержку ACK; точные границы проверяются без опроса uasync при ручных часах. */
static void ack_absolute_deadline(void) {
setup(); conn->got_initial_pkt = 1;
ack_now_us = get_time_us(); ack_clock_active = capture_ack_timer = 1;
receive_fragment(a, 2, 1); CHECK(a->ack_q->count == 1 && conn->ack_resp_timer);
etcp_conn_wake_sender(conn);
struct ETCP_DGRAM* pkt = request();
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "ACK deadline: age_us=0 queued=%d sent_early=%u", a->ack_q->count, pkt != NULL);
CHECK(!pkt && a->ack_q->count == 1);
ack_now_us += 1999; CHECK(!request() && a->ack_q->count == 1);
ack_now_us++; pkt = request(); CHECK(pkt && pkt->link == a && pkt->data[1] == 1);
memory_pool_free(inst.pkt_pool, pkt); CHECK(!a->ack_q->count && !conn->ack_resp_timer);
teardown();
}
static void receive_admission_and_path_acks(void) {
setup(); conn->got_initial_pkt = 1;
fail_rx_data = 1; receive_fragment(a, 2, 1);
@@ -1545,7 +1573,7 @@ int main(void) {
retry_waits_for_alternative, retry_alternative_lifecycle,
send_queue_scan, send_queue_input_admission,
retry_full_round_history, retry_history_slot_reuse, fast_stall_progress, stalled_retry_selection, input_admission_callbacks,
receive_admission_and_path_acks, peer_window_queries, pacing_continuity, pacing_data_units, attempt_memory_limits,
ack_absolute_deadline, receive_admission_and_path_acks, peer_window_queries, pacing_continuity, pacing_data_units, attempt_memory_limits,
normalizer_rx_oom, normalizer_tx_oom, normalizer_callback_abort, reset_without_allocation, restart_allocation_failures,
receiver_bandwidth_bounds, receiver_point_lifecycle, receiver_point_wire, receiver_point_truncated,
compact_attempt_identity, compact_attempt_exhaustion, compact_sequence_exhaustion,