Preserve the unsigned range of router RTT jitter

This commit is contained in:
evgeny committed 2026-10-24 14:54:48 +02:00
1 parent 6c13755a5c
commit dbf6bb759c
3 files changed
+26 -2

No files matched your search

+2 -1
View File
@@ -1192,7 +1192,8 @@ static void router_handle_ack(struct UTUN_INSTANCE* inst, struct ETCP_ROUTER_CON
uint16_t new_rtt = get_current_timestamp() - ack_ts;
int d_rtt = (int)new_rtt - (int)rconn->rtt;
if (d_rtt < 0) d_rtt = -d_rtt;
rconn->rtt_jitter += (int32_t)(((int64_t)d_rtt * 65536 - rconn->rtt_jitter) / 32);
int64_t jitter = rconn->rtt_jitter;
rconn->rtt_jitter = (uint32_t)(jitter + ((int64_t)d_rtt * 65536 - jitter) / 32);
rconn->rtt = new_rtt;
}
rconn->tx_acked = seq;
+1 -1
View File
@@ -109,7 +109,7 @@ struct ETCP_ROUTER_CONN {
uint8_t svc_id; // = data[16]
uint16_t last_dgram_ts; // последний timestamp датаграммы (rx или tx, timebase 0.1ms)
uint16_t rtt; // измеренный RTT (0.1ms)
int32_t rtt_jitter; // EMA jitter, fixed-point *65536 (как в ETCP)
uint32_t rtt_jitter; // EWMA |ΔRTT|, беззнаковый fixed-point *65536; монитор показывает удвоенный EWMA
uint16_t max_inflight; // настраиваемый рабочий максимум (default=ROUTER_MAX_INFLIGHT)
uint16_t inflight_limit; // текущий эффективный лимит (=max_inflight или MINRTT_PROBE_MAX_INFLIGHT)
uint16_t minrtt; // скользящее среднее minRTT (0.1ms), default=100 (10ms)
+23
View File
@@ -642,6 +642,28 @@ static int test_delivery_stats(void) {
TEARDOWN(); PASS(); return 0;
}
/* Высокий RTT не должен переполнять fixed-point EWMA jitter в отрицательное значение. */
static int test_jitter_range(void) {
TEST("ACK jitter keeps the full unsigned 16.16 range");
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
SETUP(); debug_set_category_level(DEBUG_CATEGORY_ETCPROUTE, DEBUG_LEVEL_INFO);
establish(recv_cb, &inst, TEST_REMOTE_NODE, TEST_SVC_ID, TEST_REMOTE_NODE);
struct ETCP_ROUTER_CONN* c = etcp_router_conn_get(&inst, TOPO_GROUP_UTUN, TEST_REMOTE_NODE, TEST_SVC_ID);
c->tx_seq = c->tx_sent = 1; c->rtt = 0; c->rtt_jitter = INT32_MAX;
struct SVC_ROUTE_HDR ack = {.cmd = ETCP_ID_SVC_ROUTE, .group_id = TOPO_GROUP_UTUN,
.src_node_id = TEST_REMOTE_NODE, .dst_node_id = inst.node_id, .svc_id = TEST_SVC_ID, .seq = 1,
.reset_id = c->peer_reset_id, .peer_reset_id = c->reset_id, .timestamp = (uint16_t)(get_current_timestamp() - 60000)};
if (!ack.timestamp) ack.timestamp = 1;
struct ll_entry* e = ll_alloc_lldgram(sizeof(ack)); TESTASSERT(e);
memcpy(e->dgram, &ack, sizeof(ack)); e->len = sizeof(ack); recv_cb(&fake_conn, e);
uint64_t expected = INT32_MAX + (((int64_t)c->rtt * 65536 - INT32_MAX) / 32);
uint64_t measured = (uint64_t)c->rtt_jitter;
DEBUG_INFO(DEBUG_CATEGORY_ETCPROUTE, "[regression] RTT=%u jitter=%llu expected=%llu", c->rtt,
(unsigned long long)measured, (unsigned long long)expected);
TEARDOWN();
TESTASSERT(measured == expected && measured > INT32_MAX); PASS(); return 0;
}
static int test_ack_timer(void) {
TEST("ACK timer scheduled on data receive");
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
@@ -1574,6 +1596,7 @@ int main(void) {
test_data_integrity();
test_ack_receive();
test_delivery_stats();
test_jitter_range();
test_ack_timer();
test_send_q();
test_loopback();