Correct connectivity probe and IPv4 routing documentation

This commit is contained in:
evgeny committed 2026-10-24 12:19:22 +02:00
1 parent 0445c38c31
commit bf03348c64
3 files changed
+50 -62

No files matched your search

+9 -4
View File
@@ -16,18 +16,23 @@ extern "C" {
struct UTUN_INSTANCE;
struct TOPO_GROUP;
// Запускает зондирование связности ко всем адресам удалённого узла
/* Запустить асинхронные пробы известных адресов nq из registry; group — его группа.
* UDP: до 8 сокетов, серия CONN_PROBE_COUNT с каждого до первого успешного сокета;
* TCP: один STCP ping с REALITY-параметрами при наличии. RTT — 0.1 мс, UINT16_MAX неизвестен.
* До 16 уникальных IP:port на семейство. Собственный/спящий узел и текущие пробы пропускаются;
* NAT/standby могут отложить старт. Результат — в nq->connectivity, завершение уведомляет topo callback. */
void route_connectivity_probe_node(struct UTUN_INSTANCE* instance, struct TOPO_GROUP* group,
struct TOPO_GROUP_NODE* nq);
// Отменяет все pending пробы для узла (при удалении / withdraw)
/* Отменить UDP/TCP-пробы и отложенный старт, освободить контексты; NULL допустим.
* Сбрасывает probe_status/pending_count, сохранённые RTT/status остаются. */
void route_connectivity_cancel_node(struct TOPO_GROUP_NODE* nq);
// Отменяет все pending пробы для всех узлов (при destroy)
// Отменяет pending пробы всех узлов во всех группах instance (при destroy)
void route_connectivity_cancel_all(struct UTUN_INSTANCE* instance);
// Устанавливает таймаут одного probe-пинга (по умолчанию CONN_PROBE_TIMEOUT_MS).
// Используется тестами для ускорения probe-циклов.
// Используется тестами для ускорения probe-циклов; настройка общая для процесса, 0 игнорируется.
void route_connectivity_set_probe_timeout_ms(uint16_t ms);
+35 -57
View File
@@ -1,64 +1,42 @@
# route_connectivity — зондирование прямой связности с удалённым узлом
# route_connectivity — прямые пробы адресов узла
## 1. Назначение
Проверяет прямую IP-достижимость всех адресов удалённого узла через `etcp_send_ping_to_socket()`.
Для каждого адреса перебирает локальные сокеты-кандидаты (до 8), с каждого делает серию из 3 пингов
(CONN_PROBE_COUNT=3, CONN_PROBE_TIMEOUT_MS=1000). Результаты (reachable/unreachable, min_rtt)
сохраняются в `TOPO_CONNECTIVITY` узла и используются `conn_mgr` для выбора оптимального пути.
`route_connectivity_probe_node(instance, group, nq)` берёт общую запись узла из
registry и запускает асинхронные пробы. Собственный узел, пир в SLEEP-фазе и уже
идущие/отложенные пробы пропускаются. NAT-окно сохраняет незнакомые IP для проверки
входящих; Android standby откладывает старт до активного интервала.
В отличие от `route_ping` (пинг через BGP-посредника), здесь пинги идут напрямую с локальных сокетов
на адреса удалённого узла — без промежуточных узлов.
Для каждого семейства перебираются до 16 уникальных IP:port. Нулевые адреса/порты
пропускаются. Дедупликация выполняется по IP:port, без учёта типа адреса/протокола.
## 2. Как пользоваться
```c
// Запустить зондирование узла (вызывается conn_mgr при обнаружении нового узла):
route_connectivity_probe_node(instance, nodeq);
UDP проверяется с обычных локальных сокетов того же семейства (до 8).
IPv4-кандидаты фильтруются через `sock_match` в порядке списка сокетов; предпочтений
по /24 или рейтинга DIRECT/EIM здесь нет. Для IPv6 сначала идут сокеты той же /64,
затем остальные IPv6. TCP-сокеты и `probe_only` для UDP исключены.
С каждого UDP-сокета идёт последовательная серия из `CONN_PROBE_COUNT=3` ping;
достаточно одного ответа в серии, чтобы завершить этот адрес успешно. Следующий
сокет пробуется, если текущая серия не дала успеха. RTT — минимум успешной серии,
а не обязательный минимум по всем доступным сокетам.
// Отменить зондирование (при удалении узла / withdraw):
route_connectivity_cancel_node(instance, nodeq);
TCP-адрес проверяется одним `etcp_send_tcp_ping` через STCP-клиент, независимо
от набора UDP-сокетов. Используются REALITY-параметры из записи узла; адрес с
REALITY-флагом без параметров пропускается. Проба не создаёт READY-сессию группы.
Таймаут по умолчанию 1000 мс; `route_connectivity_set_probe_timeout_ms(ms)` меняет
его для новых контекстов всего процесса, 0 игнорируется.
// Отменить все зондирования (при destroy):
route_connectivity_cancel_all(instance);
```
Результаты находятся в `nq->connectivity`: `probe_status`, `pending_count`,
`interface/nat/real_status`, соответствующие `*_min_rtt` и `*_probe_time`.
RTT и время — timebase (0.1 мс), UINT16_MAX означает неизвестный RTT.
INTERFACE обновляет также исторические поля REAL; отдельного третьего адреса
для этого не требуется. Успех одного адреса не затирается неудачей другого.
Завершение последней pending-пробы устанавливает DONE, обновляет БД и вызывает
`topo_fire_nodeinfo_cbk`. Если пригодных адресов/сокетов нет, DONE означает только
конец обхода: UNKNOWN не превращается автоматически в UNREACHABLE.
Результаты доступны через `nodeq->connectivity`:
- `probe_status` — `PROBE_STATUS_NONE` / `PROBE_STATUS_IN_PROGRESS` / `PROBE_STATUS_DONE`
- `interface_status/nat_status/real_status` — `PROBE_RESULT_UNKNOWN` / `REACHABLE` / `UNREACHABLE`
- `interface_min_rtt/nat_min_rtt/real_min_rtt` — минимальный RTT по всем сокетам (0.1ms)
- `pending_count` — счётчик незавершённых серий (когда 0 → PROBE_STATUS_DONE)
`route_connectivity_cancel_node(nq)` отменяет все UDP/TCP-пробы и отложенный старт,
освобождает контексты и сбрасывает probe_status/pending_count. Последние результаты
RTT/status сохраняются. Отмена нужна до удаления узла, группы или рабочих сокетов.
`route_connectivity_cancel_all(instance)` обходит все группы, не только UTUN.
Все вызовы выполняются в потоке ядра; group/nq заимствованы до завершения или отмены.
Ключевой нюанс: зондирование пропускает собственный узел (`nq->node->node_id == instance->node_id`).
Если зондирование уже в процессе, повторный вызов игнорируется.
## 3. API
### Внутренние структуры
| Структура | Назначение |
|-----------|------------|
| `conn_probe_ctx` | Контекст одной серии проб: `addr_type` (INTERFACE/NAT/REAL), `target_addr`, `candidate_sockets[8]`, `best_across_sockets` (min RTT по всем опробованным сокетам), `min_rtt` (в текущей серии), счётчики |
### Подбор сокетов-кандидатов (`conn_match_candidate_sockets`)
Для каждого адреса узла подбирает локальные сокеты в порядке предпочтения:
1. **INTERFACE-адрес**: PRIVATE/LOCAL сокеты в той же /24 подсети
2. **NAT/REAL-адрес**: DIRECT > EIM > PUBLIC/UNKNOWN сокеты
3. Fallback: остальные подходящие сокеты, затем все IPv4
Для IPv6: предпочитает сокеты в той же /64 подсети.
### Функции
| Функция | Назначение |
|---------|------------|
| `route_connectivity_probe_node(instance, nq)` | Перебрать все v4/v6 адреса узла, для каждого подобрать сокеты-кандидаты, запустить серии пингов по 3. Заполняет `nq->connectivity` |
| `route_connectivity_cancel_node(instance, nq)` | Сбросить `probe_status=NONE`, `pending_count=0`, занулить `nq` в ctx (чтобы callback не обновлял статистику) |
| `route_connectivity_cancel_all(instance)` | Сбросить состояние всех узлов в default-группе |
### Логика завершения
- Серия из 3 пингов с одного сокета: если все 3 потеряны → переход к следующему сокету
- Если хоть 1 пинг успешен → серия считается успешной для данного адреса, обновляется `*_status=REACHABLE` и `*_min_rtt`
- Когда `pending_count` доходит до 0 → `probe_status = PROBE_STATUS_DONE`
### Зависимости
- `src/etcp_connections.h` — `etcp_send_ping_to_socket()` (прямой пинг)
- `src/topo_node.h` — `TOPO_GROUP_NODE`, `TOPO_CONNECTIVITY`, `TOPO_ADDR4`, `TOPO_ADDR6`
- `src/topo_group.h` — `topo_groups_get_default()` (для cancel_all)
- `lib/u_async.h` — get_time_tb() для отметок времени
`route_ping` также выполняет прямые UDP-пробы, но для измерения наблюдаемого endpoint;
выбор наблюдателей/помощников и вычисление NAT-профиля находятся в `nat_detection`.
+6 -1
View File
@@ -20,8 +20,13 @@ IPv6-пакеты на данный момент дропаются на эта
**Ключевые нюансы:**
- `routing_add_conn` / `routing_del_conn` — **deprecated** (no-op), маршруты теперь управляются через BGP и таблицу `route_lib`
- Все не-IPv4 пакеты (IPv6, unknown) дропаются в `extract_dst_ip`
- Multicast (224.0.0.0/4) и limited broadcast (255.255.255.255) дропаются без логирования
- Multicast (224.0.0.0/4) и limited broadcast (255.255.255.255) отбрасываются с DEBUG-логом routing
- Пакеты без маршрута дропаются с инкрементом `instance->dropped_packets`
- `route_pkt` забирает entry и dgram при любом исходе; ожидает `[cmd:1][IPv4]` и готовые `rt`/`tun`.
- Удалённая доставка идёт через `TOPO_GROUP_UTUN`; локальная — в `tun->input_queue`.
Firewall проверяется перед маршрутизацией выхода из TUN и перед локальной доставкой в TUN.
- Все вызовы выполняются в потоке ядра. `routing_destroy` снимает DATA binding и освобождает таблицу;
callback очереди TUN снимается при остановке самого TUN/UTUN-сервиса.
## 3. API