diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 958a9c6492b5..16b149e5b567 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3115,6 +3115,7 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, afi_t afi; safi_t safi; uint32_t prefix_cnt, path_cnt; + int first = true; afi = AFI_L2VPN; safi = SAFI_EVPN; @@ -3139,8 +3140,15 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, prefix_rd2str((struct prefix_rd *)rd_destp, rd_str, 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(); + } rd_header = 1; @@ -3255,18 +3263,18 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, } if (json) { - if (add_rd_to_json) - json_object_object_add(json, rd_str, json_rd); - else { + if (add_rd_to_json) { + vty_json_no_pretty(vty, json_rd); + } else { + vty_out(vty, "{}"); json_object_free(json_rd); - json_rd = NULL; } } } if (json) { - json_object_int_add(json, "numPrefix", prefix_cnt); - json_object_int_add(json, "numPaths", path_cnt); + vty_out(vty, ",\"numPrefix\":%u", prefix_cnt); + vty_out(vty, ",\"numPaths\":%u", path_cnt); } else { if (prefix_cnt == 0) { vty_out(vty, "No EVPN prefixes %sexist\n", @@ -3284,20 +3292,18 @@ int bgp_evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, { json_object *json = NULL; - if (use_json) + if (use_json) { json = json_object_new_object(); + vty_out(vty, "{\n"); + } evpn_show_all_routes(vty, bgp, type, json, detail, false); - if (use_json) - /* - * We are using no_pretty here because under extremely high - * 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); + if (use_json) { + vty_out(vty, "}\n"); + json_object_free(json); + } + return CMD_SUCCESS; } @@ -4946,8 +4952,10 @@ DEFUN(show_bgp_l2vpn_evpn_route, if (!bgp) return CMD_WARNING; - if (uj) + if (uj) { json = json_object_new_object(); + vty_out(vty, "{\n"); + } if (bgp_evpn_cli_parse_type(&type, argv, argc) < 0) return CMD_WARNING; @@ -4960,13 +4968,10 @@ DEFUN(show_bgp_l2vpn_evpn_route, evpn_show_all_routes(vty, bgp, type, json, detail, self_orig); - /* - * This is an extremely expensive operation at scale - * and as such we need to save as much time as is - * possible. - */ - if (uj) - vty_json_no_pretty(vty, json); + if (uj) { + vty_out(vty, "}\n"); + json_object_free(json); + } return CMD_SUCCESS; } @@ -5023,10 +5028,20 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, if (bgp_evpn_cli_parse_type(&type, argv, argc) < 0) 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); - else + + if (uj) { + vty_out(vty, "}\n"); + json_object_free(json); + return CMD_SUCCESS; + } + } else { evpn_show_route_rd(vty, bgp, &prd, type, json); + } if (uj) vty_json(vty, json); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 357d5292dabb..8d1512f80d3f 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -964,9 +964,8 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, json_object_object_add(json, "nexthops", json_gates); } -static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, - struct bgp_nexthop_cache *bnc, bool specific, - json_object *json) +static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, struct bgp_nexthop_cache *bnc, + bool detail, bool uj) { char buf[PREFIX2STR_BUFFER]; time_t tbuf; @@ -977,10 +976,10 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, peer = (struct peer *)bnc->nht_info; - if (json) + if (uj) json_nexthop = json_object_new_object(); if (bnc->srte_color) { - if (json) + if (uj) json_object_int_add(json_nexthop, "srteColor", bnc->srte_color); else @@ -988,7 +987,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, buf, sizeof(buf)); 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, "complete"); json_object_int_add(json_nexthop, "igpMetric", @@ -1016,7 +1015,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); } 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_false_add(json_nexthop, "complete"); json_object_int_add(json_nexthop, "igpMetric", @@ -1036,7 +1035,7 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); } else { - if (json) { + if (uj) { json_object_boolean_false_add(json_nexthop, "valid"); json_object_boolean_false_add(json_nexthop, "complete"); json_object_int_add(json_nexthop, "pathCount", @@ -1068,8 +1067,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } } tbuf = time(NULL) - (monotime(NULL) - bnc->last_update); - if (json) { - if (!specific) { + if (uj) { + if (detail) { json_last_update = json_object_new_object(); json_object_int_add(json_last_update, "epoch", tbuf); json_object_string_add(json_last_update, "string", @@ -1084,22 +1083,25 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } /* show paths dependent on nexthop, if needed. */ - if (specific) + if (detail) 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, - bool import_table, json_object *json, afi_t afi, - bool detail) +static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, bool import_table, bool uj, + afi_t afi, bool detail) { struct bgp_nexthop_cache *bnc; struct bgp_nexthop_cache_head(*tree)[AFI_MAX]; - json_object *json_afi = NULL; bool found = false; + bool firstafi = true; + bool firstnh = true; - if (!json) { + if (!uj) { if (import_table) vty_out(vty, "Current BGP import check cache:\n"); else @@ -1111,34 +1113,42 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, tree = &bgp->nexthop_cache_table; if (afi == AFI_IP || afi == AFI_IP6) { - if (json) - json_afi = json_object_new_object(); + if (uj) + vty_out(vty, "%s:{", (afi == AFI_IP) ? "\"ipv4\"" : "\"ipv6\""); 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; + firstnh = false; } - if (found && json) - json_object_object_add( - json, (afi == AFI_IP) ? "ipv4" : "ipv6", - json_afi); + if (found && uj) + vty_out(vty, "}"); return; } for (afi = AFI_IP; afi < AFI_MAX; afi++) { - if (json && (afi == AFI_IP || afi == AFI_IP6)) - json_afi = json_object_new_object(); - frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) - bgp_show_nexthop(vty, bgp, bnc, detail, json_afi); - if (json && (afi == AFI_IP || afi == AFI_IP6)) - json_object_object_add( - json, (afi == AFI_IP) ? "ipv4" : "ipv6", - json_afi); + if (afi != AFI_IP && afi != AFI_IP6) + continue; + if (uj) + vty_out(vty, "%s%s:{", firstafi ? "" : ",", + (afi == AFI_IP) ? "\"ipv4\"" : "\"ipv6\""); + firstafi = false; + firstnh = true; + 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, - const char *nhopip_str, bool import_table, - json_object *json, afi_t afi, bool detail) +static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, const char *nhopip_str, + bool import_table, bool uj, afi_t afi, bool detail) { struct bgp *bgp; @@ -1147,7 +1157,7 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, else bgp = bgp_get_default(); if (!bgp) { - if (!json) + if (!uj) vty_out(vty, "%% No such BGP instance exist\n"); return CMD_WARNING; } @@ -1157,61 +1167,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 *bnc; bool found = false; - json_object *json_afi = NULL; if (!str2prefix(nhopip_str, &nhop)) { - if (!json) + if (!uj) vty_out(vty, "nexthop address is malformed\n"); return CMD_WARNING; } tree = import_table ? &bgp->import_check_table : &bgp->nexthop_cache_table; - if (json) - json_afi = json_object_new_object(); + if (uj) + vty_out(vty, "%s:{", + (family2afi(nhop.family) == AFI_IP) ? "\"ipv4\"" : "\"ipv6\""); frr_each (bgp_nexthop_cache, &(*tree)[family2afi(nhop.family)], bnc) { if (prefix_cmp(&bnc->prefix, &nhop)) continue; - bgp_show_nexthop(vty, bgp, bnc, true, json_afi); + bgp_show_nexthop(vty, bgp, bnc, true, uj); found = true; } - if (json) - json_object_object_add( - json, - (family2afi(nhop.family) == AFI_IP) ? "ipv4" - : "ipv6", - json_afi); - if (!found && !json) + if (!found && !uj) vty_out(vty, "nexthop %s does not have entry\n", nhopip_str); + + if (uj) + vty_out(vty, "}"); } else - bgp_show_nexthops(vty, bgp, import_table, json, afi, detail); + bgp_show_nexthops(vty, bgp, import_table, uj, afi, detail); return CMD_SUCCESS; } -static void bgp_show_all_instances_nexthops_vty(struct vty *vty, - json_object *json, afi_t afi, - bool detail) +static void bgp_show_all_instances_nexthops_vty(struct vty *vty, bool uj, afi_t afi, bool detail) { struct listnode *node, *nnode; struct bgp *bgp; const char *inst_name; - json_object *json_instance = NULL; + bool firstinst = true; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { inst_name = (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) ? VRF_DEFAULT_NAME : bgp->name; - if (json) - json_instance = json_object_new_object(); + if (uj) + vty_out(vty, "%s\"%s\":{", firstinst ? "" : ",", inst_name); + else vty_out(vty, "\nInstance %s:\n", inst_name); - bgp_show_nexthops(vty, bgp, false, json_instance, afi, detail); - - if (json) - json_object_object_add(json, inst_name, json_instance); + bgp_show_nexthops(vty, bgp, false, uj, afi, detail); + firstinst = false; + if (uj) + vty_out(vty, "}"); } } @@ -1235,20 +1241,18 @@ DEFPY (show_ip_bgp_nexthop, JSON_STR) { int rc = 0; - json_object *json = NULL; afi_t afiz = AFI_UNSPEC; if (uj) - json = json_object_new_object(); + vty_out(vty, "{\n"); if (afi) afiz = bgp_vty_afi_from_str(afi); - rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, json, afiz, - detail); + rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, uj, afiz, detail); if (uj) - vty_json(vty, json); + vty_out(vty, "}\n"); return rc; } @@ -1265,16 +1269,14 @@ DEFPY (show_ip_bgp_import_check, JSON_STR) { int rc = 0; - json_object *json = NULL; if (uj) - json = json_object_new_object(); + vty_out(vty, "{\n"); - rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, json, AFI_UNSPEC, - detail); + rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, uj, AFI_UNSPEC, detail); if (uj) - vty_json(vty, json); + vty_out(vty, "}\n"); return rc; } @@ -1292,19 +1294,18 @@ DEFPY (show_ip_bgp_instance_all_nexthop, "Show detailed information\n" JSON_STR) { - json_object *json = NULL; afi_t afiz = AFI_UNSPEC; if (uj) - json = json_object_new_object(); + vty_out(vty, "{"); if (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) - vty_json(vty, json); + vty_out(vty, "}"); return CMD_SUCCESS; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 17d25f8248b9..35b9a1f90637 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -14879,6 +14879,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). @@ -14947,6 +14949,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)) { @@ -14965,6 +14989,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); @@ -14978,34 +15003,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", @@ -15108,6 +15155,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); @@ -15149,9 +15197,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"); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e86d1dc65612..c2c405b55ac2 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -11520,6 +11520,72 @@ DEFPY (show_bgp_vrfs, 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, show_bgp_mac_hash_cmd, "show bgp mac hash", @@ -21934,6 +22000,9 @@ void bgp_vty_init(void) /* "show [ip] bgp vrfs" commands. */ install_element(VIEW_NODE, &show_bgp_vrfs_cmd); + /* Some overall BGP information */ + install_element(VIEW_NODE, &show_bgp_router_cmd); + /* Community-list. */ community_list_vty(); diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 0c7fcecb9b96..21d92a2f29b9 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -4349,6 +4349,10 @@ displays IPv6 routing table. If ``detail`` option is specified after ``json``, more verbose JSON output 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. .. clicmd:: show [ip] bgp regexp LINE diff --git a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py index 5d8338d6eb2a..7e39b83d8fd9 100644 --- a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py +++ b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py @@ -187,6 +187,16 @@ def _bgp_clear_r1_and_shutdown(): """ ) + 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") test_func = functools.partial(_bgp_converge) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) @@ -205,6 +215,11 @@ def _bgp_clear_r1_and_shutdown(): _, 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" + 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__": args = ["-s"] + sys.argv[1:]