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.
 
 
 
 
 
 

5.6 KiB

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

#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) масок в поддеревьях.