diff options
Diffstat (limited to 'bgpd/bgp_route.c')
| -rw-r--r-- | bgpd/bgp_route.c | 625 |
1 files changed, 456 insertions, 169 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 7c3dd234a2..5ac1d26603 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -78,6 +78,9 @@ #include "bgpd/bgp_route_clippy.c" +DEFINE_MTYPE_STATIC(BGPD, BGP_EOIU_MARKER_INFO, "BGP EOIU Marker info"); +DEFINE_MTYPE_STATIC(BGPD, BGP_METAQ, "BGP MetaQ"); + DEFINE_HOOK(bgp_snmp_update_stats, (struct bgp_dest *rn, struct bgp_path_info *pi, bool added), (rn, pi, added)); @@ -3488,14 +3491,6 @@ bool bgp_zebra_has_route_changed(struct bgp_path_info *selected) return false; } -struct bgp_process_queue { - struct bgp *bgp; - STAILQ_HEAD(, bgp_dest) pqueue; -#define BGP_PROCESS_QUEUE_EOIU_MARKER (1 << 0) - unsigned int flags; - unsigned int queued; -}; - static void bgp_process_evpn_route_injection(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_dest *dest, struct bgp_path_info *new_select, @@ -4043,43 +4038,286 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) &bgp->gr_info[afi][safi].t_route_select); } -static wq_item_status bgp_process_wq(struct work_queue *wq, void *data) +static const char *subqueue2str(enum meta_queue_indexes index) { - struct bgp_process_queue *pqnode = data; - struct bgp *bgp = pqnode->bgp; - struct bgp_table *table; - struct bgp_dest *dest; + switch (index) { + case META_QUEUE_EARLY_ROUTE: + return "Early Route"; + case META_QUEUE_OTHER_ROUTE: + return "Other Route"; + case META_QUEUE_EOIU_MARKER: + return "EOIU Marker"; + } + + return "Unknown"; +} + +/* + * Process a node from the Early route subqueue. + */ +static void process_subq_early_route(struct bgp_dest *dest) +{ + struct bgp_table *table = bgp_dest_table(dest); + + if (bgp_debug_bestpath(dest)) + zlog_debug("%s dequeued from sub-queue %s", bgp_dest_get_prefix_str(dest), + subqueue2str(META_QUEUE_EARLY_ROUTE)); + + /* note, new DESTs may be added as part of processing */ + bgp_process_main_one(table->bgp, dest, table->afi, table->safi); + bgp_dest_unlock_node(dest); + bgp_table_unlock(table); +} + +/* + * Process a node from the other subqueue. + */ +static void process_subq_other_route(struct bgp_dest *dest) +{ + struct bgp_table *table = bgp_dest_table(dest); + + if (bgp_debug_bestpath(dest)) + zlog_debug("%s dequeued from sub-queue %s", bgp_dest_get_prefix_str(dest), + subqueue2str(META_QUEUE_OTHER_ROUTE)); + + /* note, new DESTs may be added as part of processing */ + bgp_process_main_one(table->bgp, dest, table->afi, table->safi); + bgp_dest_unlock_node(dest); + bgp_table_unlock(table); +} + +/* + * Process a node from the eoiu marker subqueue. + */ +static void process_eoiu_marker(struct bgp_dest *dest) +{ + struct bgp_eoiu_info *info = bgp_dest_get_bgp_eoiu_info(dest); + + if (!info || !info->bgp) { + zlog_err("Unable to retrieve BGP instance, can't process EOIU marker"); + return; + } + + if (BGP_DEBUG(update, UPDATE_IN)) + zlog_debug("EOIU Marker dequeued from sub-queue %s", + subqueue2str(META_QUEUE_EOIU_MARKER)); + + bgp_process_main_one(info->bgp, NULL, 0, 0); +} + +/* + * Examine the specified subqueue; process one entry and return 1 if + * there is a node, return 0 otherwise. + */ +static unsigned int process_subq(struct bgp_dest_queue *subq, enum meta_queue_indexes qindex) +{ + struct bgp_dest *dest = STAILQ_FIRST(subq); + + if (!dest) + return 0; + + STAILQ_REMOVE_HEAD(subq, pq); + STAILQ_NEXT(dest, pq) = NULL; /* complete unlink */ + + switch (qindex) { + case META_QUEUE_EARLY_ROUTE: + process_subq_early_route(dest); + break; + case META_QUEUE_OTHER_ROUTE: + process_subq_other_route(dest); + break; + case META_QUEUE_EOIU_MARKER: + process_eoiu_marker(dest); + } + + return 1; +} + +/* Dispatch the meta queue by picking and processing the next node from + * a non-empty sub-queue with lowest priority. wq is equal to bgp->process_queue and + * data is pointed to the meta queue structure. + */ +static wq_item_status meta_queue_process(struct work_queue *dummy, void *data) +{ + struct meta_queue *mq = data; + uint32_t i; + + for (i = 0; i < MQ_SIZE; i++) + if (process_subq(mq->subq[i], i)) { + mq->size--; + break; + } + return mq->size ? WQ_REQUEUE : WQ_SUCCESS; +} + +static int early_route_meta_queue_add(struct meta_queue *mq, void *data) +{ + uint8_t qindex = META_QUEUE_EARLY_ROUTE; + struct bgp_dest *dest = data; + + if (bgp_debug_bestpath(dest)) + zlog_debug("%s queued into sub-queue %s", bgp_dest_get_prefix_str(dest), + subqueue2str(qindex)); + + assert(STAILQ_NEXT(dest, pq) == NULL); + STAILQ_INSERT_TAIL(mq->subq[qindex], dest, pq); + mq->size++; + return 0; +} + +static int other_route_meta_queue_add(struct meta_queue *mq, void *data) +{ + uint8_t qindex = META_QUEUE_OTHER_ROUTE; + struct bgp_dest *dest = data; + + if (bgp_debug_bestpath(dest)) + zlog_debug("%s queued into sub-queue %s", bgp_dest_get_prefix_str(dest), + subqueue2str(qindex)); + + assert(STAILQ_NEXT(dest, pq) == NULL); + STAILQ_INSERT_TAIL(mq->subq[qindex], dest, pq); + mq->size++; + return 0; +} + +static int eoiu_marker_meta_queue_add(struct meta_queue *mq, void *data) +{ + uint8_t qindex = META_QUEUE_EOIU_MARKER; + struct bgp_dest *dest = data; + + if (BGP_DEBUG(update, UPDATE_IN)) + zlog_debug("EOIU Marker queued into sub-queue %s", subqueue2str(qindex)); + + assert(STAILQ_NEXT(dest, pq) == NULL); + STAILQ_INSERT_TAIL(mq->subq[qindex], dest, pq); + mq->size++; + return 0; +} + +static int mq_add_handler(struct bgp *bgp, void *data, + int (*mq_add_func)(struct meta_queue *mq, void *data)) +{ + if (bgp->process_queue == NULL) { + zlog_err("%s: work_queue does not exist!", __func__); + return -1; + } + + if (work_queue_empty(bgp->process_queue)) + work_queue_add(bgp->process_queue, bgp->mq); + + return mq_add_func(bgp->mq, data); +} + +int early_route_process(struct bgp *bgp, struct bgp_dest *dest) +{ + if (!dest) { + zlog_err("%s: early route dest is NULL!", __func__); + return -1; + } + + return mq_add_handler(bgp, dest, early_route_meta_queue_add); +} + +int other_route_process(struct bgp *bgp, struct bgp_dest *dest) +{ + if (!dest) { + zlog_err("%s: other route dest is NULL!", __func__); + return -1; + } + + return mq_add_handler(bgp, dest, other_route_meta_queue_add); +} + +int eoiu_marker_process(struct bgp *bgp, struct bgp_dest *dest) +{ + if (!dest) { + zlog_err("%s: eoiu marker dest is NULL!", __func__); + return -1; + } + + return mq_add_handler(bgp, dest, eoiu_marker_meta_queue_add); +} + +/* Create new meta queue. + A destructor function doesn't seem to be necessary here. + */ +static struct meta_queue *meta_queue_new(void) +{ + struct meta_queue *new; + uint32_t i; + + new = XCALLOC(MTYPE_BGP_METAQ, sizeof(struct meta_queue)); - /* eoiu marker */ - if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER)) { - bgp_process_main_one(bgp, NULL, 0, 0); - /* should always have dedicated wq call */ - assert(STAILQ_FIRST(&pqnode->pqueue) == NULL); - return WQ_SUCCESS; + for (i = 0; i < MQ_SIZE; i++) { + new->subq[i] = XCALLOC(MTYPE_BGP_METAQ, sizeof(*(new->subq[i]))); + assert(new->subq[i]); + STAILQ_INIT(new->subq[i]); } - while (!STAILQ_EMPTY(&pqnode->pqueue)) { - dest = STAILQ_FIRST(&pqnode->pqueue); - STAILQ_REMOVE_HEAD(&pqnode->pqueue, pq); + return new; +} + +/* Clean up the early meta-queue list */ +static void early_meta_queue_free(struct meta_queue *mq, struct bgp_dest_queue *l) +{ + struct bgp_dest *dest; + + while (!STAILQ_EMPTY(l)) { + dest = STAILQ_FIRST(l); + STAILQ_REMOVE_HEAD(l, pq); STAILQ_NEXT(dest, pq) = NULL; /* complete unlink */ - table = bgp_dest_table(dest); - /* note, new DESTs may be added as part of processing */ - bgp_process_main_one(bgp, dest, table->afi, table->safi); + mq->size--; + } +} - bgp_dest_unlock_node(dest); - bgp_table_unlock(table); +/* Clean up the other meta-queue list */ +static void other_meta_queue_free(struct meta_queue *mq, struct bgp_dest_queue *l) +{ + struct bgp_dest *dest; + + while (!STAILQ_EMPTY(l)) { + dest = STAILQ_FIRST(l); + STAILQ_REMOVE_HEAD(l, pq); + STAILQ_NEXT(dest, pq) = NULL; /* complete unlink */ + mq->size--; } +} - return WQ_SUCCESS; +/* Clean up the eoiu marker meta-queue list */ +static void eoiu_marker_queue_free(struct meta_queue *mq, struct bgp_dest_queue *l) +{ + struct bgp_dest *dest; + + while (!STAILQ_EMPTY(l)) { + dest = STAILQ_FIRST(l); + XFREE(MTYPE_BGP_EOIU_MARKER_INFO, dest->info); + STAILQ_REMOVE_HEAD(l, pq); + STAILQ_NEXT(dest, pq) = NULL; /* complete unlink */ + mq->size--; + } } -static void bgp_processq_del(struct work_queue *wq, void *data) +void bgp_meta_queue_free(struct meta_queue *mq) { - struct bgp_process_queue *pqnode = data; + enum meta_queue_indexes i; - bgp_unlock(pqnode->bgp); + for (i = 0; i < MQ_SIZE; i++) { + switch (i) { + case META_QUEUE_EARLY_ROUTE: + early_meta_queue_free(mq, mq->subq[i]); + break; + case META_QUEUE_OTHER_ROUTE: + other_meta_queue_free(mq, mq->subq[i]); + break; + case META_QUEUE_EOIU_MARKER: + eoiu_marker_queue_free(mq, mq->subq[i]); + break; + } + + XFREE(MTYPE_BGP_METAQ, mq->subq[i]); + } - XFREE(MTYPE_BGP_PROCESS_QUEUE, pqnode); + XFREE(MTYPE_BGP_METAQ, mq); } void bgp_process_queue_init(struct bgp *bgp) @@ -4091,37 +4329,19 @@ void bgp_process_queue_init(struct bgp *bgp) bgp->process_queue = work_queue_new(bm->master, name); } - bgp->process_queue->spec.workfunc = &bgp_process_wq; - bgp->process_queue->spec.del_item_data = &bgp_processq_del; + bgp->process_queue->spec.workfunc = &meta_queue_process; bgp->process_queue->spec.max_retries = 0; bgp->process_queue->spec.hold = 50; /* Use a higher yield value of 50ms for main queue processing */ bgp->process_queue->spec.yield = 50 * 1000L; -} - -static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp) -{ - struct bgp_process_queue *pqnode; - - pqnode = XCALLOC(MTYPE_BGP_PROCESS_QUEUE, - sizeof(struct bgp_process_queue)); - /* unlocked in bgp_processq_del */ - pqnode->bgp = bgp_lock(bgp); - STAILQ_INIT(&pqnode->pqueue); - - return pqnode; + bgp->mq = meta_queue_new(); } static void bgp_process_internal(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *pi, afi_t afi, safi_t safi, bool early_process) { -#define ARBITRARY_PROCESS_QLEN 10000 - struct work_queue *wq = bgp->process_queue; - struct bgp_process_queue *pqnode; - int pqnode_reuse = 0; - /* * Indicate that *this* pi is in an unsorted * situation, even if the node is already @@ -4171,39 +4391,16 @@ static void bgp_process_internal(struct bgp *bgp, struct bgp_dest *dest, return; } - if (wq == NULL) - return; - - /* Add route nodes to an existing work queue item until reaching the - limit only if is from the same BGP view and it's not an EOIU marker - */ - if (work_queue_item_count(wq)) { - struct work_queue_item *item = work_queue_last_item(wq); - pqnode = item->data; - - if (CHECK_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER) || - (pqnode->queued >= ARBITRARY_PROCESS_QLEN && !early_process)) - pqnode = bgp_processq_alloc(bgp); - else - pqnode_reuse = 1; - } else - pqnode = bgp_processq_alloc(bgp); - /* all unlocked in bgp_process_wq */ + /* all unlocked in process_subq_xxx functions */ bgp_table_lock(bgp_dest_table(dest)); SET_FLAG(dest->flags, BGP_NODE_PROCESS_SCHEDULED); bgp_dest_lock_node(dest); - /* can't be enqueued twice */ - assert(STAILQ_NEXT(dest, pq) == NULL); if (early_process) - STAILQ_INSERT_HEAD(&pqnode->pqueue, dest, pq); + early_route_process(bgp, dest); else - STAILQ_INSERT_TAIL(&pqnode->pqueue, dest, pq); - pqnode->queued++; - - if (!pqnode_reuse) - work_queue_add(wq, pqnode); + other_route_process(bgp, dest); return; } @@ -4222,15 +4419,18 @@ void bgp_process_early(struct bgp *bgp, struct bgp_dest *dest, void bgp_add_eoiu_mark(struct bgp *bgp) { - struct bgp_process_queue *pqnode; - - if (bgp->process_queue == NULL) - return; + /* + * Create a dummy dest as the meta queue expects all its elements to be + * dest's + */ + struct bgp_dest *dummy_dest = XCALLOC(MTYPE_BGP_NODE, sizeof(struct bgp_dest)); - pqnode = bgp_processq_alloc(bgp); + struct bgp_eoiu_info *eoiu_info = XCALLOC(MTYPE_BGP_EOIU_MARKER_INFO, + sizeof(struct bgp_eoiu_info)); + eoiu_info->bgp = bgp; - SET_FLAG(pqnode->flags, BGP_PROCESS_QUEUE_EOIU_MARKER); - work_queue_add(bgp->process_queue, pqnode); + bgp_dest_set_bgp_eoiu_info(dummy_dest, eoiu_info); + eoiu_marker_process(bgp, dummy_dest); } static void bgp_maximum_prefix_restart_timer(struct event *thread) @@ -9361,9 +9561,18 @@ static void route_vty_short_status_out(struct vty *vty, const struct prefix *p, json_object *json_path) { - enum rpki_states rpki_state = RPKI_NOT_BEING_USED; + enum rpki_states rpki_state; + + /* RPKI validation state */ + rpki_state = hook_call(bgp_rpki_prefix_status, path->peer, path->attr, p); if (json_path) { + if (rpki_state == RPKI_VALID) + json_object_boolean_true_add(json_path, "rpkiValid"); + else if (rpki_state == RPKI_INVALID) + json_object_boolean_true_add(json_path, "rpkiInvalid"); + else if (rpki_state == RPKI_NOTFOUND) + json_object_boolean_true_add(json_path, "rpkiNotFound"); /* Route status display. */ if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED)) @@ -9411,10 +9620,6 @@ static void route_vty_short_status_out(struct vty *vty, return; } - /* RPKI validation state */ - rpki_state = - hook_call(bgp_rpki_prefix_status, path->peer, path->attr, p); - if (rpki_state == RPKI_VALID) vty_out(vty, "V"); else if (rpki_state == RPKI_INVALID) @@ -10552,14 +10757,13 @@ static void route_vty_out_detail_es_info(struct vty *vty, } void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, - const struct prefix *p, struct bgp_path_info *path, - afi_t afi, safi_t safi, - enum rpki_states rpki_curr_state, - json_object *json_paths) + const struct prefix *p, struct bgp_path_info *path, afi_t afi, + safi_t safi, enum rpki_states rpki_curr_state, json_object *json_paths, + struct attr *pattr) { char buf[INET6_ADDRSTRLEN]; char vni_buf[30] = {}; - struct attr *attr = path->attr; + struct attr *attr = pattr ? pattr : path->attr; time_t tbuf; char timebuf[32]; json_object *json_bestpath = NULL; @@ -11284,6 +11488,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_path, "community", bgp_attr_get_community(attr)->json); } else { + if (!bgp_attr_get_community(attr)->str) + community_str(bgp_attr_get_community(attr), true, true); vty_out(vty, " Community: %s\n", bgp_attr_get_community(attr)->str); } @@ -11291,6 +11497,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, /* Line 5 display Extended-community */ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { + if (!bgp_attr_get_ecommunity(attr)->str) + ecommunity_str(bgp_attr_get_ecommunity(attr)); + if (json_paths) { json_ext_community = json_object_new_object(); json_object_string_add( @@ -11305,6 +11514,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES))) { + if (!bgp_attr_get_ipv6_ecommunity(attr)->str) + ecommunity_str(bgp_attr_get_ipv6_ecommunity(attr)); + if (json_paths) { json_ext_ipv6_community = json_object_new_object(); json_object_string_add(json_ext_ipv6_community, "string", @@ -11330,6 +11542,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_path, "largeCommunity", bgp_attr_get_lcommunity(attr)->json); } else { + if (!bgp_attr_get_lcommunity(attr)->str) + lcommunity_str(bgp_attr_get_lcommunity(attr), true, true); vty_out(vty, " Large Community: %s\n", bgp_attr_get_lcommunity(attr)->str); } @@ -11512,11 +11726,11 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_last_update = json_object_new_object(); json_object_int_add(json_last_update, "epoch", tbuf); json_object_string_add(json_last_update, "string", - ctime_r(&tbuf, timebuf)); + time_to_string_json(path->uptime, timebuf)); json_object_object_add(json_path, "lastUpdate", json_last_update); } else - vty_out(vty, " Last update: %s", ctime_r(&tbuf, timebuf)); + vty_out(vty, " Last update: %s", time_to_string(path->uptime, timebuf)); /* Line 10 display PMSI tunnel attribute, if present */ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) { @@ -11761,14 +11975,13 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa continue; } - if (type == bgp_show_type_rpki) { - if (dest_p->family == AF_INET - || dest_p->family == AF_INET6) - rpki_curr_state = hook_call( - bgp_rpki_prefix_status, - pi->peer, pi->attr, dest_p); - if (rpki_target_state != RPKI_NOT_BEING_USED - && rpki_curr_state != rpki_target_state) + if ((dest_p->family == AF_INET || dest_p->family == AF_INET6) && + (detail_routes || detail_json || type == bgp_show_type_rpki)) { + rpki_curr_state = hook_call(bgp_rpki_prefix_status, pi->peer, + pi->attr, dest_p); + if (type == bgp_show_type_rpki && + rpki_target_state != RPKI_NOT_BEING_USED && + rpki_curr_state != rpki_target_state) continue; } @@ -11997,11 +12210,9 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa prd, table->afi, safi, NULL, false, false); - route_vty_out_detail( - vty, bgp, dest, dest_p, pi, - family2afi(dest_p->family), - safi, RPKI_NOT_BEING_USED, - json_paths); + route_vty_out_detail(vty, bgp, dest, dest_p, pi, + family2afi(dest_p->family), safi, + rpki_curr_state, json_paths, NULL); } else { route_vty_out(vty, dest_p, pi, display, safi, json_paths, wide); @@ -12114,8 +12325,13 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa } if (is_last) { unsigned long i; - for (i = 0; i < *json_header_depth; ++i) + for (i = 0; i < *json_header_depth; ++i) { vty_out(vty, " } "); + /* Put this information before closing the last `}` */ + if (i == *json_header_depth - 2) + vty_out(vty, ", \"totalRoutes\": %ld, \"totalPaths\": %ld", + output_count, total_count); + } if (!all) vty_out(vty, "\n"); } @@ -12511,11 +12727,10 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, } } -static void bgp_show_path_info(const struct prefix_rd *pfx_rd, - struct bgp_dest *bgp_node, struct vty *vty, - struct bgp *bgp, afi_t afi, safi_t safi, - json_object *json, enum bgp_path_type pathtype, - int *display, enum rpki_states rpki_target_state) +static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest *bgp_node, + struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, + json_object *json, enum bgp_path_type pathtype, int *display, + enum rpki_states rpki_target_state, struct attr *attr) { struct bgp_path_info *pi; int header = 1; @@ -12558,10 +12773,8 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd, || (pathtype == BGP_PATH_SHOW_MULTIPATH && (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH) || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)))) - route_vty_out_detail(vty, bgp, bgp_node, - bgp_dest_get_prefix(bgp_node), pi, - afi, safi, rpki_curr_state, - json_paths); + route_vty_out_detail(vty, bgp, bgp_node, bgp_dest_get_prefix(bgp_node), pi, + afi, safi, rpki_curr_state, json_paths, attr); } if (json && json_paths) { @@ -12648,9 +12861,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, continue; } - bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, - bgp, afi, safi, json, pathtype, - &display, rpki_target_state); + bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, + json, pathtype, &display, rpki_target_state, NULL); bgp_dest_unlock_node(rm); } @@ -12709,9 +12921,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, rm = longest_pfx; bgp_dest_lock_node(rm); - bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, - bgp, afi, safi, json, pathtype, - &display, rpki_target_state); + bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, + json, pathtype, &display, rpki_target_state, NULL); bgp_dest_unlock_node(rm); } @@ -12737,9 +12948,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, const struct prefix *dest_p = bgp_dest_get_prefix(dest); if (!prefix_check || dest_p->prefixlen == match.prefixlen) { - bgp_show_path_info(NULL, dest, vty, bgp, afi, - safi, json, pathtype, - &display, rpki_target_state); + bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json, pathtype, + &display, rpki_target_state, NULL); } bgp_dest_unlock_node(dest); @@ -14633,10 +14843,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (use_json) json_net = json_object_new_object(); - bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, - afi, safi, json_net, - BGP_PATH_SHOW_ALL, &display, - RPKI_NOT_BEING_USED); + bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, safi, json_net, + BGP_PATH_SHOW_ALL, &display, RPKI_NOT_BEING_USED, NULL); if (use_json) json_object_object_addf(json_ar, json_net, "%pFX", rn_p); @@ -14770,11 +14978,9 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, pass_in = &buildit; } else pass_in = dest; - bgp_show_path_info( - NULL, pass_in, vty, bgp, afi, - safi, json_net, - BGP_PATH_SHOW_ALL, &display, - RPKI_NOT_BEING_USED); + bgp_show_path_info(NULL, pass_in, vty, bgp, afi, safi, + json_net, BGP_PATH_SHOW_ALL, &display, + RPKI_NOT_BEING_USED, NULL); if (use_json) json_object_object_addf( json_ar, json_net, @@ -14800,9 +15006,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, bgp_dest_get_prefix(dest); attr = *adj->attr; - ret = bgp_output_modifier( - peer, rn_p, &attr, afi, safi, - rmap_name); + ret = bgp_output_modifier(peer, rn_p, &attr, afi, safi, + rmap_name); if (ret == RMAP_DENY) { (*filtered_count)++; @@ -14826,7 +15031,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, json_net = json_object_new_object(); bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json_net, BGP_PATH_SHOW_ALL, - &display, RPKI_NOT_BEING_USED); + &display, RPKI_NOT_BEING_USED, + adj->attr); if (use_json) json_object_object_addf(json_ar, json_net, "%pFX", rn_p); @@ -14839,7 +15045,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, */ if (use_json) { route_vty_out_tmp(vty, bgp, dest, rn_p, - &attr, safi, use_json, + adj->attr, safi, use_json, json_ar, wide); } else { for (bpi = bgp_dest_get_bgp_path_info(dest); @@ -14872,11 +15078,9 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (use_json) json_net = json_object_new_object(); - bgp_show_path_info( - NULL /* prefix_rd */, dest, vty, - bgp, afi, safi, json_net, - BGP_PATH_SHOW_BESTPATH, - &display, RPKI_NOT_BEING_USED); + bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, + safi, json_net, BGP_PATH_SHOW_BESTPATH, + &display, RPKI_NOT_BEING_USED, NULL); if (use_json) json_object_object_addf( json_ar, json_net, @@ -14902,6 +15106,8 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, json_object *json = NULL; json_object *json_ar = NULL; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); + bool first = true; + struct update_subgroup *subgrp; /* Init BGP headers here so they're only displayed once * even if 'table' is 2-tier (MPLS_VPN, ENCAP, EVPN). @@ -14970,6 +15176,28 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, else table = bgp->rib[afi][safi]; + subgrp = peer_subgroup(peer, afi, safi); + if (use_json) { + if (type == bgp_show_adj_route_advertised || type == bgp_show_adj_route_received) { + if (header1) { + int version = table ? table->version : 0; + vty_out(vty, "\"bgpTableVersion\":%d", version); + vty_out(vty, ",\"bgpLocalRouterId\":\"%pI4\"", &bgp->router_id); + vty_out(vty, ",\"defaultLocPrf\":%u", bgp->default_local_pref); + vty_out(vty, ",\"localAS\":%u", bgp->as); + if (type == bgp_show_adj_route_advertised && subgrp && + CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE)) + vty_out(vty, ",\"bgpOriginatingDefaultNetwork\":\"%s\"", + (afi == AFI_IP) ? "0.0.0.0/0" : "::/0"); + } + + if (type == bgp_show_adj_route_advertised) + vty_out(vty, ",\"advertisedRoutes\": "); + if (type == bgp_show_adj_route_received) + vty_out(vty, ",\"receivedRoutes\": "); + } + } + if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) || (safi == SAFI_EVPN)) { @@ -14988,6 +15216,7 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, json_routes = json_object_new_object(); const struct prefix_rd *prd; + prd = (const struct prefix_rd *)bgp_dest_get_prefix( dest); @@ -15001,34 +15230,56 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, &filtered_count_per_rd); /* Don't include an empty RD in the output! */ - if (json_routes && (output_count_per_rd > 0)) - json_object_object_add(json_ar, rd_str, - json_routes); + if (json_routes && (output_count_per_rd > 0) && use_json) { + if (type == bgp_show_adj_route_advertised || + type == bgp_show_adj_route_received) { + if (first) { + vty_out(vty, "\"%s\":", rd_str); + first = false; + } else { + vty_out(vty, ",\"%s\":", rd_str); + } + vty_json_no_pretty(vty, json_routes); + } else { + json_object_object_add(json_ar, rd_str, json_routes); + } + } output_count += output_count_per_rd; filtered_count += filtered_count_per_rd; } - } else + } else { show_adj_route(vty, peer, table, afi, safi, type, rmap_name, json, json_ar, show_flags, &header1, &header2, rd_str, match, &output_count, &filtered_count); + if (use_json) { + if (type == bgp_show_adj_route_advertised || + type == bgp_show_adj_route_received) { + vty_json_no_pretty(vty, json_ar); + } + } + } + if (use_json) { - if (type == bgp_show_adj_route_advertised) - json_object_object_add(json, "advertisedRoutes", - json_ar); - else + if (type == bgp_show_adj_route_advertised || type == bgp_show_adj_route_received) { + vty_out(vty, ",\"totalPrefixCounter\":%lu", output_count); + vty_out(vty, ",\"filteredPrefixCounter\":%lu", filtered_count); + json_object_free(json); + } else { + /* for bgp_show_adj_route_filtered & bgp_show_adj_route_bestpath type */ json_object_object_add(json, "receivedRoutes", json_ar); - json_object_int_add(json, "totalPrefixCounter", output_count); - json_object_int_add(json, "filteredPrefixCounter", - filtered_count); - - /* - * This is an extremely expensive operation at scale - * and non-pretty reduces memory footprint significantly. - */ - vty_json_no_pretty(vty, json); - } else if (output_count > 0) { + json_object_int_add(json, "totalPrefixCounter", output_count); + json_object_int_add(json, "filteredPrefixCounter", filtered_count); + } + + /* + * This is an extremely expensive operation at scale + * and non-pretty reduces memory footprint significantly. + */ + if ((type != bgp_show_adj_route_advertised) && (type != bgp_show_adj_route_received)) + vty_json_no_pretty(vty, json); + } else if (output_count > 0) { if (!match && filtered_count > 0) vty_out(vty, "\nTotal number of prefixes %ld (%ld filtered)\n", @@ -15131,6 +15382,7 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route, uint16_t show_flags = 0; struct listnode *node; struct bgp *abgp; + int ret; if (detail || prefix_str) SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL); @@ -15172,9 +15424,22 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route, else if (argv_find(argv, argc, "filtered-routes", &idx)) type = bgp_show_adj_route_filtered; - if (!all) - return peer_adj_routes(vty, peer, afi, safi, type, route_map, - prefix_str ? prefix : NULL, show_flags); + if (!all) { + if (uj) + if (type == bgp_show_adj_route_advertised || + type == bgp_show_adj_route_received) + vty_out(vty, "{\n"); + + ret = peer_adj_routes(vty, peer, afi, safi, type, route_map, + prefix_str ? prefix : NULL, show_flags); + if (uj) + if (type == bgp_show_adj_route_advertised || + type == bgp_show_adj_route_received) + vty_out(vty, "}\n"); + + return ret; + } + if (uj) vty_out(vty, "{\n"); @@ -15573,6 +15838,28 @@ static int bgp_distance_unset(struct vty *vty, const char *distance_str, return CMD_SUCCESS; } +void bgp_address_family_distance_delete(void) +{ + afi_t afi = AFI_UNSPEC; + safi_t safi = SAFI_UNSPEC; + struct bgp_dest *dest = NULL; + struct bgp_distance *bdistance = NULL; + + FOREACH_AFI_SAFI (afi, safi) { + for (dest = bgp_table_top(bgp_distance_table[afi][safi]); dest; + dest = bgp_route_next(dest)) { + if (!bgp_dest_has_bgp_path_info_data(dest)) + continue; + bdistance = bgp_dest_get_bgp_distance_info(dest); + XFREE(MTYPE_AS_LIST, bdistance->access_list); + bgp_distance_free(bdistance); + + bgp_dest_set_bgp_distance_info(dest, NULL); + bgp_dest_unlock_node(dest); + } + } +} + /* Apply BGP information to distance method. */ uint8_t bgp_distance_apply(const struct prefix *p, struct bgp_path_info *pinfo, afi_t afi, safi_t safi, struct bgp *bgp) |
