Browse Source

routing базово работает

nodeinfo-routing-update
jeka 4 weeks ago
parent
commit
473190281a
  1. 9
      lib/platform_compat.h
  2. 35
      src/route_bgp.c
  3. 4
      src/route_lib.c
  4. 13
      src/routing.c
  5. 4
      src/utun_instance.c
  6. 6
      tests/test_bgp_route_exchange.c
  7. 12
      tests/test_route_lib.c

9
lib/platform_compat.h

@ -14,6 +14,15 @@
#include <fcntl.h> #include <fcntl.h>
#include <stdint.h> #include <stdint.h>
// Byte order conversion functions
#ifdef _WIN32
#include <stdlib.h>
#define htobe64(x) _byteswap_uint64(x)
#define be64toh(x) _byteswap_uint64(x)
#elif defined(__linux__)
#include <endian.h>
#endif
// POSIX functions missing on Windows // POSIX functions missing on Windows
#define strcasecmp _stricmp #define strcasecmp _stricmp
#define strncasecmp _strnicmp #define strncasecmp _strnicmp

35
src/route_bgp.c

@ -55,18 +55,18 @@ static void format_ip(uint32_t ip, char* buffer) {
snprintf(buffer, 16, "%u.%u.%u.%u", b[3], b[2], b[1], b[0]); snprintf(buffer, 16, "%u.%u.%u.%u", b[3], b[2], b[1], b[0]);
} }
typedef struct { struct BGP_WITHDRAW_PACKET {
uint8_t cmd; uint8_t cmd;
uint8_t subcmd; uint8_t subcmd;
uint64_t node_id; uint64_t node_id;
} BGP_WITHDRAW_PACKET __attribute__((packed)); } __attribute__((packed));
typedef struct { struct BGP_REROUTE_PACKET {
uint8_t cmd; uint8_t cmd;
uint8_t subcmd; uint8_t subcmd;
uint64_t old_node_id; uint64_t old_node_id;
struct ROUTE_PEER_INFO peer_info; struct ROUTE_PEER_INFO peer_info;
} BGP_REROUTE_PACKET __attribute__((packed)); } __attribute__((packed));
/** /**
* @brief Рассылает маршрут всем соединениям (кроме exclude) * @brief Рассылает маршрут всем соединениям (кроме exclude)
@ -288,6 +288,8 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
return; return;
} }
struct ROUTE_BGP* bgp = instance->bgp;
struct BGP_ENTRY_PACKET* pkt = (struct BGP_ENTRY_PACKET*)entry->dgram; struct BGP_ENTRY_PACKET* pkt = (struct BGP_ENTRY_PACKET*)entry->dgram;
// Проверяем команду // Проверяем команду
@ -309,17 +311,17 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
uint64_t old_node_id = 0; uint64_t old_node_id = 0;
struct ROUTE_PEER_INFO *peer_info; struct ROUTE_PEER_INFO *peer_info;
if (pkt->subcmd == ROUTE_SUBCMD_ENTRY_REROUTE) { if (pkt->subcmd == ROUTE_SUBCMD_ENTRY_REROUTE) {
if (entry->len < sizeof(BGP_REROUTE_PACKET)) { if (entry->len < sizeof(struct BGP_REROUTE_PACKET)) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid REROUTE packet size"); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid REROUTE packet size");
queue_dgram_free(entry); queue_dgram_free(entry);
queue_entry_free(entry); queue_entry_free(entry);
return; return;
} }
BGP_REROUTE_PACKET *reroute_pkt = (BGP_REROUTE_PACKET*)pkt; struct BGP_REROUTE_PACKET *reroute_pkt = (struct BGP_REROUTE_PACKET*)pkt;
old_node_id = be64toh(reroute_pkt->old_node_id); old_node_id = be64toh(reroute_pkt->old_node_id);
peer_info = &reroute_pkt->peer_info; peer_info = &reroute_pkt->peer_info;
} else { } else {
if (entry->len < sizeof(BGP_ENTRY_PACKET)) { if (entry->len < sizeof(struct BGP_ENTRY_PACKET)) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid ENTRY packet size"); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid ENTRY packet size");
queue_dgram_free(entry); queue_dgram_free(entry);
queue_entry_free(entry); queue_entry_free(entry);
@ -351,7 +353,6 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
new_route.hop_count = hop_count + 1; new_route.hop_count = hop_count + 1;
new_route.latency = latency + (from_conn->rtt_last * 10); new_route.latency = latency + (from_conn->rtt_last * 10);
new_route.metrics.latency_ms = new_route.latency / 10; new_route.metrics.latency_ms = new_route.latency / 10;
new_route.metrics.hop_count = new_route.hop_count;
// Set defaults for other metrics // Set defaults for other metrics
new_route.metrics.bandwidth_kbps = 100000; // example default new_route.metrics.bandwidth_kbps = 100000; // example default
new_route.metrics.packet_loss_rate = 0; new_route.metrics.packet_loss_rate = 0;
@ -397,13 +398,13 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
break; break;
} }
case ROUTE_SUBCMD_WITHDRAW: { case ROUTE_SUBCMD_WITHDRAW: {
if (entry->len < sizeof(BGP_WITHDRAW_PACKET)) { if (entry->len < sizeof(struct BGP_WITHDRAW_PACKET)) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid WITHDRAW packet size"); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid WITHDRAW packet size");
queue_dgram_free(entry); queue_dgram_free(entry);
queue_entry_free(entry); queue_entry_free(entry);
return; return;
} }
BGP_WITHDRAW_PACKET *withdraw_pkt = (BGP_WITHDRAW_PACKET*)pkt; struct BGP_WITHDRAW_PACKET *withdraw_pkt = (struct BGP_WITHDRAW_PACKET*)pkt;
uint64_t withdrawn_node_id = be64toh(withdraw_pkt->node_id); uint64_t withdrawn_node_id = be64toh(withdraw_pkt->node_id);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received WITHDRAW for node %016llx", DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received WITHDRAW for node %016llx",
@ -449,24 +450,22 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
return; return;
} }
struct BGP_NODEINFO_PACKET *info_pkt = (struct BGP_NODEINFO_PACKET*)pkt; struct BGP_NODEINFO_PACKET *info_pkt = (struct BGP_NODEINFO_PACKET*)pkt;
struct NODE_CONNS_INFO *node_info = &info_pkt->node_info;
if (node_info->connlist_count == 0) break;
uint64_t target_node_id = be64toh(node_info->NODE_CONN_INFO[0].node_id); // assume first uint64_t target_node_id = be64toh(info_pkt->conn_info.node_id);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received NODEINFO for node %016llx, count=%d", DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received NODEINFO for node %016llx",
(unsigned long long)target_node_id, node_info->connlist_count); (unsigned long long)target_node_id);
struct ROUTE_TABLE* table = instance->rt; struct ROUTE_TABLE* table = instance->rt;
for (size_t i = 0; i < table->count; i++) { for (size_t i = 0; i < table->count; i++) {
if (table->entries[i].node_id == target_node_id) { if (table->entries[i].node_id == target_node_id) {
size_t size = sizeof(struct NODE_CONNS_INFO) + size_t size = sizeof(struct NODE_CONNS_INFO) +
node_info->connlist_count * sizeof(struct NODE_CONN_INFO); sizeof(struct NODE_CONN_INFO);
struct NODE_CONNS_INFO *new_list = u_malloc(size); struct NODE_CONNS_INFO *new_list = u_malloc(size);
if (new_list) { if (new_list) {
memcpy(new_list, node_info, size); new_list->connlist_count = 1;
new_list->ref_count = 1; new_list->ref_count = 1;
memcpy(&new_list->conn_info[0], &info_pkt->conn_info, sizeof(struct NODE_CONN_INFO));
if (table->entries[i].conn_list) { if (table->entries[i].conn_list) {
if (--table->entries[i].conn_list->ref_count == 0) { if (--table->entries[i].conn_list->ref_count == 0) {

4
src/route_lib.c

@ -5,6 +5,7 @@
#include "route_lib.h" #include "route_lib.h"
#include "etcp_connections.h" #include "etcp_connections.h"
#include "u_async.h"
#include "../lib/debug_config.h" #include "../lib/debug_config.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -18,6 +19,9 @@
#define MAX_SUBNET_VALIDATION_RANGES 50 #define MAX_SUBNET_VALIDATION_RANGES 50
#define ROUTE_CACHE_SIZE 10 #define ROUTE_CACHE_SIZE 10
// Forward declarations
static const char* route_type_to_string(route_type_t type);
/** /**
* @brief Структура кеша маршрутов (LRU) * @brief Структура кеша маршрутов (LRU)
*/ */

13
src/routing.c

@ -34,13 +34,12 @@ static uint32_t extract_dst_ip(uint8_t* data, size_t len) {
uint8_t version = (data[IP_HDR_VERSION_OFFSET] >> 4) & 0x0F; uint8_t version = (data[IP_HDR_VERSION_OFFSET] >> 4) & 0x0F;
if (version == IPv6_VERSION) { if (version == IPv6_VERSION) {
// IPv6 - drop for now DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "IPv6 packet detected, dropping");
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "IPv6 packet detected, dropping");
return 0; return 0;
} }
if (version != IPv4_VERSION) { if (version != IPv4_VERSION) {
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Unknown IP version: %d", version); DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "Unknown IP version: %d", version);
return 0; return 0;
} }
@ -108,12 +107,12 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) {
struct in_addr addr; struct in_addr addr;
addr.s_addr = htonl(dst_ip); addr.s_addr = htonl(dst_ip);
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: dst=%s len=%zu", ip_to_str(&addr, AF_INET).str, ip_len); DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: dst=%s len=%zu", ip_to_str(&addr, AF_INET).str, ip_len);
// Lookup route // Lookup route
struct ROUTE_ARRAY* routes = route_table_lookup(instance->rt, dst_ip); struct ROUTE_ARRAY* routes = route_table_lookup(instance->rt, dst_ip);
if (!routes || routes->routes == 0) { if (!routes || routes->routes == 0) {
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_pkt: no route to %s, dropping", ip_to_str(&addr, AF_INET).str); DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: no route to %s, dropping", ip_to_str(&addr, AF_INET).str);
instance->dropped_packets++; instance->dropped_packets++;
queue_entry_free(entry); queue_entry_free(entry);
queue_dgram_free(entry); queue_dgram_free(entry);
@ -132,7 +131,7 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) {
} }
// Entry sent to TUN, don't free here // Entry sent to TUN, don't free here
instance->routed_packets++; instance->routed_packets++;
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: sent %zu bytes to TUN", ip_len); DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: sent %zu bytes to TUN", ip_len);
return; return;
} }
@ -155,7 +154,7 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) {
} }
// Send to ETCP // Send to ETCP
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: sending %zu bytes to ETCP %s", ip_len, conn->log_name); DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: sending %zu bytes to ETCP %s", ip_len, conn->log_name);
if (etcp_send(conn, entry) != 0) { if (etcp_send(conn, entry) != 0) {
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: etcp_send failed for %s", ip_to_str(&addr, AF_INET).str); DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: etcp_send failed for %s", ip_to_str(&addr, AF_INET).str);
instance->dropped_packets++; instance->dropped_packets++;

4
src/utun_instance.c

@ -78,8 +78,8 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
entry.metrics.bandwidth_kbps = UINT32_MAX; // Unlimited entry.metrics.bandwidth_kbps = UINT32_MAX; // Unlimited
entry.metrics.latency_ms = 0; entry.metrics.latency_ms = 0;
entry.metrics.packet_loss_rate = 0; entry.metrics.packet_loss_rate = 0;
entry.metrics.hop_count = 0; entry.hop_count = 0;
entry.destination_node_id = instance->node_id; entry.node_id = instance->node_id;
if (route_table_insert(instance->rt, &entry)) { if (route_table_insert(instance->rt, &entry)) {
struct in_addr addr; struct in_addr addr;

6
tests/test_bgp_route_exchange.c

@ -206,8 +206,8 @@ static void print_routing_table(struct UTUN_INSTANCE* inst, const char* name) {
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 hops=%d",
i + 1, network_str, entry->prefix_length, type_str, i + 1, network_str, entry->prefix_length, type_str,
(unsigned long long)entry->destination_node_id, (unsigned long long)entry->node_id,
entry->metrics.hop_count); entry->hop_count);
} }
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "=====================================\n"); DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "=====================================\n");
} }
@ -225,7 +225,7 @@ static int check_learned_route(struct UTUN_INSTANCE* inst, uint32_t network,
if (entry->network == network && if (entry->network == network &&
entry->prefix_length == prefix_len && entry->prefix_length == prefix_len &&
entry->type == ROUTE_TYPE_LEARNED && entry->type == ROUTE_TYPE_LEARNED &&
entry->destination_node_id == expected_node_id) { entry->node_id == expected_node_id) {
return 1; return 1;
} }
} }

12
tests/test_route_lib.c

@ -53,7 +53,7 @@ static void create_test_route(struct ROUTE_ENTRY *entry, uint32_t network,
entry->flags = ROUTE_FLAG_ACTIVE; entry->flags = ROUTE_FLAG_ACTIVE;
entry->metrics.latency_ms = 10 + (rand() % 100); entry->metrics.latency_ms = 10 + (rand() % 100);
entry->metrics.packet_loss_rate = rand() % 50; entry->metrics.packet_loss_rate = rand() % 50;
entry->metrics.hop_count = 1 + (rand() % 5); entry->hop_count = 1 + (rand() % 5);
entry->metrics.bandwidth_kbps = 1000 + (rand() % 9000); entry->metrics.bandwidth_kbps = 1000 + (rand() % 9000);
route_update_quality(entry); route_update_quality(entry);
} }
@ -251,9 +251,9 @@ static void test_update_quality(void) {
struct ROUTE_ENTRY entry; struct ROUTE_ENTRY entry;
memset(&entry, 0, sizeof(entry)); memset(&entry, 0, sizeof(entry));
entry.metrics.latency_ms = 10; entry.latency = 100; // x0.1 ms units (= 10 ms)
entry.metrics.packet_loss_rate = 0; entry.metrics.packet_loss_rate = 0;
entry.metrics.hop_count = 1; entry.hop_count = 1;
ASSERT(route_update_quality(&entry), "failed to update quality"); ASSERT(route_update_quality(&entry), "failed to update quality");
@ -261,9 +261,9 @@ static void test_update_quality(void) {
struct ROUTE_ENTRY entry2; struct ROUTE_ENTRY entry2;
memset(&entry2, 0, sizeof(entry2)); memset(&entry2, 0, sizeof(entry2));
entry2.metrics.latency_ms = 5; entry2.latency = 50; // x0.1 ms units (= 5 ms)
entry2.metrics.packet_loss_rate = 0; entry2.metrics.packet_loss_rate = 0;
entry2.metrics.hop_count = 1; entry2.hop_count = 1;
route_update_quality(&entry2); route_update_quality(&entry2);
ASSERT(entry2.metrics.metric < entry.metrics.metric, ASSERT(entry2.metrics.metric < entry.metrics.metric,
@ -547,7 +547,7 @@ static void test_route_withdraw_scenario(void) {
entry.next_hop = peer; entry.next_hop = peer;
entry.type = ROUTE_TYPE_LEARNED; entry.type = ROUTE_TYPE_LEARNED;
entry.flags = ROUTE_FLAG_ACTIVE | ROUTE_FLAG_LEARNED; entry.flags = ROUTE_FLAG_ACTIVE | ROUTE_FLAG_LEARNED;
entry.destination_node_id = 0x1234567890ABCDEFULL; entry.node_id = 0x1234567890ABCDEFULL;
ASSERT(route_table_insert(table, &entry), "failed to insert learned route"); ASSERT(route_table_insert(table, &entry), "failed to insert learned route");
ASSERT_EQ(table->stats.learned_routes, 1, "should have 1 learned route"); ASSERT_EQ(table->stats.learned_routes, 1, "should have 1 learned route");

Loading…
Cancel
Save