Describe NAT transport backpressure, ownership and mapping holds
This commit is contained in:
1 parent
7de54ab3e4
commit
1ccb266971
2 files changed
+78
-49
No files matched your search
+1
-1
@@ -36,7 +36,7 @@ if (eim_nat_init_ctx(&nat, &global_cfg) == 0 && nat.initialized) {
|
||||
`last_seen` обновляется по `get_time_tb()` в обоих направлениях. Время простоя до удаления:
|
||||
TCP — 7440 секунд без отслеживания TCP-состояния ([RFC 5382, REQ-5](https://www.rfc-editor.org/rfc/rfc5382#section-5)),
|
||||
UDP — 120 секунд ([RFC 4787, REQ-5](https://www.rfc-editor.org/rfc/rfc4787#section-4.3)),
|
||||
ICMP Echo — 60 секунд ([RFC 5508](https://www.rfc-editor.org/rfc/rfc5508#section-3.1)).
|
||||
ICMP Echo — 60 секунд ([RFC 5508](https://www.rfc-editor.org/rfc/rfc5508#section-3.2)).
|
||||
`expire` проверяет не более заданного числа слотов с сохранением курсора, статические записи не удаляет.
|
||||
В nat_transport проверяются 128 слотов каждые 100мс: очистка после timeout может задержаться примерно на 51.2с
|
||||
плюс задержки выполнения event loop. Полного обхода таблицы на пути пакета нет.
|
||||
|
||||
+77
-48
@@ -1,60 +1,89 @@
|
||||
# NAT Transport Layer (nat_transport)
|
||||
|
||||
## 1. Назначение
|
||||
Транспортный слой NAT поверх ETCP. Обеспечивает проброс IP-трафика между клиентом и провайдером NAT через ETCP-роутер (канал `ETCP_RT_ID_NAT`). Клиент захватывает пакеты из TUN-интерфейса и отправляет провайдеру; провайдер выпускает их в интернет через свой NAT-движок, а обратные пакеты возвращает клиенту.
|
||||
Передача IPv4 между отдельным TUN и удалённым NAT-провайдером через сервис `ETCP_RT_ID_NAT`
|
||||
в группе `TOPO_GROUP_UTUN`. Провайдер преобразует пакеты движком `eim_nat`, клиент использует
|
||||
только транспорт. Нормативный API и правила владения описаны в `nat_transport.h` и `eim_nat.h`.
|
||||
|
||||
## 2. Как пользоваться
|
||||
## 2. Конфигурация и поток данных
|
||||
- **Провайдер** (`nat_via_node_id = 0`): создаёт таблицу `eim_nat`. В `[nat]` задаются `tun_ifname`,
|
||||
`tun_ip`, `port_start`, `port_end`; проброс — `forward=udp:node_id_hex:IPv4:internal_port:external_port`.
|
||||
- **Клиент**: в `[nat]` задаётся `nat_via=<ID провайдера в HEX>` и параметры своего NAT TUN.
|
||||
Таблица `eim_nat` не создаётся; `inst->nat.initialized=1` означает готовность транспорта.
|
||||
Опции секции `[nat]` включают NAT; параметра `enabled` нет.
|
||||
- Создаётся отдельный `nat_tun` с `TUN_MTU_DEFAULT`. Адрес берётся из IPv4 `nat_tun_ip`, иначе из `tun_ip`.
|
||||
Маршруты ОС и доступ провайдера в интернет настраиваются отдельно.
|
||||
|
||||
### Конфигурация
|
||||
- **Провайдер** (`nat_via_node_id = 0`): создаёт таблицу `eim_nat`. В секции `[nat]` задаются `tun_ifname`,
|
||||
`tun_ip`, `port_start`, `port_end`; статический проброс — `forward=udp:node_id_hex:IPv4:internal_port:external_port`.
|
||||
- **Клиент** (`nat_via_node_id != 0`): в `[nat]` задаётся `nat_via=<ID провайдера в HEX>` и параметры своего NAT TUN.
|
||||
Таблица `eim_nat` не создаётся; `inst->nat.initialized=1` используется как флаг готовности транспорта.
|
||||
Параметра `enabled` нет: NAT включают опции секции `[nat]`.
|
||||
1. Клиент получает `[prefix:1][IP]` из `nat_tun->output_queue`. `nat_tun_output` заменяет prefix
|
||||
на `ETCP_RT_ID_NAT` и передаёт исходный entry/dgram роутеру с адресатом `nat_via_node_id`.
|
||||
2. Провайдер получает пакет в `nat_receive`, выполняет `eim_nat_egress` и пишет чистый IP в NAT TUN.
|
||||
3. Ответ/статический проброс из TUN провайдера проходит `eim_nat_ingress` в `nat_tun_output`.
|
||||
Преобразованный пакет отправляется узлу из `mapping->src_node_id`.
|
||||
4. Клиент принимает ответ только от своего провайдера, проверяет IPv4 и записывает в свой NAT TUN.
|
||||
|
||||
### Поток данных
|
||||
1. **Клиент → Провайдер**: `[prefix:1][IP]` из `nat_tun->output_queue` → callback клиента →
|
||||
`[ETCP_RT_ID_NAT:1][IP]` в `etcp_route_send(inst, TOPO_GROUP_UTUN, provider_id, ...)`.
|
||||
Source/destination и заголовки протокола добавляет роутер.
|
||||
2. **Провайдер получает**: `nat_transport_etcp_recv_cb` (зарегистрирован через `etcp_router_bind`) → `eim_nat_egress()` (source NAT) → `tun_write()` в NAT TUN.
|
||||
3. **Провайдер → Клиент (ответ/статический проброс)**: пакет из NAT TUN → `eim_nat_ingress()` →
|
||||
`[ETCP_RT_ID_NAT:1][IP]` в роутер с адресатом `entry->src_node_id`. Без mapping/адресата пакет отбрасывается.
|
||||
4. **Клиент получает ответ**: `nat_transport_etcp_recv_cb` → `tun_write()` в NAT TUN клиента.
|
||||
Роутер добавляет source/destination и протокольные заголовки. Callback получает служебный заголовок
|
||||
`[svc:1][src:8][dst:8][rx_flags:1][group:8][IP]`, размером `ROUTER_SVC_HDR_SIZE=26`.
|
||||
Это формат доставки callback, а не заголовок на проводе. CLOSE/reset без IP освобождается без трансляции.
|
||||
Приём ограничен группой UTUN. Повреждённые пакеты, фрагменты, неподдерживаемые протоколы и входящие пакеты
|
||||
провайдера без mapping отбрасываются. Ограничения проверки и преобразования — в `eim_nat.h`.
|
||||
|
||||
### Ключевые нюансы
|
||||
- Используется отдельный TUN (`nat_tun`), MTU=`TUN_MTU_DEFAULT`. Шлюз берётся из IPv4 `nat_tun_ip`, иначе из `tun_ip`.
|
||||
Маршруты ОС и выход провайдера в интернет настраиваются отдельно; модуль их не создаёт.
|
||||
- Callback'и работают через очередь `output_queue` TUN-интерфейса. По одному пакету за вызов.
|
||||
- Сервисный receive callback получает общий заголовок роутера размером 26 байтов:
|
||||
`[svc:1][src:8][dst:8][rx_flags:1][group:8][IP]` (`ROUTER_SVC_*` в `etcp_router.h`).
|
||||
Это формат доставки callback, не заголовок пакета на проводе. Отдельного 9-байтного NAT-заголовка нет.
|
||||
- Приём ограничен `TOPO_GROUP_UTUN`; клиент принимает IP только от своего `nat_via_node_id`.
|
||||
- `tun_write()` получает чистый IP без служебного префикса. Роутер принимает владение отправленным entry/dgram
|
||||
при любом результате; NAT не освобождает их повторно при отказе.
|
||||
- Все операции выполняются в uasync-потоке ядра. `init` вызывается после создания роутера,
|
||||
`destroy` — до освобождения роутера/uasync и вне NAT callback; перед повторным `init` нужен `destroy`.
|
||||
- Ограничения преобразования описаны в `eim_nat.h`: фрагменты и неподдерживаемые протоколы не преобразуются.
|
||||
Сейчас провайдер передаёт такие исходящие пакеты в свой TUN без NAT, а входящие без mapping отбрасывает.
|
||||
## 3. Очереди, ожидания и владение
|
||||
NAT не копирует IP из TUN и не создаёт для него новый пакет. Роутер синхронно копирует payload
|
||||
в свою очередь и принимает владение исходным entry/dgram при любом результате отправки.
|
||||
После передачи роутеру NAT больше не обращается к пакету и не освобождает его повторно.
|
||||
|
||||
## 3. API
|
||||
Для каждого адресата создаётся FIFO и одно отменяемое ожидание готовности router send_q.
|
||||
Адресаты индексируются через хеш `ll_queue`; выделения требуются при первом обращении к узлу.
|
||||
Перед передачей владения проверяется место в router send_q. При заполнении ожидается `on_send_ready`.
|
||||
Порядок пакетов одного адресата сохраняется; ожидания разных адресатов независимы.
|
||||
|
||||
### Структуры
|
||||
| Структура | Назначение |
|
||||
|-----------|------------|
|
||||
| `nat_transport_ctx` | Контекст: `self_node_id`, `nat_via_node_id` (0=провайдер, иначе id провайдера), `nat_tun`, флаг `initialized` |
|
||||
- `NAT_PENDING_PER_PEER=64` ограничивает дополнительный буфер адресата, включая пакет в активном ожидании.
|
||||
Новый пакет переполненного адресата отбрасывается. Остальные адресаты продолжают обслуживаться.
|
||||
Счётчик потерь обновляется всегда, предупреждения о перегрузке выводятся не чаще раза в секунду.
|
||||
- `NAT_PENDING_TOTAL=1024` ограничивает сумму дополнительных буферов. При достижении лимита
|
||||
текущий преобразованный пакет возвращается в голову `output_queue` TUN, callback остаётся приостановленным.
|
||||
Непустая очередь останавливает чтение TUN; освобождение места возобновляет callback.
|
||||
- Дополнительно существуют очереди роутера: указанные лимиты ограничивают именно NAT-буферы.
|
||||
- Адресат ответа фиксируется вместе с уже преобразованным пакетом до ожидания. Истечение/повторное
|
||||
использование mapping во время ожидания не меняет адресата и не запускает повторную трансляцию.
|
||||
|
||||
### Функции
|
||||
| Функция | Назначение |
|
||||
|---------|------------|
|
||||
| `nat_transport_init(inst)` | Инициализация: создаёт NAT TUN, настраивает eim_nat (если провайдер), биндит `ETCP_RT_ID_NAT` через etcp_router, вешает callback'и на TUN output_queue |
|
||||
| `nat_transport_destroy(inst)` | Деинициализация: анбиндит ETCP-канал, закрывает TUN, разрушает eim_nat |
|
||||
При `tun_write` с `EAGAIN/EWOULDBLOCK` удерживается один принятый пакет. `nat_receive_ready` запрещает
|
||||
доставку следующих: они остаются в router recv_q без ACK. Повтор записи назначается через 10мс;
|
||||
maintenance также повторяет запись. После успеха или окончательной ошибки пакет освобождается,
|
||||
приём NAT-каналов UTUN возобновляется. Ошибки записи диагностируются в TUN-модуле.
|
||||
|
||||
### Внутренние коллбэки
|
||||
| Коллбэк | Срабатывание |
|
||||
|---------|-------------|
|
||||
| `nat_transport_client_tun_out_cb` | Пакет из TUN output_queue на клиенте — упаковывает и шлёт провайдеру |
|
||||
| `nat_transport_provider_tun_out_cb` | Пакет из TUN output_queue на провайдере — делает ingress NAT lookup, шлёт обратно клиенту |
|
||||
| `nat_transport_etcp_recv_cb` | Получен пакет из канала `ETCP_RT_ID_NAT` — клиент пишет в TUN, провайдер делает egress NAT |
|
||||
Провайдер дополнительно вызывает `eim_nat_hold` для внешнего source-порта/echo ID пакета,
|
||||
ожидающего записи в TUN. Удержанный mapping нельзя удалить или переиспользовать при очистке.
|
||||
После успешной записи `eim_nat_release` обновляет время активности; при ошибке/остановке снимает
|
||||
удержание без обновления. Это удержание относится к исходящему пакету провайдера; ожидающий
|
||||
обратной отправки ответ уже содержит внутренний адрес и сохранённый ID клиента.
|
||||
|
||||
### Зависимости
|
||||
`eim_nat.h`, `etcp_router.h`, `etcp_api.h`, `tun_if.h`, `utun_instance.h`, `ll_queue.h`
|
||||
## 4. Обслуживание и остановка
|
||||
Таймер `nat_maintenance` каждые 100мс:
|
||||
- проверяет 128 слотов NAT на истечение: TCP — 7440с, UDP — 120с, ICMP Echo — 60с простоя;
|
||||
- восстанавливает ожидания, отменённые при close/reset router-канала;
|
||||
- удаляет пустые FIFO адресатов после 60с простоя;
|
||||
- повторяет ожидающую запись TUN.
|
||||
|
||||
Статические и удержанные mapping не истекают. Полный проход таблицы занимает около 51.2с
|
||||
при своевременном выполнении таймеров; очистка после timeout дополнительно зависит от задержек event loop.
|
||||
Полного обхода mapping на пути пакета нет. Если выделение таймера повтора TUN не удалось,
|
||||
ошибка логируется и повтор остаётся на maintenance; ошибка планирования maintenance также логируется.
|
||||
|
||||
Все вызовы выполняются в uasync-потоке ядра. `init` требует созданного роутера, перед повторным `init`
|
||||
нужен `destroy`. Остановка выполняется вне NAT callback, до освобождения роутера/uasync:
|
||||
сначала отменяются таймеры и binding, затем waiters и FIFO освобождают исходные TUN-пакеты,
|
||||
закрываются NAT router-каналы, освобождаются удержанный пакет/его mapping, TUN и таблица NAT.
|
||||
Освобождение пакетов предшествует уничтожению их TUN-пула. Другие router-сервисы продолжают работать.
|
||||
|
||||
## 5. API и проверки
|
||||
| API | Назначение |
|
||||
|---|---|
|
||||
| `nat_transport_ctx` | TUN, хеш адресатов, счётчик pending, глобально остановленный пакет, ожидающая запись TUN и таймеры |
|
||||
| `nat_transport_init(inst)` | Создать транспорт по конфигу; 0 — успех/выключенный NAT, -1 — ошибка с освобождением созданных ресурсов |
|
||||
| `nat_transport_destroy(inst)` | Отменить ожидания и освободить транспорт; NULL/повторный вызов допустимы |
|
||||
|
||||
`test_nat_transport` проверяет обе роли через настоящий роутер и TUN в test mode: порядок и контрольные суммы,
|
||||
отсутствие копии исходного entry, владение при ошибке, фильтрацию источника/группы, некорректные IP,
|
||||
давление router send_q, оба лимита NAT, прогресс исправного клиента рядом с медленным,
|
||||
истечение/повторное использование mapping во время ожидания, EAGAIN TUN и остановку с активными ожиданиями.
|
||||
Reference in new issue
Block a user