You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
5.1 KiB
133 lines
5.1 KiB
#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" |
|
|
|
|
|
|
|
/** |
|
* @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; |
|
} |
|
|
|
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; |
|
} |
|
size_t name_len = 0; |
|
if (instance->name[0]) { |
|
name_len = strlen(instance->name); |
|
if (name_len > 63) name_len = 63; |
|
} |
|
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 dyn = name_len + vc * sizeof(struct NODEINFO_IPV4_SUBNET); |
|
if (!bgp->local_node) { |
|
bgp->local_node = u_calloc(1, sizeof(struct NODEINFO_Q) + dyn); |
|
if (!bgp->local_node) return -1; |
|
bgp->local_node->node.node_id = 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; |
|
bgp->local_node->node.node_name_len = name_len; |
|
} |
|
int changed = (vc != (int)bgp->local_node->node.local_v4_subnets) || (name_len != bgp->local_node->node.node_name_len); |
|
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->node.node_name_len = name_len; |
|
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); |
|
if (name_len) { |
|
memcpy(dp, instance->name, name_len); |
|
dp += name_len; |
|
} |
|
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; |
|
}
|
|
|