diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index c16823f4df62..87f47230de81 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -41,6 +41,8 @@ #include "bgpd/bgp_network.h" #include "bgp_addpath.h" #include "bgp_rd.h" +#include "bgpd/bgp_open.h" +#include "bgpd/bgp_aspath.h" static void bmp_close(struct bmp *bmp); static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp); @@ -199,7 +201,7 @@ struct bmp_lbpi_h_head bmp_lbpi; /* lock a bgp path info for a bgp instance and store it in bmp_lbpi * allocate and store in hashtable if not exist - * lock bgp_path_info, dest and bgp to keep then allocated + * lock bgp_path_info, dest and bgp to keep them in memory * increment the lock * returns the lock structure if successful */ @@ -460,13 +462,10 @@ static inline int bmp_get_peer_type_vrf(vrf_id_t vrf_id) } /* determine the peer type for per-peer headers from a struct peer - * provide a bgp->peer_self for loc-rib */ + * bgp->peer_self will NOT give loc-rib peer type + */ static inline int bmp_get_peer_type(struct peer *peer) { - - if (peer->bgp->peer_self == peer) - return BMP_PEER_TYPE_LOC_RIB_INSTANCE; - return bmp_get_peer_type_vrf(peer->bgp->vrf_id); } @@ -474,7 +473,7 @@ static inline int bmp_get_peer_type(struct peer *peer) uint64_t(holder_name) = 0; \ /* skip this message if peer distinguisher is not available */ \ if (bmp_get_peer_distinguisher((bgp), (afi), &(peer_distinguisher))) { \ - zlog_debug( \ + zlog_warn( \ "skipping bmp message for reason: can't get peer distinguisher"); \ ({ action; }); \ } @@ -503,6 +502,11 @@ static inline int bmp_get_peer_distinguisher(struct bgp *bgp, afi_t afi, if (bgp->inst_type == VRF_DEFAULT) return (int)(*result_ref = 0); + /* if requested afi has no rd configured find any other */ + if (!CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_RD_SET)) + afi = AFI_UNSPEC; + /* afi not known, use any afi configured in this vrf */ if (afi == AFI_UNSPEC) { { /* scope lock iter variables */ @@ -556,7 +560,8 @@ static void bmp_common_hdr(struct stream *s, uint8_t ver, uint8_t type) } /* add per-peer header to the stream */ -static void bmp_per_peer_hdr(struct stream *s, struct bgp *bgp, +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, @@ -640,16 +645,14 @@ 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 __attribute__((unused)) -bmp_put_vrftablename_info_tlv(struct stream *s, struct bmp *bmp) +static void +bmp_put_vrftablename_info_tlv(struct stream *s, struct bgp *bgp) { #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 (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) { + vrftablename = bgp->name; } if (vrftablename != NULL) bmp_put_info_tlv(s, BMP_INFO_TYPE_VRFTABLENAME, vrftablename); @@ -700,8 +703,10 @@ static void bmp_notify_put(struct stream *s, struct bgp_notify *nfy) } /* send peer up/down for peer based on down boolean value + * pass a bgp->peer_self for a vrf/loc-rib peer state message * returns the message to send or NULL if the peer_distinguisher is not - * available */ + * available + */ static struct stream *bmp_peerstate(struct peer *peer, bool down) { struct stream *s; @@ -712,7 +717,9 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) uptime.tv_usec = 0; monotime_to_realtime(&uptime, &uptime_real); - uint8_t peer_type = bmp_get_peer_type(peer); + bool is_locrib = peer->bgp->peer_self == peer; + uint8_t peer_type = is_locrib ? BMP_PEER_TYPE_LOC_RIB_INSTANCE + : bmp_get_peer_type(peer); BMP_PEER_DIST_TRY_GET_OR(peer->bgp, AFI_UNSPEC, peer_distinguisher, return NULL); @@ -720,17 +727,18 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) #define BGP_BMP_MAX_PACKET_SIZE 1024 s = stream_new(BGP_MAX_PACKET_SIZE); - if (peer_established(peer->connection) && !down) { + if (!down && (peer_established(peer->connection) || is_locrib)) { struct bmp_bgp_peer *bbpeer; bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_PEER_UP_NOTIFICATION); - bmp_per_peer_hdr(s, peer->bgp, peer, 0, peer_type, peer_distinguisher, &uptime_real); /* Local Address (16 bytes) */ - if (peer->su_local->sa.sa_family == AF_INET6) + if (!peer->su_local || is_locrib) + stream_put(s, 0, 16); + else if (peer->su_local->sa.sa_family == AF_INET6) stream_put(s, &peer->su_local->sin6.sin6_addr, 16); else if (peer->su_local->sa.sa_family == AF_INET) { stream_putl(s, 0); @@ -740,15 +748,21 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) } /* Local Port, Remote Port */ - if (peer->su_local->sa.sa_family == AF_INET6) + if (is_locrib) + stream_putw(s, 0); + else if (peer->su_local->sa.sa_family == AF_INET6) stream_putw(s, htons(peer->su_local->sin6.sin6_port)); else if (peer->su_local->sa.sa_family == AF_INET) stream_putw(s, htons(peer->su_local->sin.sin_port)); - if (peer->su_remote->sa.sa_family == AF_INET6) + + if (is_locrib) + stream_putw(s, 0); + else if (peer->su_remote->sa.sa_family == AF_INET6) stream_putw(s, htons(peer->su_remote->sin6.sin6_port)); else if (peer->su_remote->sa.sa_family == AF_INET) stream_putw(s, htons(peer->su_remote->sin.sin_port)); + /* TODO craft message with fields & capabilities for loc-rib */ static const uint8_t dummy_open[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -780,39 +794,48 @@ 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->bgp, peer, 0, peer_type, peer_distinguisher, &uptime_real); type_pos = stream_get_endp(s); stream_putc(s, 0); /* placeholder for down reason */ - switch (peer->last_reset) { - case PEER_DOWN_NOTIFY_RECEIVED: - type = BMP_PEERDOWN_REMOTE_NOTIFY; - bmp_notify_put(s, &peer->notify); - break; - case PEER_DOWN_CLOSE_SESSION: - type = BMP_PEERDOWN_REMOTE_CLOSE; - break; - case PEER_DOWN_WAITING_NHT: - type = BMP_PEERDOWN_LOCAL_FSM; - stream_putw(s, BGP_FSM_TcpConnectionFails); - break; - /* - * TODO: Map remaining PEER_DOWN_* reasons to RFC event codes. - * TODO: Implement BMP_PEERDOWN_LOCAL_NOTIFY. - * - * See RFC7854 ss. 4.9 - */ - default: - type = BMP_PEERDOWN_LOCAL_FSM; - stream_putw(s, BMP_PEER_DOWN_NO_RELEVANT_EVENT_CODE); - break; + if (is_locrib) { + type = BMP_PEERDOWN_LOCAL_TLV; + } else { + switch (peer->last_reset) { + case PEER_DOWN_NOTIFY_RECEIVED: + type = BMP_PEERDOWN_REMOTE_NOTIFY; + bmp_notify_put(s, &peer->notify); + break; + case PEER_DOWN_CLOSE_SESSION: + type = BMP_PEERDOWN_REMOTE_CLOSE; + break; + case PEER_DOWN_WAITING_NHT: + type = BMP_PEERDOWN_LOCAL_FSM; + stream_putw(s, BGP_FSM_TcpConnectionFails); + break; + /* + * TODO: Map remaining PEER_DOWN_* reasons to RFC event + * codes. + * TODO: Implement BMP_PEERDOWN_LOCAL_NOTIFY. + * + * See RFC7854 ss. 4.9 + */ + default: + type = BMP_PEERDOWN_LOCAL_FSM; + stream_putw( + s, + BMP_PEER_DOWN_NO_RELEVANT_EVENT_CODE); + break; + } } stream_putc_at(s, type_pos, type); } + if (is_locrib) + bmp_put_vrftablename_info_tlv(s, peer->bgp); + len = stream_get_endp(s); stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */ return s; @@ -838,6 +861,28 @@ static int bmp_send_peerup(struct bmp *bmp) return 0; } +static int bmp_send_peerup_vrf(struct bmp *bmp) { + + struct bmp_bgp *bmpbgp = bmp->targets->bmpbgp; + + /* send unconditionally because state may have 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); + + zlog_info("bmp: sending peer state message up=%d for session %s (%s)", bmpbgp->vrf_up == vrf_state_up, bmpbgp->bgp->name, bmpbgp->bgp->name_pretty); + struct stream *s = bmp_peerstate(bmpbgp->bgp->peer_self, bmpbgp->vrf_up == vrf_state_down); + + if (!s) { + zlog_warn("bmp: peer state message error"); + return 1; + } + + pullwr_write_stream(bmp->pullwr, s); + stream_free(s); + + return 0; +} + /* 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) @@ -854,6 +899,14 @@ static void bmp_send_all(struct bmp_bgp *bmpbgp, struct stream *s) stream_free(s); } +static void bmp_send_all_safe(struct bmp_bgp *bmpbgp, struct stream *s) { + + if (!s || !bmpbgp) + return; + + bmp_send_all(bmpbgp, s); +} + /* * Route Mirroring */ @@ -1128,7 +1181,7 @@ static int bmp_peer_status_changed(struct peer *peer) } } - bmp_send_all(bmpbgp, bmp_peerstate(peer, false)); + bmp_send_all_safe(bmpbgp, bmp_peerstate(peer, false)); return 0; } @@ -1153,7 +1206,7 @@ static int bmp_peer_backward(struct peer *peer) bbpeer->open_rx_len = 0; } - bmp_send_all(bmpbgp, bmp_peerstate(peer, true)); + bmp_send_all_safe(bmpbgp, bmp_peerstate(peer, true)); return 0; } @@ -1312,7 +1365,7 @@ static struct stream *bmp_withdraw(const struct prefix *p, mp_start = stream_get_endp(s); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); - bgp_packet_mpunreach_prefix(s, p, afi, safi, prd, NULL, 0, 1, + bgp_packet_mpunreach_prefix(s, p, afi, safi, prd, NULL, 0, safi != SAFI_MPLS_VPN, addpath_id, NULL); /* Set the mp_unreach attr's length */ bgp_packet_mpunreach_end(s, mplen_pos); @@ -1331,17 +1384,15 @@ static struct stream *bmp_withdraw(const struct prefix *p, * if uptime is (time_t)(-1L) then do not include the timestamp in the message */ 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, - uint32_t addpath_id, time_t uptime, + uint8_t peer_type, const struct prefix *p, + struct prefix_rd *prd, struct attr *attr, afi_t afi, + safi_t safi, uint32_t addpath_id, time_t uptime, struct bgp_path_info *bpi) { struct stream *hdr, *msg; struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 }; struct timeval uptime_real; - uint8_t peer_type = bmp_get_peer_type(peer); - BMP_PEER_DIST_TRY_GET_RET(bmp->targets->bgp, afi, peer_distinguisher); monotime_to_realtime(&tv, &uptime_real); @@ -1418,9 +1469,10 @@ static int bmp_monitor_rib_out_pre_updgrp_walkcb(struct update_group *updgrp, &ctx->bpi->tx_addpath); bmp_monitor(ctx->bmp, PAF_PEER(paf), BMP_PEER_FLAG_O, - bgp_dest_get_prefix(ctx->dest), ctx->prd, ctx->attr, - SUBGRP_AFI(subgrp), SUBGRP_SAFI(subgrp), - addpath_tx_id, monotime(NULL), ctx->bpi); + bmp_get_peer_type(PAF_PEER(paf)), bgp_dest_get_prefix(ctx->dest), + ctx->prd, ctx->attr, SUBGRP_AFI(subgrp), + SUBGRP_SAFI(subgrp), addpath_tx_id, + monotime(NULL), ctx->bpi); *ctx->written_ref = true; } @@ -1499,10 +1551,11 @@ static int bmp_monitor_rib_out_post_updgrp_walkcb(struct update_group *updgrp, SUBGRP_FOREACH_PEER (subgrp, paf) { bmp_monitor(ctx->bmp, PAF_PEER(paf), - BMP_PEER_FLAG_O | BMP_PEER_FLAG_L, ctx->pfx, - ctx->prd, advertised_attr, - SUBGRP_AFI(subgrp), SUBGRP_SAFI(subgrp), - addpath_tx_id, monotime(NULL), ctx->bpi); + BMP_PEER_FLAG_O | BMP_PEER_FLAG_L, + bmp_get_peer_type(PAF_PEER(paf)), ctx->pfx, ctx->prd, + advertised_attr, SUBGRP_AFI(subgrp), + SUBGRP_SAFI(subgrp), addpath_tx_id, + monotime(NULL), ctx->bpi); *ctx->written_ref = true; } @@ -1735,8 +1788,9 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) bool written = false; if (adjin) { - bmp_monitor(bmp, adjin->peer, 0, bn_p, prd, adjin->attr, afi, - safi, adjin->addpath_rx_id, adjin->uptime, NULL); + bmp_monitor(bmp, adjin->peer, 0, bmp_get_peer_type(adjin->peer), bn_p, + prd, adjin->attr, afi, safi, adjin->addpath_rx_id, + adjin->uptime, NULL); written = true; } @@ -1744,9 +1798,9 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_VALID) && CHECK_FLAG(mon_flags, BMP_MON_IN_POSTPOLICY)) { - bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, prd, - bpi->attr, afi, safi, bpi->addpath_rx_id, - bpi->uptime, bpi); + bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, + bmp_get_peer_type(bpi->peer), bn_p, prd, bpi->attr, afi, + safi, bpi->addpath_rx_id, bpi->uptime, bpi); UNSET_FLAG(bpi->flags, BGP_PATH_BMP_ADJIN_CHG); written = true; @@ -1757,8 +1811,8 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED | BGP_PATH_MULTIPATH); if (bpi_selected && CHECK_FLAG(mon_flags, BMP_MON_LOC_RIB)) { - bmp_monitor(bmp, bpi->peer, 0, bn_p, prd, bpi->attr, afi, safi, - bpi->addpath_rx_id, + bmp_monitor(bmp, bpi->peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, bn_p, + prd, bpi->attr, afi, safi, bpi->addpath_rx_id, bpi && bpi->extra ? bpi->extra->bgp_rib_uptime : (time_t)(-1L), bpi); @@ -1937,7 +1991,8 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr) if (CHECK_FLAG(flags, BMP_MON_IN_POSTPOLICY) && CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) { - bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd, + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, + bmp_get_peer_type(peer), &bqe->p, prd, bpi->attr, afi, safi, addpath_rx_id, bpi->uptime, bpi); ribin = bpi; @@ -1949,8 +2004,9 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr) CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED | BGP_PATH_MULTIPATH)) { - bmp_monitor(bmp, peer, 0, &bqe->p, prd, bpi->attr, afi, - safi, addpath_rx_id, + bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, + &bqe->p, prd, bpi->attr, afi, safi, + addpath_rx_id, bpi->extra ? bpi->extra->bgp_rib_uptime : (time_t)(-1L), bpi); @@ -1965,15 +2021,17 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr) /* rib-in post-policy path not found, send withdraw */ if (CHECK_FLAG(flags, BMP_MON_IN_POSTPOLICY) && !ribin) { - bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd, NULL, afi, - safi, addpath_rx_id, (time_t)(-1), NULL); + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, bmp_get_peer_type(peer), + &bqe->p, prd, NULL, afi, safi, addpath_rx_id, + (time_t)(-1), NULL); written = true; } /* loc-rib path not found, send withdraw */ if (CHECK_FLAG(flags, BMP_MON_LOC_RIB) && !locrib) { - bmp_monitor(bmp, peer, 0, &bqe->p, prd, NULL, afi, safi, - addpath_rx_id, (time_t)(-1L), NULL); + bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, &bqe->p, prd, + NULL, afi, safi, addpath_rx_id, (time_t)(-1L), + NULL); written = true; } @@ -2040,9 +2098,9 @@ static bool bmp_wrqueue_ribin(struct bmp *bmp, struct pullwr *pullwr) break; } - bmp_monitor(bmp, peer, 0, &bqe->p, prd, adjin ? adjin->attr : NULL, afi, - safi, addpath_rx_id, adjin ? adjin->uptime : monotime(NULL), - NULL); + bmp_monitor(bmp, peer, 0, bmp_get_peer_type(peer), &bqe->p, prd, + adjin ? adjin->attr : NULL, afi, safi, addpath_rx_id, + adjin ? adjin->uptime : monotime(NULL), NULL); written = true; @@ -2116,9 +2174,9 @@ static bool bmp_wrqueue_ribout(struct bmp *bmp, struct pullwr *pullwr) break; } - bmp_monitor(bmp, peer, BMP_PEER_FLAG_O, &bqe->p, prd, - bpi ? bpi->attr : NULL, afi, safi, addpath_tx_id, - monotime(NULL), bpi); + bmp_monitor(bmp, peer, BMP_PEER_FLAG_O, bmp_get_peer_type(peer), + &bqe->p, prd, bpi ? bpi->attr : NULL, afi, safi, + addpath_tx_id, monotime(NULL), bpi); written = true; } @@ -2140,8 +2198,9 @@ static bool bmp_wrqueue_ribout(struct bmp *bmp, struct pullwr *pullwr) : NULL; bmp_monitor(bmp, peer, BMP_PEER_FLAG_L | BMP_PEER_FLAG_O, - &bqe->p, prd, advertised_attr, afi, safi, - addpath_tx_id, monotime(NULL), NULL); + bmp_get_peer_type(peer), &bqe->p, prd, + advertised_attr, afi, safi, addpath_tx_id, + monotime(NULL), NULL); written = true; } @@ -2180,6 +2239,7 @@ static void bmp_wrfill(struct bmp *bmp, struct pullwr *pullwr) bmp->state = BMP_PeerUp; // fall through case BMP_PeerUp: + bmp_send_peerup_vrf(bmp); bmp_send_peerup(bmp); bmp->state = BMP_Run; break; @@ -2219,11 +2279,11 @@ static void bmp_wrerr(struct bmp *bmp, struct pullwr *pullwr, bool eof) * need to update correct queue pos for all sessions of the target after * a call to this function */ -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, uint32_t addpath_id, - struct peer * peer, uint8_t mon_flag) +static struct bmp_queue_entry * +bmp_process_one(struct bmp_targets *bt, struct bmp_qhash_head *updhash, + struct bmp_qlist_head *updlist, afi_t afi, safi_t safi, + struct bgp_dest *bn, uint32_t addpath_id, struct peer *peer, + uint8_t mon_flag) { struct bmp_queue_entry *bqe, bqeref; size_t refcount; @@ -2315,8 +2375,8 @@ static int bmp_process_ribinpre(struct bgp *bgp, afi_t afi, safi_t safi, continue; struct bmp_queue_entry *new_item = bmp_process_one( - bt, &bt->mon_in_updhash, &bt->mon_in_updlist, bgp, afi, - safi, bn, addpath_id, peer, BMP_MON_IN_PREPOLICY); + bt, &bt->mon_in_updhash, &bt->mon_in_updlist, afi, safi, + bn, addpath_id, peer, BMP_MON_IN_PREPOLICY); /* if bmp_process_one returns NULL * we don't have anything to do next @@ -2370,8 +2430,8 @@ static int bmp_process_ribinpost(struct bgp *bgp, afi_t afi, safi_t safi, if (CHECK_FLAG(bpi->flags, BGP_PATH_BMP_ADJIN_CHG)) { new_item = bmp_process_one( bt, &bt->mon_loc_updhash, - &bt->mon_loc_updlist, bgp, afi, safi, - bn, bpi->addpath_rx_id, bpi->peer, + &bt->mon_loc_updlist, afi, safi, bn, + bpi->addpath_rx_id, bpi->peer, BMP_MON_IN_POSTPOLICY); new_head = !new_head ? new_item : new_head; @@ -2481,7 +2541,7 @@ 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, bt->bgp, peer, 0, - BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv); + peer_type, peer_distinguisher, &tv); count_pos = stream_get_endp(s); stream_putl(s, 0); @@ -2719,6 +2779,7 @@ static struct bmp_bgp *bmp_bgp_get(struct bgp *bgp) bmpbgp = XCALLOC(MTYPE_BMP, sizeof(*bmpbgp)); bmpbgp->bgp = bgp; + bmpbgp->vrf_up = vrf_state_unknown; bmpbgp->mirror_qsizelimit = ~0UL; bmpbgp->startup_delay_ms = 0; bmp_mirrorq_init(&bmpbgp->mirrorq); @@ -2754,6 +2815,79 @@ static int bmp_bgp_del(struct bgp *bgp) return 0; } +static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp) { + + struct peer *peer = bgp->peer_self; + uint16_t send_holdtime; + as_t local_as; + + if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) + send_holdtime = peer->holdtime; + else + send_holdtime = peer->bgp->default_holdtime; + + /* local-as Change */ + if (peer->change_local_as) + local_as = peer->change_local_as; + else + local_as = peer->local_as; + + struct stream *s = bgp_open_make(peer, send_holdtime, local_as); + size_t open_len = stream_get_endp(s); + + bbpeer->open_rx_len = open_len; + bbpeer->open_rx = XMALLOC(MTYPE_BMP_OPEN, open_len); + memcpy(bbpeer->open_rx, s->data, open_len); + + bbpeer->open_tx_len = open_len; + bbpeer->open_tx = bbpeer->open_rx; +} + +/* update the vrf status of the bmpbgp struct for vrf peer up/down + * + * if force is unknown, use zebra vrf state + * + * returns true if state has changed + */ +bool bmp_bgp_update_vrf_status(struct bmp_bgp *bmpbgp, + enum bmp_vrf_state force) { + + if (!bmpbgp || !bmpbgp->bgp) + return false; + + struct bgp *bgp = bmpbgp->bgp; + enum bmp_vrf_state old_state = bmpbgp->vrf_up; + + struct vrf *vrf = bgp_vrf_lookup_by_instance_type(bgp); + if (force != vrf_state_unknown) { + bmpbgp->vrf_up = force; + } else { + bmpbgp->vrf_up = vrf_is_enabled(vrf) ? vrf_state_up : vrf_state_down; + } + + bool changed = old_state != bmpbgp->vrf_up; + if (changed) { + struct peer *peer = bmpbgp->bgp->peer_self; + struct bmp_bgp_peer *bbpeer; + if (bmpbgp->vrf_up == vrf_state_up) { + bbpeer = bmp_bgp_peer_get(peer); + bmp_bgp_peer_vrf(bbpeer, bgp); + } else { + bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid); + if (bbpeer) { + XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx); + bmp_peerh_del(&bmp_peerh, bbpeer); + XFREE(MTYPE_BMP_PEER, bbpeer); + } + } + } + + zlog_info("bmp: vrf \"%s\" state update detected! new state is %s, %s changed", + bgp->name_pretty, bmpbgp->vrf_up == vrf_state_up ? "UP" : "DOWN", changed ? "has" : "has not"); + + return changed; +} + static struct bmp_bgp_peer *bmp_bgp_peer_find(uint64_t peerid) { struct bmp_bgp_peer dummy = { .peerid = peerid }; @@ -3737,7 +3871,7 @@ static void bmp_show_locked(struct vty *vty) vty_out(vty, " [#%d][lock=%d] %s: bgp id=%" PRId64 - " dest=%pRN rx_id=%" PRIu32 " from peer=%pBP\n", + " dest=%pBD rx_id=%" PRIu32 " from peer=%pBP\n", n, lbpi_curr->lock, n == 0 ? "head" : "node", lbpi_curr->bgp ? (int64_t)lbpi_curr->bgp->vrf_id : -1, @@ -3897,7 +4031,7 @@ static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi, struct bmp_targets *bt; struct bmp *bmp; - zlog_info("%s: bgp id=%d, afi safi=%s, bn=%pRN, old=%p, new=%p", + zlog_info("%s: bgp id=%d, afi safi=%s, bn=%pBD, old=%p, new=%p", __func__, (int)bgp->vrf_id, get_afi_safi_str(afi, safi, false), bn, old_route, new_route); @@ -3948,13 +4082,13 @@ static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi, if (old_route && new_route && old_route != new_route) { new_head = bmp_process_one( bt, &bt->mon_loc_updhash, &bt->mon_loc_updlist, - bgp, afi, safi, bn, old_route->addpath_rx_id, + afi, safi, bn, old_route->addpath_rx_id, old_route->peer, BMP_MON_LOC_RIB); } struct bmp_queue_entry *new_item = bmp_process_one( - bt, &bt->mon_loc_updhash, &bt->mon_loc_updlist, bgp, - afi, safi, bn, updated_route->addpath_rx_id, + bt, &bt->mon_loc_updhash, &bt->mon_loc_updlist, afi, + safi, bn, updated_route->addpath_rx_id, updated_route->peer, BMP_MON_LOC_RIB); new_head = !new_head ? new_item : new_head; @@ -4010,8 +4144,8 @@ static int bmp_adj_out_changed(struct update_subgroup *subgrp, if (!lbpi) { zlog_warn( - "no locked path found for %pRN tx %" PRIu32, - dest, addpath_id); + "no locked path found for %pBD tx %" PRIu32" in bgp %s", + dest, addpath_id, SUBGRP_INST(subgrp)->name); return 0; } @@ -4020,15 +4154,15 @@ static int bmp_adj_out_changed(struct update_subgroup *subgrp, } struct attr dummy_attr = {0}; - /* - * withdraw | pre_check | result + + /* run bgp rib-out-pre check + * withdraw | pre_check | result * true | true | withdraw * true | false | nothing to do * false | true | update * false | false | nothing to do + * so if pre-policy check is false we return early. */ - - /* run bgp rib-out-pre check */ if (locked_path && !subgroup_announce_check(dest, locked_path, subgrp, bgp_dest_get_prefix(dest), &dummy_attr, NULL, @@ -4058,8 +4192,7 @@ static int bmp_adj_out_changed(struct update_subgroup *subgrp, struct bmp_queue_entry *new_item = bmp_process_one( bt, &bt->mon_out_updhash, &bt->mon_out_updlist, - NULL, afi, safi, dest, addpath_id, peer, - mon_flag); + afi, safi, dest, addpath_id, peer, mon_flag); /* if bmp_process_one returns NULL * we don't have anything to do next @@ -4086,6 +4219,43 @@ static int bmp_path_unlock(struct bgp *bgp, struct bgp_path_info *path) return bmp_unlock_bpi(bgp, path) == NULL; } +/* 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) { + + struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp); + + if (!bmp_bgp_update_vrf_status(bmpbgp, vrf_state_unknown)) + return 1; + + bmp_send_all_safe(bmpbgp, bmp_peerstate(bgp->peer_self, bmpbgp->vrf_up == vrf_state_down)); + + return 0; +} + +/* called when an interface goes up/down in a vrf, this may signal that the + * VRF changed state and is how bgp_snmp detects vrf state changes + */ +static int bmp_vrf_itf_state_changed(struct bgp *bgp, struct interface *itf) { + + /* if the update is not about the vrf device double-check + * the zebra status of the vrf + */ + if (!itf || !if_is_vrf(itf)) + return bmp_vrf_state_changed(bgp); + + enum bmp_vrf_state new_state = if_is_up(itf) ? vrf_state_up : vrf_state_down; + + struct bmp_bgp *bmpbgp = bmp_bgp_find(bgp); + if (bmp_bgp_update_vrf_status(bmpbgp, new_state)) { + bmp_send_all(bmpbgp, + bmp_peerstate(bgp->peer_self, new_state == vrf_state_down)); + } + + return 0; +} + static int bgp_bmp_module_init(void) { hook_register(bgp_packet_dump, bmp_mirror_packet); @@ -4100,6 +4270,8 @@ static int bgp_bmp_module_init(void) hook_register(bgp_route_update, bmp_route_update); hook_register(bgp_adj_out_updated, bmp_adj_out_changed); hook_register(bgp_process_main_one_end, bmp_path_unlock); + hook_register(bgp_instance_state, bmp_vrf_state_changed); + hook_register(bgp_vrf_status_changed, bmp_vrf_itf_state_changed); return 0; } diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h index cf1981d2435c..1acc0ad254be 100644 --- a/bgpd/bgp_bmp.h +++ b/bgpd/bgp_bmp.h @@ -331,10 +331,19 @@ PREDECL_HASH(bmp_bgph); #define BMP_PEER_DOWN_NO_RELEVANT_EVENT_CODE 0x00 +enum bmp_vrf_state { + vrf_state_down = -1, + vrf_state_unknown = 0, + vrf_state_up = 1, +}; + struct bmp_bgp { struct bmp_bgph_item bbi; struct bgp *bgp; + + enum bmp_vrf_state vrf_up; + struct bmp_targets_head targets; struct bmp_mirrorq_head mirrorq; @@ -345,12 +354,16 @@ struct bmp_bgp { uint32_t startup_delay_ms; }; +extern bool bmp_bgp_update_vrf_status(struct bmp_bgp *bmpbgp, + enum bmp_vrf_state force); + enum { BMP_PEERDOWN_LOCAL_NOTIFY = 1, BMP_PEERDOWN_LOCAL_FSM = 2, BMP_PEERDOWN_REMOTE_NOTIFY = 3, BMP_PEERDOWN_REMOTE_CLOSE = 4, BMP_PEERDOWN_ENDMONITOR = 5, + BMP_PEERDOWN_LOCAL_TLV = 6, }; enum { diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 11917c6c4a04..5de33e12a76b 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -257,6 +257,8 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) static int bgp_vrf_new(struct vrf *vrf) { + zlog_info("BGP VRF CREATE %s", vrf->name); + if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id); @@ -265,6 +267,7 @@ static int bgp_vrf_new(struct vrf *vrf) static int bgp_vrf_delete(struct vrf *vrf) { + zlog_info("BGP VRF DELETE %s", vrf->name); if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("VRF Deletion: %s(%u)", vrf->name, vrf->vrf_id); @@ -276,6 +279,8 @@ static int bgp_vrf_enable(struct vrf *vrf) struct bgp *bgp; vrf_id_t old_vrf_id; + zlog_info("BGP VRF ENABLE %s", vrf->name); + if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id); @@ -308,6 +313,8 @@ static int bgp_vrf_disable(struct vrf *vrf) { struct bgp *bgp; + zlog_info("BGP VRF DISABLE %s", vrf->name); + if (vrf->vrf_id == VRF_DEFAULT) return 0; diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index cb635a1268e6..a23da83dd60f 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -523,9 +523,6 @@ void bgp_mpath_diff_insert(struct bgp_mpath_diff_head *diff, bgp_path_info_lock(bpi); bgp_dest_lock_node(bpi->net); bgp_mpath_diff_add_tail(diff, item); - zlog_info("%s: added %p to %s, cnt=%d", __func__, bpi, - update ? "update" : "withdraw", - (int)bgp_mpath_diff_count(diff)); } void bgp_mpath_diff_clear(struct bgp_mpath_diff_head *diff) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 5dc35157ebf6..d2347c714456 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -643,29 +643,10 @@ void bgp_keepalive_send(struct peer *peer) bgp_writes_on(peer->connection); } -/* - * Creates a BGP Open packet and appends it to the peer's output queue. - * Sets capabilities as necessary. - */ -void bgp_open_send(struct peer_connection *connection) -{ - struct stream *s; - uint16_t send_holdtime; - as_t local_as; - struct peer *peer = connection->peer; - - if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) - send_holdtime = peer->holdtime; - else - send_holdtime = peer->bgp->default_holdtime; +struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, + as_t local_as) { - /* local-as Change */ - if (peer->change_local_as) - local_as = peer->change_local_as; - else - local_as = peer->local_as; - - s = stream_new(BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE); + struct stream *s = stream_new(BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE); /* Make open packet. */ bgp_packet_set_marker(s, BGP_MSG_OPEN); @@ -697,6 +678,34 @@ void bgp_open_send(struct peer_connection *connection) /* Set BGP packet length. */ bgp_packet_set_size(s); + return s; +} + +/* + * Creates a BGP Open packet and appends it to the peer's output queue. + * Sets capabilities as necessary. + */ +void bgp_open_send(struct peer_connection *connection) +{ + struct stream *s; + uint16_t send_holdtime; + as_t local_as; + struct peer *peer = connection->peer; + + if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) { + send_holdtime = peer->holdtime; + } else { + send_holdtime = peer->bgp->default_holdtime; + } + + /* local-as Change */ + if (peer->change_local_as) + local_as = peer->change_local_as; + else + local_as = peer->local_as; + + s = bgp_open_make(peer, send_holdtime, local_as); + if (bgp_debug_neighbor_events(peer)) zlog_debug( "%s sending OPEN, version %d, my as %u, holdtime %d, id %pI4", diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index b67acf205593..58d6453cc656 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -43,6 +43,9 @@ DECLARE_HOOK(bgp_packet_send, /* Packet send and receive function prototypes. */ extern void bgp_keepalive_send(struct peer *peer); +extern struct stream *bgp_open_make(struct peer *peer, + uint16_t send_holdtime, + as_t local_as); extern void bgp_open_send(struct peer_connection *connection); extern void bgp_notify_send(struct peer_connection *connection, uint8_t code, uint8_t sub_code); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index bcd6d936a5f4..61d7a68e0e79 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3505,18 +3505,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, } /* TODO BMP insert rib update hook */ - if (old_select) { - if (old_select->peer) - old_select->peer->stat_loc_rib_count[afi][safi]--; + if (old_select) bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED); - } + if (new_select) { if (debug) zlog_debug("%s: setting SELECTED flag", __func__); - if (new_select->peer) - new_select->peer->stat_loc_rib_count[afi][safi]++; - bgp_path_info_set_flag(dest, new_select, BGP_PATH_SELECTED); bgp_path_info_unset_flag(dest, new_select, BGP_PATH_ATTR_CHANGED); @@ -3594,12 +3589,24 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, if (old_select || new_select) hook_call(bgp_process_main_one_end, bgp, old_select && !new_select ? old_select : new_select); + if (old_select && old_select->peer) + old_select->peer->stat_loc_rib_count[afi][safi]--; + if (new_select && new_select->peer) + new_select->peer->stat_loc_rib_count[afi][safi]++; + + struct bgp_path_info *mpath; frr_each (bgp_mpath_diff, &mpath_diff, diff) { - if (!diff->path) + mpath = diff->path; + + if (!mpath) continue; - hook_call(bgp_process_main_one_end, bgp, diff->path); + if (mpath->peer) + mpath->peer->stat_loc_rib_count[afi][safi] += diff->update ? 1 : -1; + + hook_call(bgp_process_main_one_end, bgp, mpath); + } bgp_mpath_diff_clear(&mpath_diff); bgp_mpath_diff_fini(&mpath_diff); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index ab4519d75b4e..81b9742c9096 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -261,7 +261,6 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg) bgp_adj_out_updated( subgrp, ctx->dest, NULL, 0, NULL, false, true, - __func__); } } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 6ca0b0645016..b067bd63f946 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -84,6 +84,7 @@ DEFINE_QOBJ_TYPE(bgp_master); DEFINE_QOBJ_TYPE(bgp); DEFINE_QOBJ_TYPE(peer); DEFINE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)); +DEFINE_HOOK(bgp_instance_state, (struct bgp *bgp), (bgp)); /* BGP process wide configuration. */ static struct bgp_master bgp_master; @@ -3735,6 +3736,9 @@ void bgp_instance_up(struct bgp *bgp) struct peer *peer; struct listnode *node, *next; + /* notify BMP of instance state changed */ + hook_call(bgp_instance_state, bgp); + bgp_set_redist_vrf_bitmaps(bgp, true); /* Register with zebra. */ @@ -3760,6 +3764,9 @@ void bgp_instance_down(struct bgp *bgp) struct listnode *node; struct listnode *next; + /* notify BMP of instance state changed */ + hook_call(bgp_instance_state, bgp); + /* Stop timers. */ if (bgp->t_rmap_def_originate_eval) EVENT_OFF(bgp->t_rmap_def_originate_eval); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 3b8f0ce43c06..30b3cc438707 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -839,6 +839,7 @@ DECLARE_HOOK(bgp_inst_config_write, (bgp, vty)); DECLARE_HOOK(bgp_snmp_traps_config_write, (struct vty *vty), (vty)); DECLARE_HOOK(bgp_config_end, (struct bgp *bgp), (bgp)); +DECLARE_HOOK(bgp_instance_state, (struct bgp *bgp), (bgp)); /* Thread callback information */ struct afi_safi_info {