Files
utun2/src/routing_layer/etcp_router_doc.md
T
evgeny 232ad2de6b etcp_router: разделить служебные функции и API в хедере + чистка мёртвого кода
- etcp_router.h: 4 секции (протокол / внутренние структуры / API / служебные)
- переименование router_set_max_inflight -> etcp_router_set_max_inflight
- удалены неиспользуемые: input_q_count, waiter_register/cancel, conn_close_async
  (+ поля close_callback/close_callback_arg)
- docs: актуализировать backpressure (on_send_ready на send_q) вместо удалённого waiter API
2026-09-05 22:34:00 +03:00

8.7 KiB
Raw Blame History

ETCP Router (etcp_router)

1. Назначение

Сервисный слой маршрутизации поверх ETCP — упрощённый TCP с восстановлением порядка доставки, дедупликацией и контролем inflight. Мультиплексирует до 256 сервисов (svc_id) на одном ETCP-соединении. Поддерживает transit (многошаговую маршрутизацию через промежуточные узлы), ретрансмиты, minRTT-измерения и подписи Ed25519.

2. Как пользоваться

Инициализация

// В utun_instance_init():
etcp_router_init(inst);

// Зарегистрировать обработчик сервиса (svc_id 0..255)
etcp_router_bind(inst, svc_id, my_service_callback);

Отправка

// Простой способ: сформировать ll_entry с svc_id в первом байте
struct ll_entry* e = queue_entry_new(0);
e->dgram = u_malloc(1 + payload_len);
e->dgram[0] = svc_id;
memcpy(e->dgram + 1, payload, payload_len);
e->len = 1 + payload_len;
etcp_route_send(inst, group_id, dst_node_id, e, force, mode); // mode: 0 / ROUTE_CRYPTO_SIGN / ROUTE_CRYPTO_ENCRYPT

// Или через существующий ROUTER_CONN:
struct ETCP_ROUTER_CONN* rconn = etcp_router_conn_get(inst, group_id, remote_node_id, svc_id);
etcp_router_conn_send(rconn, data, len, mode);

Приём

void my_service_callback(struct ETCP_CONN* conn, struct ll_entry* entry) {
    if (!entry) { /* соединение закрыто */ return; }
    uint8_t  svc_id   = entry->dgram[0];
    uint64_t from     = *(uint64_t*)(entry->dgram + ROUTER_SVC_SRC_OFF); // remote_node_id
    uint8_t  rx_flags = entry->dgram[ROUTER_SVC_FLAGS_OFF];              // был ли SIGNED/ENCRYPTED на wire
    // ... данные начиная с entry->dgram[ROUTER_SVC_PAYLOAD_OFF] ...
    queue_dgram_free(entry);
    queue_entry_free(entry);
}

Backpressure

// На send_q (inflight переполнен):
struct queue_waiter_handle h;
etcp_router_on_send_ready(inst, group_id, node_id, svc_id, &h, my_ready_cb, my_arg);
// Когда send_q освободится — вызовется my_ready_cb

Подпись / шифрование (модуль route_crypto)

// mode — битовая маска, применяется в начале функции отправки (route_crypto_encode),
// при приёме проверяется/расшифровывается перед вызовом коллбэка (route_crypto_decode).
#include "route_crypto.h"
etcp_route_send(inst, group_id, dst, e, force, ROUTE_CRYPTO_SIGN | ROUTE_CRYPTO_ENCRYPT);

3. API

Ключевые структуры

SVC_ROUTE_HDR (33 байта) — заголовок пакета: cmd(1) + group_id(8) + dst_node_id(8) + src_node_id(8) + seq(4) + svc_id(1) + flags(1) + timestamp(2)

Флаги: ROUTER_FLAG_START (0x80), ROUTER_FLAG_RST (0x40), ROUTER_FLAG_SIGNED (0x08), ROUTER_FLAG_ENCRYPTED (0x04), ROUTER_FLAG_CLOSE (0x02).

Формат доставки сервису (router → callback): [svc_id:1][src_node_id:8][dst_node_id:8][rx_flags:1][payload...] (ROUTER_SVC_HDR_SIZE = 18).

ETCP_ROUTER_CONN — состояние логического подключения (group_id + remote_node_id + svc_id):

  • tx_seq, rx_seq, tx_acked — seq-нумерация для порядка и inflight
  • recv_q — reorder-очередь с хеш-индексом по seq (восстановление порядка)
  • send_q — очередь ожидания при полном inflight (backpressure)
  • send_waiter — waiter на send_input_q (по 1 пакету, round-robin между сервисами)
  • watchdog_timer — медленная проверка инварианта drain (страховка от заклинивания)
  • inflight_q — копии финальных отправленных пакетов для ретрансмита (хеш по seq)
  • incoming_q — FIFO между сетевым приёмом и recv_q (защита от гонок)
  • rtt, rtt_jitter, minrtt — измерения задержки
  • inflight_limit — текущий лимит пакетов в полёте (minrtt_probe снижает до 4)
  • no_ack_count — последовательные ретрансмиты без ACK (при 17 — закрытие)
  • start_sent, peer_sync_done — синхронизация после (пере)подключения
  • closed — флаг закрытия (игнорирование таймеров)

ROUTER_INFLIGHT — запись в inflight_q: seq, last_sent_tb, send_count, dgram* (финальный wire-пакет)

TRANSIT_QUEUE — per (group_id, src, dst) пара на промежуточном узле:

  • q — FIFO транзитных пакетов
  • waiter — backpressure на send_input_q next_hop'а
  • conn — ETCP_CONN следующего шага

Внутренняя архитектура

Приём: сеть → incoming_q (FIFO) → router_incoming_q_cb → recv_q (хеш по seq)
                                                              ↓
                                                    router_try_assembly → deliver → route_crypto_decode → cb

Отправка: router_enqueue_send → router_build_packet (seq + route_crypto_encode) → send_q (FIFO, backpressure)
          router_send_kick → waiter на send_input_q → router_send_drain_cb (по 1 пакету, round-robin)
              → etcp_send + inflight_q (копия финального пакета)
                                                     ↓
                                        router_track_inflight_state + retrans_schedule
ACK: периодический (10ms) + idle (500ms) → router_send_ack(rx_seq)

Константы

Константа Значение Описание
ROUTER_MAX_INFLIGHT 256 Макс. пакетов в полёте
ROUTER_ACK_INTERVAL_TB 100 ACK интервал 10ms (0.1ms timebase)
ROUTER_ACK_IDLE_TB 5000 Idle таймаут 500ms
ROUTER_RETRANS_TIMEOUT_TB 3000 Таймаут ретрансмита 300ms
ROUTER_NO_ACK_MAX_RETRANS 17 Макс. ретрансмитов без ACK (≈5s)
ROUTER_MAX_SEND_Q_PACKETS 64 Порог backpressure send_q
ROUTER_SEND_WATCHDOG_TB 5000 Watchdog проверка инварианта drain (500ms)

Функции

Функция Описание
etcp_router_init(inst) Инициализация: bind ETCP_ID_SVC_ROUTE, создание router_conns
etcp_router_destroy(inst) Деинициализация: unbind + close_all + free
etcp_router_bind(inst, svc_id, cb) Зарегистрировать обработчик сервиса
etcp_router_unbind(inst, svc_id) Удалить обработчик сервиса
etcp_route_send(inst, group, dst, entry, force, mode) Отправить пакет (loopback/transit/direct); mode = ROUTE_CRYPTO_SIGN/ENCRYPT
etcp_router_conn_get(inst, group, remote, svc_id) Найти или создать ROUTER_CONN
etcp_router_conn_send(rconn, data, len, mode) Отправить данные с авто-seq и inflight-контролем
etcp_router_conn_close(rconn) Закрыть seq-подключение (CLOSE + уведомление сервиса)
etcp_router_conn_close_all_for_node(inst, group, node_id) Закрыть все conn к узлу
etcp_router_conn_restart(inst, group, remote, svc_id) Сброс состояния (перезапуск удалённой стороны)
etcp_router_pause_retrans_for_node(inst, node_id) Сбросить ретрансмиты без закрытия (для conn reinit)
etcp_router_set_max_inflight(rconn, new_max) Установить рабочий max_inflight
etcp_router_on_send_ready/cancel_send_ready(inst, group, node, svc, h, cb, arg) Backpressure на send_q
etcp_router_transit_queues_destroy(conn) Удалить все транзитные очереди ETCP_CONN

Модуль route_crypto (пред/пост-обработка пакета)

Функция Описание
route_crypto_encode(inst, peer, base, len, mode, &out, &len) Шифрование/подпись в начале отправки → финальный пакет
route_crypto_decode(inst, wire, len, &out, &len, &rx_flags) Проверка подписи/расшифровка перед коллбэком; ошибка → дроп