#ifndef ROUTE_LIB_H #define ROUTE_LIB_H #include #include #include // Forward declarations struct ETCP_CONNECTIONS; struct ROUTE_TABLE; struct ROUTE_ENTRY; /** * @brief Флаги узла */ typedef enum { ROUTE_FLAG_ACTIVE = (1 << 0), /**< Маршрут активен */ ROUTE_FLAG_LEARNED = (1 << 1) /**< Маршрут изучен */ } route_flags_t; struct NODE_CONN_INFO { uint32_t endpoint_ip; // IP для прямого подключения (к nexthop_node_id). 0 - нет IP (если мы - сервер) uint16_t endpoint_port; // Порт для прямого подключения (к nexthop_node_id). 0 - нет PORT (если мы - сервер) uint8_t public_key[64]; // публичный ключ узла (для прямого подключения) struct ETCP_CONN* conn_id; // Указатель на подключение к next_hop, может быть null. // next_hop - это первый элемент в hop_list. // hop list может быть разный для разных подключений. Это надо понимать и учитывать. uint64_t* hop_list; // маршрут до узла (next hop -> ... -> destination_hop): список промежуточных узлов (NODE ID, кол-во - hop_count) включая конечный узел, не включая наш узел. null - локальный маршрут uint8_t hop_count; // Количество узлов до узла назначения. 0 - я (not used), 1 - direct connect (hoplist 1 запись nexthop_node_id = id узла назначения) }; struct NODE_CONNS_INFO {// Один NODE_CONNS_INFO на один node_id. несколько маршрутов с одинаковым node_id должны ссылаться на один экземпляр NODE_CONNS_INFO. uint64_t node_id; // ID узла назначения. Если = моему ID - локальный маршрут. uint8_t flags; // флаги узла uint8_t preferred_conn; // выбранное соединение (его будем распространять далее по BGP). по умолчанию 0. при изменении conn_info надо за ним присмотреть. uint8_t conninfo_count; // число подключений к узлу uint8_t conninfo_memsize; // размер выделенной памяти (оптимизация realloc) uint16_t ref_count; // счетчик ссылок с разных route_entry для освобождения struct NODE_CONN_INFO conn_info[0]; // сами подключения. управлять памятью своими силами. использовать u_malloc, u_reclloc, u_free (совместимо с stdlib). максимально просто - только увеличиваем при нехватке, не уменьшаем. }; /** * @brief Callback тип для уведомления об изменении маршрута * * @param table Таблица маршрутизации * @param entry Запись маршрута * @param action Действие: 0=insert, 1=update, 2=delete * @param arg Пользовательский аргумент */ typedef void (*route_change_callback_fn)(struct ROUTE_TABLE* table, struct ROUTE_ENTRY* entry, int action, uint64_t changed_from, /**< peer_node_id от кого пришло изменение, 0 если локальное */ void* arg); /** * @brief Расширенная запись маршрута * * Структура представляет собой отдельную запись в таблице маршрутизации с детальной информацией о маршруте. */ struct ROUTE_ENTRY { uint32_t network; // Сетевой адрес (big-endian) uint8_t prefix_length; // Длина префикса подсети struct NODE_CONNS_INFO* conn_list; // список прямых подключений к узлу. null если - локальный маршрут. // node_id - в conn_list. Если нет доступных подключений - маршрут удаляем как бесполезный // hop list / hop count - это относится к подключению. может быть разный для разных подключений. uint64_t created_time; /**< Время создания (в timebase - 0.1ms) - use get_time_tb();*/ uint64_t last_update; /**< Время последнего обновления (в timebase - 0.1ms) */ }; /** * @brief Таблица маршрутизации * * Структура представляет собой таблицу маршрутизации, содержащую записи маршрутов, подсети и статистику. * маршруты не должны пересекаться. т.е. адрес 192.168.1.1/30 нельзя добавить если есть 192.168.1.2/32 или 192.168.1.1/24 */ struct ROUTE_TABLE { struct ROUTE_ENTRY *entries; /**< Массив записей маршрутов */ size_t count; /**< Текущее количество записей */ size_t capacity; /**< Максимальная емкость таблицы */ uint32_t *dynamic_subnets; /**< Динамические подсети (массив пар: сеть, префикс) */ size_t dynamic_subnet_count; /**< Количество динамических подсетей */ uint32_t *local_subnets; /**< Локальные подсети (массив пар: сеть, префикс) */ size_t local_subnet_count; /**< Количество локальных подсетей */ struct { uint64_t local_routes; /**< Количество локальных маршрутов */ uint64_t learned_routes; /**< Количество изученных маршрутов */ uint64_t routes_lookup_hits; /**< Количество попаданий в поиск маршрутов */ uint64_t routes_lookup_misses; /**< Количество промахов в поиск маршрутов */ } stats; /**< Статистика таблицы маршрутизации */ route_change_callback_fn change_callback; /**< Callback при изменении маршрута */ void* change_callback_arg; /**< Аргумент для callback */ }; /** * @brief Создает новую таблицу маршрутизации * * @return Указатель на созданную таблицу или NULL в случае ошибки */ struct ROUTE_TABLE *route_table_create(void); /** * @brief Уничтожает таблицу маршрутизации и освобождает ресурсы * * @param table Указатель на таблицу маршрутизации */ void route_table_destroy(struct ROUTE_TABLE *table); /** * @brief Вставляет новую запись в таблицу маршрутизации * * @param table Указатель на таблицу маршрутизации * @param entry Указатель на вставляемую запись (conn_list должен быть NULL) * @param conn Соединение (next_hop). NULL = локальный маршрут * @param node_id ID узла-владельца префикса (из пакета BGP) * @param my_node_id Наш собственный node_id (для обнаружения петель, 0 = отключить проверку) * @param hop_list Список хопов (уже с препроцессингом) * @param hop_count Количество хопов * @return true если вставка/обновление успешно */ bool route_insert(struct ROUTE_TABLE *table, const struct ROUTE_ENTRY *entry, struct ETCP_CONN *conn, uint64_t node_id, // владелец префикса uint64_t my_node_id, // наш node_id (для loop detection) uint64_t *hop_list, uint8_t hop_count); /** Удаляет конкретное подключение из всех маршрутов (при падении линка) */ void route_remove_conn(struct ROUTE_TABLE *table, struct ETCP_CONN *conn); /** * @brief Удаляет один путь (через conn) к указанному node_id. * Используется при получении WITHDRAW от соседа. * Если путей больше не осталось — полностью withdraw + callback(2). * Если изменился preferred_conn — reroute + callback(1). */ bool route_remove_path(struct ROUTE_TABLE *table, struct ETCP_CONN *conn, uint64_t node_id); /** * @brief Удаляет все записи из таблицы маршрутизации для указанного узла * * @param table Указатель на таблицу маршрутизации * @param node_id ID узла, все маршруты которого нужно удалить */ void route_delete(struct ROUTE_TABLE *table, uint64_t node_id); /** * @brief Выполняет поиск маршрута для заданного IP-адреса * * @param table Указатель на таблицу маршрутизации * @param dest_ip Целевой IP-адрес * @return найденный маршрут или NULL */ struct ROUTE_ENTRY* route_lookup(struct ROUTE_TABLE *table, uint32_t dest_ip); /** * @brief Печатает содержимое таблицы маршрутизации * * @param table Указатель на таблицу маршрутизации */ void route_table_print(const struct ROUTE_TABLE *table); /** * @brief Парсит строку подсети в сетевой адрес и длину префикса * * @param subnet_str Строка подсети (например, "192.168.1.0/24") * @param network Указатель для сохранения сетевого адреса * @param prefix_length Указатель для сохранения длины префикса * @return 0 при успехе, -1 при ошибке */ int parse_subnet(const char *subnet_str, uint32_t *network, uint8_t *prefix_length); #endif // ROUTE_LIB_H