Files
utun2/lib/radix_doc.md
T
evgeny 38c9f229bc stcp: ed25519 pubkey exchange in handshake, fix instance destroy segfault, fix chat_tcp_test
- u_async.c: process immediate_queue BEFORE epoll_wait in uasync_poll
- stcp_link.c: defensive NULL etcp_conn/etcp_link in stcp_link_close
- utun_instance.c: move stcp_server_list_destroy_all to Phase J (before ETCP),
  add deferred drain in both Phase J and L
- stcp.h/c: STCP_HS_ENC_CLIENT 6→38, STCP_HS_ENC_SERVER 7→39,
  exchange ed25519_pubkey in both handshake directions
- etcp_connections.c: copy peer_ed25519 from STCP to ETCP_CONN in
  etcp_link_enter_ready_tcp; guard link->etcp in tcp_link_close_cb
- chat_sync.c: fix lk->conn NULL dereference for TCP links
- test_stcp.c: update stcp_server_create/stcp_client_connect callsites
- tools/chat_tcp_test: change transport udp→tcp
2026-08-07 00:48:27 +03:00

98 lines
5.6 KiB
Markdown

# Radix Tree (Patricia Trie) для IP-маршрутизации
## 1. Назначение
Бинарное radix-дерево (Patricia trie) для хранения маршрутов и поиска Longest Prefix Match (LPM). Производное от BSD `net/radix.c`. Используется в `route_lib.c` / `route6_lib.c` для таблиц маршрутизации IPv4/IPv6.
Каждый маршрут — пара `(key, mask)`. Ключи — sockaddr-подобные структуры: первый байт хранит длину всей структуры, остальное — IP-адрес. Максимальная длина ключа — 32 байта (`RADIX_MAX_KEY_LEN`).
Потокобезопасность: замки — заглушки (no-op). Подразумевается однопоточное использование с `u_async`.
## 2. Как пользоваться
```c
#include "../lib/radix.h"
// --- Инициализация ---
struct radix_node_head *rnh = NULL;
rn_inithead((void**)&rnh, 1); // off=1 пропускает байт длины в сравнениях
// --- Структура данных маршрута ---
struct route_data {
struct radix_node rn_nodes[2]; // ПАМЯТЬ ДЛЯ ДЕРЕВА — первые 2 поля!
uint8_t key[32];
uint8_t mask[32];
// ... пользовательские поля ...
int metric;
};
// --- Добавление маршрута ---
struct route_data *rd = u_calloc(sizeof(*rd), 1);
rd->key[0] = 17; // длина (1 + 16 байт IPv6)
memcpy(rd->key + 1, addr, 16);
rd->mask[0] = 17;
make_mask(rd->mask + 1, plen);
rn_addroute(rd->key, rd->mask, &rnh->rh, rd->rn_nodes);
// --- Longest Prefix Match ---
uint8_t search_key[17];
search_key[0] = 17;
memcpy(search_key + 1, dst_addr, 16);
struct radix_node *leaf = rn_match(search_key, &rnh->rh);
if (leaf && !(leaf->rn_flags & RNF_ROOT)) {
// leaf = &rd->rn_nodes[0] — восстанавливаем указатель на данные:
struct route_data *found = (struct route_data *)(
(char *)leaf - offsetof(struct route_data, rn_nodes));
}
// --- Точный поиск (key + mask) ---
struct radix_node *node = rn_lookup(key, mask, &rnh->rh);
// --- Удаление ---
rn_delete(rd->key, rd->mask, &rnh->rh);
// --- Обход всех маршрутов ---
static int walk_cb(struct radix_node *rn, void *arg) {
if (rn->rn_flags & RNF_ROOT) return 0;
struct route_data *rd = (struct route_data *)((char *)rn - offsetof(...));
// ... обработать rd ...
return 0; // 0 = продолжить, !=0 = прервать
}
rn_walktree(&rnh->rh, walk_cb, NULL);
// --- Обход с нижней границы (mask-фильтр) ---
uint8_t base_key[...], base_mask[...];
rn_walktree_from(&rnh->rh, base_key, base_mask, walk_cb, NULL);
// --- Завершение ---
rn_detachhead((void**)&rnh);
```
**Ключевые нюансы:**
- `rn_nodes[2]` **должны быть первыми полями** в структуре данных — дерево использует их для хранения.
- `rn_addroute` возвращает `&rd->rn_nodes[0]` при успехе. Для извлечения структуры используйте `offsetof()`.
- `rn_match` возвращает самый специфичный (longest prefix) лист либо `NULL`. Если `RNF_ROOT` — совпадений нет.
- Максимальный размер ключа — 32 байта (включая байт длины).
- Все динамические выделения через `R_Malloc`/`R_Zalloc`/`R_Free` (макросы на `u_malloc`/`u_free`).
- Потокобезопасность не реализована — замки (макросы `RADIX_NODE_HEAD_LOCK` и т.д.) пустые.
## 3. API
| Функция | Назначение |
|---------|-----------|
| `rn_inithead(void **head, int off)` | Выделяет и инициализирует `radix_node_head`. `off` — смещение (байт длины sockaddr). |
| `rn_detachhead(void **head)` | Освобождает дерево и все узлы (через `rn_walktree` + `rn_delete`). |
| `rn_match(key, head)` | Longest Prefix Match. Возвращает лист-победитель или NULL. |
| `rn_lookup(key, mask, head)` | Точный поиск (key + mask). Возвращает узел или NULL. |
| `rn_addroute(key, mask, head, nodes[2])` | Добавляет маршрут. `nodes` — память из структуры данных. |
| `rn_delete(key, mask, head)` | Удаляет маршрут. Возвращает удалённый узел для освобождения. |
| `rn_walktree(head, callback, arg)` | Обход всего дерева (in-order), вызывает `callback(rn, arg)` для каждого листа. |
| `rn_walktree_from(head, base_key, base_mask, callback, arg)` | Обход поддерева, ограниченного `base_mask`. |
| `rn_refines(mask1, mask2)` | Проверяет, является ли `mask1` более специфичной, чем `mask2`. |
| `rn_nextprefix(rn)` | Переход к следующему dupedkey-узлу с тем же ключом. |
**Структуры:**
- `struct radix_node_head` — корень дерева с таблицей функций (`rnh_matchaddr`, `rnh_addaddr`, ...).
- `struct radix_node` — узел: внутренний (bit-offset, left/right) или лист (key, mask, dupedkey).
- `struct radix_mask` — аннотация маски для нетривиальных (non-normal) масок в поддеревьях.