diff options
| author | Russ White <russ@riw.us> | 2025-01-14 08:38:37 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-14 08:38:37 -0500 | 
| commit | b4619da9388759cd718e61e8b89b814b60021a18 (patch) | |
| tree | 1af2c6ac25f4d7107ef246477e0861e61a2f5a58 /bgpd | |
| parent | ba4122d6dbc641e7549e947ed420301939e48529 (diff) | |
| parent | 9f2932d106c2cb04b5510cc905122516cc397cfd (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.c | 801 | ||||
| -rw-r--r-- | bgpd/bgp_bmp.h | 20 | ||||
| -rw-r--r-- | bgpd/bgp_trace.h | 3 | 
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)  	)  )  | 
