Browse Source

route redesign + tests

feature/nodeinfo-routing
Evgeny 4 days ago
parent
commit
9f13cf5459
  1. 20
      lib/ll_queue.h
  2. 382
      src/route_bgp.c
  3. 92
      src/route_bgp.h
  4. 31
      src/route_bgp.txt
  5. 6
      src/route_lib.c
  6. 7
      src/route_lib.h
  7. 165
      src/route_node.c
  8. 20
      src/route_node.h
  9. 23
      src/utun_instance.c
  10. 4
      tests/Makefile.am
  11. 31
      tests/test_bgp_route_exchange.c
  12. 19
      tests/test_etcp_two_instances.c
  13. 4
      tests/test_route_lib.c

20
lib/ll_queue.h

@ -228,11 +228,29 @@ int queue_data_put(struct ll_queue* q, struct ll_entry* entry);
*/
int queue_data_put_first(struct ll_queue* q, struct ll_entry* entry);
/**
* @brief Добавляет элемент в конец очереди с явным указанием смещения индекса для hash.
* @param q очередь
* @param entry элемент
* @param index_offset смещение индекса (node_id) в data[]
* @param index_size размер индекса (8 для uint64_t node_id)
* @return 0 успех, -1 ошибка
*/
int queue_data_put_with_index(struct ll_queue* q, struct ll_entry* entry,
uint16_t index_offset, uint16_t index_size);
uint16_t index_offset, uint16_t index_size);
/**
* @brief Добавляет элемент в начало очереди с явным указанием смещения индекса для hash.
* @param q очередь
* @param entry элемент
* @param index_offset смещение индекса в data[]
* @param index_size размер индекса
* @return 0 успех, -1 ошибка
*/
int queue_data_put_first_with_index(struct ll_queue* q, struct ll_entry* entry,
uint16_t index_offset, uint16_t index_size);
/**
* @brief Извлекает элемент из начала очереди.
* @param q очередь

382
src/route_bgp.c

@ -2,11 +2,9 @@
* @file route_bgp.c
* @brief BGP-like обмен маршрутами исправленная версия под новую route_lib
*/
#include <stdlib.h>
#include <string.h>
#include "../lib/platform_compat.h"
#include "route_node.h"
#include "route_lib.h"
#include "route_bgp.h"
@ -19,84 +17,84 @@
#include "../lib/debug_config.h"
#include "../lib/mem.h"
// ============================================================================
// Вспомогательные функции
// ============================================================================
// ============================================================================
// Отправка (только preferred_conn + hop_list)
// Вспомогательные функции
// ============================================================================
/* Old route packet sending function removed - using NODEINFO only now */
static void route_bgp_send_table_request(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn) {
if (!bgp || !conn) return;
static void route_bgp_send_table_request(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn)
{
if (!bgp || !conn) {
return;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending table request to %s", conn->log_name);
route_bgp_send_nodeinfo(bgp, conn);
struct BGP_ROUTE_REQUEST* req = u_calloc(1, sizeof(struct BGP_ROUTE_REQUEST));
if (!req) return;
req->cmd = ETCP_ID_ROUTE_ENTRY;
req->subcmd = ROUTE_SUBCMD_REQUEST_TABLE;
struct ll_entry* e = queue_entry_new(0);
if (!e) {
u_free(req);
return;
}
e->dgram = (uint8_t*)req;
e->len = sizeof(struct BGP_ROUTE_REQUEST);
etcp_send(conn, e);
}
/* Old full table sending removed - now using NODEINFO */
/* Old full table sending removed - now using NODEINFO broadcast now */
// ============================================================================
// Broadcast / Withdraw
// Broadcast / Withdraw: node_id - удаляемый узел, wd_source - от кого получена команда удалить
// ============================================================================
/* Old broadcast route function removed - using NODEINFO broadcast now */
static void route_bgp_broadcast_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id,
struct ETCP_CONN* exclude) {
static void route_bgp_broadcast_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id, uint64_t wd_source, struct ETCP_CONN* exclude)
{
if (!bgp) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_broadcast_withdraw: bgp is NULL");
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "bgp is NULL");
return;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_broadcast_withdraw: node_id=%016llx exclude=%p",
(unsigned long long)node_id, (void*)exclude);
struct NODEINFO_Q* nq = route_bgp_get_node(bgp, node_id);
if (!nq) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "node not found");
return;
}
if (wd_source != 0 && nq->paths) {
}
if (nq->paths && queue_entry_count(nq->paths) == 0) {
if (bgp->instance && bgp->instance->rt) route_delete(bgp->instance->rt, nq);
nq->dirty = 1;
}
struct BGP_WITHDRAW_PACKET* pkt = u_calloc(1, sizeof(struct BGP_WITHDRAW_PACKET));
if (!pkt) return;
pkt->cmd = ETCP_ID_ROUTE_ENTRY;
pkt->subcmd = ROUTE_SUBCMD_WITHDRAW;
pkt->node_id = htobe64(node_id);
struct ll_entry* send_entry = queue_entry_new(0);
if (!send_entry) { u_free(pkt); return; }
send_entry->dgram = (uint8_t*)pkt;
send_entry->len = sizeof(struct BGP_WITHDRAW_PACKET);
struct ll_entry* e = bgp->senders_list->head;
pkt->wd_source = htobe64(wd_source);
struct ll_entry* e = bgp->senders_list ? bgp->senders_list->head : NULL;
while (e) {
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)e->data;
if (item->conn != exclude) {
if (item && item->conn && item->conn != exclude) {
struct ll_entry* copy = queue_entry_new(0);
if (copy) {
copy->dgram = u_malloc(send_entry->len);
memcpy(copy->dgram, send_entry->dgram, send_entry->len);
copy->len = send_entry->len;
copy->dgram = u_malloc(sizeof(*pkt));
if (copy->dgram) memcpy(copy->dgram, pkt, sizeof(*pkt));
copy->len = sizeof(*pkt);
etcp_send(item->conn, copy);
}
}
e = e->next;
}
queue_entry_free(send_entry);
u_free(pkt);
}
// ============================================================================
// Callback на изменение таблицы (insert / update / delete)
// ============================================================================
/* Old route change callback removed - now using NODEINFO updates */
// ============================================================================
// Приём пакетов
// ============================================================================
static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* entry) {
static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* entry)
{
if (!from_conn || !entry || entry->len < 2) {
if (entry) {
queue_dgram_free(entry);
@ -130,10 +128,10 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
if (subcmd == ROUTE_SUBCMD_NODEINFO) {
route_bgp_process_nodeinfo(bgp, from_conn, data, entry->len);
} else if (subcmd == ROUTE_SUBCMD_WITHDRAW) {
route_bgp_process_withdraw(bgp, data, entry->len);
route_bgp_process_withdraw(bgp, from_conn, data, entry->len);
} else if (subcmd == ROUTE_SUBCMD_REQUEST_TABLE) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received table request from %s", from_conn->log_name);
route_bgp_send_nodeinfo(bgp, from_conn);
route_bgp_send_nodeinfo(bgp->local_node, from_conn); /* всегда отправляем свой local_node */
}
queue_dgram_free(entry);
@ -146,7 +144,8 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
// ============================================================================
// Callback для готовности ETCP соединения - отправляет маршруты
static void route_bgp_on_conn_up(struct ETCP_CONN* conn, void* arg) {
static void route_bgp_on_conn_up(struct ETCP_CONN* conn, void* arg)
{
(void)arg;
if (conn && conn->instance && conn->instance->bgp) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "BGP ON UP %s", conn->log_name);
@ -155,7 +154,8 @@ static void route_bgp_on_conn_up(struct ETCP_CONN* conn, void* arg) {
}
}
static void route_bgp_on_conn_down(struct ETCP_CONN* conn, void* arg) {
static void route_bgp_on_conn_down(struct ETCP_CONN* conn, void* arg)
{
(void)arg;
if (conn && conn->instance && conn->instance->bgp) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "BGP ON DOWN %s", conn->log_name);
@ -165,7 +165,8 @@ static void route_bgp_on_conn_down(struct ETCP_CONN* conn, void* arg) {
}
// Callback для новых ETCP соединений - устанавливает ready callback
static void route_bgp_etcp_conn_cbk(struct ETCP_CONN* conn, void* arg) {
static void route_bgp_etcp_conn_cbk(struct ETCP_CONN* conn, void* arg)
{
(void)arg;
if (conn && conn->instance && conn->instance->bgp) {
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "BGP SET CBKS %s", conn->log_name);
@ -175,13 +176,15 @@ static void route_bgp_etcp_conn_cbk(struct ETCP_CONN* conn, void* arg) {
}
}
struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance) {
struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance)
{
if (!instance) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: instance is NULL");
return NULL;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_init: node_id=%016llx", (unsigned long long)instance->node_id);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_init: node_id=%016llx",
(unsigned long long)instance->node_id);
struct ROUTE_BGP* bgp = u_calloc(1, sizeof(struct ROUTE_BGP));
if (!bgp) {
@ -207,10 +210,27 @@ struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance) {
return NULL;
}
// Build initial my_nodeinfo
if (route_bgp_build_my_nodeinfo(instance, bgp) != 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: build_my_nodeinfo failed");
int vc = 0;
struct CFG_ROUTE_ENTRY* s = instance->config->my_subnets;
while (s) {
if (s->ip.family == AF_INET) vc++;
s = s->next;
}
size_t d = vc * sizeof(struct NODEINFO_IPV4_SUBNET);
bgp->local_node = u_calloc(1, sizeof(struct NODEINFO_Q) + d);
if (!bgp->local_node) {
queue_free(bgp->nodes);
queue_free(bgp->senders_list);
u_free(bgp);
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: local_node alloc failed");
return NULL;
}
bgp->local_node->node.node_id = htobe64(instance->node_id);
bgp->local_node->node.hop_count = 0;
bgp->local_node->node.ver = 1;
bgp->local_node->dirty = 0;
route_bgp_update_my_nodeinfo(instance, bgp);
etcp_bind(instance, ETCP_ID_ROUTE_ENTRY, route_bgp_receive_cbk);
@ -221,7 +241,8 @@ struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance) {
return bgp;
}
void route_bgp_destroy(struct UTUN_INSTANCE* instance) {
void route_bgp_destroy(struct UTUN_INSTANCE* instance)
{
if (!instance) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_destroy: instance is NULL");
return;
@ -231,32 +252,34 @@ void route_bgp_destroy(struct UTUN_INSTANCE* instance) {
return;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_destroy: node_id=%016llx", (unsigned long long)instance->node_id);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_destroy: node_id=%016llx",
(unsigned long long)instance->node_id);
etcp_unbind(instance, ETCP_ID_ROUTE_ENTRY);
// очистка списка senders
struct ll_entry* e;
while ((e = queue_data_get(instance->bgp->senders_list)) != NULL) {
queue_entry_free(e);
}
queue_free(instance->bgp->senders_list);
// очистка nodes
if (instance->bgp->nodes) {
queue_free(instance->bgp->nodes);
if (instance->bgp->local_node) {
if (instance->bgp->local_node->paths) {
queue_free(instance->bgp->local_node->paths);
}
u_free(instance->bgp->local_node);
}
// Free my_nodeinfo
if (instance->bgp->my_nodeinfo) {
u_free(instance->bgp->my_nodeinfo);
if (instance->bgp->nodes) {
queue_free(instance->bgp->nodes);
}
u_free(instance->bgp);
instance->bgp = NULL;
}
void route_bgp_new_conn(struct ETCP_CONN* conn) {
void route_bgp_new_conn(struct ETCP_CONN* conn)
{
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn is NULL");
return;
@ -275,7 +298,6 @@ void route_bgp_new_conn(struct ETCP_CONN* conn) {
}
struct ROUTE_BGP* bgp = conn->instance->bgp;
struct ROUTE_TABLE* rt = conn->instance->rt;
// === 1. Проверяем, уже есть ли это соединение в списке ===
bool already_exists = false;
@ -292,11 +314,11 @@ void route_bgp_new_conn(struct ETCP_CONN* conn) {
// === 2. Если нет — добавляем (только один раз) ===
if (!already_exists) {
struct ll_entry* item_entry = queue_entry_new(sizeof(struct ROUTE_BGP_CONN_ITEM));
if (!item_entry) return;
if (!item_entry) {
return;
}
((struct ROUTE_BGP_CONN_ITEM*)item_entry->data)->conn = conn;
queue_data_put(bgp->senders_list, item_entry);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "New connection added to senders_list");
}
@ -304,7 +326,8 @@ void route_bgp_new_conn(struct ETCP_CONN* conn) {
route_bgp_send_table_request(bgp, conn);
}
void route_bgp_remove_conn(struct ETCP_CONN* conn) {
void route_bgp_remove_conn(struct ETCP_CONN* conn)
{
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: conn is NULL");
return;
@ -314,8 +337,9 @@ void route_bgp_remove_conn(struct ETCP_CONN* conn) {
return;
}
// SAFETY: проверяем что conn ещё есть в senders_list
struct ROUTE_BGP* bgp = conn->instance->bgp;
// SAFETY: проверяем что conn ещё есть в senders_list
bool found_in_list = false;
struct ll_entry* e = bgp->senders_list->head;
while (e) {
@ -332,7 +356,8 @@ void route_bgp_remove_conn(struct ETCP_CONN* conn) {
return;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: peer=%016llx", (unsigned long long)conn->peer_node_id);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: peer=%016llx",
(unsigned long long)conn->peer_node_id);
struct ROUTE_TABLE* rt = conn->instance->rt;
@ -341,7 +366,7 @@ void route_bgp_remove_conn(struct ETCP_CONN* conn) {
bool need_withdraw = false;
struct ll_entry* node_entry = bgp->nodes ? bgp->nodes->head : NULL;
while (node_entry) {
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)node_entry->data;
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)node_entry;
if (route_bgp_remove_path(nq, conn) == 1) {
need_withdraw = true;
if (rt) {
@ -364,37 +389,96 @@ void route_bgp_remove_conn(struct ETCP_CONN* conn) {
}
if (need_withdraw) {
route_bgp_send_withdraw(bgp, conn->peer_node_id);
route_bgp_broadcast_withdraw(bgp, conn->peer_node_id, conn->instance->node_id, NULL);
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Connection removed, paths updated");
}
/* ================================================
* NEW NODEINFO BASED IMPLEMENTATION
* ================================================ */
struct NODEINFO_Q* route_bgp_get_node(struct ROUTE_BGP* bgp, uint64_t node_id) {
if (!bgp || !bgp->nodes) return NULL;
struct NODEINFO_Q* route_bgp_get_node(struct ROUTE_BGP* bgp, uint64_t node_id)
{
if (!bgp || !bgp->nodes) {
return NULL;
}
uint64_t key = htobe64(node_id);
struct ll_entry* e = queue_find_data_by_index(bgp->nodes, &key, 8);
return e ? (struct NODEINFO_Q*)e->data : NULL;
return e ? (struct NODEINFO_Q*)e : NULL;
}
int route_bgp_add_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn) {
if (!nq || !conn) return -1;
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "Added path for node %016llx via conn %s",
(unsigned long long)nq->node.node_id, conn->log_name);
int route_bgp_add_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn, uint64_t* hop_list, uint8_t hop_count)
{
if (!nq || !conn || hop_count > MAX_HOPS || !hop_list) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "add_path: invalid args");
return -1;
}
if (!nq->paths) {
nq->paths = queue_new(conn->instance->ua, 32, "node_paths");
if (!nq->paths) return -1;
}
size_t hop_size = hop_count * 8;
size_t path_size = sizeof(struct NODEINFO_PATH) - sizeof(struct ll_entry) + hop_size;
struct ll_entry* pe = queue_entry_new(path_size);
if (!pe) return -1;
struct NODEINFO_PATH* path = (struct NODEINFO_PATH*)pe;
path->conn = conn;
path->hop_count = hop_count;
uint64_t* stored = (uint64_t*)((uint8_t*)path + sizeof(struct NODEINFO_PATH));
memcpy(stored, hop_list, hop_size);
queue_data_put(nq->paths, pe);
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "Added path for node %016llx via conn %s with %d hops", (unsigned long long)nq->node.node_id, conn->log_name, hop_count);
return 0;
}
int route_bgp_remove_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn) {
if (!nq || !conn || !nq->paths) return -1;
int route_bgp_remove_path_by_hop(struct NODEINFO_Q* nq, uint64_t wd_source) {
if (!nq || !nq->paths) return 0;
int removed = 0;
struct ll_entry* e = nq->paths->head;
while (e) {
struct NODEINFO_PATH* path = (struct NODEINFO_PATH*)e;
// parse hoplist in dyn after hop_count (after fixed PATH)
uint64_t* hop = (uint64_t*)((uint8_t*)path + sizeof(struct NODEINFO_PATH));
bool has_wd = false;
for (uint8_t i = 0; i < path->hop_count; i++) {
if (hop[i] == wd_source) {
has_wd = true;
break;
}
}
if (has_wd) {
struct ll_entry* next = e->next;
queue_remove_data(nq->paths, e);
queue_entry_free(e);
removed++;
e = next;
continue;
}
e = e->next;
}
if (removed > 0 && nq->paths && queue_entry_count(nq->paths) == 0) {
queue_free(nq->paths);
nq->paths = NULL;
return 1; // unreachable
}
return removed;
}
int route_bgp_remove_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn)
{
if (!nq || !conn || !nq->paths) {
return -1;
}
// Remove conn from paths queue
struct ll_entry* e = nq->paths->head;
while (e) {
if (e->data == (void*)conn) {
struct NODEINFO_PATH* path = (struct NODEINFO_PATH*)e;
if (path->conn == conn) {
queue_remove_data(nq->paths, e);
queue_entry_free(e);
break;
@ -403,7 +487,6 @@ int route_bgp_remove_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn) {
}
int remaining = nq->paths ? queue_entry_count(nq->paths) : 0;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Removed path for node %016llx via %s, remaining paths: %d",
(unsigned long long)nq->node.node_id, conn->log_name, remaining);
@ -415,13 +498,15 @@ int route_bgp_remove_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn) {
}
return 1; // signal that node became unreachable
}
return 0;
}
int route_bgp_process_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* from,
const uint8_t* data, size_t len) {
if (!bgp || !from || len < sizeof(struct BGP_NODEINFO_PACKET)) return -1;
const uint8_t* data, size_t len)
{
if (!bgp || !from || len < sizeof(struct BGP_NODEINFO_PACKET)) {
return -1;
}
struct BGP_NODEINFO_PACKET* pkt = (struct BGP_NODEINFO_PACKET*)data;
struct NODEINFO* ni = &pkt->node;
@ -443,91 +528,152 @@ int route_bgp_process_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* from,
}
if (!existing) {
struct ll_entry* entry = queue_entry_new(sizeof(struct NODEINFO_Q));
if (!entry) return -1;
existing = (struct NODEINFO_Q*)entry->data;
size_t dyn = len - sizeof(struct BGP_NODEINFO_PACKET) + 8;
struct ll_entry* entry = queue_entry_new(sizeof(struct NODEINFO_Q) + dyn);
if (!entry) {
return -1;
}
existing = (struct NODEINFO_Q*)entry;
existing->paths = queue_new(bgp->instance->ua, 32, "node_paths");
queue_data_put(bgp->nodes, entry);
queue_data_put_with_index(bgp->nodes, entry, offsetof(struct NODEINFO_Q, node.node_id), 8);
}
memcpy(&existing->node, ni, sizeof(struct NODEINFO));
existing->last_ver = new_ver;
route_bgp_add_path(existing, from);
uint8_t* dyn_dest = (uint8_t*)&existing->node + sizeof(struct NODEINFO);
const uint8_t* dyn_src = data + sizeof(struct BGP_NODEINFO_PACKET);
size_t dyn_size = len - sizeof(struct BGP_NODEINFO_PACKET);
memcpy(dyn_dest, dyn_src, dyn_size);
uint8_t* hop_dest = dyn_dest + dyn_size;
uint64_t sender = htobe64(from->peer_node_id);
memcpy(hop_dest, &sender, 8);
existing->node.hop_count = ni->hop_count + 1;
if (ni->hop_count > 0) {
route_bgp_add_path(existing, from, (uint64_t*)hop_dest, existing->node.hop_count);
}
if (bgp->instance->rt) {
route_insert(bgp->instance->rt, existing);
}
// Пересылаем дальше (увеличиваем hop_count)
if (ni->hop_count < MAX_HOPS - 1) {
ni->hop_count++;
route_bgp_broadcast_nodeinfo(bgp, from);
ni->hop_count--; // возвращаем назад
ni->hop_count--;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Processed NODEINFO from %s (node=%016llx, ver=%d, paths=%d)",
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Processed NODEINFO from %s (node=%016llx,ver=%d,paths=%d)",
from->log_name, (unsigned long long)node_id, new_ver,
existing->paths ? queue_entry_count(existing->paths) : 0);
return 0;
}
int route_bgp_process_withdraw(struct ROUTE_BGP* bgp, const uint8_t* data, size_t len) {
if (!bgp || len < sizeof(struct BGP_WITHDRAW_PACKET)) return -1;
int route_bgp_process_withdraw(struct ROUTE_BGP* bgp, struct ETCP_CONN* sender, const uint8_t* data, size_t len) {
if (!bgp || len < sizeof(struct BGP_WITHDRAW_PACKET)) {
return -1;
}
struct BGP_WITHDRAW_PACKET* wp = (struct BGP_WITHDRAW_PACKET*)data;
uint64_t node_id = be64toh(wp->node_id);
uint64_t wd_source = be64toh(wp->wd_source);
struct NODEINFO_Q* nq = route_bgp_get_node(bgp, node_id);
if (nq) {
if (!nq) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "node not found");
return 0;
}
int ret=route_bgp_remove_path_by_hop(nq, wd_source);
if (ret>0) {
if (bgp->instance && bgp->instance->rt) {
route_delete(bgp->instance->rt, nq);
}
if (nq->paths) {
queue_free(nq->paths);
}
// TODO: remove from nodes queue
uint64_t key = htobe64(node_id);
struct ll_entry* entry = queue_find_data_by_index(bgp->nodes, &key, 8);
if (entry) {
queue_remove_data(bgp->nodes, entry);
queue_entry_free(entry);
}
nq->dirty = 1;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Removed node %016llx after WITHDRAW", (unsigned long long)node_id);
route_bgp_broadcast_withdraw(bgp, node_id, wd_source, sender);
}
route_bgp_broadcast_withdraw(bgp, node_id, NULL);
return 0;
}
void route_bgp_send_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn) {
if (!bgp || !conn || !bgp->my_nodeinfo) return;
/**
* @brief Отправка NODEINFO-пакета (всегда отправляем local_node)
* Сигнатура соответствует объявлению в route_bgp.h
*/
void route_bgp_send_nodeinfo(struct NODEINFO_Q* node, struct ETCP_CONN* conn)
{
if (!node || !conn) {
return;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending NODEINFO to %s", conn->log_name);
struct ll_entry* entry = queue_entry_new(0);
if (!entry) return;
size_t nl = node->node.node_name_len;
size_t s4 = node->node.local_v4_sockets;
size_t s6 = node->node.local_v6_sockets;
size_t sub4 = node->node.local_v4_subnets;
size_t sub6 = node->node.local_v6_subnets;
size_t t = node->node.tranzit_nodes;
size_t h = node->node.hop_count;
size_t dyn = nl +
s4 * sizeof(struct NODEINFO_IPV4_SOCKET) +
s6 * sizeof(struct NODEINFO_IPV6_SOCKET) +
sub4 * sizeof(struct NODEINFO_IPV4_SUBNET) +
sub6 * sizeof(struct NODEINFO_IPV6_SUBNET) +
t * 8 + h * 8;
size_t ps = sizeof(struct BGP_NODEINFO_PACKET) + dyn;
uint8_t* p = u_malloc(ps);
if (!p) {
return;
}
entry->dgram = u_malloc(bgp->my_nodeinfo_size);
if (!entry->dgram) {
queue_entry_free(entry);
p[0] = ETCP_ID_ROUTE_ENTRY;
p[1] = ROUTE_SUBCMD_NODEINFO;
memcpy(p + 2, &node->node, sizeof(struct NODEINFO));
uint8_t* ds = (uint8_t*)&node->node + sizeof(struct NODEINFO);
memcpy(p + sizeof(struct BGP_NODEINFO_PACKET), ds, dyn);
struct ll_entry* e = queue_entry_new(0);
if (!e) {
u_free(p);
return;
}
memcpy(entry->dgram, bgp->my_nodeinfo, bgp->my_nodeinfo_size);
entry->len = bgp->my_nodeinfo_size;
etcp_send(conn, entry);
e->dgram = p;
e->len = ps;
etcp_send(conn, e);
}
void route_bgp_broadcast_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* exclude) {
if (!bgp) return;
if (!bgp) {
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "Broadcasting NODEINFO");
struct ll_entry* e = bgp->senders_list ? bgp->senders_list->head : NULL;
while (e) {
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)e->data;
if (item->conn && item->conn != exclude) {
route_bgp_send_nodeinfo(bgp, item->conn);
route_bgp_send_nodeinfo(bgp->local_node, item->conn);
}
e = e->next;
}
}
void route_bgp_send_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id) {
if (!bgp) return;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sending WITHDRAW for node %016llx", (unsigned long long)node_id);
}

92
src/route_bgp.h

@ -35,7 +35,8 @@ struct BGP_NODEINFO_PACKET {
struct BGP_WITHDRAW_PACKET {
uint8_t cmd;
uint8_t subcmd;
uint64_t node_id;
uint64_t node_id; // удаляемый узел (который стал недоступен)
uint64_t wd_source; // узел который инициировал withdraw (при удалении он должен быть в hoplist или = current node_id)
} __attribute__((packed));
/**
@ -53,27 +54,96 @@ struct ROUTE_BGP_CONN_ITEM {
struct ROUTE_BGP {
struct UTUN_INSTANCE* instance;
struct BGP_NODEINFO_PACKET* my_nodeinfo; // собранный пакет для отправки
uint16_t my_nodeinfo_size;
struct ll_queue* senders_list; // список активных соединений
struct ll_queue* nodes; // NODEINFO_Q с hash-таблицей по node_id
struct ll_queue* senders_list;
struct ll_queue* nodes;
struct NODEINFO_Q* local_node;
};
/**
* @brief Инициализирует модуль BGP маршрутизации.
*
* Создает очереди, local_node из подсетей конфига, привязывает к ETCP_ID_ROUTE_ENTRY,
* устанавливает коллбеки new_conn для on_up/on_down.
*
* @param instance экземпляр utun с node_id и конфигом
* @return ROUTE_BGP или NULL при ошибке
*/
struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance);
/**
* @brief Освобождает ресурсы BGP (очереди, local_node, снимает привязку ETCP).
*
* @param instance экземпляр utun
*/
void route_bgp_destroy(struct UTUN_INSTANCE* instance);
/**
* @brief Добавляет conn в senders_list (если нет), отправляет запрос таблицы (nodeinfo).
*
* Вызывается при ETCP on_up.
*/
void route_bgp_new_conn(struct ETCP_CONN* conn);
/**
* @brief Удаляет conn из senders_list, очищает paths во всех nodes, отправляет withdraw если node unreachable.
*
* Вызывается при ETCP on_down.
*/
void route_bgp_remove_conn(struct ETCP_CONN* conn);
/* Новые функции для работы с NODEINFO */
int route_bgp_process_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* from,
const uint8_t* data, size_t len);
int route_bgp_process_withdraw(struct ROUTE_BGP* bgp, const uint8_t* data, size_t len);
void route_bgp_send_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn);
/**
* @brief Обрабатывает пакет NODEINFO.
*
* Проверка версии, обновление или создание NODEINFO_Q, добавление пути,
* вставка в роутинг, broadcast если не max hops.
*
* @return 0 при успехе
*/
int route_bgp_process_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* from, const uint8_t* data, size_t len);
/**
* @brief Обрабатывает WITHDRAW.
*
* Удаляет node из роутинга и nodes, broadcast withdraw.
*
* @return 0 при успехе
*/
int route_bgp_process_withdraw(struct ROUTE_BGP* bgp, struct ETCP_CONN* sender, const uint8_t* data, size_t len);
/**
* @brief Отправляет NODEINFO пакет одному conn (всегда local_node).
*/
void route_bgp_send_nodeinfo(struct NODEINFO_Q* node, struct ETCP_CONN* conn);
/**
* @brief Рассылает local_node NODEINFO всем senders_list кроме exclude.
*/
void route_bgp_broadcast_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* exclude);
/**
* @brief Отправляет WITHDRAW для node_id (вызывает broadcast_withdraw).
*/
void route_bgp_send_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id);
/**
* @brief Поиск NODEINFO_Q по node_id через hash в nodes queue.
*
* @return node или NULL
*/
struct NODEINFO_Q* route_bgp_get_node(struct ROUTE_BGP* bgp, uint64_t node_id);
int route_bgp_add_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn);
/**
* @brief Добавляет путь (conn) в paths узла.
*
* @return 0 при успехе
*/
int route_bgp_add_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn, uint64_t* hop_list, uint8_t hop_count);
/**
* @brief Удаляет conn из paths узла.
*
* @return 1 если путей не осталось (unreachable)
*/
int route_bgp_remove_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn);
#endif // ROUTE_BGP_H

31
src/route_bgp.txt

@ -1,9 +1,26 @@
Ключевые изменения в понимании
tranzit_nodes — это динамический список лучших транзитных узлов для данного node.
При conn down:
Находим узел, связанный с этим соединением.
Удаляем конкретный путь (этот транзитный узел) из списка tranzit_nodes.
Если после удаления tranzit_nodes стало пусто (нет активных путей) → узел считается недоступным → route_delete() + отправка WITHDRAW.
При получении NODEINFO — добавляем информацию о транзитных узлах (их может быть несколько).
При получении WITHDRAW — удаляем узел/маршруты и распространяем дальше.
paths
route_bgp_process_nodeinfo(bgp, from_conn, data, entry->len):
проверяет текущую версию nodeinfo, если совпадает - только bgp_update local nodelist
если версия новая или нет узла - spread:
bgp_update local nodelist
realloc: добавляет next hop: hoplist += prev_node_id, hop_count++
bgp_spread
1. функция распространения маршрута
bgp_spread(struct ROUTE_BGP bgp, struct NODEINFO* n)
send to:
- все подключения, если не найден uid подключения в hoplist
bgp_update local nodelist:
- обновляем саму node
- удалеям conn где lash hop=prev_node_id
- добавляем новый conn с новым hoplist
2. withdraw:
bgp_withdraw(struct ROUTE_BGP bgp, uint64_t node_to_del, uint64_t wd_source) - wd_source это узел который захотел withdraw.
- находим у себя node to del. удаляем если в hoplist найден wd_node (или мы = wd_node)
если удалили - распространяем по всем линкам с этими же аргументами

6
src/route_lib.c

@ -138,7 +138,7 @@ void route_table_destroy(struct ROUTE_TABLE *table) {
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_table_destroy: count=%zu", table->count);
// v_node_info — внешний объект (BGP_NODEINFO_Q), память им не управляем
// v_node_info — внешний объект (NODEINFO_Q), память им не управляем
u_free(table->dynamic_subnets);
u_free(table->local_subnets);
u_free(table->entries);
@ -147,7 +147,7 @@ void route_table_destroy(struct ROUTE_TABLE *table) {
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routing table destroyed");
}
bool route_insert(struct ROUTE_TABLE *table, struct BGP_NODEINFO_Q *node) {
bool route_insert(struct ROUTE_TABLE *table, struct NODEINFO_Q *node) {
if (!table || !node) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_insert: invalid arguments");
return false;
@ -218,7 +218,7 @@ bool route_insert(struct ROUTE_TABLE *table, struct BGP_NODEINFO_Q *node) {
return true;
}
void route_delete(struct ROUTE_TABLE *table, struct BGP_NODEINFO_Q *node) {
void route_delete(struct ROUTE_TABLE *table, struct NODEINFO_Q *node) {
if (!table || !node) return;
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_delete: removing all routes for node_info=%p", (void*)node);

7
src/route_lib.h

@ -10,6 +10,7 @@
struct ETCP_CONNECTIONS;
struct ROUTE_TABLE;
struct ROUTE_ENTRY;
struct NODEINFO_Q;
/**
* @brief Флаги узла
@ -28,7 +29,7 @@ typedef enum {
struct ROUTE_ENTRY {
uint32_t network; // Сетевой адрес (big-endian)
uint8_t prefix_length; // Длина префикса подсети
struct BGP_NODEINFO_Q* v_node_info; // узел владелец этих маршрутов. null если - локальный маршрут.
struct NODEINFO_Q* v_node_info; // узел владелец этих маршрутов. null если - локальный маршрут.
};
/**
@ -73,7 +74,7 @@ void route_table_destroy(struct ROUTE_TABLE *table);
*
* @return true если вставка/обновление успешно
*/
bool route_insert(struct ROUTE_TABLE *table, struct BGP_NODEINFO_Q *node);
bool route_insert(struct ROUTE_TABLE *table, struct NODEINFO_Q *node);
/**
* @brief Удаляет все записи из таблицы маршрутизации для указанного узла
@ -81,7 +82,7 @@ bool route_insert(struct ROUTE_TABLE *table, struct BGP_NODEINFO_Q *node);
* @param table Указатель на таблицу маршрутизации
* @param node узел, все маршруты которого нужно удалить
*/
void route_delete(struct ROUTE_TABLE *table, struct BGP_NODEINFO_Q *node);
void route_delete(struct ROUTE_TABLE *table, struct NODEINFO_Q *node);
/**
* @brief Выполняет поиск маршрута для заданного IP-адреса

165
src/route_node.c

@ -12,103 +12,7 @@
#include "route_bgp.h"
#include "etcp_debug.h"
// Build MY_NODEINFO packet for this instance
int route_bgp_build_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BGP* bgp) {
if (!instance || !bgp) return -1;
// Count IPv4 sockets
int v4_socket_count = 0;
struct ETCP_SOCKET* sock = instance->etcp_sockets;
while (sock) {
if (sock->local_addr.ss_family == AF_INET) {
v4_socket_count++;
}
sock = sock->next;
}
// Count IPv4 routes (my_subnets)
int v4_route_count = 0;
struct CFG_ROUTE_ENTRY* subnet = instance->config->my_subnets;
while (subnet) {
if (subnet->ip.family == AF_INET) {
v4_route_count++;
}
subnet = subnet->next;
}
// Get name length
size_t name_len = strlen(instance->name);
// Calculate total size
size_t pkt_size = sizeof(struct BGP_NODEINFO_PACKET)
+ name_len
+ v4_socket_count * sizeof(struct NODEINFO_IPV4_SOCKET)
+ v4_route_count * sizeof(struct NODEINFO_IPV4_SUBNET);
// Allocate
struct BGP_NODEINFO_PACKET* pkt = u_malloc(pkt_size);
if (!pkt) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_build_my_nodeinfo: malloc failed");
return -1;
}
// Fill fixed fields
pkt->cmd = ETCP_ID_ROUTE_ENTRY;
pkt->subcmd = ROUTE_SUBCMD_NODEINFO;
pkt->node.node_id = htobe64(instance->node_id);
pkt->node.ver = bgp->my_nodeinfo ? bgp->my_nodeinfo->node.ver + 1 : 1;
memcpy(pkt->node.public_key, instance->my_keys.public_key, SC_PUBKEY_SIZE);
pkt->node.node_name_len = (uint8_t)name_len;
pkt->node.local_v4_sockets = (uint8_t)v4_socket_count;
pkt->node.local_v6_sockets = 0;
pkt->node.local_v4_subnets = (uint8_t)v4_route_count;
pkt->node.local_v6_subnets = 0;
pkt->node.tranzit_nodes = 0;
pkt->node.hop_count = 0;
// Fill variable data
uint8_t* ptr = (uint8_t*)pkt + sizeof(struct BGP_NODEINFO_PACKET);
// Name
if (name_len > 0) {
memcpy(ptr, instance->name, name_len);
ptr += name_len;
}
// IPv4 sockets
struct NODEINFO_IPV4_SOCKET* sock_arr = (struct NODEINFO_IPV4_SOCKET*)ptr;
sock = instance->etcp_sockets;
while (sock) {
if (sock->local_addr.ss_family == AF_INET) {
struct sockaddr_in* in = (struct sockaddr_in*)&sock->local_addr;
memcpy(sock_arr->addr, &in->sin_addr, 4);
sock_arr->port = in->sin_port;
sock_arr++;
}
sock = sock->next;
}
ptr = (uint8_t*)sock_arr;
// IPv4 routes
struct NODEINFO_IPV4_SUBNET* route_arr = (struct NODEINFO_IPV4_SUBNET*)ptr;
subnet = instance->config->my_subnets;
while (subnet) {
if (subnet->ip.family == AF_INET) {
memcpy(route_arr->addr, &subnet->ip.addr.v4, 4);
route_arr->prefix_length = subnet->netmask;
route_arr++;
}
subnet = subnet->next;
}
bgp->my_nodeinfo = pkt;
bgp->my_nodeinfo_size = pkt_size;
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Built my_nodeinfo: name='%s', v4_sockets=%d, v4_routes=%d",
instance->name, v4_socket_count, v4_route_count);
return 0;
}
/**
* @brief Получает указатель на массив IPv4-подсетей узла (без malloc/копирования).
@ -153,3 +57,72 @@ int get_node_routes(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SUBNET *
(unsigned)info->local_v4_subnets, (void*)node);
return (int)info->local_v4_subnets;
}
int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BGP* bgp) {
if (!instance || !bgp) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_update_my_nodeinfo: invalid args");
return -1;
}
if (!bgp->local_node) {
int vc = 0;
struct CFG_ROUTE_ENTRY* s = instance->config->my_subnets;
while (s) {
if (s->ip.family == AF_INET) vc++;
s = s->next;
}
size_t d = vc * sizeof(struct NODEINFO_IPV4_SUBNET);
bgp->local_node = u_calloc(1, sizeof(struct NODEINFO_Q) + d);
if (!bgp->local_node) return -1;
bgp->local_node->node.node_id = htobe64(instance->node_id);
bgp->local_node->node.hop_count = 0;
bgp->local_node->node.ver = 1;
bgp->local_node->dirty = 1;
bgp->local_node->last_ver = 1;
bgp->local_node->node.local_v4_subnets = vc;
}
int vc = 0;
struct CFG_ROUTE_ENTRY* s = instance->config->my_subnets;
while (s) {
if (s->ip.family == AF_INET) vc++;
s = s->next;
}
int changed = (vc != (int)bgp->local_node->node.local_v4_subnets);
if (!changed && vc > 0) {
uint8_t* current = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO);
struct NODEINFO_IPV4_SUBNET* ra = (struct NODEINFO_IPV4_SUBNET*)current;
s = instance->config->my_subnets;
bool same = true;
while (s) {
if (s->ip.family == AF_INET) {
if (memcmp(ra->addr, &s->ip.addr.v4, 4) != 0 || ra->prefix_length != s->netmask) {
same = false;
break;
}
ra++;
}
s = s->next;
}
changed = !same;
}
if (changed) {
uint8_t oldv = bgp->local_node->node.ver;
bgp->local_node->node.ver = ((oldv + 1) % 255) + 1;
bgp->local_node->node.local_v4_subnets = vc;
bgp->local_node->dirty = 1;
bgp->local_node->last_ver = bgp->local_node->node.ver;
uint8_t* dp = (uint8_t*)&bgp->local_node->node + sizeof(struct NODEINFO);
struct NODEINFO_IPV4_SUBNET* ra = (struct NODEINFO_IPV4_SUBNET*)dp;
s = instance->config->my_subnets;
while (s) {
if (s->ip.family == AF_INET) {
memcpy(ra->addr, &s->ip.addr.v4, 4);
ra->prefix_length = s->netmask;
ra++;
}
s = s->next;
}
} else {
bgp->local_node->last_ver = bgp->local_node->node.ver;
}
return vc;
}

20
src/route_node.h

@ -2,9 +2,12 @@
#define ROUTE_NODE_H
#include <stdint.h>
#include <stddef.h>
#include "../lib/ll_queue.h"
#include "secure_channel.h"
struct ROUTE_BGP;
/**
* @brief Информация о узле
*/
@ -48,12 +51,19 @@ struct NODEINFO_TRANZIT_NODE {
uint16_t link_q; // меньше - лучше (потери + 1/BW)
} __attribute__((packed));
struct NODEINFO_PATH {
struct ll_entry ll;
struct ETCP_CONN* conn;
uint8_t hop_count; // hop list: маршрут этого path
} __attribute__((packed));
struct NODEINFO_Q {
struct ll_entry ll;
struct NODEINFO node; // KEY = node_id (offset=0 len=8)
struct ll_queue* paths; // список ETCP_CONN* через которые узел доступен
uint32_t last_ver; // последняя обработанная версия NODEINFO
struct ll_queue* paths;
uint8_t dirty;
uint8_t last_ver;
struct NODEINFO node; // Всегда в конце структуры - динамически расширяемый блок
} __attribute__((packed));
@ -63,10 +73,10 @@ struct NODEINFO_Q {
* Собирает данные из локальных структур и упаковывает к структуру (оптимизированную для передачи по сети)
*
* @param instance Указатель на UTUN_INSTANCE (с него сбоираем все данные)
* @param bgp здесь будет обновлен struct NODEINFO
* @param bgp Указатель на ROUTE_BGP (для доступа к my_nodeinfo и instance)
* @return количество подсетей (>= 0) или -1 при ошибке
*/
int route_bgp_build_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BGP* bgp);
int route_bgp_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BGP* bgp);
/**
* @brief Получает указатель на массив IPv4-подсетей узла (без malloc/копирования).

23
src/utun_instance.c

@ -75,28 +75,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
}
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Routing module created");
// Add local subnets from config as static routes
struct CFG_ROUTE_ENTRY* subnet = config->my_subnets;
while (subnet) {
struct ROUTE_ENTRY entry = {0};
entry.network = ntohl(subnet->ip.addr.v4.s_addr);
entry.prefix_length = subnet->netmask;
entry.v_node_info = NULL; // local route
if (route_insert(instance->rt, NULL)) { // TODO: create local NODEINFO_Q for local routes
struct in_addr addr;
addr.s_addr = htonl(entry.network);
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Added local route: %s/%d",
ip_to_str(&addr, AF_INET).str, entry.prefix_length);
} else {
struct in_addr addr;
addr.s_addr = htonl(entry.network);
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Failed to add local route: %s/%d (skipping)",
ip_to_str(&addr, AF_INET).str, entry.prefix_length);
}
subnet = subnet->next;
}
if(instance->bgp&&instance->bgp->local_node){if(route_insert(instance->rt,instance->bgp->local_node)){DEBUG_INFO(DEBUG_CATEGORY_ROUTING,"Added local routes from local_node");}else{DEBUG_WARN(DEBUG_CATEGORY_ROUTING,"Failed to add local routes");}}
// Initialize TUN device if enabled
if (g_tun_init_enabled) {

4
tests/Makefile.am

@ -212,8 +212,8 @@ test_config_debug_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_config_debug_LDADD = $(top_builddir)/src/utun-config_parser.o $(COMMON_LIBS)
test_route_lib_SOURCES = test_route_lib.c
test_route_lib_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_route_lib_LDADD = $(top_builddir)/src/utun-route_lib.o $(top_builddir)/src/utun-etcp_debug.o $(COMMON_LIBS)
test_route_lib_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/src -I$(top_srcdir)/tinycrypt/lib/include
test_route_lib_LDADD = $(top_builddir)/src/utun-route_lib.o $(top_builddir)/src/utun-route_node.o $(top_builddir)/src/utun-etcp_debug.o $(COMMON_LIBS)
test_bgp_route_exchange_SOURCES = test_bgp_route_exchange.c
test_bgp_route_exchange_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_srcdir)/tinycrypt/lib/include -I$(top_srcdir)/tinycrypt/lib/source

31
tests/test_bgp_route_exchange.c

@ -196,20 +196,16 @@ static void print_routing_table(struct UTUN_INSTANCE* inst, const char* name) {
addr.s_addr = htonl(entry->network);
inet_ntop(AF_INET, &addr, network_str, sizeof(network_str));
const char* type_str = entry->conn_list ? "LEARNED" : "LOCAL";
const char* type_str = entry->v_node_info ? "LEARNED" : "LOCAL";
uint64_t node_id = 0;
uint8_t hop_count = 0;
if (entry->conn_list) {
node_id = entry->conn_list->node_id;
if (entry->conn_list->preferred_conn < entry->conn_list->conninfo_count) {
hop_count = entry->conn_list->conn_info[entry->conn_list->preferred_conn].hop_count;
}
if (entry->v_node_info) {
node_id = be64toh(entry->v_node_info->node.node_id);
}
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " Route %zu: %s/%d [%s] node_id=%016llX hops=%d",
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, " Route %zu: %s/%d [%s] node_id=%016llX",
i + 1, network_str, entry->prefix_length, type_str,
(unsigned long long)node_id, hop_count);
(unsigned long long)node_id);
}
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "=====================================\n");
}
@ -222,12 +218,13 @@ static int check_learned_route(struct UTUN_INSTANCE* inst, uint32_t network,
return 0;
}
uint64_t expected_be = htobe64(expected_node_id);
for (size_t i = 0; i < inst->rt->count; i++) {
struct ROUTE_ENTRY* entry = &inst->rt->entries[i];
if (entry->network == network &&
entry->prefix_length == prefix_len &&
entry->conn_list != NULL &&
entry->conn_list->node_id == expected_node_id) {
entry->v_node_info != NULL &&
entry->v_node_info->node.node_id == expected_be) {
return 1;
}
}
@ -248,18 +245,18 @@ static int verify_bgp_exchange(void) {
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Checking server learned client's routes...");
// Note: Routes are stored in host byte order, not network byte order
if (!check_learned_route(server_instance, 0xC0A81400, 24, 0x2222222222222222ULL)) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "FAIL: Server missing learned route 192.168.20.0/24");
if (!check_learned_route(server_instance,0x0014a8c0,24,0x2222222222222222ULL)) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING,"FAIL: Server missing learned route 192.168.20.0/24");
success = 0;
} else {
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "PASS: Server has learned route 192.168.20.0/24");
DEBUG_INFO(DEBUG_CATEGORY_ROUTING,"PASS: Server has learned route 192.168.20.0/24");
}
if (!check_learned_route(server_instance, 0xC0A81500, 24, 0x2222222222222222ULL)) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "FAIL: Server missing learned route 192.168.21.0/24");
if (!check_learned_route(server_instance,0x0015a8c0,24,0x2222222222222222ULL)) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING,"FAIL: Server missing learned route 192.168.21.0/24");
success = 0;
} else {
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "PASS: Server has learned route 192.168.21.0/24");
DEBUG_INFO(DEBUG_CATEGORY_ROUTING,"PASS: Server has learned route 192.168.21.0/24");
}
// Check client learned server's routes (192.168.10.0/24, 192.168.11.0/24)

19
tests/test_etcp_two_instances.c

@ -262,6 +262,10 @@ static void cleanup_instance_timers(struct UTUN_INSTANCE* instance, struct UASYN
uasync_cancel_timeout(ua, link->init_timer);
link->init_timer = NULL;
}
if (link->stats_timer) {
uasync_cancel_timeout(ua, link->stats_timer);
link->stats_timer = NULL;
}
link = link->next;
}
conn = conn->next;
@ -297,13 +301,6 @@ int main() {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "UTUN instance ok...");
// Initialize ETCP connections regardless of TUN state (minimal change)
if (init_connections(server_instance) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize server connections");
utun_instance_destroy(server_instance);
return 1;
}
// Initialize instance (TUN is initialized in utun_instance_create if enabled)
if (utun_instance_init(server_instance) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize server instance");
@ -321,14 +318,6 @@ int main() {
return 1;
}
// Initialize ETCP connections regardless of TUN state (minimal change)
if (init_connections(client_instance) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to initialize client connections");
utun_instance_destroy(server_instance);
utun_instance_destroy(client_instance);
return 1;
}
// Initialize instance (TUN is initialized in utun_instance_create if enabled)
if (utun_instance_init(client_instance) < 0) {
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Failed to initialize client instance\n");

4
tests/test_route_lib.c

@ -154,8 +154,8 @@ static void test_performance_1000_nodes(void) {
clock_t start = clock();
for (int i = 0; i < 1000; i++) {
uint32_t sub = 0x0a000000 + (i * 0x01000000); /* different /8 to avoid overlap */
struct NODEINFO_Q* nq = create_test_node(0x1000000ULL + i, 1, sub, 8);
uint32_t sub = 0x0a000000 + (i * 0x100); /* distinct 10.0.x.0/24 to avoid overlap */
struct NODEINFO_Q* nq = create_test_node(0x1000000ULL + i, 1, sub, 24);
route_insert(t, nq);
/* note: nq not freed here (table holds ref to it), freed in test cleanup if needed */
}

Loading…
Cancel
Save