From 9f13cf54599d668f11f333256164dacdf45d39f0 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Mon, 30 Mar 2026 18:26:56 +0300 Subject: [PATCH] route redesign + tests --- lib/ll_queue.h | 20 +- src/route_bgp.c | 406 ++++++++++++++++++++++---------- src/route_bgp.h | 92 +++++++- src/route_bgp.txt | 31 ++- src/route_lib.c | 6 +- src/route_lib.h | 7 +- src/route_node.c | 165 ++++++------- src/route_node.h | 24 +- src/utun_instance.c | 23 +- tests/Makefile.am | 4 +- tests/test_bgp_route_exchange.c | 31 ++- tests/test_etcp_two_instances.c | 19 +- tests/test_route_lib.c | 4 +- 13 files changed, 516 insertions(+), 316 deletions(-) diff --git a/lib/ll_queue.h b/lib/ll_queue.h index c9c9303..882ce6a 100644 --- a/lib/ll_queue.h +++ b/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 очередь diff --git a/src/route_bgp.c b/src/route_bgp.c index 9c51ad7..0930f25 100644 --- a/src/route_bgp.c +++ b/src/route_bgp.c @@ -2,11 +2,9 @@ * @file route_bgp.c * @brief BGP-like обмен маршрутами — исправленная версия под новую route_lib */ - #include #include #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); @@ -108,7 +106,7 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* struct UTUN_INSTANCE* instance = from_conn->instance; if (!instance || !instance->bgp) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_receive_cbk: invalid instance/bgp"); - queue_dgram_free(entry); + queue_dgram_free(entry); queue_entry_free(entry); return; } @@ -119,21 +117,21 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* uint8_t subcmd = data[1]; if (cmd != ETCP_ID_ROUTE_ENTRY) { - queue_dgram_free(entry); + queue_dgram_free(entry); queue_entry_free(entry); return; } - DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received BGP packet from %s, subcmd=%d, len=%zu", + DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received BGP packet from %s, subcmd=%d, len=%zu", from_conn->log_name, subcmd, entry->len); 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,11 +210,28 @@ 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); // Устанавливаем callback для новых ETCP соединений @@ -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) { @@ -326,13 +350,14 @@ void route_bgp_remove_conn(struct ETCP_CONN* conn) { } e = e->next; } - + if (!found_in_list) { DEBUG_WARN(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: conn already removed or not in list, skipping"); 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,8 +487,7 @@ 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", + 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); // If no paths left - node is unreachable @@ -415,20 +498,22 @@ 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; +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; + } struct BGP_NODEINFO_PACKET* pkt = (struct BGP_NODEINFO_PACKET*)data; struct NODEINFO* ni = &pkt->node; uint64_t node_id = be64toh(ni->node_id); if (ni->hop_count >= MAX_HOPS) { - DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO from %s dropped: too many hops (%d)", + DEBUG_WARN(DEBUG_CATEGORY_BGP, "NODEINFO from %s dropped: too many hops (%d)", from->log_name, ni->hop_count); return -1; } @@ -437,97 +522,158 @@ int route_bgp_process_nodeinfo(struct ROUTE_BGP* bgp, struct ETCP_CONN* from, uint8_t new_ver = ni->ver; if (existing && existing->last_ver >= new_ver) { - DEBUG_TRACE(DEBUG_CATEGORY_BGP, "NODEINFO from %s ignored (old ver %d <= %d)", + DEBUG_TRACE(DEBUG_CATEGORY_BGP, "NODEINFO from %s ignored (old ver %d <= %d)", from->log_name, new_ver, existing->last_ver); return 0; } 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)", - from->log_name, (unsigned long long)node_id, new_ver, + 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; - - entry->dgram = u_malloc(bgp->my_nodeinfo_size); - if (!entry->dgram) { - queue_entry_free(entry); + + 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; + } + + 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); -} diff --git a/src/route_bgp.h b/src/route_bgp.h index 24766e8..a644fc4 100644 --- a/src/route_bgp.h +++ b/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 diff --git a/src/route_bgp.txt b/src/route_bgp.txt index 57a0c97..a6142af 100644 --- a/src/route_bgp.txt +++ b/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) + если удалили - распространяем по всем линкам с этими же аргументами diff --git a/src/route_lib.c b/src/route_lib.c index 389b908..8e4ccf9 100644 --- a/src/route_lib.c +++ b/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); diff --git a/src/route_lib.h b/src/route_lib.h index 26808f7..3c27687 100644 --- a/src/route_lib.h +++ b/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-адреса diff --git a/src/route_node.c b/src/route_node.c index f85c4fe..efba21a 100644 --- a/src/route_node.c +++ b/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; +} diff --git a/src/route_node.h b/src/route_node.h index 7192eff..6f59368 100644 --- a/src/route_node.h +++ b/src/route_node.h @@ -2,9 +2,12 @@ #define ROUTE_NODE_H #include +#include #include "../lib/ll_queue.h" #include "secure_channel.h" +struct ROUTE_BGP; + /** * @brief Информация о узле */ @@ -48,25 +51,32 @@ 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)); /** * @brief Создаёт/обновляет nodeinfo для собственного узла - * + * * Собирает данные из локальных структур и упаковывает к структуру (оптимизированную для передачи по сети) - * + * * @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/копирования). diff --git a/src/utun_instance.c b/src/utun_instance.c index a8e8cb1..1313b72 100644 --- a/src/utun_instance.c +++ b/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) { diff --git a/tests/Makefile.am b/tests/Makefile.am index 8074ed2..db3b3fe 100644 --- a/tests/Makefile.am +++ b/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 diff --git a/tests/test_bgp_route_exchange.c b/tests/test_bgp_route_exchange.c index 63043cb..a033eb8 100644 --- a/tests/test_bgp_route_exchange.c +++ b/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) diff --git a/tests/test_etcp_two_instances.c b/tests/test_etcp_two_instances.c index 9789916..bbd0df3 100644 --- a/tests/test_etcp_two_instances.c +++ b/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"); diff --git a/tests/test_route_lib.c b/tests/test_route_lib.c index d9f73af..8dd2893 100644 --- a/tests/test_route_lib.c +++ b/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 */ }