Browse Source

etcp - добавлено etcp_on_conn_ready callback_fn

+ trace + по мелочи
nodeinfo-routing-update
jeka 3 weeks ago
parent
commit
33629a17c6
  1. 30
      src/etcp.c
  2. 16
      src/etcp.h
  3. 35
      src/etcp_api.c
  4. 34
      src/etcp_api.h
  5. 34
      src/etcp_connections.c
  6. 3
      src/pkt_normalizer.c
  7. 144
      src/route_bgp.c
  8. 87
      src/route_lib.c
  9. 5
      src/utun_instance.h

30
src/etcp.c

@ -127,6 +127,7 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) {
etcp->inflight_pool = memory_pool_init(sizeof(struct INFLIGHT_PACKET));
etcp->io_pool = memory_pool_init(sizeof(struct ETCP_FRAGMENT));
etcp->optimal_inflight=10000;
etcp->initialized=0;
// Initialize log_name with local node_id (peer will be updated later when known)
snprintf(etcp->log_name, sizeof(etcp->log_name), "%04X->????", (uint16_t)instance->node_id);
@ -160,16 +161,19 @@ struct ETCP_CONN* etcp_connection_create(struct UTUN_INSTANCE* instance) {
queue_set_callback(etcp->input_wait_ack, wait_ack_cb, etcp);
etcp->link_ready_for_send_fn = etcp_link_ready_callback;
// Register with routing module (must be done after normalizer is assigned)
routing_add_conn(etcp);
DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "[%s] connection initialized. ETCP=%p mtu=%d, next_tx_id=%u",
etcp->log_name, etcp, etcp->mtu, etcp->next_tx_id);
// Вызываем callback для нового соединения если установлен
if (instance && instance->etcp_new_conn_cbk) {
instance->etcp_new_conn_cbk(etcp, instance->etcp_new_conn_arg);
}
return etcp;
}
// Close connection with NULL pointer safety (prevents double free)
void etcp_connection_close(struct ETCP_CONN* etcp) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
@ -298,12 +302,14 @@ void etcp_conn_reset(struct ETCP_CONN* etcp) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "end");
}
void etcp_conn_reinit(struct ETCP_CONN* etcp) {
void etcp_conn_reinit(struct ETCP_CONN* etcp) {// Если сбой в обмене или ребутнулась одна из сторон -> необходимо заново переинициализировать соединение
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "Reinitializing ETCP connection [%s]", etcp->log_name);
etcp->reinit_count++;
etcp->initialized = 0;
// Сбрасываем initialized во всех линках
struct ETCP_LINK* link = etcp->links;
while (link) {
@ -317,6 +323,22 @@ void etcp_conn_reinit(struct ETCP_CONN* etcp) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "end");
}
// внутренняя функция. Вызывается стеком etcp когда соединение установлено (можно передавать данные)
void etcp_conn_ready(struct ETCP_CONN* conn) {
if (!conn) return;
conn->initialized = 1;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "[%s] Connection ready", conn->log_name);
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "etcp_conn_ready: conn=%p initialized=%d cbk=%p",
(void*)conn, conn->initialized, (void*)conn->ready_cbk);
// Вызываем callback если установлен
if (conn->ready_cbk) {
conn->ready_cbk(conn, conn->ready_arg);
}
}
// Update log_name when peer_node_id becomes known
void etcp_update_log_name(struct ETCP_CONN* etcp) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "");

16
src/etcp.h

@ -18,6 +18,8 @@ extern "C" {
// Forward declarations
struct UTUN_INSTANCE;
struct ETCP_CONN;
typedef void (*etcp_on_conn_ready)(struct ETCP_CONN* conn, void* arg);
struct UASYNC;
uint16_t get_current_timestamp(void);
@ -143,8 +145,13 @@ struct ETCP_CONN {
// uint32_t total_packets_sent; // Total packets sent counter - Not used
// Flags
uint8_t routing_exchange_active; // 0 - не активен, 1 - надо инициировать обмен маршрутами (клиент), 2 - обмен маршрутами активен
uint8_t got_initial_pkt; //
uint8_t routing_exchange_active; // 0 - не активен, 1 - надо инициировать обмен маршрутами (клиент), 2 - обмен маршрутами активен
uint8_t got_initial_pkt; //
uint8_t initialized; // 0 - только созданный ETCP, 1 - хотя бы один линк проинициалзирован (обмен ключами произведен)
// Callback for ready notification
etcp_on_conn_ready ready_cbk; // callback при готовности соединения
void* ready_arg; // аргумент для ready_cbk
uint32_t cnt_ack_hit_inf; // счетчик удлений из inflight
uint32_t cnt_ack_hit_sndq; // счетчик удалений inflight пакетов из sndq
@ -165,6 +172,8 @@ void etcp_conn_reset(struct ETCP_CONN* etcp);
void etcp_conn_reinit(struct ETCP_CONN* etcp);
void etcp_connection_ready(struct ETCP_CONN* etcp);// вызывается когда подключение инициализировано
// Отправка: используем api ll_queue для очереди ETCP_CONN.input_queue
// Прием: используем api ll_queue для очереди ETCP_CONN.output_queue
// для очередей используется формат
@ -186,6 +195,9 @@ void etcp_ack_recv(struct ETCP_CONN* etcp, uint32_t seq, uint16_t ts, uint16_t d
// Update log_name when peer_node_id becomes known
void etcp_update_log_name(struct ETCP_CONN* etcp);
// Вызывается стеком etcp когда соединение установлено (можно передавать данные)
void etcp_conn_ready(struct ETCP_CONN* conn);
#ifdef __cplusplus
}
#endif

35
src/etcp_api.c

@ -9,11 +9,46 @@
#include "utun_instance.h"
#include "../lib/debug_config.h"
#include <string.h>
#include "route_lib.h"
#include "route_bgp.h"
typedef void (*etcp_on_conn_ready)(struct ETCP_CONN* conn, void* arg);
#define DEBUG_CATEGORY_ETCP_API 1
#define ETCP_MAX_BINDINGS 256 /**< Максимальное количество bindings (по одному на каждый ID 0-255) */
// после создания подключения надо выждать conn_ready. только после этого можно передавать сообщения. Иначе сообщения могут потеряться.
// conn_ready может вызваться несколько раз (после каждого переподключения - например когда удаленный узел перегрузился или возникла неустранимая ошибка).
void etcp_conn_set_ready_cbk(struct ETCP_CONN* conn, etcp_on_conn_ready callback_fn, void* arg) {
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_conn_set_ready_cbk: NULL conn");
return;
}
conn->ready_cbk = callback_fn;
conn->ready_arg = arg;
DEBUG_TRACE(DEBUG_CATEGORY_ETCP_API, "etcp_conn_set_ready_cbk: conn=%p cbk=%p arg=%p",
(void*)conn, (void*)callback_fn, arg);
// Если соединение уже готово - сразу вызываем callback
if (conn->initialized && callback_fn) {
DEBUG_TRACE(DEBUG_CATEGORY_ETCP_API, "etcp_conn_set_ready_cbk: calling callback immediately (already initialized)");
callback_fn(conn, arg);
}
}
// Установить callback при создании нового ETCP соединения
void etcp_set_new_conn_cbk(struct UTUN_INSTANCE* instance, etcp_new_conn_fn callback_fn, void* arg) {
if (!instance) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_set_new_conn_cbk: NULL instance");
return;
}
instance->etcp_new_conn_cbk = callback_fn;
instance->etcp_new_conn_arg = arg;
DEBUG_TRACE(DEBUG_CATEGORY_ETCP_API, "etcp_set_new_conn_cbk: instance=%p cbk=%p arg=%p",
(void*)instance, (void*)callback_fn, arg);
}
int etcp_bind(struct UTUN_INSTANCE* inst, uint8_t id, etcp_recv_fn callback) {
if (!inst) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP_API, "etcp_bind: NULL instance");

34
src/etcp_api.h

@ -38,6 +38,27 @@ struct UTUN_INSTANCE;
*/
typedef void (*etcp_recv_fn)(struct ETCP_CONN* conn, struct ll_entry* entry);
// Forward declaration
struct ETCP_CONN;
struct UTUN_INSTANCE;
typedef void (*etcp_new_conn_fn)(struct ETCP_CONN* conn, void* arg);
/**
* @brief Тип коллбэка для уведомления о готовности соединения к передаче данных
* @param conn ETCP соединение которое стало готово
* @param arg Пользовательский аргумент
*/
typedef void (*etcp_on_conn_ready)(struct ETCP_CONN* conn, void* arg);
/**
* @brief Установить callback при создании нового ETCP соединения
*
* @param instance UTUN instance
* @param callback_fn Коллбэк который будет вызван при создании нового соединения
* @param arg Аргумент для коллбэка
*/
void etcp_set_new_conn_cbk(struct UTUN_INSTANCE* instance, etcp_new_conn_fn callback_fn, void* arg);
/**
* @brief Структура bindings для ETCP API (per-instance)
*/
@ -79,6 +100,19 @@ int etcp_bind(struct UTUN_INSTANCE* inst, uint8_t id, etcp_recv_fn callback);
*/
int etcp_unbind(struct UTUN_INSTANCE* inst, uint8_t id);
/**
* @brief Установить callback на событие готовности соединения
*
* После создания подключения надо дождаться conn_ready (соединение инициализировано).
* Только после этого можно передавать сообщения. Иначе сообщения могут потеряться.
* conn_ready может вызываться несколько раз (после каждого переподключения).
*
* @param conn ETCP соединение
* @param callback_fn Коллбэк который будет вызван при готовности
* @param arg Аргумент для коллбэка
*/
void etcp_conn_set_ready_cbk(struct ETCP_CONN* conn, etcp_on_conn_ready callback_fn, void* arg);
/**
* @brief Внутренняя функция etcp: Коллбэк для очередей output ll_queue normalizer
*

34
src/etcp_connections.c

@ -6,8 +6,6 @@
#endif
#include <unistd.h>
#include <string.h>
#include "route_lib.h"
#include "route_bgp.h"
#include "utun_instance.h"
#include "config_parser.h"
#include "crc32.h"
@ -887,18 +885,18 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
struct ETCP_LINK* existing_link = etcp_link_find_by_addr(e_sock, &addr);
uint8_t send_reset = 0;
if (existing_link && existing_link->etcp == conn) {
if (existing_link && existing_link->etcp == conn) {// существующий линк
// Link exists - reuse it for recovery
link = existing_link;
link->remote_link_id = ack_hdr->link_id;
// For CHANNEL_INIT (0x04): if link already initialized - no reset, otherwise reset
// For INIT_REQUEST (0x02): always reset
if (ack_hdr->code == ETCP_INIT_REQUEST_NOINIT && link->initialized) {
if (ack_hdr->code == ETCP_INIT_REQUEST_NOINIT && conn->initialized) {
send_reset = 0; // Link is up, respond without reset
} else {
send_reset = 1; // INIT_REQUEST (0x02) or uninitialized link - send reset
etcp_conn_reset(conn);
etcp_conn_reinit(conn);
}
// Cancel existing timers
@ -914,7 +912,8 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
// For new links: INIT_REQUEST (0x02) causes reset, CHANNEL_INIT (0x04) does not
if (ack_hdr->code == ETCP_INIT_REQUEST) {
etcp_conn_reset(conn);
send_reset = 1; // INIT_REQUEST (0x02) or uninitialized link - send reset
etcp_conn_reinit(conn);
}
link->keepalive_interval=(ack_hdr->keepalive[0]<<8) | ack_hdr->keepalive[1];
link->recovery_interval=((ack_hdr->recovery[0]<<8) | ack_hdr->recovery[1])*100;// timebase в link, timebase/100 в кодограмме
@ -967,6 +966,10 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
memory_pool_free(e_sock->instance->pkt_pool, pkt);
link->initialized = 1;// получен init request (server), считаем линк уже готовым к работе
if (link->etcp->initialized == 0) {
link->etcp->initialized = 1;
etcp_conn_ready(link->etcp);
}
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) initialized and marked as UP (server)",
link->etcp->log_name, link, link->local_link_id);
@ -980,12 +983,7 @@ static void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
}
loadbalancer_link_ready(link);
// Notify BGP about new connection to send routing table
if (link->etcp && link->etcp->instance && link->etcp->instance->bgp) {
route_bgp_new_conn(link->etcp);
}
return;
process_decrypted:
@ -1029,7 +1027,7 @@ process_decrypted:
// Parse response
// ETCP_INIT_RESPONSE (0x03) - reset entire ETCP_CONN
// ETCP_INIT_RESPONSE_NOINIT (0x05) - no reset
if (code == ETCP_INIT_RESPONSE) etcp_conn_reset(link->etcp);
if (code == ETCP_INIT_RESPONSE) etcp_conn_reinit(link->etcp);
uint64_t server_node_id = 0;
for (int i = 0; i < 8; i++) {
server_node_id = (server_node_id << 8) | pkt->data[offset++];
@ -1086,6 +1084,11 @@ process_decrypted:
// DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Setting link->initialized=1, link=%p, is_server=%d", link, link->is_server);
link->initialized = 1;// получен init response (client)
// link->link_status = 1; // Link is up after successful initialization
if (link->etcp->initialized == 0) {
link->etcp->initialized = 1;
etcp_conn_ready(link->etcp);
}
loadbalancer_link_ready(link);
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "[%s] Link %p (local_id=%d) initialized and marked as UP (client): rk=%d lk=%d up=%d ki=%d",
link->etcp->log_name, link, link->local_link_id, link->recv_keepalive, link->remote_keepalive, link->link_status, link->keepalive_interval);
@ -1102,11 +1105,6 @@ process_decrypted:
loadbalancer_link_ready(link);
// Notify BGP about new connection to send routing table
if (link->etcp && link->etcp->instance && link->etcp->instance->bgp) {
route_bgp_new_conn(link->etcp);
}
DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "etcp client: Link initialized successfully! Server node_id=%llu, mtu=%d, local_link_id=%d, remote_link_id=%d", (unsigned long long)server_node_id, link->mtu, link->local_link_id, link->remote_link_id);
// Cancel init timer if exists

3
src/pkt_normalizer.c

@ -276,7 +276,8 @@ static void pn_buf_renew(struct PKTNORM* pn) {
// Internal: Process input when etcp->input_queue is ready (empty)
static void etcp_input_ready_cb(struct ll_queue* q, void* arg) {
struct PKTNORM* pn = (struct PKTNORM*)arg;
if (!pn) return;
if (!pn || !pn->etcp) return;
// if (pn->etcp->initialized==0) return;// начинаем обработку очередей только когда готов etcp
DEBUG_TRACE(DEBUG_CATEGORY_NORMALIZER, "before get");
struct ll_entry* in_dgram = queue_data_get(pn->input);

144
src/route_bgp.c

@ -17,8 +17,6 @@
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#define DEBUG_CATEGORY_BGP 1
// ============================================================================
// Вспомогательные функции
// ============================================================================
@ -87,21 +85,38 @@ static void route_bgp_send_route(struct ROUTE_BGP* bgp, struct ETCP_CONN* conn,
static void route_bgp_broadcast_route(struct ROUTE_BGP* bgp, const struct ROUTE_ENTRY* route,
struct ETCP_CONN* exclude, uint8_t subcmd) {
if (!bgp || !route) return;
if (!bgp) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_broadcast_route: bgp is NULL");
return;
}
if (!route) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_broadcast_route: route is NULL");
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_broadcast_route: network=%08X prefix=%d exclude=%p subcmd=%d",
route->network, route->prefix_length, (void*)exclude, subcmd);
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, subcmd);
sent_count++;
}
entry = entry->next;
}
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_broadcast_route: sent to %d peers", sent_count);
}
static void route_bgp_broadcast_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id,
struct ETCP_CONN* exclude) {
if (!bgp) return;
if (!bgp) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_broadcast_withdraw: bgp is NULL");
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_broadcast_withdraw: node_id=%llu exclude=%p",
(unsigned long long)node_id, (void*)exclude);
struct BGP_WITHDRAW_PACKET* pkt = u_calloc(1, sizeof(struct BGP_WITHDRAW_PACKET));
if (!pkt) return;
@ -161,13 +176,22 @@ static void route_bgp_on_route_change(struct ROUTE_TABLE* table,
// ============================================================================
static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry* entry) {
if (!from_conn || !entry || entry->len < 2) {
if (!from_conn) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_receive_cbk: from_conn is NULL");
if (entry) { queue_dgram_free(entry); queue_entry_free(entry); }
return;
}
if (!entry || entry->len < 2) {
if (entry) { queue_dgram_free(entry); queue_entry_free(entry); }
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_receive_cbk: from=%llu len=%zu",
(unsigned long long)from_conn->peer_node_id, entry->len);
struct UTUN_INSTANCE* instance = from_conn->instance;
if (!instance || !instance->rt || !instance->bgp) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_receive_cbk: invalid instance/rt/bgp");
queue_dgram_free(entry); queue_entry_free(entry);
return;
}
@ -212,6 +236,8 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
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);
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_receive_cbk: UPDATE network=%08X prefix=%d owner=%llu",
network, prefix, (unsigned long long)owner_node_id);
struct ROUTE_ENTRY new_route = {0};
new_route.network = network;
@ -226,6 +252,9 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
if (!inserted) {
DEBUG_WARN(DEBUG_CATEGORY_BGP, "Route insert rejected (loop/overlap/owner conflict)");
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_receive_cbk: REJECTED");
} else {
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_receive_cbk: INSERTED");
}
} else if (subcmd == ROUTE_SUBCMD_WITHDRAW) {
@ -237,6 +266,7 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
uint64_t node_id = be64toh(wp->node_id);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Received WITHDRAW for node %016llx", (unsigned long long)node_id);
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_receive_cbk: WITHDRAW node_id=%llu", (unsigned long long)node_id);
// === ИСПРАВЛЕНИЕ: поддержка резервных путей ===
route_remove_path(instance->rt, from_conn, node_id);
@ -251,17 +281,42 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
// Init / Destroy / New / Remove conn
// ============================================================================
// Callback для готовности ETCP соединения - отправляет маршруты
static void route_bgp_on_conn_ready(struct ETCP_CONN* conn, void* arg) {
(void)arg;
if (conn && conn->instance && conn->instance->bgp) {
route_bgp_new_conn(conn);
}
}
// Callback для новых ETCP соединений - устанавливает ready callback
static void route_bgp_etcp_conn_cbk(struct ETCP_CONN* conn, void* arg) {
(void)arg;
if (conn && conn->instance && conn->instance->bgp) {
etcp_conn_set_ready_cbk(conn, route_bgp_on_conn_ready, conn->instance->bgp);
}
}
struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance) {
if (!instance) return NULL;
if (!instance) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: instance is NULL");
return NULL;
}
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_init: node_id=%llu", (unsigned long long)instance->node_id);
struct ROUTE_BGP* bgp = u_calloc(1, sizeof(struct ROUTE_BGP));
if (!bgp) return NULL;
if (!bgp) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: alloc failed");
return NULL;
}
bgp->instance = instance;
bgp->senders_list = queue_new(instance->ua, 0, "BGP_senders");
if (!bgp->senders_list) {
u_free(bgp);
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_init: queue_new failed");
return NULL;
}
@ -272,12 +327,25 @@ struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance) {
instance->rt->change_callback_arg = bgp;
}
// Устанавливаем callback для новых ETCP соединений
etcp_set_new_conn_cbk(instance, route_bgp_etcp_conn_cbk, NULL);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "BGP module initialized (with hop_list support)");
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_init: DONE");
return bgp;
}
void route_bgp_destroy(struct UTUN_INSTANCE* instance) {
if (!instance || !instance->bgp) return;
if (!instance) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_destroy: instance is NULL");
return;
}
if (!instance->bgp) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_destroy: bgp is NULL");
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_destroy: node_id=%llu", (unsigned long long)instance->node_id);
etcp_unbind(instance, ETCP_ID_ROUTE_ENTRY);
@ -298,27 +366,69 @@ void route_bgp_destroy(struct UTUN_INSTANCE* instance) {
}
void route_bgp_new_conn(struct ETCP_CONN* conn) {
if (!conn || !conn->instance || !conn->instance->bgp) return;
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn is NULL");
return;
}
if (!conn->instance) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn->instance is NULL");
return;
}
if (!conn->instance->bgp) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn->instance->bgp is NULL");
return;
}
if (!conn->instance->rt) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_new_conn: conn->instance->rt is NULL");
return;
}
struct ROUTE_BGP* bgp = conn->instance->bgp;
struct ROUTE_TABLE* rt = conn->instance->rt;
struct ll_entry* item_entry = queue_entry_new(sizeof(struct ROUTE_BGP_CONN_ITEM));
if (!item_entry) return;
// === 1. Проверяем, уже есть ли это соединение в списке ===
bool already_exists = false;
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) {
already_exists = true;
break;
}
e = e->next;
}
((struct ROUTE_BGP_CONN_ITEM*)item_entry->data)->conn = conn;
queue_data_put(bgp->senders_list, item_entry, 0);
// === 2. Если нет — добавляем (только один раз) ===
if (!already_exists) {
struct ll_entry* item_entry = queue_entry_new(sizeof(struct ROUTE_BGP_CONN_ITEM));
if (!item_entry) return;
// Отправляем полную таблицу (только preferred пути)
struct ROUTE_TABLE* rt = conn->instance->rt;
((struct ROUTE_BGP_CONN_ITEM*)item_entry->data)->conn = conn;
queue_data_put(bgp->senders_list, item_entry, 0);
DEBUG_INFO(DEBUG_CATEGORY_BGP, "New connection added to senders_list");
}
// === 3. В любом случае отправляем полную таблицу (это и нужно при переподключении) ===
for (size_t i = 0; i < rt->count; i++) {
route_bgp_send_route(bgp, conn, &rt->entries[i], ROUTE_SUBCMD_ENTRY);
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sent full routing table to new connection");
DEBUG_INFO(DEBUG_CATEGORY_BGP, "Sent full routing table to %s (reconnect OK)",
conn->log_name);
}
void route_bgp_remove_conn(struct ETCP_CONN* conn) {
if (!conn || !conn->instance || !conn->instance->bgp) return;
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: conn is NULL");
return;
}
if (!conn->instance || !conn->instance->bgp) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: invalid instance/bgp");
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_BGP, "route_bgp_remove_conn: peer=%llu", (unsigned long long)conn->peer_node_id);
struct ROUTE_BGP* bgp = conn->instance->bgp;
struct ROUTE_TABLE* rt = conn->instance->rt;

87
src/route_lib.c

@ -3,16 +3,13 @@
#include "../lib/debug_config.h"
#include "../lib/mem.h"
#include "../lib/platform_compat.h"
#include "../lib/u_async.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define INITIAL_CAPACITY 100
#define CONN_INFO_INIT_SIZE 4 // было 2 — теперь чуть больше
#define DEBUG_CATEGORY_ROUTING 1
#define CONN_INFO_INIT_SIZE 4
// ============================================================================
// Вспомогательные функции (без изменений)
@ -330,7 +327,11 @@ struct ROUTE_TABLE *route_table_create(void) {
}
void route_table_destroy(struct ROUTE_TABLE *table) {
if (!table) return;
if (!table) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_table_destroy: table is NULL");
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_table_destroy: count=%zu", table->count);
// Правильно освобождаем NODE_CONNS_INFO с учётом ref_count
// (один info может быть у нескольких префиксов)
@ -363,7 +364,16 @@ bool route_insert(struct ROUTE_TABLE *table,
uint64_t *hop_list,
uint8_t hop_count) {
if (!table || !entry) return false;
if (!table) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_insert: table is NULL");
return false;
}
if (!entry) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_insert: entry is NULL");
return false;
}
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_insert: network=%08X prefix=%d conn=%p node_id=%llu",
entry->network, entry->prefix_length, (void*)conn, (unsigned long long)node_id);
// === 0. Loop prevention — ВСЕГДА (исправление проблемы #3) ===
if (conn && my_node_id && hop_list && hop_count > 0) {
@ -372,6 +382,7 @@ bool route_insert(struct ROUTE_TABLE *table,
char ip_str[16];
ip_to_string(entry->network, ip_str);
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Loop detected: %s/%d", ip_str, entry->prefix_length);
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_insert: REJECTED (loop detected)");
return false;
}
}
@ -389,6 +400,7 @@ bool route_insert(struct ROUTE_TABLE *table,
char ip_str[16];
ip_to_string(entry->network, ip_str);
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Route conflict (different owner): %s/%d", ip_str, entry->prefix_length);
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_insert: REJECTED (conflict)");
return false;
}
@ -397,6 +409,7 @@ bool route_insert(struct ROUTE_TABLE *table,
existing->last_update = get_time_tb();
if (table->change_callback)
table->change_callback(table, existing, 1, table->change_callback_arg);
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_insert: UPDATED local route %08X/%d", entry->network, entry->prefix_length);
return true;
}
@ -404,7 +417,10 @@ bool route_insert(struct ROUTE_TABLE *table,
struct NODE_CONNS_INFO *info = existing->conn_list;
bool needs_reroute = false; // не используется здесь, но нужен для сигнатуры
info = node_conns_info_add(table, info, 0, 0, NULL, conn, hop_list, hop_count, &needs_reroute);
if (!info) return false;
if (!info) {
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_insert: FAILED (node_conns_info_add)");
return false;
}
existing->conn_list = info;
existing->last_update = get_time_tb();
@ -412,6 +428,8 @@ bool route_insert(struct ROUTE_TABLE *table,
if (table->change_callback)
table->change_callback(table, existing, 1, table->change_callback_arg);
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_insert: UPDATED learned route %08X/%d node_id=%llu",
entry->network, entry->prefix_length, (unsigned long long)node_id);
return true;
}
@ -421,6 +439,7 @@ bool route_insert(struct ROUTE_TABLE *table,
char ip_str[16];
ip_to_string(entry->network, ip_str);
DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "Route overlap rejected: %s/%d", ip_str, entry->prefix_length);
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_insert: REJECTED (overlap)");
return false;
}
@ -428,7 +447,10 @@ bool route_insert(struct ROUTE_TABLE *table,
if (table->count >= table->capacity) {
uint32_t new_cap = table->capacity * 2;
struct ROUTE_ENTRY *new_entries = u_realloc(table->entries, new_cap * sizeof(struct ROUTE_ENTRY));
if (!new_entries) return false;
if (!new_entries) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_insert: realloc failed");
return false;
}
table->entries = new_entries;
table->capacity = new_cap;
}
@ -487,12 +509,22 @@ bool route_insert(struct ROUTE_TABLE *table,
conn ? "learned" : "local", ip_str, entry->prefix_length,
(unsigned long long)node_id);
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_insert: INSERTED %s %08X/%d",
conn ? "learned" : "local", entry->network, entry->prefix_length);
return true;
}
/* ====================== НОВАЯ ФУНКЦИЯ ====================== */
void route_remove_conn(struct ROUTE_TABLE *table, struct ETCP_CONN *conn) {
if (!table || !conn) return;
if (!table) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_remove_conn: table is NULL");
return;
}
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_remove_conn: conn is NULL");
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_remove_conn: conn=%p", (void*)conn);
struct NODE_CONNS_INFO* affected[512];
bool needs_reroute[512] = {0};
@ -556,22 +588,38 @@ void route_remove_conn(struct ROUTE_TABLE *table, struct ETCP_CONN *conn) {
}
DEBUG_INFO(DEBUG_CATEGORY_ROUTING, "route_remove_conn: processed %zu nodes", aff_count);
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_remove_conn: DONE");
}
/* ====================== НОВАЯ ФУНКЦИЯ ДЛЯ WITHDRAW ====================== */
bool route_remove_path(struct ROUTE_TABLE *table,
struct ETCP_CONN *conn,
uint64_t node_id) {
if (!table || !conn) return false;
if (!table) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_remove_path: table is NULL");
return false;
}
if (!conn) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_remove_path: conn is NULL");
return false;
}
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_remove_path: node_id=%llu conn=%p",
(unsigned long long)node_id, (void*)conn);
struct NODE_CONNS_INFO* info = find_node_conns(table, node_id);
if (!info) return false;
if (!info) {
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_remove_path: node not found");
return false;
}
bool was_preferred = node_conns_info_remove(info, conn);
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_remove_path: removed, was_preferred=%d remaining_conns=%d",
was_preferred, info->conninfo_count);
if (info->conninfo_count == 0) {
// Последний путь к узлу — полный withdraw
route_delete(table, node_id); // уже вызывает callback(2) и очищает память
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_remove_path: WITHDRAW node_id=%llu", (unsigned long long)node_id);
return true;
} else if (was_preferred) {
// Изменился preferred_conn — уведомляем о reroute для всех префиксов этого узла
@ -583,12 +631,17 @@ bool route_remove_path(struct ROUTE_TABLE *table,
table->change_callback(table, e, 1, table->change_callback_arg);
}
}
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_remove_path: REROUTE node_id=%llu", (unsigned long long)node_id);
}
return false;
}
void route_delete(struct ROUTE_TABLE *table, uint64_t node_id) {
if (!table) return;
if (!table) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_delete: table is NULL");
return;
}
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_delete: node_id=%llu", (unsigned long long)node_id);
size_t i = 0;
while (i < table->count) {
@ -630,14 +683,22 @@ void route_delete(struct ROUTE_TABLE *table, uint64_t node_id) {
}
struct ROUTE_ENTRY* route_lookup(struct ROUTE_TABLE *table, uint32_t dest_ip) {
if (!table) return NULL;
if (!table) {
DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "route_lookup: table is NULL");
return NULL;
}
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_lookup: dest_ip=%08X", dest_ip);
struct ROUTE_ENTRY *result = binary_search_lpm(table, dest_ip);
if (result) {
table->stats.routes_lookup_hits++;
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_lookup: FOUND %08X/%d node_id=%llu",
result->network, result->prefix_length,
result->conn_list ? (unsigned long long)result->conn_list->node_id : 0);
} else {
table->stats.routes_lookup_misses++;
DEBUG_TRACE(DEBUG_CATEGORY_ROUTING, "route_lookup: NOT FOUND");
}
return result;

5
src/utun_instance.h

@ -14,6 +14,7 @@ struct utun_config;
struct uasync_s;
struct ROUTE_TABLE;
struct ETCP_CONN;
typedef void (*etcp_new_conn_fn)(struct ETCP_CONN* conn, void* arg);
struct ETCP_SOCKET;
struct tun_if;
struct ETCP_BINDINGS;
@ -48,6 +49,10 @@ struct UTUN_INSTANCE {
// Connections (список всех подключений для instance)
struct ETCP_CONN* connections;// linked-list
int connections_count; // Number of connections
// Callback for new ETCP connections
etcp_new_conn_fn etcp_new_conn_cbk;
void* etcp_new_conn_arg;
struct memory_pool* data_pool;// для входных-выходных данных пакета
struct memory_pool* pkt_pool;

Loading…
Cancel
Save