@ -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 ;