2021-03-29 20:45:21 +00: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 14:13:58 +00: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 13:52:01 +00:00
* has three events : connect successful ( Connect - > Established ) , socket error
2023-04-20 14:13:58 +00:00
* ( any - > Idle ) , and connect timeout ( Idle / Connect - > Connect , resetting the
* TCP socket ) .
2021-03-29 20:45:21 +00: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"
# include "lib/event.h"
# include "lib/ip.h"
# include "lib/lists.h"
# include "lib/resource.h"
# include "lib/unaligned.h"
# include "nest/iface.h"
# include "nest/route.h"
2023-06-08 02:56:41 +00:00
// List of BMP instances
static list STATIC_LIST_INIT ( bmp_proto_list ) ;
2021-03-29 20:45:21 +00:00
2023-08-18 01:53:58 +00: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 20:45:21 +00: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 14:13:58 +00:00
// Initial delay for connection to the BMP collector
# define CONNECT_INIT_TIME (200 MS)
2021-03-29 20:45:21 +00:00
// Timeout for connection to the BMP collector retry
2023-04-20 14:13:58 +00:00
# define CONNECT_RETRY_TIME (10 S)
2021-03-29 20:45:21 +00:00
# define IP4_MAX_TTL 255
2021-03-28 02:30:11 +00: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 )
2023-04-20 14:13:58 +00: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 ) ;
2021-03-29 20:45:21 +00:00
2021-03-28 02:30:11 +00:00
static void
2024-07-11 12:43:32 +00:00
bmp_send_peer_up_notif_msg ( struct bmp_proto * p , ea_list * bgp ,
2023-05-30 13:52:01 +00:00
const byte * tx_data , const size_t tx_data_size ,
const byte * rx_data , const size_t rx_data_size ) ;
2021-03-29 20:45:21 +00:00
2023-08-21 02:20:32 +00:00
static void bmp_route_monitor_end_of_rib ( struct bmp_proto * p , struct bmp_stream * bs ) ;
2021-03-29 20:45:21 +00:00
// Stores necessary any data in list
struct bmp_data_node {
node n ;
byte * data ;
size_t data_size ;
2023-08-01 15:56:56 +00:00
u32 remote_as ;
u32 remote_id ;
ip_addr remote_ip ;
btime timestamp ;
bool global_peer ;
2023-08-18 01:53:58 +00:00
bool policy ;
2021-03-29 20:45:21 +00: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 02:30:11 +00:00
static void
2021-03-29 20:45:21 +00:00
bmp_info_tlv_hdr_serialize ( buffer * stream , const enum bmp_info_tlv_type type ,
2021-03-28 02:30:11 +00:00
const char * str )
2021-03-29 20:45:21 +00:00
{
2021-03-28 02:30:11 +00:00
size_t str_len = strlen ( str ) ;
2023-05-30 13:52:01 +00:00
str_len = MIN ( str_len , MIB_II_STR_LEN ) ;
2021-03-29 20:45:21 +00:00
bmp_put_u16 ( stream , type ) ;
2021-03-28 02:30:11 +00:00
bmp_put_u16 ( stream , str_len ) ;
bmp_put_data ( stream , str , str_len ) ;
2021-03-29 20:45:21 +00:00
}
// Serializes BMP Initiation message header [RFC 7854 - Section 4.3]
2021-03-28 02:30:11 +00:00
static void
2021-03-29 20:45:21 +00: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 02:30:11 +00: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 20:45:21 +00:00
}
2021-03-28 02:30:11 +00:00
static void
2021-03-28 13:13:23 +00:00
bmp_schedule_tx_packet ( struct bmp_proto * p , const byte * payload , const size_t size )
2021-03-29 20:45:21 +00:00
{
2023-04-20 14:13:58 +00:00
ASSERT ( p - > started ) ;
2021-03-29 20:45:21 +00:00
2024-07-26 15:24:15 +00: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 ) ;
2021-03-29 20:45:21 +00:00
memcpy ( tx_data - > data , payload , size ) ;
tx_data - > data_size = size ;
2021-03-28 13:13:23 +00:00
add_tail ( & p - > tx_queue , & tx_data - > n ) ;
2021-03-28 02:30:11 +00:00
2021-03-28 14:41:53 +00:00
if ( sk_tx_buffer_empty ( p - > sk )
& & ! ev_active ( p - > tx_ev ) )
2021-03-29 20:45:21 +00:00
{
2021-03-28 14:41:53 +00:00
ev_schedule ( p - > tx_ev ) ;
2021-03-29 20:45:21 +00:00
}
}
2021-03-28 14:41:53 +00:00
static void
bmp_fire_tx ( void * p_ )
2021-03-29 20:45:21 +00:00
{
2021-03-28 14:41:53 +00:00
struct bmp_proto * p = p_ ;
2023-06-08 03:10:05 +00:00
if ( ! p - > started )
return ;
2021-03-29 20:45:21 +00:00
IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL (
2021-03-28 13:13:23 +00:00
EMPTY_LIST ( p - > tx_queue ) ,
2021-03-29 20:45:21 +00: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 13:13:23 +00:00
WALK_LIST_DELSAFE ( tx_data , tx_data_next , p - > tx_queue )
2021-03-29 20:45:21 +00:00
{
2021-03-28 14:41:53 +00:00
if ( tx_data - > data_size > p - > sk - > tbsize )
2021-03-29 20:45:21 +00:00
{
2021-03-28 14:41:53 +00:00
sk_set_tbsize ( p - > sk , tx_data - > data_size ) ;
2021-03-29 20:45:21 +00:00
}
2021-03-28 13:13:23 +00:00
size_t data_size = tx_data - > data_size ;
2023-06-08 03:10:05 +00:00
memcpy ( p - > sk - > tbuf , tx_data - > data , data_size ) ;
2021-03-29 20:45:21 +00:00
mb_free ( tx_data - > data ) ;
rem_node ( ( node * ) tx_data ) ;
mb_free ( tx_data ) ;
2023-04-20 15:14:45 +00:00
if ( sk_send ( p - > sk , data_size ) < = 0 )
return ;
2021-03-29 20:45:21 +00: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 14:41:53 +00:00
if ( ! ev_active ( p - > tx_ev ) )
2021-03-29 20:45:21 +00:00
{
2021-03-28 14:41:53 +00:00
ev_schedule ( p - > tx_ev ) ;
2021-03-29 20:45:21 +00:00
}
return ;
}
}
}
static void
bmp_tx ( struct birdsock * sk )
{
bmp_fire_tx ( sk - > data ) ;
}
2023-04-20 14:13:58 +00: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 20:45:21 +00:00
{
2023-04-20 14:13:58 +00:00
return 0 ;
2021-03-29 20:45:21 +00:00
}
2021-03-28 13:36:59 +00:00
static inline void
bmp_put_ipa ( buffer * stream , const ip_addr addr )
2021-03-29 20:45:21 +00:00
{
2021-03-28 13:36:59 +00: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 20:45:21 +00:00
}
static void
2023-05-01 01:35:21 +00:00
bmp_put_bgp_hdr ( buffer * stream , const u8 msg_type , const u16 msg_length )
2021-03-29 20:45:21 +00:00
{
2023-05-01 01:35:21 +00: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 20:45:21 +00:00
bmp_put_u8 ( stream , msg_type ) ;
}
/**
* bmp_per_peer_hdr_serialize - serializes Per - Peer Header
*
2023-08-18 01:53:58 +00:00
* @ is_post_policy : indicate the message reflects the post - policy Adj - RIB - In
2021-03-29 20:45:21 +00: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 01:53:58 +00:00
const bool is_post_policy , const bool is_as_path_4bytes ,
2021-03-29 20:45:21 +00: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 01:53:58 +00: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 20:45:21 +00: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 13:36:59 +00:00
bmp_put_ipa ( stream , peer_addr ) ;
2021-03-29 20:45:21 +00: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 01:53:58 +00:00
const bool table_in_post_policy , const u32 peer_as , const u32 peer_bgp_id ,
2021-03-29 20:45:21 +00:00
const bool as4_support , const ip_addr remote_addr , const byte * update_msg ,
2023-08-01 15:56:56 +00:00
const size_t update_msg_size , btime timestamp )
2021-03-29 20:45:21 +00:00
{
const size_t data_size = BMP_PER_PEER_HDR_SIZE + update_msg_size ;
2023-08-01 15:56:56 +00:00
u32 ts_sec = timestamp TO_S ;
u32 ts_usec = timestamp - ( ts_sec S ) ;
2021-03-29 20:45:21 +00:00
bmp_buffer_need ( stream , BMP_COMMON_HDR_SIZE + data_size ) ;
bmp_common_hdr_serialize ( stream , BMP_ROUTE_MONITOR , data_size ) ;
2023-08-18 01:53:58 +00:00
bmp_per_peer_hdr_serialize ( stream , is_peer_global , table_in_post_policy ,
2021-03-29 20:45:21 +00: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 13:52:01 +00: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 20:45:21 +00:00
{
2023-05-01 01:35:21 +00:00
const size_t data_size =
BMP_PER_PEER_HDR_SIZE + BMP_PEER_UP_NOTIF_MSG_FIX_SIZE +
2023-05-30 13:52:01 +00:00
BGP_HEADER_LENGTH + sent_msg_length + BGP_HEADER_LENGTH + recv_msg_length ;
2023-05-01 01:35:21 +00:00
2021-03-29 20:45:21 +00: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 01:53:58 +00:00
false /* TODO: Hardcoded pre-policy Adj-RIB-In */ , as4_support , remote_addr ,
2021-03-29 20:45:21 +00:00
peer_as , peer_bgp_id , 0 , 0 ) ; // 0, 0 - No timestamp provided
2021-03-28 13:36:59 +00:00
bmp_put_ipa ( stream , local_addr ) ;
2021-03-29 20:45:21 +00:00
bmp_put_u16 ( stream , local_port ) ;
bmp_put_u16 ( stream , remote_port ) ;
2023-05-30 13:52:01 +00: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 20:45:21 +00: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 01:53:58 +00:00
false /* TODO: Hardcoded pre-policy adj RIB IN */ , as4_support , remote_addr ,
2021-03-29 20:45:21 +00:00
peer_as , peer_bgp_id , 0 , 0 ) ; // 0, 0 - No timestamp provided
bmp_put_data ( stream , data , data_size ) ;
}
2023-08-18 01:53:58 +00:00
/*
* BMP tables
*/
static struct bmp_table *
2024-07-04 11:13:38 +00:00
bmp_find_table ( struct bmp_proto * p , rtable * tab )
2023-08-18 01:53:58 +00:00
{
return HASH_FIND ( p - > table_map , HASH_TABLE , tab ) ;
}
static struct bmp_table *
2024-07-04 11:13:38 +00:00
bmp_add_table ( struct bmp_proto * p , rtable * tab )
2023-08-18 01:53:58 +00:00
{
struct bmp_table * bt = mb_allocz ( p - > p . pool , sizeof ( struct bmp_table ) ) ;
bt - > table = tab ;
rt_lock_table ( bt - > table ) ;
HASH_INSERT ( p - > table_map , HASH_TABLE , bt ) ;
struct channel_config cc = {
. name = " monitor " ,
2024-07-04 11:13:38 +00:00
//.channel = &channel_basic,
2023-08-18 01:53:58 +00:00
. table = tab - > config ,
. in_filter = FILTER_REJECT ,
. net_type = tab - > addr_type ,
. ra_mode = RA_ANY ,
2024-07-04 11:13:38 +00:00
//.bmp_hack = 1,
2023-08-18 01:53:58 +00:00
} ;
bt - > channel = proto_add_channel ( & p - > p , & cc ) ;
channel_set_state ( bt - > channel , CS_UP ) ;
return bt ;
}
2023-06-08 02:56:41 +00:00
static void
2023-08-18 01:53:58 +00:00
bmp_remove_table ( struct bmp_proto * p , struct bmp_table * bt )
{
2024-07-04 11:13:38 +00:00
channel_set_state ( bt - > channel , CS_STOP ) ;
2023-08-18 01:53:58 +00: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 ;
mb_free ( bt ) ;
}
2024-07-04 11:13:38 +00:00
static inline struct bmp_table * bmp_get_table ( struct bmp_proto * p , rtable * tab )
2023-08-18 01:53:58 +00:00
{ return bmp_find_table ( p , tab ) ? : bmp_add_table ( p , tab ) ; }
static inline void bmp_lock_table ( struct bmp_proto * p UNUSED , struct bmp_table * bt )
{ bt - > uc + + ; }
static inline void bmp_unlock_table ( struct bmp_proto * p , struct bmp_table * bt )
{ bt - > uc - - ; if ( ! bt - > uc ) bmp_remove_table ( p , bt ) ; }
/*
* BMP streams
*/
static inline u32 bmp_stream_key ( u32 afi , bool policy )
{ return afi ^ ( policy ? BMP_STREAM_KEY_POLICY : 0 ) ; }
static inline u32 bmp_stream_afi ( struct bmp_stream * bs )
{ return bs - > key & ~ BMP_STREAM_KEY_POLICY ; }
static inline bool bmp_stream_policy ( struct bmp_stream * bs )
{ return ! ! ( bs - > key & BMP_STREAM_KEY_POLICY ) ; }
static struct bmp_stream *
2024-07-11 12:43:32 +00:00
bmp_find_stream ( struct bmp_proto * p , struct bgp_proto * bgp_attr , u32 afi , bool policy )
2023-08-18 01:53:58 +00:00
{
2024-07-04 11:13:38 +00:00
return HASH_FIND ( p - > stream_map , HASH_STREAM , ( void * ) bgp_attr , bmp_stream_key ( afi , policy ) ) ;
2023-08-18 01:53:58 +00:00
}
static struct bmp_stream *
2024-07-04 11:13:38 +00: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 01:53:58 +00:00
{
struct bmp_stream * bs = mb_allocz ( p - > p . pool , sizeof ( struct bmp_stream ) ) ;
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 ) ;
bmp_lock_table ( p , bs - > table ) ;
bs - > sender = sender ;
2023-08-21 02:20:32 +00:00
bs - > sync = false ;
2024-07-04 11:13:38 +00:00
bs - > in_pre_policy = in_pre_policy ;
2023-08-18 01:53:58 +00:00
return bs ;
}
static void
bmp_remove_stream ( struct bmp_proto * p , struct bmp_stream * bs )
{
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 11:13:38 +00:00
bmp_find_peer ( struct bmp_proto * p , ea_list * bgp_attr )
2023-08-18 01:53:58 +00:00
{
2024-07-04 11:13:38 +00:00
return HASH_FIND ( p - > peer_map , HASH_PEER , ( void * ) bgp_attr ) ; //TODO this is wrong, hash find is not for eattrs. but.
2023-08-18 01:53:58 +00:00
}
static struct bmp_peer *
2024-07-04 11:13:38 +00:00
bmp_add_peer ( struct bmp_proto * p , ea_list * bgp_attr )
2023-08-18 01:53:58 +00:00
{
2024-07-26 15:24:15 +00: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-07-04 11:13:38 +00:00
bp - > bgp = bgp_attr ;
2023-08-18 01:53:58 +00:00
init_list ( & bp - > streams ) ;
HASH_INSERT ( p - > peer_map , HASH_PEER , bp ) ;
2024-07-04 11:13:38 +00:00
int proto_id = ea_get_int ( bgp_attr , & ea_proto_id , 0 ) ;
ea_list * chan_attr ;
2024-07-26 15:24:15 +00:00
log ( " before while id %i, eattrs %i " , proto_id , proto_state_table - > channels_attrs [ proto_id ] ) ;
2024-07-04 11:13:38 +00:00
WALK_LIST ( chan_attr , proto_state_table - > channels_attrs [ proto_id ] )
2023-08-18 01:53:58 +00:00
{
2024-07-26 15:24:15 +00:00
log ( " chan_attr in bmp_add_peer %i " , chan_attr ) ;
rtable * ch_table = ( rtable * ) ea_get_ptr ( chan_attr , & ea_rtable , 0 ) ;
log ( " has table ptr %i " , ch_table ) ;
2024-07-04 11:13:38 +00:00
if ( p - > monitoring_rib . in_pre_policy & & ch_table )
bmp_add_stream ( p , bp , ea_get_int ( chan_attr , & ea_bgp_afi , 0 ) , false , ch_table , chan_attr , 1 ) ;
2023-08-18 01:53:58 +00:00
2024-07-04 11:13:38 +00:00
if ( p - > monitoring_rib . in_post_policy & & ch_table )
bmp_add_stream ( p , bp , ea_get_int ( chan_attr , & ea_bgp_afi , 0 ) , true , ch_table , chan_attr , 0 ) ;
2023-08-18 01:53:58 +00: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 )
bmp_remove_stream ( p , bs ) ;
HASH_REMOVE ( p - > peer_map , HASH_PEER , bp ) ;
mb_free ( bp ) ;
}
static void
2024-07-04 11:13:38 +00:00
bmp_peer_up_ ( struct bmp_proto * p , ea_list * bgp_attr , bool sync ,
2023-05-01 01:35:21 +00:00
const byte * tx_open_msg , uint tx_open_length ,
const byte * rx_open_msg , uint rx_open_length )
2021-03-29 20:45:21 +00:00
{
2023-06-08 02:56:41 +00:00
if ( ! p - > started )
2023-05-01 01:35:21 +00:00
return ;
2021-03-29 20:45:21 +00:00
2024-07-04 11:13:38 +00:00
struct bmp_peer * bp = bmp_find_peer ( p , bgp_attr ) ;
2023-08-18 01:53:58 +00:00
if ( bp )
return ;
2024-07-11 12:43:32 +00:00
const char * name = ea_get_adata ( bgp_attr , & ea_name ) - > data ;
2024-07-04 11:13:38 +00:00
TRACE ( D_STATES , " Peer up for %s " , name ) ;
2023-06-08 02:56:41 +00:00
2024-07-04 11:13:38 +00:00
bp = bmp_add_peer ( p , bgp_attr ) ;
2021-03-29 20:45:21 +00:00
2024-07-04 11:13:38 +00: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 01:35:21 +00:00
2023-08-21 02:20:32 +00: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 02:56:41 +00:00
}
void
2024-07-04 11:13:38 +00:00
bmp_peer_up ( ea_list * bgp ,
2023-06-08 02:56:41 +00:00
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 )
2023-08-21 02:20:32 +00:00
bmp_peer_up_ ( p , bgp , true , tx_open_msg , tx_open_length , rx_open_msg , rx_open_length ) ;
2021-03-29 20:45:21 +00:00
}
static void
2024-07-04 11:13:38 +00:00
bmp_peer_init ( struct bmp_proto * p , ea_list * bgp_attr )
2021-03-29 20:45:21 +00:00
{
2024-07-11 12:43:32 +00:00
const struct bgp_conn * conn = ( const struct bgp_conn * ) ea_get_ptr ( bgp_attr , & ea_bgp_conn , 0 ) ;
2023-05-01 01:35:21 +00:00
if ( ! conn | | ( conn - > state ! = BS_ESTABLISHED ) | |
! conn - > local_open_msg | | ! conn - > remote_open_msg )
return ;
2024-07-04 11:13:38 +00:00
bmp_peer_up_ ( p , bgp_attr , false , conn - > local_open_msg , conn - > local_open_length ,
2023-06-08 02:56:41 +00:00
conn - > remote_open_msg , conn - > remote_open_length ) ;
2021-03-29 20:45:21 +00:00
}
2023-08-18 01:53:58 +00:00
2021-03-29 20:45:21 +00:00
static const struct birdsock *
2024-07-11 12:43:32 +00:00
bmp_get_birdsock ( ea_list * bgp )
2021-03-29 20:45:21 +00:00
{
2024-07-11 12:43:32 +00: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 20:45:21 +00:00
return NULL ;
}
static const struct birdsock *
2024-07-11 12:43:32 +00:00
bmp_get_birdsock_ext ( ea_list * bgp )
2021-03-29 20:45:21 +00:00
{
const struct birdsock * sk = bmp_get_birdsock ( bgp ) ;
if ( sk ! = NULL )
return sk ;
2024-07-11 12:43:32 +00: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 20:45:21 +00:00
{
2024-07-11 12:43:32 +00:00
sk = in_conn - > sk ;
2021-03-29 20:45:21 +00:00
}
2024-07-11 12:43:32 +00:00
else if ( out_conn - > sk )
2021-03-29 20:45:21 +00:00
{
2024-07-11 12:43:32 +00:00
sk = out_conn - > sk ;
2021-03-29 20:45:21 +00:00
}
return sk ;
}
static const struct bgp_caps *
bmp_get_bgp_remote_caps ( const struct bgp_proto * bgp )
{
if ( bgp - > conn & & bgp - > conn - > remote_caps )
return bgp - > conn - > remote_caps ;
return NULL ;
}
static const struct bgp_caps *
bmp_get_bgp_remote_caps_ext ( const struct bgp_proto * bgp )
{
const struct bgp_caps * remote_caps = bmp_get_bgp_remote_caps ( bgp ) ;
if ( remote_caps ! = NULL )
return remote_caps ;
if ( bgp - > incoming_conn . remote_caps )
{
remote_caps = bgp - > incoming_conn . remote_caps ;
}
else if ( bgp - > outgoing_conn . remote_caps )
{
remote_caps = bgp - > outgoing_conn . remote_caps ;
}
return remote_caps ;
}
static bool
2024-07-11 12:43:32 +00:00
bmp_is_peer_global_instance ( ea_list * bgp )
2021-03-29 20:45:21 +00:00
{
2024-07-11 12:43:32 +00: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 ) ;
return ( peer_type ! = BGP_PT_EXTERNAL & &
peer_type ! = BGP_PT_INTERNAL )
? ( local_as ! = remote_as )
: ( peer_type = = BGP_PT_EXTERNAL ) ;
2021-03-29 20:45:21 +00:00
}
2021-03-28 02:30:11 +00:00
static void
2024-07-11 12:43:32 +00:00
bmp_send_peer_up_notif_msg ( struct bmp_proto * p , ea_list * bgp ,
2023-05-30 13:52:01 +00:00
const byte * tx_data , const size_t tx_data_size ,
const byte * rx_data , const size_t rx_data_size )
2021-03-29 20:45:21 +00:00
{
2023-04-20 14:13:58 +00:00
ASSERT ( p - > started ) ;
2021-03-29 20:45:21 +00:00
2021-03-28 02:30:11 +00: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 20:45:21 +00:00
2024-07-11 12:43:32 +00: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 ) ;
2021-03-29 20:45:21 +00:00
const bool is_global_instance_peer = bmp_is_peer_global_instance ( bgp ) ;
2021-03-28 13:13:23 +00:00
buffer payload = bmp_buffer_alloc ( p - > buffer_mpool , DEFAULT_MEM_BLOCK_SIZE ) ;
2021-03-29 20:45:21 +00:00
bmp_peer_up_notif_msg_serialize ( & payload , is_global_instance_peer ,
2024-07-11 12:43:32 +00:00
rem_as , rem_id , 1 ,
2021-03-29 20:45:21 +00:00
sk - > saddr , sk - > daddr , sk - > sport , sk - > dport , tx_data , tx_data_size ,
rx_data , rx_data_size ) ;
2021-03-28 13:13:23 +00:00
bmp_schedule_tx_packet ( p , bmp_buffer_data ( & payload ) , bmp_buffer_pos ( & payload ) ) ;
2021-04-15 16:32:47 +00:00
bmp_buffer_free ( & payload ) ;
2021-03-29 20:45:21 +00:00
}
2023-06-08 02:56:41 +00:00
static void
2023-08-18 13:39:08 +00: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 20:45:21 +00:00
{
2023-08-01 15:56:56 +00:00
struct bmp_data_node * upd_msg = mb_alloc ( p - > update_msg_mem_pool ,
sizeof ( struct bmp_data_node ) ) ;
upd_msg - > data = mb_alloc ( p - > update_msg_mem_pool , length ) ;
memcpy ( upd_msg - > data , data , length ) ;
upd_msg - > data_size = length ;
add_tail ( & p - > update_msg_queue , & upd_msg - > n ) ;
/* Save some metadata */
2024-07-11 12:43:32 +00: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 13:39:08 +00:00
upd_msg - > timestamp = timestamp ;
2023-08-01 15:56:56 +00:00
upd_msg - > global_peer = bmp_is_peer_global_instance ( bgp ) ;
2023-08-18 01:53:58 +00:00
upd_msg - > policy = bmp_stream_policy ( bs ) ;
2023-08-01 15:56:56 +00:00
/* Kick the commit */
if ( ! ev_active ( p - > update_ev ) )
ev_schedule ( p - > update_ev ) ;
2021-03-29 20:45:21 +00:00
}
2023-08-01 15:56:56 +00:00
static void
2024-07-11 12:43:32 +00:00
bmp_route_monitor_notify ( struct bmp_proto * p , struct bgp_proto * bgp_p , struct bmp_stream * bs ,
2023-08-18 01:53:58 +00:00
const net_addr * n , const struct rte * new , const struct rte_src * src )
2021-03-29 20:45:21 +00:00
{
2023-08-01 15:56:56 +00:00
byte buf [ BGP_MAX_EXT_MSG_LENGTH ] ;
2024-07-11 12:43:32 +00:00
byte * end = bgp_bmp_encode_rte ( bs - > sender , bgp_p , buf , n , new , src ) ;
2021-03-29 20:45:21 +00:00
2023-08-18 13:39:08 +00:00
btime delta_t = new ? current_time ( ) - new - > lastmod : 0 ;
btime timestamp = current_real_time ( ) - delta_t ;
2023-08-18 01:53:58 +00:00
if ( end )
2023-08-18 13:39:08 +00:00
bmp_route_monitor_put_update ( p , bs , buf , end - buf , timestamp ) ;
2023-08-18 01:53:58 +00:00
else
log ( L_WARN " %s: Cannot encode update for %N " , p - > p . name , n ) ;
2023-06-08 02:56:41 +00:00
}
2021-03-28 13:13:23 +00:00
2023-06-08 02:56:41 +00:00
static void
2023-08-01 15:56:56 +00:00
bmp_route_monitor_commit ( void * p_ )
2023-06-08 02:56:41 +00:00
{
2023-08-01 15:56:56 +00:00
struct bmp_proto * p = p_ ;
2023-06-08 02:56:41 +00:00
if ( ! p - > started )
2021-03-29 20:45:21 +00:00
return ;
buffer payload
2023-08-01 15:56:56 +00:00
= bmp_buffer_alloc ( p - > buffer_mpool , DEFAULT_MEM_BLOCK_SIZE ) ;
2021-03-29 20:45:21 +00:00
2023-08-01 15:56:56 +00:00
struct bmp_data_node * data , * data_next ;
WALK_LIST_DELSAFE ( data , data_next , p - > update_msg_queue )
2021-03-29 20:45:21 +00:00
{
bmp_route_monitor_msg_serialize ( & payload ,
2023-08-18 01:53:58 +00:00
data - > global_peer , data - > policy ,
2023-08-01 15:56:56 +00:00
data - > remote_as , data - > remote_id , true ,
2023-08-01 16:39:38 +00:00
data - > remote_ip , data - > data , data - > data_size ,
2023-08-01 15:56:56 +00:00
data - > timestamp ) ;
2021-03-29 20:45:21 +00:00
2021-03-28 13:13:23 +00:00
bmp_schedule_tx_packet ( p , bmp_buffer_data ( & payload ) , bmp_buffer_pos ( & payload ) ) ;
2021-03-29 20:45:21 +00:00
bmp_buffer_flush ( & payload ) ;
2023-08-01 15:56:56 +00:00
mb_free ( data - > data ) ;
rem_node ( & data - > n ) ;
mb_free ( data ) ;
2021-03-29 20:45:21 +00:00
}
2021-04-15 16:32:47 +00:00
bmp_buffer_free ( & payload ) ;
2021-03-29 20:45:21 +00:00
}
2021-03-29 02:43:04 +00:00
static void
2023-08-18 01:53:58 +00:00
bmp_route_monitor_end_of_rib ( struct bmp_proto * p , struct bmp_stream * bs )
2021-03-29 20:45:21 +00:00
{
2024-07-11 12:43:32 +00: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 02:56:41 +00:00
byte rx_end_payload [ DEFAULT_MEM_BLOCK_SIZE ] ;
2024-07-11 12:43:32 +00:00
byte * pos = bgp_create_end_mark_ea_ ( bs - > sender , rx_end_payload + BGP_HEADER_LENGTH ) ;
2023-06-08 02:56:41 +00: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 13:39:08 +00:00
bmp_route_monitor_put_update ( p , bs , rx_end_payload , pos - rx_end_payload , current_real_time ( ) ) ;
2023-06-08 02:56:41 +00:00
}
2021-03-28 13:13:23 +00:00
2021-03-28 02:30:11 +00:00
static void
2021-03-28 13:13:23 +00:00
bmp_send_peer_down_notif_msg ( struct bmp_proto * p , const struct bgp_proto * bgp ,
2023-05-30 13:52:01 +00:00
const byte * data , const size_t data_size )
2021-03-29 20:45:21 +00:00
{
2023-04-20 14:13:58 +00:00
ASSERT ( p - > started ) ;
2021-03-28 02:30:11 +00:00
2021-03-29 20:45:21 +00:00
const struct bgp_caps * remote_caps = bmp_get_bgp_remote_caps_ext ( bgp ) ;
2024-07-11 12:43:32 +00:00
bool is_global_instance_peer = bmp_is_peer_global_instance ( proto_state_table - > attrs [ bgp - > p . id ] ) ;
2021-03-29 20:45:21 +00:00
buffer payload
2021-03-28 13:13:23 +00:00
= bmp_buffer_alloc ( p - > buffer_mpool , DEFAULT_MEM_BLOCK_SIZE ) ;
2021-03-29 20:45:21 +00:00
bmp_peer_down_notif_msg_serialize ( & payload , is_global_instance_peer ,
bgp - > remote_as , bgp - > remote_id ,
remote_caps ? remote_caps - > as4_support : bgp - > as4_session ,
bgp - > remote_ip , data , data_size ) ;
2021-03-28 13:13:23 +00:00
bmp_schedule_tx_packet ( p , bmp_buffer_data ( & payload ) , bmp_buffer_pos ( & payload ) ) ;
2021-03-29 20:45:21 +00:00
bmp_buffer_free ( & payload ) ;
}
2023-06-08 02:56:41 +00:00
static void
bmp_peer_down_ ( struct bmp_proto * p , const struct bgp_proto * bgp ,
2023-08-21 23:24:21 +00:00
int err_class , int err_code , int err_subcode , const byte * data , int length )
2021-03-29 20:45:21 +00:00
{
2023-06-08 02:56:41 +00:00
if ( ! p - > started )
2021-03-29 20:45:21 +00:00
return ;
2024-07-11 12:43:32 +00:00
struct bmp_peer * bp = bmp_find_peer ( p , proto_state_table - > attrs [ bgp - > p . id ] ) ;
2023-08-18 01:53:58 +00:00
if ( ! bp )
return ;
2023-06-08 02:56:41 +00:00
2023-08-18 01:53:58 +00:00
TRACE ( D_STATES , " Peer down for %s " , bgp - > p . name ) ;
2021-03-29 20:45:21 +00:00
2023-08-21 23:24:21 +00:00
uint bmp_code = 0 ;
uint fsm_code = 0 ;
2023-04-20 15:14:45 +00:00
2023-08-21 23:24:21 +00:00
switch ( err_class )
2021-03-29 20:45:21 +00:00
{
2023-08-21 23:24:21 +00: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 20:45:21 +00:00
}
2023-08-21 23:24:21 +00: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 20:45:21 +00:00
{
2023-08-21 23:24:21 +00: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 20:45:21 +00:00
}
2021-03-28 13:13:23 +00:00
bmp_send_peer_down_notif_msg ( p , bgp , bmp_buffer_data ( & payload ) , bmp_buffer_pos ( & payload ) ) ;
2021-03-29 20:45:21 +00:00
bmp_buffer_free ( & payload ) ;
2023-08-18 01:53:58 +00:00
bmp_remove_peer ( p , bp ) ;
2021-03-29 20:45:21 +00:00
}
2023-06-08 02:56:41 +00:00
void
2023-08-21 23:24:21 +00:00
bmp_peer_down ( const struct bgp_proto * bgp ,
int err_class , int code , int subcode , const byte * data , int length )
2023-06-08 02:56:41 +00:00
{
struct bmp_proto * p ; node * n ;
WALK_LIST2 ( p , n , bmp_proto_list , bmp_node )
2023-08-21 23:24:21 +00:00
bmp_peer_down_ ( p , bgp , err_class , code , subcode , data , length ) ;
2023-06-08 02:56:41 +00:00
}
2021-03-28 02:30:11 +00:00
static void
2021-03-28 13:13:23 +00:00
bmp_send_termination_msg ( struct bmp_proto * p ,
2021-03-29 20:45:21 +00: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 14:41:53 +00:00
buffer stream = bmp_buffer_alloc ( p - > buffer_mpool , term_msg_size ) ;
2021-03-29 20:45:21 +00: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 14:41:53 +00:00
memcpy ( p - > sk - > tbuf , bmp_buffer_data ( & stream ) , bmp_buffer_pos ( & stream ) ) ;
2021-03-28 02:30:11 +00:00
IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL (
2021-03-28 14:41:53 +00:00
sk_send ( p - > sk , bmp_buffer_pos ( & stream ) ) < 0 ,
2021-03-28 02:30:11 +00:00
" Failed to send BMP termination message "
) ;
2021-03-29 20:45:21 +00:00
bmp_buffer_free ( & stream ) ;
}
2023-08-18 01:53:58 +00:00
int
bmp_preexport ( struct channel * C UNUSED , rte * e )
{
2024-07-04 11:13:38 +00: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 01:53:58 +00:00
return - 1 ;
/* Reject non-BGP routes */
2024-07-04 11:13:38 +00:00
if ( p - > proto ! = & proto_bgp )
2023-08-18 01:53:58 +00:00
return - 1 ;
return 1 ;
}
static void
2024-07-04 11:13:38 +00:00
bmp_rt_notify ( struct proto * P , struct channel * c , const net_addr * net ,
2024-07-11 12:43:32 +00:00
struct rte * new , const struct rte * old )
2023-08-18 01:53:58 +00:00
{
struct bmp_proto * p = ( void * ) P ;
struct bgp_channel * src = ( void * ) ( new ? : old ) - > sender ;
struct bgp_proto * bgp = ( void * ) src - > c . proto ;
bool policy = ( c - > table = = src - > c . table ) ;
2023-08-21 23:24:21 +00:00
/*
* We assume that we receive peer_up before the first route and peer_down
* synchronously with BGP session close . So if bmp_stream exists , the related
* BGP session is up and could be accessed . That may not be true in
* multithreaded setup .
*/
2023-08-18 01:53:58 +00:00
struct bmp_stream * bs = bmp_find_stream ( p , bgp , src - > afi , policy ) ;
if ( ! bs )
return ;
2024-07-11 12:43:32 +00:00
bmp_route_monitor_notify ( p , bgp , bs , net , new , ( new ? : old ) - > src ) ;
2023-08-18 01:53:58 +00:00
}
2023-08-21 02:20:32 +00:00
static void
bmp_feed_end ( struct channel * c )
{
struct bmp_proto * p = ( void * ) c - > proto ;
struct bmp_table * bt = bmp_find_table ( p , c - > table ) ;
if ( ! bt )
return ;
/*
* 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 01:53:58 +00:00
2023-04-20 14:13:58 +00: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 20:45:21 +00:00
static void
2023-04-20 14:13:58 +00:00
bmp_startup ( struct bmp_proto * p )
2021-03-29 20:45:21 +00:00
{
2023-04-20 14:13:58 +00:00
ASSERT ( ! p - > started ) ;
p - > started = true ;
2023-05-31 15:41:53 +00:00
p - > sock_err = 0 ;
2021-03-28 13:13:23 +00:00
2023-04-20 14:13:58 +00:00
TRACE ( D_EVENTS , " BMP session established " ) ;
2021-03-28 02:30:11 +00:00
2024-07-26 15:24:15 +00:00
log ( " bmp startup %s %i " , p - > p . name , p - > p . id ) ;
2023-08-18 01:53:58 +00:00
proto_notify_state ( & p - > p , PS_UP ) ;
2023-04-20 14:13:58 +00: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 20:45:21 +00:00
2023-04-20 14:13:58 +00:00
/* Send Peer Up messages */
2024-07-11 12:43:32 +00:00
for ( u32 i = 0 ; i < proto_state_table - > length ; i + + )
2024-07-04 11:13:38 +00:00
{
2024-07-11 12:43:32 +00:00
ea_list * proto_attr = proto_state_table - > attrs [ i ] ;
if ( proto_attr = = NULL )
2024-07-04 11:13:38 +00:00
continue ;
2024-07-11 12:43:32 +00: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-07-04 11:13:38 +00:00
if ( proto ! = & proto_bgp | | state ! = PS_UP )
continue ;
2024-07-11 12:43:32 +00:00
bmp_peer_init ( p , proto_attr ) ;
2024-07-04 11:13:38 +00:00
}
/*struct proto *peer;
2023-05-01 01:35:21 +00:00
WALK_LIST ( peer , proto_list )
2024-07-04 11:13:38 +00:00
if ( ( peer - > proto ! = & proto_bgp ) & & ( peer - > proto_state = = PS_UP ) )
bmp_peer_init ( p , ( struct bgp_proto * ) peer ) ; */
2021-03-29 20:45:21 +00:00
}
2023-04-20 14:13:58 +00:00
/**
* bmp_down - leave established state
* @ p : BMP instance
*
2023-08-18 01:53:58 +00:00
* The bgp_down ( ) function is called when the BMP session fails . The caller is
* responsible for changing protocol state .
2023-04-20 14:13:58 +00:00
*/
static void
bmp_down ( struct bmp_proto * p )
2021-03-29 20:45:21 +00:00
{
2023-04-20 14:13:58 +00:00
ASSERT ( p - > started ) ;
p - > started = false ;
TRACE ( D_EVENTS , " BMP session closed " ) ;
2023-08-18 01:53:58 +00:00
/* Unregister existing peer structures */
HASH_WALK_DELSAFE ( p - > peer_map , next , bp )
{
bmp_remove_peer ( p , bp ) ;
}
HASH_WALK_END ;
/* Removing peers should also remove all streams and tables */
ASSERT ( ! p - > peer_map . count & & ! p - > stream_map . count & & ! p - > table_map . count ) ;
2023-04-20 14:13:58 +00: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 20:45:21 +00:00
sk - > type = SK_TCP_ACTIVE ;
2023-05-30 15:09:25 +00:00
sk - > saddr = p - > local_addr ;
2023-04-20 14:13:58 +00:00
sk - > daddr = p - > station_ip ;
sk - > dport = p - > station_port ;
2021-03-29 20:45:21 +00:00
sk - > ttl = IP4_MAX_TTL ;
sk - > tos = IP_PREC_INTERNET_CONTROL ;
sk - > tbsize = BGP_TX_BUFFER_EXT_SIZE ;
2023-04-20 14:13:58 +00:00
sk - > tx_hook = bmp_connected ;
sk - > err_hook = bmp_sock_err ;
2021-03-29 20:45:21 +00:00
2021-03-28 14:41:53 +00:00
p - > sk = sk ;
sk - > data = p ;
2023-04-20 14:13:58 +00:00
2023-06-08 02:56:41 +00:00
TRACE ( D_EVENTS , " Connecting to %I port %u " , sk - > daddr , sk - > dport ) ;
2024-07-11 12:43:32 +00:00
int rc = sk_open ( sk , p - > p . loop ) ;
2023-04-20 14:13:58 +00:00
if ( rc < 0 )
sk_log_error ( sk , p - > p . name ) ;
tm_start ( p - > connect_retry_timer , CONNECT_RETRY_TIME ) ;
2021-03-29 20:45:21 +00:00
}
2023-05-30 13:52:01 +00:00
/* BMP connect successful event - switch from Connect to Established state */
2023-04-20 14:13:58 +00:00
static void
bmp_connected ( struct birdsock * sk )
{
struct bmp_proto * p = ( void * ) sk - > data ;
2023-06-08 02:56:41 +00:00
TRACE ( D_EVENTS , " Connected " ) ;
2023-04-20 14:13:58 +00: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 15:41:53 +00:00
p - > sock_err = err ;
2023-04-20 14:13:58 +00: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 01:53:58 +00:00
proto_notify_state ( & p - > p , PS_START ) ;
2023-04-20 14:13:58 +00: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 15:23:56 +00: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 15:24:15 +00:00
void
fc_for_bmp_recipient ( void * rec )
{
log ( " received update, locked %i " , locking_stack . service ) ;
struct lfjour_item * last_up ;
struct proto_pending_update * pupdate ;
while ( last_up = lfjour_get ( ( struct lfjour_recipient * ) rec ) )
{
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 ) ;
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?
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)
//{
log ( " protocol %s is bgp %i " , proto - > name , proto = = & proto_bgp ) ;
//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 ) ;
bmp_peer_up ( proto_state_table - > attrs [ id ] , tx_open_msg , l_len , rx_open_msg , r_len ) ;
}
lfjour_release ( rec ) ;
}
}
void
create_bmp_recipient ( void )
{
struct lfjour_recipient * r = mb_allocz ( & root_pool , sizeof ( struct lfjour_recipient ) ) ;
r - > event = ev_new_init ( & root_pool , fc_for_bmp_recipient , r ) ;
struct birdloop * loop = birdloop_new ( & root_pool , DOMAIN_ORDER ( service ) , 1 , " bmp recipient loop " ) ;
r - > target = birdloop_event_list ( loop ) ;
LOCK_DOMAIN ( rtable , proto_journal_domain ) ;
lfjour_register ( proto_journal , r ) ;
UNLOCK_DOMAIN ( rtable , proto_journal_domain ) ;
}
2021-03-29 20:45:21 +00:00
/** Configuration handle section **/
static struct proto *
bmp_init ( struct proto_config * CF )
{
2024-07-26 15:24:15 +00:00
log ( " start init locked %i " , locking_stack . service ) ;
2021-03-29 20:45:21 +00:00
struct proto * P = proto_new ( CF ) ;
2021-03-28 13:13:23 +00:00
struct bmp_proto * p = ( void * ) P ;
struct bmp_config * cf = ( void * ) CF ;
2023-05-31 15:41:53 +00:00
2023-08-18 01:53:58 +00:00
P - > rt_notify = bmp_rt_notify ;
P - > preexport = bmp_preexport ;
2024-07-11 12:43:32 +00:00
//P->feed_end = bmp_feed_end; I am confused. It looks like feed_end and bmp_feed_end exist only here
2023-08-18 01:53:58 +00:00
2021-03-28 13:13:23 +00:00
p - > cf = cf ;
2023-05-30 15:09:25 +00:00
p - > local_addr = cf - > local_addr ;
2021-03-28 13:13:23 +00: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 01:53:58 +00:00
p - > monitoring_rib . in_post_policy = cf - > monitoring_rib_in_post_policy ;
2024-07-26 15:24:15 +00:00
create_bmp_recipient ( ) ;
log ( " new proto created locked %i " , locking_stack . service ) ;
2021-03-28 13:13:23 +00:00
2021-03-29 20:45:21 +00:00
return P ;
}
2023-05-30 15:09:25 +00:00
/**
* bmp_start - initialize internal resources of BMP implementation .
* NOTE : It does not connect to BMP collector yet .
*/
2021-03-29 20:45:21 +00:00
static int
bmp_start ( struct proto * P )
{
2024-07-26 15:24:15 +00:00
log ( " start locked %i " , locking_stack . service ) ;
2021-03-28 13:13:23 +00:00
struct bmp_proto * p = ( void * ) P ;
2024-07-11 12:43:32 +00: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 15:56:56 +00: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 14:13:58 +00:00
p - > connect_retry_timer = tm_new_init ( p - > p . pool , bmp_connection_retry , p , 0 , 0 ) ;
p - > sk = NULL ;
2023-04-18 13:13:24 +00:00
2023-08-18 01:53:58 +00: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 13:13:24 +00:00
init_list ( & p - > tx_queue ) ;
2023-08-01 15:56:56 +00:00
init_list ( & p - > update_msg_queue ) ;
2023-04-18 13:13:24 +00:00
p - > started = false ;
2023-05-31 15:41:53 +00:00
p - > sock_err = 0 ;
2023-06-08 02:56:41 +00:00
add_tail ( & bmp_proto_list , & p - > bmp_node ) ;
2023-04-18 13:13:24 +00:00
2023-04-20 14:13:58 +00:00
tm_start ( p - > connect_retry_timer , CONNECT_INIT_TIME ) ;
2021-03-29 20:45:21 +00:00
2024-07-26 15:24:15 +00:00
log ( " end of start locked %i " , locking_stack . service ) ;
2023-04-20 14:13:58 +00:00
return PS_START ;
2021-03-29 20:45:21 +00:00
}
static int
bmp_shutdown ( struct proto * P )
{
2021-03-28 13:13:23 +00:00
struct bmp_proto * p = ( void * ) P ;
2023-04-20 14:13:58 +00:00
if ( p - > started )
{
bmp_send_termination_msg ( p , BMP_TERM_REASON_ADM ) ;
2023-08-18 01:53:58 +00:00
bmp_down ( p ) ;
2023-04-20 14:13:58 +00:00
}
2021-03-29 20:45:21 +00:00
2023-05-31 15:41:53 +00:00
p - > sock_err = 0 ;
2023-06-08 02:56:41 +00:00
rem_node ( & p - > bmp_node ) ;
2021-03-29 20:45:21 +00:00
return PS_DOWN ;
}
static int
2023-04-18 16:57:54 +00:00
bmp_reconfigure ( struct proto * P , struct proto_config * CF )
2021-03-29 20:45:21 +00:00
{
2023-04-18 16:57:54 +00:00
struct bmp_proto * p = ( void * ) P ;
2023-05-31 15:41:53 +00:00
const struct bmp_config * new = ( void * ) CF ;
const struct bmp_config * old = p - > cf ;
2023-04-18 16:57:54 +00:00
2023-05-31 15:41:53 +00: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 01:53:58 +00: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 16:57:54 +00:00
2023-05-31 15:41:53 +00: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 16:57:54 +00:00
return 1 ;
2021-03-29 20:45:21 +00:00
}
2023-05-31 15:41:53 +00: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 20:45:21 +00:00
struct protocol proto_bmp = {
. name = " BMP " ,
2023-04-18 13:09:21 +00:00
. template = " bmp%d " ,
2024-07-11 12:43:32 +00:00
//.class = PROTOCOL_BMP, looks like there are no classes for protocols anymore
2021-03-29 20:45:21 +00:00
. proto_size = sizeof ( struct bmp_proto ) ,
. config_size = sizeof ( struct bmp_config ) ,
2023-05-30 15:23:56 +00:00
. postconfig = bmp_postconfig ,
2021-03-29 20:45:21 +00:00
. init = bmp_init ,
. start = bmp_start ,
. shutdown = bmp_shutdown ,
. reconfigure = bmp_reconfigure ,
2023-05-31 15:41:53 +00:00
. get_status = bmp_get_status ,
. show_proto_info = bmp_show_proto_info ,
2021-03-29 20:45:21 +00:00
} ;
void
bmp_build ( void )
{
proto_build ( & proto_bmp ) ;
}