You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

20 KiB

ETCP Router Architecture

Структуры данных

ETCP_ROUTER_CONN (один на пару remote_node_id + svc_id)
┌─────────────────────────────────────────────────────┐
│  ll_entry  (хеш-индекс: remote_node_id[8] + svc_id[1]) │
│  remote_node_id: u64                                 │
│  svc_id:         u8                                  │
│  last_dgram_ts:  u16  (timestamp последней датаграммы) │
│                                                      │
│  tx_seq:  u32   следующий seq для отправки            │
│  rx_seq:  u32   ожидаемый seq для сборки              │
│  tx_acked: u32  сколько наших пакетов подтвердил remote │
│  last_sent_ack_seq: u32  последний отправленный ACK    │
│                                                      │
│  recv_q:  ll_queue*  очередь reorder (хеш по seq[4])  │
│  send_q:  ll_queue*  очередь при переполнении inflight │
│                                                      │
│  ack_timer:          void*   периодический 100ms      │
│  idle_ack_timer:     void*   idle таймаут 500ms       │
│  send_resume_timer:  void*   retry send_q 50ms        │
│  send_blocked:       u8      inflight полон           │
└─────────────────────────────────────────────────────┘

SVC_ROUTE_HDR (22 байта)
┌──────┬────────────────┬────────────────┬───────┬────────┬──────────┐
│ cmd  │  dst_node_id   │  src_node_id   │  seq  │ svc_id │ payload  │
│  u8  │      u64       │      u64       │  u32  │  u8    │  ...     │
└──────┴────────────────┴────────────────┴───────┴────────┴──────────┘

  seq в data-пакетах = tx_seq (счетчик отправленных)
  seq в ACK-пакетах   = rx_seq (ожидаемый следующий)
  CLOSE-флаг = 0x80000000 в seq, RST-флаг = 0x40000000

Send Path (отправка данных)

                    etcp_route_send(inst, dst, entry)
                    etcp_router_conn_send(rconn, data, len)
                              │
                              ▼
                    ┌─────────────────────┐
                    │ rconn = find/get    │  поиск по (dst, svc_id)
                    │ авто-создание если │  или etcp_router_conn_get()
                    │ ещё нет            │
                    └────────┬────────────┘
                             │
                             ▼
              ┌──────────────────────────────┐
              │ inflight < ROUTER_MAX(256)?  │
              │ tx_seq - tx_acked < 256 ?    │
              └──────┬───────────┬───────────┘
                     │ YES       │ NO (inflight полон)
                     ▼           ▼
          ┌──────────────┐  ┌─────────────────────┐
          │router_send_one│  │ router_enqueue_send │ → send_q (FIFO)
          │  (прямая)     │  │   (в очередь)       │   send_blocked = 1
          └──────┬────────┘  └─────────┬───────────┘   send_resume_timer (50ms)
                 │                     │
                 ▼                     │
     ┌────────────────────┐            │
     │ tx_seq++           │            │
     │ hdr.dst = dst      │            │
     │ hdr.src = node_id  │            │
     │ hdr.seq = tx_seq   │            │
     │ hdr.svc_id = svc   │            │
     │                     │            │
     │ etcp_send(conn, e)  │            │
     └────────────────────┘            │
                                       │
          ┌────────────────────────────┘
          │  (при получении ACK от remote)
          ▼
   ┌────────────────────┐
   │ router_drain_send_q│  вызывается из ACK handler
   │                     │  или по send_resume_timer
   │ while inflight < 256│
   │   e = send_q.pop()  │
   │   router_send_one(e)│
   │                     │
   │ если send_q пуст:   │
   │   send_blocked = 0  │
   └────────────────────┘

Receive Path (приём данных)

               etcp_router_recv_cb(conn, entry)
                         │
                         ▼
              ┌──────────────────────┐
              │ dst == node_id?      │
              └──┬───────────────┬───┘
                 │ YES           │ NO (транзит)
                 ▼               ▼
    ┌────────────────────┐   ┌──────────────────────────┐
    │ Мы — целевая нода   │   │ Транзит: найти next hop   │
    └────────┬───────────┘   │ route_bgp_find_conn_for_  │
             │               │ node(bgp, hdr.dst)        │
             ▼               │ etcp_send(next, entry)    │
    ┌────────────────────┐   └──────────────────────────┘
    │ pl_len == 0?       │
    └──┬───────────┬─────┘
       │ YES       │ NO (данные)
       ▼           ▼
  ┌─────────┐  ┌─────────────────────────┐
  │ CLOSE/  │  │ rconn = find/get        │
  │ RST?    │  │ (авто-создание если нет) │
  └──┬──┬───┘  └───────────┬─────────────┘
     │  │                  │
     │  │ NO (ACK)         ▼
     │  ▼          ┌───────────────────────────────────────┐
     │ ┌──────────┐│ Проверка границ seq:                   │
     │ │ tx_acked ││ d = seq - rx_seq                       │
     │ │ = hdr.seq││ |d| < ROUTER_MAX_INFLIGHT?             │
     │ │ (только  ││                                        │
     │ │ вперёд)  ││ Дубликат?                              │
     │ │ drain_q  ││ rx_seq - seq > 0  ИЛИ                  │
     │ └──────────┘│ seq уже в recv_q?                      │
     │             └──────┬─────────────┬──────────────────┘
     │                    │ OK          │ out-of-bounds / dup
     │                    ▼             ▼
     │             ┌──────────────┐  ┌─────────┐
     │             │ recv_q.put() │  │ DROP    │
     │             │ хеш по seq   │  └─────────┘
     │             └──────┬───────┘
     │                    │
     │                    ▼
     │             ┌──────────────────────┐
     │             │ seq == rx_seq?       │
     │             └──┬───────────────┬───┘
     │                │ YES           │ NO
     │                ▼               │
     │         ┌──────────────┐       │
     │         │ try_assembly │       │
     │         │ while next в │       │
     │         │ recv_q:      │       │
     │         │   deliver()  │       │
     │         │   rx_seq++   │       │
     │         └──────┬───────┘       │
     │                │               │
     │                ▼               │
     │         ┌──────────────────────┴──┐
     │         │ router_deliver()        │
     │         │ вызывает callback       │
     │         │ сервиса (svc_id)        │
     │         │ entry: [svc_id|payload] │
     │         └──────────────┬──────────┘
     │                        │
     ▼                        ▼
  ┌────────────────────────────────────┐
  │ router_schedule_ack(rconn)         │
  │ запускает ack_timer (100ms) если   │
  │ ещё не запущен                     │
  └────────────────────────────────────┘
     CLOSE / RST ветка:
     ┌────────────────────────────────────────┐
     │ pl_len == 0 && seq & CLOSE/RST         │
     │   → router_close_and_notify(rconn)     │
     │     ├─ router_send_close_to_service()  │
     │     │   (callback с NULL conn)         │
     │     ├─ отправить CLOSE удалённой стороне│
     │     ├─ отмена всех таймеров            │
     │     ├─ очистка recv_q + send_q         │
     │     └─ удаление из inst->router_conns  │
     └────────────────────────────────────────┘

ACK Mechanism

         ┌─────────────────────────────────────────┐
         │       router_schedule_ack(rconn)        │
         │  (вызывается при получении данных)       │
         └────────────────┬────────────────────────┘
                          │
         ┌────────────────▼────────────────────────┐
         │  если idle_ack_timer активен — отменить  │
         │  если ack_timer не активен — запустить   │
         │  ROUTER_ACK_INTERVAL_TB = 1000 (100ms)  │
         └────────────────┬────────────────────────┘
                          │
                          ▼  (через 100ms)
         ┌─────────────────────────────────────────┐
         │          router_ack_timer_cb()           │
         │                                          │
         │  if rx_seq != last_sent_ack_seq:         │
         │    router_send_ack(rconn)                │
         │    last_sent_ack_seq = rx_seq            │
         │    перезапустить ack_timer               │
         │  else:                                   │
         │    запустить idle_ack_timer (500ms)      │
         └────────────────┬────────────────────────┘
                          │
                          ▼  (через 500ms)
         ┌─────────────────────────────────────────┐
         │        router_idle_ack_timer_cb()        │
         │                                          │
         │  if rx_seq != last_sent_ack_seq:         │
         │    router_send_ack(rconn)   (досылка)    │
         │    last_sent_ack_seq = rx_seq            │
         └─────────────────────────────────────────┘

         router_send_ack(rconn):
           hdr.seq = rx_seq
           hdr.svc_id = svc_id
           pl_len = 0  →  это ACK-пакет
           etcp_send(conn, entry)
         Обработка входящего ACK:
         ┌────────────────────────────────────────┐
         │ pl_len == 0 && нет CLOSE/RST флагов     │
         │                                         │
         │ if seq >= tx_acked:    // только вперёд │
         │   tx_acked = seq       // обновить      │
         │ else:                                   │
         │   DEBUG_WARN "stale ACK"                │
         │                                         │
         │ if send_blocked:                        │
         │   router_drain_send_q(rconn)            │
         └────────────────────────────────────────┘

Inflight Control

   ROUTER_MAX_INFLIGHT = 256

   Отправка возможна когда:   tx_seq - tx_acked < 256
   Отправка заблокирована:    tx_seq - tx_acked >= 256

   При блокировке:
     данные → send_q (FIFO, без дропов)
     send_blocked = 1
     send_resume_timer = 50ms retry

   Разблокировка:
     приход ACK от remote → tx_acked обновляется
       → router_drain_send_q() разгребает send_q
     или send_resume_timer (50ms) → router_drain_send_q()

   send_q полностью разобран → send_blocked = 0

Полная схема потоков

                           ┌──────────┐
                           │  Сервис  │ (routing, proxy, NAT, ...)
                           │  (svc_id)│
                           └────┬─────┘
                                │
              etcp_route_send() │              callback(svc_id, entry)
                                ▼              ▲
 ┌─────────┐   send   ┌─────────────────────────────────┐   recv   ┌─────────┐
 │  TUN    │─────────▶│         ETCP ROUTER              │─────────▶│  TUN    │
 │ (выход) │          │                                  │          │ (вход)  │
 └─────────┘          │  ┌──────────┐  ┌──────────┐    │          └─────────┘
                      │  │ send_q   │  │ recv_q   │    │
                      │  │ (FIFO)   │  │ (хеш seq)│    │
                      │  └────┬─────┘  └────┬─────┘    │
                      │       │             │          │
                      │       ▼             ▼          │
                      │  ┌─────────────────────────┐   │
                      │  │   Inflight / Assembly   │   │
                      │  │   tx_seq - tx_acked     │   │
                      │  │   rx_seq → deliver      │   │
                      │  └───────────┬─────────────┘   │
                      │              │                  │
                      └──────────────┼──────────────────┘
                                     │
                              ┌──────▼──────┐
                              │   BGP       │
                              │  (нахождение│
                              │   next hop) │
                              └──────┬──────┘
                                     │
                              ┌──────▼──────┐
                              │ ETCP conn   │──▶ сеть
                              └─────────────┘

   ──▶ send (исходящие данные)
   ──▶ recv (входящие данные, callback сервису)
   ──▶ транзит (через BGP к следующему hop)

Таймеры (один rconn)

   ┌─────────────────────────────────────────────────────┐
   │                                                     │
   │  ack_timer ──────── 100ms ─────▶ router_ack_timer_cb│
   │    (периодический)                                    │
   │                                                     │
   │  idle_ack_timer ─── 500ms ─────▶ router_idle_ack_cb │
   │    (досылка последнего ACK)                           │
   │                                                     │
   │  send_resume_timer ─ 50ms ─────▶ router_send_resume │
   │    (retry когда send_q не пуст)                      │
   │                                                     │
   └─────────────────────────────────────────────────────┘

Флаги seq

   ┌──────────────────────────────────────────────────┐
   │  CLOSE:  0x80000000  нормальное закрытие conn     │
   │  RST:    0x40000000  conn не найден (reset)       │
   │                                                   │
   │  CLOSE/RST-пакеты: seq=0 | флаг, pl_len=0         │
   │  Data-пакеты:      seq=tx_seq,     pl_len>0       │
   │  ACK-пакеты:       seq=rx_seq,     pl_len=0       │
   └──────────────────────────────────────────────────┘