diff options
| -rw-r--r-- | bgpd/bgp_bmp.c | 304 | ||||
| -rw-r--r-- | bgpd/bgp_bmp.h | 7 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 16 | ||||
| -rw-r--r-- | bgpd/bgp_route.h | 6 |
4 files changed, 297 insertions, 36 deletions
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 7270802915..d1edba30f1 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -1051,6 +1051,7 @@ afibreak: prefix_copy(&bmp->syncpos, bgp_dest_get_prefix(bn)); } + // TODO BMP add BMP_MON_LOC_RIB case if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { for (bpiter = bgp_dest_get_bgp_path_info(bn); bpiter; bpiter = bpiter->next) { @@ -1116,24 +1117,123 @@ 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) +{ + + zlog_info("bmp: wrqueue_locrib!"); + struct bmp_queue_entry *bqe; + struct peer *peer; + struct bgp_dest *bn; + bool written = false; + + bqe = bmp_pull_locrib(bmp); + if (!bqe) + return false; + + zlog_info("bmp: got update from queue"); + + afi_t afi = bqe->afi; + safi_t safi = bqe->safi; + + 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; + + // TODO BMP_MON_LOCRIB check if this is true after implenting + // LOCRIB syncing + /* currently syncing & haven't reached this prefix yet + * => it'll be sent as part of the table sync, no need here */ + zlog_info( + "bmp: skipping direct monitor msg bc will be sent with sync :)"); + goto out; + case BMP_AFI_LIVE: + break; + } + + zlog_info("passed afi state check"); + + peer = QOBJ_GET_TYPESAFE(bqe->peerid, peer); + if (!peer) { + zlog_info("bmp: skipping queued item for deleted peer"); + goto out; + } + if (!peer_established(peer)) { + zlog_info("bmp: not established peer"); + goto out; + } + + bn = bgp_node_lookup(bmp->targets->bgp->rib[afi][safi], &bqe->p); + struct prefix_rd *prd = NULL; + if ((bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN) || + (bqe->safi == SAFI_MPLS_VPN)) + prd = &bqe->rd; + + if (bmp->targets->afimon[afi][safi] & BMP_MON_LOC_RIB) { + zlog_info("bmp: loc rib monitoring on"); + struct bgp_path_info *bpi; + + // TODO BMP_MON_LOC_RIB understand this part more, why iterate + // through the table ? + for (bpi = bn ? bgp_dest_get_bgp_path_info(bn) : NULL; bpi; + bpi = bpi->next) { + // if (!CHECK_FLAG(bpi->flags, + //BGP_PATH_VALID)) continue; + if (bpi->peer == peer) + break; + } + + bmp_monitor(bmp, peer, 5, &bqe->p, prd, bpi ? bpi->attr : NULL, + afi, safi, bpi ? bpi->uptime : monotime(NULL)); + written = true; + } + +out: + if (!bqe->refcount) + XFREE(MTYPE_BMP_QUEUE, bqe); + return written; +} + static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) { struct bmp_queue_entry *bqe; @@ -1181,6 +1281,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) &bqe->p, prd); + // TODO BMP add MON_BGP_LOC_RIB case if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { struct bgp_path_info *bpi; @@ -1235,6 +1336,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; @@ -1633,6 +1736,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 +1768,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 +2313,15 @@ 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 +DEFPY(bmp_monitor_cfg, bmp_monitor_cmd, + // TODO BMP add loc-rib option + "[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 +2334,12 @@ 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') + // TODO BMP set right flag + if (policy[0] == 'l') { + flag = BMP_MON_LOC_RIB; + vty_out(vty, + "changing loc rib monitoring config for this target\n"); + } else if (policy[1] == 'r') flag = BMP_MON_PREPOLICY; else flag = BMP_MON_POSTPOLICY; @@ -2364,23 +2470,29 @@ 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 = + afimon_flag & BMP_MON_PREPOLICY + ? "pre-policy " + : ""; + const char *post_str = + afimon_flag & BMP_MON_POSTPOLICY + ? "post-policy " + : ""; + const char *locrib_str = + 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"); @@ -2507,6 +2619,9 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty) vty_out(vty, " bmp monitor %s %s post-policy\n", afi2str_lower(afi), safi2str(safi)); + if (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 +2670,122 @@ static int bgp_bmp_init(struct event_loop *tm) return 0; } + +// TODO remove "bn", redundant with updated_route->net ? +static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi, + struct bgp_dest *bn, + struct bgp_path_info *updated_route, bool withdraw) +{ + + zlog_info( + "bmp: got route update (%s) ! vrf_id=%d, afi/safi=%s, dest=%pRN, bpi=%pRN", + withdraw ? "withdraw" : "update", bgp->vrf_id, + get_afi_safi_str(afi, safi, false), bn, updated_route->net); + + struct bmp_bgp *bmpbgp = bmp_bgp_get(bgp); + struct peer *peer = updated_route->peer; + const struct prefix *prefix = bgp_dest_get_prefix(updated_route->net); + + zlog_info("bmp: peer %pBP", peer); + + struct bmp_targets *bt; + struct bmp *bmp; + + afi_t afi_iter; + safi_t safi_iter; + + frr_each (bmp_targets, &bmpbgp->targets, bt) { + zlog_info("bmp: targets name=%s", bt->name); + + FOREACH_AFI_SAFI (afi_iter, safi_iter) { + if (bt->afimon[afi_iter][safi_iter]) + zlog_info("bmp: afi/safi=%s, flag=%d", + get_afi_safi_str(afi_iter, safi_iter, + false), + bt->afimon[afi_iter][safi_iter]); + }; + + + uint8_t flags = 5; + zlog_info("bmp wanna monitor : peer=%pBP", updated_route->peer); + zlog_info("flags=%d", flags); + zlog_info("prefix=%pFX", prefix); + zlog_info("attr=%p", updated_route->attr); + zlog_info("afi=%d safi=%d", afi, safi); + zlog_info("uptime=%ld", updated_route->uptime); + + if (bt->afimon[afi][safi] & BMP_MON_LOC_RIB) { + zlog_info("has LOC RIB monitoring on!"); + + struct bmp_queue_entry *bqe, bqeref; + size_t refcount; + + refcount = bmp_session_count(&bt->sessions); + if (refcount == 0) + return 0; + + memset(&bqeref, 0, sizeof(bqeref)); + prefix_copy(&bqeref.p, prefix); + bqeref.peerid = peer->qobj_node.nid; + bqeref.afi = afi; + bqeref.safi = safi; + + zlog_info("before afi/safi check"); + if ((afi == AFI_L2VPN && safi == SAFI_EVPN && + bn->pdest) || + (safi == SAFI_MPLS_VPN)) + prefix_copy( + &bqeref.rd, + (struct prefix_rd *)bgp_dest_get_prefix( + bn->pdest)); + + zlog_info("bmp: before hash check"); + bqe = bmp_qhash_find(&bt->locupdhash, &bqeref); + uint32_t key = bmp_qhash_hkey(&bqeref); + zlog_info("bmp: key = %lu", key); + if (bqe) { + zlog_info("bmp: prefix already registered"); + if (bqe->refcount >= refcount) + /* nothing to do here */ + return 0; + + zlog_info("bmp: removing prefix"); + bmp_qlist_del(&bt->locupdlist, bqe); + zlog_info("bmp: removed prefix"); + } else { + zlog_info( + "bmp: prefix not registered in queue yet"); + bqe = XMALLOC(MTYPE_BMP_QUEUE, sizeof(*bqe)); + zlog_info("bmp: got malloc %p", bqe); + memcpy(bqe, &bqeref, sizeof(*bqe)); + zlog_info("bmp: copied bqeref into bqe"); + + bmp_qhash_add(&bt->locupdhash, bqe); + zlog_info("bmp: added hash"); + } + + zlog_info("bmp: before list add tail"); + bqe->refcount = refcount; + bmp_qlist_add_tail(&bt->locupdlist, bqe); + + zlog_info("bmp: before queuepos update"); + frr_each (bmp_session, &bt->sessions, bmp) { + zlog_info("bmp: session host=%s", bmp->remote); + + if (!bmp->locrib_queuepos) + bmp->locrib_queuepos = bqe; + + pullwr_bump(bmp->pullwr); + }; + + zlog_info("bmp: end"); + } + }; + + return 0; +} + + static int bgp_bmp_module_init(void) { hook_register(bgp_packet_dump, bmp_mirror_packet); @@ -2565,6 +2796,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; } diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h index ab7463fadc..be952b591a 100644 --- a/bgpd/bgp_bmp.h +++ b/bgpd/bgp_bmp.h @@ -124,6 +124,7 @@ struct bmp { * ahead we need to make sure that refcount is decremented. Also, on * disconnects we need to walk the queue and drop our reference. */ + struct bmp_queue_entry *locrib_queuepos; struct bmp_queue_entry *queuepos; struct bmp_mirrorq *mirrorpos; bool mirror_lost; @@ -221,6 +222,9 @@ struct bmp_targets { */ #define BMP_MON_PREPOLICY (1 << 0) #define BMP_MON_POSTPOLICY (1 << 1) + +// TODO define BMP_MON_LOC_RIB flag +#define BMP_MON_LOC_RIB (1 << 2) uint8_t afimon[AFI_MAX][SAFI_MAX]; bool mirror; @@ -232,6 +236,9 @@ struct bmp_targets { struct bmp_qhash_head updhash; struct bmp_qlist_head updlist; + struct bmp_qhash_head locupdhash; + struct bmp_qlist_head locupdlist; + uint64_t cnt_accept, cnt_aclrefused; QOBJ_FIELDS; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b627487e7c..b206f96f41 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -85,6 +85,11 @@ DEFINE_HOOK(bgp_rpki_prefix_status, const struct prefix *prefix), (peer, attr, prefix)); +DEFINE_HOOK(bgp_route_update, + (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, + struct bgp_path_info *updated_route, bool withdraw), + (bgp, afi, safi, bn, updated_route, withdraw)); + /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; @@ -3435,6 +3440,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, &bgp->t_rmap_def_originate_eval); } + // TODO BMP insert rib update hook if (old_select) bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED); if (new_select) { @@ -3447,6 +3453,16 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, UNSET_FLAG(new_select->flags, BGP_PATH_LINK_BW_CHG); } + if (old_select || new_select) { + zlog_info("old_select==NULL %s | new_select==NULL %s", + old_select == NULL ? "YES" : "NO", + new_select == NULL ? "YES" : "NO"); + bool is_withdraw = old_select && !new_select; + hook_call(bgp_route_update, bgp, afi, safi, dest, + is_withdraw ? old_select : new_select, is_withdraw); + } + + #ifdef ENABLE_BGP_VNC if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (old_select != new_select) { diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e9f48ea647..b340327d3b 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -674,6 +674,12 @@ DECLARE_HOOK(bgp_process, struct peer *peer, bool withdraw), (bgp, afi, safi, bn, peer, withdraw)); +/* called when a route is updated in the rib */ +DECLARE_HOOK(bgp_route_update, + (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, + struct bgp_path_info *updated_route, bool withdraw), + (bgp, afi, safi, bn, updated_route, withdraw)); + /* BGP show options */ #define BGP_SHOW_OPT_JSON (1 << 0) #define BGP_SHOW_OPT_WIDE (1 << 1) |
