2021-03-29 22:45:21 +02:00
/*
* BIRD - - The BGP Monitoring Protocol ( BMP )
*
* ( c ) 2020 Akamai Technologies , Inc . ( Pawel Maslanka , pmaslank @ akamai . com )
*
* Can be freely distributed and used under the terms of the GNU GPL .
*/
/**
* DOC : BGP Monitoring Protocol ( BMP )
*
* Supported standards :
* o RFC 7854 - BMP standard
*
* TODO :
* - Support Peer Distinguisher ID in Per - Peer Header
* - Support peer type as RD Instance in Peer Type field of Per - Peer Header .
* Currently , there are supported Global and Local Instance Peer types
* - Support corresponding FSM event code during send PEER DOWN NOTIFICATION
* - Support DE_CONFIGURED PEER DOWN REASON code in PEER DOWN NOTIFICATION message
* - If connection with BMP collector will lost then we don ' t establish connection again
* - Set Peer Type by its a global and local - scope IP address
2023-04-20 16:13:58 +02:00
*
* The BMP session is managed by a simple state machine with three states : Idle
* ( ! started , ! sk ) , Connect ( ! started , sk active ) , and Established ( started ) . It
2023-05-30 15:52:01 +02:00
* has three events : connect successful ( Connect - > Established ) , socket error
2023-04-20 16:13:58 +02:00
* ( any - > Idle ) , and connect timeout ( Idle / Connect - > Connect , resetting the
* TCP socket ) .
2021-03-29 22:45:21 +02:00
*/
# include "proto/bmp/bmp.h"
# include "proto/bmp/buffer.h"
# include "proto/bmp/map.h"
# include <sys/socket.h>
# include <sys/time.h>
# include <sys/types.h>
# include <netinet/in.h>
# include <netdb.h>
# include <string.h>
# include <stdlib.h>
# include <unistd.h>
# include <errno.h>
# include <arpa/inet.h>
# include <limits.h>
# include "nest/cli.h"
# include "filter/filter.h"
# include "proto/bgp/bgp.h"
# include "sysdep/unix/unix.h"
2024-09-04 13:48:40 +02:00
# include "sysdep/unix/io-loop.h"
2021-03-29 22:45:21 +02:00
# include "lib/event.h"
# include "lib/ip.h"
# include "lib/lists.h"
# include "lib/resource.h"
# include "lib/unaligned.h"
2024-09-06 12:17:05 +02:00
# include "lib/tlists.h"
2021-03-29 22:45:21 +02:00
# include "nest/iface.h"
# include "nest/route.h"
2023-08-18 03:53:58 +02:00
# define HASH_PEER_KEY(n) n->bgp
# define HASH_PEER_NEXT(n) n->next
# define HASH_PEER_EQ(b1,b2) b1 == b2
# define HASH_PEER_FN(b) ptr_hash(b)
# define BMP_STREAM_KEY_POLICY 0x100
# define HASH_STREAM_KEY(n) n->bgp, n->key
# define HASH_STREAM_NEXT(n) n->next
# define HASH_STREAM_EQ(b1,k1,b2,k2) b1 == b2 && k1 == k2
# define HASH_STREAM_FN(b,k) ptr_hash(b) ^ u32_hash(k)
# define HASH_TABLE_KEY(n) n->table
# define HASH_TABLE_NEXT(n) n->next
# define HASH_TABLE_EQ(t1,t2) t1 == t2
# define HASH_TABLE_FN(t) ptr_hash(t)
2021-03-29 22:45:21 +02:00
/* BMP Common Header [RFC 7854 - Section 4.1] */
enum bmp_version {
BMP_VER_UNUSED = 0 , // Version 0 is reserved and MUST NOT be sent
BMP_VERSION_1 = 1 , // Version 1 was used by draft version of RFC 7854
BMP_VERSION_2 = 2 , // Version 2 was used by draft version of RFC 7854
BMP_VERSION_3 = 3 // Version 3 is used by all messages defined in RFC 7854
} ;
enum bmp_message_type {
BMP_ROUTE_MONITOR = 0 , // Route Monitoring
BMP_STATS_REPORT = 1 , // Statistics Report
BMP_PEER_DOWN_NOTIF = 2 , // Peer Down Notification
BMP_PEER_UP_NOTIF = 3 , // Peer Up Notification
BMP_INIT_MSG = 4 , // Initiation Message
BMP_TERM_MSG = 5 , // Termination Message
BMP_ROUTE_MIRROR_MSG = 6 // Route Mirroring Message
} ;
// Total size of Common Header
# define BMP_COMMON_HDR_SIZE 6
// Defines size of padding when IPv4 address is going to be put into field
// which can accept also IPv6 address
# define BMP_PADDING_IP4_ADDR_SIZE 12
/* BMP Per-Peer Header [RFC 7854 - Section 4.2] */
// Total size of Per-Peer Header
# define BMP_PER_PEER_HDR_SIZE 42
enum bmp_peer_type {
BMP_PEER_TYPE_GLOBAL_INSTANCE = 0 ,
BMP_PEER_TYPE_RD_INSTANCE = 1 ,
BMP_PEER_TYPE_LOCAL_INSTANCE = 2
} ;
# define BMP_PEER_HDR_FLAG_V_SHIFT 7
enum bmp_peer_flag_v_t {
// The Peer address is an IPv4 address
BMP_PEER_HDR_FLAG_V_IP4 = ( 0 < < BMP_PEER_HDR_FLAG_V_SHIFT ) ,
// The Peer address is an IPv6 address
BMP_PEER_HDR_FLAG_V_IP6 = ( 1 < < BMP_PEER_HDR_FLAG_V_SHIFT )
} ;
# define BMP_PEER_HDR_FLAG_L_SHIFT 6
enum bmp_peer_flag_l {
BMP_PEER_HDR_FLAG_L_PRE_POLICY_ADJ_RIB_IN = ( 0 < < BMP_PEER_HDR_FLAG_L_SHIFT ) ,
BMP_PEER_HDR_FLAG_L_POST_POLICY_ADJ_RIB_IN = ( 1 < < BMP_PEER_HDR_FLAG_L_SHIFT )
} ;
# define BMP_PEER_HDR_FLAG_A_SHIFT 5
enum bmp_peer_flag_a {
// The 4-byte AS_PATH format
BMP_PEER_HDR_FLAG_A_AS_PATH_4B = ( 0 < < BMP_PEER_HDR_FLAG_A_SHIFT ) ,
// The legacy 2-byte AS_PATH format
BMP_PEER_HDR_FLAG_A_AS_PATH_2B = ( 1 < < BMP_PEER_HDR_FLAG_A_SHIFT )
} ;
# define BMP_PEER_HDR_FLAGS_INIT(flags) \
( flags ) = 0
# define BMP_PEER_HDR_FLAGS_SET(flags, bit_mask) \
( flags ) | = ( bit_mask )
/* BMP Information TLV header [RFC 7854 - Section 4.4] */
// Total size of Type and Length fields of Information TLV Header without
// variable part
# define BMP_INFO_TLV_FIX_SIZE 4
enum bmp_info_tlv_type {
BMP_INFO_TLV_TYPE_STRING = 0 , // String
BMP_INFO_TLV_TYPE_SYS_DESCR = 1 , // SysDescr
BMP_INFO_TLV_TYPE_SYS_NAME = 2 // SysName
} ;
/* BMP Peer Up Notification message header [RFC 7854 - Section 4.10] */
// Total size of all fields of Peer Up Notification message except variable part
# define BMP_PEER_UP_NOTIF_MSG_FIX_SIZE 20
enum bmp_peer_down_notif_reason {
// The local system closed the session
BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION = 1 ,
// The local system closed the session
BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION = 2 ,
// The remote system closed the session with a notification message
BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION = 3 ,
// The remote system closed the session without a notification message
BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION = 4 ,
// Information for this peer will no longer be sent to the monitoring station
// for configuration reasons
BMP_PEER_DOWN_REASON_PEER_DE_CONFIGURED = 5
} ;
/* BMP Termination Message [RFC 7854 - Section 4.5] */
# define BMP_TERM_INFO_TYPE_SIZE 2
enum bmp_term_info_type {
BMP_TERM_INFO_STRING = 0 , // The Information field contains string
BMP_TERM_INFO_REASON = 1 , // The Information field contains 2-byte reason code
} ;
// 2-byte code in the Information field
# define BMP_TERM_REASON_CODE_SIZE 2
enum bmp_term_reason {
BMP_TERM_REASON_ADM = 0 , // Session administratively closed
BMP_TERM_REASON_UNK = 1 , // Unspecified reason
BMP_TERM_REASON_OOR = 2 , // Out of resources
BMP_TERM_REASON_DUP = 3 , // Redundant connection
BMP_TERM_REASON_PERM = 4 , // Session permanently administratively closed
} ;
// Size of Information Length field in Termination Message header
# define BMP_TERM_INFO_LEN_FIELD_SIZE 2
// Default chunk size request when memory allocation
# define DEFAULT_MEM_BLOCK_SIZE 4096
2023-04-20 16:13:58 +02:00
// Initial delay for connection to the BMP collector
# define CONNECT_INIT_TIME (200 MS)
2021-03-29 22:45:21 +02:00
// Timeout for connection to the BMP collector retry
2023-04-20 16:13:58 +02:00
# define CONNECT_RETRY_TIME (10 S)
2021-03-29 22:45:21 +02:00
# define IP4_MAX_TTL 255
2021-03-28 04:30:11 +02:00
# define IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(expr, msg, rv...) \
do { \
if ( ( expr ) ) \
{ \
log ( L_WARN " [BMP] " msg ) ; \
return rv ; \
} \
} while ( 0 )
# define IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(p, msg, rv...) \
do { \
IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL ( ! ( p ) , msg , rv ) ; \
} while ( 0 )
2024-09-06 12:23:31 +02:00
static const struct ea_class * bgp_next_hop_ea_class = NULL ;
2021-03-28 04:30:11 +02:00
2023-04-20 16:13:58 +02:00
static void bmp_connected ( struct birdsock * sk ) ;
static void bmp_sock_err ( sock * sk , int err ) ;
static void bmp_close_socket ( struct bmp_proto * p ) ;
2024-09-19 09:54:06 +02:00
static void bmp_check_routes ( void * bt_ ) ;
2024-09-19 11:26:32 +02:00
static void bmp_feed_end ( struct rt_export_request * req ) ;
2021-03-29 22:45:21 +02:00
2021-03-28 04:30:11 +02:00
static void
2024-07-11 14:43:32 +02:00
bmp_send_peer_up_notif_msg ( struct bmp_proto * p , ea_list * bgp ,
2023-05-30 15:52:01 +02:00
const byte * tx_data , const size_t tx_data_size ,
const byte * rx_data , const size_t rx_data_size ) ;
2021-03-29 22:45:21 +02:00
2023-08-21 04:20:32 +02:00
static void bmp_route_monitor_end_of_rib ( struct bmp_proto * p , struct bmp_stream * bs ) ;
2021-03-29 22:45:21 +02:00
// Stores necessary any data in list
struct bmp_data_node {
node n ;
byte * data ;
size_t data_size ;
2023-08-01 17:56:56 +02:00
u32 remote_as ;
u32 remote_id ;
ip_addr remote_ip ;
btime timestamp ;
bool global_peer ;
2023-08-18 03:53:58 +02:00
bool policy ;
2021-03-29 22:45:21 +02:00
} ;
static void
bmp_common_hdr_serialize ( buffer * stream , const enum bmp_message_type type , const u32 data_size )
{
bmp_put_u8 ( stream , BMP_VERSION_3 ) ;
bmp_put_u32 ( stream , BMP_COMMON_HDR_SIZE + data_size ) ;
bmp_put_u8 ( stream , type ) ;
}
2021-03-28 04:30:11 +02:00
static void
2021-03-29 22:45:21 +02:00
bmp_info_tlv_hdr_serialize ( buffer * stream , const enum bmp_info_tlv_type type ,
2021-03-28 04:30:11 +02:00
const char * str )
2021-03-29 22:45:21 +02:00
{
2021-03-28 04:30:11 +02:00
size_t str_len = strlen ( str ) ;
2023-05-30 15:52:01 +02:00
str_len = MIN ( str_len , MIB_II_STR_LEN ) ;
2021-03-29 22:45:21 +02:00
bmp_put_u16 ( stream , type ) ;
2021-03-28 04:30:11 +02:00
bmp_put_u16 ( stream , str_len ) ;
bmp_put_data ( stream , str , str_len ) ;
2021-03-29 22:45:21 +02:00
}
// Serializes BMP Initiation message header [RFC 7854 - Section 4.3]
2021-03-28 04:30:11 +02:00
static void
2021-03-29 22:45:21 +02:00
bmp_init_msg_serialize ( buffer * stream , const char * sys_descr , const char * sys_name )
{
const size_t sys_descr_len = strlen ( sys_descr ) ;
const size_t sys_name_len = strlen ( sys_name ) ;
// We include MIB-II sysDescr and sysName in BMP INIT MSG so that's why
// allocated 2x BMP_INFO_TLV_FIX_SIZE memory pool size
const size_t data_size = ( 2 * BMP_INFO_TLV_FIX_SIZE ) + sys_descr_len + sys_name_len ;
bmp_buffer_need ( stream , BMP_COMMON_HDR_SIZE + data_size ) ;
bmp_common_hdr_serialize ( stream , BMP_INIT_MSG , data_size ) ;
2021-03-28 04:30:11 +02:00
bmp_info_tlv_hdr_serialize ( stream , BMP_INFO_TLV_TYPE_SYS_DESCR , sys_descr ) ;
bmp_info_tlv_hdr_serialize ( stream , BMP_INFO_TLV_TYPE_SYS_NAME , sys_name ) ;
2021-03-29 22:45:21 +02:00
}
2021-03-28 04:30:11 +02:00
static void
2021-03-28 15:13:23 +02:00
bmp_schedule_tx_packet ( struct bmp_proto * p , const byte * payload , const size_t size )
2021-03-29 22:45:21 +02:00
{
2023-04-20 16:13:58 +02:00
ASSERT ( p - > started ) ;
2021-03-29 22:45:21 +02:00
2024-07-26 17:24:15 +02:00
struct bmp_data_node * tx_data = mb_allocz ( p - > tx_mem_pool , sizeof ( struct bmp_data_node ) ) ;
tx_data - > data = mb_allocz ( p - > tx_mem_pool , size ) ;
2024-08-27 15:02:38 +02:00
log ( " tx_data %x data %x " , tx_data , tx_data - > data ) ;
2021-03-29 22:45:21 +02:00
memcpy ( tx_data - > data , payload , size ) ;
tx_data - > data_size = size ;
2024-09-19 09:54:06 +02:00
log ( " schedule tx packet size %i " , size ) ;
if ( size > 5000 )
log ( " too big " ) ;
2021-03-28 15:13:23 +02:00
add_tail ( & p - > tx_queue , & tx_data - > n ) ;
2021-03-28 04:30:11 +02:00
2021-03-28 16:41:53 +02:00
if ( sk_tx_buffer_empty ( p - > sk )
& & ! ev_active ( p - > tx_ev ) )
2021-03-29 22:45:21 +02:00
{
2021-03-28 16:41:53 +02:00
ev_schedule ( p - > tx_ev ) ;
2021-03-29 22:45:21 +02:00
}
}
2021-03-28 16:41:53 +02:00
static void
bmp_fire_tx ( void * p_ )
2021-03-29 22:45:21 +02:00
{
2024-08-19 15:04:13 +02:00
log ( " fire " ) ;
2021-03-28 16:41:53 +02:00
struct bmp_proto * p = p_ ;
2023-06-08 05:10:05 +02:00
if ( ! p - > started )
return ;
2021-03-29 22:45:21 +02:00
IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL (
2021-03-28 15:13:23 +02:00
EMPTY_LIST ( p - > tx_queue ) ,
2021-03-29 22:45:21 +02:00
" Called BMP TX event handler when there is not any data to send "
) ;
size_t cnt = 0 ; // Counts max packets which we want to send per TX slot
struct bmp_data_node * tx_data ;
struct bmp_data_node * tx_data_next ;
2021-03-28 15:13:23 +02:00
WALK_LIST_DELSAFE ( tx_data , tx_data_next , p - > tx_queue )
2021-03-29 22:45:21 +02:00
{
2024-08-19 15:04:13 +02:00
log ( " WALK_LIST_DELSAFE " ) ;
2021-03-28 16:41:53 +02:00
if ( tx_data - > data_size > p - > sk - > tbsize )
2021-03-29 22:45:21 +02:00
{
2021-03-28 16:41:53 +02:00
sk_set_tbsize ( p - > sk , tx_data - > data_size ) ;
2021-03-29 22:45:21 +02:00
}
2021-03-28 15:13:23 +02:00
size_t data_size = tx_data - > data_size ;
2023-06-08 05:10:05 +02:00
memcpy ( p - > sk - > tbuf , tx_data - > data , data_size ) ;
2021-03-29 22:45:21 +02:00
mb_free ( tx_data - > data ) ;
rem_node ( ( node * ) tx_data ) ;
mb_free ( tx_data ) ;
2024-08-19 15:04:13 +02:00
log ( " walk ifs for returns socket %i, data size %i " , p - > sk , data_size ) ;
2023-04-20 17:14:45 +02:00
if ( sk_send ( p - > sk , data_size ) < = 0 )
return ;
2021-03-29 22:45:21 +02:00
// BMP packets should be treat with lowest priority when scheduling sending
// packets to target. That's why we want to send max. 32 packets per event
// call
if ( + + cnt > 32 )
{
2021-03-28 16:41:53 +02:00
if ( ! ev_active ( p - > tx_ev ) )
2021-03-29 22:45:21 +02:00
{
2021-03-28 16:41:53 +02:00
ev_schedule ( p - > tx_ev ) ;
2021-03-29 22:45:21 +02:00
}
return ;
}
}
}
static void
bmp_tx ( struct birdsock * sk )
{
bmp_fire_tx ( sk - > data ) ;
}
2023-04-20 16:13:58 +02:00
/* We need RX hook just to accept socket close events */
static int
bmp_rx ( struct birdsock * sk UNUSED , uint size UNUSED )
2021-03-29 22:45:21 +02:00
{
2023-04-20 16:13:58 +02:00
return 0 ;
2021-03-29 22:45:21 +02:00
}
2021-03-28 15:36:59 +02:00
static inline void
bmp_put_ipa ( buffer * stream , const ip_addr addr )
2021-03-29 22:45:21 +02:00
{
2021-03-28 15:36:59 +02:00
bmp_put_ip6 ( stream , ipa_is_ip4 ( addr ) ?
ip6_build ( 0 , 0 , 0 , ipa_to_u32 ( addr ) ) :
ipa_to_ip6 ( addr ) ) ;
2021-03-29 22:45:21 +02:00
}
static void
2023-05-01 03:35:21 +02:00
bmp_put_bgp_hdr ( buffer * stream , const u8 msg_type , const u16 msg_length )
2021-03-29 22:45:21 +02:00
{
2023-05-01 03:35:21 +02:00
bmp_buffer_need ( stream , BGP_HEADER_LENGTH ) ;
memset ( stream - > pos , 0xff , BGP_HDR_MARKER_LENGTH ) ;
stream - > pos + = BGP_HDR_MARKER_LENGTH ;
bmp_put_u16 ( stream , msg_length ) ;
2021-03-29 22:45:21 +02:00
bmp_put_u8 ( stream , msg_type ) ;
}
/**
* bmp_per_peer_hdr_serialize - serializes Per - Peer Header
*
2023-08-18 03:53:58 +02:00
* @ is_post_policy : indicate the message reflects the post - policy Adj - RIB - In
2021-03-29 22:45:21 +02:00
* @ peer_addr : the remote IP address associated with the TCP session
* @ peer_as : the Autonomous System number of the peer
* @ peer_bgp_id : the BGP Identifier of the peer
* @ ts_sec : the time in seconds when the encapsulated routes were received
* @ ts_usec : the time in microseconds when the encapsulated routes were received
*/
static void
bmp_per_peer_hdr_serialize ( buffer * stream , const bool is_global_instance_peer ,
2023-08-18 03:53:58 +02:00
const bool is_post_policy , const bool is_as_path_4bytes ,
2021-03-29 22:45:21 +02:00
const ip_addr peer_addr , const u32 peer_as , const u32 peer_bgp_id ,
const u32 ts_sec , const u32 ts_usec )
{
// TODO: ATM we don't support BMP_PEER_TYPE_RD_INSTANCE
const enum bmp_peer_type peer_type = is_global_instance_peer
? BMP_PEER_TYPE_GLOBAL_INSTANCE
: BMP_PEER_TYPE_LOCAL_INSTANCE ;
const u8 peer_flag_v = ipa_is_ip4 ( peer_addr )
? BMP_PEER_HDR_FLAG_V_IP4
: BMP_PEER_HDR_FLAG_V_IP6 ;
2023-08-18 03:53:58 +02:00
const u8 peer_flag_l = is_post_policy
? BMP_PEER_HDR_FLAG_L_POST_POLICY_ADJ_RIB_IN
: BMP_PEER_HDR_FLAG_L_PRE_POLICY_ADJ_RIB_IN ;
2021-03-29 22:45:21 +02:00
const u8 peer_flag_a = is_as_path_4bytes
? BMP_PEER_HDR_FLAG_A_AS_PATH_4B
: BMP_PEER_HDR_FLAG_A_AS_PATH_2B ;
u8 peer_flags ;
BMP_PEER_HDR_FLAGS_INIT ( peer_flags ) ;
BMP_PEER_HDR_FLAGS_SET ( peer_flags , peer_flag_v ) ;
BMP_PEER_HDR_FLAGS_SET ( peer_flags , peer_flag_l ) ;
BMP_PEER_HDR_FLAGS_SET ( peer_flags , peer_flag_a ) ;
bmp_put_u8 ( stream , peer_type ) ;
bmp_put_u8 ( stream , peer_flags ) ;
// TODO: Provide appropriate peer Route Distinguisher if applicable
bmp_put_u64 ( stream , 0x00 ) ; // 0x00 - Not supported peer distinguisher
2021-03-28 15:36:59 +02:00
bmp_put_ipa ( stream , peer_addr ) ;
2021-03-29 22:45:21 +02:00
bmp_put_u32 ( stream , peer_as ) ;
bmp_put_u32 ( stream , peer_bgp_id ) ;
bmp_put_u32 ( stream , ts_sec ) ;
bmp_put_u32 ( stream , ts_usec ) ;
}
/* [4.6] Route Monitoring */
static void
bmp_route_monitor_msg_serialize ( buffer * stream , const bool is_peer_global ,
2023-08-18 03:53:58 +02:00
const bool table_in_post_policy , const u32 peer_as , const u32 peer_bgp_id ,
2021-03-29 22:45:21 +02:00
const bool as4_support , const ip_addr remote_addr , const byte * update_msg ,
2023-08-01 17:56:56 +02:00
const size_t update_msg_size , btime timestamp )
2021-03-29 22:45:21 +02:00
{
const size_t data_size = BMP_PER_PEER_HDR_SIZE + update_msg_size ;
2023-08-01 17:56:56 +02:00
u32 ts_sec = timestamp TO_S ;
u32 ts_usec = timestamp - ( ts_sec S ) ;
2021-03-29 22:45:21 +02:00
bmp_buffer_need ( stream , BMP_COMMON_HDR_SIZE + data_size ) ;
bmp_common_hdr_serialize ( stream , BMP_ROUTE_MONITOR , data_size ) ;
2023-08-18 03:53:58 +02:00
bmp_per_peer_hdr_serialize ( stream , is_peer_global , table_in_post_policy ,
2021-03-29 22:45:21 +02:00
as4_support , remote_addr , peer_as , peer_bgp_id , ts_sec , ts_usec ) ;
bmp_put_data ( stream , update_msg , update_msg_size ) ;
}
static void
bmp_peer_up_notif_msg_serialize ( buffer * stream , const bool is_peer_global ,
const u32 peer_as , const u32 peer_bgp_id , const bool as4_support ,
const ip_addr local_addr , const ip_addr remote_addr , const u16 local_port ,
2023-05-30 15:52:01 +02:00
const u16 remote_port , const byte * sent_msg , const size_t sent_msg_length ,
const byte * recv_msg , const size_t recv_msg_length )
2021-03-29 22:45:21 +02:00
{
2023-05-01 03:35:21 +02:00
const size_t data_size =
BMP_PER_PEER_HDR_SIZE + BMP_PEER_UP_NOTIF_MSG_FIX_SIZE +
2023-05-30 15:52:01 +02:00
BGP_HEADER_LENGTH + sent_msg_length + BGP_HEADER_LENGTH + recv_msg_length ;
2023-05-01 03:35:21 +02:00
2021-03-29 22:45:21 +02:00
bmp_buffer_need ( stream , BMP_COMMON_HDR_SIZE + data_size ) ;
bmp_common_hdr_serialize ( stream , BMP_PEER_UP_NOTIF , data_size ) ;
bmp_per_peer_hdr_serialize ( stream , is_peer_global ,
2023-08-18 03:53:58 +02:00
false /* TODO: Hardcoded pre-policy Adj-RIB-In */ , as4_support , remote_addr ,
2021-03-29 22:45:21 +02:00
peer_as , peer_bgp_id , 0 , 0 ) ; // 0, 0 - No timestamp provided
2021-03-28 15:36:59 +02:00
bmp_put_ipa ( stream , local_addr ) ;
2021-03-29 22:45:21 +02:00
bmp_put_u16 ( stream , local_port ) ;
bmp_put_u16 ( stream , remote_port ) ;
2023-05-30 15:52:01 +02:00
bmp_put_bgp_hdr ( stream , PKT_OPEN , BGP_HEADER_LENGTH + sent_msg_length ) ;
bmp_put_data ( stream , sent_msg , sent_msg_length ) ;
bmp_put_bgp_hdr ( stream , PKT_OPEN , BGP_HEADER_LENGTH + recv_msg_length ) ;
bmp_put_data ( stream , recv_msg , recv_msg_length ) ;
2021-03-29 22:45:21 +02:00
}
static void
bmp_peer_down_notif_msg_serialize ( buffer * stream , const bool is_peer_global ,
const u32 peer_as , const u32 peer_bgp_id , const bool as4_support ,
const ip_addr remote_addr , const byte * data , const size_t data_size )
{
const size_t payload_size = BMP_PER_PEER_HDR_SIZE + data_size ;
bmp_buffer_need ( stream , BMP_COMMON_HDR_SIZE + payload_size ) ;
bmp_common_hdr_serialize ( stream , BMP_PEER_DOWN_NOTIF , payload_size ) ;
bmp_per_peer_hdr_serialize ( stream , is_peer_global ,
2023-08-18 03:53:58 +02:00
false /* TODO: Hardcoded pre-policy adj RIB IN */ , as4_support , remote_addr ,
2021-03-29 22:45:21 +02:00
peer_as , peer_bgp_id , 0 , 0 ) ; // 0, 0 - No timestamp provided
bmp_put_data ( stream , data , data_size ) ;
}
2023-08-18 03:53:58 +02:00
/*
* BMP tables
*/
static struct bmp_table *
2024-07-04 13:13:38 +02:00
bmp_find_table ( struct bmp_proto * p , rtable * tab )
2023-08-18 03:53:58 +02:00
{
return HASH_FIND ( p - > table_map , HASH_TABLE , tab ) ;
}
2024-08-19 15:04:13 +02:00
const struct channel_class channel_bmp = {
. channel_size = sizeof ( struct channel ) ,
. config_size = sizeof ( struct channel_config ) ,
/*.init =
. start =
. shutdown =
. cleanup =
. reconfigure = */
} ;
2023-08-18 03:53:58 +02:00
static struct bmp_table *
2024-07-04 13:13:38 +02:00
bmp_add_table ( struct bmp_proto * p , rtable * tab )
2024-09-04 13:48:40 +02:00
{
struct bmp_table * bt = mb_allocz ( p - > p . pool , sizeof ( struct bmp_table ) ) ;
log ( " adding table %x " , bt ) ;
bt - > table = tab ;
2024-09-06 12:17:05 +02:00
bt - > p = p ;
2024-09-04 13:48:40 +02:00
rt_lock_table ( bt - > table ) ;
HASH_INSERT ( p - > table_map , HASH_TABLE , bt ) ;
2024-09-06 12:17:05 +02:00
bt - > event . data = bt ;
2024-09-19 09:54:06 +02:00
log ( " name %s post %i pre %i " , p - > p . name , p - > monitoring_rib . in_post_policy , p - > monitoring_rib . in_pre_policy ) ;
2024-09-04 13:48:40 +02:00
2024-09-19 09:54:06 +02:00
//if(p->monitoring_rib.in_post_policy){
bt - > event . hook = bmp_check_routes ;
2024-09-04 14:42:00 +02:00
bt - > out_req = ( struct rt_export_request ) {
2024-09-04 13:48:40 +02:00
. name = mb_sprintf ( p - > p . pool , " %s.exp_request " , p - > p . name ) ,
. r = ( struct lfjour_recipient ) {
2024-09-06 12:17:05 +02:00
. target = proto_event_list ( & p - > p ) , //&p->p.loop->event_list,
. event = & bt - > event ,
2024-09-04 13:48:40 +02:00
} ,
. pool = p - > p . pool ,
. trace_routes = p - > p . debug ,
2024-09-19 11:26:32 +02:00
//.dump = channel_dump_export_req, TODO: this will crash on `dump tables` from CLI
. fed = bmp_feed_end ,
2024-09-04 13:48:40 +02:00
} ;
2024-09-19 09:54:06 +02:00
rt_export_subscribe ( tab , all , & bt - > out_req ) ; //}
2024-09-04 13:48:40 +02:00
return bt ;
}
2024-09-11 11:35:29 +02:00
/*static void
2023-08-18 03:53:58 +02:00
bmp_remove_table ( struct bmp_proto * p , struct bmp_table * bt )
{
2024-08-27 15:02:38 +02:00
log ( " removing table - bmp table %x chann %x, (subscr %x uc %x) " , bt , bt - > channel , & bt - > channel - > roa_subscriptions , & bt - > uc ) ;
2024-07-04 13:13:38 +02:00
channel_set_state ( bt - > channel , CS_STOP ) ;
2023-08-18 03:53:58 +02:00
channel_set_state ( bt - > channel , CS_DOWN ) ;
proto_remove_channel ( & p - > p , bt - > channel ) ;
HASH_REMOVE ( p - > table_map , HASH_TABLE , bt ) ;
rt_unlock_table ( bt - > table ) ;
bt - > table = NULL ;
2024-08-27 15:02:38 +02:00
log ( " free table %x " , bt ) ;
2023-08-18 03:53:58 +02:00
mb_free ( bt ) ;
2024-09-11 11:35:29 +02:00
} */
2023-08-18 03:53:58 +02:00
2024-09-04 13:48:40 +02:00
static void
2024-09-10 09:29:12 +02:00
bmp_remove_table_rt ( struct bmp_proto * p , struct bmp_table * bt ) // still falling in krt routes... The thread synchronization was maybe not needed...
2024-09-04 13:48:40 +02:00
{
log ( " removing table - bmp table %x chann %x, (subscr %x uc %x) " , bt , bt - > channel , & bt - > channel - > roa_subscriptions , & bt - > uc ) ;
2024-09-10 09:29:12 +02:00
if ( bt - > channel )
{
channel_set_state ( bt - > channel , CS_STOP ) ;
channel_set_state ( bt - > channel , CS_DOWN ) ;
}
2024-09-19 09:54:06 +02:00
//if (p->monitoring_rib.in_post_policy)
rt_export_unsubscribe ( all , & bt - > out_req ) ;
//else
//rt_feeder_unsubscribe(&bt->in_req);
2024-09-04 13:48:40 +02:00
HASH_REMOVE ( p - > table_map , HASH_TABLE , bt ) ;
rt_unlock_table ( bt - > table ) ;
bt - > table = NULL ;
log ( " free table %x " , bt ) ;
mb_free ( bt ) ;
2024-09-10 09:29:12 +02:00
//log("free done");
2024-09-04 13:48:40 +02:00
}
2023-08-18 03:53:58 +02:00
static inline void bmp_lock_table ( struct bmp_proto * p UNUSED , struct bmp_table * bt )
{ bt - > uc + + ; }
2024-09-10 09:29:12 +02:00
struct bmp_table * bmp_get_table ( struct bmp_proto * p , rtable * tab )
{
struct bmp_table * bt = bmp_find_table ( p , tab ) ;
if ( bt )
{
while ( true ) {
atomic_int i = bt - > uc ;
if ( i = = 0 )
{
2024-09-19 11:26:32 +02:00
struct bmp_table * new = bmp_add_table ( p , tab ) ;
2024-09-10 09:29:12 +02:00
bmp_lock_table ( p , new ) ;
return new ;
}
if ( atomic_compare_exchange_strong_explicit ( & bt - > uc , & i , i + 1 , memory_order_acq_rel , memory_order_relaxed ) )
return bt ;
}
}
2024-09-19 11:26:32 +02:00
struct bmp_table * new = bmp_add_table ( p , tab ) ;
2024-09-10 09:29:12 +02:00
bmp_lock_table ( p , new ) ;
return new ;
}
2023-08-18 03:53:58 +02:00
static inline void bmp_unlock_table ( struct bmp_proto * p , struct bmp_table * bt )
2024-09-10 09:29:12 +02:00
{ atomic_int i = 1 ;
if ( atomic_compare_exchange_strong_explicit ( & bt - > uc , & i , 0 , memory_order_acq_rel , memory_order_relaxed ) )
bmp_remove_table_rt ( p , bt ) ;
else
bt - > uc - - ;
}
2023-08-18 03:53:58 +02:00
/*
* BMP streams
*/
static inline u32 bmp_stream_key ( u32 afi , bool policy )
{ return afi ^ ( policy ? BMP_STREAM_KEY_POLICY : 0 ) ; }
2024-09-19 09:54:06 +02:00
//static inline u32 bmp_stream_afi(struct bmp_stream *bs)
//{ return bs->key & ~BMP_STREAM_KEY_POLICY; }
2023-08-18 03:53:58 +02:00
static inline bool bmp_stream_policy ( struct bmp_stream * bs )
{ return ! ! ( bs - > key & BMP_STREAM_KEY_POLICY ) ; }
static struct bmp_stream *
2024-08-19 15:04:13 +02:00
bmp_find_stream ( struct bmp_proto * p , const struct bgp_proto * bgp , u32 afi , bool policy )
2023-08-18 03:53:58 +02:00
{
2024-08-19 15:04:13 +02:00
ea_list * bgp_attr = proto_state_table - > attrs [ bgp - > p . id ] ;
return HASH_FIND ( p - > stream_map , HASH_STREAM , bgp_attr , bmp_stream_key ( afi , policy ) ) ;
2024-09-19 09:54:06 +02:00
2023-08-18 03:53:58 +02:00
}
static struct bmp_stream *
2024-07-04 13:13:38 +02:00
bmp_add_stream ( struct bmp_proto * p , struct bmp_peer * bp , u32 afi , bool policy , rtable * tab , ea_list * sender , int in_pre_policy )
2023-08-18 03:53:58 +02:00
{
struct bmp_stream * bs = mb_allocz ( p - > p . pool , sizeof ( struct bmp_stream ) ) ;
2024-08-27 15:02:38 +02:00
log ( " add stream to p %i bs %x " , p , bs ) ;
2023-08-18 03:53:58 +02:00
bs - > bgp = bp - > bgp ;
bs - > key = bmp_stream_key ( afi , policy ) ;
add_tail ( & bp - > streams , & bs - > n ) ;
HASH_INSERT ( p - > stream_map , HASH_STREAM , bs ) ;
bs - > table = bmp_get_table ( p , tab ) ;
2024-09-10 09:29:12 +02:00
//bmp_lock_table(p, bs->table);
2023-08-18 03:53:58 +02:00
bs - > sender = sender ;
2023-08-21 04:20:32 +02:00
bs - > sync = false ;
2024-07-04 13:13:38 +02:00
bs - > in_pre_policy = in_pre_policy ;
2023-08-18 03:53:58 +02:00
return bs ;
}
static void
bmp_remove_stream ( struct bmp_proto * p , struct bmp_stream * bs )
{
2024-08-27 15:02:38 +02:00
log ( " go to unlock table " ) ;
2023-08-18 03:53:58 +02:00
rem_node ( & bs - > n ) ;
HASH_REMOVE ( p - > stream_map , HASH_STREAM , bs ) ;
bmp_unlock_table ( p , bs - > table ) ;
bs - > table = NULL ;
mb_free ( bs ) ;
}
/*
* BMP peers
*/
static struct bmp_peer *
2024-07-04 13:13:38 +02:00
bmp_find_peer ( struct bmp_proto * p , ea_list * bgp_attr )
2023-08-18 03:53:58 +02:00
{
2024-08-19 15:04:13 +02:00
return HASH_FIND ( p - > peer_map , HASH_PEER , bgp_attr ) ;
2023-08-18 03:53:58 +02:00
}
static struct bmp_peer *
2024-07-04 13:13:38 +02:00
bmp_add_peer ( struct bmp_proto * p , ea_list * bgp_attr )
2023-08-18 03:53:58 +02:00
{
2024-07-26 17:24:15 +02:00
log ( " domain is locked %i, service is locked %i " , DG_IS_LOCKED ( p - > p . pool - > domain ) , locking_stack . service ) ;
struct bmp_peer * bp ;
if ( DG_IS_LOCKED ( p - > p . pool - > domain ) )
bp = mb_allocz ( p - > p . pool , sizeof ( struct bmp_peer ) ) ;
else
{
DG_LOCK ( p - > p . pool - > domain ) ;
bp = mb_allocz ( p - > p . pool , sizeof ( struct bmp_peer ) ) ;
DG_UNLOCK ( p - > p . pool - > domain ) ;
}
2024-08-27 15:02:38 +02:00
log ( " bmp_peer %x " , bp ) ;
2024-07-04 13:13:38 +02:00
bp - > bgp = bgp_attr ;
2023-08-18 03:53:58 +02:00
init_list ( & bp - > streams ) ;
HASH_INSERT ( p - > peer_map , HASH_PEER , bp ) ;
2024-09-06 12:17:05 +02:00
int proto_id = ea_get_int ( bgp_attr , & ea_proto_id , 0 ) ;
2024-08-28 17:11:50 +02:00
2024-08-19 15:04:13 +02:00
struct channel_attrs * chan_attr ;
2024-07-26 17:24:15 +02:00
log ( " before while id %i, eattrs %i " , proto_id , proto_state_table - > channels_attrs [ proto_id ] ) ;
2024-09-06 12:17:05 +02:00
WALK_TLIST ( channel_attrs , chan_attr , & proto_state_table - > channels_attrs [ proto_id ] )
2023-08-18 03:53:58 +02:00
{
2024-08-19 15:04:13 +02:00
log ( " chan_attr in bmp_add_peer %i, attrs %i " , chan_attr , chan_attr - > attrs ) ;
rtable * ch_table = ( rtable * ) ea_get_ptr ( chan_attr - > attrs , & ea_rtable , 0 ) ;
2024-09-19 09:54:06 +02:00
const char * name = ea_get_adata ( chan_attr - > attrs , & ea_name ) - > data ;
int in_keep = ea_get_int ( chan_attr - > attrs , & ea_in_keep , 0 ) ;
log ( " name %s ch_table %i first if %i second if %i in keep %i " , name , ch_table , p - > monitoring_rib . in_pre_policy , p - > monitoring_rib . in_post_policy , in_keep ) ;
2024-08-19 15:04:13 +02:00
2024-07-04 13:13:38 +02:00
if ( p - > monitoring_rib . in_pre_policy & & ch_table )
2024-09-19 09:54:06 +02:00
{
log ( " in pre " ) ;
if ( in_keep = = RIK_PREFILTER )
{
log ( " add stream in keep %i " , in_keep ) ;
bmp_add_stream ( p , bp , ea_get_int ( chan_attr - > attrs , & ea_bgp_afi , 0 ) , false , ch_table , chan_attr - > attrs , 1 ) ;
}
else
log ( L_WARN " %s: Try to do pre policy with disabled import tables (channel %s) " , p - > p . name , name ) ;
}
2023-08-18 03:53:58 +02:00
2024-07-04 13:13:38 +02:00
if ( p - > monitoring_rib . in_post_policy & & ch_table )
2024-09-19 09:54:06 +02:00
{
log ( " in post " ) ;
2024-08-19 15:04:13 +02:00
bmp_add_stream ( p , bp , ea_get_int ( chan_attr - > attrs , & ea_bgp_afi , 0 ) , true , ch_table , chan_attr - > attrs , 0 ) ;
2024-09-19 09:54:06 +02:00
}
2023-08-18 03:53:58 +02:00
}
return bp ;
}
static void
bmp_remove_peer ( struct bmp_proto * p , struct bmp_peer * bp )
{
struct bmp_stream * bs , * bs_next ;
WALK_LIST_DELSAFE ( bs , bs_next , bp - > streams )
2024-09-10 09:29:12 +02:00
bmp_remove_stream ( p , bs ) ; //TODO//TODO//TODO
2023-08-18 03:53:58 +02:00
HASH_REMOVE ( p - > peer_map , HASH_PEER , bp ) ;
mb_free ( bp ) ;
}
static void
2024-07-04 13:13:38 +02:00
bmp_peer_up_ ( struct bmp_proto * p , ea_list * bgp_attr , bool sync ,
2023-05-01 03:35:21 +02:00
const byte * tx_open_msg , uint tx_open_length ,
const byte * rx_open_msg , uint rx_open_length )
2021-03-29 22:45:21 +02:00
{
2023-06-08 04:56:41 +02:00
if ( ! p - > started )
2023-05-01 03:35:21 +02:00
return ;
2021-03-29 22:45:21 +02:00
2024-07-04 13:13:38 +02:00
struct bmp_peer * bp = bmp_find_peer ( p , bgp_attr ) ;
2023-08-18 03:53:58 +02:00
if ( bp )
return ;
2024-07-11 14:43:32 +02:00
const char * name = ea_get_adata ( bgp_attr , & ea_name ) - > data ;
2024-07-04 13:13:38 +02:00
TRACE ( D_STATES , " Peer up for %s " , name ) ;
2023-06-08 04:56:41 +02:00
2024-07-04 13:13:38 +02:00
bp = bmp_add_peer ( p , bgp_attr ) ;
2021-03-29 22:45:21 +02:00
2024-07-04 13:13:38 +02:00
bmp_send_peer_up_notif_msg ( p , bgp_attr , tx_open_msg , tx_open_length , rx_open_msg , rx_open_length ) ;
2023-05-01 03:35:21 +02:00
2023-08-21 04:20:32 +02:00
/*
* We asssume peer_up ( ) notifications are received before any route
* notifications from that peer . Therefore , peers established after BMP
* session coould be considered synced with empty RIB .
*/
if ( sync )
{
struct bmp_stream * bs ;
WALK_LIST ( bs , bp - > streams )
{
bmp_route_monitor_end_of_rib ( p , bs ) ;
bs - > sync = true ;
}
}
2023-06-08 04:56:41 +02:00
}
2024-08-28 15:58:15 +02:00
//void
//bmp_peer_up(ea_list *bgp,
// const byte *tx_open_msg, uint tx_open_length,
// const byte *rx_open_msg, uint rx_open_length)
//{
// struct bmp_proto *p; node *n;
// WALK_LIST2(p, n, bmp_proto_list, bmp_node)
// bmp_peer_up_(p, bgp, true, tx_open_msg, tx_open_length, rx_open_msg, rx_open_length);
//}
2024-08-27 15:02:38 +02:00
2021-03-29 22:45:21 +02:00
static void
2024-07-04 13:13:38 +02:00
bmp_peer_init ( struct bmp_proto * p , ea_list * bgp_attr )
2021-03-29 22:45:21 +02:00
{
2024-07-11 14:43:32 +02:00
const struct bgp_conn * conn = ( const struct bgp_conn * ) ea_get_ptr ( bgp_attr , & ea_bgp_conn , 0 ) ;
2023-05-01 03:35:21 +02:00
if ( ! conn | | ( conn - > state ! = BS_ESTABLISHED ) | |
! conn - > local_open_msg | | ! conn - > remote_open_msg )
return ;
2024-07-04 13:13:38 +02:00
bmp_peer_up_ ( p , bgp_attr , false , conn - > local_open_msg , conn - > local_open_length ,
2023-06-08 04:56:41 +02:00
conn - > remote_open_msg , conn - > remote_open_length ) ;
2021-03-29 22:45:21 +02:00
}
2023-08-18 03:53:58 +02:00
2021-03-29 22:45:21 +02:00
static const struct birdsock *
2024-07-11 14:43:32 +02:00
bmp_get_birdsock ( ea_list * bgp )
2021-03-29 22:45:21 +02:00
{
2024-07-11 14:43:32 +02:00
struct bgp_conn * conn = ( struct bgp_conn * ) ea_get_ptr ( bgp , & ea_bgp_conn , 0 ) ;
if ( conn & & conn - > sk )
return conn - > sk ;
2021-03-29 22:45:21 +02:00
return NULL ;
}
static const struct birdsock *
2024-07-11 14:43:32 +02:00
bmp_get_birdsock_ext ( ea_list * bgp )
2021-03-29 22:45:21 +02:00
{
const struct birdsock * sk = bmp_get_birdsock ( bgp ) ;
if ( sk ! = NULL )
return sk ;
2024-07-11 14:43:32 +02:00
struct bgp_conn * in_conn = ( struct bgp_conn * ) ea_get_ptr ( bgp , & ea_bgp_in_conn , 0 ) ;
struct bgp_conn * out_conn = ( struct bgp_conn * ) ea_get_ptr ( bgp , & ea_bgp_out_conn , 0 ) ;
if ( in_conn - > sk )
2021-03-29 22:45:21 +02:00
{
2024-07-11 14:43:32 +02:00
sk = in_conn - > sk ;
2021-03-29 22:45:21 +02:00
}
2024-07-11 14:43:32 +02:00
else if ( out_conn - > sk )
2021-03-29 22:45:21 +02:00
{
2024-07-11 14:43:32 +02:00
sk = out_conn - > sk ;
2021-03-29 22:45:21 +02:00
}
return sk ;
}
static const struct bgp_caps *
2024-08-28 15:58:15 +02:00
bmp_get_bgp_remote_caps ( struct bgp_conn * bgp_conn )
2021-03-29 22:45:21 +02:00
{
2024-08-28 15:58:15 +02:00
if ( bgp_conn & & bgp_conn - > remote_caps )
return bgp_conn - > remote_caps ;
2021-03-29 22:45:21 +02:00
return NULL ;
}
static const struct bgp_caps *
2024-08-28 15:58:15 +02:00
bmp_get_bgp_remote_caps_ext ( ea_list * bgp )
2021-03-29 22:45:21 +02:00
{
2024-08-28 15:58:15 +02:00
struct bgp_conn * bgp_conn = ( struct bgp_conn * ) ea_get_adata ( bgp , & ea_bgp_conn ) - > data ;
const struct bgp_caps * remote_caps = bmp_get_bgp_remote_caps ( bgp_conn ) ;
2021-03-29 22:45:21 +02:00
if ( remote_caps ! = NULL )
return remote_caps ;
2024-08-28 15:58:15 +02:00
struct bgp_conn * bgp_in_conn = ( struct bgp_conn * ) ea_get_adata ( bgp , & ea_bgp_in_conn ) - > data ;
struct bgp_conn * bgp_out_conn = ( struct bgp_conn * ) ea_get_adata ( bgp , & ea_bgp_out_conn ) - > data ;
if ( bgp_in_conn - > remote_caps )
2021-03-29 22:45:21 +02:00
{
2024-08-28 15:58:15 +02:00
remote_caps = bgp_in_conn - > remote_caps ;
2021-03-29 22:45:21 +02:00
}
2024-08-28 15:58:15 +02:00
else if ( bgp_out_conn - > remote_caps )
2021-03-29 22:45:21 +02:00
{
2024-08-28 15:58:15 +02:00
remote_caps = bgp_out_conn - > remote_caps ;
2021-03-29 22:45:21 +02:00
}
return remote_caps ;
}
static bool
2024-07-11 14:43:32 +02:00
bmp_is_peer_global_instance ( ea_list * bgp )
2021-03-29 22:45:21 +02:00
{
2024-07-11 14:43:32 +02:00
int peer_type = ea_get_int ( bgp , & ea_bgp_peer_type , 0 ) ;
int local_as = ea_get_int ( bgp , & ea_bgp_loc_as , 0 ) ;
int remote_as = ea_get_int ( bgp , & ea_bgp_rem_as , 0 ) ;
2024-09-19 09:54:06 +02:00
log ( " bmp_is_peer_global_instance loc as %i rem as %i peer_type %i (constants BGP_PT_EXTERNAL %i, BGP_PT_INTERNAL %i) " , local_as , remote_as , peer_type , BGP_PT_EXTERNAL , BGP_PT_INTERNAL ) ;
2024-07-11 14:43:32 +02:00
return ( peer_type ! = BGP_PT_EXTERNAL & &
peer_type ! = BGP_PT_INTERNAL )
? ( local_as ! = remote_as )
: ( peer_type = = BGP_PT_EXTERNAL ) ;
2021-03-29 22:45:21 +02:00
}
2021-03-28 04:30:11 +02:00
static void
2024-07-11 14:43:32 +02:00
bmp_send_peer_up_notif_msg ( struct bmp_proto * p , ea_list * bgp ,
2023-05-30 15:52:01 +02:00
const byte * tx_data , const size_t tx_data_size ,
const byte * rx_data , const size_t rx_data_size )
2021-03-29 22:45:21 +02:00
{
2023-04-20 16:13:58 +02:00
ASSERT ( p - > started ) ;
2021-03-29 22:45:21 +02:00
2021-03-28 04:30:11 +02:00
const struct birdsock * sk = bmp_get_birdsock_ext ( bgp ) ;
IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL (
sk ,
" [BMP] No BGP socket "
) ;
2021-03-29 22:45:21 +02:00
2024-07-11 14:43:32 +02:00
const int rem_as = ea_get_int ( bgp , & ea_bgp_rem_as , 0 ) ;
const int rem_id = ea_get_int ( bgp , & ea_bgp_rem_id , 0 ) ;
2024-09-19 09:54:06 +02:00
log ( " bmp_send_peer_up_notif_msg rem_as %i rem_id %i " , rem_as , rem_id ) ;
2021-03-29 22:45:21 +02:00
const bool is_global_instance_peer = bmp_is_peer_global_instance ( bgp ) ;
2021-03-28 15:13:23 +02:00
buffer payload = bmp_buffer_alloc ( p - > buffer_mpool , DEFAULT_MEM_BLOCK_SIZE ) ;
2021-03-29 22:45:21 +02:00
bmp_peer_up_notif_msg_serialize ( & payload , is_global_instance_peer ,
2024-07-11 14:43:32 +02:00
rem_as , rem_id , 1 ,
2021-03-29 22:45:21 +02:00
sk - > saddr , sk - > daddr , sk - > sport , sk - > dport , tx_data , tx_data_size ,
rx_data , rx_data_size ) ;
2021-03-28 15:13:23 +02:00
bmp_schedule_tx_packet ( p , bmp_buffer_data ( & payload ) , bmp_buffer_pos ( & payload ) ) ;
2021-04-15 18:32:47 +02:00
bmp_buffer_free ( & payload ) ;
2021-03-29 22:45:21 +02:00
}
2023-06-08 04:56:41 +02:00
static void
2023-08-18 15:39:08 +02:00
bmp_route_monitor_put_update ( struct bmp_proto * p , struct bmp_stream * bs , const byte * data , size_t length , btime timestamp )
2021-03-29 22:45:21 +02:00
{
2024-08-19 15:04:13 +02:00
struct bmp_data_node * upd_msg = mb_allocz ( p - > update_msg_mem_pool ,
2023-08-01 17:56:56 +02:00
sizeof ( struct bmp_data_node ) ) ;
upd_msg - > data = mb_alloc ( p - > update_msg_mem_pool , length ) ;
2024-08-27 15:02:38 +02:00
log ( " upd_msg %x, data %x " , upd_msg , upd_msg - > data ) ;
2023-08-01 17:56:56 +02:00
memcpy ( upd_msg - > data , data , length ) ;
upd_msg - > data_size = length ;
2024-09-19 09:54:06 +02:00
2023-08-01 17:56:56 +02:00
add_tail ( & p - > update_msg_queue , & upd_msg - > n ) ;
/* Save some metadata */
2024-07-11 14:43:32 +02:00
ea_list * bgp = bs - > bgp ;
upd_msg - > remote_as = ea_get_int ( bgp , & ea_bgp_rem_as , 0 ) ;
upd_msg - > remote_id = ea_get_int ( bgp , & ea_bgp_rem_id , 0 ) ;
upd_msg - > remote_ip = ea_get_ip ( bgp , & ea_bgp_rem_ip , IPA_NONE ) ;
2023-08-18 15:39:08 +02:00
upd_msg - > timestamp = timestamp ;
2023-08-01 17:56:56 +02:00
upd_msg - > global_peer = bmp_is_peer_global_instance ( bgp ) ;
2023-08-18 03:53:58 +02:00
upd_msg - > policy = bmp_stream_policy ( bs ) ;
2023-08-01 17:56:56 +02:00
/* Kick the commit */
if ( ! ev_active ( p - > update_ev ) )
ev_schedule ( p - > update_ev ) ;
2021-03-29 22:45:21 +02:00
}
2023-08-01 17:56:56 +02:00
static void
2024-09-19 11:26:32 +02:00
bmp_route_monitor_notify ( struct bmp_proto * p , struct bgp_proto * bgp_p , struct bmp_stream * bs , const struct rte * new )
2021-03-29 22:45:21 +02:00
{
2024-09-19 09:54:06 +02:00
log ( " notified " ) ;
2024-09-19 11:26:32 +02:00
bmp_route_monitor_end_of_rib ( p , bs ) ;
2023-08-01 17:56:56 +02:00
byte buf [ BGP_MAX_EXT_MSG_LENGTH ] ;
2024-09-19 11:26:32 +02:00
byte * end = bgp_bmp_encode_rte ( bs - > sender , bgp_p , buf , new ) ;
2021-03-29 22:45:21 +02:00
2024-09-19 11:26:32 +02:00
btime delta_t = new - > attrs ? current_time ( ) - new - > lastmod : 0 ;
2023-08-18 15:39:08 +02:00
btime timestamp = current_real_time ( ) - delta_t ;
2023-08-18 03:53:58 +02:00
if ( end )
2023-08-18 15:39:08 +02:00
bmp_route_monitor_put_update ( p , bs , buf , end - buf , timestamp ) ;
2023-08-18 03:53:58 +02:00
else
2024-09-19 11:26:32 +02:00
log ( L_WARN " %s: Cannot encode update for %N " , p - > p . name , new - > net ) ;
2023-06-08 04:56:41 +02:00
}
2021-03-28 15:13:23 +02:00
2023-06-08 04:56:41 +02:00
static void
2023-08-01 17:56:56 +02:00
bmp_route_monitor_commit ( void * p_ )
2023-06-08 04:56:41 +02:00
{
2023-08-01 17:56:56 +02:00
struct bmp_proto * p = p_ ;
2023-06-08 04:56:41 +02:00
if ( ! p - > started )
2021-03-29 22:45:21 +02:00
return ;
buffer payload
2023-08-01 17:56:56 +02:00
= bmp_buffer_alloc ( p - > buffer_mpool , DEFAULT_MEM_BLOCK_SIZE ) ;
2021-03-29 22:45:21 +02:00
2023-08-01 17:56:56 +02:00
struct bmp_data_node * data , * data_next ;
WALK_LIST_DELSAFE ( data , data_next , p - > update_msg_queue )
2021-03-29 22:45:21 +02:00
{
bmp_route_monitor_msg_serialize ( & payload ,
2023-08-18 03:53:58 +02:00
data - > global_peer , data - > policy ,
2023-08-01 17:56:56 +02:00
data - > remote_as , data - > remote_id , true ,
2023-08-01 18:39:38 +02:00
data - > remote_ip , data - > data , data - > data_size ,
2023-08-01 17:56:56 +02:00
data - > timestamp ) ;
2021-03-29 22:45:21 +02:00
2021-03-28 15:13:23 +02:00
bmp_schedule_tx_packet ( p , bmp_buffer_data ( & payload ) , bmp_buffer_pos ( & payload ) ) ;
2021-03-29 22:45:21 +02:00
bmp_buffer_flush ( & payload ) ;
2023-08-01 17:56:56 +02:00
mb_free ( data - > data ) ;
rem_node ( & data - > n ) ;
mb_free ( data ) ;
2021-03-29 22:45:21 +02:00
}
2021-04-15 18:32:47 +02:00
bmp_buffer_free ( & payload ) ;
2021-03-29 22:45:21 +02:00
}
2021-03-29 04:43:04 +02:00
static void
2023-08-18 03:53:58 +02:00
bmp_route_monitor_end_of_rib ( struct bmp_proto * p , struct bmp_stream * bs )
2021-03-29 22:45:21 +02:00
{
2024-07-11 14:43:32 +02:00
TRACE ( D_PACKETS , " Sending END-OF-RIB for %s.%s " , ea_get_adata ( bs - > bgp , & ea_name ) - > data , ea_get_adata ( bs - > sender , & ea_name ) - > data ) ;
2023-06-08 04:56:41 +02:00
byte rx_end_payload [ DEFAULT_MEM_BLOCK_SIZE ] ;
2024-07-11 14:43:32 +02:00
byte * pos = bgp_create_end_mark_ea_ ( bs - > sender , rx_end_payload + BGP_HEADER_LENGTH ) ;
2023-06-08 04:56:41 +02:00
memset ( rx_end_payload + BGP_MSG_HDR_MARKER_POS , 0xff ,
BGP_MSG_HDR_MARKER_SIZE ) ; // BGP UPDATE MSG marker
put_u16 ( rx_end_payload + BGP_MSG_HDR_LENGTH_POS , pos - rx_end_payload ) ;
put_u8 ( rx_end_payload + BGP_MSG_HDR_TYPE_POS , PKT_UPDATE ) ;
2023-08-18 15:39:08 +02:00
bmp_route_monitor_put_update ( p , bs , rx_end_payload , pos - rx_end_payload , current_real_time ( ) ) ;
2023-06-08 04:56:41 +02:00
}
2021-03-28 15:13:23 +02:00
2021-03-28 04:30:11 +02:00
static void
2024-08-28 15:58:15 +02:00
bmp_send_peer_down_notif_msg ( struct bmp_proto * p , ea_list * bgp ,
2023-05-30 15:52:01 +02:00
const byte * data , const size_t data_size )
2021-03-29 22:45:21 +02:00
{
2023-04-20 16:13:58 +02:00
ASSERT ( p - > started ) ;
2021-03-28 04:30:11 +02:00
2021-03-29 22:45:21 +02:00
const struct bgp_caps * remote_caps = bmp_get_bgp_remote_caps_ext ( bgp ) ;
2024-08-28 15:58:15 +02:00
bool is_global_instance_peer = bmp_is_peer_global_instance ( bgp ) ;
2021-03-29 22:45:21 +02:00
buffer payload
2021-03-28 15:13:23 +02:00
= bmp_buffer_alloc ( p - > buffer_mpool , DEFAULT_MEM_BLOCK_SIZE ) ;
2021-03-29 22:45:21 +02:00
bmp_peer_down_notif_msg_serialize ( & payload , is_global_instance_peer ,
2024-08-28 15:58:15 +02:00
ea_get_int ( bgp , & ea_bgp_rem_as , 0 ) , ea_get_int ( bgp , & ea_bgp_rem_id , 0 ) ,
remote_caps ? remote_caps - > as4_support : ea_get_int ( bgp , & ea_bgp_as4_session , 0 ) ,
* ( ( ip_addr * ) ea_get_adata ( bgp , & ea_bgp_rem_ip ) - > data ) , data , data_size ) ;
2021-03-28 15:13:23 +02:00
bmp_schedule_tx_packet ( p , bmp_buffer_data ( & payload ) , bmp_buffer_pos ( & payload ) ) ;
2021-03-29 22:45:21 +02:00
bmp_buffer_free ( & payload ) ;
}
2023-06-08 04:56:41 +02:00
static void
2024-08-28 15:58:15 +02:00
bmp_peer_down_ ( struct bmp_proto * p , ea_list * bgp ,
2023-08-22 01:24:21 +02:00
int err_class , int err_code , int err_subcode , const byte * data , int length )
2021-03-29 22:45:21 +02:00
{
2023-06-08 04:56:41 +02:00
if ( ! p - > started )
2021-03-29 22:45:21 +02:00
return ;
2024-08-28 15:58:15 +02:00
struct bmp_peer * bp = bmp_find_peer ( p , bgp ) ;
2023-08-18 03:53:58 +02:00
if ( ! bp )
return ;
2023-06-08 04:56:41 +02:00
2024-08-28 15:58:15 +02:00
TRACE ( D_STATES , " Peer down for %s " , ea_find ( bgp , & ea_name ) - > u . ad - > data ) ;
2021-03-29 22:45:21 +02:00
2023-08-22 01:24:21 +02:00
uint bmp_code = 0 ;
uint fsm_code = 0 ;
2023-04-20 17:14:45 +02:00
2023-08-22 01:24:21 +02:00
switch ( err_class )
2021-03-29 22:45:21 +02:00
{
2023-08-22 01:24:21 +02:00
case BE_BGP_RX :
bmp_code = BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION ;
break ;
case BE_BGP_TX :
case BE_AUTO_DOWN :
case BE_MAN_DOWN :
bmp_code = BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION ;
break ;
default :
bmp_code = BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION ;
length = 0 ;
break ;
2021-03-29 22:45:21 +02:00
}
2023-08-22 01:24:21 +02:00
buffer payload = bmp_buffer_alloc ( p - > buffer_mpool , 1 + BGP_HEADER_LENGTH + 2 + length ) ;
bmp_put_u8 ( & payload , bmp_code ) ;
switch ( bmp_code )
2021-03-29 22:45:21 +02:00
{
2023-08-22 01:24:21 +02:00
case BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION :
case BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION :
bmp_put_bgp_hdr ( & payload , BGP_HEADER_LENGTH + 2 + length , PKT_NOTIFICATION ) ;
bmp_put_u8 ( & payload , err_code ) ;
bmp_put_u8 ( & payload , err_subcode ) ;
bmp_put_data ( & payload , data , length ) ;
break ;
case BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION :
bmp_put_u16 ( & payload , fsm_code ) ;
break ;
2021-03-29 22:45:21 +02:00
}
2021-03-28 15:13:23 +02:00
bmp_send_peer_down_notif_msg ( p , bgp , bmp_buffer_data ( & payload ) , bmp_buffer_pos ( & payload ) ) ;
2021-03-29 22:45:21 +02:00
bmp_buffer_free ( & payload ) ;
2023-08-18 03:53:58 +02:00
bmp_remove_peer ( p , bp ) ;
2021-03-29 22:45:21 +02:00
}
2024-08-28 15:58:15 +02:00
//#if 0
//void
//bmp_peer_down(const struct bgp_proto *bgp,
// int err_class, int code, int subcode, const byte *data, int length)
//{
// int need_unlock = 1;
// if (DG_IS_LOCKED(p->p.pool->domain))
// need_unlock = 0;
// else
// DG_LOCK(p->p.pool->domain);
// struct bmp_proto *p; node *n;
// WALK_LIST2(p, n, bmp_proto_list, bmp_node)
// bmp_peer_down_(p, bgp, err_class, code, subcode, data, length);
// if (need_unlock)
// DG_UNLOCK(p->p.pool->domain);
//}
//#endif
2023-06-08 04:56:41 +02:00
2021-03-28 04:30:11 +02:00
static void
2021-03-28 15:13:23 +02:00
bmp_send_termination_msg ( struct bmp_proto * p ,
2021-03-29 22:45:21 +02:00
const enum bmp_term_reason reason )
{
const size_t term_msg_hdr_size = BMP_TERM_INFO_TYPE_SIZE
+ BMP_TERM_INFO_LEN_FIELD_SIZE
+ BMP_TERM_REASON_CODE_SIZE ;
const size_t term_msg_size = BMP_COMMON_HDR_SIZE + term_msg_hdr_size ;
2021-03-28 16:41:53 +02:00
buffer stream = bmp_buffer_alloc ( p - > buffer_mpool , term_msg_size ) ;
2021-03-29 22:45:21 +02:00
bmp_common_hdr_serialize ( & stream , BMP_TERM_MSG , term_msg_hdr_size ) ;
bmp_put_u16 ( & stream , BMP_TERM_INFO_REASON ) ;
bmp_put_u16 ( & stream , BMP_TERM_REASON_CODE_SIZE ) ; // 2-byte code indication the reason
bmp_put_u16 ( & stream , reason ) ;
2021-03-28 16:41:53 +02:00
memcpy ( p - > sk - > tbuf , bmp_buffer_data ( & stream ) , bmp_buffer_pos ( & stream ) ) ;
2021-03-28 04:30:11 +02:00
IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL (
2021-03-28 16:41:53 +02:00
sk_send ( p - > sk , bmp_buffer_pos ( & stream ) ) < 0 ,
2021-03-28 04:30:11 +02:00
" Failed to send BMP termination message "
) ;
2021-03-29 22:45:21 +02:00
2024-08-27 15:02:38 +02:00
log ( " bmp_send_termination_msg free %x " , stream ) ;
2021-03-29 22:45:21 +02:00
bmp_buffer_free ( & stream ) ;
}
2023-08-18 03:53:58 +02:00
int
bmp_preexport ( struct channel * C UNUSED , rte * e )
{
2024-07-04 13:13:38 +02:00
/* Reject non-direct routes. Check if sender proto is the same as proto which created the route.
* It assumes that route was created in a protocol .
*/
struct rt_import_request * req = e - > sender - > req ;
struct channel * ch = SKIP_BACK ( struct channel , in_req , req ) ;
struct rte_owner * owner = e - > src - > owner ;
struct proto * p = SKIP_BACK ( struct proto , sources , owner ) ;
if ( ch - > proto ! = p )
2023-08-18 03:53:58 +02:00
return - 1 ;
/* Reject non-BGP routes */
2024-07-04 13:13:38 +02:00
if ( p - > proto ! = & proto_bgp )
2023-08-18 03:53:58 +02:00
return - 1 ;
return 1 ;
}
2024-09-06 12:17:05 +02:00
int
2024-09-10 09:29:12 +02:00
bgp_next_hop_present ( const rte * n )
2024-09-06 12:17:05 +02:00
{
for ( int i = 0 ; i < n - > attrs - > count ; i + + )
{
eattr a = n - > attrs - > attrs [ i ] ;
const struct ea_class * class = ea_class_find ( a . id ) ;
log ( " ea class %s " , class - > name ) ;
2024-09-10 09:29:12 +02:00
if ( class = = bgp_next_hop_ea_class )
return 1 ;
2024-09-06 12:17:05 +02:00
}
2024-09-10 09:29:12 +02:00
log ( " BAD RTE, BAD. " ) ;
2024-09-06 12:17:05 +02:00
return 0 ;
}
2024-09-19 10:25:28 +02:00
static void
solve_for_post_and_pre ( struct bmp_proto * p , const rte * new , const rte * old )
2024-09-19 09:54:06 +02:00
{
2024-09-19 11:26:32 +02:00
rte loc = * ( new ? : old ) ;
struct proto * rte_proto = ( struct proto * ) SKIP_BACK ( struct proto , sources , loc . src - > owner ) ;
2024-09-19 09:54:06 +02:00
struct bgp_proto * bgp = ( struct bgp_proto * ) rte_proto ;
2024-09-19 11:26:32 +02:00
struct bgp_channel * src_ch = SKIP_BACK ( struct bgp_channel , c . in_req , loc . sender - > req ) ;
2024-09-19 10:25:28 +02:00
ASSERT_DIE ( src_ch - > c . proto = = rte_proto ) ; /* No pipes supported for now */
log ( " solve_for_post_and_pre %s " , rte_proto - > name ) ;
/* Ignore non-BGP routes */
if ( rte_proto - > proto ! = & proto_bgp )
return ;
2024-09-19 09:54:06 +02:00
2024-09-19 10:25:28 +02:00
/* Checking the pre policy */
if ( p - > monitoring_rib . in_pre_policy )
2024-09-19 09:54:06 +02:00
{
2024-09-19 10:25:28 +02:00
/* Compute the pre policy attributes */
ea_list * new_attrs = new ? ea_strip_to ( new - > attrs , BIT32_ALL ( EALS_PREIMPORT ) ) : NULL ;
ea_list * old_attrs = old ? ea_strip_to ( old - > attrs , BIT32_ALL ( EALS_PREIMPORT ) ) : NULL ;
2024-09-19 11:26:32 +02:00
loc . attrs = new_attrs ;
2024-09-19 10:25:28 +02:00
if ( new_attrs ! = old_attrs )
{
/* The attributes are actually different, announce the change */
if ( ea_same ( new_attrs , old_attrs ) )
bug ( " Two attribute sets are same in the attribute cache. " ) ;
struct bmp_stream * bs = bmp_find_stream ( p , bgp , src_ch - > afi , false ) ;
if ( bs )
{
log ( " s true bmp stream found feed, pre policy %i proto %s " , bs - > in_pre_policy , p - > p . name ) ;
if ( bmp_find_peer ( p , proto_state_table - > attrs [ bgp - > p . id ] ) = = NULL )
bug ( " not implemented " ) ;
2024-09-19 11:26:32 +02:00
bmp_route_monitor_notify ( p , bgp , bs , & loc ) ;
2024-09-19 10:25:28 +02:00
}
}
2024-09-19 09:54:06 +02:00
}
2024-09-19 10:25:28 +02:00
/* Checking the post policy */
if ( p - > monitoring_rib . in_post_policy )
2024-09-19 09:54:06 +02:00
{
2024-09-19 10:25:28 +02:00
/* Compute the post policy attributes */
ea_list * new_attrs = new ? ea_normalize ( new - > attrs , 0 ) : NULL ;
ea_list * old_attrs = old ? ea_normalize ( old - > attrs , 0 ) : NULL ;
2024-09-19 11:26:32 +02:00
loc . attrs = new_attrs ;
2024-09-19 10:25:28 +02:00
/* TODO: filter only BGP-relevant attributes */
if ( ( new_attrs ! = old_attrs ) | | ea_same ( new_attrs , old_attrs ) )
{
/* The attributes are actually different, announce the change */
struct bmp_stream * bs = bmp_find_stream ( p , bgp , src_ch - > afi , true ) ;
if ( bs )
{
log ( " s true bmp stream found feed, pre policy %i proto %s " , bs - > in_pre_policy , p - > p . name ) ;
if ( bmp_find_peer ( p , proto_state_table - > attrs [ bgp - > p . id ] ) = = NULL )
bug ( " not implemented " ) ;
2024-09-19 11:26:32 +02:00
bmp_route_monitor_notify ( p , bgp , bs , & loc ) ;
2024-09-19 10:25:28 +02:00
}
}
2024-09-19 09:54:06 +02:00
}
}
2024-09-19 10:25:28 +02:00
2024-09-04 13:48:40 +02:00
static void
2024-09-19 09:54:06 +02:00
bmp_check_routes ( void * bt_ )
2024-09-04 13:48:40 +02:00
{
2024-09-19 09:54:06 +02:00
log ( " bmp_check_routes " ) ;
2024-09-06 12:17:05 +02:00
struct bmp_table * bt = ( struct bmp_table * ) bt_ ;
struct bmp_proto * p = bt - > p ;
2024-09-10 09:29:12 +02:00
2024-09-06 12:17:05 +02:00
RT_EXPORT_WALK ( & bt - > out_req , u ) //const struct rt_export_union *_u;
2024-09-04 13:48:40 +02:00
{
2024-09-19 09:54:06 +02:00
log ( " feeder %x rte ptr %x " , & bt - > out_req , u ) ;
2024-09-04 13:48:40 +02:00
switch ( u - > kind )
{
case RT_EXPORT_STOP :
bug ( " Main table export stopped " ) ;
case RT_EXPORT_FEED :
2024-09-06 12:17:05 +02:00
log ( " export feed " ) ;
2024-09-04 13:48:40 +02:00
uint oldpos = 0 ;
while ( ( oldpos < u - > feed - > count_routes ) & & ! ( u - > feed - > block [ oldpos ] . flags & REF_OBSOLETE ) )
oldpos + + ;
/* Send updates one after another */
2024-09-19 09:54:06 +02:00
log ( " oldpos %i " , oldpos ) ;
2024-09-04 13:48:40 +02:00
for ( uint i = 0 ; i < oldpos ; i + + )
{
rte * new = & u - > feed - > block [ i ] ;
2024-09-19 09:54:06 +02:00
log ( " pre policy %i rte attr %x " , p - > monitoring_rib . in_pre_policy , new - > attrs ) ;
2024-09-19 10:25:28 +02:00
solve_for_post_and_pre ( p , new , NULL ) ;
2024-09-04 13:48:40 +02:00
}
break ;
case RT_EXPORT_UPDATE :
2024-09-06 12:17:05 +02:00
log ( " export update " ) ;
2024-09-19 09:54:06 +02:00
2024-09-19 10:25:28 +02:00
solve_for_post_and_pre ( p , u - > update - > new , u - > update - > old ) ;
2024-09-19 11:26:32 +02:00
break ;
2024-09-04 13:48:40 +02:00
}
}
2024-09-06 12:17:05 +02:00
log ( " end of notify fce " ) ;
2024-09-04 13:48:40 +02:00
}
2023-08-21 04:20:32 +02:00
static void
2024-09-19 11:26:32 +02:00
bmp_feed_end ( struct rt_export_request * req )
2023-08-21 04:20:32 +02:00
{
2024-09-19 11:26:32 +02:00
SKIP_BACK_DECLARE ( struct bmp_table , bt , out_req , req ) ;
2023-08-21 04:20:32 +02:00
2024-09-19 11:26:32 +02:00
struct bmp_proto * p = bt - > p ;
2023-08-21 04:20:32 +02:00
2024-08-19 15:04:13 +02:00
log ( " bmp table found " ) ;
2023-08-21 04:20:32 +02:00
/*
* Unsynced streams are added in one moment during BMP session establishment ,
* therefore we can assume that all unsynced streams ( for given channel )
* already received full feed now and are synced .
*
* TODO : Use more efficent way to find bmp_stream from bmp_table
*/
HASH_WALK ( p - > stream_map , next , bs )
{
if ( ( bs - > table = = bt ) & & ! bs - > sync )
{
bmp_route_monitor_end_of_rib ( p , bs ) ;
bs - > sync = true ;
}
}
HASH_WALK_END ;
}
2023-08-18 03:53:58 +02:00
2023-04-20 16:13:58 +02:00
/**
* bmp_startup - enter established state
* @ p : BMP instance
*
* The bgp_startup ( ) function is called when the BMP session is established .
* It sends initiation and peer up messagages .
*/
2021-03-29 22:45:21 +02:00
static void
2023-04-20 16:13:58 +02:00
bmp_startup ( struct bmp_proto * p )
2021-03-29 22:45:21 +02:00
{
2023-04-20 16:13:58 +02:00
ASSERT ( ! p - > started ) ;
p - > started = true ;
2023-05-31 17:41:53 +02:00
p - > sock_err = 0 ;
2021-03-28 15:13:23 +02:00
2023-04-20 16:13:58 +02:00
TRACE ( D_EVENTS , " BMP session established " ) ;
2021-03-28 04:30:11 +02:00
2024-07-26 17:24:15 +02:00
log ( " bmp startup %s %i " , p - > p . name , p - > p . id ) ;
2023-08-18 03:53:58 +02:00
proto_notify_state ( & p - > p , PS_UP ) ;
2023-04-20 16:13:58 +02:00
/* Send initiation message */
buffer payload = bmp_buffer_alloc ( p - > buffer_mpool , DEFAULT_MEM_BLOCK_SIZE ) ;
bmp_init_msg_serialize ( & payload , p - > sys_descr , p - > sys_name ) ;
bmp_schedule_tx_packet ( p , bmp_buffer_data ( & payload ) , bmp_buffer_pos ( & payload ) ) ;
bmp_buffer_free ( & payload ) ;
2021-03-29 22:45:21 +02:00
2023-04-20 16:13:58 +02:00
/* Send Peer Up messages */
2024-07-11 14:43:32 +02:00
for ( u32 i = 0 ; i < proto_state_table - > length ; i + + )
2024-07-04 13:13:38 +02:00
{
2024-07-11 14:43:32 +02:00
ea_list * proto_attr = proto_state_table - > attrs [ i ] ;
2024-08-19 15:04:13 +02:00
log ( " startup proto attr %i " , proto_attr ) ;
2024-07-11 14:43:32 +02:00
if ( proto_attr = = NULL )
2024-07-04 13:13:38 +02:00
continue ;
2024-07-11 14:43:32 +02:00
struct protocol * proto = ( struct protocol * ) ea_get_ptr ( proto_attr , & ea_protocol_type , 0 ) ;
const int state = ea_get_int ( proto_attr , & ea_state , 0 ) ;
2024-08-19 15:04:13 +02:00
log ( " proto bgp and up %i %i " , proto ! = & proto_bgp , state ! = PS_UP ) ;
2024-07-04 13:13:38 +02:00
if ( proto ! = & proto_bgp | | state ! = PS_UP )
continue ;
2024-07-11 14:43:32 +02:00
bmp_peer_init ( p , proto_attr ) ;
2024-07-04 13:13:38 +02:00
}
/*struct proto *peer;
2023-05-01 03:35:21 +02:00
WALK_LIST ( peer , proto_list )
2024-07-04 13:13:38 +02:00
if ( ( peer - > proto ! = & proto_bgp ) & & ( peer - > proto_state = = PS_UP ) )
bmp_peer_init ( p , ( struct bgp_proto * ) peer ) ; */
2021-03-29 22:45:21 +02:00
}
2023-04-20 16:13:58 +02:00
/**
* bmp_down - leave established state
* @ p : BMP instance
*
2023-08-18 03:53:58 +02:00
* The bgp_down ( ) function is called when the BMP session fails . The caller is
* responsible for changing protocol state .
2023-04-20 16:13:58 +02:00
*/
static void
bmp_down ( struct bmp_proto * p )
2021-03-29 22:45:21 +02:00
{
2023-04-20 16:13:58 +02:00
ASSERT ( p - > started ) ;
p - > started = false ;
2024-09-10 09:29:12 +02:00
log ( " _!p->peer_map.count (%i) && !p->stream_map.count (%i)&& !p->table_map.count(%i) " , p - > peer_map . count , p - > stream_map . count , p - > table_map . count ) ;
2023-04-20 16:13:58 +02:00
TRACE ( D_EVENTS , " BMP session closed " ) ;
2023-08-18 03:53:58 +02:00
/* Unregister existing peer structures */
HASH_WALK_DELSAFE ( p - > peer_map , next , bp )
{
2024-08-27 15:02:38 +02:00
log ( " bmp_remove_peer(p %x, bp %x) " , p , bp ) ;
2023-08-18 03:53:58 +02:00
bmp_remove_peer ( p , bp ) ;
}
HASH_WALK_END ;
2024-09-06 12:17:05 +02:00
/* Removing peers should also remove all streams and tables */ //TODO
2024-09-10 09:29:12 +02:00
log ( " !p->peer_map.count (%i) && !p->stream_map.count (%i)&& !p->table_map.count(%i) " , p - > peer_map . count , p - > stream_map . count , p - > table_map . count ) ;
2023-08-18 03:53:58 +02:00
ASSERT ( ! p - > peer_map . count & & ! p - > stream_map . count & & ! p - > table_map . count ) ;
2023-04-20 16:13:58 +02:00
}
/**
* bmp_connect - initiate an outgoing connection
* @ p : BMP instance
*
* The bmp_connect ( ) function creates the socket and initiates an outgoing TCP
* connection to the monitoring station . It is called to enter Connect state .
*/
static void
bmp_connect ( struct bmp_proto * p )
{
ASSERT ( ! p - > started ) ;
sock * sk = sk_new ( p - > p . pool ) ;
2021-03-29 22:45:21 +02:00
sk - > type = SK_TCP_ACTIVE ;
2023-05-30 17:09:25 +02:00
sk - > saddr = p - > local_addr ;
2023-04-20 16:13:58 +02:00
sk - > daddr = p - > station_ip ;
sk - > dport = p - > station_port ;
2021-03-29 22:45:21 +02:00
sk - > ttl = IP4_MAX_TTL ;
sk - > tos = IP_PREC_INTERNET_CONTROL ;
sk - > tbsize = BGP_TX_BUFFER_EXT_SIZE ;
2023-04-20 16:13:58 +02:00
sk - > tx_hook = bmp_connected ;
sk - > err_hook = bmp_sock_err ;
2021-03-29 22:45:21 +02:00
2021-03-28 16:41:53 +02:00
p - > sk = sk ;
sk - > data = p ;
2023-04-20 16:13:58 +02:00
2023-06-08 04:56:41 +02:00
TRACE ( D_EVENTS , " Connecting to %I port %u " , sk - > daddr , sk - > dport ) ;
2024-07-11 14:43:32 +02:00
int rc = sk_open ( sk , p - > p . loop ) ;
2023-04-20 16:13:58 +02:00
if ( rc < 0 )
sk_log_error ( sk , p - > p . name ) ;
tm_start ( p - > connect_retry_timer , CONNECT_RETRY_TIME ) ;
2021-03-29 22:45:21 +02:00
}
2023-05-30 15:52:01 +02:00
/* BMP connect successful event - switch from Connect to Established state */
2023-04-20 16:13:58 +02:00
static void
bmp_connected ( struct birdsock * sk )
{
struct bmp_proto * p = ( void * ) sk - > data ;
2023-06-08 04:56:41 +02:00
TRACE ( D_EVENTS , " Connected " ) ;
2023-04-20 16:13:58 +02:00
sk - > rx_hook = bmp_rx ;
sk - > tx_hook = bmp_tx ;
tm_stop ( p - > connect_retry_timer ) ;
bmp_startup ( p ) ;
}
/* BMP socket error event - switch from any state to Idle state */
static void
bmp_sock_err ( sock * sk , int err )
{
struct bmp_proto * p = sk - > data ;
2023-05-31 17:41:53 +02:00
p - > sock_err = err ;
2023-04-20 16:13:58 +02:00
if ( err )
TRACE ( D_EVENTS , " Connection lost (%M) " , err ) ;
else
TRACE ( D_EVENTS , " Connection closed " ) ;
if ( p - > started )
bmp_down ( p ) ;
bmp_close_socket ( p ) ;
tm_start ( p - > connect_retry_timer , CONNECT_RETRY_TIME ) ;
2023-08-18 03:53:58 +02:00
proto_notify_state ( & p - > p , PS_START ) ;
2023-04-20 16:13:58 +02:00
}
/* BMP connect timeout event - switch from Idle/Connect state to Connect state */
static void
bmp_connection_retry ( timer * t )
{
struct bmp_proto * p = t - > data ;
if ( p - > started )
return ;
bmp_close_socket ( p ) ;
bmp_connect ( p ) ;
}
static void
bmp_close_socket ( struct bmp_proto * p )
{
rfree ( p - > sk ) ;
p - > sk = NULL ;
}
2023-05-30 17:23:56 +02:00
static void
bmp_postconfig ( struct proto_config * CF )
{
struct bmp_config * cf = ( void * ) CF ;
/* Do not check templates at all */
if ( cf - > c . class = = SYM_TEMPLATE )
return ;
if ( ipa_zero ( cf - > station_ip ) )
cf_error ( " Station IP address not specified " ) ;
if ( ! cf - > station_port )
cf_error ( " Station port number not specified " ) ;
}
2024-07-26 17:24:15 +02:00
void
2024-08-27 14:59:15 +02:00
fc_for_bmp_recipient ( void * _p )
2024-07-26 17:24:15 +02:00
{
2024-08-27 14:59:15 +02:00
struct bmp_proto * p = _p ;
ASSERT_DIE ( birdloop_inside ( p - > p . loop ) ) ;
2024-08-27 15:02:38 +02:00
//log("received update, locked %i", locking_stack.service);
2024-07-26 17:24:15 +02:00
struct lfjour_item * last_up ;
struct proto_pending_update * pupdate ;
2024-08-28 15:58:15 +02:00
while ( last_up = lfjour_get ( & p - > proto_state_reader ) )
2024-07-26 17:24:15 +02:00
{
pupdate = SKIP_BACK ( struct proto_pending_update , li , last_up ) ;
const byte * tx_open_msg = ea_get_adata ( pupdate - > proto_attr , & ea_bgp_local_open_msg ) - > data ;
int id = ea_get_int ( pupdate - > proto_attr , & ea_proto_id , 0 ) ;
2024-08-27 15:02:38 +02:00
//log("id %i, tx = %i, l %i", id, tx_open_msg, ea_get_int(pupdate->proto_attr, &ea_bgp_local_open_msg_len, 0)); //FIXME why WHY are bmp eattrs able to give not null pointer?
2024-07-26 17:24:15 +02:00
if ( ea_get_int ( pupdate - > proto_attr , & ea_bgp_local_open_msg_len , 0 ) )
{
struct protocol * proto = ( struct protocol * ) ea_get_ptr ( pupdate - > proto_attr , & ea_protocol_type , 0 ) ;
//if (proto != &proto_bgp)
//{
2024-08-27 15:02:38 +02:00
//log("protocol %s is bgp %i", proto->name, proto == &proto_bgp);
2024-07-26 17:24:15 +02:00
//bug("wrong protocol");
//}
//int id = ea_get_int(pupdate->proto_attr, &ea_proto_id, 0);
const byte * rx_open_msg = ea_get_adata ( pupdate - > proto_attr , & ea_bgp_remote_open_msg ) - > data ;
int l_len = ea_get_int ( pupdate - > proto_attr , & ea_bgp_remote_open_msg_len , 0 ) ;
int r_len = ea_get_int ( pupdate - > proto_attr , & ea_bgp_remote_open_msg_len , 0 ) ;
2024-08-28 15:58:15 +02:00
bmp_peer_up_ ( p , proto_state_table - > attrs [ id ] , true , tx_open_msg , l_len , rx_open_msg , r_len ) ;
2024-08-27 14:59:15 +02:00
2024-07-26 17:24:15 +02:00
}
2024-08-28 15:58:15 +02:00
else if ( ea_get_int ( pupdate - > proto_attr , & ea_bgp_close_bmp_set , 0 ) )
{
struct closing_bgp * closing = ( struct closing_bgp * ) ea_get_ptr ( pupdate - > proto_attr , & ea_protocol_type , 0 ) ;
bmp_peer_down_ ( p , proto_state_table - > attrs [ id ] ,
closing - > err_class , closing - > err_code , closing - > err_subcode , closing - > data , closing - > length ) ;
}
2024-07-26 17:24:15 +02:00
2024-08-28 16:35:37 +02:00
lfjour_release ( & p - > proto_state_reader , last_up ) ;
2024-07-26 17:24:15 +02:00
}
}
void
2024-08-27 14:59:15 +02:00
create_bmp_recipient ( struct bmp_proto * p )
2024-07-26 17:24:15 +02:00
{
2024-08-28 15:58:15 +02:00
struct lfjour_recipient * r = & p - > proto_state_reader ;
r - > event = & p - > proto_state_changed ;
* r - > event = ( event ) { . hook = fc_for_bmp_recipient , . data = p } ;
log ( " p->p.loop %x " , p - > p . loop ) ;
r - > target = birdloop_event_list ( p - > p . loop ) ;
2024-07-26 17:24:15 +02:00
LOCK_DOMAIN ( rtable , proto_journal_domain ) ;
lfjour_register ( proto_journal , r ) ;
UNLOCK_DOMAIN ( rtable , proto_journal_domain ) ;
2024-08-28 15:58:15 +02:00
p - > lf_jour_inited = 1 ;
2024-07-26 17:24:15 +02:00
}
2021-03-29 22:45:21 +02:00
/** Configuration handle section **/
static struct proto *
bmp_init ( struct proto_config * CF )
{
2024-07-26 17:24:15 +02:00
log ( " start init locked %i " , locking_stack . service ) ;
2021-03-29 22:45:21 +02:00
struct proto * P = proto_new ( CF ) ;
2021-03-28 15:13:23 +02:00
struct bmp_proto * p = ( void * ) P ;
struct bmp_config * cf = ( void * ) CF ;
2023-05-31 17:41:53 +02:00
2024-09-06 12:23:31 +02:00
if ( ! bgp_next_hop_ea_class )
bgp_next_hop_ea_class = ea_class_find_by_name ( " bgp_next_hop " ) ;
2021-03-28 15:13:23 +02:00
p - > cf = cf ;
2023-05-30 17:09:25 +02:00
p - > local_addr = cf - > local_addr ;
2021-03-28 15:13:23 +02:00
p - > station_ip = cf - > station_ip ;
p - > station_port = cf - > station_port ;
strcpy ( p - > sys_descr , cf - > sys_descr ) ;
strcpy ( p - > sys_name , cf - > sys_name ) ;
p - > monitoring_rib . in_pre_policy = cf - > monitoring_rib_in_pre_policy ;
2023-08-18 03:53:58 +02:00
p - > monitoring_rib . in_post_policy = cf - > monitoring_rib_in_post_policy ;
2024-08-28 15:58:15 +02:00
//create_bmp_recipient(p); //should be here, but.
2024-07-26 17:24:15 +02:00
log ( " new proto created locked %i " , locking_stack . service ) ;
2021-03-28 15:13:23 +02:00
2021-03-29 22:45:21 +02:00
return P ;
}
2023-05-30 17:09:25 +02:00
/**
* bmp_start - initialize internal resources of BMP implementation .
* NOTE : It does not connect to BMP collector yet .
*/
2021-03-29 22:45:21 +02:00
static int
bmp_start ( struct proto * P )
{
2024-07-26 17:24:15 +02:00
log ( " start locked %i " , locking_stack . service ) ;
2021-03-28 15:13:23 +02:00
struct bmp_proto * p = ( void * ) P ;
2024-07-11 14:43:32 +02:00
p - > buffer_mpool = rp_new ( P - > pool , proto_domain ( & p - > p ) , " BMP Buffer " ) ;
p - > map_mem_pool = rp_new ( P - > pool , proto_domain ( & p - > p ) , " BMP Map " ) ;
p - > tx_mem_pool = rp_new ( P - > pool , proto_domain ( & p - > p ) , " BMP Tx " ) ;
p - > update_msg_mem_pool = rp_new ( P - > pool , proto_domain ( & p - > p ) , " BMP Update " ) ;
2023-08-01 17:56:56 +02:00
p - > tx_ev = ev_new_init ( p - > p . pool , bmp_fire_tx , p ) ;
p - > update_ev = ev_new_init ( p - > p . pool , bmp_route_monitor_commit , p ) ;
2023-04-20 16:13:58 +02:00
p - > connect_retry_timer = tm_new_init ( p - > p . pool , bmp_connection_retry , p , 0 , 0 ) ;
p - > sk = NULL ;
2023-04-18 15:13:24 +02:00
2023-08-18 03:53:58 +02:00
HASH_INIT ( p - > peer_map , P - > pool , 4 ) ;
HASH_INIT ( p - > stream_map , P - > pool , 4 ) ;
HASH_INIT ( p - > table_map , P - > pool , 4 ) ;
2023-04-18 15:13:24 +02:00
init_list ( & p - > tx_queue ) ;
2023-08-01 17:56:56 +02:00
init_list ( & p - > update_msg_queue ) ;
2023-04-18 15:13:24 +02:00
p - > started = false ;
2023-05-31 17:41:53 +02:00
p - > sock_err = 0 ;
2023-04-18 15:13:24 +02:00
2023-04-20 16:13:58 +02:00
tm_start ( p - > connect_retry_timer , CONNECT_INIT_TIME ) ;
2021-03-29 22:45:21 +02:00
2024-07-26 17:24:15 +02:00
log ( " end of start locked %i " , locking_stack . service ) ;
2024-08-28 15:58:15 +02:00
if ( p - > lf_jour_inited = = 0 )
create_bmp_recipient ( p ) ;
2023-04-20 16:13:58 +02:00
return PS_START ;
2021-03-29 22:45:21 +02:00
}
static int
bmp_shutdown ( struct proto * P )
{
2021-03-28 15:13:23 +02:00
struct bmp_proto * p = ( void * ) P ;
2023-04-20 16:13:58 +02:00
if ( p - > started )
{
bmp_send_termination_msg ( p , BMP_TERM_REASON_ADM ) ;
2023-08-18 03:53:58 +02:00
bmp_down ( p ) ;
2023-04-20 16:13:58 +02:00
}
2021-03-29 22:45:21 +02:00
2023-05-31 17:41:53 +02:00
p - > sock_err = 0 ;
2021-03-29 22:45:21 +02:00
return PS_DOWN ;
}
static int
2023-04-18 18:57:54 +02:00
bmp_reconfigure ( struct proto * P , struct proto_config * CF )
2021-03-29 22:45:21 +02:00
{
2023-04-18 18:57:54 +02:00
struct bmp_proto * p = ( void * ) P ;
2023-05-31 17:41:53 +02:00
const struct bmp_config * new = ( void * ) CF ;
const struct bmp_config * old = p - > cf ;
2023-04-18 18:57:54 +02:00
2023-05-31 17:41:53 +02:00
int needs_restart = bstrcmp ( new - > sys_descr , old - > sys_descr )
| | bstrcmp ( new - > sys_name , old - > sys_name )
| | ! ipa_equal ( new - > local_addr , old - > local_addr )
| | ! ipa_equal ( new - > station_ip , old - > station_ip )
| | ( new - > station_port ! = old - > station_port )
2023-08-18 03:53:58 +02:00
| | ( new - > monitoring_rib_in_pre_policy ! = old - > monitoring_rib_in_pre_policy )
| | ( new - > monitoring_rib_in_post_policy ! = old - > monitoring_rib_in_post_policy ) ;
2023-04-18 18:57:54 +02:00
2023-05-31 17:41:53 +02:00
/* If there is any change, restart the protocol */
if ( needs_restart )
return 0 ;
/* We must update our copy of configuration ptr */
p - > cf = new ;
2023-04-18 18:57:54 +02:00
return 1 ;
2021-03-29 22:45:21 +02:00
}
2023-05-31 17:41:53 +02:00
static void
bmp_get_status ( struct proto * P , byte * buf )
{
struct bmp_proto * p = ( void * ) P ;
if ( P - > proto_state = = PS_DOWN )
bsprintf ( buf , " Down " ) ;
else
{
const char * state = ! p - > started ? ( ! p - > sk ? " Idle " : " Connect " ) : " Established " ;
if ( ! p - > sock_err )
bsprintf ( buf , " %s " , state ) ;
else
bsprintf ( buf , " %-14s%s %M " , state , " Error: " , p - > sock_err ) ;
}
}
static void
bmp_show_proto_info ( struct proto * P )
{
struct bmp_proto * p = ( void * ) P ;
if ( P - > proto_state ! = PS_DOWN )
{
cli_msg ( - 1006 , " %-19s %I " , " Station address: " , p - > station_ip ) ;
cli_msg ( - 1006 , " %-19s %u " , " Station port: " , p - > station_port ) ;
if ( ! ipa_zero ( p - > local_addr ) )
cli_msg ( - 1006 , " %-19s %I " , " Local address: " , p - > local_addr ) ;
if ( p - > sock_err )
cli_msg ( - 1006 , " %-19s %M " , " Last error: " , p - > sock_err ) ;
}
}
2021-03-29 22:45:21 +02:00
struct protocol proto_bmp = {
. name = " BMP " ,
2023-04-18 15:09:21 +02:00
. template = " bmp%d " ,
2024-07-11 14:43:32 +02:00
//.class = PROTOCOL_BMP, looks like there are no classes for protocols anymore
2021-03-29 22:45:21 +02:00
. proto_size = sizeof ( struct bmp_proto ) ,
. config_size = sizeof ( struct bmp_config ) ,
2023-05-30 17:23:56 +02:00
. postconfig = bmp_postconfig ,
2021-03-29 22:45:21 +02:00
. init = bmp_init ,
. start = bmp_start ,
. shutdown = bmp_shutdown ,
. reconfigure = bmp_reconfigure ,
2023-05-31 17:41:53 +02:00
. get_status = bmp_get_status ,
. show_proto_info = bmp_show_proto_info ,
2021-03-29 22:45:21 +02:00
} ;
void
bmp_build ( void )
{
proto_build ( & proto_bmp ) ;
}