|
|
|
|
@ -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);
|
|
|
|
|
/* 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_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);
|
|
|
|
|
} else {
|
|
|
|
|
stream_putl(s, 0);
|
|
|
|
|
stream_putl(s, 0);
|
|
|
|
|
stream_putl(s, 0);
|
|
|
|
|
stream_putl(s, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Peer AS */
|
|
|
|
|
stream_putl(s, peer->as);
|
|
|
|
|
/* set peer ASN but for LOC-RIB INSTANCE (RFC 9069) put the local bgp
|
|
|
|
|
* ASN if available or 0
|
|
|
|
|
*/
|
|
|
|
|
as_t asn = !is_locrib ? peer->as : bgp ? bgp->as : 0L;
|
|
|
|
|
|
|
|
|
|
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 if available or 0
|
|
|
|
|
*/
|
|
|
|
|
struct in_addr *bgp_id =
|
|
|
|
|
!is_locrib ? &peer->remote_id : bgp ? &bgp->router_id : NULL;
|
|
|
|
|
|
|
|
|
|
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(3, 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);
|
|
|
|
|
|
|
|
|
|
frr_each (bmp_session, &bt->sessions, bmp)
|
|
|
|
|
if (!bmp->queuepos)
|
|
|
|
|
bmp->queuepos = bqe;
|
|
|
|
|
return 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(afi), safi2str(safi));
|
|
|
|
|
}
|
|
|
|
|
frr_each (bmp_listeners, &bt->listeners, bl)
|
|
|
|
|
vty_out(vty, " \n bmp listener %pSU port %d\n",
|
|
|
|
|
@ -2555,6 +2815,76 @@ 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_module_init(void)
|
|
|
|
|
{
|
|
|
|
|
hook_register(bgp_packet_dump, bmp_mirror_packet);
|
|
|
|
|
@ -2565,6 +2895,7 @@ 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);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|