Merge pull request #17431 from krishna-samy/bgpd_json_commits

bgpd: show json output changes to optimize various show commands
This commit is contained in:
Russ White 2025-01-07 08:43:55 -05:00 committed by GitHub
commit c9c9608c70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 288 additions and 123 deletions

View file

@ -3108,6 +3108,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
afi_t afi; afi_t afi;
safi_t safi; safi_t safi;
uint32_t prefix_cnt, path_cnt; uint32_t prefix_cnt, path_cnt;
int first = true;
afi = AFI_L2VPN; afi = AFI_L2VPN;
safi = SAFI_EVPN; safi = SAFI_EVPN;
@ -3132,8 +3133,15 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
prefix_rd2str((struct prefix_rd *)rd_destp, rd_str, prefix_rd2str((struct prefix_rd *)rd_destp, rd_str,
sizeof(rd_str), bgp->asnotation); sizeof(rd_str), bgp->asnotation);
if (json) if (json) {
if (first) {
vty_out(vty, "\"%s\":", rd_str);
first = false;
} else {
vty_out(vty, ",\"%s\":", rd_str);
}
json_rd = json_object_new_object(); json_rd = json_object_new_object();
}
rd_header = 1; rd_header = 1;
@ -3247,18 +3255,18 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
} }
if (json) { if (json) {
if (add_rd_to_json) if (add_rd_to_json) {
json_object_object_add(json, rd_str, json_rd); vty_json_no_pretty(vty, json_rd);
else { } else {
vty_out(vty, "{}");
json_object_free(json_rd); json_object_free(json_rd);
json_rd = NULL;
} }
} }
} }
if (json) { if (json) {
json_object_int_add(json, "numPrefix", prefix_cnt); vty_out(vty, ",\"numPrefix\":%u", prefix_cnt);
json_object_int_add(json, "numPaths", path_cnt); vty_out(vty, ",\"numPaths\":%u", path_cnt);
} else { } else {
if (prefix_cnt == 0) { if (prefix_cnt == 0) {
vty_out(vty, "No EVPN prefixes %sexist\n", vty_out(vty, "No EVPN prefixes %sexist\n",
@ -3276,20 +3284,18 @@ int bgp_evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type,
{ {
json_object *json = NULL; json_object *json = NULL;
if (use_json) if (use_json) {
json = json_object_new_object(); json = json_object_new_object();
vty_out(vty, "{\n");
}
evpn_show_all_routes(vty, bgp, type, json, detail, false); evpn_show_all_routes(vty, bgp, type, json, detail, false);
if (use_json) if (use_json) {
/* vty_out(vty, "}\n");
* We are using no_pretty here because under extremely high json_object_free(json);
* settings (lots of routes with many different paths) this can }
* save several minutes of output when FRR is run on older cpu's
* or more underperforming routers out there. So for route
* scale, we need to use no_pretty json.
*/
vty_json_no_pretty(vty, json);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -4940,8 +4946,10 @@ DEFUN(show_bgp_l2vpn_evpn_route,
if (!bgp) if (!bgp)
return CMD_WARNING; return CMD_WARNING;
if (uj) if (uj) {
json = json_object_new_object(); json = json_object_new_object();
vty_out(vty, "{\n");
}
if (bgp_evpn_cli_parse_type(&type, argv, argc) < 0) if (bgp_evpn_cli_parse_type(&type, argv, argc) < 0)
return CMD_WARNING; return CMD_WARNING;
@ -4954,13 +4962,10 @@ DEFUN(show_bgp_l2vpn_evpn_route,
evpn_show_all_routes(vty, bgp, type, json, detail, self_orig); evpn_show_all_routes(vty, bgp, type, json, detail, self_orig);
/* if (uj) {
* This is an extremely expensive operation at scale vty_out(vty, "}\n");
* and as such we need to save as much time as is json_object_free(json);
* possible. }
*/
if (uj)
vty_json_no_pretty(vty, json);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -5017,10 +5022,20 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd,
if (bgp_evpn_cli_parse_type(&type, argv, argc) < 0) if (bgp_evpn_cli_parse_type(&type, argv, argc) < 0)
return CMD_WARNING; return CMD_WARNING;
if (rd_all) if (rd_all) {
if (uj)
vty_out(vty, "{\n");
evpn_show_all_routes(vty, bgp, type, json, 1, false); evpn_show_all_routes(vty, bgp, type, json, 1, false);
else
if (uj) {
vty_out(vty, "}\n");
json_object_free(json);
return CMD_SUCCESS;
}
} else {
evpn_show_route_rd(vty, bgp, &prd, type, json); evpn_show_route_rd(vty, bgp, &prd, type, json);
}
if (uj) if (uj)
vty_json(vty, json); vty_json(vty, json);

View file

@ -970,9 +970,8 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
json_object_object_add(json, "nexthops", json_gates); json_object_object_add(json, "nexthops", json_gates);
} }
static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, struct bgp_nexthop_cache *bnc,
struct bgp_nexthop_cache *bnc, bool specific, bool detail, bool uj)
json_object *json)
{ {
char buf[PREFIX2STR_BUFFER]; char buf[PREFIX2STR_BUFFER];
time_t tbuf; time_t tbuf;
@ -983,10 +982,10 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
peer = (struct peer *)bnc->nht_info; peer = (struct peer *)bnc->nht_info;
if (json) if (uj)
json_nexthop = json_object_new_object(); json_nexthop = json_object_new_object();
if (bnc->srte_color) { if (bnc->srte_color) {
if (json) if (uj)
json_object_int_add(json_nexthop, "srteColor", json_object_int_add(json_nexthop, "srteColor",
bnc->srte_color); bnc->srte_color);
else else
@ -994,7 +993,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
} }
inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, buf, sizeof(buf)); inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, buf, sizeof(buf));
if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) { if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
if (json) { if (uj) {
json_object_boolean_true_add(json_nexthop, "valid"); json_object_boolean_true_add(json_nexthop, "valid");
json_object_boolean_true_add(json_nexthop, "complete"); json_object_boolean_true_add(json_nexthop, "complete");
json_object_int_add(json_nexthop, "igpMetric", json_object_int_add(json_nexthop, "igpMetric",
@ -1022,7 +1021,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
} }
bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop);
} else if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) { } else if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) {
if (json) { if (uj) {
json_object_boolean_true_add(json_nexthop, "valid"); json_object_boolean_true_add(json_nexthop, "valid");
json_object_boolean_false_add(json_nexthop, "complete"); json_object_boolean_false_add(json_nexthop, "complete");
json_object_int_add(json_nexthop, "igpMetric", json_object_int_add(json_nexthop, "igpMetric",
@ -1042,7 +1041,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
} }
bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop);
} else { } else {
if (json) { if (uj) {
json_object_boolean_false_add(json_nexthop, "valid"); json_object_boolean_false_add(json_nexthop, "valid");
json_object_boolean_false_add(json_nexthop, "complete"); json_object_boolean_false_add(json_nexthop, "complete");
json_object_int_add(json_nexthop, "pathCount", json_object_int_add(json_nexthop, "pathCount",
@ -1074,8 +1073,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
} }
} }
tbuf = time(NULL) - (monotime(NULL) - bnc->last_update); tbuf = time(NULL) - (monotime(NULL) - bnc->last_update);
if (json) { if (uj) {
if (!specific) { if (detail) {
json_last_update = json_object_new_object(); json_last_update = json_object_new_object();
json_object_int_add(json_last_update, "epoch", tbuf); json_object_int_add(json_last_update, "epoch", tbuf);
json_object_string_add(json_last_update, "string", json_object_string_add(json_last_update, "string",
@ -1090,22 +1089,25 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
} }
/* show paths dependent on nexthop, if needed. */ /* show paths dependent on nexthop, if needed. */
if (specific) if (detail)
bgp_show_nexthop_paths(vty, bgp, bnc, json_nexthop); bgp_show_nexthop_paths(vty, bgp, bnc, json_nexthop);
if (json)
json_object_object_add(json, buf, json_nexthop); if (uj) {
vty_out(vty, "\"%s\":", buf);
vty_json_no_pretty(vty, json_nexthop);
}
} }
static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, bool import_table, bool uj,
bool import_table, json_object *json, afi_t afi, afi_t afi, bool detail)
bool detail)
{ {
struct bgp_nexthop_cache *bnc; struct bgp_nexthop_cache *bnc;
struct bgp_nexthop_cache_head(*tree)[AFI_MAX]; struct bgp_nexthop_cache_head(*tree)[AFI_MAX];
json_object *json_afi = NULL;
bool found = false; bool found = false;
bool firstafi = true;
bool firstnh = true;
if (!json) { if (!uj) {
if (import_table) if (import_table)
vty_out(vty, "Current BGP import check cache:\n"); vty_out(vty, "Current BGP import check cache:\n");
else else
@ -1117,34 +1119,42 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp,
tree = &bgp->nexthop_cache_table; tree = &bgp->nexthop_cache_table;
if (afi == AFI_IP || afi == AFI_IP6) { if (afi == AFI_IP || afi == AFI_IP6) {
if (json) if (uj)
json_afi = json_object_new_object(); vty_out(vty, "%s:{", (afi == AFI_IP) ? "\"ipv4\"" : "\"ipv6\"");
frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) { frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) {
bgp_show_nexthop(vty, bgp, bnc, detail, json_afi); if (uj)
vty_out(vty, "%s", firstnh ? "" : ",");
bgp_show_nexthop(vty, bgp, bnc, detail, uj);
found = true; found = true;
firstnh = false;
} }
if (found && json) if (found && uj)
json_object_object_add( vty_out(vty, "}");
json, (afi == AFI_IP) ? "ipv4" : "ipv6",
json_afi);
return; return;
} }
for (afi = AFI_IP; afi < AFI_MAX; afi++) { for (afi = AFI_IP; afi < AFI_MAX; afi++) {
if (json && (afi == AFI_IP || afi == AFI_IP6)) if (afi != AFI_IP && afi != AFI_IP6)
json_afi = json_object_new_object(); continue;
frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) if (uj)
bgp_show_nexthop(vty, bgp, bnc, detail, json_afi); vty_out(vty, "%s%s:{", firstafi ? "" : ",",
if (json && (afi == AFI_IP || afi == AFI_IP6)) (afi == AFI_IP) ? "\"ipv4\"" : "\"ipv6\"");
json_object_object_add( firstafi = false;
json, (afi == AFI_IP) ? "ipv4" : "ipv6", firstnh = true;
json_afi); frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) {
if (uj)
vty_out(vty, "%s", firstnh ? "" : ",");
bgp_show_nexthop(vty, bgp, bnc, detail, uj);
firstnh = false;
}
if (uj)
vty_out(vty, "}");
} }
} }
static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, const char *nhopip_str,
const char *nhopip_str, bool import_table, bool import_table, bool uj, afi_t afi, bool detail)
json_object *json, afi_t afi, bool detail)
{ {
struct bgp *bgp; struct bgp *bgp;
@ -1153,7 +1163,7 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
else else
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) { if (!bgp) {
if (!json) if (!uj)
vty_out(vty, "%% No such BGP instance exist\n"); vty_out(vty, "%% No such BGP instance exist\n");
return CMD_WARNING; return CMD_WARNING;
} }
@ -1163,61 +1173,57 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
struct bgp_nexthop_cache_head (*tree)[AFI_MAX]; struct bgp_nexthop_cache_head (*tree)[AFI_MAX];
struct bgp_nexthop_cache *bnc; struct bgp_nexthop_cache *bnc;
bool found = false; bool found = false;
json_object *json_afi = NULL;
if (!str2prefix(nhopip_str, &nhop)) { if (!str2prefix(nhopip_str, &nhop)) {
if (!json) if (!uj)
vty_out(vty, "nexthop address is malformed\n"); vty_out(vty, "nexthop address is malformed\n");
return CMD_WARNING; return CMD_WARNING;
} }
tree = import_table ? &bgp->import_check_table tree = import_table ? &bgp->import_check_table
: &bgp->nexthop_cache_table; : &bgp->nexthop_cache_table;
if (json) if (uj)
json_afi = json_object_new_object(); vty_out(vty, "%s:{",
(family2afi(nhop.family) == AFI_IP) ? "\"ipv4\"" : "\"ipv6\"");
frr_each (bgp_nexthop_cache, &(*tree)[family2afi(nhop.family)], frr_each (bgp_nexthop_cache, &(*tree)[family2afi(nhop.family)],
bnc) { bnc) {
if (prefix_cmp(&bnc->prefix, &nhop)) if (prefix_cmp(&bnc->prefix, &nhop))
continue; continue;
bgp_show_nexthop(vty, bgp, bnc, true, json_afi); bgp_show_nexthop(vty, bgp, bnc, true, uj);
found = true; found = true;
} }
if (json) if (!found && !uj)
json_object_object_add(
json,
(family2afi(nhop.family) == AFI_IP) ? "ipv4"
: "ipv6",
json_afi);
if (!found && !json)
vty_out(vty, "nexthop %s does not have entry\n", vty_out(vty, "nexthop %s does not have entry\n",
nhopip_str); nhopip_str);
if (uj)
vty_out(vty, "}");
} else } else
bgp_show_nexthops(vty, bgp, import_table, json, afi, detail); bgp_show_nexthops(vty, bgp, import_table, uj, afi, detail);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
static void bgp_show_all_instances_nexthops_vty(struct vty *vty, static void bgp_show_all_instances_nexthops_vty(struct vty *vty, bool uj, afi_t afi, bool detail)
json_object *json, afi_t afi,
bool detail)
{ {
struct listnode *node, *nnode; struct listnode *node, *nnode;
struct bgp *bgp; struct bgp *bgp;
const char *inst_name; const char *inst_name;
json_object *json_instance = NULL; bool firstinst = true;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
inst_name = (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) inst_name = (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
? VRF_DEFAULT_NAME ? VRF_DEFAULT_NAME
: bgp->name; : bgp->name;
if (json) if (uj)
json_instance = json_object_new_object(); vty_out(vty, "%s\"%s\":{", firstinst ? "" : ",", inst_name);
else else
vty_out(vty, "\nInstance %s:\n", inst_name); vty_out(vty, "\nInstance %s:\n", inst_name);
bgp_show_nexthops(vty, bgp, false, json_instance, afi, detail); bgp_show_nexthops(vty, bgp, false, uj, afi, detail);
firstinst = false;
if (json) if (uj)
json_object_object_add(json, inst_name, json_instance); vty_out(vty, "}");
} }
} }
@ -1241,20 +1247,18 @@ DEFPY (show_ip_bgp_nexthop,
JSON_STR) JSON_STR)
{ {
int rc = 0; int rc = 0;
json_object *json = NULL;
afi_t afiz = AFI_UNSPEC; afi_t afiz = AFI_UNSPEC;
if (uj) if (uj)
json = json_object_new_object(); vty_out(vty, "{\n");
if (afi) if (afi)
afiz = bgp_vty_afi_from_str(afi); afiz = bgp_vty_afi_from_str(afi);
rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, json, afiz, rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, uj, afiz, detail);
detail);
if (uj) if (uj)
vty_json(vty, json); vty_out(vty, "}\n");
return rc; return rc;
} }
@ -1271,16 +1275,14 @@ DEFPY (show_ip_bgp_import_check,
JSON_STR) JSON_STR)
{ {
int rc = 0; int rc = 0;
json_object *json = NULL;
if (uj) if (uj)
json = json_object_new_object(); vty_out(vty, "{\n");
rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, json, AFI_UNSPEC, rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, uj, AFI_UNSPEC, detail);
detail);
if (uj) if (uj)
vty_json(vty, json); vty_out(vty, "}\n");
return rc; return rc;
} }
@ -1298,19 +1300,18 @@ DEFPY (show_ip_bgp_instance_all_nexthop,
"Show detailed information\n" "Show detailed information\n"
JSON_STR) JSON_STR)
{ {
json_object *json = NULL;
afi_t afiz = AFI_UNSPEC; afi_t afiz = AFI_UNSPEC;
if (uj) if (uj)
json = json_object_new_object(); vty_out(vty, "{");
if (afi) if (afi)
afiz = bgp_vty_afi_from_str(afi); afiz = bgp_vty_afi_from_str(afi);
bgp_show_all_instances_nexthops_vty(vty, json, afiz, detail); bgp_show_all_instances_nexthops_vty(vty, uj, afiz, detail);
if (uj) if (uj)
vty_json(vty, json); vty_out(vty, "}");
return CMD_SUCCESS; return CMD_SUCCESS;
} }

View file

@ -15106,6 +15106,8 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
json_object *json = NULL; json_object *json = NULL;
json_object *json_ar = NULL; json_object *json_ar = NULL;
bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); 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 /* Init BGP headers here so they're only displayed once
* even if 'table' is 2-tier (MPLS_VPN, ENCAP, EVPN). * even if 'table' is 2-tier (MPLS_VPN, ENCAP, EVPN).
@ -15174,6 +15176,28 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
else else
table = bgp->rib[afi][safi]; 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) if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP)
|| (safi == SAFI_EVPN)) { || (safi == SAFI_EVPN)) {
@ -15192,6 +15216,7 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
json_routes = json_object_new_object(); json_routes = json_object_new_object();
const struct prefix_rd *prd; const struct prefix_rd *prd;
prd = (const struct prefix_rd *)bgp_dest_get_prefix( prd = (const struct prefix_rd *)bgp_dest_get_prefix(
dest); dest);
@ -15205,34 +15230,56 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
&filtered_count_per_rd); &filtered_count_per_rd);
/* Don't include an empty RD in the output! */ /* Don't include an empty RD in the output! */
if (json_routes && (output_count_per_rd > 0)) if (json_routes && (output_count_per_rd > 0) && use_json) {
json_object_object_add(json_ar, rd_str, if (type == bgp_show_adj_route_advertised ||
json_routes); 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; output_count += output_count_per_rd;
filtered_count += filtered_count_per_rd; filtered_count += filtered_count_per_rd;
} }
} else } else {
show_adj_route(vty, peer, table, afi, safi, type, rmap_name, show_adj_route(vty, peer, table, afi, safi, type, rmap_name,
json, json_ar, show_flags, &header1, &header2, json, json_ar, show_flags, &header1, &header2,
rd_str, match, &output_count, &filtered_count); rd_str, match, &output_count, &filtered_count);
if (use_json) { if (use_json) {
if (type == bgp_show_adj_route_advertised) if (type == bgp_show_adj_route_advertised ||
json_object_object_add(json, "advertisedRoutes", type == bgp_show_adj_route_received) {
json_ar); vty_json_no_pretty(vty, json_ar);
else }
json_object_object_add(json, "receivedRoutes", json_ar); }
json_object_int_add(json, "totalPrefixCounter", output_count); }
json_object_int_add(json, "filteredPrefixCounter",
filtered_count);
/* if (use_json) {
* This is an extremely expensive operation at scale if (type == bgp_show_adj_route_advertised || type == bgp_show_adj_route_received) {
* and non-pretty reduces memory footprint significantly. vty_out(vty, ",\"totalPrefixCounter\":%lu", output_count);
*/ vty_out(vty, ",\"filteredPrefixCounter\":%lu", filtered_count);
vty_json_no_pretty(vty, json); json_object_free(json);
} else if (output_count > 0) { } 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.
*/
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) if (!match && filtered_count > 0)
vty_out(vty, vty_out(vty,
"\nTotal number of prefixes %ld (%ld filtered)\n", "\nTotal number of prefixes %ld (%ld filtered)\n",
@ -15335,6 +15382,7 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route,
uint16_t show_flags = 0; uint16_t show_flags = 0;
struct listnode *node; struct listnode *node;
struct bgp *abgp; struct bgp *abgp;
int ret;
if (detail || prefix_str) if (detail || prefix_str)
SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL); SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL);
@ -15376,9 +15424,22 @@ DEFPY(show_ip_bgp_instance_neighbor_advertised_route,
else if (argv_find(argv, argc, "filtered-routes", &idx)) else if (argv_find(argv, argc, "filtered-routes", &idx))
type = bgp_show_adj_route_filtered; type = bgp_show_adj_route_filtered;
if (!all) if (!all) {
return peer_adj_routes(vty, peer, afi, safi, type, route_map, if (uj)
prefix_str ? prefix : NULL, show_flags); 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) if (uj)
vty_out(vty, "{\n"); vty_out(vty, "{\n");

View file

@ -11476,6 +11476,72 @@ DEFPY (show_bgp_vrfs,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFPY(show_bgp_router,
show_bgp_router_cmd,
"show bgp router [json]",
SHOW_STR
BGP_STR
"Overall BGP information\n"
JSON_STR)
{
char timebuf[MONOTIME_STRLEN];
time_t unix_timestamp;
bool uj = use_json(argc, argv);
json_object *json = NULL;
if (uj)
json = json_object_new_object();
time_to_string(bm->start_time, timebuf);
if (uj) {
unix_timestamp = time(NULL) - (monotime(NULL) - bm->start_time);
json_object_int_add(json, "bgpStartedAt", unix_timestamp);
json_object_boolean_add(json, "bgpStartedGracefully",
CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART));
}
if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART)) {
if (!uj)
vty_out(vty, "BGP started gracefully at %s", timebuf);
else
json_object_boolean_add(json, "grComplete",
CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE));
if (CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)) {
time_to_string(bm->gr_completion_time, timebuf);
if (uj) {
unix_timestamp = time(NULL) -
(monotime(NULL) - bm->gr_completion_time);
json_object_int_add(json, "grCompletedAt", unix_timestamp);
} else
vty_out(vty, "Graceful restart completed at %s", timebuf);
} else {
if (!uj)
vty_out(vty, "Graceful restart is in progress\n");
}
} else {
if (!uj)
vty_out(vty, "BGP started at %s", timebuf);
}
if (uj) {
json_object_boolean_add(json, "bgpInMaintenanceMode",
(CHECK_FLAG(bm->flags, BM_FLAG_MAINTENANCE_MODE)));
json_object_int_add(json, "bgpInstanceCount", listcount(bm->bgp));
vty_json(vty, json);
} else {
if (CHECK_FLAG(bm->flags, BM_FLAG_MAINTENANCE_MODE))
vty_out(vty, "BGP is in Maintenance mode (BGP GSHUT is in effect)\n");
vty_out(vty, "Number of BGP instances (including default): %d\n",
listcount(bm->bgp));
}
return CMD_SUCCESS;
}
DEFUN (show_bgp_mac_hash, DEFUN (show_bgp_mac_hash,
show_bgp_mac_hash_cmd, show_bgp_mac_hash_cmd,
"show bgp mac hash", "show bgp mac hash",
@ -21927,6 +21993,9 @@ void bgp_vty_init(void)
/* "show [ip] bgp vrfs" commands. */ /* "show [ip] bgp vrfs" commands. */
install_element(VIEW_NODE, &show_bgp_vrfs_cmd); install_element(VIEW_NODE, &show_bgp_vrfs_cmd);
/* Some overall BGP information */
install_element(VIEW_NODE, &show_bgp_router_cmd);
/* Community-list. */ /* Community-list. */
community_list_vty(); community_list_vty();

View file

@ -4350,6 +4350,10 @@ displays IPv6 routing table.
If ``detail`` option is specified after ``json``, more verbose JSON output If ``detail`` option is specified after ``json``, more verbose JSON output
will be displayed. will be displayed.
.. clicmd:: show bgp router [json]
This command displays information related BGP router and Graceful Restart.
Some other commands provide additional options for filtering the output. Some other commands provide additional options for filtering the output.
.. clicmd:: show [ip] bgp regexp LINE .. clicmd:: show [ip] bgp regexp LINE

View file

@ -187,6 +187,16 @@ def test_bgp_administrative_reset_gr():
""" """
) )
def _bgp_verify_show_bgp_router_json():
output = json.loads(r1.vtysh_cmd("show bgp router json"))
expected = {
"bgpStartedAt": "*",
"bgpStartedGracefully": False,
"bgpInMaintenanceMode": False,
"bgpInstanceCount": 1,
}
return topotest.json_cmp(output, expected)
step("Initial BGP converge") step("Initial BGP converge")
test_func = functools.partial(_bgp_converge) test_func = functools.partial(_bgp_converge)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
@ -205,6 +215,11 @@ def test_bgp_administrative_reset_gr():
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed to send Administrative Reset notification from R2" assert result is None, "Failed to send Administrative Reset notification from R2"
step("Check show bgp router json")
test_func = functools.partial(_bgp_verify_show_bgp_router_json)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Invalid BGP router details"
if __name__ == "__main__": if __name__ == "__main__":
args = ["-s"] + sys.argv[1:] args = ["-s"] + sys.argv[1:]