@ -34,8 +34,6 @@ static void route_bgp_on_route_change(struct ROUTE_TABLE* table,
static const char * route_type_to_str ( route_type_t type ) {
switch ( type ) {
case ROUTE_TYPE_STATIC : return " STATIC " ;
case ROUTE_TYPE_DYNAMIC : return " DYNAMIC " ;
case ROUTE_TYPE_LOCAL : return " LOCAL " ;
case ROUTE_TYPE_LEARNED : return " LEARNED " ;
default : return " UNKNOWN " ;
@ -48,6 +46,31 @@ static void format_ip(uint32_t ip, char* buffer) {
snprintf ( buffer , 16 , " %u.%u.%u.%u " , b [ 3 ] , b [ 2 ] , b [ 1 ] , b [ 0 ] ) ;
}
/**
* @ brief Р а с с ы л а е т м а р ш р у т в с е м с о е д и н е н и я м ( к р о м е exclude )
*/
static void route_bgp_broadcast_route ( struct ROUTE_BGP * bgp , const struct ROUTE_ENTRY * route ,
struct ETCP_CONN * exclude ) {
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 + + ;
}
entry = entry - > next ;
}
char net_buf [ 16 ] ;
format_ip ( route - > network , net_buf ) ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Broadcasted route %s/%d to %d connections " ,
net_buf , route - > prefix_length , sent_count ) ;
}
/**
* @ brief К о л б э к д л я п р и е м а р о у т и н г - п а к е т о в о т ETCP
*
@ -121,46 +144,41 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
// Вставляем в таблицу
char net_buf [ 16 ] ;
format_ip ( route . network , net_buf ) ;
size_t old_count = instance - > rt - > count ;
if ( route_table_insert ( instance - > rt , & route ) ) {
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Added learned route: %s/%d via node %016llx (hops=%d) " ,
net_buf , route . prefix_length ,
( unsigned long long ) route . destination_node_id ,
route . metrics . hop_count ) ;
struct ROUTE_BGP * bgp = instance - > bgp ;
if ( instance - > rt - > count > old_count & & ! ( route . flags & ROUTE_FLAG_ADVERTISED ) ) {
// Новый маршрут - распространяем всем кроме источника
route_bgp_broadcast_route ( bgp , & route , from_conn ) ;
// Устанавливаем флаг, чтобы не повторять
route . flags | = ROUTE_FLAG_ADVERTISED ;
}
} else {
DEBUG_WARN ( DEBUG_CATEGORY_BGP , " Failed to insert route: %s/%d " ,
DEBUG_WARN ( DEBUG_CATEGORY_BGP , " Failed to insert learned route: %s/%d " ,
net_buf , route . prefix_length ) ;
}
break ;
}
case ROUTE_SUBCMD_WITHDRAW : {
// Удаление маршрута (withdrawal)
uint32_t network = ntohl ( pkt - > network ) ;
uint8_t prefix_length = pkt - > prefix_length & 0x3F ;
char w_net_buf [ 16 ] ;
format_ip ( network , w_net_buf ) ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Processing route withdrawal: %s/%d from conn %p " ,
w_net_buf , prefix_length , ( void * ) from_conn ) ;
if ( route_table_delete_entry ( instance - > rt , network , prefix_length , from_conn ) ) {
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Route withdrawn successfully: %s/%d " ,
w_net _buf, prefix_length ) ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Withdrawn route: %s/%d from conn %p " ,
ip_buf , prefix_length , ( void * ) from_conn ) ;
} else {
DEBUG_WARN ( DEBUG_CATEGORY_BGP , " Route to withdraw not found: %s/% d" ,
w_net _buf, prefix_length ) ;
DEBUG_WARN ( DEBUG_CATEGORY_BGP , " Withdraw failed: route %s/%d not foun d" ,
ip _buf, prefix_length ) ;
}
break ;
}
case ROUTE_SUBCMD_REQUEST : {
// Запрос полной таблицы - отправляем всё
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Full table request received from connection " ) ;
// Получаем bgp из instance (нужно добавить поле в instance)
// Пока просто игнорируем - таблица отправляется при new_conn
break ;
}
default :
DEBUG_WARN ( DEBUG_CATEGORY_BGP , " Unknown BGP subcommand: %d " , pkt - > subcmd ) ;
break ;
@ -171,281 +189,195 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
}
/**
* @ brief О т п р а в и т ь withdraw ( о т з ы в м а р ш р у т а ) ч е р е з ETCP
* @ brief О т п р а в л я е т м а р ш р у т к о н к р е т н о м у с о е д и н е н и ю
*/
static void route_bgp_send_withdraw ( struct ROUTE_BGP * bgp , struct ETCP_CONN * conn ,
const struct ROUTE_ENTRY * route )
{
if ( ! bgp | | ! conn | | ! route ) {
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 ll_entry * entry = queue_entry_new_from_pool ( bgp - > instance - > pkt_pool ) ;
if ( ! entry ) {
DEBUG_ERROR ( DEBUG_CATEGORY_BGP , " Failed to allocate entry for BGP send " ) ;
return ;
}
// Создаем ETCP пакет
struct ll_entry * entry = ll_alloc_lldgram ( sizeof ( struct ROUTE_BGP_PACKET ) ) ;
if ( ! entry ) {
DEBUG_ERROR ( DEBUG_CATEGORY_BGP , " Failed to allocate withdraw packet " ) ;
// Выделяем буфер для пакета
entry - > dgram = u_malloc ( BGP_PACKET_SIZE ) ;
if ( ! entry - > dgram ) {
queue_entry_free ( entry ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_BGP , " Failed to allocate dgram for BGP send " ) ;
return ;
}
entry - > len = BGP_PACKET_SIZE ;
entry - > memlen = BGP_PACKET_SIZE ;
struct ROUTE_BGP_PACKET * pkt = ( struct ROUTE_BGP_PACKET * ) entry - > dgram ;
memset ( pkt , 0 , BGP_PACKET_SIZE ) ;
pkt - > cmd = ETCP_ID_ROUTE_ENTRY ;
pkt - > subcmd = ROUTE_SUBCMD_WITHDRAW ;
pkt - > hop_count = 0 ;
pkt - > prefix_length = route - > prefix_length & 0x3F ;
pkt - > latency = 0 ;
pkt - > endpoint_port = 0 ;
pkt - > endpoint_ip = 0 ;
pkt - > network = htonl ( route - > network ) ;
pkt - > bandwidth_kbps = 0 ;
pkt - > node_id = route - > destination_node_id ;
pkt - > subcmd = ROUTE_SUBCMD_ENTRY ;
pkt - > hop_count = route - > metrics . hop_count ;
pkt - > prefix_length = route - > prefix_length ;
entry - > len = sizeof ( struct ROUTE_BGP_PACKET ) ;
if ( route - > type = = ROUTE_TYPE_LOCAL ) {
pkt - > prefix_length | = ROUTE_PREFIX_F_LOCAL ;
}
char wd_net_buf [ 16 ] ;
format_ip ( route - > network , wd_net_buf ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_BGP , " Sending withdraw: %s/%d to conn %p " ,
wd_net_buf , route - > prefix_length , ( void * ) conn ) ;
pkt - > latency = route - > metrics . latency_ms * 10 ; // ms -> x0.1 ms
pkt - > bandwidth_kbps = htonl ( route - > metrics . bandwidth_kbps ) ;
pkt - > network = htonl ( route - > network ) ;
pkt - > endpoint_ip = htonl ( route - > endpoint_ip ) ;
pkt - > endpoint_port = htons ( route - > endpoint_port ) ;
pkt - > node_id = route - > destination_node_id ;
pkt - > route_type = route - > type ;
// Отправляем через ETCP
if ( etcp_send ( conn , entry ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_BGP , " Failed to send withdraw via ETCP " ) ;
queue_dgram_free ( entry ) ;
queue_entry_free ( entry ) ;
DEBUG_WARN ( DEBUG_CATEGORY_BGP , " Failed to send BGP route to conn %p " , ( void * ) conn ) ;
} else {
char net_buf [ 16 ] ;
format_ip ( route - > network , net_buf ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_BGP , " Sent BGP route: %s/%d to conn %p " ,
net_buf , route - > prefix_length , ( void * ) conn ) ;
}
}
/**
* @ brief О т п р а в и т ь withdraw д л я в с е х м а р ш р у т о в ч е р е з у к а з а н н о е с о е д и н е н и е
* @ brief О т п р а в л я е т withdraw д л я к о н к р е т н о й п о д с е т и о д н о м у с о е д и н е н и ю
*/
static void route_bgp_send_withdraw_for_conn ( struct ROUTE_BGP * bgp , struct ETCP_CONN * conn )
{
if ( ! bgp | | ! conn | | ! bgp - > instance - > rt ) {
static void route_bgp_send_withdraw ( struct ROUTE_BGP * bgp , struct ETCP_CONN * conn ,
uint32_t network , uint8_t prefix_length ) {
if ( ! bgp | | ! conn ) return ;
struct ll_entry * entry = queue_entry_new_from_pool ( bgp - > instance - > pkt_pool ) ;
if ( ! entry ) return ;
entry - > dgram = u_malloc ( BGP_PACKET_SIZE ) ;
if ( ! entry - > dgram ) {
queue_entry_free ( entry ) ;
return ;
}
entry - > len = BGP_PACKET_SIZE ;
entry - > memlen = BGP_PACKET_SIZE ;
struct ROUTE_TABLE * rt = bgp - > instance - > rt ;
struct ROUTE_BGP_PACKET * pkt = ( struct ROUTE_BGP_PACKET * ) entry - > dgram ;
memset ( pkt , 0 , BGP_PACKET_SIZE ) ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Sending withdraw for routes via conn %p to all peers " , ( void * ) conn ) ;
pkt - > cmd = ETCP_ID_ROUTE_ENTRY ;
pkt - > subcmd = ROUTE_SUBCMD_WITHDRAW ;
pkt - > network = htonl ( network ) ;
pkt - > prefix_length = prefix_length ;
// Находим все маршруты через это соединение и отправляем withdraw
for ( size_t i = 0 ; i < rt - > count ; i + + ) {
struct ROUTE_ENTRY * entry = & rt - > entries [ i ] ;
if ( entry - > next_hop = = conn & & entry - > type = = ROUTE_TYPE_LEARNED ) {
// Отправляем withdraw всем соединениям в senders_list
struct ll_entry * item_entry = bgp - > senders_list - > head ;
while ( item_entry ) {
struct ROUTE_BGP_CONN_ITEM * item = ( struct ROUTE_BGP_CONN_ITEM * ) item_entry - > data ;
if ( item - > conn ! = conn ) { // Не отправляем тому, кто прислал
route_bgp_send_withdraw ( bgp , item - > conn , entry ) ;
}
item_entry = item_entry - > next ;
}
}
if ( etcp_send ( conn , entry ) ! = 0 ) {
queue_dgram_free ( entry ) ;
queue_entry_free ( entry ) ;
}
}
/**
* @ brief К о л б э к п р и и з м е н е н и и т а б л и ц ы м а р ш р у т и з а ц и и
*
* Р а с с ы л а е т о б н о в л е н и я в с е м с о е д и н е н и я м в senders_list
* @ brief Р а с с ы л а е т withdraw в с е м с о е д и н е н и я м ( к р о м е exclude )
*/
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 ;
}
// Не рассылаем локальные маршруты помеченные ROUTE_PREFIX_F_LOCAL
if ( entry - > type = = ROUTE_TYPE_LOCAL & & ( entry - > prefix_length & ROUTE_PREFIX_F_LOCAL ) ) {
return ;
}
// Не рассылаем маршруты через которые мы их получили (чтобы избежать петель)
// Это делается в цикле ниже
char ch_net_buf [ 16 ] ;
format_ip ( entry - > network , ch_net_buf ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_BGP , " Route change: action=%d, network=%s/%d, type=%d " ,
action , ch_net_buf , entry - > prefix_length , entry - > type ) ;
static void route_bgp_broadcast_withdraw ( struct ROUTE_BGP * bgp , uint32_t network ,
uint8_t prefix_length , struct ETCP_CONN * exclude ) {
if ( ! bgp ) return ;
// Перебираем все соединения в senders_list
struct ll_entry * item_entry = bgp - > senders_list - > head ;
while ( item_entry ) {
struct ROUTE_BGP_CONN_ITEM * item = ( struct ROUTE_BGP_CONN_ITEM * ) item_entry - > data ;
// Не отправляем тому, от кого пришел маршрут
if ( entry - > type = = ROUTE_TYPE_LEARNED & & entry - > next_hop = = item - > conn ) {
item_entry = item_entry - > next ;
continue ;
}
if ( action = = 2 ) { // delete - отправить withdraw
route_bgp_send_withdraw ( bgp , item - > conn , entry ) ;
} else { // insert (0) или update (1) - отправить маршрут
route_bgp_send_route ( bgp , item - > conn , entry ) ;
struct ll_entry * entry = bgp - > senders_list - > head ;
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 , network , prefix_length ) ;
}
item_entry = item_entry - > next ;
entry = entry - > next ;
}
}
/**
* @ brief О т п р а в и т ь о д и н м а р ш р у т ч е р е з ETCP ( в с п о м о г а т е л ь н а я ф у н к ц и я д л я о т п р а в к и о д н о г о п а к е т а )
* @ brief О т п р а в л я е т withdraw д л я в с е х м а р ш р у т о в ч е р е з з а к р ы т о е с о е д и н е н и е
*/
static int route_bgp_send_route_single ( struct ROUTE_BGP * bgp , struct ETCP_CONN * conn ,
const struct ROUTE_ENTRY * route ,
uint32_t endpoint_ip , uint16_t endpoint_port )
{
struct ll_entry * entry = ll_alloc_lldgram ( sizeof ( struct ROUTE_BGP_PACKET ) ) ;
if ( ! entry ) {
DEBUG_ERROR ( DEBUG_CATEGORY_BGP , " Failed to allocate packet " ) ;
return - 1 ;
}
static void route_bgp_send_withdraw_for_conn ( struct ROUTE_BGP * bgp , struct ETCP_CONN * conn ) {
if ( ! bgp | | ! bgp - > instance - > rt ) return ;
struct ROUTE_BGP_PACKET * pkt = ( struct ROUTE_BGP_PACKET * ) entry - > dgram ;
pkt - > cmd = ETCP_ID_ROUTE_ENTRY ;
pkt - > subcmd = ROUTE_SUBCMD_ENTRY ;
pkt - > hop_count = route - > metrics . hop_count ;
pkt - > prefix_length = route - > prefix_length ;
struct ROUTE_ENTRY * routes = NULL ;
size_t count = 0 ;
// Устанавливаем флаги
if ( endpoint_ip & & endpoint_port ) {
pkt - > prefix_length | = ROUTE_PREFIX_F_DIRECT ;
}
// Если это локальный маршрут - отмечаем (не будет пересылаться дальше)
if ( route - > type = = ROUTE_TYPE_LOCAL ) {
pkt - > prefix_length | = ROUTE_PREFIX_F_LOCAL ;
// Получаем все маршруты (чтобы не итерать таблицу во время отправки)
for ( size_t i = 0 ; i < bgp - > instance - > rt - > count ; i + + ) {
if ( bgp - > instance - > rt - > entries [ i ] . next_hop = = conn ) {
count + + ;
}
}
pkt - > latency = htons ( route - > metrics . latency_ms * 10 ) ; // ms -> x0.1 ms
pkt - > endpoint_port = endpoint_port ;
pkt - > endpoint_ip = endpoint_ip ;
pkt - > network = htonl ( route - > network ) ;
pkt - > bandwidth_kbps = htonl ( route - > metrics . bandwidth_kbps ) ;
pkt - > node_id = bgp - > instance - > node_id ; // Наш node_id
pkt - > route_type = route - > type ;
if ( count = = 0 ) return ;
entry - > len = sizeof ( struct ROUTE_BGP_PACKET ) ;
char sr_net_buf [ 16 ] ;
char sr_ep_buf [ 16 ] ;
format_ip ( route - > network , sr_net_buf ) ;
format_ip ( ntohl ( endpoint_ip ) , sr_ep_buf ) ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Sending route: %s/%d type=%s flags=0x%x "
" metrics{hops=%u lat=%u kbps=%u loss=%u metric=%u} "
" endpoint=%s:%u node_id=%016llx " ,
sr_net_buf , route - > prefix_length ,
route_type_to_str ( route - > type ) , route - > flags ,
route - > metrics . hop_count , route - > metrics . latency_ms ,
route - > metrics . bandwidth_kbps , route - > metrics . packet_loss_rate ,
route - > metrics . metric ,
sr_ep_buf , ntohs ( endpoint_port ) ,
( unsigned long long ) route - > destination_node_id ) ;
routes = u_calloc ( count , sizeof ( struct ROUTE_ENTRY ) ) ;
if ( ! routes ) return ;
// Отправляем через ETCP
if ( etcp_send ( conn , entry ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_BGP , " Failed to send route via ETCP " ) ;
queue_dgram_free ( entry ) ;
queue_entry_free ( entry ) ;
return - 1 ;
size_t idx = 0 ;
for ( size_t i = 0 ; i < bgp - > instance - > rt - > count ; i + + ) {
if ( bgp - > instance - > rt - > entries [ i ] . next_hop = = conn ) {
routes [ idx + + ] = bgp - > instance - > rt - > entries [ i ] ;
}
}
return 0 ;
// Рассылаем withdraw для каждого
struct ll_entry * entry = bgp - > senders_list - > head ;
while ( entry ) {
struct ROUTE_BGP_CONN_ITEM * item = ( struct ROUTE_BGP_CONN_ITEM * ) entry - > data ;
if ( item - > conn ! = conn ) {
for ( size_t i = 0 ; i < count ; i + + ) {
route_bgp_send_withdraw ( bgp , item - > conn , routes [ i ] . network , routes [ i ] . prefix_length ) ;
}
}
entry = entry - > next ;
}
u_free ( routes ) ;
}
/**
* @ brief О т п р а в и т ь о д и н м а р ш р у т ч е р е з ETCP
* @ 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 ;
}
// Пропускаем неактивные маршруты
if ( ! ( route - > flags & ROUTE_FLAG_ACTIVE ) ) {
return ;
}
static void route_bgp_send_table_to_conn_internal ( struct ROUTE_BGP * bgp , struct ETCP_CONN * conn ) {
if ( ! bgp | | ! conn | | ! bgp - > instance - > rt ) return ;
// Пропускаем локальные маршруты если они не для анонса
if ( ( route - > flags & ROUTE_FLAG_ADVERTISED ) & & ( route - > prefix_length & ROUTE_PREFIX_F_LOCAL ) ) {
return ;
}
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Sending full routing table to conn %p " , ( void * ) conn ) ;
// Для LOCAL маршрутов - отправляем с нескольких endpoints если есть PUBLIC или NAT серверы
if ( route - > type = = ROUTE_TYPE_LOCAL & & conn - > links ) {
// Сначала отправляем PUBLIC (приоритет), затем NAT
struct ETCP_LINK * link = conn - > links ;
int sent_any = 0 ;
// Первый проход - PUBLIC
while ( link ) {
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Sending routine: scanning conn type=%d init=%d " , link - > conn - > type , link - > initialized ) ;
if ( link - > conn & & link - > conn - > type = = CFG_SERVER_TYPE_PUBLIC & & link - > initialized ) {
struct sockaddr_in * sin = ( struct sockaddr_in * ) & link - > conn - > local_addr ;
uint32_t ip = * ( uint32_t * ) & sin - > sin_addr ;
uint16_t port = sin - > sin_port ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Sending routine [public] " ) ;
route_bgp_send_route_single ( bgp , conn , route , ip , port ) ;
sent_any = 1 ;
}
link = link - > next ;
}
// Второй проход - NAT
link = conn - > links ;
while ( link ) {
if ( link - > conn & & link - > conn - > type = = CFG_SERVER_TYPE_NAT & & link - > nat_ip & & link - > initialized ) {
uint32_t ip = link - > nat_ip ;
uint16_t port = link - > nat_port ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Sending routine [nat] " ) ;
route_bgp_send_route_single ( bgp , conn , route , ip , port ) ;
sent_any = 1 ;
}
link = link - > next ;
}
// Если нет PUBLIC и NAT - отправляем без endpoint (0.0.0.0:0)
if ( ! sent_any ) {
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Sending routine [any] " ) ;
route_bgp_send_route_single ( bgp , conn , route , 0 , 0 ) ;
for ( size_t i = 0 ; i < bgp - > instance - > rt - > count ; i + + ) {
const struct ROUTE_ENTRY * route = & bgp - > instance - > rt - > entries [ i ] ;
if ( route - > type = = ROUTE_TYPE_LOCAL | |
( route - > type = = ROUTE_TYPE_LEARNED & & ( route - > flags & ROUTE_FLAG_ADVERTISED ) ) ) {
route_bgp_send_route ( bgp , conn , route ) ;
}
} else {
// Для LEARNED маршрутов - используем endpoint из route
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Sending routine [learned] " ) ;
route_bgp_send_route_single ( bgp , conn , route ,
htonl ( route - > endpoint_ip ) ,
htons ( route - > endpoint_port ) ) ;
}
}
/**
* @ brief О т п р а в и т ь п о л н у ю т а б л и ц у у к а з а н н о м у с о е д и н е н и ю
* @ brief Callback н а и з м е н е н и е т а б л и ц ы м а р ш р у т и з а ц и и
*/
static void route_bgp_send_table_to_conn_internal ( struct ROUTE_BGP * bgp , struct ETCP_CONN * conn )
{
if ( ! bgp | | ! conn | | ! bgp - > instance - > rt ) {
return ;
}
struct ROUTE_TABLE * rt = bgp - > instance - > rt ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Sending full routing table (%zu routes) to connection " ,
rt - > count ) ;
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 ;
// Отправляем все маршруты из таблицы
for ( size_t i = 0 ; i < rt - > count ; i + + ) {
route_bgp_send_route ( bgp , conn , & rt - > entries [ i ] ) ;
if ( action = = 0 | | action = = 1 ) { // insert or update
// Анонсируем только локальные и статические маршруты
if ( entry - > type = = ROUTE_TYPE_LOCAL ) {
route_bgp_broadcast_route ( bgp , entry , NULL ) ;
}
} else if ( action = = 2 ) { // delete
// Отправляем withdraw всем
route_bgp_broadcast_withdraw ( bgp , entry - > network , entry - > prefix_length , NULL ) ;
}
}
struct ROUTE_BGP * route_bgp_init ( struct UTUN_INSTANCE * instance )
{
/**
* @ brief И н и ц и а л и з а ц и я BGP м о д у л я
*/
struct ROUTE_BGP * route_bgp_init ( struct UTUN_INSTANCE * instance ) {
if ( ! instance ) {
DEBUG_ERROR ( DEBUG_CATEGORY_BGP , " Cannot init BGP: no instance " ) ;
return NULL ;