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.
 
 
 
 
 
 

15 KiB

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. Как пользоваться

Типовые сценарии

Создание/обновление информации о себе:

topo_group_update_my_nodeinfo(instance, group);

Строит TOPO_NODEQ (в group->local_node) из конфига: собирает список сокетов, адресов (interface/NAT/real), подсетей; при изменениях инкрементирует ver и помечает dirty=1. Для chat-групп (TOPO_GROUP_TYPE_CHAT) подсети не включаются.

Сериализация для отправки по BGP:

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:

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:

struct TOPO_NODEQ *nq = topo_node_find_by_id(group, node_id);

Использует хеш-индекс очереди group->nodes (ключ — node_id, 8 байт).

Дамп всех узлов:

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)