@ -22,11 +22,12 @@
// Размер пакета (без заголовка ETCP)
# define BGP_PACKET_SIZE (sizeof(struct ROUTE_BGP_PACKET))
// Внутренняя структура для элемента списка соединений
struct bgp_conn_item {
struct ETCP_CONN * conn ;
struct bgp_conn_item * next ;
} ;
// Forward declarations
static void route_bgp_send_route ( struct ROUTE_BGP * bgp , struct ETCP_CONN * conn ,
const struct ROUTE_ENTRY * route ) ;
static void route_bgp_on_route_change ( struct ROUTE_TABLE * table ,
struct ROUTE_ENTRY * entry ,
int action , void * arg ) ;
/**
* @ brief К о л б э к д л я п р и е м а р о у т и н г - п а к е т о в о т ETCP
@ -143,6 +144,124 @@ static void route_bgp_receive_cbk(struct ETCP_CONN* from_conn, struct ll_entry*
queue_entry_free ( entry ) ;
}
/**
* @ brief О т п р а в и т ь withdraw ( о т з ы в м а р ш р у т а ) ч е р е з ETCP
*/
static void route_bgp_send_withdraw ( struct ROUTE_BGP * bgp , struct ETCP_CONN * conn ,
const struct ROUTE_ENTRY * route )
{
if ( ! bgp | | ! conn | | ! route ) {
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 " ) ;
return ;
}
struct ROUTE_BGP_PACKET * pkt = ( struct ROUTE_BGP_PACKET * ) entry - > dgram ;
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 ;
entry - > len = sizeof ( struct ROUTE_BGP_PACKET ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_BGP , " Sending withdraw: %08x/%d to conn %p " ,
route - > network , route - > prefix_length , ( void * ) conn ) ;
// Отправляем через 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 ) ;
}
}
/**
* @ brief О т п р а в и т ь withdraw д л я в с е х м а р ш р у т о в ч е р е з у к а з а н н о е с о е д и н е н и е
*/
static void route_bgp_send_withdraw_for_conn ( 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 withdraw for routes via conn %p to all peers " , ( void * ) conn ) ;
// Находим все маршруты через это соединение и отправляем 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 ;
}
}
}
}
/**
* @ brief К о л б э к п р и и з м е н е н и и т а б л и ц ы м а р ш р у т и з а ц и и
*
* Р а с с ы л а е т о б н о в л е н и я в с е м с о е д и н е н и я м в senders_list
*/
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 ;
}
// Не рассылаем маршруты через которые мы их получили (чтобы избежать петель)
// Это делается в цикле ниже
DEBUG_DEBUG ( DEBUG_CATEGORY_BGP , " Route change: action=%d, network=%08x/%d, type=%d " ,
action , entry - > network , entry - > prefix_length , entry - > type ) ;
// Перебираем все соединения в 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 ) ;
}
item_entry = item_entry - > next ;
}
}
/**
* @ brief О т п р а в и т ь о д и н м а р ш р у т ч е р е з ETCP
*/
@ -256,6 +375,13 @@ struct ROUTE_BGP* route_bgp_init(struct UTUN_INSTANCE* instance)
return NULL ;
}
// Устанавливаем callback на изменение таблицы маршрутизации
if ( instance - > rt ) {
instance - > rt - > change_callback = route_bgp_on_route_change ;
instance - > rt - > change_callback_arg = bgp ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Route change callback registered " ) ;
}
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " BGP module initialized " ) ;
return bgp ;
}
@ -271,11 +397,16 @@ void route_bgp_destroy(struct UTUN_INSTANCE* instance)
// Очищаем и освобождаем структуру BGP
if ( instance - > bgp ) {
// Убираем callback из таблицы маршрутизации
if ( instance - > rt & & instance - > rt - > change_callback = = route_bgp_on_route_change ) {
instance - > rt - > change_callback = NULL ;
instance - > rt - > change_callback_arg = NULL ;
}
if ( instance - > bgp - > senders_list ) {
// Очищаем очередь
// Очищаем очередь - освобождаем элементы conn_item
struct ll_entry * entry ;
while ( ( entry = queue_data_get ( instance - > bgp - > senders_list ) ) ! = NULL ) {
queue_dgram_free ( entry ) ;
queue_entry_free ( entry ) ;
}
queue_free ( instance - > bgp - > senders_list ) ;
@ -301,23 +432,69 @@ void route_bgp_new_conn(struct ETCP_CONN* conn)
return ;
}
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " New connection, sending routing table " ) ;
// Создаем элемент для добавления в senders_list
struct ll_entry * entry = queue_entry_new ( sizeof ( struct ROUTE_BGP_CONN_ITEM ) ) ;
if ( ! entry ) {
DEBUG_ERROR ( DEBUG_CATEGORY_BGP , " Failed to allocate connection item " ) ;
return ;
}
struct ROUTE_BGP_CONN_ITEM * item = ( struct ROUTE_BGP_CONN_ITEM * ) entry - > data ;
item - > conn = conn ;
// Добавляем в очередь (id = 0, не используем хеш)
if ( queue_data_put ( bgp - > senders_list , entry , 0 ) ! = 0 ) {
queue_entry_free ( entry ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_BGP , " Failed to add connection to senders_list " ) ;
return ;
}
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Added connection %p to senders_list " , ( void * ) conn ) ;
// Отправляем полную таблицу новому соединению
route_bgp_send_table_to_conn_internal ( bgp , conn ) ;
}
void route_bgp_close_conn ( struct ETCP_CONN * conn )
void route_bgp_remov e_conn ( struct ETCP_CONN * conn )
{
if ( ! conn ) {
if ( ! conn | | ! conn - > instance ) {
return ;
}
struct UTUN_INSTANCE * instance = conn - > instance ;
struct ROUTE_BGP * bgp = instance - > bgp ;
if ( ! bgp ) {
return ;
}
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Connection closed, removing from distribution list " ) ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Removing connection %p from senders_list " , ( void * ) conn ) ;
// Отправляем withdraw всем остальным соединениям для маршрутов через это соединение
route_bgp_send_withdraw_for_conn ( bgp , conn ) ;
// Находим и удаляем соединение из senders_list
struct ll_entry * entry = bgp - > senders_list - > head ;
while ( entry ) {
struct ROUTE_BGP_CONN_ITEM * item = ( struct ROUTE_BGP_CONN_ITEM * ) entry - > data ;
if ( item - > conn = = conn ) {
// Удаляем из очереди
queue_remove_data ( bgp - > senders_list , entry ) ;
queue_entry_free ( entry ) ;
DEBUG_INFO ( DEBUG_CATEGORY_BGP , " Connection %p removed from senders_list " , ( void * ) conn ) ;
break ;
}
entry = entry - > next ;
}
// Удаляем все маршруты, связанные с этим соединением
struct UTUN_INSTANCE * instance = conn - > instance ;
if ( instance & & instance - > rt ) {
if ( instance - > rt ) {
route_table_delete ( instance - > rt , conn ) ;
}
}
void route_bgp_close_conn ( struct ETCP_CONN * conn )
{
// Устаревшая функция, используйте route_bgp_remove_conn
route_bgp_remove_conn ( conn ) ;
}