refactor: move transport (etcp/stcp/normalizer) to transport_layer/, routing (bgp/pings/topo*) to routing_layer/
This commit is contained in:
1 parent
3dda701c67
commit
fcf3fb7f51
146 files changed
+582
-333
No files matched your search
@@ -0,0 +1,170 @@
|
||||
# topo_node
|
||||
|
||||
## 1. Назначение
|
||||
|
||||
Модель данных узла топологии — структуры данных для представления узла в памяти, сериализации/десериализации в бинарный wire-формат для BGP-обмена, учёт ссылок (refcounting) и диагностический дамп.
|
||||
|
||||
Модуль определяет два слоя представлений:
|
||||
- **Память:** связанные списки (`TOPO_ADDR4`, `TOPO_SOCKMETA4`, `TOPO_SUBNET4` и др.) для удобной модификации.
|
||||
- **Wire-формат:** packed-структуры (`TOPOMSG_NODE`, `TOPOMSG_ADDR4` и др.) для передачи по сети без выравнивания.
|
||||
|
||||
Сам модуль не содержит сетевой логики BGP-обмена — этим занимается `topo_group`. Здесь только данные и их упаковка/распаковка.
|
||||
|
||||
Узлы персистентно хранятся в SQLite через модуль `topo_node_sqlite`. Память для элементов списков (адреса, сокет-мета, подсети) выделяется из memory pool'ов из `topo_groups`.
|
||||
|
||||
## 2. Как пользоваться
|
||||
|
||||
### Типовые сценарии
|
||||
|
||||
**Создание/обновление информации о себе:**
|
||||
```c
|
||||
topo_group_update_my_nodeinfo(instance, group);
|
||||
```
|
||||
Строит `TOPO_NODEQ` (в `group->local_node`) из конфига: собирает список сокетов, адресов (interface/NAT/real), подсетей; при изменениях инкрементирует `ver` и помечает `dirty=1`. Для chat-групп (`TOPO_GROUP_TYPE_CHAT`) подсети не включаются.
|
||||
|
||||
**Сериализация для отправки по BGP:**
|
||||
```c
|
||||
uint8_t buf[2048];
|
||||
int len = topo_node_serialize(group, nq, buf, sizeof(buf));
|
||||
```
|
||||
Запаковывает `TOPO_NODEQ` → бинарный буфер: заголовок `TOPOMSG_NODE`, затем имя узла, v4/v6 sock_meta, v4/v6 адреса, подсети (если `TOPO_FLAG_SEND_SUBNETS`), транзитные узлы и hop-лист.
|
||||
|
||||
**Десериализация при получении NODEINFO:**
|
||||
```c
|
||||
struct TOPO_NODE *ni = NULL;
|
||||
struct TOPO_NODESUBNETS *subnets = NULL;
|
||||
struct TOPOMSG_TRANZIT *tranzit = NULL;
|
||||
uint8_t tranzit_count = 0;
|
||||
uint64_t *hop_list = NULL;
|
||||
uint8_t hop_count = 0;
|
||||
topo_node_deserialize(group, data, data_len, &ni, &subnets, &tranzit, &tranzit_count, &hop_list, &hop_count);
|
||||
```
|
||||
Восстанавливает `TOPO_NODE`, подсети, транзит и hop-лист из бинарного буфера. Элементы списков аллоцируются из memory pool'ов. Выделенная память должна быть освобождена:
|
||||
- `topo_node_unref(ni)` — освобождает `TOPO_NODE` и `node_name`
|
||||
- `topo_node_free_lists(group, nq)` — освобождает списки обратно в пулы, а также `subnets`, `tranzit_data`, `hop_list`
|
||||
|
||||
**Поиск узла по ID:**
|
||||
```c
|
||||
struct TOPO_NODEQ *nq = topo_node_find_by_id(group, node_id);
|
||||
```
|
||||
Использует хеш-индекс очереди `group->nodes` (ключ — `node_id`, 8 байт).
|
||||
|
||||
**Дамп всех узлов:**
|
||||
```c
|
||||
topo_node_dump_all(group); // в лог
|
||||
topo_node_format_all(group, buf, size); // в строку
|
||||
```
|
||||
|
||||
### Ключевые концепции
|
||||
|
||||
- **TOPO_NODE** — базовые данные узла: pubkey (X25519), ed25519_pubkey, имя, версия, групповой ID. Разделяется между группами через счётчик ссылок.
|
||||
|
||||
- **TOPO_NODEQ** — запись в очереди узлов группы. Содержит `TOPO_NODE*` (общий), плюс динамические пути, подсети, транзитные узлы, hop-лист, связность, conn_mgr. Все поля аллоцированы отдельно и освобождаются через `topo_node_free_lists()`.
|
||||
|
||||
- **TOPO_NODEPATH** — путь до узла через конкретное ETCP-соединение. Хранится в `paths`-очереди типа `ll_queue`. После самой структуры идёт массив `uint64_t hop[hop_count]` (variable-length).
|
||||
|
||||
- **Счётчик ссылок:** `topo_node_ref()`/`topo_node_unref()`. При падении счётчика до 0 освобождается `node_name` и сам `TOPO_NODE`. Сами списки адресов и sock_meta освобождаются отдельно через `free_lists()`.
|
||||
|
||||
- **Адреса бывают трёх типов:** `TOPO_ADDR_INTERFACE` (LAN-адрес), `TOPO_ADDR_NAT` (после детекции NAT), `TOPO_ADDR_REAL` (подтверждённый прямой адрес). Для каждого сокета может быть до 3 адресов в списке.
|
||||
|
||||
- **TOPO_CONNECTIVITY** — локальное состояние связности (не передаётся по BGP): статус зондирования (NONE/IN_PROGRESS/DONE), результаты для interface/nat/real адресов, минимальные RTT, время зондирования.
|
||||
|
||||
- **TOPO_FLAG_SEND_SUBNETS** — флаг в `TOPO_NODE.flags`: если установлен, подсети сериализуются и включаются в wire-формат. Для chat-групп сбрасывается в 0.
|
||||
|
||||
- **Wire-протокол:** заголовок `TOPOMSG_NODE` (75 байт packed) + динамическая часть: `node_name` (0-255 байт), `SOCKMETA4*N`, `ADDR4*N`, `SOCKMETA6*N`, `ADDR6*N`, опционально подсети, транзит, hop-лист. Размер динамической части вычисляется функцией `topo_node_dyn_size()`.
|
||||
|
||||
## 3. API
|
||||
|
||||
### Основные структуры
|
||||
|
||||
| Структура | Назначение |
|
||||
|-----------|-----------|
|
||||
| `struct TOPO_NODE` | Идентичность узла: pubkeys (X25519+Ed25519), имя, версия, group_id, node_id, списки v4/v6 сокет-метаданных и адресов. Счётчик ссылок. |
|
||||
| `struct TOPO_NODEQ` | Запись в очереди группы. Содержит `TOPO_NODE*`, подсети, транзитные данные, hop-лист, очередь `paths` (TOPO_NODEPATH), связность, conn_mgr. `best_socket` — указатель на лучший ETCP-сокет для связи. |
|
||||
| `struct TOPO_NODEPATH` | Путь до узла через ETCP-соединение с hop_count. Variable-length: после структуры идёт `uint64_t hop[]`. |
|
||||
| `struct TOPO_NODESUBNETS` | Списки v4 и v6 подсетей, анонсируемых узлом. Отдельный malloc, может быть NULL. |
|
||||
| `struct TOPO_CONNECTIVITY` | Локальное состояние проверки связности: статусы зондирования, RTT для interface/nat/real адресов. |
|
||||
| `struct TOPOMSG_NODE` | Packed-заголовок wire-формата (75 байт). Содержит счётчики элементов динамической части. |
|
||||
| `struct TOPOMSG_ADDR4/6` | Packed wire-формат одного адреса (addr, port, type, socket_id, protocol). |
|
||||
| `struct TOPOMSG_SOCKMETA4/6` | Packed wire-формат метаданных сокета (id, config_type, nat_type). |
|
||||
| `struct TOPOMSG_SUBNET4/6` | Packed wire-формат подсети (addr, prefix_length). |
|
||||
| `struct TOPOMSG_TRANZIT` | Packed wire-формат транзитного узла (node_id, rtt, link_q). |
|
||||
|
||||
### Вспомогательные типы в памяти (связанные списки)
|
||||
|
||||
| Тип | Назначение |
|
||||
|-----|-----------|
|
||||
| `struct TOPO_SOCKMETA4` | Элемент списка v4 сокет-метаданных (next*, id, config_type, nat_type). |
|
||||
| `struct TOPO_ADDR4` | Элемент списка v4 адресов (next*, addr[4], port, type, socket_id, protocol). |
|
||||
| `struct TOPO_SOCKMETA6` | Элемент списка v6 сокет-метаданных. |
|
||||
| `struct TOPO_ADDR6` | Элемент списка v6 адресов. |
|
||||
| `struct TOPO_SUBNET4` | Элемент списка v4 подсетей (next*, addr[4], prefix_length). |
|
||||
| `struct TOPO_SUBNET6` | Элемент списка v6 подсетей. |
|
||||
|
||||
Все элементы списков аллоцируются из memory pool'ов и освобождаются через `memory_pool_free()`.
|
||||
|
||||
### Константы
|
||||
|
||||
| Константа | Значение | Назначение |
|
||||
|-----------|---------|-----------|
|
||||
| `TOPO_ADDR_INTERFACE` | 0 | Интерфейсный (LAN) адрес сокета |
|
||||
| `TOPO_ADDR_NAT` | 1 | NAT-адрес после детекции |
|
||||
| `TOPO_ADDR_REAL` | 2 | Подтверждённый прямой адрес |
|
||||
| `TOPO_PROTO_UDP` | 0x01 | UDP-транспорт |
|
||||
| `TOPO_PROTO_TCP` | 0x02 | TCP-транспорт |
|
||||
| `PROBE_STATUS_NONE` | 0 | Зондирование не запускалось |
|
||||
| `PROBE_STATUS_IN_PROGRESS` | 1 | Зондирование идёт |
|
||||
| `PROBE_STATUS_DONE` | 2 | Зондирование завершено |
|
||||
| `PROBE_RESULT_UNKNOWN` | 0 | Результат неизвестен |
|
||||
| `PROBE_RESULT_REACHABLE` | 1 | Адрес достижим |
|
||||
| `PROBE_RESULT_UNREACHABLE` | 2 | Адрес недостижим |
|
||||
| `CONN_TYPE_DIRECT` | 1 | Прямое соединение |
|
||||
| `CONN_TYPE_REVERSE` | 2 | Обратное соединение |
|
||||
| `CONN_TYPE_INDIRECT` | 3 | Соединение через посредника |
|
||||
| `TOPO_FLAG_SEND_SUBNETS` | 0x01 | Флаг: отправлять подсети |
|
||||
| `TOPO_GROUP_UTUN` | `0x8000000000000000ULL` | ID группы uTun по умолчанию |
|
||||
|
||||
### Функции
|
||||
|
||||
**Управление памятью и refcounting:**
|
||||
- `topo_node_ref(ni)` — увеличить счётчик ссылок на `TOPO_NODE`.
|
||||
- `topo_node_unref(ni)` — уменьшить счётчик; при 0 освободить `node_name` и `TOPO_NODE` (но не списки — их надо предварительно освободить через `topo_node_free_lists`).
|
||||
- `topo_node_free_lists(group, nq)` — освободить все списки адресов/sock_meta обратно в memory pool'ы, освободить `subnets`, `tranzit_data`, `hop_list`, сделать `unref` на `node`, обнулить указатели.
|
||||
|
||||
**Сериализация:**
|
||||
- `topo_node_dyn_size(msg)` — вычислить размер динамической части wire-формата по полям-счётчикам заголовка `TOPOMSG_NODE`. Не учитывает сам заголовок.
|
||||
- `topo_node_serialize(group, nq, out, out_max)` — сериализовать `TOPO_NODEQ` в бинарный буфер. Возвращает количество записанных байт или -1 при ошибке (переполнение или невалидные аргументы). Формат: заголовок `TOPOMSG_NODE`, затем name, v4 sock_meta, v4 addrs, v6 sock_meta, v6 addrs, подсети (опционально), tranzit, hop_list.
|
||||
|
||||
**Десериализация:**
|
||||
- `topo_node_deserialize(group, data, len, &out_ni, &out_subnets, &out_tranzit, &out_tranzit_count, &out_hop_list, &out_hop_count)` — восстановить `TOPO_NODE`, подсети, транзит и hop-лист из бинарного wire-формата. Аллоцирует `TOPO_NODE` через `u_calloc` (ref_count=1), элементы списков — из memory pool'ов, `subnets`, `tranzit_data`, `hop_list` — отдельными `u_malloc`. Возвращает 0 при успехе, -1 при несоответствии размера или ошибке аллокации. Если подсети есть в wire-формате но флаг `TOPO_FLAG_SEND_SUBNETS` не установлен, они пропускаются.
|
||||
|
||||
**Поиск:**
|
||||
- `topo_node_find_by_id(group, node_id)` — найти `TOPO_NODEQ` в очереди группы по `node_id` через хеш-индекс. Возвращает NULL если не найден.
|
||||
|
||||
**Обновление информации о себе:**
|
||||
- `topo_group_update_my_nodeinfo(instance, group)` — перестроить `group->local_node` (`TOPO_NODEQ`) из текущих данных инстанса (сокеты, NAT, адреса, подсети, ключи). Сравнивает количество элементов с предыдущим значением; если есть изменения — освобождает старый `local_node`, создаёт новый, инкрементирует `ver`, помечает `dirty=1`. Обновляет таблицу маршрутов (`route_delete`/`route_insert`). Для chat-групп подсети не включаются. Возвращает количество v4 подсетей.
|
||||
|
||||
**Диагностика:**
|
||||
- `topo_node_dump_all(group)` — дамп всех узлов группы в лог (DEBUG_CATEGORY_BGP). Для каждого узла выводит: ID, имя, версию, pubkeys, v4/v6 сокеты и адреса, подсети, транзитные узлы, пути (с hop-ами), статус связности, conn_mgr. Пропускает узлы с `node==NULL`.
|
||||
- `topo_node_format_all(group, buf, buf_size)` — аналогичный дамп в строковый буфер. Возвращает количество записанных байт. При переполнении добавляет `[TRUNCATED]`.
|
||||
|
||||
**Inline-аксессоры (из .h):**
|
||||
- `topo_v4_sock_meta(ni)` / `topo_v4_addrs(ni)` / `topo_v6_sock_meta(ni)` / `topo_v6_addrs(ni)` — получить списки из `TOPO_NODE`.
|
||||
- `topo_v4_subnets(r)` / `topo_v6_subnets(r)` — получить списки подсетей из `TOPO_NODESUBNETS*` (NULL-safe).
|
||||
- `topo_list_count(head)` — посчитать количество элементов в любом из списков (next — первое поле).
|
||||
|
||||
### Зависимости
|
||||
|
||||
| Модуль | Использование |
|
||||
|--------|--------------|
|
||||
| `ll_queue.h` | `TOPO_NODEQ` — запись в очереди, хеш-индекс по `node_id`, `paths` — вложенная очередь |
|
||||
| `secure_channel.h` | `SC_PUBKEY_SIZE` (32) для массивов pubkey/ed25519 |
|
||||
| `mem.h` | `u_malloc`, `u_calloc`, `u_free`, `u_strdup` |
|
||||
| `memory_pool.h` | `memory_pool_alloc`/`memory_pool_free` для элементов списков (пулы из `topo_groups`) |
|
||||
| `debug_config.h` | `DEBUG_INFO`, `DEBUG_WARN`, `DEBUG_ERROR`, `log_dump` |
|
||||
| `topo_group.h` | `struct TOPO_GROUP` (аргумент большинства функций) |
|
||||
| `etcp.h` | `struct ETCP_CONN`, `struct ETCP_SOCKET` |
|
||||
| `config_parser.h` | `struct CFG_ROUTE_ENTRY`, `struct CFG_SERVER` (при построении local_node) |
|
||||
| `route_lib.h` | `route_insert()`, `route_delete()` (при обновлении local_node) |
|
||||
| `etcp_debug.h` | `ip_to_str()` (для дампа адресов и подсетей) |
|
||||
| `utun_instance.h` | `struct UTUN_INSTANCE` (аргумент `topo_group_update_my_nodeinfo`) |
|
||||
Reference in new issue
Block a user