From 1be0be1b71f0127740a4aa6f35d4a256d6c34fb9 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 28 Apr 2023 19:13:56 +0200 Subject: [PATCH 01/17] BGP: Save sent and received OPEN messages These are necessary for BMP Peer UP message and it is better to keep them in BGP than in BMP (so BMP could be restarted or added later). --- proto/bgp/bgp.c | 7 +++++++ proto/bgp/bgp.h | 6 ++++++ proto/bgp/packets.c | 17 ++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index c806765a..373b0392 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -380,6 +380,13 @@ bgp_close_conn(struct bgp_conn *conn) rfree(conn->sk); conn->sk = NULL; + mb_free(conn->local_open_msg); + conn->local_open_msg = NULL; + mb_free(conn->remote_open_msg); + conn->remote_open_msg = NULL; + conn->local_open_length = 0; + conn->remote_open_length = 0; + mb_free(conn->local_caps); conn->local_caps = NULL; mb_free(conn->remote_caps); diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 7c96e851..5f8f183d 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -287,6 +287,11 @@ struct bgp_conn { u8 ext_messages; /* Session uses extended message length */ u32 received_as; /* ASN received in OPEN message */ + byte *local_open_msg; /* Saved OPEN messages (no header) */ + byte *remote_open_msg; + uint local_open_length; + uint remote_open_length; + struct bgp_caps *local_caps; struct bgp_caps *remote_caps; timer *connect_timer; @@ -487,6 +492,7 @@ struct bgp_parse_state { #define BGP_PORT 179 #define BGP_VERSION 4 #define BGP_HEADER_LENGTH 19 +#define BGP_HDR_MARKER_LENGTH 16 #define BGP_MAX_MESSAGE_LENGTH 4096 #define BGP_MAX_EXT_MSG_LENGTH 65535 #define BGP_RX_BUFFER_SIZE 4096 diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index b9537169..c6c12cf2 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -772,6 +772,14 @@ err: return -1; } +static byte * +bgp_copy_open(struct bgp_proto *p, const byte *pkt, uint len) +{ + char *buf = mb_alloc(p->p.pool, len - BGP_HEADER_LENGTH); + memcpy(buf, pkt + BGP_HEADER_LENGTH, len - BGP_HEADER_LENGTH); + return buf; +} + static byte * bgp_create_open(struct bgp_conn *conn, byte *buf) { @@ -846,6 +854,9 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len) id = get_u32(pkt+24); BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%R)", asn, hold, id); + conn->remote_open_msg = bgp_copy_open(p, pkt, len); + conn->remote_open_length = len - BGP_HEADER_LENGTH; + if (bgp_read_options(conn, pkt+29, pkt[28], len-29) < 0) return; @@ -2984,7 +2995,7 @@ bgp_send(struct bgp_conn *conn, uint type, uint len) conn->bgp->stats.tx_messages++; conn->bgp->stats.tx_bytes += len; - memset(buf, 0xff, 16); /* Marker */ + memset(buf, 0xff, BGP_HDR_MARKER_LENGTH); put_u16(buf+16, len); buf[18] = type; @@ -3032,6 +3043,10 @@ bgp_fire_tx(struct bgp_conn *conn) { conn->packets_to_send &= ~(1 << PKT_OPEN); end = bgp_create_open(conn, pkt); + + conn->local_open_msg = bgp_copy_open(p, buf, end - buf); + conn->local_open_length = end - buf - BGP_HEADER_LENGTH; + int rv = bgp_send(conn, PKT_OPEN, end - buf); if (rv >= 0) { From aa3c35498d3c5ae7ec7fd34bf8758652fc2748f1 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 1 May 2023 03:35:21 +0200 Subject: [PATCH 02/17] BMP: Use OPEN messages stored in BGP The BMP protocol needs OPEN messages of established BGP sessions to construct appropriate Peer Up messages. Instead of saving them internally we use OPEN messages stored in BGP instances. This allows BMP instances to be restarted or enabled later. Because of this change, we can simplify BMP data structures. No need to keep track of BGP sessions when we are not started. We have to iterate over all (established) BGP sessions when the BMP session is established. This is just a scaffolding now, but some kind of iteration would be necessary anyway. Also, the commit cleans up handling of msg/msg_length arguments to be body/body_length consistently in both rx/tx and peer_up/peer_down calls. --- proto/bgp/bgp.c | 2 + proto/bgp/packets.c | 12 +-- proto/bmp/bmp.c | 207 ++++++++++++++------------------------------ proto/bmp/bmp.h | 32 ++----- 4 files changed, 74 insertions(+), 179 deletions(-) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 373b0392..17c503c4 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -689,6 +689,8 @@ bgp_conn_enter_established_state(struct bgp_conn *conn) bgp_conn_set_state(conn, BS_ESTABLISHED); proto_notify_state(&p->p, PS_UP); + bmp_peer_up(p, conn->local_open_msg, conn->local_open_length, + conn->remote_open_msg, conn->remote_open_length); } static void diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index c6c12cf2..3138095a 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -167,7 +167,6 @@ bgp_create_notification(struct bgp_conn *conn, byte *buf) buf[0] = conn->notify_code; buf[1] = conn->notify_subcode; memcpy(buf+2, conn->notify_data, conn->notify_size); - bmp_peer_down(p, BE_NONE, buf, conn->notify_size + 2); return buf + 2 + conn->notify_size; } @@ -988,7 +987,6 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len) bgp_schedule_packet(conn, NULL, PKT_KEEPALIVE); bgp_start_timer(conn->hold_timer, conn->hold_time); bgp_conn_enter_openconfirm_state(conn); - bmp_put_recv_bgp_open_msg(p, pkt, len); } @@ -3037,6 +3035,7 @@ bgp_fire_tx(struct bgp_conn *conn) { conn->packets_to_send = 1 << PKT_SCHEDULE_CLOSE; end = bgp_create_notification(conn, pkt); + bmp_peer_down(p, BE_BGP_TX, pkt, end - pkt); return bgp_send(conn, PKT_NOTIFICATION, end - buf); } else if (s & (1 << PKT_OPEN)) @@ -3047,12 +3046,7 @@ bgp_fire_tx(struct bgp_conn *conn) conn->local_open_msg = bgp_copy_open(p, buf, end - buf); conn->local_open_length = end - buf - BGP_HEADER_LENGTH; - int rv = bgp_send(conn, PKT_OPEN, end - buf); - if (rv >= 0) - { - bmp_put_sent_bgp_open_msg(p, pkt, end - buf); - } - return rv; + return bgp_send(conn, PKT_OPEN, end - buf); } else if (s & (1 << PKT_KEEPALIVE)) { @@ -3352,7 +3346,7 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len) } } - bmp_peer_down(p, BE_NONE, pkt, len); + bmp_peer_down(p, BE_BGP_RX, pkt + BGP_HEADER_LENGTH, len - BGP_HEADER_LENGTH); } static void diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index f04b59b8..acfcae34 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -214,7 +214,7 @@ struct bmp_data_node { }; static void -bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C); +bmp_route_monitor_pre_policy_table_in_snapshot(struct bgp_channel *c); static void bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size) @@ -336,12 +336,14 @@ bmp_put_ipa(buffer *stream, const ip_addr addr) } static void -bmp_set_initial_bgp_hdr(buffer *stream, const u16 msg_size, const u8 msg_type) +bmp_put_bgp_hdr(buffer *stream, const u8 msg_type, const u16 msg_length) { - byte marker[BGP_MSG_HDR_MARKER_SIZE]; - memset(marker, 0xff, BGP_MSG_HDR_MARKER_SIZE); - bmp_put_data(stream, marker, BGP_MSG_HDR_MARKER_SIZE); - bmp_put_u16(stream, msg_size); + 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); bmp_put_u8(stream, msg_type); } @@ -413,8 +415,10 @@ bmp_peer_up_notif_msg_serialize(buffer *stream, const bool is_peer_global, const u16 remote_port, const byte *sent_msg, const size_t sent_msg_size, const byte *recv_msg, const size_t recv_msg_size) { - const size_t data_size = BMP_PER_PEER_HDR_SIZE + BMP_PEER_UP_NOTIF_MSG_FIX_SIZE - + sent_msg_size + recv_msg_size; + const size_t data_size = + BMP_PER_PEER_HDR_SIZE + BMP_PEER_UP_NOTIF_MSG_FIX_SIZE + + BGP_HEADER_LENGTH + sent_msg_size + BGP_HEADER_LENGTH + recv_msg_size; + 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, @@ -423,11 +427,9 @@ bmp_peer_up_notif_msg_serialize(buffer *stream, const bool is_peer_global, bmp_put_ipa(stream, local_addr); bmp_put_u16(stream, local_port); bmp_put_u16(stream, remote_port); - bmp_set_initial_bgp_hdr(stream, sent_msg_size, PKT_OPEN); - const size_t missing_bgp_hdr_size = BGP_MSG_HDR_MARKER_SIZE - + BGP_MSG_HDR_LENGTH_SIZE - + BGP_MSG_HDR_TYPE_SIZE; - bmp_put_data(stream, sent_msg, sent_msg_size - missing_bgp_hdr_size); + bmp_put_bgp_hdr(stream, PKT_OPEN, BGP_HEADER_LENGTH + sent_msg_size); + bmp_put_data(stream, sent_msg, sent_msg_size); + bmp_put_bgp_hdr(stream, PKT_OPEN, BGP_HEADER_LENGTH + recv_msg_size); bmp_put_data(stream, recv_msg, recv_msg_size); } @@ -445,43 +447,37 @@ bmp_peer_down_notif_msg_serialize(buffer *stream, const bool is_peer_global, bmp_put_data(stream, data, data_size); } -static void -bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif( - const struct bmp_peer_map_key key, const byte *tx_msg, - const size_t tx_msg_size, void *bmp_) +void +bmp_peer_up(const struct bgp_proto *bgp, + const byte *tx_open_msg, uint tx_open_length, + const byte *rx_open_msg, uint rx_open_length) { - struct bmp_proto *p = bmp_; - ASSERT(p->started); + struct bmp_proto *p = g_bmp; - const struct bmp_peer_map_entry *map_rx_msg = bmp_peer_map_get(&p->peer_open_msg.rx_msg, key); - IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - map_rx_msg, - "Processing TX BGP OPEN MSG but there is not corresponding received MSG" - ); + if (!p || !p->started) + return; - const struct bmp_peer_map_entry *map_bgp_proto = bmp_peer_map_get(&p->bgp_peers, key); - IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - map_bgp_proto, - "There is not BGP proto related with stored TX/RX OPEN MSG" - ); + // struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); + // bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); - const struct bgp_proto *bgp; - memcpy(&bgp, map_bgp_proto->data.buf, sizeof (bgp)); - if (bgp->p.proto_state == PS_UP) - { - bmp_send_peer_up_notif_msg(p, bgp, tx_msg, tx_msg_size, - map_rx_msg->data.buf, map_rx_msg->data.buf_size); - } + bmp_send_peer_up_notif_msg(p, bgp, tx_open_msg, tx_open_length, rx_open_msg, rx_open_length); + + struct bgp_channel *c; + BGP_WALK_CHANNELS(bgp, c) + bmp_route_monitor_pre_policy_table_in_snapshot(c); } static void -bmp_peer_up(const struct bgp_proto *bgp) +bmp_peer_init(const struct bgp_proto *bgp) { - struct bgp_channel *c; - WALK_LIST(c, bgp->p.channels) - { - bmp_route_monitor_pre_policy_table_in_snapshot((struct channel *) c); - } + struct bgp_conn *conn = bgp->conn; + + if (!conn || (conn->state != BS_ESTABLISHED) || + !conn->local_open_msg || !conn->remote_open_msg) + return; + + bmp_peer_up(bgp, conn->local_open_msg, conn->local_open_length, + conn->remote_open_msg, conn->remote_open_length); } static const struct birdsock * @@ -579,60 +575,6 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, rx_data, rx_data_size); bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_free(&payload); - - bmp_peer_up(bgp); -} - -void -bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, - const size_t pkt_size) -{ - struct bmp_proto *p = g_bmp; - - if (!p) - { - return; - } - - struct bmp_peer_map_key key - = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - const struct bmp_peer_map_entry *rx_msg - = bmp_peer_map_get(&p->peer_open_msg.rx_msg, key); - - bmp_peer_map_insert(&p->peer_open_msg.tx_msg, key, pkt, pkt_size); - - if (!rx_msg) - bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); - - if (rx_msg && p->started) - bmp_send_peer_up_notif_msg(p, bgp, pkt, pkt_size, rx_msg->data.buf, - rx_msg->data.buf_size); -} - -void -bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, - const size_t pkt_size) -{ - struct bmp_proto *p = g_bmp; - - if (!p) - { - return; - } - - struct bmp_peer_map_key key - = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - const struct bmp_peer_map_entry *tx_msg - = bmp_peer_map_get(&p->peer_open_msg.tx_msg, key); - - bmp_peer_map_insert(&p->peer_open_msg.rx_msg, key, pkt, pkt_size); - - if (!tx_msg) - bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); - - if (tx_msg && p->started) - bmp_send_peer_up_notif_msg(p, bgp, tx_msg->data.buf, tx_msg->data.buf_size, - pkt, pkt_size); } void @@ -775,7 +717,7 @@ bmp_route_monitor_update_in_pre_end() } static void -bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C) +bmp_route_monitor_pre_policy_table_in_snapshot(struct bgp_channel *c) { struct bmp_proto *p = g_bmp; @@ -784,7 +726,7 @@ bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C) return; } - struct rtable *tab = C->in_table; + struct rtable *tab = c->c.in_table; if (!tab) { return; @@ -808,7 +750,7 @@ bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C) rte *e; for (e = n->routes; e; e = e->next) { - bgp_rte_update_in_notify(C, n->n.addr, e, e->src); + bgp_rte_update_in_notify(&c->c, n->n.addr, e, e->src); } bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) P); @@ -821,15 +763,13 @@ bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C) { bmp_route_monitor_update_in_pre_begin(); byte rx_end_payload[DEFAULT_MEM_BLOCK_SIZE]; - byte *pos - = bgp_create_end_mark((struct bgp_channel *) C, rx_end_payload - + BGP_HEADER_LENGTH); + byte *pos = bgp_create_end_mark(c, rx_end_payload + BGP_HEADER_LENGTH); 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); bmp_route_monitor_put_update_in_pre_msg(rx_end_payload, pos - rx_end_payload); - bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) C->proto); + bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) c->c.proto); bmp_route_monitor_update_in_pre_end(); } } @@ -854,49 +794,28 @@ bmp_send_peer_down_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, } void -bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, - size_t pkt_size) +bmp_peer_down(const struct bgp_proto *bgp, const int err_class, + const byte *msg, size_t msg_length) { struct bmp_proto *p = g_bmp; - if (!p) - { - return; - } - - struct bmp_peer_map_key key - = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - - bmp_peer_map_remove(&p->peer_open_msg.tx_msg, key); - bmp_peer_map_remove(&p->peer_open_msg.rx_msg, key); - bmp_peer_map_remove(&p->bgp_peers, key); - const size_t missing_bgp_hdr_size = BGP_MSG_HDR_MARKER_SIZE - + BGP_MSG_HDR_LENGTH_SIZE - + BGP_MSG_HDR_TYPE_SIZE; - - if (!p->started) + if (!p || !p->started) return; - buffer payload - = bmp_buffer_alloc(p->buffer_mpool, pkt_size + missing_bgp_hdr_size + 1); - if (pkt != NULL && pkt_size > 0) + // struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); + // bmp_peer_map_remove(&p->bgp_peers, key); + + buffer payload = bmp_buffer_alloc(p->buffer_mpool, 1 + BGP_HEADER_LENGTH + msg_length); + + if (msg) { - byte marker[BGP_MSG_HDR_MARKER_SIZE]; - memset(marker, 0xff, BGP_MSG_HDR_MARKER_SIZE); // NOTIF MSG marker - if (!memcmp(pkt, marker, BGP_MSG_HDR_MARKER_SIZE)) - { - // So it is received BGP PDU - bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION); - bmp_put_data(&payload, pkt, pkt_size); - } - else - { + if (err_class == BE_BGP_TX) bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION); - bmp_put_data(&payload, marker, BGP_MSG_HDR_MARKER_SIZE); - bmp_put_u16(&payload, pkt_size); - bmp_put_u8(&payload, PKT_NOTIFICATION); - bmp_put_data(&payload, pkt, pkt_size); - } + else + bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION); + + bmp_put_bgp_hdr(&payload, BGP_HEADER_LENGTH + msg_length, PKT_NOTIFICATION); + bmp_put_data(&payload, msg, msg_length); } else { @@ -962,8 +881,10 @@ bmp_startup(struct bmp_proto *p) bmp_buffer_free(&payload); /* Send Peer Up messages */ - bmp_peer_map_walk(&p->peer_open_msg.tx_msg, - bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif, p); + struct proto *peer; + WALK_LIST(peer, proto_list) + if ((peer->proto->class == PROTOCOL_BGP) && (peer->proto_state == PS_UP)) + bmp_peer_init((struct bgp_proto *) peer); proto_notify_state(&p->p, PS_UP); } @@ -1105,9 +1026,7 @@ bmp_start(struct proto *P) p->connect_retry_timer = tm_new_init(p->p.pool, bmp_connection_retry, p, 0, 0); p->sk = NULL; - bmp_peer_map_init(&p->peer_open_msg.tx_msg, p->map_mem_pool); - bmp_peer_map_init(&p->peer_open_msg.rx_msg, p->map_mem_pool); - bmp_peer_map_init(&p->bgp_peers, p->map_mem_pool); + // bmp_peer_map_init(&p->bgp_peers, p->map_mem_pool); init_list(&p->tx_queue); init_list(&p->rt_table_in_pre_policy.update_msg_queue); diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 19623e33..51a8e636 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -46,12 +46,6 @@ struct bmp_config { struct bgp_proto; struct bmp_proto; -// Stores sent and received BGP OPEN MSGs -struct bmp_peer_open_msg { - struct bmp_peer_map tx_msg; - struct bmp_peer_map rx_msg; -}; - // Keeps necessary information during composing BGP UPDATE MSG which is going // to be sent to the BMP collector struct rt_table_info { @@ -72,8 +66,7 @@ struct bmp_proto { u16 station_port; // Monitoring station TCP port struct monitoring_rib monitoring_rib; // Below fields are for internal use - struct bmp_peer_map bgp_peers; // Stores 'bgp_proto' structure per BGP peer - struct bmp_peer_open_msg peer_open_msg; // Stores sent and received BGP OPEN MSG per BGP peer + // struct bmp_peer_map bgp_peers; // Stores 'bgp_proto' structure per BGP peer pool *buffer_mpool; // Memory pool used for BMP buffer allocations pool *map_mem_pool; // Memory pool used for BMP map allocations pool *tx_mem_pool; // Memory pool used for packet allocations designated to BMP collector @@ -88,24 +81,12 @@ struct bmp_proto { #ifdef CONFIG_BMP /** - * bmp_put_sent_bgp_open_msg - save sent BGP OPEN msg packet in BMP implementation. - * NOTE: If there has been passed sent and received BGP OPEN MSGs to the BMP - * implementation, then there is going to be send BMP Peer Up Notification - * message to the BMP collector. + * bmp_peer_up - send notification that BGP peer connection is established */ void -bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, - const size_t pkt_size); - -/** - * bmp_put_recv_bgp_open_msg - save received BGP OPEN msg packet in BMP implementation. - * NOTE: If there has been passed sent and received BGP OPEN MSGs to the BMP - * implementation, then there is going to be send BMP Peer Up Notification - * message to the BMP collector. - */ -void -bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt, - const size_t pkt_size); +bmp_peer_up(const struct bgp_proto *bgp, + const byte *tx_open_msg, uint tx_open_length, + const byte *rx_open_msg, uint rx_open_length); /** * The following 4 functions create BMP Route Monitoring message based on @@ -140,8 +121,7 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, #else /* BMP build disabled */ -static inline void bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp UNUSED, const byte* pkt UNUSED, const size_t pkt_size UNUSED) { } -static inline void bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp UNUSED, const byte* pkt UNUSED, const size_t pkt_size UNUSED) { } +static inline void bmp_peer_up(const struct bgp_proto *bgp, const byte *tx_open_msg, uint tx_open_length, const byte *rx_open_msg, uint rx_open_length) { } static inline void bmp_route_monitor_update_in_pre_begin(void) { } static inline void bmp_route_monitor_put_update_in_pre_msg(const byte *data UNUSED, const size_t data_size UNUSED) { } static inline void bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp UNUSED) { } From c1821a9aba3c7fbdb48cee7d86e4661317900a0a Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 30 May 2023 15:37:52 +0200 Subject: [PATCH 03/17] BGP: Improve bgp_create_update_bmp() Fix issue with missing AF cap (e.g. IPv4 unicast when no capabilities are announced). Add Linpool save/restore action similar to bgp_create_update(). Based on patch from Michal Zagorski co-authored with Pawel Maslanka . Thanks! --- proto/bgp/packets.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 3138095a..63ff955b 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2424,15 +2424,20 @@ bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck, { struct bgp_proto *p = (void *) c->c.proto; byte *end = buf + (BGP_MAX_EXT_MSG_LENGTH - BGP_HEADER_LENGTH); + byte *res = NULL; /* FIXME: must be a bit shorter */ + struct lp_state tmpp; + lp_save(tmp_linpool, &tmpp); + struct bgp_caps *peer = p->conn->remote_caps; const struct bgp_af_caps *rem = bgp_find_af_caps(peer, c->afi); + struct bgp_write_state s = { .proto = p, .channel = c, .pool = tmp_linpool, - .mp_reach = (c->afi != BGP_AF_IPV4) || rem->ext_next_hop, + .mp_reach = (c->afi != BGP_AF_IPV4) || (rem && rem->ext_next_hop), .as4_session = 1, .add_path = c->add_path_rx, .mpls = c->desc->mpls, @@ -2441,16 +2446,20 @@ bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck, if (!update) { - return !s.mp_reach ? + res = !s.mp_reach ? bgp_create_ip_unreach(&s, buck, buf, end): bgp_create_mp_unreach(&s, buck, buf, end); } else { - return !s.mp_reach ? + res = !s.mp_reach ? bgp_create_ip_reach(&s, buck, buf, end): bgp_create_mp_reach(&s, buck, buf, end); } + + lp_restore(tmp_linpool, &tmpp); + + return res; } static byte * From ae4d934c53cdc4cc5ec3d4535cd5138fdf9b25cb Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 30 May 2023 15:52:01 +0200 Subject: [PATCH 04/17] BMP: Minor formatting cleanups Based on patches from Michal Zagorski co-authored with Pawel Maslanka . Thanks! --- proto/bmp/README.txt | 4 +-- proto/bmp/bmp.c | 64 +++++++++++++------------------------------- proto/bmp/bmp.h | 2 +- proto/bmp/buffer.c | 5 +--- 4 files changed, 22 insertions(+), 53 deletions(-) diff --git a/proto/bmp/README.txt b/proto/bmp/README.txt index 386f4029..ed51529f 100644 --- a/proto/bmp/README.txt +++ b/proto/bmp/README.txt @@ -1,6 +1,6 @@ ABOUT This package |proto/bmp/*| provide implementation of BGP Monitoring Protocol (BMP). It has been started by Akamai Technologies, Inc. as a pilot program for support BMP in BIRD. -It provides only basic features of BMP specification which are needed by Akamai evaluation of +It provides only basic features of BMP specification which are needed by Akamai evaluation of feasible BMP protocol. -Content of this package has been provided as a patch for BIRD release v2.0.7. \ No newline at end of file +Content of this package has been provided as a patch for BIRD release v2.0.7. diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index acfcae34..ca508049 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -23,7 +23,7 @@ * * The BMP session is managed by a simple state machine with three states: Idle * (!started, !sk), Connect (!started, sk active), and Established (started). It - * has three events: connect successfull (Connect -> Established), socket error + * has three events: connect successful (Connect -> Established), socket error * (any -> Idle), and connect timeout (Idle/Connect -> Connect, resetting the * TCP socket). */ @@ -203,8 +203,8 @@ static void bmp_close_socket(struct bmp_proto *p); static void bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, - const byte* tx_data, const size_t tx_data_size, - const byte* rx_data, const size_t rx_data_size); + const byte *tx_data, const size_t tx_data_size, + const byte *rx_data, const size_t rx_data_size); // Stores necessary any data in list struct bmp_data_node { @@ -229,7 +229,7 @@ bmp_info_tlv_hdr_serialize(buffer *stream, const enum bmp_info_tlv_type type, const char *str) { size_t str_len = strlen(str); - str_len = MIN(str_len, 65535); + str_len = MIN(str_len, MIB_II_STR_LEN); bmp_put_u16(stream, type); bmp_put_u16(stream, str_len); @@ -412,12 +412,12 @@ 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, - const u16 remote_port, const byte *sent_msg, const size_t sent_msg_size, - const byte *recv_msg, const size_t recv_msg_size) + const u16 remote_port, const byte *sent_msg, const size_t sent_msg_length, + const byte *recv_msg, const size_t recv_msg_length) { const size_t data_size = BMP_PER_PEER_HDR_SIZE + BMP_PEER_UP_NOTIF_MSG_FIX_SIZE + - BGP_HEADER_LENGTH + sent_msg_size + BGP_HEADER_LENGTH + recv_msg_size; + BGP_HEADER_LENGTH + sent_msg_length + BGP_HEADER_LENGTH + recv_msg_length; bmp_buffer_need(stream, BMP_COMMON_HDR_SIZE + data_size); bmp_common_hdr_serialize(stream, BMP_PEER_UP_NOTIF, data_size); @@ -427,10 +427,10 @@ bmp_peer_up_notif_msg_serialize(buffer *stream, const bool is_peer_global, bmp_put_ipa(stream, local_addr); bmp_put_u16(stream, local_port); bmp_put_u16(stream, remote_port); - bmp_put_bgp_hdr(stream, PKT_OPEN, BGP_HEADER_LENGTH + sent_msg_size); - bmp_put_data(stream, sent_msg, sent_msg_size); - bmp_put_bgp_hdr(stream, PKT_OPEN, BGP_HEADER_LENGTH + recv_msg_size); - bmp_put_data(stream, recv_msg, recv_msg_size); + 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); } static void @@ -484,9 +484,7 @@ static const struct birdsock * bmp_get_birdsock(const struct bgp_proto *bgp) { if (bgp->conn && bgp->conn->sk) - { return bgp->conn->sk; - } return NULL; } @@ -495,11 +493,8 @@ static const struct birdsock * bmp_get_birdsock_ext(const struct bgp_proto *bgp) { const struct birdsock *sk = bmp_get_birdsock(bgp); - if (sk != NULL) - { return sk; - } if (bgp->incoming_conn.sk) { @@ -517,9 +512,7 @@ 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; } @@ -529,9 +522,7 @@ 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) { @@ -556,8 +547,8 @@ bmp_is_peer_global_instance(const struct bgp_proto *bgp) static void bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, - const byte* tx_data, const size_t tx_data_size, - const byte* rx_data, const size_t rx_data_size) + const byte *tx_data, const size_t tx_data_size, + const byte *rx_data, const size_t rx_data_size) { ASSERT(p->started); @@ -577,20 +568,17 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, bmp_buffer_free(&payload); } + void -bmp_route_monitor_update_in_pre_begin() +bmp_route_monitor_update_in_pre_begin(void) { struct bmp_proto *p = g_bmp; if (!p || !p->started) - { return; - } if (p->monitoring_rib.in_pre_policy == false) - { return; - } IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( !EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue), @@ -609,14 +597,10 @@ bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size struct bmp_proto *p = g_bmp; if (!p || !p->started) - { return; - } if (p->monitoring_rib.in_pre_policy == false) - { return; - } IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( !p->rt_table_in_pre_policy.update_in_progress, @@ -638,14 +622,10 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) struct bmp_proto *p = g_bmp; if (!p || !p->started) - { return; - } if (p->monitoring_rib.in_pre_policy == false) - { return; - } const struct birdsock *sk = bmp_get_birdsock(bgp); IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( @@ -690,19 +670,15 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) } void -bmp_route_monitor_update_in_pre_end() +bmp_route_monitor_update_in_pre_end(void) { struct bmp_proto *p = g_bmp; if (!p || !p->started) - { return; - } if (p->monitoring_rib.in_pre_policy == false) - { return; - } struct bmp_data_node *upd_msg; struct bmp_data_node *upd_msg_next; @@ -722,15 +698,11 @@ bmp_route_monitor_pre_policy_table_in_snapshot(struct bgp_channel *c) struct bmp_proto *p = g_bmp; if (p->monitoring_rib.in_pre_policy == false) - { return; - } struct rtable *tab = c->c.in_table; if (!tab) - { return; - } size_t cnt = 0; struct proto *P; @@ -776,7 +748,7 @@ bmp_route_monitor_pre_policy_table_in_snapshot(struct bgp_channel *c) static void bmp_send_peer_down_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, - const byte* data, const size_t data_size) + const byte *data, const size_t data_size) { ASSERT(p->started); @@ -939,7 +911,7 @@ bmp_connect(struct bmp_proto *p) tm_start(p->connect_retry_timer, CONNECT_RETRY_TIME); } -/* BMP connect successfull event - switch from Connect to Established state */ +/* BMP connect successful event - switch from Connect to Established state */ static void bmp_connected(struct birdsock *sk) { diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 51a8e636..40d42e6a 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -121,7 +121,7 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, #else /* BMP build disabled */ -static inline void bmp_peer_up(const struct bgp_proto *bgp, const byte *tx_open_msg, uint tx_open_length, const byte *rx_open_msg, uint rx_open_length) { } +static inline void bmp_peer_up(const struct bgp_proto *bgp UNUSED, const byte *tx_open_msg UNUSED, uint tx_open_length UNUSED, const byte *rx_open_msg UNUSED, uint rx_open_length UNUSED) { } static inline void bmp_route_monitor_update_in_pre_begin(void) { } static inline void bmp_route_monitor_put_update_in_pre_msg(const byte *data UNUSED, const size_t data_size UNUSED) { } static inline void bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp UNUSED) { } diff --git a/proto/bmp/buffer.c b/proto/bmp/buffer.c index f471e08a..9e62e468 100644 --- a/proto/bmp/buffer.c +++ b/proto/bmp/buffer.c @@ -15,7 +15,6 @@ bmp_buffer_alloc(pool *ppool, const size_t n) buf.start = mb_alloc(ppool, n); buf.pos = buf.start; buf.end = buf.start + n; - return buf; } @@ -48,11 +47,9 @@ void bmp_put_data(buffer *buf, const void *src, const size_t n) { if (!n) - { return; - } bmp_buffer_need(buf, n); memcpy(buf->pos, src, n); buf->pos += n; -} \ No newline at end of file +} From 62d8fbdc1cb3d358b0d20d7b10bd3f17f357d567 Mon Sep 17 00:00:00 2001 From: Michal Zagorski Date: Tue, 30 May 2023 17:09:25 +0200 Subject: [PATCH 05/17] BMP: Add local address option Also remove unused local and ip_post_policy options. Co-authored with Pawel Maslanka . Minor changes by committer. --- proto/bmp/bmp.c | 11 ++++++----- proto/bmp/bmp.h | 6 +++--- proto/bmp/config.Y | 12 ++++-------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index ca508049..7efa8f6a 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -892,6 +892,7 @@ bmp_connect(struct bmp_proto *p) sock *sk = sk_new(p->p.pool); sk->type = SK_TCP_ACTIVE; + sk->saddr = p->local_addr; sk->daddr = p->station_ip; sk->dport = p->station_port; sk->ttl = IP4_MAX_TTL; @@ -970,26 +971,26 @@ bmp_init(struct proto_config *CF) struct proto *P = proto_new(CF); struct bmp_proto *p = (void *) P; struct bmp_config *cf = (void *) CF; - p->cf = cf; + p->local_addr = cf->local_addr; 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; - p->monitoring_rib.in_post_policy = cf->monitoring_rib_in_post_policy; - p->monitoring_rib.local = cf->monitoring_rib_local; return P; } +/** + * bmp_start - initialize internal resources of BMP implementation. + * NOTE: It does not connect to BMP collector yet. + */ static int bmp_start(struct proto *P) { struct bmp_proto *p = (void *) P; - log(L_DEBUG "Init BMP"); - p->buffer_mpool = rp_new(P->pool, "BMP Buffer"); p->map_mem_pool = rp_new(P->pool, "BMP Map"); p->tx_mem_pool = rp_new(P->pool, "BMP Tx"); diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 40d42e6a..6d429e66 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -35,11 +35,10 @@ struct bmp_config { struct proto_config c; const char *sys_descr; // sysDescr MIB-II [RFC1213] object const char *sys_name; // sysName MIB-II [RFC1213] object + ip_addr local_addr; // Local IP address ip_addr station_ip; // Monitoring station address u16 station_port; // Monitoring station TCP port bool monitoring_rib_in_pre_policy; // Route monitoring pre-policy Adj-Rib-In - bool monitoring_rib_in_post_policy; // Route monitoring post-policy Adj-Rib-In - bool monitoring_rib_local; // Route monitoring Local Rib }; /* Forward declarations */ @@ -59,9 +58,10 @@ struct bmp_proto { struct proto p; // Parent proto const struct bmp_config *cf; // Shortcut to BMP configuration sock *sk; // TCP connection - event *tx_ev; // TX event + event *tx_ev; // TX event char sys_descr[MIB_II_STR_LEN]; // sysDescr MIB-II [RFC1213] object char sys_name[MIB_II_STR_LEN]; // sysName MIB-II [RFC1213] object + ip_addr local_addr; // Source local IP address ip_addr station_ip; // Monitoring station IP address u16 station_port; // Monitoring station TCP port struct monitoring_rib monitoring_rib; diff --git a/proto/bmp/config.Y b/proto/bmp/config.Y index 776d7ecc..2fc87458 100644 --- a/proto/bmp/config.Y +++ b/proto/bmp/config.Y @@ -25,13 +25,12 @@ proto: bmp_proto '}' ; bmp_proto_start: proto_start BMP { this_proto = proto_config_new(&proto_bmp, $1); + BMP_CFG->local_addr = IPA_NONE4; BMP_CFG->station_ip = IPA_NONE4; BMP_CFG->station_port = 0; BMP_CFG->sys_descr = "Not defined"; BMP_CFG->sys_name = "Not defined"; BMP_CFG->monitoring_rib_in_pre_policy = false; - BMP_CFG->monitoring_rib_in_post_policy = false; - BMP_CFG->monitoring_rib_local = false; } ; @@ -52,6 +51,9 @@ bmp_station_address: bmp_proto: bmp_proto_start proto_name '{' | bmp_proto proto_item ';' + | bmp_proto LOCAL ADDRESS ipa ';' { + BMP_CFG->local_addr = $4; + } | bmp_proto STATION ADDRESS bmp_station_address ';' | bmp_proto SYSTEM DESCRIPTION text ';' { if (!$4 || (strlen($4) == 0)) @@ -70,12 +72,6 @@ bmp_proto: | bmp_proto MONITORING RIB IN PRE_POLICY bool ';' { BMP_CFG->monitoring_rib_in_pre_policy = $6; } - | bmp_proto MONITORING RIB IN POST_POLICY bool ';' { - BMP_CFG->monitoring_rib_in_post_policy = $6; - } - | bmp_proto MONITORING RIB LOCAL bool ';' { - BMP_CFG->monitoring_rib_local = $5; - } ; CF_CODE From 1e45e2aa4e173869be071bfa28057d8b52e8948c Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 30 May 2023 17:23:56 +0200 Subject: [PATCH 06/17] BMP: Add station address check Also, do not initialize it to IPA_NONE4, use regular IPA_NONE. --- proto/bmp/bmp.c | 17 +++++++++++++++++ proto/bmp/config.Y | 3 --- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 7efa8f6a..fce9a0a1 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -964,6 +964,22 @@ bmp_close_socket(struct bmp_proto *p) } +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"); +} + /** Configuration handle section **/ static struct proto * bmp_init(struct proto_config *CF) @@ -1047,6 +1063,7 @@ struct protocol proto_bmp = { .class = PROTOCOL_BMP, .proto_size = sizeof(struct bmp_proto), .config_size = sizeof(struct bmp_config), + .postconfig = bmp_postconfig, .init = bmp_init, .start = bmp_start, .shutdown = bmp_shutdown, diff --git a/proto/bmp/config.Y b/proto/bmp/config.Y index 2fc87458..5a5e0812 100644 --- a/proto/bmp/config.Y +++ b/proto/bmp/config.Y @@ -25,9 +25,6 @@ proto: bmp_proto '}' ; bmp_proto_start: proto_start BMP { this_proto = proto_config_new(&proto_bmp, $1); - BMP_CFG->local_addr = IPA_NONE4; - BMP_CFG->station_ip = IPA_NONE4; - BMP_CFG->station_port = 0; BMP_CFG->sys_descr = "Not defined"; BMP_CFG->sys_name = "Not defined"; BMP_CFG->monitoring_rib_in_pre_policy = false; From e8be7a7080be2ffd800ead5377b06c7a535b564a Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 31 May 2023 17:41:53 +0200 Subject: [PATCH 07/17] BMP: Proper reconfiguration and protocol status Based on patches from Michal Zagorski co-authored with Pawel Maslanka . Thanks! --- proto/bmp/bmp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++--- proto/bmp/bmp.h | 1 + 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index fce9a0a1..5c261584 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -843,6 +843,7 @@ bmp_startup(struct bmp_proto *p) { ASSERT(!p->started); p->started = true; + p->sock_err = 0; TRACE(D_EVENTS, "BMP session established"); @@ -931,6 +932,8 @@ bmp_sock_err(sock *sk, int err) { struct bmp_proto *p = sk->data; + p->sock_err = err; + if (err) TRACE(D_EVENTS, "Connection lost (%M)", err); else @@ -987,6 +990,7 @@ bmp_init(struct proto_config *CF) struct proto *P = proto_new(CF); struct bmp_proto *p = (void *) P; struct bmp_config *cf = (void *) CF; + p->cf = cf; p->local_addr = cf->local_addr; p->station_ip = cf->station_ip; @@ -1020,6 +1024,7 @@ bmp_start(struct proto *P) init_list(&p->tx_queue); init_list(&p->rt_table_in_pre_policy.update_msg_queue); p->started = false; + p->sock_err = 0; tm_start(p->connect_retry_timer, CONNECT_INIT_TIME); @@ -1039,6 +1044,7 @@ bmp_shutdown(struct proto *P) p->started = false; } + p->sock_err = 0; g_bmp = NULL; return PS_DOWN; @@ -1048,15 +1054,62 @@ static int bmp_reconfigure(struct proto *P, struct proto_config *CF) { struct bmp_proto *p = (void *) P; - const struct bmp_config *cf = (void *) CF; + const struct bmp_config *new = (void *) CF; + const struct bmp_config *old = p->cf; - log(L_WARN "Reconfiguring BMP is not supported"); + 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) + || (new->monitoring_rib_in_pre_policy != old->monitoring_rib_in_pre_policy); - p->cf = cf; + /* If there is any change, restart the protocol */ + if (needs_restart) + return 0; + + /* We must update our copy of configuration ptr */ + p->cf = new; return 1; } +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); + } +} + struct protocol proto_bmp = { .name = "BMP", .template = "bmp%d", @@ -1068,6 +1121,8 @@ struct protocol proto_bmp = { .start = bmp_start, .shutdown = bmp_shutdown, .reconfigure = bmp_reconfigure, + .get_status = bmp_get_status, + .show_proto_info = bmp_show_proto_info, }; void diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 6d429e66..be28468c 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -75,6 +75,7 @@ struct bmp_proto { timer *connect_retry_timer; // Timer for retrying connection to the BMP collector struct rt_table_info rt_table_in_pre_policy; // Pre-policy route import table bool started; // Flag that stores running status of BMP instance + int sock_err; // Last socket error code }; From 0799fc99abb523432bc3f903f6a32eafbe37d043 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Wed, 31 May 2023 18:32:53 +0200 Subject: [PATCH 08/17] BMP: Fix bug in buffer resize The buffer code in bmp_buffer_grow(), reuse the MRT buffer handling code. Based on comments by Michal Zagorski , Thanks! --- proto/bmp/buffer.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/proto/bmp/buffer.c b/proto/bmp/buffer.c index 9e62e468..be9dd698 100644 --- a/proto/bmp/buffer.c +++ b/proto/bmp/buffer.c @@ -25,22 +25,32 @@ bmp_buffer_free(buffer *buf) buf->start = buf->pos = buf->end = NULL; } +/** + * @brief bmp_buffer_grow + * @param buf - buffer to grow + * @param n - required amount of available space + * Resize buffer in a way that there is at least @n bytes of available space. + */ static void bmp_buffer_grow(buffer *buf, const size_t n) { - const size_t pos = bmp_buffer_pos(buf); - buf->start = mb_realloc(buf->start, n); + size_t pos = bmp_buffer_pos(buf); + size_t size = bmp_buffer_size(buf); + size_t req = pos + n; + + while (size < req) + size = size * 3 / 2; + + buf->start = mb_realloc(buf->start, size); buf->pos = buf->start + pos; - buf->end = buf->start + n; + buf->end = buf->start + size; } void bmp_buffer_need(buffer *buf, const size_t n) { if (bmp_buffer_avail(buf) < n) - { bmp_buffer_grow(buf, n); - } } void From e8838d930cd5c875f32aa2b7da5d84995b14ccac Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 8 Jun 2023 04:56:41 +0200 Subject: [PATCH 09/17] BMP: Support multiple instances of BMP protocol Add internal BMP functions with plicit bmp_proto *p as first argument, which allows using TRACE() macro. Keep list of BMP instances and call internal functions. Old BMP functions are wrappers that call internal functions for all enabled BMP instances. Extract End-of-RIB mark into separate function. Based on patch from Michal Zagorski . Thanks! --- proto/bgp/bgp.c | 2 +- proto/bgp/bgp.h | 6 +- proto/bgp/packets.c | 21 +++--- proto/bmp/bmp.c | 170 +++++++++++++++++++++++++++++--------------- proto/bmp/bmp.h | 17 +++-- 5 files changed, 140 insertions(+), 76 deletions(-) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 17c503c4..54da2253 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1715,7 +1715,7 @@ bgp_init(struct proto_config *CF) P->rte_igp_metric = bgp_rte_igp_metric; #ifdef CONFIG_BMP - P->rte_update_in_notify = bgp_rte_update_in_notify; + P->rte_update_in_notify = bmp_route_monitor_update_in_notify; #endif p->cf = cf; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 5f8f183d..861f831a 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -631,11 +631,13 @@ struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool); u32 bgp_rte_igp_metric(struct rte *); void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old); int bgp_preexport(struct channel *, struct rte *); -void bgp_rte_update_in_notify(struct channel *C, const net_addr *n, const struct rte *new, const struct rte_src *src); int bgp_get_attr(const struct eattr *e, byte *buf, int buflen); void bgp_get_route_info(struct rte *, byte *buf); int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad); +struct bmp_proto; +void bgp_bmp_encode_rte(struct bgp_channel *c, struct bmp_proto *bmp, const net_addr *n, const struct rte *new, const struct rte_src *src); + #define BGP_AIGP_METRIC 1 #define BGP_AIGP_MAX U64(0xffffffffffffffff) @@ -664,8 +666,8 @@ const char * bgp_error_dsc(unsigned code, unsigned subcode); void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len); void bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to); +byte *bgp_create_end_mark_(struct bgp_channel *c, byte *buf); -byte * bgp_create_end_mark(struct bgp_channel *c, byte *buf); /* Packet types */ diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 63ff955b..0338a887 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2473,11 +2473,10 @@ bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type) } void -bgp_rte_update_in_notify(struct channel *C, const net_addr *n, - const struct rte *new, const struct rte_src *src) +bgp_bmp_encode_rte(struct bgp_channel *c, struct bmp_proto *bmp, const net_addr *n, + const struct rte *new, const struct rte_src *src) { -// struct bgp_proto *p = (void *) C->proto; - struct bgp_channel *c = (void *) C; +// struct bgp_proto *p = (void *) c->c.proto; byte buf[BGP_MAX_EXT_MSG_LENGTH]; byte *pkt = buf + BGP_HEADER_LENGTH; @@ -2507,7 +2506,7 @@ bgp_rte_update_in_notify(struct channel *C, const net_addr *n, return; bgp_bmp_prepare_bgp_hdr(buf, end - buf, PKT_UPDATE); - bmp_route_monitor_put_update_in_pre_msg(buf, end - buf); + bmp_route_monitor_put_update_in_pre_msg(bmp, buf, end - buf); } #endif /* CONFIG_BMP */ @@ -2614,6 +2613,14 @@ bgp_create_mp_end_mark(struct bgp_channel *c, byte *buf) } byte * +bgp_create_end_mark_(struct bgp_channel *c, byte *buf) +{ + return (c->afi == BGP_AF_IPV4) ? + bgp_create_ip_end_mark(c, buf): + bgp_create_mp_end_mark(c, buf); +} + +static byte * bgp_create_end_mark(struct bgp_channel *c, byte *buf) { struct bgp_proto *p = (void *) c->c.proto; @@ -2621,9 +2628,7 @@ bgp_create_end_mark(struct bgp_channel *c, byte *buf) BGP_TRACE(D_PACKETS, "Sending END-OF-RIB"); p->stats.tx_updates++; - return (c->afi == BGP_AF_IPV4) ? - bgp_create_ip_end_mark(c, buf): - bgp_create_mp_end_mark(c, buf); + return bgp_create_end_mark_(c, buf); } static inline void diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 5c261584..aed9d9d6 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -56,8 +56,8 @@ #include "nest/iface.h" #include "nest/route.h" -// We allow for single instance of BMP protocol -static struct bmp_proto *g_bmp; +// List of BMP instances +static list STATIC_LIST_INIT(bmp_proto_list); /* BMP Common Header [RFC 7854 - Section 4.1] */ enum bmp_version { @@ -214,7 +214,7 @@ struct bmp_data_node { }; static void -bmp_route_monitor_pre_policy_table_in_snapshot(struct bgp_channel *c); +bmp_route_monitor_pre_policy_table_in_snapshot(struct bmp_proto *p, struct bgp_channel *c); static void bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size) @@ -447,16 +447,16 @@ bmp_peer_down_notif_msg_serialize(buffer *stream, const bool is_peer_global, bmp_put_data(stream, data, data_size); } -void -bmp_peer_up(const struct bgp_proto *bgp, +static void +bmp_peer_up_(struct bmp_proto *p, const struct bgp_proto *bgp, const byte *tx_open_msg, uint tx_open_length, const byte *rx_open_msg, uint rx_open_length) { - struct bmp_proto *p = g_bmp; - - if (!p || !p->started) + if (!p->started) return; + TRACE(D_STATES, "Peer up for %s", bgp->p.name); + // struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); // bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); @@ -464,11 +464,21 @@ bmp_peer_up(const struct bgp_proto *bgp, struct bgp_channel *c; BGP_WALK_CHANNELS(bgp, c) - bmp_route_monitor_pre_policy_table_in_snapshot(c); + bmp_route_monitor_pre_policy_table_in_snapshot(p, c); +} + +void +bmp_peer_up(const struct bgp_proto *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, tx_open_msg, tx_open_length, rx_open_msg, rx_open_length); } static void -bmp_peer_init(const struct bgp_proto *bgp) +bmp_peer_init(struct bmp_proto *p, const struct bgp_proto *bgp) { struct bgp_conn *conn = bgp->conn; @@ -476,8 +486,8 @@ bmp_peer_init(const struct bgp_proto *bgp) !conn->local_open_msg || !conn->remote_open_msg) return; - bmp_peer_up(bgp, conn->local_open_msg, conn->local_open_length, - conn->remote_open_msg, conn->remote_open_length); + bmp_peer_up_(p, bgp, conn->local_open_msg, conn->local_open_length, + conn->remote_open_msg, conn->remote_open_length); } static const struct birdsock * @@ -569,12 +579,10 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, } -void -bmp_route_monitor_update_in_pre_begin(void) +static void +bmp_route_monitor_update_in_pre_begin_(struct bmp_proto *p) { - struct bmp_proto *p = g_bmp; - - if (!p || !p->started) + if (!p->started) return; if (p->monitoring_rib.in_pre_policy == false) @@ -592,11 +600,17 @@ bmp_route_monitor_update_in_pre_begin(void) } void -bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size) +bmp_route_monitor_update_in_pre_begin(void) { - struct bmp_proto *p = g_bmp; + struct bmp_proto *p; node *n; + WALK_LIST2(p, n, bmp_proto_list, bmp_node) + bmp_route_monitor_update_in_pre_begin_(p); +} - if (!p || !p->started) +void +bmp_route_monitor_put_update_in_pre_msg(struct bmp_proto *p, const byte *data, const size_t data_size) +{ + if (!p->started) return; if (p->monitoring_rib.in_pre_policy == false) @@ -617,11 +631,20 @@ bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size } void -bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) +bmp_route_monitor_update_in_notify(struct channel *C, const net_addr *n, + const struct rte *new, const struct rte_src *src) { - struct bmp_proto *p = g_bmp; + struct bgp_channel *c = (void *) C; - if (!p || !p->started) + struct bmp_proto *p; node *nx; + WALK_LIST2(p, nx, bmp_proto_list, bmp_node) + bgp_bmp_encode_rte(c, p, n, new, src); +} + +static void +bmp_route_monitor_update_in_pre_commit_(struct bmp_proto *p, const struct bgp_proto *bgp) +{ + if (!p->started) return; if (p->monitoring_rib.in_pre_policy == false) @@ -670,11 +693,17 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) } void -bmp_route_monitor_update_in_pre_end(void) +bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) { - struct bmp_proto *p = g_bmp; + struct bmp_proto *p; node *n; + WALK_LIST2(p, n, bmp_proto_list, bmp_node) + bmp_route_monitor_update_in_pre_commit_(p, bgp); +} - if (!p || !p->started) +static void +bmp_route_monitor_update_in_pre_end_(struct bmp_proto *p) +{ + if (!p->started) return; if (p->monitoring_rib.in_pre_policy == false) @@ -692,11 +721,37 @@ bmp_route_monitor_update_in_pre_end(void) p->rt_table_in_pre_policy.update_in_progress = false; } -static void -bmp_route_monitor_pre_policy_table_in_snapshot(struct bgp_channel *c) +void +bmp_route_monitor_update_in_pre_end(void) { - struct bmp_proto *p = g_bmp; + struct bmp_proto *p; node *n; + WALK_LIST2(p, n, bmp_proto_list, bmp_node) + bmp_route_monitor_update_in_pre_end_(p); +} +static void +bmp_route_monitor_end_of_rib_msg(struct bmp_proto *p, struct bgp_channel *c) +{ + struct bgp_proto *bgp = (void *) c->c.proto; + + TRACE(D_PACKETS, "Sending END-OF-RIB for %s.%s", bgp->p.name, c->c.name); + + byte rx_end_payload[DEFAULT_MEM_BLOCK_SIZE]; + byte *pos = bgp_create_end_mark_(c, rx_end_payload + BGP_HEADER_LENGTH); + 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); + + bmp_route_monitor_update_in_pre_begin_(p); + bmp_route_monitor_put_update_in_pre_msg(p, rx_end_payload, pos - rx_end_payload); + bmp_route_monitor_update_in_pre_commit_(p, bgp); + bmp_route_monitor_update_in_pre_end_(p); +} + +static void +bmp_route_monitor_pre_policy_table_in_snapshot(struct bmp_proto *p, struct bgp_channel *c) +{ if (p->monitoring_rib.in_pre_policy == false) return; @@ -713,37 +768,22 @@ bmp_route_monitor_pre_policy_table_in_snapshot(struct bgp_channel *c) { P = n->routes->sender->proto; if (P->proto->class != PROTOCOL_BGP) - { continue; - } - bmp_route_monitor_update_in_pre_begin(); + bmp_route_monitor_update_in_pre_begin_(p); rte *e; for (e = n->routes; e; e = e->next) - { - bgp_rte_update_in_notify(&c->c, n->n.addr, e, e->src); - } + bgp_bmp_encode_rte(c, p, n->n.addr, e, e->src); - bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) P); - bmp_route_monitor_update_in_pre_end(); + bmp_route_monitor_update_in_pre_commit_(p, (struct bgp_proto *) P); + bmp_route_monitor_update_in_pre_end_(p); ++cnt; } FIB_ITERATE_END; if (cnt > 0) - { - bmp_route_monitor_update_in_pre_begin(); - byte rx_end_payload[DEFAULT_MEM_BLOCK_SIZE]; - byte *pos = bgp_create_end_mark(c, rx_end_payload + BGP_HEADER_LENGTH); - 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); - bmp_route_monitor_put_update_in_pre_msg(rx_end_payload, pos - rx_end_payload); - bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) c->c.proto); - bmp_route_monitor_update_in_pre_end(); - } + bmp_route_monitor_end_of_rib_msg(p, c); } static void @@ -765,15 +805,15 @@ bmp_send_peer_down_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, bmp_buffer_free(&payload); } -void -bmp_peer_down(const struct bgp_proto *bgp, const int err_class, - const byte *msg, size_t msg_length) +static void +bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp, + const int err_class, const byte *msg, size_t msg_length) { - struct bmp_proto *p = g_bmp; - - if (!p || !p->started) + if (!p->started) return; + TRACE(D_STATES, "Peer down for %s", bgp->p.name); + // struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); // bmp_peer_map_remove(&p->bgp_peers, key); @@ -809,6 +849,15 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, bmp_buffer_free(&payload); } +void +bmp_peer_down(const struct bgp_proto *bgp, const int err_class, + const byte *msg, size_t msg_length) +{ + struct bmp_proto *p; node *n; + WALK_LIST2(p, n, bmp_proto_list, bmp_node) + bmp_peer_down_(p, bgp, err_class, msg, msg_length); +} + static void bmp_send_termination_msg(struct bmp_proto *p, const enum bmp_term_reason reason) @@ -857,7 +906,7 @@ bmp_startup(struct bmp_proto *p) struct proto *peer; WALK_LIST(peer, proto_list) if ((peer->proto->class == PROTOCOL_BGP) && (peer->proto_state == PS_UP)) - bmp_peer_init((struct bgp_proto *) peer); + bmp_peer_init(p, (struct bgp_proto *) peer); proto_notify_state(&p->p, PS_UP); } @@ -905,6 +954,8 @@ bmp_connect(struct bmp_proto *p) p->sk = sk; sk->data = p; + TRACE(D_EVENTS, "Connecting to %I port %u", sk->daddr, sk->dport); + int rc = sk_open(sk); if (rc < 0) @@ -919,6 +970,8 @@ bmp_connected(struct birdsock *sk) { struct bmp_proto *p = (void *) sk->data; + TRACE(D_EVENTS, "Connected"); + sk->rx_hook = bmp_rx; sk->tx_hook = bmp_tx; tm_stop(p->connect_retry_timer); @@ -1025,11 +1078,10 @@ bmp_start(struct proto *P) init_list(&p->rt_table_in_pre_policy.update_msg_queue); p->started = false; p->sock_err = 0; + add_tail(&bmp_proto_list, &p->bmp_node); tm_start(p->connect_retry_timer, CONNECT_INIT_TIME); - g_bmp = p; - return PS_START; } @@ -1045,7 +1097,7 @@ bmp_shutdown(struct proto *P) } p->sock_err = 0; - g_bmp = NULL; + rem_node(&p->bmp_node); return PS_DOWN; } diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index be28468c..258a5089 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -57,6 +57,7 @@ struct rt_table_info { struct bmp_proto { struct proto p; // Parent proto const struct bmp_config *cf; // Shortcut to BMP configuration + node bmp_node; // Node in bmp_proto_list sock *sk; // TCP connection event *tx_ev; // TX event char sys_descr[MIB_II_STR_LEN]; // sysDescr MIB-II [RFC1213] object @@ -90,20 +91,22 @@ bmp_peer_up(const struct bgp_proto *bgp, const byte *rx_open_msg, uint rx_open_length); /** - * The following 4 functions create BMP Route Monitoring message based on + * The following 5 functions create BMP Route Monitoring message based on * pre-policy Adj-RIB-In. Composing Route Monitoring message consist of few * stages. First of all call bmp_route_monitor_update_in_pre_begin() in order * to start composing message. As a second step, call - * bmp_route_monitor_put_update_in_pre_msg() in order to save BGP UPDATE msg. - * As a third step call bmp_route_monitor_update_in_pre_commit() in order to - * send BMP Route Monitoring message to the BMP collector. As a last step, + * bmp_route_monitor_update_in_notify() to announce each rte, which internally + * calls bmp_route_monitor_put_update_in_pre_msg() in order to save BGP UPDATE + * msg. As a third step call bmp_route_monitor_update_in_pre_commit() in order + * to send BMP Route Monitoring message to the BMP collector. As a last step, * call bmp_route_monitor_update_in_pre_end() in order to release resources. */ void bmp_route_monitor_update_in_pre_begin(void); void -bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size); +bmp_route_monitor_update_in_notify(struct channel *C, const net_addr *n, + const struct rte *new, const struct rte_src *src); void bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp); @@ -111,6 +114,9 @@ bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp); void bmp_route_monitor_update_in_pre_end(void); +void +bmp_route_monitor_put_update_in_pre_msg(struct bmp_proto *p, const byte *data, const size_t data_size); + /** * bmp_peer_down - send notification that BGP peer connection is not in * established state @@ -124,7 +130,6 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, static inline void bmp_peer_up(const struct bgp_proto *bgp UNUSED, const byte *tx_open_msg UNUSED, uint tx_open_length UNUSED, const byte *rx_open_msg UNUSED, uint rx_open_length UNUSED) { } static inline void bmp_route_monitor_update_in_pre_begin(void) { } -static inline void bmp_route_monitor_put_update_in_pre_msg(const byte *data UNUSED, const size_t data_size UNUSED) { } static inline void bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp UNUSED) { } static inline void bmp_route_monitor_update_in_pre_end(void) { } static inline void bmp_peer_down(const struct bgp_proto *bgp UNUSED, const int err_class UNUSED, const byte *pkt UNUSED, size_t pkt_size UNUSED) { } From 43d41d8449a4eb196422d6d309dbea998d920541 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 8 Jun 2023 05:10:05 +0200 Subject: [PATCH 10/17] BMP: Ensure that bmp_fire_tx() does nothing when not up --- proto/bmp/bmp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index aed9d9d6..c530b3d4 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -273,7 +273,10 @@ static void bmp_fire_tx(void *p_) { struct bmp_proto *p = p_; - byte *buf = p->sk->tbuf; + + if (!p->started) + return; + IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( EMPTY_LIST(p->tx_queue), "Called BMP TX event handler when there is not any data to send" @@ -290,7 +293,7 @@ bmp_fire_tx(void *p_) } size_t data_size = tx_data->data_size; - memcpy(buf, tx_data->data, tx_data->data_size); + memcpy(p->sk->tbuf, tx_data->data, data_size); mb_free(tx_data->data); rem_node((node *) tx_data); mb_free(tx_data); From 8ded8baba2a95cec81f20b10160c81d229f8fae8 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 1 Aug 2023 17:56:56 +0200 Subject: [PATCH 11/17] BMP: Simplify route monitoring hooks No need for *_begin(), *_commit(), and *_end() hooks. The hook *_notify() is sufficient for everything. --- proto/bgp/bgp.h | 3 +- proto/bgp/packets.c | 19 ++--- proto/bmp/bmp.c | 185 +++++++++++++++----------------------------- proto/bmp/bmp.h | 37 +-------- 4 files changed, 74 insertions(+), 170 deletions(-) diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 861f831a..324df43c 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -635,8 +635,7 @@ int bgp_get_attr(const struct eattr *e, byte *buf, int buflen); void bgp_get_route_info(struct rte *, byte *buf); int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad); -struct bmp_proto; -void bgp_bmp_encode_rte(struct bgp_channel *c, struct bmp_proto *bmp, const net_addr *n, const struct rte *new, const struct rte_src *src); +byte * bgp_bmp_encode_rte(struct bgp_channel *c, byte *buf, const net_addr *n, const struct rte *new, const struct rte_src *src); #define BGP_AIGP_METRIC 1 #define BGP_AIGP_MAX U64(0xffffffffffffffff) diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 0338a887..2f1ff659 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2472,13 +2472,11 @@ bgp_bmp_prepare_bgp_hdr(byte *buf, const u16 msg_size, const u8 msg_type) return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE; } -void -bgp_bmp_encode_rte(struct bgp_channel *c, struct bmp_proto *bmp, const net_addr *n, +byte * +bgp_bmp_encode_rte(struct bgp_channel *c, byte *buf, const net_addr *n, const struct rte *new, const struct rte_src *src) { // struct bgp_proto *p = (void *) c->c.proto; - - byte buf[BGP_MAX_EXT_MSG_LENGTH]; byte *pkt = buf + BGP_HEADER_LENGTH; ea_list *attrs = new ? new->attrs->eattrs : NULL; @@ -2502,11 +2500,11 @@ bgp_bmp_encode_rte(struct bgp_channel *c, struct bmp_proto *bmp, const net_addr add_tail(&b->prefixes, &px->buck_node); byte *end = bgp_create_update_bmp(c, pkt, b, !!new); - if (!end) - return; - bgp_bmp_prepare_bgp_hdr(buf, end - buf, PKT_UPDATE); - bmp_route_monitor_put_update_in_pre_msg(bmp, buf, end - buf); + if (end) + bgp_bmp_prepare_bgp_hdr(buf, end - buf, PKT_UPDATE); + + return end; } #endif /* CONFIG_BMP */ @@ -2769,8 +2767,6 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) s.ip_reach_len = len - pos; s.ip_reach_nlri = pkt + pos; - bmp_route_monitor_update_in_pre_begin(); - if (s.attr_len) ea = bgp_decode_attrs(&s, s.attrs, s.attr_len); else @@ -2801,9 +2797,6 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) bgp_decode_nlri(&s, s.mp_reach_af, s.mp_reach_nlri, s.mp_reach_len, ea, s.mp_next_hop_data, s.mp_next_hop_len); - bmp_route_monitor_update_in_pre_commit(p); - bmp_route_monitor_update_in_pre_end(); - done: rta_free(s.cached_rta); lp_restore(tmp_linpool, &tmpp); diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index c530b3d4..1916563a 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -211,6 +211,12 @@ struct bmp_data_node { node n; byte *data; size_t data_size; + + u32 remote_as; + u32 remote_id; + ip_addr remote_ip; + btime timestamp; + bool global_peer; }; static void @@ -401,9 +407,12 @@ static void bmp_route_monitor_msg_serialize(buffer *stream, const bool is_peer_global, const bool table_in_pre_policy, const u32 peer_as, const u32 peer_bgp_id, const bool as4_support, const ip_addr remote_addr, const byte *update_msg, - const size_t update_msg_size, u32 ts_sec, u32 ts_usec) + const size_t update_msg_size, btime timestamp) { const size_t data_size = BMP_PER_PEER_HDR_SIZE + update_msg_size; + u32 ts_sec = timestamp TO_S; + u32 ts_usec = timestamp - (ts_sec S); + bmp_buffer_need(stream, BMP_COMMON_HDR_SIZE + data_size); bmp_common_hdr_serialize(stream, BMP_ROUTE_MONITOR, data_size); bmp_per_peer_hdr_serialize(stream, is_peer_global, table_in_pre_policy, @@ -581,56 +590,43 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, bmp_buffer_free(&payload); } - static void -bmp_route_monitor_update_in_pre_begin_(struct bmp_proto *p) +bmp_route_monitor_put_update(struct bmp_proto *p, const byte *data, size_t length, struct bgp_proto *bgp) { - if (!p->started) - return; - - if (p->monitoring_rib.in_pre_policy == false) - return; - - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue), - "Previous BMP route monitoring update not finished yet" - ); - - gettimeofday(&p->rt_table_in_pre_policy.update_begin_time,NULL); - init_list(&p->rt_table_in_pre_policy.update_msg_queue); - p->rt_table_in_pre_policy.update_msg_size = 0; - p->rt_table_in_pre_policy.update_in_progress = true; -} - -void -bmp_route_monitor_update_in_pre_begin(void) -{ - struct bmp_proto *p; node *n; - WALK_LIST2(p, n, bmp_proto_list, bmp_node) - bmp_route_monitor_update_in_pre_begin_(p); -} - -void -bmp_route_monitor_put_update_in_pre_msg(struct bmp_proto *p, const byte *data, const size_t data_size) -{ - if (!p->started) - return; - - if (p->monitoring_rib.in_pre_policy == false) - return; - - IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - !p->rt_table_in_pre_policy.update_in_progress, - "BMP route monitoring update not started yet" - ); - 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, data_size); - memcpy(upd_msg->data, data, data_size); - upd_msg->data_size = data_size; - p->rt_table_in_pre_policy.update_msg_size += data_size; - add_tail(&p->rt_table_in_pre_policy.update_msg_queue, &upd_msg->n); + 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 */ + upd_msg->remote_as = bgp->remote_as; + upd_msg->remote_id = bgp->remote_id; + upd_msg->remote_ip = bgp->remote_ip; + upd_msg->timestamp = current_time(); + upd_msg->global_peer = bmp_is_peer_global_instance(bgp); + + /* Kick the commit */ + if (!ev_active(p->update_ev)) + ev_schedule(p->update_ev); +} + +static void +bmp_route_monitor_update_in_notify_(struct bmp_proto *p, struct bgp_channel *c, + const net_addr *n, const struct rte *new, const struct rte_src *src) +{ + struct bgp_proto *bgp = (void *) c->c.proto; + + if (!p->started) + return; + + if (p->monitoring_rib.in_pre_policy == false) + return; + + byte buf[BGP_MAX_EXT_MSG_LENGTH]; + byte *end = bgp_bmp_encode_rte(c, buf, n, new, src); + bmp_route_monitor_put_update(p, buf, end - buf, bgp); } void @@ -641,97 +637,50 @@ bmp_route_monitor_update_in_notify(struct channel *C, const net_addr *n, struct bmp_proto *p; node *nx; WALK_LIST2(p, nx, bmp_proto_list, bmp_node) - bgp_bmp_encode_rte(c, p, n, new, src); + bmp_route_monitor_update_in_notify_(p, c, n, new, src); } static void -bmp_route_monitor_update_in_pre_commit_(struct bmp_proto *p, const struct bgp_proto *bgp) +bmp_route_monitor_commit(void *p_) { + struct bmp_proto *p = p_; + if (!p->started) return; if (p->monitoring_rib.in_pre_policy == false) return; - const struct birdsock *sk = bmp_get_birdsock(bgp); - IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - sk, - "Failed to get bird socket from BGP proto" - ); - - const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps(bgp); - IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL( - remote_caps, - "Failed to get remote capabilities from BGP proto" - ); - - bool is_global_instance_peer = bmp_is_peer_global_instance(bgp); buffer payload - = bmp_buffer_alloc(p->buffer_mpool, - p->rt_table_in_pre_policy.update_msg_size + DEFAULT_MEM_BLOCK_SIZE); + = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); buffer update_msgs - = bmp_buffer_alloc(p->buffer_mpool, - p->rt_table_in_pre_policy.update_msg_size); + = bmp_buffer_alloc(p->buffer_mpool, BGP_MAX_EXT_MSG_LENGTH); - struct bmp_data_node *data; - WALK_LIST(data, p->rt_table_in_pre_policy.update_msg_queue) + struct bmp_data_node *data, *data_next; + WALK_LIST_DELSAFE(data, data_next, p->update_msg_queue) { bmp_put_data(&update_msgs, data->data, data->data_size); bmp_route_monitor_msg_serialize(&payload, - is_global_instance_peer, true /* TODO: Hardcoded pre-policy Adj-Rib-In */, - bgp->conn->received_as, bgp->remote_id, remote_caps->as4_support, - sk->daddr, bmp_buffer_data(&update_msgs), bmp_buffer_pos(&update_msgs), - p->rt_table_in_pre_policy.update_begin_time.tv_sec, - p->rt_table_in_pre_policy.update_begin_time.tv_usec); + data->global_peer, true /* TODO: Hardcoded pre-policy Adj-Rib-In */, + data->remote_as, data->remote_id, true, + data->remote_ip, bmp_buffer_data(&update_msgs), bmp_buffer_pos(&update_msgs), + data->timestamp); bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_flush(&payload); bmp_buffer_flush(&update_msgs); + + mb_free(data->data); + rem_node(&data->n); + mb_free(data); } bmp_buffer_free(&payload); bmp_buffer_free(&update_msgs); } -void -bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp) -{ - struct bmp_proto *p; node *n; - WALK_LIST2(p, n, bmp_proto_list, bmp_node) - bmp_route_monitor_update_in_pre_commit_(p, bgp); -} - -static void -bmp_route_monitor_update_in_pre_end_(struct bmp_proto *p) -{ - if (!p->started) - return; - - if (p->monitoring_rib.in_pre_policy == false) - return; - - struct bmp_data_node *upd_msg; - struct bmp_data_node *upd_msg_next; - WALK_LIST_DELSAFE(upd_msg, upd_msg_next, p->rt_table_in_pre_policy.update_msg_queue) - { - mb_free(upd_msg->data); - rem_node((node *) upd_msg); - mb_free(upd_msg); - } - - p->rt_table_in_pre_policy.update_in_progress = false; -} - -void -bmp_route_monitor_update_in_pre_end(void) -{ - struct bmp_proto *p; node *n; - WALK_LIST2(p, n, bmp_proto_list, bmp_node) - bmp_route_monitor_update_in_pre_end_(p); -} - static void bmp_route_monitor_end_of_rib_msg(struct bmp_proto *p, struct bgp_channel *c) { @@ -746,10 +695,7 @@ bmp_route_monitor_end_of_rib_msg(struct bmp_proto *p, struct bgp_channel *c) 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); - bmp_route_monitor_update_in_pre_begin_(p); - bmp_route_monitor_put_update_in_pre_msg(p, rx_end_payload, pos - rx_end_payload); - bmp_route_monitor_update_in_pre_commit_(p, bgp); - bmp_route_monitor_update_in_pre_end_(p); + bmp_route_monitor_put_update(p, rx_end_payload, pos - rx_end_payload, bgp); } static void @@ -773,14 +719,10 @@ bmp_route_monitor_pre_policy_table_in_snapshot(struct bmp_proto *p, struct bgp_c if (P->proto->class != PROTOCOL_BGP) continue; - bmp_route_monitor_update_in_pre_begin_(p); - rte *e; for (e = n->routes; e; e = e->next) - bgp_bmp_encode_rte(c, p, n->n.addr, e, e->src); + bmp_route_monitor_update_in_notify_(p, c, n->n.addr, e, e->src); - bmp_route_monitor_update_in_pre_commit_(p, (struct bgp_proto *) P); - bmp_route_monitor_update_in_pre_end_(p); ++cnt; } FIB_ITERATE_END; @@ -1071,14 +1013,15 @@ bmp_start(struct proto *P) p->map_mem_pool = rp_new(P->pool, "BMP Map"); p->tx_mem_pool = rp_new(P->pool, "BMP Tx"); p->update_msg_mem_pool = rp_new(P->pool, "BMP Update"); - p->tx_ev = ev_new_init(p->tx_mem_pool, bmp_fire_tx, p); + 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); p->connect_retry_timer = tm_new_init(p->p.pool, bmp_connection_retry, p, 0, 0); p->sk = NULL; // bmp_peer_map_init(&p->bgp_peers, p->map_mem_pool); init_list(&p->tx_queue); - init_list(&p->rt_table_in_pre_policy.update_msg_queue); + init_list(&p->update_msg_queue); p->started = false; p->sock_err = 0; add_tail(&bmp_proto_list, &p->bmp_node); diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 258a5089..0c355754 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -45,21 +45,13 @@ struct bmp_config { struct bgp_proto; struct bmp_proto; -// Keeps necessary information during composing BGP UPDATE MSG which is going -// to be sent to the BMP collector -struct rt_table_info { - list update_msg_queue; // Stores all composed BGP UPDATE MSGs - size_t update_msg_size; // Size of all BGP UPDATE MSGs - struct timeval update_begin_time; // Keeps timestamp of starting BGP UPDATE MSGs composing - bool update_in_progress; // Holds information whether composing process is still in progress -}; - struct bmp_proto { struct proto p; // Parent proto const struct bmp_config *cf; // Shortcut to BMP configuration node bmp_node; // Node in bmp_proto_list sock *sk; // TCP connection event *tx_ev; // TX event + event *update_ev; // Update event char sys_descr[MIB_II_STR_LEN]; // sysDescr MIB-II [RFC1213] object char sys_name[MIB_II_STR_LEN]; // sysName MIB-II [RFC1213] object ip_addr local_addr; // Source local IP address @@ -74,7 +66,7 @@ struct bmp_proto { pool *update_msg_mem_pool; // Memory pool used for BPG UPDATE MSG allocations list tx_queue; // Stores queued packets going to be sent timer *connect_retry_timer; // Timer for retrying connection to the BMP collector - struct rt_table_info rt_table_in_pre_policy; // Pre-policy route import table + list update_msg_queue; // Stores all composed BGP UPDATE MSGs bool started; // Flag that stores running status of BMP instance int sock_err; // Last socket error code }; @@ -91,32 +83,12 @@ bmp_peer_up(const struct bgp_proto *bgp, const byte *rx_open_msg, uint rx_open_length); /** - * The following 5 functions create BMP Route Monitoring message based on - * pre-policy Adj-RIB-In. Composing Route Monitoring message consist of few - * stages. First of all call bmp_route_monitor_update_in_pre_begin() in order - * to start composing message. As a second step, call - * bmp_route_monitor_update_in_notify() to announce each rte, which internally - * calls bmp_route_monitor_put_update_in_pre_msg() in order to save BGP UPDATE - * msg. As a third step call bmp_route_monitor_update_in_pre_commit() in order - * to send BMP Route Monitoring message to the BMP collector. As a last step, - * call bmp_route_monitor_update_in_pre_end() in order to release resources. + * bmp_route_monitor_update_in_notify - send notification that rte vas received */ -void -bmp_route_monitor_update_in_pre_begin(void); - void bmp_route_monitor_update_in_notify(struct channel *C, const net_addr *n, const struct rte *new, const struct rte_src *src); -void -bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp); - -void -bmp_route_monitor_update_in_pre_end(void); - -void -bmp_route_monitor_put_update_in_pre_msg(struct bmp_proto *p, const byte *data, const size_t data_size); - /** * bmp_peer_down - send notification that BGP peer connection is not in * established state @@ -129,9 +101,6 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, #else /* BMP build disabled */ static inline void bmp_peer_up(const struct bgp_proto *bgp UNUSED, const byte *tx_open_msg UNUSED, uint tx_open_length UNUSED, const byte *rx_open_msg UNUSED, uint rx_open_length UNUSED) { } -static inline void bmp_route_monitor_update_in_pre_begin(void) { } -static inline void bmp_route_monitor_update_in_pre_commit(const struct bgp_proto *bgp UNUSED) { } -static inline void bmp_route_monitor_update_in_pre_end(void) { } static inline void bmp_peer_down(const struct bgp_proto *bgp UNUSED, const int err_class UNUSED, const byte *pkt UNUSED, size_t pkt_size UNUSED) { } #endif /* CONFIG_BMP */ From aec21cda249f9460d63c14ca83a9fa4210bcc20d Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 1 Aug 2023 18:39:38 +0200 Subject: [PATCH 12/17] BMP: Remove useless buffer --- proto/bmp/bmp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 1916563a..f8899863 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -654,23 +654,18 @@ bmp_route_monitor_commit(void *p_) buffer payload = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); - buffer update_msgs - = bmp_buffer_alloc(p->buffer_mpool, BGP_MAX_EXT_MSG_LENGTH); - struct bmp_data_node *data, *data_next; WALK_LIST_DELSAFE(data, data_next, p->update_msg_queue) { - bmp_put_data(&update_msgs, data->data, data->data_size); bmp_route_monitor_msg_serialize(&payload, data->global_peer, true /* TODO: Hardcoded pre-policy Adj-Rib-In */, data->remote_as, data->remote_id, true, - data->remote_ip, bmp_buffer_data(&update_msgs), bmp_buffer_pos(&update_msgs), + data->remote_ip, data->data, data->data_size, data->timestamp); bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_flush(&payload); - bmp_buffer_flush(&update_msgs); mb_free(data->data); rem_node(&data->n); @@ -678,7 +673,6 @@ bmp_route_monitor_commit(void *p_) } bmp_buffer_free(&payload); - bmp_buffer_free(&update_msgs); } static void From f4deef89bebae6e41654217e20f2a7531c65bf49 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 18 Aug 2023 03:53:58 +0200 Subject: [PATCH 13/17] BMP: Refactor route monitoring - Manage BMP state through bmp_peer, bmp_stream, bmp_table structures - Use channels and rt_notify() hook for route announcements - Add support for post-policy monitoring - Send End-of-RIB even when there is no routes - Remove rte_update_in_notify() hook from import tables - Update import tables to support channels - Add bmp_hack (no feed / no flush) flag to channels --- nest/proto.c | 11 +- nest/protocol.h | 7 +- nest/rt-table.c | 69 +++++---- proto/bgp/bgp.c | 6 +- proto/bmp/bmp.c | 362 +++++++++++++++++++++++++++++++++++---------- proto/bmp/bmp.h | 37 ++++- proto/bmp/config.Y | 4 +- 7 files changed, 366 insertions(+), 130 deletions(-) diff --git a/nest/proto.c b/nest/proto.c index 885a0b75..16245dca 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -179,6 +179,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf) c->merge_limit = cf->merge_limit; c->in_keep_filtered = cf->in_keep_filtered; c->rpki_reload = cf->rpki_reload; + c->bmp_hack = cf->bmp_hack; c->channel_state = CS_DOWN; c->export_state = ES_DOWN; @@ -450,7 +451,10 @@ channel_start_export(struct channel *c) ASSERT(c->channel_state == CS_UP); ASSERT(c->export_state == ES_DOWN); - channel_schedule_feed(c, 1); /* Sets ES_FEEDING */ + if (!c->bmp_hack) + channel_schedule_feed(c, 1); /* Sets ES_FEEDING */ + else + c->export_state = ES_READY; } static void @@ -523,7 +527,7 @@ channel_setup_in_table(struct channel *c) cf->addr_type = c->net_type; cf->internal = 1; - c->in_table = rt_setup(c->proto->pool, cf); + c->in_table = cf->table = rt_setup(c->proto->pool, cf); c->reload_event = ev_new_init(c->proto->pool, channel_reload_loop, c); } @@ -574,7 +578,8 @@ channel_do_up(struct channel *c) static void channel_do_flush(struct channel *c) { - rt_schedule_prune(c->table); + if (!c->bmp_hack) + rt_schedule_prune(c->table); c->gr_wait = 0; if (c->gr_lock) diff --git a/nest/protocol.h b/nest/protocol.h index da6d434e..d94a11bc 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -214,7 +214,6 @@ struct proto { void (*if_notify)(struct proto *, unsigned flags, struct iface *i); void (*ifa_notify)(struct proto *, unsigned flags, struct ifa *a); void (*rt_notify)(struct proto *, struct channel *, struct network *net, struct rte *new, struct rte *old); - void (*rte_update_in_notify)(struct channel *, const net_addr *, const struct rte *, const struct rte_src *); void (*neigh_notify)(struct neighbor *neigh); int (*preexport)(struct channel *, struct rte *rt); void (*reload_routes)(struct channel *); @@ -477,7 +476,8 @@ struct channel_class { #endif }; -extern struct channel_class channel_bgp; +extern const struct channel_class channel_basic; +extern const struct channel_class channel_bgp; struct channel_config { node n; @@ -500,6 +500,7 @@ struct channel_config { u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */ u8 in_keep_filtered; /* Routes rejected in import filter are kept */ u8 rpki_reload; /* RPKI changes trigger channel reload */ + u8 bmp_hack; /* No feed, no flush */ }; struct channel { @@ -552,6 +553,7 @@ struct channel { u8 reload_pending; /* Reloading and another reload is scheduled */ u8 refeed_pending; /* Refeeding and another refeed is scheduled */ u8 rpki_reload; /* RPKI changes trigger channel reload */ + u8 bmp_hack; /* No feed, no flush */ struct rtable *out_table; /* Internal table for exported routes */ @@ -620,6 +622,7 @@ static inline struct channel_config *proto_cf_main_channel(struct proto_config * struct channel *proto_find_channel_by_table(struct proto *p, struct rtable *t); struct channel *proto_find_channel_by_name(struct proto *p, const char *n); struct channel *proto_add_channel(struct proto *p, struct channel_config *cf); +void proto_remove_channel(struct proto *p, struct channel *c); int proto_configure_channel(struct proto *p, struct channel **c, struct channel_config *cf); void channel_set_state(struct channel *c, uint state); diff --git a/nest/rt-table.c b/nest/rt-table.c index 2b065032..e8478c36 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -3063,6 +3063,23 @@ rt_feed_channel_abort(struct channel *c) * Import table */ +static void +rte_announce_in(struct rtable *tab, struct network *net, struct rte *new, struct rte *old) +{ + struct channel *c; node *n; + WALK_LIST2(c, n, tab->channels, table_node) + { + if (c->export_state == ES_DOWN) + continue; + + if (c->ra_mode != RA_ANY) + continue; + + struct proto *p = c->proto; + p->rt_notify(p, c, net, new, old); + } +} + int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) { @@ -3096,9 +3113,6 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr { old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY); - if (c->proto->rte_update_in_notify) - c->proto->rte_update_in_notify(c, n, old, src); - return 1; } @@ -3111,28 +3125,15 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr /* Remove the old rte */ *pos = old->next; - rte_free_quick(old); tab->rt_count--; - break; } - if (!new) - { - if (!old) - goto drop_withdraw; - - if (!net->routes) - fib_delete(&tab->fib, net); - - if (c->proto->rte_update_in_notify) - c->proto->rte_update_in_notify(c, n, NULL, src); - - return 1; - } + if (!old && !new) + goto drop_withdraw; struct channel_limit *l = &c->rx_limit; - if (l->action && !old) + if (l->action && !old && new) { if (tab->rt_count >= l->limit) channel_notify_limit(c, l, PLD_RX, tab->rt_count); @@ -3147,18 +3148,26 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr } } - /* Insert the new rte */ - rte *e = rte_do_cow(new); - e->flags |= REF_COW; - e->net = net; - e->sender = c; - e->lastmod = current_time(); - e->next = *pos; - *pos = e; - tab->rt_count++; + if (new) + { + /* Insert the new rte */ + rte *e = rte_do_cow(new); + e->flags |= REF_COW; + e->net = net; + e->sender = c; + e->lastmod = current_time(); + e->next = *pos; + *pos = new = e; + tab->rt_count++; + } - if (c->proto->rte_update_in_notify) - c->proto->rte_update_in_notify(c, n, e, src); + rte_announce_in(tab, net, new, old); + + if (old) + rte_free_quick(old); + + if (!net->routes) + fib_delete(&tab->fib, net); return 1; diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 54da2253..ccaa5067 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1714,10 +1714,6 @@ bgp_init(struct proto_config *CF) P->rte_modify = bgp_rte_modify_stale; P->rte_igp_metric = bgp_rte_igp_metric; -#ifdef CONFIG_BMP - P->rte_update_in_notify = bmp_route_monitor_update_in_notify; -#endif - p->cf = cf; p->is_internal = (cf->local_as == cf->remote_as); p->is_interior = p->is_internal || cf->confederation_member; @@ -2643,7 +2639,7 @@ bgp_show_proto_info(struct proto *P) } } -struct channel_class channel_bgp = { +const struct channel_class channel_bgp = { .channel_size = sizeof(struct bgp_channel), .config_size = sizeof(struct bgp_channel_config), .init = bgp_channel_init, diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index f8899863..ec1614f5 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -59,6 +59,23 @@ // List of BMP instances static list STATIC_LIST_INIT(bmp_proto_list); +#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) + /* BMP Common Header [RFC 7854 - Section 4.1] */ enum bmp_version { BMP_VER_UNUSED = 0, // Version 0 is reserved and MUST NOT be sent @@ -217,10 +234,11 @@ struct bmp_data_node { ip_addr remote_ip; btime timestamp; bool global_peer; + bool policy; }; static void -bmp_route_monitor_pre_policy_table_in_snapshot(struct bmp_proto *p, struct bgp_channel *c); +bmp_route_monitor_snapshot(struct bmp_proto *p, struct bmp_stream *bs); static void bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size) @@ -359,7 +377,7 @@ bmp_put_bgp_hdr(buffer *stream, const u8 msg_type, const u16 msg_length) /** * bmp_per_peer_hdr_serialize - serializes Per-Peer Header * - * @is_pre_policy: indicate the message reflects the pre-policy Adj-RIB-In + * @is_post_policy: indicate the message reflects the post-policy Adj-RIB-In * @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 @@ -368,7 +386,7 @@ bmp_put_bgp_hdr(buffer *stream, const u8 msg_type, const u16 msg_length) */ static void bmp_per_peer_hdr_serialize(buffer *stream, const bool is_global_instance_peer, - const bool is_pre_policy, const bool is_as_path_4bytes, + const bool is_post_policy, const bool is_as_path_4bytes, const ip_addr peer_addr, const u32 peer_as, const u32 peer_bgp_id, const u32 ts_sec, const u32 ts_usec) { @@ -379,9 +397,9 @@ bmp_per_peer_hdr_serialize(buffer *stream, const bool is_global_instance_peer, const u8 peer_flag_v = ipa_is_ip4(peer_addr) ? BMP_PEER_HDR_FLAG_V_IP4 : BMP_PEER_HDR_FLAG_V_IP6; - const u8 peer_flag_l = is_pre_policy - ? BMP_PEER_HDR_FLAG_L_PRE_POLICY_ADJ_RIB_IN - : BMP_PEER_HDR_FLAG_L_POST_POLICY_ADJ_RIB_IN; + 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; 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; @@ -405,7 +423,7 @@ bmp_per_peer_hdr_serialize(buffer *stream, const bool is_global_instance_peer, /* [4.6] Route Monitoring */ static void bmp_route_monitor_msg_serialize(buffer *stream, const bool is_peer_global, - const bool table_in_pre_policy, const u32 peer_as, const u32 peer_bgp_id, + const bool table_in_post_policy, const u32 peer_as, const u32 peer_bgp_id, const bool as4_support, const ip_addr remote_addr, const byte *update_msg, const size_t update_msg_size, btime timestamp) { @@ -415,7 +433,7 @@ bmp_route_monitor_msg_serialize(buffer *stream, const bool is_peer_global, bmp_buffer_need(stream, BMP_COMMON_HDR_SIZE + data_size); bmp_common_hdr_serialize(stream, BMP_ROUTE_MONITOR, data_size); - bmp_per_peer_hdr_serialize(stream, is_peer_global, table_in_pre_policy, + bmp_per_peer_hdr_serialize(stream, is_peer_global, table_in_post_policy, as4_support, remote_addr, peer_as, peer_bgp_id, ts_sec, ts_usec); bmp_put_data(stream, update_msg, update_msg_size); } @@ -434,7 +452,7 @@ bmp_peer_up_notif_msg_serialize(buffer *stream, const bool is_peer_global, 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, - true /* TODO: Hardcoded pre-policy Adj-RIB-In */, as4_support, remote_addr, + false /* TODO: Hardcoded pre-policy Adj-RIB-In */, as4_support, remote_addr, peer_as, peer_bgp_id, 0, 0); // 0, 0 - No timestamp provided bmp_put_ipa(stream, local_addr); bmp_put_u16(stream, local_port); @@ -454,33 +472,192 @@ bmp_peer_down_notif_msg_serialize(buffer *stream, const bool is_peer_global, 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, - true /* TODO: Hardcoded pre-policy adj RIB IN */, as4_support, remote_addr, + false /* TODO: Hardcoded pre-policy adj RIB IN */, as4_support, remote_addr, peer_as, peer_bgp_id, 0, 0); // 0, 0 - No timestamp provided bmp_put_data(stream, data, data_size); } + +/* + * BMP tables + */ + +static struct bmp_table * +bmp_find_table(struct bmp_proto *p, struct rtable *tab) +{ + return HASH_FIND(p->table_map, HASH_TABLE, tab); +} + +static struct bmp_table * +bmp_add_table(struct bmp_proto *p, struct rtable *tab) +{ + 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", + .channel = &channel_basic, + .table = tab->config, + .in_filter = FILTER_REJECT, + .net_type = tab->addr_type, + .ra_mode = RA_ANY, + .bmp_hack = 1, + }; + + bt->channel = proto_add_channel(&p->p, &cc); + channel_set_state(bt->channel, CS_UP); + + return bt; +} + static void -bmp_peer_up_(struct bmp_proto *p, const struct bgp_proto *bgp, +bmp_remove_table(struct bmp_proto *p, struct bmp_table *bt) +{ + channel_set_state(bt->channel, CS_FLUSHING); + 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); +} + +static inline struct bmp_table *bmp_get_table(struct bmp_proto *p, struct rtable *tab) +{ 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 * +bmp_find_stream(struct bmp_proto *p, const struct bgp_proto *bgp, u32 afi, bool policy) +{ + return HASH_FIND(p->stream_map, HASH_STREAM, bgp, bmp_stream_key(afi, policy)); +} + +static struct bmp_stream * +bmp_add_stream(struct bmp_proto *p, struct bmp_peer *bp, u32 afi, bool policy, struct rtable *tab, struct bgp_channel *sender) +{ + 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; + + 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 * +bmp_find_peer(struct bmp_proto *p, const struct bgp_proto *bgp) +{ + return HASH_FIND(p->peer_map, HASH_PEER, bgp); +} + +static struct bmp_peer * +bmp_add_peer(struct bmp_proto *p, struct bgp_proto *bgp) +{ + struct bmp_peer *bp = mb_allocz(p->p.pool, sizeof(struct bmp_peer)); + bp->bgp = bgp; + + init_list(&bp->streams); + + HASH_INSERT(p->peer_map, HASH_PEER, bp); + + struct bgp_channel *c; + BGP_WALK_CHANNELS(bgp, c) + { + if (p->monitoring_rib.in_pre_policy && c->c.in_table) + bmp_add_stream(p, bp, c->afi, false, c->c.in_table, c); + + if (p->monitoring_rib.in_post_policy && c->c.table) + bmp_add_stream(p, bp, c->afi, true, c->c.table, c); + } + + 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 +bmp_peer_up_(struct bmp_proto *p, struct bgp_proto *bgp, const byte *tx_open_msg, uint tx_open_length, const byte *rx_open_msg, uint rx_open_length) { if (!p->started) return; + struct bmp_peer *bp = bmp_find_peer(p, bgp); + if (bp) + return; + TRACE(D_STATES, "Peer up for %s", bgp->p.name); - // struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - // bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp)); + bp = bmp_add_peer(p, bgp); bmp_send_peer_up_notif_msg(p, bgp, tx_open_msg, tx_open_length, rx_open_msg, rx_open_length); - struct bgp_channel *c; - BGP_WALK_CHANNELS(bgp, c) - bmp_route_monitor_pre_policy_table_in_snapshot(p, c); + struct bmp_stream *bs; + WALK_LIST(bs, bp->streams) + bmp_route_monitor_snapshot(p, bs); } void -bmp_peer_up(const struct bgp_proto *bgp, +bmp_peer_up(struct bgp_proto *bgp, const byte *tx_open_msg, uint tx_open_length, const byte *rx_open_msg, uint rx_open_length) { @@ -490,7 +667,7 @@ bmp_peer_up(const struct bgp_proto *bgp, } static void -bmp_peer_init(struct bmp_proto *p, const struct bgp_proto *bgp) +bmp_peer_init(struct bmp_proto *p, struct bgp_proto *bgp) { struct bgp_conn *conn = bgp->conn; @@ -502,6 +679,8 @@ bmp_peer_init(struct bmp_proto *p, const struct bgp_proto *bgp) conn->remote_open_msg, conn->remote_open_length); } + + static const struct birdsock * bmp_get_birdsock(const struct bgp_proto *bgp) { @@ -591,7 +770,7 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, } static void -bmp_route_monitor_put_update(struct bmp_proto *p, const byte *data, size_t length, struct bgp_proto *bgp) +bmp_route_monitor_put_update(struct bmp_proto *p, struct bmp_stream *bs, const byte *data, size_t length) { struct bmp_data_node *upd_msg = mb_alloc(p->update_msg_mem_pool, sizeof (struct bmp_data_node)); @@ -601,11 +780,13 @@ bmp_route_monitor_put_update(struct bmp_proto *p, const byte *data, size_t lengt add_tail(&p->update_msg_queue, &upd_msg->n); /* Save some metadata */ + struct bgp_proto *bgp = bs->bgp; upd_msg->remote_as = bgp->remote_as; upd_msg->remote_id = bgp->remote_id; upd_msg->remote_ip = bgp->remote_ip; upd_msg->timestamp = current_time(); upd_msg->global_peer = bmp_is_peer_global_instance(bgp); + upd_msg->policy = bmp_stream_policy(bs); /* Kick the commit */ if (!ev_active(p->update_ev)) @@ -613,31 +794,16 @@ bmp_route_monitor_put_update(struct bmp_proto *p, const byte *data, size_t lengt } static void -bmp_route_monitor_update_in_notify_(struct bmp_proto *p, struct bgp_channel *c, - const net_addr *n, const struct rte *new, const struct rte_src *src) +bmp_route_monitor_notify(struct bmp_proto *p, struct bmp_stream *bs, + const net_addr *n, const struct rte *new, const struct rte_src *src) { - struct bgp_proto *bgp = (void *) c->c.proto; - - if (!p->started) - return; - - if (p->monitoring_rib.in_pre_policy == false) - return; - byte buf[BGP_MAX_EXT_MSG_LENGTH]; - byte *end = bgp_bmp_encode_rte(c, buf, n, new, src); - bmp_route_monitor_put_update(p, buf, end - buf, bgp); -} + byte *end = bgp_bmp_encode_rte(bs->sender, buf, n, new, src); -void -bmp_route_monitor_update_in_notify(struct channel *C, const net_addr *n, - const struct rte *new, const struct rte_src *src) -{ - struct bgp_channel *c = (void *) C; - - struct bmp_proto *p; node *nx; - WALK_LIST2(p, nx, bmp_proto_list, bmp_node) - bmp_route_monitor_update_in_notify_(p, c, n, new, src); + if (end) + bmp_route_monitor_put_update(p, bs, buf, end - buf); + else + log(L_WARN "%s: Cannot encode update for %N", p->p.name, n); } static void @@ -648,9 +814,6 @@ bmp_route_monitor_commit(void *p_) if (!p->started) return; - if (p->monitoring_rib.in_pre_policy == false) - return; - buffer payload = bmp_buffer_alloc(p->buffer_mpool, DEFAULT_MEM_BLOCK_SIZE); @@ -658,7 +821,7 @@ bmp_route_monitor_commit(void *p_) WALK_LIST_DELSAFE(data, data_next, p->update_msg_queue) { bmp_route_monitor_msg_serialize(&payload, - data->global_peer, true /* TODO: Hardcoded pre-policy Adj-Rib-In */, + data->global_peer, data->policy, data->remote_as, data->remote_id, true, data->remote_ip, data->data, data->data_size, data->timestamp); @@ -676,53 +839,37 @@ bmp_route_monitor_commit(void *p_) } static void -bmp_route_monitor_end_of_rib_msg(struct bmp_proto *p, struct bgp_channel *c) +bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_stream *bs) { - struct bgp_proto *bgp = (void *) c->c.proto; - - TRACE(D_PACKETS, "Sending END-OF-RIB for %s.%s", bgp->p.name, c->c.name); + TRACE(D_PACKETS, "Sending END-OF-RIB for %s.%s", bs->bgp->p.name, bs->sender->c.name); byte rx_end_payload[DEFAULT_MEM_BLOCK_SIZE]; - byte *pos = bgp_create_end_mark_(c, rx_end_payload + BGP_HEADER_LENGTH); + byte *pos = bgp_create_end_mark_(bs->sender, rx_end_payload + BGP_HEADER_LENGTH); 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); - bmp_route_monitor_put_update(p, rx_end_payload, pos - rx_end_payload, bgp); + bmp_route_monitor_put_update(p, bs, rx_end_payload, pos - rx_end_payload); } static void -bmp_route_monitor_pre_policy_table_in_snapshot(struct bmp_proto *p, struct bgp_channel *c) +bmp_route_monitor_snapshot(struct bmp_proto *p, struct bmp_stream *bs) { - if (p->monitoring_rib.in_pre_policy == false) - return; + struct rtable *tab = bs->table->table; - struct rtable *tab = c->c.in_table; - if (!tab) - return; - - size_t cnt = 0; - struct proto *P; - struct fib_iterator fit; - memset(&fit, 0x00, sizeof (fit)); + struct fib_iterator fit = {}; FIB_ITERATE_INIT(&fit, &tab->fib); FIB_ITERATE_START(&tab->fib, &fit, net, n) { - P = n->routes->sender->proto; - if (P->proto->class != PROTOCOL_BGP) - continue; - rte *e; for (e = n->routes; e; e = e->next) - bmp_route_monitor_update_in_notify_(p, c, n->n.addr, e, e->src); - - ++cnt; + if (e->sender == &bs->sender->c) + bmp_route_monitor_notify(p, bs, n->n.addr, e, e->src); } FIB_ITERATE_END; - if (cnt > 0) - bmp_route_monitor_end_of_rib_msg(p, c); + bmp_route_monitor_end_of_rib(p, bs); } static void @@ -751,10 +898,11 @@ bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp, if (!p->started) return; - TRACE(D_STATES, "Peer down for %s", bgp->p.name); + struct bmp_peer *bp = bmp_find_peer(p, bgp); + if (!bp) + return; - // struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip, bgp->remote_as); - // bmp_peer_map_remove(&p->bgp_peers, key); + TRACE(D_STATES, "Peer down for %s", bgp->p.name); buffer payload = bmp_buffer_alloc(p->buffer_mpool, 1 + BGP_HEADER_LENGTH + msg_length); @@ -786,6 +934,8 @@ bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp, bmp_send_peer_down_notif_msg(p, bgp, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); bmp_buffer_free(&payload); + + bmp_remove_peer(p, bp); } void @@ -819,6 +969,38 @@ bmp_send_termination_msg(struct bmp_proto *p, bmp_buffer_free(&stream); } +int +bmp_preexport(struct channel *C UNUSED, rte *e) +{ + /* Reject non-direct routes */ + if (e->src->proto != e->sender->proto) + return -1; + + /* Reject non-BGP routes */ + if (e->sender->channel != &channel_bgp) + return -1; + + return 1; +} + +static void +bmp_rt_notify(struct proto *P, struct channel *c, struct network *net, + struct rte *new, struct rte *old) +{ + 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); + + struct bmp_stream *bs = bmp_find_stream(p, bgp, src->afi, policy); + if (!bs) + return; + + bmp_route_monitor_notify(p, bs, net->n.addr, new, (new ?: old)->src); +} + + /** * bmp_startup - enter established state * @p: BMP instance @@ -835,6 +1017,8 @@ bmp_startup(struct bmp_proto *p) TRACE(D_EVENTS, "BMP session established"); + proto_notify_state(&p->p, PS_UP); + /* 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); @@ -846,15 +1030,14 @@ bmp_startup(struct bmp_proto *p) WALK_LIST(peer, proto_list) if ((peer->proto->class == PROTOCOL_BGP) && (peer->proto_state == PS_UP)) bmp_peer_init(p, (struct bgp_proto *) peer); - - proto_notify_state(&p->p, PS_UP); } /** * bmp_down - leave established state * @p: BMP instance * - * The bgp_down() function is called when the BMP session fails. + * The bgp_down() function is called when the BMP session fails. The caller is + * responsible for changing protocol state. */ static void bmp_down(struct bmp_proto *p) @@ -864,7 +1047,15 @@ bmp_down(struct bmp_proto *p) TRACE(D_EVENTS, "BMP session closed"); - proto_notify_state(&p->p, PS_START); + /* 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); } /** @@ -936,6 +1127,8 @@ bmp_sock_err(sock *sk, int err) bmp_close_socket(p); tm_start(p->connect_retry_timer, CONNECT_RETRY_TIME); + + proto_notify_state(&p->p, PS_START); } /* BMP connect timeout event - switch from Idle/Connect state to Connect state */ @@ -983,6 +1176,9 @@ bmp_init(struct proto_config *CF) struct bmp_proto *p = (void *) P; struct bmp_config *cf = (void *) CF; + P->rt_notify = bmp_rt_notify; + P->preexport = bmp_preexport; + p->cf = cf; p->local_addr = cf->local_addr; p->station_ip = cf->station_ip; @@ -990,6 +1186,7 @@ bmp_init(struct proto_config *CF) 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; + p->monitoring_rib.in_post_policy = cf->monitoring_rib_in_post_policy; return P; } @@ -1012,7 +1209,9 @@ bmp_start(struct proto *P) p->connect_retry_timer = tm_new_init(p->p.pool, bmp_connection_retry, p, 0, 0); p->sk = NULL; - // bmp_peer_map_init(&p->bgp_peers, p->map_mem_pool); + HASH_INIT(p->peer_map, P->pool, 4); + HASH_INIT(p->stream_map, P->pool, 4); + HASH_INIT(p->table_map, P->pool, 4); init_list(&p->tx_queue); init_list(&p->update_msg_queue); @@ -1033,7 +1232,7 @@ bmp_shutdown(struct proto *P) if (p->started) { bmp_send_termination_msg(p, BMP_TERM_REASON_ADM); - p->started = false; + bmp_down(p); } p->sock_err = 0; @@ -1054,7 +1253,8 @@ bmp_reconfigure(struct proto *P, struct proto_config *CF) || !ipa_equal(new->local_addr, old->local_addr) || !ipa_equal(new->station_ip, old->station_ip) || (new->station_port != old->station_port) - || (new->monitoring_rib_in_pre_policy != old->monitoring_rib_in_pre_policy); + || (new->monitoring_rib_in_pre_policy != old->monitoring_rib_in_pre_policy) + || (new->monitoring_rib_in_post_policy != old->monitoring_rib_in_post_policy); /* If there is any change, restart the protocol */ if (needs_restart) diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 0c355754..9b4e2a73 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -39,6 +39,7 @@ struct bmp_config { ip_addr station_ip; // Monitoring station address u16 station_port; // Monitoring station TCP port bool monitoring_rib_in_pre_policy; // Route monitoring pre-policy Adj-Rib-In + bool monitoring_rib_in_post_policy; // Route monitoring post-policy Adj-Rib-In }; /* Forward declarations */ @@ -49,6 +50,11 @@ struct bmp_proto { struct proto p; // Parent proto const struct bmp_config *cf; // Shortcut to BMP configuration node bmp_node; // Node in bmp_proto_list + + HASH(struct bmp_peer) peer_map; + HASH(struct bmp_stream) stream_map; + HASH(struct bmp_table) table_map; + sock *sk; // TCP connection event *tx_ev; // TX event event *update_ev; // Update event @@ -71,6 +77,28 @@ struct bmp_proto { int sock_err; // Last socket error code }; +struct bmp_peer { + struct bgp_proto *bgp; + struct bmp_peer *next; + list streams; +}; + +struct bmp_stream { + node n; + struct bgp_proto *bgp; + u32 key; + struct bmp_stream *next; + struct bmp_table *table; + struct bgp_channel *sender; +}; + +struct bmp_table { + struct rtable *table; + struct bmp_table *next; + struct channel *channel; + u32 uc; +}; + #ifdef CONFIG_BMP @@ -78,17 +106,10 @@ struct bmp_proto { * bmp_peer_up - send notification that BGP peer connection is established */ void -bmp_peer_up(const struct bgp_proto *bgp, +bmp_peer_up(struct bgp_proto *bgp, const byte *tx_open_msg, uint tx_open_length, const byte *rx_open_msg, uint rx_open_length); -/** - * bmp_route_monitor_update_in_notify - send notification that rte vas received - */ -void -bmp_route_monitor_update_in_notify(struct channel *C, const net_addr *n, - const struct rte *new, const struct rte_src *src); - /** * bmp_peer_down - send notification that BGP peer connection is not in * established state diff --git a/proto/bmp/config.Y b/proto/bmp/config.Y index 5a5e0812..acb0c4d9 100644 --- a/proto/bmp/config.Y +++ b/proto/bmp/config.Y @@ -27,7 +27,6 @@ bmp_proto_start: proto_start BMP { this_proto = proto_config_new(&proto_bmp, $1); BMP_CFG->sys_descr = "Not defined"; BMP_CFG->sys_name = "Not defined"; - BMP_CFG->monitoring_rib_in_pre_policy = false; } ; @@ -69,6 +68,9 @@ bmp_proto: | bmp_proto MONITORING RIB IN PRE_POLICY bool ';' { BMP_CFG->monitoring_rib_in_pre_policy = $6; } + | bmp_proto MONITORING RIB IN POST_POLICY bool ';' { + BMP_CFG->monitoring_rib_in_post_policy = $6; + } ; CF_CODE From c40f29a79035b54a8b48ece0e91d38d9066529e3 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 18 Aug 2023 15:39:08 +0200 Subject: [PATCH 14/17] BMP: Fix route timestamps --- proto/bmp/bmp.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index ec1614f5..964d44b5 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -770,7 +770,7 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, } static void -bmp_route_monitor_put_update(struct bmp_proto *p, struct bmp_stream *bs, const byte *data, size_t length) +bmp_route_monitor_put_update(struct bmp_proto *p, struct bmp_stream *bs, const byte *data, size_t length, btime timestamp) { struct bmp_data_node *upd_msg = mb_alloc(p->update_msg_mem_pool, sizeof (struct bmp_data_node)); @@ -784,7 +784,7 @@ bmp_route_monitor_put_update(struct bmp_proto *p, struct bmp_stream *bs, const b upd_msg->remote_as = bgp->remote_as; upd_msg->remote_id = bgp->remote_id; upd_msg->remote_ip = bgp->remote_ip; - upd_msg->timestamp = current_time(); + upd_msg->timestamp = timestamp; upd_msg->global_peer = bmp_is_peer_global_instance(bgp); upd_msg->policy = bmp_stream_policy(bs); @@ -800,8 +800,11 @@ bmp_route_monitor_notify(struct bmp_proto *p, struct bmp_stream *bs, byte buf[BGP_MAX_EXT_MSG_LENGTH]; byte *end = bgp_bmp_encode_rte(bs->sender, buf, n, new, src); + btime delta_t = new ? current_time() - new->lastmod : 0; + btime timestamp = current_real_time() - delta_t; + if (end) - bmp_route_monitor_put_update(p, bs, buf, end - buf); + bmp_route_monitor_put_update(p, bs, buf, end - buf, timestamp); else log(L_WARN "%s: Cannot encode update for %N", p->p.name, n); } @@ -850,7 +853,7 @@ bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_stream *bs) 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); - bmp_route_monitor_put_update(p, bs, rx_end_payload, pos - rx_end_payload); + bmp_route_monitor_put_update(p, bs, rx_end_payload, pos - rx_end_payload, current_real_time()); } static void From ef6ab5ce86af925ee10687fde4e62912fb892433 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 21 Aug 2023 04:17:21 +0200 Subject: [PATCH 15/17] Nest: Use generic rte_announce() also for import tables Remove special rte_announce_in(), so we can use generic rte_announce() for bot feed and notifications. --- nest/rt-table.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/nest/rt-table.c b/nest/rt-table.c index e8478c36..23c4bbb2 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2148,11 +2148,11 @@ rt_setup(pool *pp, struct rtable_config *cf) init_list(&t->flowspec_links); init_list(&t->subscribers); + hmap_init(&t->id_map, p, 1024); + hmap_set(&t->id_map, 0); + if (!(t->internal = cf->internal)) { - hmap_init(&t->id_map, p, 1024); - hmap_set(&t->id_map, 0); - t->rt_event = ev_new_init(p, rt_event, t); t->prune_timer = tm_new_init(p, rt_prune_timer, t, 0, 0); t->last_rt_change = t->gc_time = current_time(); @@ -3063,23 +3063,6 @@ rt_feed_channel_abort(struct channel *c) * Import table */ -static void -rte_announce_in(struct rtable *tab, struct network *net, struct rte *new, struct rte *old) -{ - struct channel *c; node *n; - WALK_LIST2(c, n, tab->channels, table_node) - { - if (c->export_state == ES_DOWN) - continue; - - if (c->ra_mode != RA_ANY) - continue; - - struct proto *p = c->proto; - p->rt_notify(p, c, net, new, old); - } -} - int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src) { @@ -3159,12 +3142,25 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr e->next = *pos; *pos = new = e; tab->rt_count++; + + if (!old) + { + new->id = hmap_first_zero(&tab->id_map); + hmap_set(&tab->id_map, new->id); + } + else + new->id = old->id; } - rte_announce_in(tab, net, new, old); + rte_announce(tab, RA_ANY, net, new, old, NULL, NULL); if (old) + { + if (!new) + hmap_clear(&tab->id_map, old->id); + rte_free_quick(old); + } if (!net->routes) fib_delete(&tab->fib, net); From 52641e086675832e9f43f86237b0cddbd5ec551e Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 21 Aug 2023 04:20:32 +0200 Subject: [PATCH 16/17] BMP: Use generic channel feed instead of direct walk over rtable Now we use rt_notify() and channels for both feed and notifications, in both import tables (pre-policy) and regular tables (post-policy). Remove direct walk in bmp_route_monitor_snapshot(). --- nest/proto.c | 5 +--- nest/protocol.h | 4 +-- proto/bmp/bmp.c | 77 +++++++++++++++++++++++++++++++------------------ proto/bmp/bmp.h | 1 + 4 files changed, 53 insertions(+), 34 deletions(-) diff --git a/nest/proto.c b/nest/proto.c index 16245dca..a5325705 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -451,10 +451,7 @@ channel_start_export(struct channel *c) ASSERT(c->channel_state == CS_UP); ASSERT(c->export_state == ES_DOWN); - if (!c->bmp_hack) - channel_schedule_feed(c, 1); /* Sets ES_FEEDING */ - else - c->export_state = ES_READY; + channel_schedule_feed(c, 1); /* Sets ES_FEEDING */ } static void diff --git a/nest/protocol.h b/nest/protocol.h index d94a11bc..dad0b781 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -500,7 +500,7 @@ struct channel_config { u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */ u8 in_keep_filtered; /* Routes rejected in import filter are kept */ u8 rpki_reload; /* RPKI changes trigger channel reload */ - u8 bmp_hack; /* No feed, no flush */ + u8 bmp_hack; /* No flush */ }; struct channel { @@ -553,7 +553,7 @@ struct channel { u8 reload_pending; /* Reloading and another reload is scheduled */ u8 refeed_pending; /* Refeeding and another refeed is scheduled */ u8 rpki_reload; /* RPKI changes trigger channel reload */ - u8 bmp_hack; /* No feed, no flush */ + u8 bmp_hack; /* No flush */ struct rtable *out_table; /* Internal table for exported routes */ diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 964d44b5..22b9f2fb 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -223,6 +223,8 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, const byte *tx_data, const size_t tx_data_size, const byte *rx_data, const size_t rx_data_size); +static void bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_stream *bs); + // Stores necessary any data in list struct bmp_data_node { node n; @@ -237,9 +239,6 @@ struct bmp_data_node { bool policy; }; -static void -bmp_route_monitor_snapshot(struct bmp_proto *p, struct bmp_stream *bs); - static void bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size) { @@ -571,6 +570,7 @@ bmp_add_stream(struct bmp_proto *p, struct bmp_peer *bp, u32 afi, bool policy, s bmp_lock_table(p, bs->table); bs->sender = sender; + bs->sync = false; return bs; } @@ -634,7 +634,7 @@ bmp_remove_peer(struct bmp_proto *p, struct bmp_peer *bp) } static void -bmp_peer_up_(struct bmp_proto *p, struct bgp_proto *bgp, +bmp_peer_up_(struct bmp_proto *p, struct bgp_proto *bgp, bool sync, const byte *tx_open_msg, uint tx_open_length, const byte *rx_open_msg, uint rx_open_length) { @@ -651,9 +651,20 @@ bmp_peer_up_(struct bmp_proto *p, struct bgp_proto *bgp, bmp_send_peer_up_notif_msg(p, bgp, tx_open_msg, tx_open_length, rx_open_msg, rx_open_length); - struct bmp_stream *bs; - WALK_LIST(bs, bp->streams) - bmp_route_monitor_snapshot(p, bs); + /* + * 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; + } + } } void @@ -663,7 +674,7 @@ bmp_peer_up(struct bgp_proto *bgp, { struct bmp_proto *p; node *n; WALK_LIST2(p, n, bmp_proto_list, bmp_node) - bmp_peer_up_(p, bgp, tx_open_msg, tx_open_length, rx_open_msg, rx_open_length); + bmp_peer_up_(p, bgp, true, tx_open_msg, tx_open_length, rx_open_msg, rx_open_length); } static void @@ -675,7 +686,7 @@ bmp_peer_init(struct bmp_proto *p, struct bgp_proto *bgp) !conn->local_open_msg || !conn->remote_open_msg) return; - bmp_peer_up_(p, bgp, conn->local_open_msg, conn->local_open_length, + bmp_peer_up_(p, bgp, false, conn->local_open_msg, conn->local_open_length, conn->remote_open_msg, conn->remote_open_length); } @@ -856,25 +867,6 @@ bmp_route_monitor_end_of_rib(struct bmp_proto *p, struct bmp_stream *bs) bmp_route_monitor_put_update(p, bs, rx_end_payload, pos - rx_end_payload, current_real_time()); } -static void -bmp_route_monitor_snapshot(struct bmp_proto *p, struct bmp_stream *bs) -{ - struct rtable *tab = bs->table->table; - - struct fib_iterator fit = {}; - FIB_ITERATE_INIT(&fit, &tab->fib); - FIB_ITERATE_START(&tab->fib, &fit, net, n) - { - rte *e; - for (e = n->routes; e; e = e->next) - if (e->sender == &bs->sender->c) - bmp_route_monitor_notify(p, bs, n->n.addr, e, e->src); - } - FIB_ITERATE_END; - - bmp_route_monitor_end_of_rib(p, bs); -} - static void bmp_send_peer_down_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, const byte *data, const size_t data_size) @@ -1003,6 +995,34 @@ bmp_rt_notify(struct proto *P, struct channel *c, struct network *net, bmp_route_monitor_notify(p, bs, net->n.addr, new, (new ?: old)->src); } +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; +} + /** * bmp_startup - enter established state @@ -1181,6 +1201,7 @@ bmp_init(struct proto_config *CF) P->rt_notify = bmp_rt_notify; P->preexport = bmp_preexport; + P->feed_end = bmp_feed_end; p->cf = cf; p->local_addr = cf->local_addr; diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index 9b4e2a73..e51c2ea0 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -87,6 +87,7 @@ struct bmp_stream { node n; struct bgp_proto *bgp; u32 key; + bool sync; struct bmp_stream *next; struct bmp_table *table; struct bgp_channel *sender; From 4558adabfbbe3696156d20767168010d6238f434 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Tue, 22 Aug 2023 01:24:21 +0200 Subject: [PATCH 17/17] BMP: Improve peer_down handling Move all bmp_peer_down() calls to one place and make it synchronous with BGP session down, ensuring that BMP receives peer_down before route withdraws from flushing. Also refactor bmp_peer_down_() message generating code. --- proto/bgp/bgp.c | 25 ++++++++--------- proto/bgp/packets.c | 8 ++++-- proto/bmp/bmp.c | 67 +++++++++++++++++++++++++++++---------------- proto/bmp/bmp.h | 7 ++--- 4 files changed, 63 insertions(+), 44 deletions(-) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index ccaa5067..a6e9cf83 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -391,6 +391,9 @@ bgp_close_conn(struct bgp_conn *conn) conn->local_caps = NULL; mb_free(conn->remote_caps); conn->remote_caps = NULL; + + conn->notify_data = NULL; + conn->notify_size = 0; } @@ -694,7 +697,7 @@ bgp_conn_enter_established_state(struct bgp_conn *conn) } static void -bgp_conn_leave_established_state(struct bgp_proto *p) +bgp_conn_leave_established_state(struct bgp_conn *conn, struct bgp_proto *p) { BGP_TRACE(D_EVENTS, "BGP session closed"); p->last_established = current_time(); @@ -702,6 +705,10 @@ bgp_conn_leave_established_state(struct bgp_proto *p) if (p->p.proto_state == PS_UP) bgp_stop(p, 0, NULL, 0); + + bmp_peer_down(p, p->last_error_class, + conn->notify_code, conn->notify_subcode, + conn->notify_data, conn->notify_size); } void @@ -718,7 +725,7 @@ bgp_conn_enter_close_state(struct bgp_conn *conn) bgp_start_timer(conn->hold_timer, 10); if (os == BS_ESTABLISHED) - bgp_conn_leave_established_state(p); + bgp_conn_leave_established_state(conn, p); } void @@ -732,7 +739,7 @@ bgp_conn_enter_idle_state(struct bgp_conn *conn) ev_schedule(p->event); if (os == BS_ESTABLISHED) - bgp_conn_leave_established_state(p); + bgp_conn_leave_established_state(conn, p); } /** @@ -876,10 +883,7 @@ bgp_graceful_restart_timeout(timer *t) } } else - { bgp_stop(p, 0, NULL, 0); - bmp_peer_down(p, BE_NONE, NULL, 0); - } } static void @@ -1003,10 +1007,7 @@ bgp_sock_err(sock *sk, int err) if (err) BGP_TRACE(D_EVENTS, "Connection lost (%M)", err); else - { BGP_TRACE(D_EVENTS, "Connection closed"); - bmp_peer_down(p, BE_SOCKET, NULL, 0); - } if ((conn->state == BS_ESTABLISHED) && p->gr_ready) bgp_handle_graceful_restart(p); @@ -1331,7 +1332,6 @@ bgp_neigh_notify(neighbor *n) bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST); /* Perhaps also run bgp_update_startup_delay(p)? */ bgp_stop(p, 0, NULL, 0); - bmp_peer_down(p, BE_MISC, NULL, 0); } } else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP)) @@ -1343,7 +1343,6 @@ bgp_neigh_notify(neighbor *n) if (ps == PS_UP) bgp_update_startup_delay(p); bgp_stop(p, 0, NULL, 0); - bmp_peer_down(p, BE_MISC, NULL, 0); } } else @@ -1385,7 +1384,6 @@ bgp_bfd_notify(struct bfd_request *req) if (ps == PS_UP) bgp_update_startup_delay(p); bgp_stop(p, 0, NULL, 0); - bmp_peer_down(p, BE_MISC, NULL, 0); } } } @@ -2266,12 +2264,13 @@ bgp_error(struct bgp_conn *c, uint code, uint subcode, byte *data, int len) bgp_log_error(p, BE_BGP_TX, "Error", code, subcode, data, ABS(len)); bgp_store_error(p, c, BE_BGP_TX, (code << 16) | subcode); - bgp_conn_enter_close_state(c); c->notify_code = code; c->notify_subcode = subcode; c->notify_data = data; c->notify_size = (len > 0) ? len : 0; + + bgp_conn_enter_close_state(c); bgp_schedule_packet(c, NULL, PKT_NOTIFICATION); if (code != 6) diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 2f1ff659..6b728b4e 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -3042,7 +3042,6 @@ bgp_fire_tx(struct bgp_conn *conn) { conn->packets_to_send = 1 << PKT_SCHEDULE_CLOSE; end = bgp_create_notification(conn, pkt); - bmp_peer_down(p, BE_BGP_TX, pkt, end - pkt); return bgp_send(conn, PKT_NOTIFICATION, end - buf); } else if (s & (1 << PKT_OPEN)) @@ -3334,6 +3333,11 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len) bgp_log_error(p, BE_BGP_RX, "Received", code, subcode, pkt+21, len-21); bgp_store_error(p, conn, BE_BGP_RX, (code << 16) | subcode); + conn->notify_code = code; + conn->notify_subcode = subcode; + conn->notify_data = pkt+21; + conn->notify_size = len-21; + bgp_conn_enter_close_state(conn); bgp_schedule_packet(conn, NULL, PKT_SCHEDULE_CLOSE); @@ -3352,8 +3356,6 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len) p->p.disabled = 1; } } - - bmp_peer_down(p, BE_BGP_RX, pkt + BGP_HEADER_LENGTH, len - BGP_HEADER_LENGTH); } static void diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 22b9f2fb..261e9fdd 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -888,7 +888,7 @@ bmp_send_peer_down_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp, static void bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp, - const int err_class, const byte *msg, size_t msg_length) + int err_class, int err_code, int err_subcode, const byte *data, int length) { if (!p->started) return; @@ -899,31 +899,43 @@ bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp, TRACE(D_STATES, "Peer down for %s", bgp->p.name); - buffer payload = bmp_buffer_alloc(p->buffer_mpool, 1 + BGP_HEADER_LENGTH + msg_length); + uint bmp_code = 0; + uint fsm_code = 0; - if (msg) + switch (err_class) { - if (err_class == BE_BGP_TX) - bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION); - else - bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION); + case BE_BGP_RX: + bmp_code = BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION; + break; - bmp_put_bgp_hdr(&payload, BGP_HEADER_LENGTH + msg_length, PKT_NOTIFICATION); - bmp_put_data(&payload, msg, msg_length); + 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; } - else + + buffer payload = bmp_buffer_alloc(p->buffer_mpool, 1 + BGP_HEADER_LENGTH + 2 + length); + bmp_put_u8(&payload, bmp_code); + + switch (bmp_code) { - // TODO: Handle De-configured Peer Down Reason Code - if (err_class == BE_SOCKET || err_class == BE_MISC) - { - bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION); - } - else - { - bmp_put_u8(&payload, BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION); - // TODO: Fill in with appropriate FSM event code - bmp_put_u16(&payload, 0x00); // no relevant Event code is defined - } + 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; } bmp_send_peer_down_notif_msg(p, bgp, bmp_buffer_data(&payload), bmp_buffer_pos(&payload)); @@ -934,12 +946,12 @@ bmp_peer_down_(struct bmp_proto *p, const struct bgp_proto *bgp, } void -bmp_peer_down(const struct bgp_proto *bgp, const int err_class, - const byte *msg, size_t msg_length) +bmp_peer_down(const struct bgp_proto *bgp, + int err_class, int code, int subcode, const byte *data, int length) { struct bmp_proto *p; node *n; WALK_LIST2(p, n, bmp_proto_list, bmp_node) - bmp_peer_down_(p, bgp, err_class, msg, msg_length); + bmp_peer_down_(p, bgp, err_class, code, subcode, data, length); } static void @@ -988,6 +1000,13 @@ bmp_rt_notify(struct proto *P, struct channel *c, struct network *net, struct bgp_proto *bgp = (void *) src->c.proto; bool policy = (c->table == src->c.table); + /* + * 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. + */ + struct bmp_stream *bs = bmp_find_stream(p, bgp, src->afi, policy); if (!bs) return; diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index e51c2ea0..2d700c25 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -116,14 +116,13 @@ bmp_peer_up(struct bgp_proto *bgp, * established state */ void -bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt, - size_t pkt_size); +bmp_peer_down(const struct bgp_proto *bgp, int err_class, int code, int subcode, const byte *data, int length); #else /* BMP build disabled */ -static inline void bmp_peer_up(const struct bgp_proto *bgp UNUSED, const byte *tx_open_msg UNUSED, uint tx_open_length UNUSED, const byte *rx_open_msg UNUSED, uint rx_open_length UNUSED) { } -static inline void bmp_peer_down(const struct bgp_proto *bgp UNUSED, const int err_class UNUSED, const byte *pkt UNUSED, size_t pkt_size UNUSED) { } +static inline void bmp_peer_up(struct bgp_proto *bgp UNUSED, const byte *tx_open_msg UNUSED, uint tx_open_length UNUSED, const byte *rx_open_msg UNUSED, uint rx_open_length UNUSED) { } +static inline void bmp_peer_down(const struct bgp_proto *bgp UNUSED, const int err_class UNUSED, int code UNUSED, int subcode UNUSED, const byte *data UNUSED, int length UNUSED) { } #endif /* CONFIG_BMP */