Browse Source

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
feature/nodeinfo-routing
Evgeny 5 days ago
parent
commit
a93e34f85f
  1. 108
      src/route_bgp.c
  2. 2
      src/route_bgp.h
  3. 155
      src/route_node.c
  4. 84
      src/route_node.h

108
src/route_bgp.c

@ -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;
}

2
src/route_bgp.h

@ -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)

155
src/route_node.c

@ -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;
}

84
src/route_node.h

@ -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
Loading…
Cancel
Save