summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_bmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_bmp.c')
-rw-r--r--bgpd/bgp_bmp.c548
1 files changed, 443 insertions, 105 deletions
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index 7270802..1de48a0 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -240,60 +240,115 @@ static void bmp_free(struct bmp *bmp)
XFREE(MTYPE_BMP_CONN, bmp);
}
+#define BMP_PEER_TYPE_GLOBAL_INSTANCE 0
+#define BMP_PEER_TYPE_RD_INSTANCE 1
+#define BMP_PEER_TYPE_LOCAL_INSTANCE 2
+#define BMP_PEER_TYPE_LOC_RIB_INSTANCE 3
+
+static inline int bmp_get_peer_distinguisher(struct bmp *bmp, afi_t afi,
+ uint8_t peer_type,
+ uint64_t *result_ref)
+{
+
+ /* remove this check when the other peer types get correct peer dist.
+ *(RFC7854) impl.
+ * for now, always return no error and 0 peer distinguisher as before
+ */
+ if (peer_type != BMP_PEER_TYPE_LOC_RIB_INSTANCE)
+ return (*result_ref = 0);
+
+ /* sending vrf_id or rd could be turned into an option at some point */
+ struct bgp *bgp = bmp->targets->bgp;
+
+ /* vrf default => ok, distinguisher 0 */
+ if (bgp->inst_type == VRF_DEFAULT)
+ return (*result_ref = 0);
+
+ /* use RD if set in VRF config for this AFI */
+ struct prefix_rd *prd = &bgp->vpn_policy[afi].tovpn_rd;
+
+ if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET)) {
+ memcpy(result_ref, prd->val, sizeof(prd->val));
+ return 0;
+ }
+
+ /* VRF has no id => error => message should be skipped */
+ if (bgp->vrf_id == VRF_UNKNOWN)
+ return 1;
+
+ /* use VRF id converted to ::vrf_id 64bits format */
+ *result_ref = ((uint64_t)htonl(bgp->vrf_id)) << 32;
+ return 0;
+}
+
static void bmp_common_hdr(struct stream *s, uint8_t ver, uint8_t type)
{
stream_putc(s, ver);
- stream_putl(s, 0); //dummy message length. will be set later.
+ stream_putl(s, 0); /* dummy message length. will be set later. */
stream_putc(s, type);
}
-static void bmp_per_peer_hdr(struct stream *s, struct peer *peer,
- uint8_t flags, const struct timeval *tv)
+static void bmp_per_peer_hdr(struct stream *s, struct bgp *bgp,
+ struct peer *peer, uint8_t flags,
+ uint8_t peer_type_flag,
+ uint64_t peer_distinguisher,
+ const struct timeval *tv)
{
- char peer_distinguisher[8];
-
-#define BMP_PEER_TYPE_GLOBAL_INSTANCE 0
-#define BMP_PEER_TYPE_RD_INSTANCE 1
-#define BMP_PEER_TYPE_LOCAL_INSTANCE 2
-
#define BMP_PEER_FLAG_V (1 << 7)
#define BMP_PEER_FLAG_L (1 << 6)
#define BMP_PEER_FLAG_A (1 << 5)
+ bool is_locrib = peer_type_flag == BMP_PEER_TYPE_LOC_RIB_INSTANCE;
+
/* Peer Type */
- stream_putc(s, BMP_PEER_TYPE_GLOBAL_INSTANCE);
+ stream_putc(s, peer_type_flag);
/* Peer Flags */
- if (peer->connection->su.sa.sa_family == AF_INET6)
+ if (!is_locrib && peer->connection->su.sa.sa_family == AF_INET6)
SET_FLAG(flags, BMP_PEER_FLAG_V);
else
UNSET_FLAG(flags, BMP_PEER_FLAG_V);
stream_putc(s, flags);
/* Peer Distinguisher */
- memset (&peer_distinguisher[0], 0, 8);
- stream_put(s, &peer_distinguisher[0], 8);
+ stream_put(s, (uint8_t *)&peer_distinguisher, 8);
/* Peer Address */
- if (peer->connection->su.sa.sa_family == AF_INET6)
- stream_put(s, &peer->connection->su.sin6.sin6_addr, 16);
- else if (peer->connection->su.sa.sa_family == AF_INET) {
+ /* Set to 0 if it's a LOC-RIB INSTANCE (RFC 9069) or if it's not an
+ * IPv4/6 address
+ */
+ if (is_locrib || (peer->connection->su.sa.sa_family != AF_INET6 &&
+ peer->connection->su.sa.sa_family != AF_INET)) {
stream_putl(s, 0);
stream_putl(s, 0);
stream_putl(s, 0);
- stream_put_in_addr(s, &peer->connection->su.sin.sin_addr);
- } else {
stream_putl(s, 0);
+ } else if (peer->connection->su.sa.sa_family == AF_INET6)
+ stream_put(s, &peer->connection->su.sin6.sin6_addr, IPV6_MAX_BYTELEN);
+ else if (peer->connection->su.sa.sa_family == AF_INET) {
stream_putl(s, 0);
stream_putl(s, 0);
stream_putl(s, 0);
+ stream_put_in_addr(s, &peer->connection->su.sin.sin_addr);
}
/* Peer AS */
- stream_putl(s, peer->as);
+ /* set peer ASN but for LOC-RIB INSTANCE (RFC 9069) put the local bgp
+ * ASN
+ */
+ as_t asn = !is_locrib ? peer->as : bgp->as;
+
+ stream_putl(s, asn);
/* Peer BGP ID */
- stream_put_in_addr(s, &peer->remote_id);
+ /* set router-id but for LOC-RIB INSTANCE (RFC 9069) put the instance
+ * router-id
+ */
+ struct in_addr *bgp_id =
+ !is_locrib ? &peer->remote_id : &bgp->router_id;
+
+ stream_put_in_addr(s, bgp_id);
/* Timestamp */
if (tv) {
@@ -314,11 +369,26 @@ static void bmp_put_info_tlv(struct stream *s, uint16_t type,
stream_put(s, string, len);
}
+static void __attribute__((unused))
+bmp_put_vrftablename_info_tlv(struct stream *s, struct bmp *bmp)
+{
+
+#define BMP_INFO_TYPE_VRFTABLENAME 3
+ const char *vrftablename = "global";
+ if (bmp->targets->bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) {
+ struct vrf *vrf = vrf_lookup_by_id(bmp->targets->bgp->vrf_id);
+
+ vrftablename = vrf ? vrf->name : NULL;
+ }
+ if (vrftablename != NULL)
+ bmp_put_info_tlv(s, BMP_INFO_TYPE_VRFTABLENAME, vrftablename);
+}
+
static int bmp_send_initiation(struct bmp *bmp)
{
int len;
- struct stream *s;
- s = stream_new(BGP_MAX_PACKET_SIZE);
+ struct stream *s = stream_new(BGP_MAX_PACKET_SIZE);
+
bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_INITIATION);
#define BMP_INFO_TYPE_SYSDESCR 1
@@ -328,7 +398,7 @@ static int bmp_send_initiation(struct bmp *bmp)
bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSNAME, cmd_hostname_get());
len = stream_get_endp(s);
- stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set.
+ stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */
pullwr_write_stream(bmp->pullwr, s);
stream_free(s);
@@ -375,7 +445,9 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
bmp_common_hdr(s, BMP_VERSION_3,
BMP_TYPE_PEER_UP_NOTIFICATION);
- bmp_per_peer_hdr(s, peer, 0, &uptime_real);
+ bmp_per_peer_hdr(s, peer->bgp, peer, 0,
+ BMP_PEER_TYPE_GLOBAL_INSTANCE, 0,
+ &uptime_real);
/* Local Address (16 bytes) */
if (peer->su_local->sa.sa_family == AF_INET6)
@@ -428,7 +500,9 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
bmp_common_hdr(s, BMP_VERSION_3,
BMP_TYPE_PEER_DOWN_NOTIFICATION);
- bmp_per_peer_hdr(s, peer, 0, &uptime_real);
+ bmp_per_peer_hdr(s, peer->bgp, peer, 0,
+ BMP_PEER_TYPE_GLOBAL_INSTANCE, 0,
+ &uptime_real);
type_pos = stream_get_endp(s);
stream_putc(s, 0); /* placeholder for down reason */
@@ -460,7 +534,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
}
len = stream_get_endp(s);
- stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set.
+ stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */
return s;
}
@@ -618,7 +692,8 @@ static void bmp_wrmirror_lost(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_self, 0, &tv);
+ bmp_per_peer_hdr(s, bmp->targets->bgp, bmp->targets->bgp->peer_self, 0,
+ BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv);
stream_putw(s, BMP_MIRROR_TLV_TYPE_INFO);
stream_putw(s, 2);
@@ -656,7 +731,8 @@ 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, peer, 0, &bmq->tv);
+ bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0,
+ BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &bmq->tv);
/* BMP Mirror TLV. */
stream_putw(s, BMP_MIRROR_TLV_TYPE_BGP_MESSAGE);
@@ -763,7 +839,8 @@ static int bmp_peer_backward(struct peer *peer)
return 0;
}
-static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags)
+static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags,
+ uint8_t peer_type_flag)
{
struct peer *peer;
struct listnode *node;
@@ -771,7 +848,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(3, frr_bgp, bmp_eor, afi, safi, flags);
+ frrtrace(4, frr_bgp, bmp_eor, afi, safi, flags, peer_type_flag);
s = stream_new(BGP_MAX_PACKET_SIZE);
@@ -803,11 +880,22 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags)
if (!peer->afc_nego[afi][safi])
continue;
+ uint64_t peer_distinguisher = 0;
+ /* skip this message if peer distinguisher is not available */
+ if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag,
+ &peer_distinguisher)) {
+ zlog_warn(
+ "skipping bmp message for reason: can't get peer distinguisher");
+ continue;
+ }
+
s2 = stream_new(BGP_MAX_PACKET_SIZE);
bmp_common_hdr(s2, BMP_VERSION_3,
BMP_TYPE_ROUTE_MONITORING);
- bmp_per_peer_hdr(s2, peer, flags, NULL);
+
+ bmp_per_peer_hdr(s2, bmp->targets->bgp, peer, flags,
+ peer_type_flag, peer_distinguisher, NULL);
stream_putl_at(s2, BMP_LENGTH_POS,
stream_get_endp(s) + stream_get_endp(s2));
@@ -912,14 +1000,23 @@ static struct stream *bmp_withdraw(const struct prefix *p,
}
static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
- const struct prefix *p, struct prefix_rd *prd,
- struct attr *attr, afi_t afi, safi_t safi,
- time_t uptime)
+ uint8_t peer_type_flag, const struct prefix *p,
+ struct prefix_rd *prd, struct attr *attr, afi_t afi,
+ safi_t safi, time_t uptime)
{
struct stream *hdr, *msg;
struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 };
struct timeval uptime_real;
+ uint64_t peer_distinguisher = 0;
+ /* skip this message if peer distinguisher is not available */
+ if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag,
+ &peer_distinguisher)) {
+ zlog_warn(
+ "skipping bmp message for reason: can't get peer distinguisher");
+ return;
+ }
+
monotime_to_realtime(&tv, &uptime_real);
if (attr)
msg = bmp_update(p, prd, peer, attr, afi, safi);
@@ -928,7 +1025,9 @@ 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, peer, flags, &uptime_real);
+ bmp_per_peer_hdr(hdr, bmp->targets->bgp, peer, flags, peer_type_flag,
+ peer_distinguisher,
+ uptime == (time_t)(-1L) ? NULL : &uptime_real);
stream_putl_at(hdr, BMP_LENGTH_POS,
stream_get_endp(hdr) + stream_get_endp(msg));
@@ -1039,8 +1138,13 @@ afibreak:
zlog_info("bmp[%s] %s %s table completed (EoR)",
bmp->remote, afi2str(afi),
safi2str(safi));
- bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L);
- bmp_eor(bmp, afi, safi, 0);
+
+ bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L,
+ BMP_PEER_TYPE_GLOBAL_INSTANCE);
+ bmp_eor(bmp, afi, safi, 0,
+ BMP_PEER_TYPE_GLOBAL_INSTANCE);
+ bmp_eor(bmp, afi, safi, 0,
+ BMP_PEER_TYPE_LOC_RIB_INSTANCE);
bmp->afistate[afi][safi] = BMP_AFI_LIVE;
bmp->syncafi = AFI_MAX;
@@ -1051,10 +1155,16 @@ afibreak:
prefix_copy(&bmp->syncpos, bgp_dest_get_prefix(bn));
}
- if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
+ if (CHECK_FLAG(bmp->targets->afimon[afi][safi],
+ BMP_MON_POSTPOLICY) ||
+ CHECK_FLAG(bmp->targets->afimon[afi][safi],
+ BMP_MON_LOC_RIB)) {
for (bpiter = bgp_dest_get_bgp_path_info(bn); bpiter;
bpiter = bpiter->next) {
- if (!CHECK_FLAG(bpiter->flags, BGP_PATH_VALID))
+ if (!CHECK_FLAG(bpiter->flags,
+ BGP_PATH_VALID) &&
+ !CHECK_FLAG(bpiter->flags,
+ BGP_PATH_SELECTED))
continue;
if (bpiter->peer->qobj_node.nid
<= bmp->syncpeerid)
@@ -1065,7 +1175,8 @@ afibreak:
bpi = bpiter;
}
}
- if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) {
+ if (CHECK_FLAG(bmp->targets->afimon[afi][safi],
+ BMP_MON_PREPOLICY)) {
for (adjiter = bn->adj_in; adjiter;
adjiter = adjiter->next) {
if (adjiter->peer->qobj_node.nid
@@ -1103,12 +1214,23 @@ afibreak:
(safi == SAFI_MPLS_VPN))
prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos);
- if (bpi)
- bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, prd,
- bpi->attr, afi, safi, bpi->uptime);
+ if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) &&
+ CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_LOC_RIB)) {
+ bmp_monitor(bmp, bpi->peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE,
+ bn_p, prd, bpi->attr, afi, safi,
+ bpi && bpi->extra ? bpi->extra->bgp_rib_uptime
+ : (time_t)(-1L));
+ }
+
+ if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_VALID) &&
+ CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY))
+ bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L,
+ BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd, bpi->attr,
+ afi, safi, bpi->uptime);
+
if (adjin)
- bmp_monitor(bmp, adjin->peer, 0, bn_p, prd, adjin->attr, afi,
- safi, adjin->uptime);
+ bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE,
+ bn_p, prd, adjin->attr, afi, safi, adjin->uptime);
if (bn)
bgp_dest_unlock_node(bn);
@@ -1116,24 +1238,124 @@ afibreak:
return true;
}
-static struct bmp_queue_entry *bmp_pull(struct bmp *bmp)
+static struct bmp_queue_entry *
+bmp_pull_from_queue(struct bmp_qlist_head *list, struct bmp_qhash_head *hash,
+ struct bmp_queue_entry **queuepos_ptr)
{
struct bmp_queue_entry *bqe;
- bqe = bmp->queuepos;
+ bqe = *queuepos_ptr;
if (!bqe)
return NULL;
- bmp->queuepos = bmp_qlist_next(&bmp->targets->updlist, bqe);
+ *queuepos_ptr = bmp_qlist_next(list, bqe);
bqe->refcount--;
if (!bqe->refcount) {
- bmp_qhash_del(&bmp->targets->updhash, bqe);
- bmp_qlist_del(&bmp->targets->updlist, bqe);
+ bmp_qhash_del(hash, bqe);
+ bmp_qlist_del(list, bqe);
}
return bqe;
}
+static inline struct bmp_queue_entry *bmp_pull(struct bmp *bmp)
+{
+ return bmp_pull_from_queue(&bmp->targets->updlist,
+ &bmp->targets->updhash, &bmp->queuepos);
+}
+
+static inline struct bmp_queue_entry *bmp_pull_locrib(struct bmp *bmp)
+{
+ return bmp_pull_from_queue(&bmp->targets->locupdlist,
+ &bmp->targets->locupdhash,
+ &bmp->locrib_queuepos);
+}
+
+/* TODO BMP_MON_LOCRIB find a way to merge properly this function with
+ * bmp_wrqueue or abstract it if possible
+ */
+static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr)
+{
+
+ struct bmp_queue_entry *bqe;
+ struct peer *peer;
+ struct bgp_dest *bn = NULL;
+ bool written = false;
+
+ bqe = bmp_pull_locrib(bmp);
+ if (!bqe)
+ return false;
+
+ afi_t afi = bqe->afi;
+ safi_t safi = bqe->safi;
+
+ if (!CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_LOC_RIB))
+ goto out;
+
+ switch (bmp->afistate[afi][safi]) {
+ case BMP_AFI_INACTIVE:
+ case BMP_AFI_NEEDSYNC:
+ goto out;
+ case BMP_AFI_SYNC:
+ if (prefix_cmp(&bqe->p, &bmp->syncpos) <= 0)
+ /* currently syncing but have already passed this
+ * prefix => send it.
+ */
+ break;
+
+ /* currently syncing & haven't reached this prefix yet
+ * => it'll be sent as part of the table sync, no need here
+ */
+ goto out;
+ case BMP_AFI_LIVE:
+ break;
+ }
+
+ peer = QOBJ_GET_TYPESAFE(bqe->peerid, peer);
+ if (!peer) {
+ /* skipping queued item for deleted peer
+ */
+ goto out;
+ }
+ if (peer != bmp->targets->bgp->peer_self && !peer_established(peer->connection)) {
+ /* peer is neither self, nor established
+ */
+ goto out;
+ }
+
+ bool is_vpn = (bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN) ||
+ (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);
+
+ struct bgp_path_info *bpi;
+
+ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) {
+ if (!CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED))
+ continue;
+ if (bpi->peer == peer)
+ break;
+ }
+
+ bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, &bqe->p, prd,
+ bpi ? bpi->attr : NULL, afi, safi,
+ bpi && bpi->extra ? bpi->extra->bgp_rib_uptime
+ : (time_t)(-1L));
+ written = true;
+
+out:
+ if (!bqe->refcount)
+ XFREE(MTYPE_BMP_QUEUE, bqe);
+
+ if (bn)
+ bgp_dest_unlock_node(bn);
+
+ return written;
+}
+
static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
{
struct bmp_queue_entry *bqe;
@@ -1180,11 +1402,10 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
bn = bgp_safi_node_lookup(bmp->targets->bgp->rib[afi][safi], safi,
&bqe->p, prd);
-
- if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
+ if (CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY)) {
struct bgp_path_info *bpi;
- for (bpi = bn ? bgp_dest_get_bgp_path_info(bn) : NULL; bpi;
+ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi;
bpi = bpi->next) {
if (!CHECK_FLAG(bpi->flags, BGP_PATH_VALID))
continue;
@@ -1192,13 +1413,14 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
break;
}
- bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd,
+ bmp_monitor(bmp, peer, BMP_PEER_FLAG_L,
+ BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd,
bpi ? bpi->attr : NULL, afi, safi,
bpi ? bpi->uptime : monotime(NULL));
written = true;
}
- if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) {
+ if (CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_PREPOLICY)) {
struct bgp_adj_in *adjin;
for (adjin = bn ? bn->adj_in : NULL; adjin;
@@ -1206,8 +1428,8 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
if (adjin->peer == peer)
break;
}
- bmp_monitor(bmp, peer, 0, &bqe->p, prd,
- adjin ? adjin->attr : NULL, afi, safi,
+ bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE,
+ &bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi,
adjin ? adjin->uptime : monotime(NULL));
written = true;
}
@@ -1235,6 +1457,8 @@ static void bmp_wrfill(struct bmp *bmp, struct pullwr *pullwr)
break;
if (bmp_wrqueue(bmp, pullwr))
break;
+ if (bmp_wrqueue_locrib(bmp, pullwr))
+ break;
if (bmp_wrsync(bmp, pullwr))
break;
break;
@@ -1253,16 +1477,17 @@ static void bmp_wrerr(struct bmp *bmp, struct pullwr *pullwr, bool eof)
bmp_free(bmp);
}
-static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, afi_t afi,
- safi_t safi, struct bgp_dest *bn, struct peer *peer)
+static struct bmp_queue_entry *
+bmp_process_one(struct bmp_targets *bt, struct bmp_qhash_head *updhash,
+ struct bmp_qlist_head *updlist, struct bgp *bgp, afi_t afi,
+ safi_t safi, struct bgp_dest *bn, struct peer *peer)
{
- struct bmp *bmp;
struct bmp_queue_entry *bqe, bqeref;
size_t refcount;
refcount = bmp_session_count(&bt->sessions);
if (refcount == 0)
- return;
+ return NULL;
memset(&bqeref, 0, sizeof(bqeref));
prefix_copy(&bqeref.p, bgp_dest_get_prefix(bn));
@@ -1275,26 +1500,28 @@ static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, afi_t afi,
prefix_copy(&bqeref.rd,
(struct prefix_rd *)bgp_dest_get_prefix(bn->pdest));
- bqe = bmp_qhash_find(&bt->updhash, &bqeref);
+ bqe = bmp_qhash_find(updhash, &bqeref);
if (bqe) {
if (bqe->refcount >= refcount)
/* nothing to do here */
- return;
+ return NULL;
- bmp_qlist_del(&bt->updlist, bqe);
+ bmp_qlist_del(updlist, bqe);
} else {
bqe = XMALLOC(MTYPE_BMP_QUEUE, sizeof(*bqe));
memcpy(bqe, &bqeref, sizeof(*bqe));
- bmp_qhash_add(&bt->updhash, bqe);
+ bmp_qhash_add(updhash, bqe);
}
bqe->refcount = refcount;
- bmp_qlist_add_tail(&bt->updlist, bqe);
+ bmp_qlist_add_tail(updlist, bqe);
+
+ return bqe;
- frr_each (bmp_session, &bt->sessions, bmp)
- if (!bmp->queuepos)
- bmp->queuepos = bqe;
+ /* need to update correct queue pos for all sessions of the target after
+ * a call to this function
+ */
}
static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi,
@@ -1316,12 +1543,26 @@ static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi,
return 0;
frr_each(bmp_targets, &bmpbgp->targets, bt) {
- if (!bt->afimon[afi][safi])
+ /* 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;
- bmp_process_one(bt, bgp, afi, safi, bn, peer);
+ struct bmp_queue_entry *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;
+
pullwr_bump(bmp->pullwr);
}
}
@@ -1360,7 +1601,8 @@ static void bmp_stats(struct event *thread)
s = stream_new(BGP_MAX_PACKET_SIZE);
bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_STATISTICS_REPORT);
- bmp_per_peer_hdr(s, peer, 0, &tv);
+ bmp_per_peer_hdr(s, bt->bgp, peer, 0,
+ BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv);
count_pos = stream_get_endp(s);
stream_putl(s, 0);
@@ -1530,6 +1772,9 @@ static void bmp_close(struct bmp *bmp)
while ((bqe = bmp_pull(bmp)))
if (!bqe->refcount)
XFREE(MTYPE_BMP_QUEUE, bqe);
+ while ((bqe = bmp_pull_locrib(bmp)))
+ if (!bqe->refcount)
+ XFREE(MTYPE_BMP_QUEUE, bqe);
EVENT_OFF(bmp->t_read);
pullwr_del(bmp->pullwr);
@@ -1633,6 +1878,8 @@ static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name)
bmp_session_init(&bt->sessions);
bmp_qhash_init(&bt->updhash);
bmp_qlist_init(&bt->updlist);
+ bmp_qhash_init(&bt->locupdhash);
+ bmp_qlist_init(&bt->locupdlist);
bmp_actives_init(&bt->actives);
bmp_listeners_init(&bt->listeners);
@@ -1663,6 +1910,8 @@ static void bmp_targets_put(struct bmp_targets *bt)
bmp_actives_fini(&bt->actives);
bmp_qhash_fini(&bt->updhash);
bmp_qlist_fini(&bt->updlist);
+ bmp_qhash_fini(&bt->locupdhash);
+ bmp_qlist_fini(&bt->locupdlist);
XFREE(MTYPE_BMP_ACLNAME, bt->acl_name);
XFREE(MTYPE_BMP_ACLNAME, bt->acl6_name);
@@ -2206,21 +2455,17 @@ DEFPY(bmp_stats_cfg,
return CMD_SUCCESS;
}
-DEFPY(bmp_monitor_cfg,
- bmp_monitor_cmd,
- "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn|vpn> <pre-policy|post-policy>$policy",
- NO_STR
- BMP_STR
- "Send BMP route monitoring messages\n"
- BGP_AF_STR
- BGP_AF_STR
- BGP_AF_STR
- BGP_AF_STR
- BGP_AF_STR
- BGP_AF_STR
- BGP_AF_STR
+#define BMP_POLICY_IS_LOCRIB(str) ((str)[0] == 'l') /* __l__oc-rib */
+#define BMP_POLICY_IS_PRE(str) ((str)[1] == 'r') /* p__r__e-policy */
+
+DEFPY(bmp_monitor_cfg, bmp_monitor_cmd,
+ "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn|vpn> <pre-policy|post-policy|loc-rib>$policy",
+ NO_STR BMP_STR
+ "Send BMP route monitoring messages\n" BGP_AF_STR BGP_AF_STR BGP_AF_STR
+ BGP_AF_STR BGP_AF_STR BGP_AF_STR BGP_AF_STR
"Send state before policy and filter processing\n"
- "Send state with policy and filters applied\n")
+ "Send state with policy and filters applied\n"
+ "Send state after decision process is applied\n")
{
int index = 0;
uint8_t flag, prev;
@@ -2233,7 +2478,9 @@ DEFPY(bmp_monitor_cfg,
argv_find_and_parse_afi(argv, argc, &index, &afi);
argv_find_and_parse_safi(argv, argc, &index, &safi);
- if (policy[1] == 'r')
+ if (BMP_POLICY_IS_LOCRIB(policy))
+ flag = BMP_MON_LOC_RIB;
+ else if (BMP_POLICY_IS_PRE(policy))
flag = BMP_MON_PREPOLICY;
else
flag = BMP_MON_POSTPOLICY;
@@ -2364,23 +2611,31 @@ DEFPY(show_bmp,
safi_t safi;
FOREACH_AFI_SAFI (afi, safi) {
- const char *str = NULL;
-
- switch (bt->afimon[afi][safi]) {
- case BMP_MON_PREPOLICY:
- str = "pre-policy";
- break;
- case BMP_MON_POSTPOLICY:
- str = "post-policy";
- break;
- case BMP_MON_PREPOLICY | BMP_MON_POSTPOLICY:
- str = "pre-policy and post-policy";
- break;
- }
- if (!str)
+
+ uint8_t afimon_flag = bt->afimon[afi][safi];
+
+ if (!afimon_flag)
continue;
- vty_out(vty, " Route Monitoring %s %s %s\n",
- afi2str(afi), safi2str(safi), str);
+
+ const char *pre_str =
+ CHECK_FLAG(afimon_flag,
+ BMP_MON_PREPOLICY)
+ ? "pre-policy "
+ : "";
+ const char *post_str =
+ CHECK_FLAG(afimon_flag,
+ BMP_MON_POSTPOLICY)
+ ? "post-policy "
+ : "";
+ const char *locrib_str =
+ CHECK_FLAG(afimon_flag, BMP_MON_LOC_RIB)
+ ? "loc-rib"
+ : "";
+
+ vty_out(vty,
+ " Route Monitoring %s %s %s%s%s\n",
+ afi2str(afi), safi2str(safi), pre_str,
+ post_str, locrib_str);
}
vty_out(vty, " Listeners:\n");
@@ -2500,13 +2755,18 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
vty_out(vty, " bmp mirror\n");
FOREACH_AFI_SAFI (afi, safi) {
- if (bt->afimon[afi][safi] & BMP_MON_PREPOLICY)
+ if (CHECK_FLAG(bt->afimon[afi][safi],
+ BMP_MON_PREPOLICY))
vty_out(vty, " bmp monitor %s %s pre-policy\n",
afi2str_lower(afi), safi2str(safi));
- if (bt->afimon[afi][safi] & BMP_MON_POSTPOLICY)
+ if (CHECK_FLAG(bt->afimon[afi][safi],
+ BMP_MON_POSTPOLICY))
vty_out(vty,
" bmp monitor %s %s post-policy\n",
afi2str_lower(afi), safi2str(safi));
+ if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB))
+ vty_out(vty, " bmp monitor %s %s loc-rib\n",
+ afi2str_lower(afi), safi2str(safi));
}
frr_each (bmp_listeners, &bt->listeners, bl)
vty_out(vty, " \n bmp listener %pSU port %d\n",
@@ -2555,6 +2815,82 @@ static int bgp_bmp_init(struct event_loop *tm)
return 0;
}
+static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi,
+ struct bgp_dest *bn,
+ 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;
+
+
+ /* this should never happen */
+ if (!updated_route) {
+ zlog_warn("%s: no updated route found!", __func__);
+ return 0;
+ }
+
+ struct bmp_bgp *bmpbgp = bmp_bgp_get(bgp);
+ struct peer *peer = updated_route->peer;
+ struct bmp_targets *bt;
+ struct bmp *bmp;
+
+ frr_each (bmp_targets, &bmpbgp->targets, bt) {
+ if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) {
+ is_locribmon_enabled = true;
+ break;
+ }
+ }
+
+ if (!is_locribmon_enabled)
+ return 0;
+
+ /* route is not installed in locrib anymore and rib uptime was saved */
+ if (old_route && old_route->extra)
+ bgp_path_info_extra_get(old_route)->bgp_rib_uptime =
+ (time_t)(-1L);
+
+ /* route is installed in locrib from now on so
+ * save rib uptime in bgp_path_info_extra
+ */
+ if (new_route)
+ 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);
+
+ /* 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->locrib_queuepos)
+ bmp->locrib_queuepos = last_item;
+
+ pullwr_bump(bmp->pullwr);
+ };
+ }
+ };
+
+ return 0;
+}
+
+static int bgp_bmp_early_fini(void)
+{
+ resolver_terminate();
+
+ return 0;
+}
+
static int bgp_bmp_module_init(void)
{
hook_register(bgp_packet_dump, bmp_mirror_packet);
@@ -2565,6 +2901,8 @@ static int bgp_bmp_module_init(void)
hook_register(bgp_inst_config_write, bmp_config_write);
hook_register(bgp_inst_delete, bmp_bgp_del);
hook_register(frr_late_init, bgp_bmp_init);
+ hook_register(bgp_route_update, bmp_route_update);
+ hook_register(frr_early_fini, bgp_bmp_early_fini);
return 0;
}