>From 85151f783b4b2247f206467ffcd725d92fc29138 Mon Sep 17 00:00:00 2001
From: Michal Zagorski <mzagorsk@akamai.com>
Date: Wed, 17 May 2023 15:14:18 +0200
Subject: [PATCH] BMP: Support for multiple protocol instances and bugfixes
To: bird-users@network.cz

* Fix use-after-free by checking status before processing bgp_open msgs
* Report more info with protocol status
* Send End-Of-RIB, when updates pushed
* Remove infinite loop when not pushing any routes on peer_up
* Set proper BGP data size in NOTIFICATION when peer down
* Don't try to get BMP internal data when protocol itself is not running
* Fixed peer ASN size in UPDATE MSG
* Implemented reconfigure command callback
* Added source local address for BMP connection
* Debug logs using TRACE() macro on p protocol instance

Co-authored By: Pawel Maslanka <pmaslank@akamai.com>

Signed-off-by: Michal Zagorski <mzagorsk@akamai.com>
---
 proto/bgp/attrs.c   |   1 -
 proto/bgp/bgp.h     |  12 +-
 proto/bgp/packets.c |  85 ++++--
 proto/bmp/LICENSE   |   2 +-
 proto/bmp/bmp.c     | 695 +++++++++++++++++++++++++++-----------------
 proto/bmp/bmp.h     |  39 +--
 proto/bmp/buffer.c  |  14 +-
 proto/bmp/config.Y  |  13 +-
 8 files changed, 544 insertions(+), 317 deletions(-)

diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index de45cae0..e962038d 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -1961,7 +1961,6 @@ bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old)
   bgp_schedule_packet(p->conn, c, PKT_UPDATE);
 }
 
-
 static inline u32
 bgp_get_neighbor(rte *r)
 {
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 7c96e851..8e214a4d 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -393,6 +393,7 @@ struct bgp_channel {
 
   u8 feed_state;			/* Feed state (TX) for EoR, RR packets, see BFS_* */
   u8 load_state;			/* Load state (RX) for EoR, RR packets, see BFS_* */
+  u8 update_state;			/* Confirmed last batch of route updates */
 };
 
 struct bgp_prefix {
@@ -494,6 +495,13 @@ struct bgp_parse_state {
 #define BGP_RX_BUFFER_EXT_SIZE	65535
 #define BGP_TX_BUFFER_EXT_SIZE	65535
 
+#define BGP_MSG_HDR_MARKER_SIZE 16
+#define BGP_MSG_HDR_MARKER_POS 0
+#define BGP_MSG_HDR_LENGTH_SIZE 2
+#define BGP_MSG_HDR_LENGTH_POS BGP_MSG_HDR_MARKER_SIZE
+#define BGP_MSG_HDR_TYPE_SIZE 1
+#define BGP_MSG_HDR_TYPE_POS (BGP_MSG_HDR_MARKER_SIZE + BGP_MSG_HDR_LENGTH_SIZE)
+
 #define BGP_CF_WALK_CHANNELS(P,C) WALK_LIST(C, P->c.channels) if (C->c.channel == &channel_bgp)
 #define BGP_WALK_CHANNELS(P,C) WALK_LIST(C, P->p.channels) if (C->c.channel == &channel_bgp)
 
@@ -659,7 +667,8 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi
 
 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_ip_end_mark(struct bgp_channel *c, byte *buf);
+byte * bgp_create_mp_end_mark(struct bgp_channel *c, byte *buf);
 
 /* Packet types */
 
@@ -670,6 +679,7 @@ byte * bgp_create_end_mark(struct bgp_channel *c, byte *buf);
 #define PKT_ROUTE_REFRESH	0x05	/* [RFC2918] */
 #define PKT_BEGIN_REFRESH	0x1e	/* Dummy type for BoRR packet [RFC7313] */
 #define PKT_SCHEDULE_CLOSE	0x1f	/* Used internally to schedule socket close */
+#define PKT_BMP_MSG 0x20 /* BGP Monitoring Protocol message [RFC7854] */
 
 /* Attributes */
 
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index b9537169..034b0ebb 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -2419,29 +2419,47 @@ bgp_create_update_bmp(struct bgp_channel *c, byte *buf, struct bgp_bucket *buck,
 
   struct bgp_caps *peer = p->conn->remote_caps;
   const struct bgp_af_caps *rem = bgp_find_af_caps(peer, c->afi);
+  if (!rem)
+    return NULL;
+
+  struct lp_state tmpp;
+  lp_save(tmp_linpool, &tmpp);
+
   struct bgp_write_state s = {
     .proto = p,
     .channel = c,
     .pool = tmp_linpool,
     .mp_reach = (c->afi != BGP_AF_IPV4) || rem->ext_next_hop,
-    .as4_session = 1,
+    .as4_session = peer->as4_support,
     .add_path = c->add_path_rx,
     .mpls = c->desc->mpls,
     .sham = 1,
   };
 
+  byte *pos;
   if (!update)
   {
-    return !s.mp_reach ?
+    pos = !s.mp_reach ?
       bgp_create_ip_unreach(&s, buck, buf, end):
       bgp_create_mp_unreach(&s, buck, buf, end);
   }
   else
   {
-    return !s.mp_reach ?
+    pos = !s.mp_reach ?
       bgp_create_ip_reach(&s, buck, buf, end):
       bgp_create_mp_reach(&s, buck, buf, end);
   }
+
+  if (!pos)
+  {
+    while (!EMPTY_LIST(buck->prefixes))
+    {
+      struct bgp_prefix *px = HEAD(buck->prefixes);
+      rem_node(&px->buck_node);
+    }
+  }
+  lp_restore(tmp_linpool, &tmpp);
+  return pos;
 }
 
 static byte *
@@ -2475,7 +2493,10 @@ bgp_rte_update_in_notify(struct channel *C, const net_addr *n,
   init_list(&b->prefixes);
 
   if (attrs)
+  {
     memcpy(b->eattrs, attrs, ea_size);
+    bgp_fix_attr_flags(b->eattrs);
+  }
 
   /* Sham prefix */
   struct bgp_prefix *px = alloca(prefix_size);
@@ -2489,7 +2510,10 @@ 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);
+  struct proto *P = NULL;
+  WALK_LIST(P, proto_list)
+    if (P && P->proto && P->proto->class == PROTOCOL_BMP)
+      bmp_route_monitor_put_update_in_pre_msg((struct bmp_proto *) P, buf, end - buf);
 }
 
 #endif /* CONFIG_BMP */
@@ -2571,7 +2595,7 @@ done:
   return res;
 }
 
-static byte *
+byte *
 bgp_create_ip_end_mark(struct bgp_channel *c UNUSED, byte *buf)
 {
   /* Empty update packet */
@@ -2580,7 +2604,7 @@ bgp_create_ip_end_mark(struct bgp_channel *c UNUSED, byte *buf)
   return buf+4;
 }
 
-static byte *
+byte *
 bgp_create_mp_end_mark(struct bgp_channel *c, byte *buf)
 {
   put_u16(buf+0, 0);
@@ -2681,6 +2705,7 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
 {
   struct bgp_proto *p = conn->bgp;
   ea_list *ea = NULL;
+  u32 af = BGP_AF_IPV4;
 
   BGP_TRACE_RL(&rl_rcv_update, D_PACKETS, "Got UPDATE");
   p->last_rx_update = current_time();
@@ -2745,8 +2770,10 @@ 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();
+  struct proto *P = NULL;
+  WALK_LIST(P, proto_list)
+    if (P && P->proto && P->proto->class == PROTOCOL_BMP && P->proto_state == PS_UP)
+        bmp_route_monitor_update_in_pre_begin((struct bmp_proto *) P);
 
   if (s.attr_len)
     ea = bgp_decode_attrs(&s, s.attrs, s.attr_len);
@@ -2760,13 +2787,16 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
   /* Check for MP End-of-RIB marker */
   if ((s.attr_len < 8) && !s.ip_unreach_len && !s.ip_reach_len &&
       !s.mp_reach_len && !s.mp_unreach_len && s.mp_unreach_af)
-  { bgp_rx_end_mark(&s, s.mp_unreach_af); goto done; }
+  { af = s.mp_unreach_af; bgp_rx_end_mark(&s, af); goto done; }
 
-  if (s.ip_unreach_len)
+  if (s.ip_unreach_len) {
     bgp_decode_nlri(&s, BGP_AF_IPV4, s.ip_unreach_nlri, s.ip_unreach_len, NULL, NULL, 0);
+  }
 
-  if (s.mp_unreach_len)
-    bgp_decode_nlri(&s, s.mp_unreach_af, s.mp_unreach_nlri, s.mp_unreach_len, NULL, NULL, 0);
+  if (s.mp_unreach_len) {
+    af = s.mp_unreach_af;
+    bgp_decode_nlri(&s, af, s.mp_unreach_nlri, s.mp_unreach_len, NULL, NULL, 0);
+  }
 
   s.reach_nlri_step = 1;
 
@@ -2774,14 +2804,29 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
     bgp_decode_nlri(&s, BGP_AF_IPV4, s.ip_reach_nlri, s.ip_reach_len,
 		    ea, s.ip_next_hop_data, s.ip_next_hop_len);
 
-  if (s.mp_reach_len)
-    bgp_decode_nlri(&s, s.mp_reach_af, s.mp_reach_nlri, s.mp_reach_len,
+  if (s.mp_reach_len) {
+    af = s.mp_reach_af;
+    bgp_decode_nlri(&s, 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:
+  WALK_LIST(P, proto_list)
+  {
+    if (P && P->proto && P->proto->class == PROTOCOL_BMP)
+    {
+      if (P->proto_state == PS_UP)
+      {
+        bmp_route_monitor_update_in_pre_commit((struct bmp_proto *) P, p);
+        bmp_route_monitor_update_in_pre_end((struct bmp_proto *) P);
+      }
+    }
+  }
+  struct bgp_channel *c = bgp_get_channel(s.proto, af);
+  if (c) {
+      c->update_state = 1;
+  }
+
   rta_free(s.cached_rta);
   lp_restore(tmp_linpool, &tmpp);
   return;
@@ -3041,6 +3086,12 @@ bgp_fire_tx(struct bgp_conn *conn)
   }
   else if (s & (1 << PKT_KEEPALIVE))
   {
+    WALK_LIST(c, p->p.channels) {
+      if (c->update_state) {
+        bmp_route_monitor_empty_update_msg((struct channel *) c);
+        c->update_state = 0;
+      }
+    }
     conn->packets_to_send &= ~(1 << PKT_KEEPALIVE);
     BGP_TRACE(D_PACKETS, "Sending KEEPALIVE");
     bgp_start_timer(conn->keepalive_timer, conn->keepalive_time);
diff --git a/proto/bmp/LICENSE b/proto/bmp/LICENSE
index 1772f08d..63337f04 100644
--- a/proto/bmp/LICENSE
+++ b/proto/bmp/LICENSE
@@ -1,2 +1,2 @@
 The patch is provided under the terms of the GNU General Public License, either
-version 2, or any later version.
\ No newline at end of file
+version 2, or any later version.
diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c
index f04b59b8..0d5bb072 100644
--- a/proto/bmp/bmp.c
+++ b/proto/bmp/bmp.c
@@ -56,9 +56,6 @@
 #include "nest/iface.h"
 #include "nest/route.h"
 
-// We allow for single instance of BMP protocol
-static struct bmp_proto *g_bmp;
-
 /* BMP Common Header [RFC 7854 - Section 4.1] */
 enum bmp_version {
   BMP_VER_UNUSED = 0, // Version 0 is reserved and MUST NOT be sent
@@ -180,6 +177,16 @@ enum bmp_term_reason {
 
 #define IP4_MAX_TTL 255
 
+#define NO_SOCK_ERROR 0
+
+// This value is passing to socket error handler to force restart socket
+#define FORCE_SOCKET_RESTART NO_SOCK_ERROR
+
+/* Return values for reconfiguration functions */
+#define NEED_RESTART      0
+#define SUCCESSFUL_RECONF 1
+
+#define NULL_TERM_CHAR '\0'
 
 #define IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(expr, msg, rv...)     \
   do {                                                                      \
@@ -196,15 +203,23 @@ enum bmp_term_reason {
     IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(!(p), msg, rv);	\
   } while (0)
 
+static void
+bmp_setup_socket(struct bmp_proto *p);
+
+// static void
+// bmp_close_conn(struct bmp_proto *p);
 
 static void bmp_connected(struct birdsock *sk);
 static void bmp_sock_err(sock *sk, int err);
 static void bmp_close_socket(struct bmp_proto *p);
 
+static void
+bmp_connect(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 {
@@ -214,7 +229,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 bmp_proto *p, struct channel *C);
 
 static void
 bmp_common_hdr_serialize(buffer *stream, const enum bmp_message_type type, const u32 data_size)
@@ -229,7 +244,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);
@@ -254,9 +269,13 @@ bmp_init_msg_serialize(buffer *stream, const char *sys_descr, const char *sys_na
 static void
 bmp_schedule_tx_packet(struct bmp_proto *p, const byte *payload, const size_t size)
 {
-  ASSERT(p->started);
+  if (!p->sk || (p->p.proto_state != PS_UP))
+  {
+    bmp_sock_err(p->sk, FORCE_SOCKET_RESTART);
+    return;
+  }
 
-  struct bmp_data_node *tx_data = mb_alloc(p->tx_mem_pool, sizeof (struct bmp_data_node));
+  struct bmp_data_node *tx_data = mb_allocz(p->tx_mem_pool, sizeof (struct bmp_data_node));
   tx_data->data = mb_alloc(p->tx_mem_pool, size);
   memcpy(tx_data->data, payload, size);
   tx_data->data_size = size;
@@ -273,12 +292,19 @@ static void
 bmp_fire_tx(void *p_)
 {
   struct bmp_proto *p = p_;
+  if (!p->sk || (p->p.proto_state != PS_UP))
+  {
+    bmp_sock_err(p->sk, FORCE_SOCKET_RESTART);
+    return;
+  }
+
   byte *buf = p->sk->tbuf;
   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"
   );
 
+  int rv;
   size_t cnt = 0; // Counts max packets which we want to send per TX slot
   struct bmp_data_node *tx_data;
   struct bmp_data_node *tx_data_next;
@@ -291,11 +317,16 @@ bmp_fire_tx(void *p_)
 
     size_t data_size = tx_data->data_size;
     memcpy(buf, tx_data->data, tx_data->data_size);
+    rv = sk_send(p->sk, data_size);
+    IF_COND_TRUE_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(
+      (rv < 0),
+      "Failed to send BMP packet"
+    );
+
     mb_free(tx_data->data);
     rem_node((node *) tx_data);
     mb_free(tx_data);
-
-    if (sk_send(p->sk, data_size) <= 0)
+    if (rv == 0)
       return;
 
     // BMP packets should be treat with lowest priority when scheduling sending
@@ -319,11 +350,49 @@ bmp_tx(struct birdsock *sk)
   bmp_fire_tx(sk->data);
 }
 
-/* We need RX hook just to accept socket close events */
+/*  We need RX hook just to accept socket close events */
 static int
 bmp_rx(struct birdsock *sk UNUSED, uint size UNUSED)
 {
-  return 0;
+      return 0;
+}
+
+// Configure socket with dynamic values, then open it
+static inline int
+bmp_open_socket(struct bmp_proto *p)
+{
+  sock *s = p->sk;
+  s->daddr = p->station_ip;
+  s->dport = p->station_port;
+  if (ipa_nonzero(p->src_local_addr))
+    s->saddr = p->src_local_addr;
+
+  int rc = sk_open(s);
+  TRACE(D_EVENTS, "Try to connect %I:%u", s->daddr, s->dport);
+  if (rc < 0) {
+    sk_log_error(s, p->p.name);
+    bmp_sock_err(s, 0);
+  }
+
+  return rc;
+}
+
+void
+bmp_close_socket(struct bmp_proto *p)
+{
+  rfree(p->sk);
+  p->sk = NULL;
+}
+
+static void
+bmp_connection_retry(timer *t)
+{
+  struct bmp_proto *p = t->data;
+  if (p->started)
+    return;
+
+  bmp_close_socket(p);
+  bmp_connect(p);
 }
 
 
@@ -445,14 +514,51 @@ bmp_peer_down_notif_msg_serialize(buffer *stream, const bool is_peer_global,
   bmp_put_data(stream, data, data_size);
 }
 
-static void
+void
+bmp_connect(struct bmp_proto *p)
+{
+  bmp_setup_socket(p);
+  bmp_open_socket(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: %s", P->name);
+
+  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");
+  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->connect_retry_timer = tm_new_init(p->p.pool, bmp_connection_retry, p, 0 /* set each time with tm_start */, 0 /* not randomized */);
+  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);
+
+  init_list(&p->tx_queue);
+  init_list(&p->rt_table_in_pre_policy.update_msg_queue);
+  p->started = false;
+
+  tm_start(p->connect_retry_timer, CONNECT_INIT_TIME);
+
+  return PS_START;
+}
+
+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_)
 {
   struct bmp_proto *p = bmp_;
-  ASSERT(p->started);
-
   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,
@@ -465,32 +571,37 @@ bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif(
     "There is not BGP proto related with stored TX/RX OPEN MSG"
   );
 
-  const struct bgp_proto *bgp;
-  memcpy(&bgp, map_bgp_proto->data.buf, sizeof (bgp));
-  if (bgp->p.proto_state == PS_UP)
+  struct bgp_proto *bgp_stored;
+  memcpy(&bgp_stored, map_bgp_proto->data.buf, sizeof (bgp_stored));
+
+  struct proto *P;
+  WALK_LIST(P, proto_list)
+  if ((P->proto == &proto_bgp) && (P->proto_state != PS_DOWN))
   {
-    bmp_send_peer_up_notif_msg(p, bgp, tx_msg, tx_msg_size,
-			       map_rx_msg->data.buf, map_rx_msg->data.buf_size);
+    struct bgp_proto *bgp = (void *) P;
+    if (bgp == bgp_stored)
+    {
+      bmp_send_peer_up_notif_msg(p, bgp, tx_msg, tx_msg_size,
+        map_rx_msg->data.buf, map_rx_msg->data.buf_size);
+      return;
+    }
   }
 }
 
 static void
-bmp_peer_up(const struct bgp_proto *bgp)
+bmp_peer_up(struct bmp_proto *p, const struct bgp_proto *bgp)
 {
+  TRACE(D_STATES, "peer up for %s", bgp->p.name);
   struct bgp_channel *c;
   WALK_LIST(c, bgp->p.channels)
-  {
-    bmp_route_monitor_pre_policy_table_in_snapshot((struct channel *) c);
-  }
+    bmp_route_monitor_pre_policy_table_in_snapshot(p, (struct channel *) c);
 }
 
 static const struct birdsock *
 bmp_get_birdsock(const struct bgp_proto *bgp)
 {
   if (bgp->conn && bgp->conn->sk)
-  {
     return bgp->conn->sk;
-  }
 
   return NULL;
 }
@@ -499,11 +610,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)
   {
@@ -521,9 +629,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;
 }
@@ -533,9 +639,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)
   {
@@ -560,10 +664,11 @@ 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);
+  if (!p->sk)
+    return; // Don't restart socket because this call could become from socket's callback
 
   const struct birdsock *sk = bmp_get_birdsock_ext(bgp);
   IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(
@@ -580,80 +685,113 @@ bmp_send_peer_up_notif_msg(struct bmp_proto *p, const struct bgp_proto *bgp,
   bmp_schedule_tx_packet(p, bmp_buffer_data(&payload), bmp_buffer_pos(&payload));
   bmp_buffer_free(&payload);
 
-  bmp_peer_up(bgp);
+  bmp_peer_up(p, bgp);
 }
 
-void
-bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt,
-  const size_t pkt_size)
+static void
+bmp_proto_put_sent_bgp_open_msg(struct bmp_proto *p, const struct bgp_proto *bgp,
+  const byte *pkt, const size_t pkt_size)
 {
-  struct bmp_proto *p = g_bmp;
 
-  if (!p)
-  {
+  if (!p || p->p.proto_state == PS_DOWN)
     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
+  struct bmp_peer_map_key key = bmp_peer_map_key_create(bgp->remote_ip,
+                                  bgp->remote_as);
+  const struct bmp_peer_map_entry *tx_map_entry
+    = bmp_peer_map_get(&p->peer_open_msg.tx_msg, key);
+  const struct bmp_peer_map_entry *rx_map_entry
     = bmp_peer_map_get(&p->peer_open_msg.rx_msg, key);
+  if (!tx_map_entry)
+    bmp_peer_map_insert(&p->peer_open_msg.tx_msg, key, pkt, pkt_size);
 
-  bmp_peer_map_insert(&p->peer_open_msg.tx_msg, key, pkt, pkt_size);
-
-  if (!rx_msg)
+  if (!tx_map_entry && !rx_map_entry)
+  {
     bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp));
+    // There is still missing TX or RX OPEN MSG
+    return;
+  }
 
-  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);
+  if (!rx_map_entry)
+    return;
+
+  bmp_send_peer_up_notif_msg(p, bgp, pkt, pkt_size, rx_map_entry->data.buf,
+			     rx_map_entry->data.buf_size);
 }
 
 void
-bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt,
+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;
+  struct proto *P = NULL;
+  WALK_LIST(P, proto_list)
+    if (P && P->proto == &proto_bmp)
+      bmp_proto_put_sent_bgp_open_msg((struct bmp_proto *) P, bgp, pkt, pkt_size);
+}
+
+static void
+bmp_proto_put_recv_bgp_open_msg(struct bmp_proto *p, const struct bgp_proto *bgp,
+  const byte *pkt, const size_t pkt_size)
+{
 
   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
+  const struct bmp_peer_map_entry *tx_map_entry
     = bmp_peer_map_get(&p->peer_open_msg.tx_msg, key);
+  const struct bmp_peer_map_entry *rx_map_entry
+    = bmp_peer_map_get(&p->peer_open_msg.rx_msg, key);
+  if (!rx_map_entry)
+    bmp_peer_map_insert(&p->peer_open_msg.rx_msg, key, pkt, pkt_size);
 
-  bmp_peer_map_insert(&p->peer_open_msg.rx_msg, key, pkt, pkt_size);
-
-  if (!tx_msg)
+  if (!tx_map_entry && !rx_map_entry)
+  {
     bmp_peer_map_insert(&p->bgp_peers, key, (const byte *) &bgp, sizeof (bgp));
+    // There is still missing TX or RX OPEN MSG
+    return;
+  }
+
+  if (!tx_map_entry)
+    return;
 
-  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);
+  bmp_send_peer_up_notif_msg(p, bgp, tx_map_entry->data.buf, tx_map_entry->data.buf_size,
+			     pkt, pkt_size);
 }
 
 void
-bmp_route_monitor_update_in_pre_begin()
+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;
+  struct proto *P = NULL;
+  WALK_LIST(P, proto_list)
+    if (P && P->proto == &proto_bmp && P->proto_state == PS_UP)
+      bmp_proto_put_recv_bgp_open_msg((struct bmp_proto *) P, bgp, pkt, pkt_size);
+}
 
-  if (!p || !p->started)
-  {
+void
+bmp_route_monitor_update_in_pre_begin(struct bmp_proto *p)
+{
+
+  if (!p || (p->p.proto_state == PS_DOWN))
     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"
-  );
+  if (p->p.proto_state != PS_UP)
+    return;
+
+  if (!EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue))
+  {
+    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);
+    }
+  }
 
   gettimeofday(&p->rt_table_in_pre_policy.update_begin_time,NULL);
   init_list(&p->rt_table_in_pre_policy.update_msg_queue);
@@ -662,26 +800,19 @@ bmp_route_monitor_update_in_pre_begin()
 }
 
 void
-bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size)
+bmp_route_monitor_put_update_in_pre_msg(struct bmp_proto *p, const byte *data, const size_t data_size)
 {
-  struct bmp_proto *p = g_bmp;
 
-  if (!p || !p->started)
-  {
+  if (!p || (p->p.proto_state == PS_DOWN))
     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"
-  );
+  if (!p->rt_table_in_pre_policy.update_in_progress)
+    return;
 
-  struct bmp_data_node *upd_msg = mb_alloc(p->update_msg_mem_pool,
+  struct bmp_data_node *upd_msg = mb_allocz(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);
@@ -691,19 +822,16 @@ 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_pre_commit(struct bmp_proto *p, const struct bgp_proto *bgp)
 {
-  struct bmp_proto *p = g_bmp;
-
-  if (!p || !p->started)
-  {
+  if (!p || (p->p.proto_state == PS_DOWN))
     return;
-  }
 
   if (p->monitoring_rib.in_pre_policy == false)
-  {
     return;
-  }
+
+  if (!bgp)
+    return;
 
   const struct birdsock *sk = bmp_get_birdsock(bgp);
   IF_PTR_IS_NULL_PRINT_ERR_MSG_AND_RETURN_OPT_VAL(
@@ -748,19 +876,16 @@ 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(struct bmp_proto *p)
 {
-  struct bmp_proto *p = g_bmp;
-
-  if (!p || !p->started)
-  {
+  if (!p || (p->p.proto_state == PS_DOWN))
     return;
-  }
 
   if (p->monitoring_rib.in_pre_policy == false)
-  {
     return;
-  }
+
+  if (EMPTY_LIST(p->rt_table_in_pre_policy.update_msg_queue))
+    return;
 
   struct bmp_data_node *upd_msg;
   struct bmp_data_node *upd_msg_next;
@@ -770,76 +895,111 @@ bmp_route_monitor_update_in_pre_end()
     rem_node((node *) upd_msg);
     mb_free(upd_msg);
   }
+}
+
+byte *
+bmp_create_end_mark(struct bmp_proto *p, struct bgp_channel *c, byte *buf)
+{
+  struct bgp_proto *bgp = (struct bgp_proto*) c->c.proto;
+  TRACE(D_PACKETS, "%s.%s Sending END-OF-RIB", bgp->p.name, c->c.name);
+
+  return (c->afi == BGP_AF_IPV4) ?
+    bgp_create_ip_end_mark(c, buf):
+    bgp_create_mp_end_mark(c, buf);
+}
+
+static void
+bmp_proto_route_monitor_empty_update_msg(struct bmp_proto *p, struct channel* C)
+{
+  if (!p || p->p.proto_state != PS_UP)
+      return;
+  bmp_route_monitor_update_in_pre_begin(p);
+  byte rx_end_payload[DEFAULT_MEM_BLOCK_SIZE];
+  byte *pos
+    = bmp_create_end_mark(p, (struct bgp_channel *) 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(p, rx_end_payload, pos - rx_end_payload);
+  bmp_route_monitor_update_in_pre_commit(p, (struct bgp_proto *) C->proto);
+  bmp_route_monitor_update_in_pre_end(p);
+}
+
+/**
+ * bmp_route_monitor_dump_fib - dump fib content for BMP init
+ * @n: network data - route table container
+ * @C: bgp protocol channel about to be monitored
+ *
+ * bmp_route_monitor_dump_fib() takes potential protocol fib and push it through bmp
+ * returns added 1 if rotues has been pushed
+ *
+ **/
+static int
+bmp_route_monitor_dump_fib(struct bmp_proto *p, net *n, struct channel *C) {
+    struct proto *P = NULL;
+    if (!n->routes || !n->routes->sender)
+      return 0;
+
+    P = n->routes->sender->proto;
+    if (P && P->proto && (P->proto->class != PROTOCOL_BGP))
+      return 0;
+
+    bmp_route_monitor_update_in_pre_begin(p);
+
+    rte *e;
+    for (e = n->routes; e; e = e->next)
+    {
+      if (!e->src)
+        continue;
+      if (C->proto && C->proto->rte_update_in_notify)
+        C->proto->rte_update_in_notify(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);
+    return 1;
+}
 
-  p->rt_table_in_pre_policy.update_in_progress = false;
+void
+bmp_route_monitor_empty_update_msg(struct channel *C)
+{
+  struct proto *P = NULL;
+  WALK_LIST(P, proto_list)
+    if (P && P->proto == &proto_bmp)
+      bmp_proto_route_monitor_empty_update_msg((struct bmp_proto *) P, C);
 }
 
 static void
-bmp_route_monitor_pre_policy_table_in_snapshot(struct channel *C)
+bmp_route_monitor_pre_policy_table_in_snapshot(struct bmp_proto *p, struct channel *C)
 {
-  struct bmp_proto *p = g_bmp;
+
+  if (!p)
+    return;
 
   if (p->monitoring_rib.in_pre_policy == false)
-  {
     return;
-  }
 
   struct rtable *tab = C->in_table;
   if (!tab)
-  {
     return;
-  }
 
   size_t cnt = 0;
-  struct proto *P;
   struct fib_iterator fit;
   memset(&fit, 0x00, sizeof (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;
-    }
-
-    bmp_route_monitor_update_in_pre_begin();
-
-    rte *e;
-    for (e = n->routes; e; e = e->next)
-    {
-      bgp_rte_update_in_notify(C, n->n.addr, e, e->src);
-    }
-
-    bmp_route_monitor_update_in_pre_commit((struct bgp_proto *) P);
-    bmp_route_monitor_update_in_pre_end();
-    ++cnt;
-  }
+    cnt += bmp_route_monitor_dump_fib(p, n, C);
   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((struct bgp_channel *) 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_end();
-  }
+    bmp_proto_route_monitor_empty_update_msg(p, 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);
-
   const struct bgp_caps *remote_caps = bmp_get_bgp_remote_caps_ext(bgp);
   bool is_global_instance_peer = bmp_is_peer_global_instance(bgp);
   buffer payload
@@ -853,30 +1013,26 @@ 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 *pkt,
+static void
+bmp_proto_peer_down(struct bmp_proto *p, const struct bgp_proto *bgp, const int err_class, const byte *pkt,
   size_t pkt_size)
 {
-  struct bmp_proto *p = g_bmp;
-
-  if (!p)
-  {
+  if (!p || (p->p.proto_state == PS_DOWN))
     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->peer_open_msg.tx_msg, key);
   bmp_peer_map_remove(&p->peer_open_msg.rx_msg, key);
+  if (!bmp_peer_map_get(&p->bgp_peers, key))
+    return;
+
   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)
-    return;
-
   buffer payload
     = bmp_buffer_alloc(p->buffer_mpool, pkt_size + missing_bgp_hdr_size + 1);
   if (pkt != NULL && pkt_size > 0)
@@ -893,7 +1049,7 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt,
     {
       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_u16(&payload, pkt_size + missing_bgp_hdr_size);
       bmp_put_u8(&payload, PKT_NOTIFICATION);
       bmp_put_data(&payload, pkt, pkt_size);
     }
@@ -914,14 +1070,27 @@ bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt,
   }
 
   bmp_send_peer_down_notif_msg(p, bgp, bmp_buffer_data(&payload), bmp_buffer_pos(&payload));
-
   bmp_buffer_free(&payload);
 }
 
+void bmp_peer_down(const struct bgp_proto *bgp, const int err_class, const byte *pkt,
+  size_t pkt_size)
+{
+  struct proto *P = NULL;
+  WALK_LIST(P, proto_list)
+    if (P && P->proto == &proto_bmp)
+      bmp_proto_peer_down((struct bmp_proto *) P, bgp, err_class, pkt, pkt_size);
+}
+
 static void
 bmp_send_termination_msg(struct bmp_proto *p,
   const enum bmp_term_reason reason)
 {
+  // Check tbuf in case when it is NULL when there has not been successfully
+  // connected to collector
+  if ((!p->sk) || (!p->sk->tbuf))
+    return;
+
   const size_t term_msg_hdr_size = BMP_TERM_INFO_TYPE_SIZE
                                      + BMP_TERM_INFO_LEN_FIELD_SIZE
                                      + BMP_TERM_REASON_CODE_SIZE;
@@ -952,7 +1121,6 @@ bmp_startup(struct bmp_proto *p)
 {
   ASSERT(!p->started);
   p->started = true;
-
   TRACE(D_EVENTS, "BMP session established");
 
   /* Send initiation message */
@@ -963,7 +1131,7 @@ bmp_startup(struct bmp_proto *p)
 
   /* 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);
+                        bmp_peer_map_walk_tx_open_msg_and_send_peer_up_notif, p);
 
   proto_notify_state(&p->p, PS_UP);
 }
@@ -985,45 +1153,12 @@ bmp_down(struct bmp_proto *p)
   proto_notify_state(&p->p, PS_START);
 }
 
-/**
- * bmp_connect - initiate an outgoing connection
- * @p: BMP instance
- *
- * The bmp_connect() function creates the socket and initiates an outgoing TCP
- * connection to the monitoring station. It is called to enter Connect state.
- */
-static void
-bmp_connect(struct bmp_proto *p)
-{
-  ASSERT(!p->started);
-
-  sock *sk = sk_new(p->p.pool);
-  sk->type = SK_TCP_ACTIVE;
-  sk->daddr = p->station_ip;
-  sk->dport = p->station_port;
-  sk->ttl = IP4_MAX_TTL;
-  sk->tos = IP_PREC_INTERNET_CONTROL;
-  sk->tbsize = BGP_TX_BUFFER_EXT_SIZE;
-  sk->tx_hook = bmp_connected;
-  sk->err_hook = bmp_sock_err;
-
-  p->sk = sk;
-  sk->data = p;
-
-  int rc = sk_open(sk);
-
-  if (rc < 0)
-    sk_log_error(sk, p->p.name);
-
-  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)
 {
   struct bmp_proto *p = (void *) sk->data;
-
+  TRACE(D_EVENTS, "Station connected from %I to %I", sk->saddr, sk->daddr);
   sk->rx_hook = bmp_rx;
   sk->tx_hook = bmp_tx;
   tm_stop(p->connect_retry_timer);
@@ -1031,44 +1166,48 @@ bmp_connected(struct birdsock *sk)
   bmp_startup(p);
 }
 
-/* BMP socket error event - switch from any state to Idle state */
-static void
+/*  BMP socket error event - switch from any state to Idle state */
+void
 bmp_sock_err(sock *sk, int err)
 {
-  struct bmp_proto *p = sk->data;
+  struct bmp_proto *p = sk ? sk->data : NULL;
+  if (!p)
+    return;
+
+  // Check if err_hook has not been called synchronously from sk_send()
+  // or other bmp_*() code
 
   if (err)
-    TRACE(D_EVENTS, "Connection lost (%M)", err);
+      TRACE(D_EVENTS, "Connection lost (%M)", err);
   else
-    TRACE(D_EVENTS, "Connection closed");
+      TRACE(D_EVENTS, "Connection closed");
 
   if (p->started)
-    bmp_down(p);
+      bmp_down(p);
 
   bmp_close_socket(p);
   tm_start(p->connect_retry_timer, CONNECT_RETRY_TIME);
-}
-
-/* BMP connect timeout event - switch from Idle/Connect state to Connect state */
-static void
-bmp_connection_retry(timer *t)
-{
-  struct bmp_proto *p = t->data;
 
-  if (p->started)
-    return;
+  p->sock_err = err;
 
-  bmp_close_socket(p);
-  bmp_connect(p);
 }
 
-static void
-bmp_close_socket(struct bmp_proto *p)
+// Configure socket only with static values
+void
+bmp_setup_socket(struct bmp_proto *p)
 {
-  rfree(p->sk);
-  p->sk = NULL;
-}
+  sock *sk = sk_new(p->tx_mem_pool);
+  sk->type = SK_TCP_ACTIVE;
+  sk->ttl = IP4_MAX_TTL;
+  sk->tos = IP_PREC_INTERNET_CONTROL;
+  sk->tbsize = BGP_TX_BUFFER_EXT_SIZE;
+  sk->tos = IP_PREC_INTERNET_CONTROL;
+  sk->err_hook = bmp_sock_err;
+  sk->tx_hook = bmp_connected;
 
+  p->sk = sk;
+  sk->data = p;
+}
 
 /** Configuration handle section **/
 static struct proto *
@@ -1077,81 +1216,100 @@ 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->src_local_addr = cf->src_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;
+  p->sock_err = NO_SOCK_ERROR;
 
   return P;
 }
 
-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");
-  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->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);
-
-  init_list(&p->tx_queue);
-  init_list(&p->rt_table_in_pre_policy.update_msg_queue);
-  p->started = false;
-
-  tm_start(p->connect_retry_timer, CONNECT_INIT_TIME);
-
-  g_bmp = p;
-
-  return PS_START;
-}
-
 static int
 bmp_shutdown(struct proto *P)
 {
   struct bmp_proto *p = (void *) P;
-
   if (p->started)
   {
     bmp_send_termination_msg(p, BMP_TERM_REASON_ADM);
     p->started = false;
   }
-
-  g_bmp = NULL;
-
   return PS_DOWN;
 }
 
 static int
-bmp_reconfigure(struct proto *P, struct proto_config *CF)
+bmp_reconfigure(struct proto *P, struct proto_config *CF UNUSED)
 {
   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;
+
+  int needs_restart = bstrcmp(new->sys_descr, old->sys_descr)
+    || bstrcmp(new->sys_name, old->sys_name)
+    || !ipa_equal(new->src_local_addr, old->src_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);
+
+  // We need to replace config struct in protocol as old config would be freed
+  p->cf = new;
+  if (!needs_restart)
+    return SUCCESSFUL_RECONF;
+
+  p->src_local_addr = new->src_local_addr;
+  p->station_ip = new->station_ip;
+  p->station_port = new->station_port;
+  strncpy(p->sys_descr, new->sys_descr, MIB_II_STR_LEN - 1);
+  p->sys_descr[MIB_II_STR_LEN - 1] = NULL_TERM_CHAR;
+  strncpy(p->sys_name, new->sys_name, MIB_II_STR_LEN - 1);
+  p->sys_name[MIB_II_STR_LEN - 1] = NULL_TERM_CHAR;
+  p->monitoring_rib.in_pre_policy = new->monitoring_rib_in_pre_policy;
+
+  bmp_send_termination_msg(p, BMP_TERM_REASON_ADM);
+  p->started = false;
+  bmp_sock_err(p->sk, FORCE_SOCKET_RESTART);
 
-  log(L_WARN "Reconfiguring BMP is not supported");
+  return SUCCESSFUL_RECONF;
+}
 
-  p->cf = cf;
+static void
+bmp_get_status(struct proto *P, byte *buf)
+{
+  struct bmp_proto *p = (struct bmp_proto *) P;
+  if (P->proto_state == PS_START)
+    if (p->sock_err != NO_SOCK_ERROR)
+      bsprintf(buf, "Socket: %M", p->sock_err);
+    else
+      bsprintf(buf, "No connection");
+  if (P->proto_state == PS_UP)
+      if (p->sk && p->sk->err)
+          bsprintf(buf, "%-14s%s" "Socket err:", p->sk->err);
+      else if (!p->sk)
+          bsprintf(buf, "%-14s%s", "Connect", "No active socket");
+   if (P->proto_state == PS_DOWN)
+       bsprintf(buf, "Down");
+}
+
+static void
+bmp_show_proto_info(struct proto *P)
+{
+  struct bmp_proto *p = (struct bmp_proto *) P;
+  if (P->proto_state != PS_DOWN)
+  {
+    cli_msg(-1006, "  %-38s%I:%u", "Station address/port:", p->station_ip, p->station_port);
+    if (!ipa_zero2(p->src_local_addr))
+      cli_msg(-1006, "  %-38s%I", "Source local address:", p->src_local_addr);
 
-  return 1;
+    cli_msg(-1006, "  %-38s%s", "Monitoring pre-policy Adj-RIB-In:",
+      p->cf->monitoring_rib_in_pre_policy ? "True" : "False");
+  }
 }
 
 struct protocol proto_bmp = {
   .name = "BMP",
-  .template = "bmp%d",
   .class = PROTOCOL_BMP,
   .proto_size = sizeof(struct bmp_proto),
   .config_size = sizeof(struct bmp_config),
@@ -1159,10 +1317,11 @@ 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
-bmp_build(void)
-{
+bmp_build(void) {
   proto_build(&proto_bmp);
 }
diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h
index 19623e33..4cf551ff 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 src_local_addr;             // Source 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 */
@@ -65,9 +64,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 src_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;
@@ -81,6 +81,7 @@ struct bmp_proto {
   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
+  int sock_err;                    // Last socket error code
   bool started;                    // Flag that stores running status of BMP instance
 };
 
@@ -94,7 +95,7 @@ struct bmp_proto {
  *       message to the BMP collector.
  */
 void
-bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt,
+bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte *pkt,
   const size_t pkt_size);
 
 /**
@@ -104,9 +105,14 @@ bmp_put_sent_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt,
  *       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_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte *pkt,
+                          const size_t pkt_size);
 
+/**
+ * bmp_route_monitor_empty_update_msg - generate End-Of-RIB mesage encapsulated with BMP Monitoring
+ */
+void
+bmp_route_monitor_empty_update_msg(struct channel *C);
 /**
  * The following 4 functions create BMP Route Monitoring message based on
  * pre-policy Adj-RIB-In. Composing Route Monitoring message consist of few
@@ -118,34 +124,33 @@ bmp_put_recv_bgp_open_msg(const struct bgp_proto *bgp, const byte* pkt,
  * call bmp_route_monitor_update_in_pre_end() in order to release resources.
  */
 void
-bmp_route_monitor_update_in_pre_begin(void);
+bmp_route_monitor_update_in_pre_begin(struct bmp_proto *p);
 
 void
-bmp_route_monitor_put_update_in_pre_msg(const byte *data, const size_t data_size);
+bmp_route_monitor_put_update_in_pre_msg(struct bmp_proto *p, 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_pre_commit(struct bmp_proto *p, const struct bgp_proto *bgp);
 
 void
-bmp_route_monitor_update_in_pre_end(void);
+bmp_route_monitor_update_in_pre_end(struct bmp_proto *p);
 
 /**
  * bmp_peer_down - send notification that BGP peer connection is not in
  * 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, const int err_class,
+              const byte *pkt, size_t pkt_size);
 
 #else /* BMP build disabled */
-
+static inline void bmp_route_monitor_empty_update_msg(struct channel *C UNUSED) {}
 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_route_monitor_update_in_pre_begin(void) { }
+static inline void bmp_route_monitor_update_in_pre_begin(struct bmp_proto *p UNUSED) { }
 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_route_monitor_update_in_pre_commit(struct bmp_proto *p UNUSED, const struct bgp_proto *bgp UNUSED) { }
+static inline void bmp_route_monitor_update_in_pre_end(struct bmp_proto *p 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) { }
 
 #endif /* CONFIG_BMP */
diff --git a/proto/bmp/buffer.c b/proto/bmp/buffer.c
index f471e08a..9555a6cf 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;
 }
 
@@ -26,13 +25,20 @@ bmp_buffer_free(buffer *buf)
   buf->start = buf->pos = buf->end = NULL;
 }
 
+/**
+ * @brief bmp_buffer_grow
+ * @param buf - buffer to grow
+ * @param n   - size of buffer, which should be added to current buffer
+ * Resulted buffer has new size = size + n
+ */
 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);
+  const size_t new_size = bmp_buffer_size(buf) + n;
+  buf->start = mb_realloc(buf->start, new_size);
   buf->pos = buf->start + pos;
-  buf->end = buf->start + n;
+  buf->end = buf->start + new_size;
 }
 
 void
@@ -55,4 +61,4 @@ bmp_put_data(buffer *buf, const void *src, const size_t n)
   bmp_buffer_need(buf, n);
   memcpy(buf->pos, src, n);
   buf->pos += n;
-}
\ No newline at end of file
+}
diff --git a/proto/bmp/config.Y b/proto/bmp/config.Y
index 776d7ecc..eec45b1c 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->src_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,10 @@ bmp_station_address:
 bmp_proto:
    bmp_proto_start proto_name '{'
  | bmp_proto proto_item ';'
+ | bmp_proto SOURCE LOCAL ADDRESS ipa ';' {
+     if (ipa_nonzero($5))
+       BMP_CFG->src_local_addr = $5;
+   }
  | bmp_proto STATION ADDRESS bmp_station_address ';'
  | bmp_proto SYSTEM DESCRIPTION text ';' {
      if (!$4 || (strlen($4) == 0))
@@ -70,12 +73,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
-- 
2.39.2

