summaryrefslogtreecommitdiff
path: root/bgpd/bgp_route.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_route.c')
-rw-r--r--bgpd/bgp_route.c625
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)