feat: transition to NODEINFO based routing system
- Replaced old BGP_ROUTE_PACKET with NODEINFO packets - Added paths list to NODEINFO_Q for multi-path routing - Implemented process_nodeinfo, process_withdraw, add/remove_path - Updated routing.c to use v_node_info->paths - Fixed type inconsistencies and includes across route_* files - Hash size for nodes queue increased to 256 - Version increment logic in build_my_nodeinfo Branch: feature/nodeinfo-routing
This commit is contained in:
1 parent
5c9e9ba144
commit
a93e34f85f
4 files changed
+342
-7
No files matched your search
+102
-6
@@ -338,10 +338,16 @@ void route_bgp_remove_conn(struct ETCP_CONN* conn) {
|
||||
|
||||
// Remove this connection from all nodes' path lists
|
||||
// and send WITHDRAW if a node becomes unreachable
|
||||
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;
|
||||
route_bgp_remove_path(nq, conn);
|
||||
if (route_bgp_remove_path(nq, conn) == 1) {
|
||||
need_withdraw = true;
|
||||
if (rt) {
|
||||
route_delete(rt, nq);
|
||||
}
|
||||
}
|
||||
node_entry = node_entry->next;
|
||||
}
|
||||
|
||||
@@ -357,6 +363,10 @@ void route_bgp_remove_conn(struct ETCP_CONN* conn) {
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
if (need_withdraw) {
|
||||
route_bgp_send_withdraw(bgp, conn->peer_node_id);
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Connection removed, paths updated");
|
||||
}
|
||||
|
||||
@@ -379,24 +389,110 @@ int route_bgp_add_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn) {
|
||||
}
|
||||
|
||||
int route_bgp_remove_path(struct NODEINFO_Q* nq, struct ETCP_CONN* conn) {
|
||||
if (!nq || !conn) return -1;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "Removed path for node %016llx via conn %s",
|
||||
(unsigned long long)nq->node.node_id, conn->log_name);
|
||||
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) {
|
||||
queue_remove_data(nq->paths, e);
|
||||
queue_entry_free(e);
|
||||
break;
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// If no paths left - node is unreachable
|
||||
if (remaining == 0) {
|
||||
if (nq->paths) {
|
||||
queue_free(nq->paths);
|
||||
nq->paths = NULL;
|
||||
}
|
||||
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;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Processing NODEINFO from %s", from->log_name);
|
||||
|
||||
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)",
|
||||
from->log_name, ni->hop_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct NODEINFO_Q* existing = route_bgp_get_node(bgp, node_id);
|
||||
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)",
|
||||
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;
|
||||
existing->paths = queue_new(bgp->instance->ua, 32, "node_paths");
|
||||
queue_data_put(bgp->nodes, entry);
|
||||
}
|
||||
|
||||
memcpy(&existing->node, ni, sizeof(struct NODEINFO));
|
||||
existing->last_ver = new_ver;
|
||||
|
||||
route_bgp_add_path(existing, from);
|
||||
|
||||
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--; // возвращаем назад
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
struct BGP_WITHDRAW_PACKET* wp = (struct BGP_WITHDRAW_PACKET*)data;
|
||||
uint64_t node_id = be64toh(wp->node_id);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Processing WITHDRAW for node %016llx", (unsigned long long)node_id);
|
||||
|
||||
struct NODEINFO_Q* nq = route_bgp_get_node(bgp, node_id);
|
||||
if (nq) {
|
||||
if (bgp->instance && bgp->instance->rt) {
|
||||
route_delete(bgp->instance->rt, nq);
|
||||
}
|
||||
if (nq->paths) {
|
||||
queue_free(nq->paths);
|
||||
}
|
||||
// TODO: remove from nodes queue
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Removed node %016llx after WITHDRAW", (unsigned long long)node_id);
|
||||
}
|
||||
|
||||
route_bgp_broadcast_withdraw(bgp, node_id, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@
|
||||
#define ROUTE_SUBCMD_WITHDRAW 0x06 // узел стал недоступен
|
||||
|
||||
#define MAX_HOPS 16
|
||||
#define BGP_NODES_HASH_SIZE 64
|
||||
#define BGP_NODES_HASH_SIZE 256
|
||||
|
||||
/**
|
||||
* @brief Пакет с информацией об узле (NODEINFO)
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../lib/ll_queue.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/mem.h"
|
||||
#include "utun_instance.h"
|
||||
#include "etcp.h"
|
||||
#include "config_parser.h"
|
||||
#include "route_node.h"
|
||||
#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/копирования).
|
||||
*
|
||||
* Функция вычисляет смещение внутри динамической части BGP_NODEINFO_Q
|
||||
* и возвращает прямой указатель на массив struct BGP_NODEINFO_IPV4_SUBNET.
|
||||
*
|
||||
* @param node Указатель на BGP_NODEINFO_Q
|
||||
* @param out_subnets [out] сюда будет записан указатель на первый элемент массива
|
||||
* (NULL если подсетей нет)
|
||||
* @return количество подсетей (>= 0) или -1 при ошибке
|
||||
*/
|
||||
int get_node_routes(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SUBNET **out_subnets) {
|
||||
if (!node || !out_subnets) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out_subnets = NULL;
|
||||
|
||||
const struct NODEINFO *info = &node->node;
|
||||
|
||||
if (info->local_v4_subnets == 0) {
|
||||
return 0; // успех, но нет подсетей
|
||||
}
|
||||
|
||||
// Начало динамических полей сразу после фиксированной части NODEINFO
|
||||
const uint8_t *dynamic = (const uint8_t *)&node->node + sizeof(struct NODEINFO);
|
||||
|
||||
// 1. Пропускаем node_name
|
||||
dynamic += info->node_name_len;
|
||||
|
||||
// 2. Пропускаем local_v4_sockets
|
||||
dynamic += info->local_v4_sockets * sizeof(struct NODEINFO_IPV4_SOCKET);
|
||||
|
||||
// 3. Пропускаем local_v6_sockets
|
||||
dynamic += info->local_v6_sockets * sizeof(struct NODEINFO_IPV6_SOCKET);
|
||||
|
||||
// Теперь dynamic указывает точно на начало массива NODEINFO_IPV4_SUBNET
|
||||
*out_subnets = (const struct NODEINFO_IPV4_SUBNET *)dynamic;
|
||||
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "get_node_routes: returned %u IPv4 subnets from node %p",
|
||||
(unsigned)info->local_v4_subnets, (void*)node);
|
||||
return (int)info->local_v4_subnets;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
#ifndef ROUTE_NODE_H
|
||||
#define ROUTE_NODE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../lib/ll_queue.h"
|
||||
#include "secure_channel.h"
|
||||
|
||||
/**
|
||||
* @brief Информация о узле
|
||||
*/
|
||||
struct NODEINFO {
|
||||
uint64_t node_id; // (big-endian)
|
||||
uint8_t ver; // версия пакета (циклический счетчик чтобы быстро сравнивать с локальной копией - были ли обновления)
|
||||
uint8_t public_key[SC_PUBKEY_SIZE]; // node pubkey
|
||||
uint8_t node_name_len; // размер в байтах (без null терминации)
|
||||
uint8_t local_v4_sockets; // NODEINFO_IPV4_SOCKET число локальных ipv4 сокетов узла (для direct incoming connections)
|
||||
uint8_t local_v6_sockets; // NODEINFO_IPV6_SOCKET число локальных ipv6 сокетов узла (для direct incoming connections) (пока 0)
|
||||
uint8_t local_v4_subnets; // NODEINFO_IPV4_SUBNET число локальных ipv4 подсетей узла
|
||||
uint8_t local_v6_subnets; // NODEINFO_IPV6_SUBNET число локальных ipv6 подсетей узла (пока 0)
|
||||
uint8_t tranzit_nodes; // NODEINFO_TRANZIT_NODE лучшие транзитные узлы для этой ноды (минимальный пинг / лучшее качество каналов. выбирается/обновляется узлом)
|
||||
uint8_t hop_count; // hop list: маршрут по которому распространялся этот NODEINFO_PACKET. для избежания зацикливаний при распространении по узлам. каждый узел при передаче инкрементирует и добавляет в конец свой node_id.
|
||||
// далее идут динамическип поля по порядку следования полей в этой структуре: char node_name[node_name_len], сокеты, роуты, tranzit nodes, hop list (блоки описаны структурами ниже). hop list - это массив node_id[hop_count].
|
||||
} __attribute__((packed));
|
||||
|
||||
struct NODEINFO_IPV4_SOCKET {
|
||||
uint8_t addr[4];// network byte order
|
||||
uint16_t port;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct NODEINFO_IPV6_SOCKET {
|
||||
uint8_t addr[16];
|
||||
uint16_t port;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct NODEINFO_IPV4_SUBNET {
|
||||
uint8_t addr[4];// network byte order
|
||||
uint8_t prefix_length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct NODEINFO_IPV6_SUBNET {
|
||||
uint8_t addr[16];
|
||||
uint8_t prefix_length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct NODEINFO_TRANZIT_NODE {
|
||||
uint64_t node_id; // (big-endian)
|
||||
uint16_t rtt; // x0.1 ms (измеренный удаленным узлом RTT до транзитного узла)
|
||||
uint16_t link_q; // меньше - лучше (потери + 1/BW)
|
||||
} __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
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* @brief Создаёт/обновляет nodeinfo для собственного узла
|
||||
*
|
||||
* Собирает данные из локальных структур и упаковывает к структуру (оптимизированную для передачи по сети)
|
||||
*
|
||||
* @param instance Указатель на UTUN_INSTANCE (с него сбоираем все данные)
|
||||
* @param bgp здесь будет обновлен struct NODEINFO
|
||||
* @return количество подсетей (>= 0) или -1 при ошибке
|
||||
*/
|
||||
int route_bgp_build_my_nodeinfo(struct UTUN_INSTANCE* instance, struct ROUTE_BGP* bgp);
|
||||
|
||||
/**
|
||||
* @brief Получает указатель на массив IPv4-подсетей узла (без malloc/копирования).
|
||||
*
|
||||
* Функция вычисляет смещение внутри динамической части NODEINFO_Q
|
||||
* и возвращает прямой указатель на массив struct NODEINFO_IPV4_SUBNET.
|
||||
*
|
||||
* @param node Указатель на NODEINFO_Q
|
||||
* @param out_subnets [out] сюда будет записан указатель на первый элемент массива
|
||||
* (NULL если подсетей нет)
|
||||
* @return количество подсетей (>= 0) или -1 при ошибке
|
||||
*/
|
||||
int get_node_routes(struct NODEINFO_Q *node, const struct NODEINFO_IPV4_SUBNET **out_subnets);
|
||||
|
||||
#endif // ROUTE_NODE_H
|
||||
Reference in new issue
Block a user