summaryrefslogtreecommitdiff
path: root/bgpd
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2025-01-14 08:38:37 -0500
committerGitHub <noreply@github.com>2025-01-14 08:38:37 -0500
commitb4619da9388759cd718e61e8b89b814b60021a18 (patch)
tree1af2c6ac25f4d7107ef246477e0861e61a2f5a58 /bgpd
parentba4122d6dbc641e7549e947ed420301939e48529 (diff)
parent9f2932d106c2cb04b5510cc905122516cc397cfd (diff)
Merge pull request #17639 from pguibert6WIND/bmp_import_vrf_view
Ability to import BMP information from a separate BGP instance
Diffstat (limited to 'bgpd')
-rw-r--r--bgpd/bgp_bmp.c801
-rw-r--r--bgpd/bgp_bmp.h20
-rw-r--r--bgpd/bgp_trace.h3
3 files changed, 634 insertions, 190 deletions
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 036bece359..680eaae47a 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -50,6 +50,12 @@ static struct bmp_bgp_peer *bmp_bgp_peer_find(uint64_t peerid);
static struct bmp_bgp_peer *bmp_bgp_peer_get(struct peer *peer);
static void bmp_active_disconnected(struct bmp_active *ba);
static void bmp_active_put(struct bmp_active *ba);
+static int bmp_route_update_bgpbmp(struct bmp_targets *bt, afi_t afi, safi_t safi,
+ struct bgp_dest *bn, struct bgp_path_info *old_route,
+ struct bgp_path_info *new_route);
+static void bmp_send_all_bgp(struct peer *peer, bool down);
+static struct bmp_imported_bgp *bmp_imported_bgp_find(struct bmp_targets *bt, char *name);
+static void bmp_stats_per_instance(struct bgp *bgp, struct bmp_targets *bt);
DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)");
@@ -64,6 +70,7 @@ DEFINE_MTYPE_STATIC(BMP, BMP, "BMP instance state");
DEFINE_MTYPE_STATIC(BMP, BMP_MIRRORQ, "BMP route mirroring buffer");
DEFINE_MTYPE_STATIC(BMP, BMP_PEER, "BMP per BGP peer data");
DEFINE_MTYPE_STATIC(BMP, BMP_OPEN, "BMP stored BGP OPEN message");
+DEFINE_MTYPE_STATIC(BMP, BMP_IMPORTED_BGP, "BMP imported BGP instance");
DEFINE_QOBJ_TYPE(bmp_targets);
@@ -141,6 +148,17 @@ static int bmp_targets_cmp(const struct bmp_targets *a,
DECLARE_SORTLIST_UNIQ(bmp_targets, struct bmp_targets, bti, bmp_targets_cmp);
+static int bmp_imported_bgps_cmp(const struct bmp_imported_bgp *a, const struct bmp_imported_bgp *b)
+{
+ if (a->name == NULL && b->name == NULL)
+ return 0;
+ if (a->name == NULL || b->name == NULL)
+ return 1;
+ return strcmp(a->name, b->name);
+}
+
+DECLARE_SORTLIST_UNIQ(bmp_imported_bgps, struct bmp_imported_bgp, bib, bmp_imported_bgps_cmp);
+
DECLARE_LIST(bmp_session, struct bmp, bsi);
DECLARE_DLIST(bmp_qlist, struct bmp_queue_entry, bli);
@@ -228,6 +246,7 @@ static struct bmp *bmp_new(struct bmp_targets *bt, int bmp_sock)
new->targets = bt;
new->socket = bmp_sock;
new->syncafi = AFI_MAX;
+ new->sync_bgp = NULL;
FOREACH_AFI_SAFI (afi, safi) {
new->afistate[afi][safi] = bt->afimon[afi][safi]
@@ -399,14 +418,17 @@ static void bmp_put_info_tlv(struct stream *s, uint16_t type,
/* put the vrf table name of the bgp instance bmp is bound to in a tlv on the
* stream
*/
-static void bmp_put_vrftablename_info_tlv(struct stream *s, struct bgp *bgp)
+static void bmp_put_vrftablename_info_tlv(struct stream *s, struct peer *peer)
{
const char *vrftablename = "global";
+ struct vrf *vrf;
#define BMP_INFO_TYPE_VRFTABLENAME 3
- if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT)
- vrftablename = bgp->name;
+ if (peer->bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
+ vrf = vrf_lookup_by_id(peer->bgp->vrf_id);
+ vrftablename = vrf ? vrf->name : NULL;
+ }
if (vrftablename != NULL)
bmp_put_info_tlv(s, BMP_INFO_TYPE_VRFTABLENAME, vrftablename);
@@ -590,63 +612,123 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
}
if (is_locrib)
- bmp_put_vrftablename_info_tlv(s, peer->bgp);
+ bmp_put_vrftablename_info_tlv(s, peer);
len = stream_get_endp(s);
stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */
return s;
}
-
-static int bmp_send_peerup(struct bmp *bmp)
+static int bmp_send_peerup_per_instance(struct bmp *bmp, struct bgp *bgp)
{
struct peer *peer;
struct listnode *node;
struct stream *s;
/* Walk down all peers */
- for (ALL_LIST_ELEMENTS_RO(bmp->targets->bgp->peer, node, peer)) {
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
s = bmp_peerstate(peer, false);
if (s) {
pullwr_write_stream(bmp->pullwr, s);
stream_free(s);
}
}
+ return 0;
+}
+
+static int bmp_send_peerup(struct bmp *bmp)
+{
+ struct bmp_imported_bgp *bib;
+ struct bgp *bgp;
+
+ bmp_send_peerup_per_instance(bmp, bmp->targets->bgp);
+ frr_each (bmp_imported_bgps, &bmp->targets->imported_bgps, bib) {
+ bgp = bgp_lookup_by_name(bib->name);
+ if (bgp)
+ bmp_send_peerup_per_instance(bmp, bgp);
+ }
return 0;
}
-static int bmp_send_peerup_vrf(struct bmp *bmp)
+static void bmp_send_peerup_vrf_per_instance(struct bmp *bmp, enum bmp_vrf_state *vrf_state,
+ struct bgp *bgp)
{
- struct bmp_bgp *bmpbgp = bmp->targets->bmpbgp;
struct stream *s;
/* send unconditionally because state may has been set before the
* session was up. and in this case the peer up has not been sent.
*/
- bmp_bgp_update_vrf_status(bmpbgp, vrf_state_unknown);
+ bmp_bgp_update_vrf_status(vrf_state, bgp, vrf_state_unknown);
- s = bmp_peerstate(bmpbgp->bgp->peer_self, bmpbgp->vrf_state == vrf_state_down);
+ s = bmp_peerstate(bgp->peer_self, *vrf_state == vrf_state_down);
if (s) {
pullwr_write_stream(bmp->pullwr, s);
stream_free(s);
}
+}
+
+static int bmp_send_peerup_vrf(struct bmp *bmp)
+{
+ struct bgp *bgp;
+ struct bmp_imported_bgp *bib;
+ struct bmp_bgp *bmpbgp = bmp->targets->bmpbgp;
+ struct bmp_targets *bt;
+
+ bmp_send_peerup_vrf_per_instance(bmp, &bmpbgp->vrf_state, bmpbgp->bgp);
+
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ frr_each (bmp_imported_bgps, &bt->imported_bgps, bib) {
+ bgp = bgp_lookup_by_name(bib->name);
+ if (!bgp)
+ continue;
+ bmp_send_peerup_vrf_per_instance(bmp, &bib->vrf_state, bgp);
+ }
+ }
return 0;
}
+static void bmp_send_bt(struct bmp_targets *bt, struct stream *s)
+{
+ struct bmp *bmp;
+
+ frr_each (bmp_session, &bt->sessions, bmp)
+ pullwr_write_stream(bmp->pullwr, s);
+}
+
+static void bmp_send_bt_safe(struct bmp_targets *bt, struct stream *s)
+{
+ if (!s)
+ return;
+
+ bmp_send_bt(bt, s);
+
+ stream_free(s);
+}
+
+static void bmp_send_peerdown_vrf_per_instance(struct bmp_targets *bt, struct bgp *bgp)
+{
+ struct stream *s;
+
+ s = bmp_peerstate(bgp->peer_self, true);
+ if (!s)
+ return;
+ bmp_send_bt(bt, s);
+ stream_free(s);
+}
+
/* send a stream to all bmp sessions configured in a bgp instance */
/* XXX: kludge - filling the pullwr's buffer */
static void bmp_send_all(struct bmp_bgp *bmpbgp, struct stream *s)
{
struct bmp_targets *bt;
- struct bmp *bmp;
if (!s)
return;
frr_each(bmp_targets, &bmpbgp->targets, bt)
- frr_each(bmp_session, &bt->sessions, bmp)
- pullwr_write_stream(bmp->pullwr, s);
+ bmp_send_bt(bt, s);
+
stream_free(s);
}
@@ -725,11 +807,13 @@ static void bmp_mirror_cull(struct bmp_bgp *bmpbgp)
static int bmp_mirror_packet(struct peer *peer, uint8_t type, bgp_size_t size,
struct stream *packet)
{
- struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
+ struct bmp_bgp *bmpbgp;
struct timeval tv;
- struct bmp_mirrorq *qitem;
+ struct bmp_mirrorq *qitem = NULL;
struct bmp_targets *bt;
struct bmp *bmp;
+ struct bgp *bgp_vrf;
+ struct listnode *node;
frrtrace(3, frr_bgp, bmp_mirror_packet, peer, type, packet);
@@ -745,8 +829,6 @@ static int bmp_mirror_packet(struct peer *peer, uint8_t type, bgp_size_t size,
memcpy(bbpeer->open_rx, packet->data, size);
}
- if (!bmpbgp)
- return 0;
qitem = XCALLOC(MTYPE_BMP_MIRRORQ, sizeof(*qitem) + size);
qitem->peerid = peer->qobj_node.nid;
@@ -754,27 +836,41 @@ static int bmp_mirror_packet(struct peer *peer, uint8_t type, bgp_size_t size,
qitem->len = size;
memcpy(qitem->data, packet->data, size);
- frr_each(bmp_targets, &bmpbgp->targets, bt) {
- if (!bt->mirror)
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+ bmpbgp = bmp_bgp_find(bgp_vrf);
+ if (!bmpbgp)
continue;
- frr_each(bmp_session, &bt->sessions, bmp) {
- qitem->refcount++;
- if (!bmp->mirrorpos)
- bmp->mirrorpos = qitem;
- pullwr_bump(bmp->pullwr);
- }
- }
- if (qitem->refcount == 0)
- XFREE(MTYPE_BMP_MIRRORQ, qitem);
- else {
- bmpbgp->mirror_qsize += sizeof(*qitem) + size;
- bmp_mirrorq_add_tail(&bmpbgp->mirrorq, qitem);
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ if (!bt->mirror)
+ continue;
+
+ if (bgp_vrf != peer->bgp && !bmp_imported_bgp_find(bt, peer->bgp->name))
+ continue;
+
+ frr_each (bmp_session, &bt->sessions, bmp) {
+ if (!qitem) {
+ qitem = XCALLOC(MTYPE_BMP_MIRRORQ, sizeof(*qitem) + size);
+ qitem->peerid = peer->qobj_node.nid;
+ qitem->tv = tv;
+ qitem->len = size;
+ memcpy(qitem->data, packet->data, size);
+ }
+
+ qitem->refcount++;
+ if (!bmp->mirrorpos)
+ bmp->mirrorpos = qitem;
+ pullwr_bump(bmp->pullwr);
+ }
+ bmpbgp->mirror_qsize += sizeof(*qitem) + size;
+ bmp_mirrorq_add_tail(&bmpbgp->mirrorq, qitem);
- bmp_mirror_cull(bmpbgp);
+ bmp_mirror_cull(bmpbgp);
- bmpbgp->mirror_qsizemax = MAX(bmpbgp->mirror_qsizemax,
- bmpbgp->mirror_qsize);
+ bmpbgp->mirror_qsizemax = MAX(bmpbgp->mirror_qsizemax, bmpbgp->mirror_qsize);
+ }
}
+ if (qitem && qitem->refcount == 0)
+ XFREE(MTYPE_BMP_MIRRORQ, qitem);
return 0;
}
@@ -847,8 +943,7 @@ static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr)
s = stream_new(BGP_MAX_PACKET_SIZE);
bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING);
- bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0, peer_type_flag, peer_distinguisher,
- &bmq->tv);
+ bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type_flag, peer_distinguisher, &bmq->tv);
/* BMP Mirror TLV. */
stream_putw(s, BMP_MIRROR_TLV_TYPE_BGP_MESSAGE);
@@ -887,14 +982,10 @@ static int bmp_outgoing_packet(struct peer *peer, uint8_t type, bgp_size_t size,
static int bmp_peer_status_changed(struct peer *peer)
{
- struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
struct bmp_bgp_peer *bbpeer, *bbdopp;
frrtrace(1, frr_bgp, bmp_peer_status_changed, peer);
- if (!bmpbgp)
- return 0;
-
if (peer->connection->status == Deleted) {
bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
if (bbpeer) {
@@ -929,20 +1020,16 @@ static int bmp_peer_status_changed(struct peer *peer)
}
}
- bmp_send_all_safe(bmpbgp, bmp_peerstate(peer, false));
+ bmp_send_all_bgp(peer, false);
return 0;
}
static int bmp_peer_backward(struct peer *peer)
{
- struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
struct bmp_bgp_peer *bbpeer;
frrtrace(1, frr_bgp, bmp_peer_backward_transition, peer);
- if (!bmpbgp)
- return 0;
-
bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid);
if (bbpeer) {
XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
@@ -951,12 +1038,12 @@ static int bmp_peer_backward(struct peer *peer)
bbpeer->open_rx_len = 0;
}
- bmp_send_all_safe(bmpbgp, bmp_peerstate(peer, true));
+ bmp_send_all_bgp(peer, true);
return 0;
}
-static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags,
- uint8_t peer_type_flag)
+static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags, uint8_t peer_type_flag,
+ struct bgp *bgp)
{
struct peer *peer;
struct listnode *node;
@@ -964,7 +1051,7 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags,
iana_afi_t pkt_afi = IANA_AFI_IPV4;
iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
- frrtrace(4, frr_bgp, bmp_eor, afi, safi, flags, peer_type_flag);
+ frrtrace(5, frr_bgp, bmp_eor, afi, safi, flags, peer_type_flag, bgp);
s = stream_new(BGP_MAX_PACKET_SIZE);
@@ -992,7 +1079,7 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags,
bgp_packet_set_size(s);
- for (ALL_LIST_ELEMENTS_RO(bmp->targets->bgp->peer, node, peer)) {
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
if (!peer->afc_nego[afi][safi])
continue;
@@ -1009,8 +1096,7 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags,
bmp_common_hdr(s2, BMP_VERSION_3,
BMP_TYPE_ROUTE_MONITORING);
- bmp_per_peer_hdr(s2, bmp->targets->bgp, peer, flags,
- peer_type_flag, peer_distinguisher, NULL);
+ bmp_per_peer_hdr(s2, bgp, peer, flags, peer_type_flag, peer_distinguisher, NULL);
stream_putl_at(s2, BMP_LENGTH_POS,
stream_get_endp(s) + stream_get_endp(s2));
@@ -1141,8 +1227,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
hdr = stream_new(BGP_MAX_PACKET_SIZE);
bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING);
- bmp_per_peer_hdr(hdr, bmp->targets->bgp, peer, flags, peer_type_flag,
- peer_distinguisher,
+ bmp_per_peer_hdr(hdr, peer->bgp, peer, flags, peer_type_flag, peer_distinguisher,
uptime == (time_t)(-1L) ? NULL : &uptime_real);
stream_putl_at(hdr, BMP_LENGTH_POS,
@@ -1155,6 +1240,93 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
stream_free(msg);
}
+static struct bgp *bmp_get_next_bgp(struct bmp_targets *bt, struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ struct bmp_imported_bgp *bib;
+ struct bgp *bgp_inst;
+ bool get_first = false;
+
+ if (bgp == NULL && bt->bgp_request_sync[afi][safi])
+ return bt->bgp;
+ if (bgp == NULL)
+ get_first = true;
+ frr_each (bmp_imported_bgps, &bt->imported_bgps, bib) {
+ bgp_inst = bgp_lookup_by_name(bib->name);
+ if (get_first && bgp_inst && bib->bgp_request_sync[afi][safi])
+ return bgp_inst;
+ if (bgp_inst == bgp)
+ get_first = true;
+ }
+ return NULL;
+}
+
+static void bmp_update_syncro(struct bmp *bmp, afi_t afi, safi_t safi, struct bgp *bgp)
+{
+ struct bmp_imported_bgp *bib;
+
+ if (bmp->syncafi == afi && bmp->syncsafi == safi) {
+ bmp->syncafi = AFI_MAX;
+ bmp->syncsafi = SAFI_MAX;
+ bmp->sync_bgp = NULL;
+ }
+
+ if (!bmp->targets->afimon[afi][safi]) {
+ bmp->afistate[afi][safi] = BMP_AFI_INACTIVE;
+ return;
+ }
+
+ bmp->afistate[afi][safi] = BMP_AFI_NEEDSYNC;
+
+ if (bgp == NULL || bmp->targets->bgp == bgp)
+ bmp->targets->bgp_request_sync[afi][safi] = true;
+
+ frr_each (bmp_imported_bgps, &bmp->targets->imported_bgps, bib) {
+ if (bgp != NULL && bgp_lookup_by_name(bib->name) != bgp)
+ continue;
+ bib->bgp_request_sync[afi][safi] = true;
+ }
+}
+
+static void bmp_update_syncro_set(struct bmp *bmp, afi_t afi, safi_t safi, struct bgp *bgp,
+ enum bmp_afi_state state)
+{
+ struct bmp_imported_bgp *bib;
+
+ bmp->afistate[afi][safi] = state;
+ bmp->syncafi = AFI_MAX;
+ bmp->syncsafi = SAFI_MAX;
+ if (bgp == NULL || bmp->targets->bgp == bmp->sync_bgp)
+ bmp->targets->bgp_request_sync[afi][safi] = false;
+
+ frr_each (bmp_imported_bgps, &bmp->targets->imported_bgps, bib) {
+ if (bgp == NULL || bgp_lookup_by_name(bib->name) != bmp->sync_bgp)
+ continue;
+ bib->bgp_request_sync[afi][safi] = false;
+ }
+}
+
+static void bmp_eor_afi_safi(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t peer_type_flag)
+{
+ struct bgp *sync_bgp;
+
+ zlog_info("bmp[%s] %s %s table completed (EoR) (BGP %s)", bmp->remote, afi2str(afi),
+ safi2str(safi), bmp->sync_bgp->name_pretty);
+
+ bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L, peer_type_flag, bmp->sync_bgp);
+ bmp_eor(bmp, afi, safi, 0, peer_type_flag, bmp->sync_bgp);
+ bmp_eor(bmp, afi, safi, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, bmp->sync_bgp);
+
+ sync_bgp = bmp_get_next_bgp(bmp->targets, bmp->sync_bgp, afi, safi);
+ if (sync_bgp) {
+ memset(&bmp->syncpos, 0, sizeof(bmp->syncpos));
+ bmp->syncpos.family = afi2family(afi);
+ bmp->syncrdpos = NULL;
+ bmp->syncpeerid = 0;
+ } else
+ bmp_update_syncro_set(bmp, afi, safi, bmp->sync_bgp, BMP_AFI_LIVE);
+ bmp->sync_bgp = sync_bgp;
+}
+
static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
{
uint8_t bpi_num_labels, adjin_num_labels;
@@ -1175,10 +1347,13 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr)
memset(&bmp->syncpos, 0, sizeof(bmp->syncpos));
bmp->syncpos.family = afi2family(afi);
bmp->syncrdpos = NULL;
- zlog_info("bmp[%s] %s %s sending table",
- bmp->remote,
- afi2str(bmp->syncafi),
- safi2str(bmp->syncsafi));
+ bmp->sync_bgp = bmp_get_next_bgp(bmp->targets, NULL, afi, safi);
+ if (bmp->sync_bgp == NULL)
+ /* all BGP instances already synced*/
+ return true;
+ zlog_info("bmp[%s] %s %s sending table (BGP %s)", bmp->remote,
+ afi2str(bmp->syncafi), safi2str(bmp->syncsafi),
+ bmp->sync_bgp->name_pretty);
/* break does not work here, 2 loops... */
goto afibreak;
}
@@ -1192,18 +1367,22 @@ afibreak:
if (!bmp->targets->afimon[afi][safi]) {
/* shouldn't happen */
- bmp->afistate[afi][safi] = BMP_AFI_INACTIVE;
- bmp->syncafi = AFI_MAX;
- bmp->syncsafi = SAFI_MAX;
+ bmp_update_syncro_set(bmp, afi, safi, bmp->sync_bgp, BMP_AFI_INACTIVE);
+ bmp->sync_bgp = NULL;
return true;
}
+ if (bmp->sync_bgp == NULL) {
+ bmp->sync_bgp = bmp_get_next_bgp(bmp->targets, NULL, afi, safi);
+ if (bmp->sync_bgp == NULL)
+ return true;
+ }
- struct bgp_table *table = bmp->targets->bgp->rib[afi][safi];
+ struct bgp_table *table = bmp->sync_bgp->rib[afi][safi];
struct bgp_dest *bn = NULL;
struct bgp_path_info *bpi = NULL, *bpiter;
struct bgp_adj_in *adjin = NULL, *adjiter;
- peer_type_flag = bmp_get_peer_type_vrf(bmp->targets->bgp->vrf_id);
+ peer_type_flag = bmp_get_peer_type_vrf(bmp->sync_bgp->vrf_id);
if ((afi == AFI_L2VPN && safi == SAFI_EVPN) ||
(safi == SAFI_MPLS_VPN)) {
@@ -1255,19 +1434,9 @@ afibreak:
return true;
}
eor:
- zlog_info("bmp[%s] %s %s table completed (EoR)",
- bmp->remote, afi2str(afi),
- safi2str(safi));
-
- bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L, peer_type_flag);
- bmp_eor(bmp, afi, safi, 0, peer_type_flag);
- bmp_eor(bmp, afi, safi, 0,
- BMP_PEER_TYPE_LOC_RIB_INSTANCE);
-
- bmp->afistate[afi][safi] = BMP_AFI_LIVE;
- bmp->syncafi = AFI_MAX;
- bmp->syncsafi = SAFI_MAX;
- return true;
+ bmp_eor_afi_safi(bmp, afi, safi,
+ peer_type_flag);
+ return true;
}
bmp->syncpeerid = 0;
prefix_copy(&bmp->syncpos, bgp_dest_get_prefix(bn));
@@ -1446,7 +1615,7 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr)
*/
goto out;
}
- if (peer != bmp->targets->bgp->peer_self && !peer_established(peer->connection)) {
+ if (peer != peer->bgp->peer_self && !peer_established(peer->connection)) {
/* peer is neither self, nor established
*/
goto out;
@@ -1457,8 +1626,7 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr)
struct prefix_rd *prd = is_vpn ? &bqe->rd : NULL;
- bn = bgp_safi_node_lookup(bmp->targets->bgp->rib[afi][safi], safi,
- &bqe->p, prd);
+ bn = bgp_safi_node_lookup(peer->bgp->rib[afi][safi], safi, &bqe->p, prd);
struct bgp_path_info *bpi;
@@ -1534,8 +1702,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
(bqe->safi == SAFI_MPLS_VPN);
struct prefix_rd *prd = is_vpn ? &bqe->rd : NULL;
- bn = bgp_safi_node_lookup(bmp->targets->bgp->rib[afi][safi], safi,
- &bqe->p, prd);
+ bn = bgp_safi_node_lookup(peer->bgp->rib[afi][safi], safi, &bqe->p, prd);
peer_type_flag = bmp_get_peer_type(peer);
@@ -1585,11 +1752,16 @@ out:
static void bmp_wrfill(struct bmp *bmp, struct pullwr *pullwr)
{
+ afi_t afi;
+ safi_t safi;
+
switch(bmp->state) {
case BMP_PeerUp:
bmp_send_peerup_vrf(bmp);
bmp_send_peerup(bmp);
bmp->state = BMP_Run;
+ FOREACH_AFI_SAFI (afi, safi)
+ bmp_update_syncro(bmp, afi, safi, NULL);
break;
case BMP_Run:
@@ -1667,9 +1839,12 @@ bmp_process_one(struct bmp_targets *bt, struct bmp_qhash_head *updhash,
static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi,
struct bgp_dest *bn, struct peer *peer, bool withdraw)
{
- struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
+ struct bmp_bgp *bmpbgp;
struct bmp_targets *bt;
struct bmp *bmp;
+ struct bgp *bgp_vrf;
+ struct listnode *node;
+ struct bmp_queue_entry *last_item;
if (frrtrace_enabled(frr_bgp, bmp_process)) {
char pfxprint[PREFIX2STR_BUFFER];
@@ -1679,31 +1854,34 @@ static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi,
withdraw);
}
- if (!bmpbgp)
- return 0;
-
- frr_each(bmp_targets, &bmpbgp->targets, bt) {
- /* check if any monitoring is enabled (ignoring loc-rib since it
- * uses another hook & queue
- */
- if (!CHECK_FLAG(bt->afimon[afi][safi], ~BMP_MON_LOC_RIB))
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+ bmpbgp = bmp_bgp_find(bgp_vrf);
+ if (!bmpbgp)
continue;
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ /* check if any monitoring is enabled (ignoring loc-rib since it
+ * uses another hook & queue
+ */
+ if (!CHECK_FLAG(bt->afimon[afi][safi], ~BMP_MON_LOC_RIB))
+ continue;
- struct bmp_queue_entry *last_item =
- bmp_process_one(bt, &bt->updhash, &bt->updlist, bgp,
- afi, safi, bn, peer);
+ if (bgp_vrf != peer->bgp && !bmp_imported_bgp_find(bt, peer->bgp->name))
+ continue;
- /* if bmp_process_one returns NULL
- * we don't have anything to do next
- */
- if (!last_item)
- continue;
+ last_item = bmp_process_one(bt, &bt->updhash, &bt->updlist, bgp, afi, safi,
+ bn, peer);
+ /* if bmp_process_one returns NULL
+ * we don't have anything to do next
+ */
+ if (!last_item)
+ continue;
- frr_each(bmp_session, &bt->sessions, bmp) {
- if (!bmp->queuepos)
- bmp->queuepos = last_item;
+ frr_each (bmp_session, &bt->sessions, bmp) {
+ if (!bmp->queuepos)
+ bmp->queuepos = last_item;
- pullwr_bump(bmp->pullwr);
+ pullwr_bump(bmp->pullwr);
+ }
}
}
return 0;
@@ -1750,6 +1928,22 @@ static void bmp_stat_put_u64(struct stream *s, size_t *cnt, uint16_t type,
static void bmp_stats(struct event *thread)
{
struct bmp_targets *bt = EVENT_ARG(thread);
+ struct bmp_imported_bgp *bib;
+ struct bgp *bgp;
+
+ if (bt->stat_msec)
+ event_add_timer_msec(bm->master, bmp_stats, bt, bt->stat_msec, &bt->t_stats);
+
+ bmp_stats_per_instance(bt->bgp, bt);
+ frr_each (bmp_imported_bgps, &bt->imported_bgps, bib) {
+ bgp = bgp_lookup_by_name(bib->name);
+ if (bgp)
+ bmp_stats_per_instance(bgp, bt);
+ }
+}
+
+static void bmp_stats_per_instance(struct bgp *bgp, struct bmp_targets *bt)
+{
struct stream *s;
struct peer *peer;
struct listnode *node;
@@ -1757,14 +1951,10 @@ static void bmp_stats(struct event *thread)
uint8_t peer_type_flag;
uint64_t peer_distinguisher = 0;
- if (bt->stat_msec)
- event_add_timer_msec(bm->master, bmp_stats, bt, bt->stat_msec,
- &bt->t_stats);
-
gettimeofday(&tv, NULL);
/* Walk down all peers */
- for (ALL_LIST_ELEMENTS_RO(bt->bgp->peer, node, peer)) {
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
size_t count = 0, count_pos, len;
if (!peer_established(peer->connection))
@@ -1980,6 +2170,7 @@ static struct bmp_bgp *bmp_bgp_get(struct bgp *bgp)
bmpbgp->bgp = bgp;
bmpbgp->vrf_state = vrf_state_unknown;
bmpbgp->mirror_qsizelimit = ~0UL;
+ bmp_targets_init(&bmpbgp->targets);
bmp_mirrorq_init(&bmpbgp->mirrorq);
bmp_bgph_add(&bmp_bgph, bmpbgp);
@@ -2054,30 +2245,29 @@ static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp)
*
* returns true if state has changed
*/
-bool bmp_bgp_update_vrf_status(struct bmp_bgp *bmpbgp, enum bmp_vrf_state force)
+bool bmp_bgp_update_vrf_status(enum bmp_vrf_state *vrf_state, struct bgp *bgp,
+ enum bmp_vrf_state force)
{
enum bmp_vrf_state old_state;
struct bmp_bgp_peer *bbpeer;
struct peer *peer;
struct vrf *vrf;
- struct bgp *bgp;
bool changed;
- if (!bmpbgp || !bmpbgp->bgp)
+ if (!vrf_state || !bgp)
return false;
- bgp = bmpbgp->bgp;
- old_state = bmpbgp->vrf_state;
+ old_state = *vrf_state;
vrf = bgp_vrf_lookup_by_instance_type(bgp);
- bmpbgp->vrf_state = force != vrf_state_unknown ? force
- : vrf_is_enabled(vrf) ? vrf_state_up
- : vrf_state_down;
+ *vrf_state = force != vrf_state_unknown ? force
+ : vrf_is_enabled(vrf) ? vrf_state_up
+ : vrf_state_down;
- changed = old_state != bmpbgp->vrf_state;
+ changed = old_state != *vrf_state;
if (changed) {
- peer = bmpbgp->bgp->peer_self;
- if (bmpbgp->vrf_state == vrf_state_up) {
+ peer = bgp->peer_self;
+ if (*vrf_state == vrf_state_up) {
bbpeer = bmp_bgp_peer_get(peer);
bmp_bgp_peer_vrf(bbpeer, bgp);
} else {
@@ -2085,6 +2275,7 @@ bool bmp_bgp_update_vrf_status(struct bmp_bgp *bmpbgp, enum bmp_vrf_state force)
if (bbpeer) {
XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx);
+ XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx);
bmp_peerh_del(&bmp_peerh, bbpeer);
XFREE(MTYPE_BMP_PEER, bbpeer);
}
@@ -2129,6 +2320,8 @@ static struct bmp_targets *bmp_targets_find1(struct bgp *bgp, const char *name)
static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name)
{
struct bmp_targets *bt;
+ afi_t afi;
+ safi_t safi;
bt = bmp_targets_find1(bgp, name);
if (bt)
@@ -2139,6 +2332,8 @@ static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name)
bt->bgp = bgp;
bt->bmpbgp = bmp_bgp_get(bgp);
bt->stats_send_experimental = true;
+ FOREACH_AFI_SAFI (afi, safi)
+ bt->bgp_request_sync[afi][safi] = false;
bmp_session_init(&bt->sessions);
bmp_qhash_init(&bt->updhash);
bmp_qlist_init(&bt->updlist);
@@ -2146,16 +2341,25 @@ static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name)
bmp_qlist_init(&bt->locupdlist);
bmp_actives_init(&bt->actives);
bmp_listeners_init(&bt->listeners);
+ bmp_imported_bgps_init(&bt->imported_bgps);
QOBJ_REG(bt, bmp_targets);
bmp_targets_add(&bt->bmpbgp->targets, bt);
return bt;
}
+static void bmp_imported_bgp_free(struct bmp_imported_bgp *bib)
+{
+ if (bib->name)
+ XFREE(MTYPE_BMP_IMPORTED_BGP, bib->name);
+ XFREE(MTYPE_BMP_IMPORTED_BGP, bib);
+}
+
static void bmp_targets_put(struct bmp_targets *bt)
{
struct bmp *bmp;
struct bmp_active *ba;
+ struct bmp_imported_bgp *bib;
EVENT_OFF(bt->t_stats);
@@ -2170,6 +2374,10 @@ static void bmp_targets_put(struct bmp_targets *bt)
bmp_targets_del(&bt->bmpbgp->targets, bt);
QOBJ_UNREG(bt);
+ frr_each_safe (bmp_imported_bgps, &bt->imported_bgps, bib)
+ bmp_imported_bgp_free(bib);
+
+ bmp_imported_bgps_fini(&bt->imported_bgps);
bmp_listeners_fini(&bt->listeners);
bmp_actives_fini(&bt->actives);
bmp_qhash_fini(&bt->updhash);
@@ -2214,6 +2422,71 @@ static struct bmp_listener *bmp_listener_get(struct bmp_targets *bt,
return bl;
}
+static struct bmp_imported_bgp *bmp_imported_bgp_find(struct bmp_targets *bt, char *name)
+{
+ struct bmp_imported_bgp dummy;
+
+ dummy.name = name;
+ return bmp_imported_bgps_find(&bt->imported_bgps, &dummy);
+}
+
+static void bmp_send_all_bgp(struct peer *peer, bool down)
+{
+ struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp);
+ struct bgp *bgp_vrf;
+ struct listnode *node;
+ struct stream *s = NULL;
+ struct bmp_targets *bt;
+
+ s = bmp_peerstate(peer, down);
+ if (!s)
+ return;
+
+ if (bmpbgp) {
+ frr_each (bmp_targets, &bmpbgp->targets, bt)
+ bmp_send_bt(bt, s);
+ }
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+ bmpbgp = bmp_bgp_find(bgp_vrf);
+ if (!bmpbgp)
+ continue;
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ if (bgp_vrf != peer->bgp && !bmp_imported_bgp_find(bt, peer->bgp->name))
+ continue;
+ bmp_send_bt(bt, s);
+ }
+ }
+ stream_free(s);
+}
+
+static void bmp_imported_bgp_put(struct bmp_targets *bt, struct bmp_imported_bgp *bib)
+{
+ bmp_imported_bgps_del(&bt->imported_bgps, bib);
+ bmp_imported_bgp_free(bib);
+}
+
+static struct bmp_imported_bgp *bmp_imported_bgp_get(struct bmp_targets *bt, char *name)
+{
+ struct bmp_imported_bgp *bib = bmp_imported_bgp_find(bt, name);
+ afi_t afi;
+ safi_t safi;
+
+ if (bib)
+ return bib;
+
+ bib = XCALLOC(MTYPE_BMP_IMPORTED_BGP, sizeof(*bib));
+ if (name)
+ bib->name = XSTRDUP(MTYPE_BMP_IMPORTED_BGP, name);
+ bib->vrf_state = vrf_state_unknown;
+ FOREACH_AFI_SAFI (afi, safi)
+ bib->bgp_request_sync[afi][safi] = false;
+
+ bib->targets = bt;
+ bmp_imported_bgps_add(&bt->imported_bgps, bib);
+
+ return bib;
+}
+
static void bmp_listener_start(struct bmp_listener *bl)
{
int sock, ret;
@@ -2574,6 +2847,63 @@ DEFPY(no_bmp_targets_main,
return CMD_SUCCESS;
}
+DEFPY(bmp_import_vrf,
+ bmp_import_vrf_cmd,
+ "[no] bmp import-vrf-view VRFNAME$vrfname",
+ NO_STR
+ BMP_STR
+ "Import BMP information from another VRF\n"
+ "Specify the VRF or view instance name\n")
+{
+ VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt);
+ struct bmp_imported_bgp *bib;
+ struct bgp *bgp;
+ struct bmp *bmp;
+ afi_t afi;
+ safi_t safi;
+
+ if (!bt->bgp) {
+ vty_out(vty, "%% BMP target, BGP instance not found\n");
+ return CMD_WARNING;
+ }
+ if ((bt->bgp->name == NULL && vrfname == NULL) ||
+ (bt->bgp->name && vrfname && strmatch(vrfname, bt->bgp->name))) {
+ vty_out(vty, "%% BMP target, can not import our own BGP instance\n");
+ return CMD_WARNING;
+ }
+ if (no) {
+ bib = bmp_imported_bgp_find(bt, (char *)vrfname);
+ if (!bib) {
+ vty_out(vty, "%% BMP imported BGP instance not found\n");
+ return CMD_WARNING;
+ }
+ bgp = bgp_lookup_by_name(bib->name);
+ if (!bgp)
+ return CMD_WARNING;
+ bmp_send_peerdown_vrf_per_instance(bt, bgp);
+ bmp_imported_bgp_put(bt, bib);
+ return CMD_SUCCESS;
+ }
+ bib = bmp_imported_bgp_find(bt, (char *)vrfname);
+ if (bib)
+ return CMD_SUCCESS;
+
+ bib = bmp_imported_bgp_get(bt, (char *)vrfname);
+ bgp = bgp_lookup_by_name(bib->name);
+ if (!bgp)
+ return CMD_SUCCESS;
+
+ frr_each (bmp_session, &bt->sessions, bmp) {
+ if (bmp->state != BMP_PeerUp && bmp->state != BMP_Run)
+ continue;
+ bmp_send_peerup_per_instance(bmp, bgp);
+ bmp_send_peerup_vrf_per_instance(bmp, &bib->vrf_state, bgp);
+ FOREACH_AFI_SAFI (afi, safi)
+ bmp_update_syncro(bmp, afi, safi, bgp);
+ }
+ return CMD_SUCCESS;
+}
+
DEFPY(bmp_listener_main,
bmp_listener_cmd,
"bmp listener <X:X::X:X|A.B.C.D> port (1-65535)",
@@ -2776,19 +3106,8 @@ DEFPY(bmp_monitor_cfg, bmp_monitor_cmd,
if (prev == bt->afimon[afi][safi])
return CMD_SUCCESS;
- frr_each (bmp_session, &bt->sessions, bmp) {
- if (bmp->syncafi == afi && bmp->syncsafi == safi) {
- bmp->syncafi = AFI_MAX;
- bmp->syncsafi = SAFI_MAX;
- }
-
- if (!bt->afimon[afi][safi]) {
- bmp->afistate[afi][safi] = BMP_AFI_INACTIVE;
- continue;
- }
-
- bmp->afistate[afi][safi] = BMP_AFI_NEEDSYNC;
- }
+ frr_each (bmp_session, &bt->sessions, bmp)
+ bmp_update_syncro(bmp, afi, safi, NULL);
return CMD_SUCCESS;
}
@@ -3011,6 +3330,7 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
struct bmp_targets *bt;
struct bmp_listener *bl;
struct bmp_active *ba;
+ struct bmp_imported_bgp *bib;
afi_t afi;
safi_t safi;
@@ -3053,6 +3373,11 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
vty_out(vty, " bmp monitor %s %s loc-rib\n",
afi2str_lower(afi), safi2str(safi));
}
+
+ frr_each (bmp_imported_bgps, &bt->imported_bgps, bib)
+ vty_out(vty, " bmp import-vrf-view %s\n",
+ bib->name ? bib->name : VRF_DEFAULT_NAME);
+
frr_each (bmp_listeners, &bt->listeners, bl)
vty_out(vty, " bmp listener %pSU port %d\n", &bl->addr, bl->port);
@@ -3090,6 +3415,7 @@ static int bgp_bmp_init(struct event_loop *tm)
install_element(BMP_NODE, &bmp_stats_cmd);
install_element(BMP_NODE, &bmp_monitor_cmd);
install_element(BMP_NODE, &bmp_mirror_cmd);
+ install_element(BMP_NODE, &bmp_import_vrf_cmd);
install_element(BGP_NODE, &bmp_mirror_limit_cmd);
install_element(BGP_NODE, &no_bmp_mirror_limit_cmd);
@@ -3105,11 +3431,14 @@ static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi,
struct bgp_path_info *old_route,
struct bgp_path_info *new_route)
{
- bool is_locribmon_enabled = false;
bool is_withdraw = old_route && !new_route;
struct bgp_path_info *updated_route =
is_withdraw ? old_route : new_route;
-
+ struct bmp_bgp *bmpbgp;
+ struct bmp_targets *bt;
+ int ret = 0;
+ struct bgp *bgp_vrf;
+ struct listnode *node;
/* this should never happen */
if (!updated_route) {
@@ -3117,23 +3446,30 @@ static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi,
return 0;
}
- struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
- struct peer *peer = updated_route->peer;
- struct bmp_targets *bt;
- struct bmp *bmp;
-
- if (!bmpbgp)
- return 0;
-
- frr_each (bmp_targets, &bmpbgp->targets, bt) {
- if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) {
- is_locribmon_enabled = true;
- break;
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+ bmpbgp = bmp_bgp_find(bgp_vrf);
+ if (!bmpbgp)
+ continue;
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ if (!CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB))
+ continue;
+ if (bgp_vrf != bgp && !bmp_imported_bgp_find(bt, bgp->name))
+ continue;
+ ret = bmp_route_update_bgpbmp(bt, afi, safi, bn, old_route, new_route);
}
}
+ return ret;
+}
- if (!is_locribmon_enabled)
- return 0;
+static int bmp_route_update_bgpbmp(struct bmp_targets *bt, afi_t afi, safi_t safi,
+ struct bgp_dest *bn, struct bgp_path_info *old_route,
+ struct bgp_path_info *new_route)
+{
+ bool is_withdraw = old_route && !new_route;
+ struct bgp_path_info *updated_route = is_withdraw ? old_route : new_route;
+ struct peer *peer = updated_route->peer;
+ struct bmp *bmp;
+ struct bmp_queue_entry *last_item;
/* route is not installed in locrib anymore and rib uptime was saved */
if (old_route && old_route->extra)
@@ -3147,26 +3483,20 @@ static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi,
bgp_path_info_extra_get(new_route)->bgp_rib_uptime =
monotime(NULL);
- frr_each (bmp_targets, &bmpbgp->targets, bt) {
- if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) {
-
- struct bmp_queue_entry *last_item = bmp_process_one(
- bt, &bt->locupdhash, &bt->locupdlist, bgp, afi,
- safi, bn, peer);
+ last_item = bmp_process_one(bt, &bt->locupdhash, &bt->locupdlist, bt->bgp, afi, safi, bn,
+ peer);
- /* if bmp_process_one returns NULL
- * we don't have anything to do next
- */
- if (!last_item)
- continue;
+ /* if bmp_process_one returns NULL
+ * we don't have anything to do next
+ */
+ if (!last_item)
+ return 0;
- frr_each (bmp_session, &bt->sessions, bmp) {
- if (!bmp->locrib_queuepos)
- bmp->locrib_queuepos = last_item;
+ frr_each (bmp_session, &bt->sessions, bmp) {
+ if (!bmp->locrib_queuepos)
+ bmp->locrib_queuepos = last_item;
- pullwr_bump(bmp->pullwr);
- };
- }
+ pullwr_bump(bmp->pullwr);
};
return 0;
@@ -3179,24 +3509,76 @@ static int bgp_bmp_early_fini(void)
return 0;
}
+static int bmp_bgp_attribute_updated_instance(struct bmp_targets *bt, enum bmp_vrf_state *vrf_state,
+ struct bgp *bgp, bool withdraw, struct stream *s)
+{
+ bmp_bgp_update_vrf_status(vrf_state, bgp, vrf_state_unknown);
+ if (*vrf_state == vrf_state_down)
+ /* do not send peer events, router id will not be enough to set state to up
+ */
+ return 0;
+
+ /* vrf_state is up: trigger a peer event
+ */
+ bmp_send_bt(bt, s);
+ return 1;
+}
+
/* called when the routerid of an instance changes */
static int bmp_bgp_attribute_updated(struct bgp *bgp, bool withdraw)
{
struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
+ struct bgp *bgp_vrf;
+ struct bmp_targets *bt;
+ struct listnode *node;
+ struct bmp_imported_bgp *bib;
+ int ret = 0;
+ struct stream *s = bmp_peerstate(bgp->peer_self, withdraw);
+ struct bmp *bmp;
+ afi_t afi;
+ safi_t safi;
- if (!bmpbgp)
+ if (!s)
return 0;
- bmp_bgp_update_vrf_status(bmpbgp, vrf_state_unknown);
-
- if (bmpbgp->vrf_state == vrf_state_down)
- /* do not send peer events, router id will not be enough to set state to up
- */
- return 0;
+ if (bmpbgp) {
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ ret = bmp_bgp_attribute_updated_instance(bt, &bmpbgp->vrf_state, bgp,
+ withdraw, s);
+ if (withdraw)
+ continue;
+ frr_each (bmp_session, &bt->sessions, bmp) {
+ bmp_send_peerup_per_instance(bmp, bgp);
+ FOREACH_AFI_SAFI (afi, safi)
+ bmp_update_syncro(bmp, afi, safi, bgp);
+ }
+ }
+ }
- /* vrf_state is up: trigger a peer event
- */
- bmp_send_all_safe(bmpbgp, bmp_peerstate(bgp->peer_self, withdraw));
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+ if (bgp == bgp_vrf)
+ continue;
+ bmpbgp = bmp_bgp_find(bgp_vrf);
+ if (!bmpbgp)
+ continue;
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ frr_each (bmp_imported_bgps, &bt->imported_bgps, bib) {
+ if (bgp_lookup_by_name(bib->name) != bgp)
+ continue;
+ ret += bmp_bgp_attribute_updated_instance(bt, &bib->vrf_state, bgp,
+ withdraw, s);
+ if (withdraw)
+ continue;
+ frr_each (bmp_session, &bt->sessions, bmp) {
+ bmp_send_peerup_per_instance(bmp, bgp);
+ FOREACH_AFI_SAFI (afi, safi) {
+ bmp_update_syncro(bmp, afi, safi, bgp);
+ }
+ }
+ }
+ }
+ }
+ stream_free(s);
return 1;
}
@@ -3210,19 +3592,67 @@ static int bmp_route_distinguisher_update(struct bgp *bgp, afi_t afi, bool preco
return bmp_bgp_attribute_updated(bgp, preconfig);
}
-/* called when a bgp instance goes up/down, implying that the underlying VRF
- * has been created or deleted in zebra
- */
-static int bmp_vrf_state_changed(struct bgp *bgp)
+static void _bmp_vrf_state_changed_internal(struct bgp *bgp, enum bmp_vrf_state vrf_state)
{
struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp);
+ struct bgp *bgp_vrf;
+ struct bmp_targets *bt;
+ struct listnode *node;
+ struct bmp_imported_bgp *bib;
+ struct bmp *bmp;
+ afi_t afi;
+ safi_t safi;
- if (!bmp_bgp_update_vrf_status(bmpbgp, vrf_state_unknown))
- return 1;
+ if (bmpbgp && bmp_bgp_update_vrf_status(&bmpbgp->vrf_state, bgp, vrf_state)) {
+ bmp_send_all_safe(bmpbgp, bmp_peerstate(bgp->peer_self,
+ bmpbgp->vrf_state == vrf_state_down));
+ if (vrf_state == vrf_state_up && bmpbgp->vrf_state == vrf_state_up) {
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ frr_each (bmp_session, &bt->sessions, bmp) {
+ bmp_send_peerup_per_instance(bmp, bgp);
+ FOREACH_AFI_SAFI (afi, safi)
+ bmp_update_syncro(bmp, afi, safi, bgp);
+ }
+ }
+ }
+ }
- bmp_send_all_safe(bmpbgp,
- bmp_peerstate(bgp->peer_self, bmpbgp->vrf_state == vrf_state_down));
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+ bmpbgp = bmp_bgp_find(bgp_vrf);
+ if (!bmpbgp)
+ continue;
+ if (bgp_vrf == bgp)
+ continue;
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ frr_each (bmp_imported_bgps, &bt->imported_bgps, bib) {
+ if (bgp_lookup_by_name(bib->name) != bgp)
+ continue;
+ if (bmp_bgp_update_vrf_status(&bib->vrf_state, bgp, vrf_state)) {
+ bmp_send_bt_safe(bt, bmp_peerstate(bgp->peer_self,
+ bib->vrf_state ==
+ vrf_state_down));
+ if (vrf_state == vrf_state_up &&
+ bib->vrf_state == vrf_state_up) {
+ frr_each (bmp_session, &bt->sessions, bmp) {
+ bmp_send_peerup_per_instance(bmp, bgp);
+ FOREACH_AFI_SAFI (afi, safi)
+ bmp_update_syncro(bmp, afi, safi,
+ bgp);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+/* called when a bgp instance goes up/down, implying that the underlying VRF
+ * has been created or deleted in zebra
+ */
+static int bmp_vrf_state_changed(struct bgp *bgp)
+{
+ _bmp_vrf_state_changed_internal(bgp, vrf_state_unknown);
return 0;
}
@@ -3231,7 +3661,6 @@ static int bmp_vrf_state_changed(struct bgp *bgp)
*/
static int bmp_vrf_itf_state_changed(struct bgp *bgp, struct interface *itf)
{
- struct bmp_bgp *bmpbgp;
enum bmp_vrf_state new_state;
/* if the update is not about the vrf device double-check
@@ -3240,10 +3669,8 @@ static int bmp_vrf_itf_state_changed(struct bgp *bgp, struct interface *itf)
if (!itf || !if_is_vrf(itf))
return bmp_vrf_state_changed(bgp);
- bmpbgp = bmp_bgp_find(bgp);
new_state = if_is_up(itf) ? vrf_state_up : vrf_state_down;
- if (bmp_bgp_update_vrf_status(bmpbgp, new_state))
- bmp_send_all(bmpbgp, bmp_peerstate(bgp->peer_self, new_state == vrf_state_down));
+ _bmp_vrf_state_changed_internal(bgp, new_state);
return 0;
}
diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h
index d45a4278f6..d81b8f9b05 100644
--- a/bgpd/bgp_bmp.h
+++ b/bgpd/bgp_bmp.h
@@ -92,7 +92,7 @@ struct bmp_mirrorq {
uint8_t data[0];
};
-enum {
+enum bmp_afi_state {
BMP_AFI_INACTIVE = 0,
BMP_AFI_NEEDSYNC,
BMP_AFI_SYNC,
@@ -148,6 +148,7 @@ struct bmp {
uint64_t syncpeerid;
afi_t syncafi;
safi_t syncsafi;
+ struct bgp *sync_bgp;
};
/* config & state for an active outbound connection. When the connection
@@ -195,6 +196,9 @@ struct bmp_listener {
int sock;
};
+/* config for imported bgp instances */
+PREDECL_SORTLIST_UNIQ(bmp_imported_bgps);
+
/* bmp_targets - plural since it may contain multiple bmp_listener &
* bmp_active items. If they have the same config, BMP session should be
* put in the same targets since that's a bit more effective.
@@ -206,6 +210,7 @@ struct bmp_targets {
struct bmp_bgp *bmpbgp;
struct bgp *bgp;
+ bool bgp_request_sync[AFI_MAX][SAFI_MAX];
char *name;
struct bmp_listeners_head listeners;
@@ -238,6 +243,8 @@ struct bmp_targets {
struct bmp_qhash_head locupdhash;
struct bmp_qlist_head locupdlist;
+ struct bmp_imported_bgps_head imported_bgps;
+
uint64_t cnt_accept, cnt_aclrefused;
bool stats_send_experimental;
@@ -274,6 +281,14 @@ enum bmp_vrf_state {
vrf_state_up = 1,
};
+struct bmp_imported_bgp {
+ struct bmp_imported_bgps_item bib;
+ struct bmp_targets *targets;
+ char *name;
+ enum bmp_vrf_state vrf_state;
+ bool bgp_request_sync[AFI_MAX][SAFI_MAX];
+};
+
struct bmp_bgp {
struct bmp_bgph_item bbi;
@@ -289,7 +304,8 @@ struct bmp_bgp {
size_t mirror_qsizelimit;
};
-extern bool bmp_bgp_update_vrf_status(struct bmp_bgp *bmpbgp, enum bmp_vrf_state force);
+extern bool bmp_bgp_update_vrf_status(enum bmp_vrf_state *vrf_state, struct bgp *bgp,
+ enum bmp_vrf_state force);
enum {
/* RFC7854 - 10.8 */
diff --git a/bgpd/bgp_trace.h b/bgpd/bgp_trace.h
index 43bc7a5a17..ce86920634 100644
--- a/bgpd/bgp_trace.h
+++ b/bgpd/bgp_trace.h
@@ -135,12 +135,13 @@ TRACEPOINT_LOGLEVEL(frr_bgp, bmp_mirror_packet, TRACE_INFO)
TRACEPOINT_EVENT(
frr_bgp,
bmp_eor,
- TP_ARGS(afi_t, afi, safi_t, safi, uint8_t, flags, uint8_t, peer_type_flag),
+ TP_ARGS(afi_t, afi, safi_t, safi, uint8_t, flags, uint8_t, peer_type_flag, bgp),
TP_FIELDS(
ctf_integer(afi_t, afi, afi)
ctf_integer(safi_t, safi, safi)
ctf_integer(uint8_t, flags, flags)
ctf_integer(uint8_t, peer_type_flag, peer_type_flag)
+ ctf_string(bgp, bgp->name_pretty)
)
)