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.
 
 
 
 
 
 

7.5 KiB

Packet Normalizer (фрагментация/дефрагментация)

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

Модуль адаптирует произвольные IP-пакеты к передаче через ETCP-канал с ограниченным MTU. Состоит из двух половин:

  • Packer (упаковщик) — разбивает входящие пакеты на фрагменты размером frag_size и помещает их в etcp->input_queue. Фрагменты собираются в общий буфер пачками для экономии накладных расходов, сброс по таймеру (call_soon) при пустой входной очереди.
  • Unpacker (распаковщик) — собирает фрагменты из etcp->output_queue обратно в исходные пакеты по заголовку длины (2 байта LE), помещает результат в pn->output (который читает ETCP router/клиент).

Каждое ETCP-соединение имеет свой экземпляр PKTNORM (создаётся в etcp.c:247).

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

Создание и привязка

pn_init() вызывается автоматически при создании ETCP_CONN. Клиентский код получает нормализатор через etcp->normalizer и использует:

  • Отправка: положить пакет в pn->input (очередь pn_input). Packer сам разобьёт и отправит.
  • Приём: читать собранные пакеты из pn->output (очередь pn_output). На эту очередь ETCP вешает свой callback etcp_int_recv.
// Создание (внутри etcp_connection_create):
etcp->normalizer = pn_init(etcp);
etcp->send_input_q = etcp->normalizer->input; // единая точка входа для отправки

// Отправка пакета (пример из тестов):
struct ll_entry* entry = ll_alloc_lldgram(len);
memcpy(entry->dgram, data, len);
entry->len = len;
queue_data_put(pn->input, entry);

// Приём (через callback на pn->output):
// queue_set_callback(pn->output, etcp_int_recv, etcp);

Формат фрагментов

Каждый фрагмент, уходящий в ETCP, содержит конкатенацию пакетов, каждый предварён 2-байтовым LE-заголовком длины:

[packet1_len:2 LE][packet1_data][packet2_len:2 LE][packet2_data]...

Сброс состояния

При разрыве/переподключении вызывать pn_reset(). При ошибке сборки (некорректный заголовок) вызывается etcp_conn_reinit() — полный перезапуск соединения.

3. API

Структуры

struct PKTNORM — основная структура пары packer/unpacker.

Поле Описание
input Входная очередь packer (pn_input) — сюда кладут пакеты для отправки
output Выходная очередь unpacker (pn_output) — отсюда читают собранные пакеты
frag_size Максимальный размер одного фрагмента ETCP (mtu - ACK_REZERV - UDP_HDR - UDP_SC_HDR)
data / data_ptr / data_size Буфер-накопитель packer (из data_pool)
recvpart Частично собранный пакет unpacker
flush_timer Таймер сброса накопленного буфера (call_soon)
input_waiter_handle Backpressure-ожидание на etcp->input_queue
tx_wait_time Задержка сброса (по умолчанию 10, не используется — сброс через call_soon)
alloc_errors / logic_errors Счётчики ошибок
in_total_pkts / in_total_bytes Статистика входящих (в packer)
out_total_pkts / out_total_bytes Статистика исходящих (из unpacker)

Функции

pn_init(etcp) — создаёт пару PKTNORM. Выделяет input/output очереди с порогом 0 (backpressure: ждать полного опустошения). Вешает callback-и: packer_cb на input, pn_unpacker_cb на etcp->output_queue, etcp_int_recv на output. Возвращает NULL при ошибке.

pn_deinit(pn) — освобождает все ресурсы: очереди, буферы, таймеры, waiter-ы. Вызывает routing_del_conn() (deprecated, no-op). Снимает callback с etcp->output_queue для предотвращения use-after-free.

pn_reset(pn) — сбрасывает состояние packer и unpacker (буферы, pending, recvpart, таймер). Используется при переподключении.

pn_unpacker_reset_state(pn) — сбрасывает только unpacker (recvpart).

pn_packer_send(pn, data, len) — копирует данные в ll_alloc_lldgram и кладёт в pn->input. Используется только в юнит-тестах.

Внутренние callback-и

packer_cb — callback на pn->input. Ждёт освобождения etcp->input_queue через queue_waiter_wait, затем вызывает etcp_input_ready_cb.

etcp_input_ready_cb — основной цикл packer. Извлекает пакет из pn->input, записывает 2-байтовый заголовок длины, копирует данные в буфер pn->data. При заполнении буфера (или если осталось <3 байт) вызывает pn_send_to_etcp. Если входная очередь пуста — ставит flush_timer через uasync_call_soon для сброса хвоста.

pn_flush_cb — таймерный callback, вызывает pn_send_to_etcp при простое.

pn_send_to_etcp(pn) — выделяет ETCP_FRAGMENT из io_pool, передаёт в него накопленный буфер pn->data, отправляет в etcp->input_queue. Буфер после этого обнуляется (передан во владение фрагмента).

pn_unpacker_cb — callback на etcp->output_queue. В цикле извлекает фрагменты, парсит 2-байтовые заголовки длины, копирует данные в pn->recvpart. При полной сборке пакета помещает его в pn->output. При ошибке вызывает etcp_conn_reinit.

pn_buf_renew(pn) — выделяет новый буфер из data_pool если pn->data == NULL. При нехватке места (<3 байт) вызывает pn_send_to_etcp для сброса текущего буфера.

Зависимости

  • etcp.h / etcp_api.h — структуры ETCP_CONN, ETCP_FRAGMENT, etcp_int_recv
  • routing.h — routing_add_conn/routing_del_conn (deprecated, no-op)
  • utun_instance.h — UTUN_INSTANCE (data_pool, ua)
  • ll_queue.h — очереди, waiter, threshold
  • u_async.h — uasync_call_soon для flush-таймера
  • mem.h / memory_pool — аллокация буферов и фрагментов