Align route table and observation documentation

This commit is contained in:
evgeny committed 2026-10-24 12:17:44 +02:00
1 parent 1ad8ff73ad
commit 30a69712fc
3 files changed
+43 -39

No files matched your search

+34 -31
View File
@@ -1,31 +1,34 @@
В таблице роутинга маршруты не пересекаются. Т.е. не может быть одновременно 192.168.1.1/24 и 192.168.1.100/30
Как работает роутинг:
1. типов маршрута бывает два: learned (роутятся в ETCP instance) и local (роутятся в TUN).
local - локальные маршруты из конфига (опция конфига my_subnet=IP/Mask)
при инициализации local сразу добавляются в роутинг таблицу (ипользуя запись BGP_NODEINFO_PACKET* my_nodeinfo).
BGP_NODEINFO собирается на узле владельце node, далее распространяется по остальным узлам.
2. При установке подключения к новому узлу мы отправляем этому узлу все nodeinfo. Если несколько доступных линков - отправляем только один - preferred_conn
3. При изменении preferred_conn рассылаем reroute (например старый preferred_conn удален)
3. При удалении всех подключений рассылаем withdraw.
3. При получении BGP_NODEINFO_PACKET мы смотрим есть ли такой узел уже в таблице. Если узла нет - добавляем, если есть - обновляем информацию о узле включая его маршруты и список next_hop через которые доступен узел (nb_routes).
Добавляем так:
инкрементируем hop_count
устанавливая etcp линк с которого приняли как next_hop, добавляем его в hop_list.
рассылаем по всем активным линкам кроме линка с которого получили (обязательно)
Обновление: обновляем hop_list если поменялся
4. При отключении от узла (если у node не осталось nb_routes) мы:
Удаляем node и вложенные структуры: все маршруты узла
Рассылаем withdraw для узла hop_id.
Логика рассылки withdraw:
Если получен withdraw - удаляем этот маршрут и распространяем withdraw или reroute по всем линкам кроме того с которого получили. В зависимости от изменений (остались ли резервные линки или изменился preferred_conn).
Метрик маршрута пока нет. используется первый доступный.
Как работаеут маршрутизация:
destination IP -> route table lookup -> route entry (ip/mask, node_info*) -> выбор лучшего next_hop -> отправка в next_hop
route_lib — локальная таблица IPv4-подсетей UTUN
================================================
Подсети в таблице не пересекаются. Запрещены одинаковые и вложенные диапазоны,
как между узлами, так и внутри одного переданного набора. Например,
10.0.0.0/8 исключает 10.1.0.0/24; соседние 10.1.0.0/24 и 10.1.1.0/24 допустимы.
Маршрут /0 занимает всё адресное пространство и может быть только единственным.
route_insert(table, node) добавляет все node->subnets->v4_subnets атомарно.
Префиксы должны быть в диапазоне 0..32; адреса нормализуются маской перед хранением.
При неверных аргументах, отсутствии подсетей, пересечении или OOM возвращает false,
не меняя таблицу и её статистику. Перед заменой маршрутов узла вызывают route_delete.
Таблица — отсортированный массив. route_lookup получает IPv4 в host byte order
и бинарным поиском возвращает единственный подходящий диапазон либо NULL.
Это не LPM-таблица: вложенные префиксы исключены при вставке.
Указатель на ROUTE_ENTRY действителен только до следующего изменения таблицы.
Адреса TOPO_SUBNET4 хранятся в сетевых байтах, parse_subnet возвращает host order,
is_local_subnet принимает network order. parse_subnet сохраняет host-биты и читает
префикс через atoi; это не строгий валидатор всей строки CIDR.
TOPO_GROUP_NODE заимствован, в том числе для локальных маршрутов.
Маршруты удаляют до освобождения узла. destroy освобождает массив, но не узлы.
Все вызовы выполняются в одном потоке ядра.
Наполнение таблицы и поиск следующего узла — разные задачи:
IPv4 destination -> route_lookup -> TOPO_GROUP_NODE -> etcp_route_send
-> выбор живого next hop через CM/BGP -> ETCP.
Для локального владельца routing доставляет пакет в TUN после firewall.
Групповые пути, WITHDRAW, выбор по числу переходов и READY описаны в topo_group.h;
общая подписанная запись узла — в topo_node.h и doc/node_snapshot.md.
IPv6-таблица route6_lib использует radix и разрешает вложенные префиксы.
Основной routing.c пока доставляет только IPv4.
+1 -1
View File
@@ -25,7 +25,7 @@ int route_ping_addr_equal(const struct sockaddr_storage *a, const struct sockadd
/* Отправить OBSERVE PING: group/round и generation сокета ненулевые, timeout_ms — мс.
* peer_key — 32 байта ключа наблюдателя, peer_address — его UDP endpoint.
* Возвращает результат etcp_send_ping_to_socket (0/-1), callback/arg — его контракт.
* Возвращает 0 при запуске, отрицательный код ошибки ETCP при отказе; callback/arg — контракт ETCP.
* Ответ: address(19) || tag(33); профиль сокета здесь не изменяется. */
int route_ping_observe(struct ETCP_SOCKET *socket, const uint8_t peer_key[SC_PUBKEY_SIZE],
const struct sockaddr_storage *peer_address, uint64_t group, uint64_t round, int timeout_ms,
+8 -7
View File
@@ -4,15 +4,16 @@
`ETCP_SOCKET`. Выбор B/C, пересылка управляющих сообщений и классификация
профиля принадлежат `nat_detection`; алгоритм — в `doc/nat_detection.txt`.
`route_ping_observe(socket, peer_key, peer_address, round, timeout_ms, callback, arg)`
`route_ping_observe(socket, peer_key, peer_address, group, round, timeout_ms, callback, arg)`
передаёт PING с `ETCP_PING_FLAG_OBSERVE`. PONG содержит фактически наблюдаемый
source IP:port и исходный тег. Профиль не меняется от единственного ответа.
`route_ping_observation` проверяет размер, ID/поколение сокета и round.
`route_ping_observation` проверяет размер, ID/поколение сокета, round и group.
Адрес занимает 19 байт: family(1: 4/6), IP(16: IPv4 + 12 нулей либо IPv6),
port(2, BE). Тег занимает 25 байт: `NAT2UDP!`(8), socket_id(1),
generation(8, BE), round(8, BE). Неправильные family, скрытые IPv4-байты
и нулевой порт отвергаются. Новый wire не использует native packed integers.
port(2, BE). Тег занимает 33 байта: `NAT4UDP!`(8), socket_id(1),
generation(8, BE), round(8, BE), group(8, BE). Декодирование отвергает неправильные
family, скрытые IPv4-байты и нулевой порт. IPv6 scope_id в wire не передаётся.
Кодирование нулевой порт не запрещает. Числа тега передаются в BE.
В транспорте nonce генерируется CSPRNG; PONG должен соответствовать ожидаемому
ключу, source IP:port и принимающему socket generation. Pending снимается
@@ -20,8 +21,8 @@ generation(8, BE), round(8, BE). Неправильные family, скрытые
совпадающие запросы без callback; arg остаётся собственностью вызывающего.
`ETCP_PING_FLAG_ADDRESS_CHECK` обозначает прямое входящее испытание. Его
receipt фиксируется на рабочем сокете владельца до отправки PONG. Потеря
обратного PONG поэтому не превращает полученный ingress в отрицательный результат.
приём передаётся `nat_detection_receive_ingress` без UDP-ответа: ответ мог бы
испортить историю контактов. Результат передаётся по защищённому управляющему каналу.
UDP-результаты не используются для TCP listener и SOCKS5 endpoint.
Проверки: `tests/test_route_ping.c`, `tests/test_nat_detection.c`,