routing + bgp big update
This commit is contained in:
1 parent
4f20e12f8c
commit
167b3b36da
12 files changed
+1256
-1919
No files matched your search
+246
-562
@@ -1,11 +1,6 @@
|
||||
/**
|
||||
* @file route_bgp.c
|
||||
* @brief Модуль обмена роутинг-таблицами между узлами (BGP-like)
|
||||
*
|
||||
* Функции:
|
||||
* - Прием и обработка роутинг-пакетов от других узлов
|
||||
* - Рассылка локальной таблицы при подключении нового узла
|
||||
* - Обновление таблицы при получении изменений
|
||||
* @brief BGP-like обмен маршрутами — исправленная версия под новую route_lib
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -22,643 +17,332 @@
|
||||
#include "../lib/debug_config.h"
|
||||
#include "../lib/mem.h"
|
||||
|
||||
// Размер пакета (без заголовка ETCP)
|
||||
#define BGP_PACKET_SIZE (sizeof(struct ROUTE_BGP_PACKET))
|
||||
#define DEBUG_CATEGORY_BGP 1
|
||||
|
||||
// Forward declarations
|
||||
static void route_bgp_send_route(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn,
|
||||
const struct ROUTE_ENTRY* route);
|
||||
static void route_bgp_send_reroute(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn,
|
||||
uint64_t old_node_id, const struct ROUTE_ENTRY* route);
|
||||
static void route_bgp_broadcast_route(struct ROUTE_BGP* bgp, const struct ROUTE_ENTRY* route,
|
||||
struct ETCP_CONN* exclude);
|
||||
static void route_bgp_broadcast_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id,
|
||||
struct ETCP_CONN* exclude);
|
||||
static void route_bgp_send_withdraw(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn, uint64_t node_id);
|
||||
static void route_bgp_send_table_to_conn_internal(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn);
|
||||
static void route_bgp_on_route_change(struct ROUTE_TABLE* table,
|
||||
struct ROUTE_ENTRY* entry,
|
||||
int action, void* arg);
|
||||
static void route_bgp_send_withdraw_for_conn(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn);
|
||||
|
||||
static const char* route_type_to_str(route_type_t type) {
|
||||
switch (type) {
|
||||
case ROUTE_TYPE_LOCAL: return "LOCAL";
|
||||
case ROUTE_TYPE_LEARNED: return "LEARNED";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
// ============================================================================
|
||||
// Вспомогательные функции
|
||||
// ============================================================================
|
||||
|
||||
static void format_ip(uint32_t ip, char* buffer) {
|
||||
if (!buffer) return;
|
||||
uint8_t* b = (uint8_t*)&ip;
|
||||
snprintf(buffer, 16, "%u.%u.%u.%u", b[3], b[2], b[1], b[0]);
|
||||
}
|
||||
|
||||
struct BGP_WITHDRAW_PACKET {
|
||||
uint8_t cmd;
|
||||
uint8_t subcmd;
|
||||
uint64_t node_id;
|
||||
} __attribute__((packed));
|
||||
// ============================================================================
|
||||
// Отправка (только preferred_conn + hop_list)
|
||||
// ============================================================================
|
||||
|
||||
struct BGP_REROUTE_PACKET {
|
||||
uint8_t cmd;
|
||||
uint8_t subcmd;
|
||||
uint64_t old_node_id;
|
||||
struct ROUTE_PEER_INFO peer_info;
|
||||
} __attribute__((packed));
|
||||
static void route_bgp_send_route(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn,
|
||||
const struct ROUTE_ENTRY* route, uint8_t subcmd) {
|
||||
if (!bgp || !conn || !route) return;
|
||||
|
||||
size_t pkt_size;
|
||||
struct BGP_ROUTE_PACKET* pkt;
|
||||
|
||||
if (!route->conn_list) {
|
||||
pkt_size = sizeof(struct BGP_ROUTE_PACKET);
|
||||
pkt = u_calloc(1, pkt_size);
|
||||
if (!pkt) return;
|
||||
pkt->node_id = htobe64(bgp->instance->node_id);
|
||||
pkt->hop_count = 0;
|
||||
} else {
|
||||
uint8_t pref = route->conn_list->preferred_conn;
|
||||
if (pref >= route->conn_list->conninfo_count) pref = 0;
|
||||
|
||||
struct NODE_CONN_INFO* ci = &route->conn_list->conn_info[pref];
|
||||
pkt_size = sizeof(struct BGP_ROUTE_PACKET) + ci->hop_count * sizeof(uint64_t);
|
||||
pkt = u_calloc(1, pkt_size);
|
||||
if (!pkt) return;
|
||||
|
||||
pkt->node_id = htobe64(route->conn_list->node_id);
|
||||
pkt->hop_count = ci->hop_count;
|
||||
if (ci->hop_count > 0 && ci->hop_list)
|
||||
memcpy(pkt->hop_list, ci->hop_list, ci->hop_count * sizeof(uint64_t));
|
||||
}
|
||||
|
||||
pkt->cmd = ETCP_ID_ROUTE_ENTRY;
|
||||
pkt->subcmd = subcmd; // ← теперь используем REROUTE
|
||||
pkt->network = htonl(route->network);
|
||||
pkt->prefix_length = route->prefix_length;
|
||||
pkt->latency = 0;
|
||||
|
||||
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 = (uint16_t)pkt_size;
|
||||
|
||||
if (etcp_send(conn, send_entry) != 0) {
|
||||
queue_entry_free(send_entry);
|
||||
u_free(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Broadcast / Withdraw
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief Рассылает маршрут всем соединениям (кроме exclude)
|
||||
*/
|
||||
static void route_bgp_broadcast_route(struct ROUTE_BGP* bgp, const struct ROUTE_ENTRY* route,
|
||||
struct ETCP_CONN* exclude) {
|
||||
struct ETCP_CONN* exclude, uint8_t subcmd) {
|
||||
if (!bgp || !route) return;
|
||||
|
||||
|
||||
struct ll_entry* entry = bgp->senders_list->head;
|
||||
int sent_count = 0;
|
||||
|
||||
while (entry) {
|
||||
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)entry->data;
|
||||
if (item->conn != exclude) {
|
||||
route_bgp_send_route(bgp, item->conn, route);
|
||||
sent_count++;
|
||||
route_bgp_send_route(bgp, item->conn, route, subcmd);
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
char net_buf[16];
|
||||
format_ip(route->peer_info.network, net_buf);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Broadcasted route %s/%d to %d connections",
|
||||
net_buf, route->peer_info.prefix_length, sent_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Рассылает withdraw всем соединениям (кроме exclude)
|
||||
*/
|
||||
static void route_bgp_broadcast_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id,
|
||||
struct ETCP_CONN* exclude) {
|
||||
if (!bgp) return;
|
||||
|
||||
struct ll_entry* entry = bgp->senders_list->head;
|
||||
int sent_count = 0;
|
||||
|
||||
while (entry) {
|
||||
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)entry->data;
|
||||
if (item->conn != exclude) {
|
||||
route_bgp_send_withdraw(bgp, item->conn, node_id);
|
||||
sent_count++;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Broadcasted withdraw for node %016llx to %d connections",
|
||||
(unsigned long long)node_id, sent_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет маршрут конкретному соединению
|
||||
*/
|
||||
static void route_bgp_send_route(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn,
|
||||
const struct ROUTE_ENTRY* route) {
|
||||
if (!bgp || !conn || !route) return;
|
||||
|
||||
struct BGP_ENTRY_PACKET *pkt = u_calloc(1, sizeof(struct BGP_ENTRY_PACKET));
|
||||
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_ENTRY;
|
||||
pkt->peer_info.node_id = htobe64(route->peer_info.node_id);
|
||||
pkt->peer_info.network = htonl(route->peer_info.network);
|
||||
pkt->peer_info.prefix_length = route->peer_info.prefix_length;
|
||||
pkt->peer_info.hop_count = route->peer_info.hop_count;
|
||||
pkt->peer_info.latency = htons(route->peer_info.latency);
|
||||
// Add other fields if present, e.g., bandwidth
|
||||
|
||||
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_ENTRY_PACKET);
|
||||
|
||||
if (etcp_send(conn, send_entry) != 0) {
|
||||
queue_entry_free(send_entry);
|
||||
u_free(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет reroute конкретному соединению
|
||||
*/
|
||||
static void route_bgp_send_reroute(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn,
|
||||
uint64_t old_node_id, const struct ROUTE_ENTRY* route) {
|
||||
if (!bgp || !conn || !route) return;
|
||||
|
||||
struct BGP_REROUTE_PACKET *pkt = u_calloc(1, sizeof(struct BGP_REROUTE_PACKET));
|
||||
if (!pkt) return;
|
||||
|
||||
pkt->cmd = ETCP_ID_ROUTE_ENTRY;
|
||||
pkt->subcmd = ROUTE_SUBCMD_ENTRY_REROUTE;
|
||||
pkt->old_node_id = htobe64(old_node_id);
|
||||
pkt->peer_info.node_id = htobe64(route->peer_info.node_id);
|
||||
pkt->peer_info.network = htonl(route->peer_info.network);
|
||||
pkt->peer_info.prefix_length = route->peer_info.prefix_length;
|
||||
pkt->peer_info.hop_count = route->peer_info.hop_count;
|
||||
pkt->peer_info.latency = htons(route->peer_info.latency);
|
||||
|
||||
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_REROUTE_PACKET);
|
||||
|
||||
if (etcp_send(conn, send_entry) != 0) {
|
||||
queue_entry_free(send_entry);
|
||||
u_free(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет withdraw конкретному соединению
|
||||
*/
|
||||
static void route_bgp_send_withdraw(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn, uint64_t node_id) {
|
||||
if (!bgp || !conn) return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
if (etcp_send(conn, send_entry) != 0) {
|
||||
queue_entry_free(send_entry);
|
||||
u_free(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет withdraw для всех affected node_id при удалении conn
|
||||
*/
|
||||
static void route_bgp_send_withdraw_for_conn(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn) {
|
||||
if (!bgp || !conn || !conn->instance || !conn->instance->rt) return;
|
||||
|
||||
struct ROUTE_TABLE* table = conn->instance->rt;
|
||||
|
||||
// Collect unique node_ids where next_hop == conn
|
||||
uint64_t unique_nodes[1024]; // assume max
|
||||
size_t unique_count = 0;
|
||||
bool found;
|
||||
|
||||
for (size_t i = 0; i < table->count; i++) {
|
||||
if (table->entries[i].next_hop == conn) {
|
||||
uint64_t nid = table->entries[i].peer_info.node_id;
|
||||
found = false;
|
||||
for (size_t j = 0; j < unique_count; j++) {
|
||||
if (unique_nodes[j] == nid) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found && unique_count < 1024) {
|
||||
unique_nodes[unique_count++] = nid;
|
||||
struct ll_entry* e = bgp->senders_list->head;
|
||||
while (e) {
|
||||
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)e->data;
|
||||
if (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;
|
||||
etcp_send(item->conn, copy);
|
||||
}
|
||||
}
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
// Broadcast withdraw for each unique node_id
|
||||
for (size_t j = 0; j < unique_count; j++) {
|
||||
route_bgp_broadcast_withdraw(bgp, unique_nodes[j], conn); // exclude conn, but since removing, anyway
|
||||
|
||||
queue_entry_free(send_entry);
|
||||
u_free(pkt);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Callback на изменение таблицы (insert / update / delete)
|
||||
// ============================================================================
|
||||
|
||||
static void route_bgp_on_route_change(struct ROUTE_TABLE* table,
|
||||
struct ROUTE_ENTRY* entry,
|
||||
int action, void* arg) {
|
||||
struct ROUTE_BGP* bgp = (struct ROUTE_BGP*)arg;
|
||||
if (!bgp || !entry) return;
|
||||
|
||||
if (action == 0) { // insert
|
||||
route_bgp_broadcast_route(bgp, entry, NULL, ROUTE_SUBCMD_ENTRY);
|
||||
}
|
||||
else if (action == 1) { // update / reroute / hop_list changed
|
||||
route_bgp_broadcast_route(bgp, entry, NULL, ROUTE_SUBCMD_ENTRY_REROUTE);
|
||||
}
|
||||
else if (action == 2) { // withdraw
|
||||
uint64_t node_id = entry->conn_list ? entry->conn_list->node_id : 0;
|
||||
route_bgp_broadcast_withdraw(bgp, node_id, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Отправляет полную таблицу конкретному соединению
|
||||
*/
|
||||
static void route_bgp_send_table_to_conn_internal(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn) {
|
||||
if (!bgp || !conn || !bgp->instance || !bgp->instance->rt) return;
|
||||
|
||||
struct ROUTE_TABLE* table = bgp->instance->rt;
|
||||
|
||||
for (size_t i = 0; i < table->count; i++) {
|
||||
if (table->entries[i].next_hop!=conn) route_bgp_send_route(bgp, conn, &table->entries[i]);
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sent full routing table (%zu entries) to connection %p",
|
||||
table->count, (void*)conn);
|
||||
}
|
||||
// ============================================================================
|
||||
// Приём пакетов
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief Колбэк для приема роутинг-пакетов от ETCP
|
||||
*
|
||||
* Вызывается когда приходит пакет с ETCP_ID_ROUTE_ENTRY.
|
||||
* Парсит пакет и добавляет маршрут в таблицу.
|
||||
*/
|
||||
static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* entry)
|
||||
{
|
||||
if (!from_conn || !entry || !entry->dgram || entry->len < 2) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid BGP packet received");
|
||||
if (entry) {
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(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); queue_entry_free(entry); }
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
struct UTUN_INSTANCE* instance = from_conn->instance;
|
||||
if (!instance || !instance->rt) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "No instance or routing table");
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
if (!instance || !instance->rt || !instance->bgp) {
|
||||
queue_dgram_free(entry); queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
struct ROUTE_BGP* bgp = instance->bgp;
|
||||
|
||||
struct BGP_ENTRY_PACKET* pkt = (struct BGP_ENTRY_PACKET*)entry->dgram;
|
||||
|
||||
// Проверяем команду
|
||||
if (pkt->cmd != ETCP_ID_ROUTE_ENTRY) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "Unknown BGP command: %d", pkt->cmd);
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
uint8_t* data = entry->dgram;
|
||||
|
||||
if (data[0] != ETCP_ID_ROUTE_ENTRY) {
|
||||
queue_dgram_free(entry); queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
|
||||
char ip_buf[16];
|
||||
uint32_t network;
|
||||
uint8_t prefix_length;
|
||||
uint64_t node_id;
|
||||
|
||||
switch (pkt->subcmd) {
|
||||
case ROUTE_SUBCMD_ENTRY:
|
||||
case ROUTE_SUBCMD_ENTRY_REROUTE: {
|
||||
uint64_t old_node_id = 0;
|
||||
struct ROUTE_PEER_INFO *peer_info;
|
||||
if (pkt->subcmd == ROUTE_SUBCMD_ENTRY_REROUTE) {
|
||||
if (entry->len < sizeof(struct BGP_REROUTE_PACKET)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid REROUTE packet size");
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
struct BGP_REROUTE_PACKET *reroute_pkt = (struct BGP_REROUTE_PACKET*)pkt;
|
||||
old_node_id = be64toh(reroute_pkt->old_node_id);
|
||||
peer_info = &reroute_pkt->peer_info;
|
||||
} else {
|
||||
if (entry->len < sizeof(struct BGP_ENTRY_PACKET)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid ENTRY packet size");
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
peer_info = &pkt->peer_info;
|
||||
}
|
||||
|
||||
node_id = be64toh(peer_info->node_id);
|
||||
network = ntohl(peer_info->network);
|
||||
prefix_length = peer_info->prefix_length;
|
||||
uint8_t hop_count = peer_info->hop_count;
|
||||
uint16_t latency = ntohs(peer_info->latency);
|
||||
|
||||
format_ip(network, ip_buf);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received BGP %s: network=%s/%d, node_id=%016llx, hop=%d, lat=%u",
|
||||
(pkt->subcmd == ROUTE_SUBCMD_ENTRY) ? "ENTRY" : "REROUTE",
|
||||
ip_buf, prefix_length, (unsigned long long)node_id, hop_count, latency);
|
||||
|
||||
struct ROUTE_ENTRY new_route;
|
||||
memset(&new_route, 0, sizeof(new_route));
|
||||
|
||||
new_route.peer_info.node_id = node_id;
|
||||
new_route.peer_info.network = network;
|
||||
new_route.peer_info.prefix_length = prefix_length;
|
||||
new_route.next_hop = from_conn;
|
||||
new_route.type = ROUTE_TYPE_LEARNED;
|
||||
new_route.flags = ROUTE_FLAG_ACTIVE | ROUTE_FLAG_LEARNED;
|
||||
new_route.peer_info.hop_count = hop_count + 1;
|
||||
new_route.peer_info.latency = latency + (from_conn->rtt_last * 10);
|
||||
new_route.metrics.latency_ms = new_route.peer_info.latency / 10;
|
||||
// Set defaults for other metrics
|
||||
new_route.metrics.bandwidth_kbps = 100000; // example default
|
||||
new_route.metrics.packet_loss_rate = 0;
|
||||
route_update_quality(&new_route);
|
||||
|
||||
struct ROUTE_TABLE* table = instance->rt;
|
||||
bool exists = false;
|
||||
bool updated = false;
|
||||
|
||||
for (size_t i = 0; i < table->count; i++) {
|
||||
struct ROUTE_ENTRY* existing = &table->entries[i];
|
||||
if (existing->peer_info.network == network && existing->peer_info.prefix_length == prefix_length) {
|
||||
exists = true;
|
||||
if (new_route.peer_info.hop_count < existing->peer_info.hop_count) {
|
||||
// Update to better route
|
||||
existing->next_hop = new_route.next_hop;
|
||||
existing->peer_info.hop_count = new_route.peer_info.hop_count;
|
||||
existing->peer_info.latency = new_route.peer_info.latency;
|
||||
existing->metrics = new_route.metrics;
|
||||
existing->last_update = get_time_tb();
|
||||
if (table->change_callback) {
|
||||
table->change_callback(table, existing, 1, table->change_callback_arg);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
new_route.created_time = get_time_tb();
|
||||
new_route.last_update = new_route.created_time;
|
||||
new_route.metrics.last_updated = new_route.created_time;
|
||||
if (route_table_insert(table, &new_route)) {
|
||||
updated = true; // treat insert as update for broadcast
|
||||
}
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
route_bgp_broadcast_route(bgp, &new_route, from_conn);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
uint8_t subcmd = data[1];
|
||||
|
||||
if (subcmd == ROUTE_SUBCMD_ENTRY || subcmd == ROUTE_SUBCMD_ENTRY_REROUTE) {
|
||||
if (entry->len < sizeof(struct BGP_ROUTE_PACKET)) {
|
||||
queue_dgram_free(entry); queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
case ROUTE_SUBCMD_WITHDRAW: {
|
||||
if (entry->len < sizeof(struct BGP_WITHDRAW_PACKET)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid WITHDRAW packet size");
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
struct BGP_WITHDRAW_PACKET *withdraw_pkt = (struct BGP_WITHDRAW_PACKET*)pkt;
|
||||
uint64_t withdrawn_node_id = be64toh(withdraw_pkt->node_id);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received WITHDRAW for node %016llx",
|
||||
(unsigned long long)withdrawn_node_id);
|
||||
|
||||
struct ROUTE_TABLE* table = instance->rt;
|
||||
bool has_alternative = false;
|
||||
size_t i = 0;
|
||||
while (i < table->count) {
|
||||
struct ROUTE_ENTRY* rte = &table->entries[i];
|
||||
if (rte->peer_info.node_id == withdrawn_node_id) {
|
||||
if (rte->next_hop == from_conn) {
|
||||
route_table_delete_entry(table, rte->peer_info.network, rte->peer_info.prefix_length, from_conn);
|
||||
// Do not increment i, array shifted
|
||||
} else {
|
||||
has_alternative = true;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_alternative) {
|
||||
// Send reroute for each remaining route to from_conn
|
||||
for (size_t j = 0; j < table->count; j++) {
|
||||
if (table->entries[j].peer_info.node_id == withdrawn_node_id) {
|
||||
route_bgp_send_reroute(bgp, from_conn, withdrawn_node_id, &table->entries[j]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Propagate withdraw
|
||||
route_bgp_broadcast_withdraw(bgp, withdrawn_node_id, from_conn);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
struct BGP_ROUTE_PACKET* pkt = (struct BGP_ROUTE_PACKET*)data;
|
||||
uint32_t network = ntohl(pkt->network);
|
||||
uint8_t prefix = pkt->prefix_length;
|
||||
uint64_t owner_node_id = be64toh(pkt->node_id);
|
||||
uint8_t recv_hop_count = pkt->hop_count;
|
||||
|
||||
if (recv_hop_count > MAX_HOPS - 1) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "Too many hops (%d)", recv_hop_count);
|
||||
queue_dgram_free(entry); queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
case ROUTE_SUBCMD_NODEINFO: {
|
||||
if (entry->len < sizeof(struct BGP_NODEINFO_PACKET)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Invalid NODEINFO packet size");
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
struct BGP_NODEINFO_PACKET *info_pkt = (struct BGP_NODEINFO_PACKET*)pkt;
|
||||
|
||||
uint64_t target_node_id = be64toh(info_pkt->conn_info.node_id);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received NODEINFO for node %016llx",
|
||||
(unsigned long long)target_node_id);
|
||||
|
||||
struct ROUTE_TABLE* table = instance->rt;
|
||||
for (size_t i = 0; i < table->count; i++) {
|
||||
if (table->entries[i].peer_info.node_id == target_node_id) {
|
||||
size_t size = sizeof(struct NODE_CONNS_INFO) +
|
||||
sizeof(struct NODE_CONN_INFO);
|
||||
struct NODE_CONNS_INFO *new_list = u_malloc(size);
|
||||
if (new_list) {
|
||||
new_list->connlist_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->ref_count == 0) {
|
||||
u_free(table->entries[i].conn_list);
|
||||
}
|
||||
}
|
||||
|
||||
table->entries[i].conn_list = new_list;
|
||||
|
||||
if (table->change_callback) {
|
||||
table->change_callback(table, &table->entries[i], 1, table->change_callback_arg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Строим новый hop_list: next_hop = отправитель + полученный список
|
||||
uint8_t new_hop_count = recv_hop_count + 1;
|
||||
uint64_t new_hop_list[MAX_HOPS];
|
||||
new_hop_list[0] = from_conn->peer_node_id;
|
||||
if (recv_hop_count > 0) {
|
||||
memcpy(&new_hop_list[1], pkt->hop_list, recv_hop_count * sizeof(uint64_t));
|
||||
}
|
||||
default:
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "Unknown BGP subcommand: %d", pkt->subcmd);
|
||||
break;
|
||||
|
||||
char ip_buf[16];
|
||||
format_ip(network, ip_buf);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received route %s/%d from %016llx (hops=%d)",
|
||||
ip_buf, prefix, (unsigned long long)owner_node_id, new_hop_count);
|
||||
|
||||
struct ROUTE_ENTRY new_route = {0};
|
||||
new_route.network = network;
|
||||
new_route.prefix_length = prefix;
|
||||
|
||||
bool inserted = route_insert(instance->rt, &new_route,
|
||||
from_conn,
|
||||
owner_node_id,
|
||||
instance->node_id,
|
||||
new_hop_list,
|
||||
new_hop_count);
|
||||
|
||||
if (!inserted) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "Route insert rejected (loop/overlap/owner conflict)");
|
||||
}
|
||||
|
||||
} else if (subcmd == ROUTE_SUBCMD_WITHDRAW) {
|
||||
if (entry->len < sizeof(struct BGP_WITHDRAW_PACKET)) {
|
||||
queue_dgram_free(entry); queue_entry_free(entry);
|
||||
return;
|
||||
}
|
||||
struct BGP_WITHDRAW_PACKET* wp = (struct BGP_WITHDRAW_PACKET*)data;
|
||||
uint64_t node_id = be64toh(wp->node_id);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received WITHDRAW for node %016llx", (unsigned long long)node_id);
|
||||
|
||||
// === ИСПРАВЛЕНИЕ: поддержка резервных путей ===
|
||||
route_remove_path(instance->rt, from_conn, node_id);
|
||||
// callback внутри route_remove_path уже сделает broadcast (withdraw или reroute)
|
||||
}
|
||||
|
||||
|
||||
queue_dgram_free(entry);
|
||||
queue_entry_free(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback на изменение маршрута (broadcast при insert/update)
|
||||
*/
|
||||
static void route_bgp_on_route_change(struct ROUTE_TABLE* table,
|
||||
struct ROUTE_ENTRY* entry,
|
||||
int action, void* arg) {
|
||||
struct ROUTE_BGP* bgp = (struct ROUTE_BGP*)arg;
|
||||
if (!bgp || !entry) return;
|
||||
|
||||
if (action == 0 || action == 1) { // insert or update
|
||||
route_bgp_broadcast_route(bgp, entry, NULL);
|
||||
}
|
||||
// for delete, handled in remove_conn/withdraw
|
||||
}
|
||||
// ============================================================================
|
||||
// Init / Destroy / New / Remove conn
|
||||
// ============================================================================
|
||||
|
||||
struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance) {
|
||||
if (!instance) return NULL;
|
||||
|
||||
struct ROUTE_BGP* bgp = u_calloc(1, sizeof(struct ROUTE_BGP));
|
||||
if (!bgp) return NULL;
|
||||
|
||||
struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance)
|
||||
{
|
||||
if (!instance) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ROUTE_BGP* bgp = (struct ROUTE_BGP*)u_calloc(1, sizeof(struct ROUTE_BGP));
|
||||
if (!bgp) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Failed to allocate BGP structure");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bgp->instance = instance;
|
||||
|
||||
// Создаем очередь для рассылки
|
||||
bgp->senders_list = queue_new(instance->ua, 0, "BGP sender_list");
|
||||
|
||||
bgp->senders_list = queue_new(instance->ua, 0, "BGP_senders");
|
||||
if (!bgp->senders_list) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Failed to create senders queue");
|
||||
u_free(bgp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Регистрируем колбэк для приема роутинг-пакетов
|
||||
if (etcp_bind(instance, ETCP_ID_ROUTE_ENTRY, route_bgp_receive_cbk) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Failed to bind ETCP callback");
|
||||
queue_free(bgp->senders_list);
|
||||
u_free(bgp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Устанавливаем callback на изменение таблицы маршрутизации
|
||||
|
||||
etcp_bind(instance, ETCP_ID_ROUTE_ENTRY, route_bgp_receive_cbk);
|
||||
|
||||
if (instance->rt) {
|
||||
instance->rt->change_callback = route_bgp_on_route_change;
|
||||
instance->rt->change_callback_arg = bgp;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Route change callback registered");
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module initialized");
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module initialized (with hop_list support)");
|
||||
return bgp;
|
||||
}
|
||||
|
||||
void route_bgp_destroy(struct UTUN_INSTANCE* instance)
|
||||
{
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Отвязываем колбэк
|
||||
void route_bgp_destroy(struct UTUN_INSTANCE* instance) {
|
||||
if (!instance || !instance->bgp) return;
|
||||
|
||||
etcp_unbind(instance, ETCP_ID_ROUTE_ENTRY);
|
||||
|
||||
// Очищаем и освобождаем структуру BGP
|
||||
if (instance->bgp) {
|
||||
// Убираем callback из таблицы маршрутизации
|
||||
if (instance->rt && instance->rt->change_callback == route_bgp_on_route_change) {
|
||||
instance->rt->change_callback = NULL;
|
||||
instance->rt->change_callback_arg = NULL;
|
||||
}
|
||||
|
||||
if (instance->bgp->senders_list) {
|
||||
// Очищаем очередь - освобождаем элементы conn_item
|
||||
struct ll_entry* entry;
|
||||
while ((entry = queue_data_get(instance->bgp->senders_list)) != NULL) {
|
||||
queue_entry_free(entry);
|
||||
}
|
||||
queue_free(instance->bgp->senders_list);
|
||||
}
|
||||
u_free(instance->bgp);
|
||||
instance->bgp = NULL;
|
||||
|
||||
if (instance->rt && instance->rt->change_callback == route_bgp_on_route_change) {
|
||||
instance->rt->change_callback = NULL;
|
||||
instance->rt->change_callback_arg = NULL;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module destroyed");
|
||||
|
||||
// очистка списка
|
||||
struct ll_entry* e;
|
||||
while ((e = queue_data_get(instance->bgp->senders_list)) != NULL) {
|
||||
queue_entry_free(e);
|
||||
}
|
||||
queue_free(instance->bgp->senders_list);
|
||||
|
||||
u_free(instance->bgp);
|
||||
instance->bgp = NULL;
|
||||
}
|
||||
|
||||
void route_bgp_new_conn(struct ETCP_CONN* conn)
|
||||
{
|
||||
if (!conn || !conn->instance) {
|
||||
return;
|
||||
void route_bgp_new_conn(struct ETCP_CONN* conn) {
|
||||
if (!conn || !conn->instance || !conn->instance->bgp) return;
|
||||
|
||||
struct ROUTE_BGP* bgp = conn->instance->bgp;
|
||||
|
||||
struct ll_entry* item_entry = queue_entry_new(sizeof(struct ROUTE_BGP_CONN_ITEM));
|
||||
if (!item_entry) return;
|
||||
|
||||
((struct ROUTE_BGP_CONN_ITEM*)item_entry->data)->conn = conn;
|
||||
queue_data_put(bgp->senders_list, item_entry, 0);
|
||||
|
||||
// Отправляем полную таблицу (только preferred пути)
|
||||
struct ROUTE_TABLE* rt = conn->instance->rt;
|
||||
for (size_t i = 0; i < rt->count; i++) {
|
||||
route_bgp_send_route(bgp, conn, &rt->entries[i], ROUTE_SUBCMD_ENTRY);
|
||||
}
|
||||
|
||||
struct UTUN_INSTANCE* instance = conn->instance;
|
||||
struct ROUTE_BGP* bgp = instance->bgp;
|
||||
|
||||
if (!bgp) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_BGP, "BGP not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
// Создаем элемент для добавления в senders_list
|
||||
struct ll_entry* entry = queue_entry_new(sizeof(struct ROUTE_BGP_CONN_ITEM));
|
||||
if (!entry) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Failed to allocate connection item");
|
||||
return;
|
||||
}
|
||||
|
||||
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)entry->data;
|
||||
item->conn = conn;
|
||||
|
||||
// Добавляем в очередь (id = 0, не используем хеш)
|
||||
if (queue_data_put(bgp->senders_list, entry, 0) != 0) {
|
||||
queue_entry_free(entry);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "Failed to add connection to senders_list");
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Added connection %p to senders_list", (void*)conn);
|
||||
|
||||
// Отправляем полную таблицу новому соединению
|
||||
route_bgp_send_table_to_conn_internal(bgp, conn);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sent full routing table to new connection");
|
||||
}
|
||||
|
||||
void route_bgp_remove_conn(struct ETCP_CONN* conn)
|
||||
{
|
||||
if (!conn || !conn->instance) {
|
||||
return;
|
||||
void route_bgp_remove_conn(struct ETCP_CONN* conn) {
|
||||
if (!conn || !conn->instance || !conn->instance->bgp) return;
|
||||
|
||||
struct ROUTE_BGP* bgp = conn->instance->bgp;
|
||||
struct ROUTE_TABLE* rt = conn->instance->rt;
|
||||
|
||||
// ← КЛЮЧЕВОЕ ИЗМЕНЕНИЕ: теперь используем route_remove_conn
|
||||
if (rt) {
|
||||
route_remove_conn(rt, conn); // автоматически вызовет reroute / withdraw через callback
|
||||
}
|
||||
|
||||
struct UTUN_INSTANCE* instance = conn->instance;
|
||||
struct ROUTE_BGP* bgp = instance->bgp;
|
||||
|
||||
if (!bgp) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Removing connection %p from senders_list", (void*)conn);
|
||||
|
||||
// Отправляем withdraw всем остальным соединениям для маршрутов через это соединение
|
||||
route_bgp_send_withdraw_for_conn(bgp, conn);
|
||||
|
||||
// Находим и удаляем соединение из senders_list
|
||||
struct ll_entry* entry = bgp->senders_list->head;
|
||||
while (entry) {
|
||||
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)entry->data;
|
||||
|
||||
// Удаляем из списка рассылки
|
||||
struct ll_entry* e = bgp->senders_list->head;
|
||||
while (e) {
|
||||
struct ROUTE_BGP_CONN_ITEM* item = (struct ROUTE_BGP_CONN_ITEM*)e->data;
|
||||
if (item->conn == conn) {
|
||||
// Удаляем из очереди
|
||||
queue_remove_data(bgp->senders_list, entry);
|
||||
queue_entry_free(entry);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Connection %p removed from senders_list", (void*)conn);
|
||||
queue_remove_data(bgp->senders_list, e);
|
||||
queue_entry_free(e);
|
||||
break;
|
||||
}
|
||||
entry = entry->next;
|
||||
}
|
||||
|
||||
// Удаляем все маршруты, связанные с этим соединением
|
||||
if (instance->rt) {
|
||||
route_table_delete(instance->rt, conn);
|
||||
e = e->next;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Connection removed, routes updated via route_remove_conn");
|
||||
}
|
||||
|
||||
void route_bgp_close_conn(struct ETCP_CONN* conn)
|
||||
{
|
||||
// Устаревшая функция, используйте route_bgp_remove_conn
|
||||
void route_bgp_close_conn(struct ETCP_CONN* conn) {
|
||||
route_bgp_remove_conn(conn);
|
||||
}
|
||||
+31
-42
@@ -5,66 +5,55 @@
|
||||
#include "../lib/ll_queue.h"
|
||||
#include "route_lib.h"
|
||||
|
||||
// Forward declarations
|
||||
struct UTUN_INSTANCE;
|
||||
struct ETCP_CONN;
|
||||
|
||||
// ETCP ID для маршрутных пакетов
|
||||
#define ETCP_ID_ROUTE_ENTRY 0x01
|
||||
|
||||
// Sub-команды для маршрутных пакетов
|
||||
#define ROUTE_SUBCMD_ENTRY 0x01 // Элемент таблицы
|
||||
#define ROUTE_SUBCMD_ENTRY_REROUTE 0x02 // old_node_id + элемент таблицы - когда найден альтернативный маршрут при WITHDRAW
|
||||
#define ROUTE_SUBCMD_WITHDRAW 0x03 // Отзыв маршрута
|
||||
#define ROUTE_SUBCMD_NODEINFO 0x04 // информация об узле для прямого подключения
|
||||
// Sub-команды
|
||||
#define ROUTE_SUBCMD_ENTRY 0x01 // Обычное обновление маршрута
|
||||
#define ROUTE_SUBCMD_ENTRY_REROUTE 0x02 // Reroute (preferred_conn изменился) — пока обрабатывается как ENTRY
|
||||
#define ROUTE_SUBCMD_WITHDRAW 0x03
|
||||
#define ROUTE_SUBCMD_NODEINFO 0x04
|
||||
|
||||
#define MAX_HOPS 16
|
||||
|
||||
/**
|
||||
* @brief Пакет маршрутной информации (бинарный формат)
|
||||
* @brief Основной пакет маршрута (переменной длины)
|
||||
*/
|
||||
// struct PEER_INFO_ENTRY -> struct ROUTE_PEER_INFO;
|
||||
|
||||
struct BGP_ENTRY_PACKET {
|
||||
uint8_t cmd; // ETCP_CMD_ROUTE (1)
|
||||
uint8_t subcmd; // ROUTE_SUBCMD_ENTRY (1)
|
||||
struct ROUTE_PEER_INFO peer_info;
|
||||
struct BGP_ROUTE_PACKET {
|
||||
uint8_t cmd; // ETCP_ID_ROUTE_ENTRY
|
||||
uint8_t subcmd; // ENTRY / REROUTE
|
||||
uint32_t network; // big-endian
|
||||
uint8_t prefix_length;
|
||||
uint64_t node_id; // владелец префикса (big-endian)
|
||||
uint8_t hop_count; // количество хопов
|
||||
uint16_t latency; // зарезервировано (0)
|
||||
uint64_t hop_list[0]; // flexible array: next_hop → ... → destination
|
||||
} __attribute__((packed));
|
||||
|
||||
struct BGP_NODEINFO_PACKET {
|
||||
uint8_t cmd; // ETCP_CMD_ROUTE (1)
|
||||
uint8_t subcmd; // ROUTE_SUBCMD_NODEINFO (4)
|
||||
struct NODE_CONN_INFO conn_info;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
struct ROUTE_BGP_QUEUE_ITEM {
|
||||
struct ll_entry ll; // Для очереди
|
||||
struct ETCP_CONN* target; // Кому отправлять (NULL = всем)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Элемент списка соединений для рассылки обновлений
|
||||
* @brief Пакет WITHDRAW (фиксированный)
|
||||
*/
|
||||
struct BGP_WITHDRAW_PACKET {
|
||||
uint8_t cmd;
|
||||
uint8_t subcmd;
|
||||
uint64_t node_id;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ROUTE_BGP_CONN_ITEM {
|
||||
struct ll_entry ll; // Для очереди/списка
|
||||
struct ETCP_CONN* conn; // Указатель на соединение
|
||||
struct ll_entry ll;
|
||||
struct ETCP_CONN* conn;
|
||||
};
|
||||
|
||||
struct ROUTE_BGP {
|
||||
struct UTUN_INSTANCE* instance; // Ссылка на instance
|
||||
struct ll_queue* senders_list; // список для рассылки обновлений (рассылаем через etcp_send)
|
||||
struct UTUN_INSTANCE* instance;
|
||||
struct ll_queue* senders_list;
|
||||
};
|
||||
|
||||
|
||||
// Создание/уничтожение (делаем bind на 0x01)
|
||||
struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance);
|
||||
void route_bgp_destroy(struct UTUN_INSTANCE* instance);
|
||||
|
||||
// Прием пакетов (вызывается из ETCP при получении ETCP_ID_ROUTE)
|
||||
//BIND: static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* entry);
|
||||
|
||||
// Отправка таблицы конкретному соединению или всем
|
||||
void route_bgp_new_conn(struct ETCP_CONN* conn); // Добавление в список рассылки и отправка таблицы
|
||||
void route_bgp_remove_conn(struct ETCP_CONN* conn); // Удаление из списка рассылки и отправка withdraw
|
||||
void route_bgp_close_conn(struct ETCP_CONN* conn); // Убрать из списка рассылки (deprecated, используй remove_conn)
|
||||
void route_bgp_new_conn(struct ETCP_CONN* conn);
|
||||
void route_bgp_remove_conn(struct ETCP_CONN* conn);
|
||||
void route_bgp_close_conn(struct ETCP_CONN* conn); // deprecated
|
||||
|
||||
#endif // ROUTE_BGP_H
|
||||
@@ -41,26 +41,3 @@ subcmd:
|
||||
если записей много - добавляет 4 бита к хеш таблице и строит субтаблицу для
|
||||
|
||||
|
||||
|
||||
Как работает роутинг:
|
||||
1. типов маршрута бывает два: learned и local.
|
||||
local - маршруты из конфига (my_subnet)
|
||||
при инициализации они сразу добавляются в роутинг таблицу.
|
||||
|
||||
2. При установке подключения к новому узлу мы отправляем этому узлу полностью свою таблицу маршрутизации (local + learned узлы)
|
||||
|
||||
3. При получении маршрута мы смотрим есть ли такой маршрут уже в таблице. Если такоц маршрут есть - пропускаем. иначе добавляем/обновляем (стремимся получить маршрут с минимальным hop count).
|
||||
Добавляем так:
|
||||
инкрементируем hop_count
|
||||
устанавливая etcp линк с которого приняли как next_hop.
|
||||
рассылаем по всем активным линкам кроме линка с которого получили
|
||||
|
||||
4. При отключении от узла мы
|
||||
Удаляем все маршруты узла
|
||||
Рассылаем withdraw для узла hop_id.
|
||||
|
||||
Логика рассылки withdraw:
|
||||
Если получен withdraw и next hop маршрутов узла = hop id - удаляем маршрут и распространяем withdraw дальше по доступным линкам.
|
||||
А если next hop у нас другой - отправляем в ответ наш маршрут командой reoute (для распространения альтернативного найденного маршрута) в линк с которого пришел withdraw.
|
||||
reroute содержит дополнительное поле - old_hop_id
|
||||
|
||||
+624
-541
File diff suppressed because it is too large.
Load diff
+59
-130
@@ -10,67 +10,33 @@ struct ROUTE_TABLE;
|
||||
struct ROUTE_ENTRY;
|
||||
|
||||
/**
|
||||
* @brief Типы маршрутов
|
||||
*/
|
||||
typedef enum {
|
||||
ROUTE_TYPE_STATIC = 0, /**< Статический маршрут */
|
||||
ROUTE_TYPE_DYNAMIC = 1, /**< Динамический маршрут */
|
||||
ROUTE_TYPE_LOCAL = 2, /**< Локальный маршрут */
|
||||
ROUTE_TYPE_LEARNED = 3 /**< Изученный маршрут */
|
||||
} route_type_t;
|
||||
|
||||
/**
|
||||
* @brief Флаги маршрута
|
||||
* @brief Флаги узла
|
||||
*/
|
||||
typedef enum {
|
||||
ROUTE_FLAG_ACTIVE = (1 << 0), /**< Маршрут активен */
|
||||
ROUTE_FLAG_VALIDATED = (1 << 1), /**< Маршрут валидирован */
|
||||
ROUTE_FLAG_ADVERTISED = (1 << 2), /**< Маршрут анонсирован */
|
||||
ROUTE_FLAG_LEARNED = (1 << 3) /**< Маршрут изучен */
|
||||
ROUTE_FLAG_LEARNED = (1 << 1) /**< Маршрут изучен */
|
||||
} route_flags_t;
|
||||
|
||||
|
||||
struct ROUTE_PEER_INFO {
|
||||
uint64_t node_id; // ID узла назначения
|
||||
uint32_t network; // Сетевой адрес (big-endian)
|
||||
uint8_t prefix_length; // Длина префикса подсети
|
||||
uint8_t hop_count; // Количество прыжков (инкриментирует получатель). 0 - локальный маршрут
|
||||
uint16_t latency; // Задержка (x0.1 ms) - суммируется при распространении маршрута
|
||||
} __attribute__((packed));
|
||||
|
||||
struct NODE_CONN_INFO {
|
||||
uint64_t node_id; // ID узла назначения
|
||||
uint32_t endpoint_ip; // IP для прямого подключения
|
||||
uint16_t endpoint_port; // Порт для прямого подключения
|
||||
uint32_t endpoint_ip; // IP для прямого подключения (к nexthop_node_id). 0 - нет IP (если мы - сервер)
|
||||
uint16_t endpoint_port; // Порт для прямого подключения (к nexthop_node_id). 0 - нет PORT (если мы - сервер)
|
||||
uint8_t public_key[64]; // публичный ключ узла (для прямого подключения)
|
||||
} __attribute__((packed));
|
||||
|
||||
struct NODE_CONNS_INFO {
|
||||
uint8_t connlist_count; // число подключений к узлу
|
||||
uint16_t ref_count; // счетчик ссылок с разных route_entry для освобождения
|
||||
struct NODE_CONN_INFO conn_info[0]; // сами подключения
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/**
|
||||
* @brief Расширенные метрики маршрута
|
||||
*
|
||||
* Структура содержит дополнительные метрики для оценки качества маршрута.
|
||||
*/
|
||||
struct ROUTE_METRICS {
|
||||
uint32_t metric; /**< общее качество подсчитанное из метрик (меньше - лучше) */
|
||||
uint32_t bandwidth_kbps; /**< Пропускная способность в Кбит/с */
|
||||
uint16_t packet_loss_rate; /**< Уровень потери пакетов (x0.1%) */
|
||||
uint16_t latency_ms; /**< Задержка в миллисекундах */
|
||||
// uint8_t hop_count; /**< Количество прыжков */
|
||||
uint64_t last_updated; /**< Время последнего обновления (в микросекундах) */
|
||||
struct ETCP_CONN* conn_id; // Указатель на подключение к next_hop, может быть null.
|
||||
// next_hop - это первый элемент в hop_list.
|
||||
// hop list может быть разный для разных подключений. Это надо понимать и учитывать.
|
||||
uint64_t* hop_list; // маршрут до узла (next hop -> ... -> destination_hop): список промежуточных узлов (NODE ID, кол-во - hop_count) включая конечный узел, не включая наш узел. null - локальный маршрут
|
||||
uint8_t hop_count; // Количество узлов до узла назначения. 0 - я (not used), 1 - direct connect (hoplist 1 запись nexthop_node_id = id узла назначения)
|
||||
};
|
||||
|
||||
struct ROUTE_ARRAY {
|
||||
uint32_t capacity;// max число элементов (для realloc)
|
||||
uint32_t routes; /**< число маршрутов в массиве */
|
||||
uint32_t ip; /**< адрес назначения */
|
||||
struct ROUTE_ENTRY* entries[0]; /**< массив указателей на роуты */
|
||||
struct NODE_CONNS_INFO {// Один NODE_CONNS_INFO на один node_id. несколько маршрутов с одинаковым node_id должны ссылаться на один экземпляр NODE_CONNS_INFO.
|
||||
uint64_t node_id; // ID узла назначения. Если = моему ID - локальный маршрут.
|
||||
uint8_t flags; // флаги узла
|
||||
uint8_t preferred_conn; // выбранное соединение (его будем распространять далее по BGP). по умолчанию 0. при изменении conn_info надо за ним присмотреть.
|
||||
uint8_t conninfo_count; // число подключений к узлу
|
||||
uint8_t conninfo_memsize; // размер выделенной памяти (оптимизация realloc)
|
||||
uint16_t ref_count; // счетчик ссылок с разных route_entry для освобождения
|
||||
struct NODE_CONN_INFO conn_info[0]; // сами подключения. управлять памятью своими силами. использовать u_malloc, u_reclloc, u_free (совместимо с stdlib). максимально просто - только увеличиваем при нехватке, не уменьшаем.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -93,27 +59,20 @@ typedef void (*route_change_callback_fn)(struct ROUTE_TABLE* table,
|
||||
* Структура представляет собой отдельную запись в таблице маршрутизации с детальной информацией о маршруте.
|
||||
*/
|
||||
struct ROUTE_ENTRY {
|
||||
struct ROUTE_PEER_INFO peer_info;// сюда перенесли часть полей:
|
||||
// uint32_t network; /**< Сетевой адрес */ moved
|
||||
// uint8_t prefix_length; /**< Длина префикса подсети */ moved
|
||||
struct ETCP_CONN* next_hop; // Указатель на подключение до следующего хопа
|
||||
struct NODE_CONNS_INFO* conn_list; // список прямых подключений к узлу. null если нет прямых подключений.
|
||||
route_type_t type; /**< Тип маршрута */
|
||||
uint8_t flags; /**< Флаги маршрута */
|
||||
struct ROUTE_METRICS metrics; /**< Метрики маршрута */
|
||||
uint64_t created_time; /**< Время создания (в микросекундах) */
|
||||
uint64_t last_update; /**< Время последнего обновления (в микросекундах) */
|
||||
|
||||
// BGP поля - информация о конечном узле для прямого подключения
|
||||
// uint32_t endpoint_ip; /**< IP для прямого подключения (из BGP) */
|
||||
// uint16_t endpoint_port; /**< Порт для прямого подключения (из BGP) */
|
||||
// uint64_t destination_node_id; /**< ID узла назначения (из BGP) */
|
||||
uint32_t network; // Сетевой адрес (big-endian)
|
||||
uint8_t prefix_length; // Длина префикса подсети
|
||||
struct NODE_CONNS_INFO* conn_list; // список прямых подключений к узлу. null если - локальный маршрут.
|
||||
// node_id - в conn_list. Если нет доступных подключений - маршрут удаляем как бесполезный
|
||||
// hop list / hop count - это относится к подключению. может быть разный для разных подключений.
|
||||
uint64_t created_time; /**< Время создания (в timebase - 0.1ms) - use get_time_tb();*/
|
||||
uint64_t last_update; /**< Время последнего обновления (в timebase - 0.1ms) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Таблица маршрутизации
|
||||
*
|
||||
* Структура представляет собой таблицу маршрутизации, содержащую записи маршрутов, подсети и статистику.
|
||||
* маршруты не должны пересекаться. т.е. адрес 192.168.1.1/30 нельзя добавить если есть 192.168.1.2/32 или 192.168.1.1/24
|
||||
*/
|
||||
struct ROUTE_TABLE {
|
||||
struct ROUTE_ENTRY *entries; /**< Массив записей маршрутов */
|
||||
@@ -147,52 +106,55 @@ struct ROUTE_TABLE *route_table_create(void);
|
||||
*/
|
||||
void route_table_destroy(struct ROUTE_TABLE *table);
|
||||
|
||||
/**
|
||||
* @brief Очищает глобальный кеш маршрутов
|
||||
*/
|
||||
void route_cache_clear(void);
|
||||
|
||||
/**
|
||||
* @brief Вставляет новую запись в таблицу маршрутизации
|
||||
*
|
||||
* @param table Указатель на таблицу маршрутизации
|
||||
* @param entry Указатель на вставляемую запись маршрута
|
||||
* @return true если вставка успешна, false иначе
|
||||
* @param entry Указатель на вставляемую запись (conn_list должен быть NULL)
|
||||
* @param conn Соединение (next_hop). NULL = локальный маршрут
|
||||
* @param node_id ID узла-владельца префикса (из пакета BGP)
|
||||
* @param my_node_id Наш собственный node_id (для обнаружения петель, 0 = отключить проверку)
|
||||
* @param hop_list Список хопов (уже с препроцессингом)
|
||||
* @param hop_count Количество хопов
|
||||
* @return true если вставка/обновление успешно
|
||||
*/
|
||||
bool route_table_insert(struct ROUTE_TABLE *table, const struct ROUTE_ENTRY *entry);
|
||||
bool route_insert(struct ROUTE_TABLE *table,
|
||||
const struct ROUTE_ENTRY *entry,
|
||||
struct ETCP_CONN *conn,
|
||||
uint64_t node_id, // владелец префикса
|
||||
uint64_t my_node_id, // наш node_id (для loop detection)
|
||||
uint64_t *hop_list,
|
||||
uint8_t hop_count);
|
||||
|
||||
/** Удаляет конкретное подключение из всех маршрутов (при падении линка) */
|
||||
void route_remove_conn(struct ROUTE_TABLE *table, struct ETCP_CONN *conn);
|
||||
|
||||
/**
|
||||
* @brief Удаляет запись из таблицы маршрутизации
|
||||
* @brief Удаляет один путь (через conn) к указанному node_id.
|
||||
* Используется при получении WITHDRAW от соседа.
|
||||
* Если путей больше не осталось — полностью withdraw + callback(2).
|
||||
* Если изменился preferred_conn — reroute + callback(1).
|
||||
*/
|
||||
bool route_remove_path(struct ROUTE_TABLE *table,
|
||||
struct ETCP_CONN *conn,
|
||||
uint64_t node_id);
|
||||
|
||||
/**
|
||||
* @brief Удаляет все записи из таблицы маршрутизации для указанного узла
|
||||
*
|
||||
* @param table Указатель на таблицу маршрутизации
|
||||
* @param conn соединение все роуты которого надо удалить
|
||||
* @param node_id ID узла, все маршруты которого нужно удалить
|
||||
*/
|
||||
void route_table_delete(struct ROUTE_TABLE *table, struct ETCP_CONN* conn);
|
||||
void route_delete(struct ROUTE_TABLE *table, uint64_t node_id);
|
||||
|
||||
/**
|
||||
* @brief Удаляет конкретный маршрут из таблицы
|
||||
*
|
||||
* @param table Указатель на таблицу маршрутизации
|
||||
* @param network Сетевой адрес
|
||||
* @param prefix_length Длина префикса подсети
|
||||
* @param next_hop Указатель на соединение (NULL = любой next_hop)
|
||||
* @return true если маршрут найден и удален, false если не найден
|
||||
*/
|
||||
bool route_table_delete_entry(struct ROUTE_TABLE *table, uint32_t network,
|
||||
uint8_t prefix_length, struct ETCP_CONN* next_hop);
|
||||
|
||||
/**
|
||||
* @brief Выполняет поиск доступных маршрутов для заданного IP-адреса, отсортированных по quality
|
||||
* при поиске ищет готовый результат в кеше или добавляет в кеш новый результат и возвращает запись из кеша
|
||||
* @brief Выполняет поиск маршрута для заданного IP-адреса
|
||||
*
|
||||
* @param table Указатель на таблицу маршрутизации
|
||||
* @param dest_ip Целевой IP-адрес
|
||||
* @return структура с найденными маршрутами
|
||||
* @return найденный маршрут или NULL
|
||||
*/
|
||||
struct ROUTE_ARRAY* route_table_lookup(struct ROUTE_TABLE *table, uint32_t dest_ip);
|
||||
|
||||
// пересчитывает quality на основе других метрик (rtt, %loss, hopcount). чем меньше quality - тем лучше
|
||||
bool route_update_quality(struct ROUTE_ENTRY *entry);
|
||||
struct ROUTE_ENTRY* route_lookup(struct ROUTE_TABLE *table, uint32_t dest_ip);
|
||||
|
||||
/**
|
||||
* @brief Печатает содержимое таблицы маршрутизации
|
||||
@@ -201,7 +163,7 @@ bool route_update_quality(struct ROUTE_ENTRY *entry);
|
||||
*/
|
||||
void route_table_print(const struct ROUTE_TABLE *table);
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief Парсит строку подсети в сетевой адрес и длину префикса
|
||||
*
|
||||
* @param subnet_str Строка подсети (например, "192.168.1.0/24")
|
||||
@@ -211,37 +173,4 @@ void route_table_print(const struct ROUTE_TABLE *table);
|
||||
*/
|
||||
int parse_subnet(const char *subnet_str, uint32_t *network, uint8_t *prefix_length);
|
||||
|
||||
/**
|
||||
* @brief Добавляет диапазон динамических подсетей для валидации
|
||||
*
|
||||
* @param table Указатель на таблицу маршрутизации
|
||||
* @param network Сетевой адрес
|
||||
* @param prefix_length Длина префикса
|
||||
* @return true при успехе, false при ошибке
|
||||
*/
|
||||
bool route_add_dynamic_subnet(struct ROUTE_TABLE *table, uint32_t network, uint8_t prefix_length);
|
||||
|
||||
/**
|
||||
* @brief Добавляет диапазон локальных подсетей для валидации
|
||||
*
|
||||
* @param table Указатель на таблицу маршрутизации
|
||||
* @param network Сетевой адрес
|
||||
* @param prefix_length Длина префикса
|
||||
* @return true при успехе, false при ошибке
|
||||
*/
|
||||
bool route_add_local_subnet(struct ROUTE_TABLE *table, uint32_t network, uint8_t prefix_length);
|
||||
|
||||
/**
|
||||
* @brief Получает все маршруты для указанной подсети
|
||||
*
|
||||
* @param table Указатель на таблицу маршрутизации
|
||||
* @param network Сетевой адрес
|
||||
* @param prefix_length Длина префикса
|
||||
* @param routes Указатель для сохранения массива маршрутов (выделяется calloc)
|
||||
* @param count Указатель для сохранения количества маршрутов
|
||||
* @return true при успехе, false при ошибке
|
||||
*/
|
||||
bool route_get_all_routes(const struct ROUTE_TABLE *table, uint32_t network, uint8_t prefix_length,
|
||||
struct ROUTE_ENTRY **routes, size_t *count);
|
||||
|
||||
#endif // ROUTE_LIB_H
|
||||
+25
-6
@@ -1,7 +1,26 @@
|
||||
internal_routing.c/h:
|
||||
В таблице роутинга маршруты не пересекаются. Т.е. не может быть одновременно 192.168.1.1/24 и 192.168.1.100/30
|
||||
|
||||
это модуль роутинга пакетов.
|
||||
пакеты приходят:
|
||||
1. из очередей ETCP (struct ETCP_CONN output_queue).
|
||||
при добавлении подключения (из конфига)) в вызовы etcp_connection_create/close надо добавить
|
||||
2. из tun интерфейса
|
||||
Как работает роутинг:
|
||||
1. типов маршрута бывает два: learned и local.
|
||||
local - локальные маршруты из конфига (опция конфига my_subnet=IP/Mask)
|
||||
при инициализации они сразу добавляются в роутинг таблицу (и используются для отправки пакетов в tun интерфейс).
|
||||
|
||||
2. При установке подключения к новому узлу мы отправляем этому узлу полностью свою таблицу маршрутизации (local + learned узлы). Если несколько доступных линков - отправляем только один - preferred_conn
|
||||
3. При изменении preferred_conn рассылаем reroute (например старый preferred_conn удален)
|
||||
3. При удалении всех подключений рассылаем withdraw.
|
||||
|
||||
3. При получении маршрута мы смотрим есть ли такой маршрут уже в таблице. Если такой маршрут есть и ID узла другой - игнорируем с ошибкой. иначе добавляем/обновляем (для одного узла может быть несколько маршрутов). Игнорируем маршрут если наш ID есть в списке узлов (hop_list).
|
||||
Добавляем так:
|
||||
инкрементируем hop_count
|
||||
устанавливая etcp линк с которого приняли как next_hop, добавляем его в hop_list.
|
||||
рассылаем по всем активным линкам кроме линка с которого получили (обязательно)
|
||||
Обновление: обновляем hop_list если поменялся
|
||||
|
||||
4. При отключении от узла мы
|
||||
Удаляем все маршруты узла
|
||||
Рассылаем withdraw для узла hop_id.
|
||||
|
||||
Логика рассылки withdraw:
|
||||
Если получен withdraw - удаляем этот маршрут и распространяем withdraw или reroute по всем линкам кроме того с которого получили. В зависимости от изменений (остались ли резервные линки или изменился preferred_conn).
|
||||
|
||||
Метрик маршрута пока нет. используется первый доступный.
|
||||
+9
-6
@@ -112,8 +112,8 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_pkt: dst=%s len=%zu", ip_to_str(&addr, AF_INET).str, ip_len);
|
||||
|
||||
// Lookup route
|
||||
struct ROUTE_ARRAY* routes = route_table_lookup(instance->rt, dst_ip);
|
||||
if (!routes || routes->routes == 0) {
|
||||
struct ROUTE_ENTRY* route = route_lookup(instance->rt, dst_ip);
|
||||
if (!route) {
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "route_pkt: no route to %s, dropping", ip_to_str(&addr, AF_INET).str);
|
||||
instance->dropped_packets++;
|
||||
queue_entry_free(entry);
|
||||
@@ -121,8 +121,8 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check route type
|
||||
if (routes->entries[0]->type == ROUTE_TYPE_LOCAL) {
|
||||
// Check route type: conn_list == NULL means local route
|
||||
if (route->conn_list == NULL) {
|
||||
// Local route - send to TUN (entry has [cmd=0][IP data], TUN skips cmd byte)
|
||||
int put_err = queue_data_put(instance->tun->input_queue, entry, 0);
|
||||
if (put_err != 0) {
|
||||
@@ -139,8 +139,11 @@ static void route_pkt(struct UTUN_INSTANCE* instance, struct ll_entry* entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Learned route - use next_hop
|
||||
struct ETCP_CONN* conn = routes->entries[0]->next_hop;
|
||||
// Learned route - use first conn from conn_list
|
||||
struct ETCP_CONN* conn = NULL;
|
||||
if (route->conn_list->conninfo_count > 0) {
|
||||
conn = route->conn_list->conn_info[0].conn_id;
|
||||
}
|
||||
if (!conn) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "route_pkt: route to %s has no next_hop, dropping", ip_to_str(&addr, AF_INET).str);
|
||||
instance->dropped_packets++;
|
||||
|
||||
+7
-15
@@ -70,27 +70,19 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u
|
||||
struct CFG_ROUTE_ENTRY* subnet = config->my_subnets;
|
||||
while (subnet) {
|
||||
struct ROUTE_ENTRY entry = {0};
|
||||
entry.peer_info.network = ntohl(subnet->ip.addr.v4.s_addr); // Convert network byte order to host
|
||||
entry.peer_info.prefix_length = subnet->netmask;
|
||||
entry.next_hop = NULL; // Local route
|
||||
entry.type = ROUTE_TYPE_LOCAL;
|
||||
entry.flags = ROUTE_FLAG_ACTIVE | ROUTE_FLAG_VALIDATED;
|
||||
entry.metrics.bandwidth_kbps = UINT32_MAX; // Unlimited
|
||||
entry.metrics.latency_ms = 0;
|
||||
entry.metrics.packet_loss_rate = 0;
|
||||
entry.peer_info.hop_count = 0;
|
||||
entry.peer_info.node_id = instance->node_id;
|
||||
entry.network = ntohl(subnet->ip.addr.v4.s_addr); // Convert network byte order to host
|
||||
entry.prefix_length = subnet->netmask;
|
||||
|
||||
if (route_table_insert(instance->rt, &entry)) {
|
||||
if (route_insert(instance->rt, &entry, NULL, 0, 0, NULL, 0)) {
|
||||
struct in_addr addr;
|
||||
addr.s_addr = htonl(entry.peer_info.network);
|
||||
addr.s_addr = htonl(entry.network);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "Added local route: %s/%d",
|
||||
ip_to_str(&addr, AF_INET).str, entry.peer_info.prefix_length);
|
||||
ip_to_str(&addr, AF_INET).str, entry.prefix_length);
|
||||
} else {
|
||||
struct in_addr addr;
|
||||
addr.s_addr = htonl(entry.peer_info.network);
|
||||
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.peer_info.prefix_length);
|
||||
ip_to_str(&addr, AF_INET).str, entry.prefix_length);
|
||||
}
|
||||
|
||||
subnet = subnet->next;
|
||||
|
||||
Reference in new issue
Block a user