etcp - добавлено etcp_on_conn_ready callback_fn
+ trace + по мелочи
This commit is contained in:
1 parent
167b3b36da
commit
33629a17c6
9 files changed
+335
-57
No files matched your search
+26
-4
@@ -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, "");
|
||||
|
||||
+14
-2
@@ -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
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
+16
-18
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
+129
-19
@@ -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 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;
|
||||
|
||||
// === 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;
|
||||
}
|
||||
|
||||
// === 2. Если нет — добавляем (только один раз) ===
|
||||
if (!already_exists) {
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
+74
-13
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user