bgpd: JSON support for show ip bgp vrf all update-group

Ticket:#3229030
Testing Done: UT

Changes:

 - JSON support for the update group command.

Testing:

torc-11# show ip bgp vrf all ipv6 update-groups json

torc-12# show bgp vrf all update-groups json
{
  "default":{
    "2":{
      "groupCreateTime":{
        "epoch":1669225617,
        "epochString":"Wed Nov 23 17:46:57 2022\n"
      },
      "afi":"IPv6",
      "safi":"unicast",
      "outRouteMap":"MY_ORIGIN_ASPATH_ONLY",
      "minRouteAdvInt":0,
      "subGroup":[
        {
          "subGroupId":2,
          "groupCreateTime":{
            "epoch":1669225617,
            "epochString":"Wed Nov 23 17:46:57 2022\n"
          },
          "statistics":{
            "joinEvents":2,
            "pruneEvents":0,
            "mergeEvents":0,
            "splitEvents":0,
            "switchEvents":0,
            "peerRefreshEvents":0,
            "mergeCheckEvents":2
          },
          "coalesceTime":1100,
          "version":12,
          "packetQueueInfo":{
            "qeueueLen":0,
            "queuedTotal":1,
            "queueHwmLen":1,
            "totalEnqueued":1
          },
          "adjListCount":1,
          "needsRefresh":false,
          "peers":[
            "uplink_1",
            "uplink_2"
          ]
        }
      ]
    }
  }
}
{
  "sym_3":{
  }
}
{
  "sym_5":{
  }
}
{
  "sym_2":{
  }
}
{
  "sym_4":{
  }
}
{
  "sym_1":{
  }
}

Co-authored-by: Chirag Shah <chirag@nvidia.com>
Signed-off-by: Ashwini Reddy <ashred@nvidia.com>
This commit is contained in:
Ashwini Reddy 2022-11-07 11:53:48 -08:00 committed by Chirag Shah
parent a86afb3e0e
commit fa5a9276d1
4 changed files with 274 additions and 81 deletions

View File

@ -677,6 +677,15 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
struct bgp_filter *filter; struct bgp_filter *filter;
struct peer *peer = UPDGRP_PEER(updgrp); struct peer *peer = UPDGRP_PEER(updgrp);
int match = 0; int match = 0;
json_object *json_updgrp = NULL;
json_object *json_subgrps = NULL;
json_object *json_subgrp = NULL;
json_object *json_time = NULL;
json_object *json_subgrp_time = NULL;
json_object *json_subgrp_event = NULL;
json_object *json_peers = NULL;
json_object *json_pkt_info = NULL;
time_t epoch_tbuf, tbuf;
if (!ctx) if (!ctx)
return CMD_SUCCESS; return CMD_SUCCESS;
@ -703,79 +712,232 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
vty = ctx->vty; vty = ctx->vty;
vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id); if (ctx->uj) {
vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime)); json_updgrp = json_object_new_object();
filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi]; /* Display json o/p */
if (filter->map[RMAP_OUT].name) tbuf = monotime(NULL);
vty_out(vty, " Outgoing route map: %s\n", tbuf -= updgrp->uptime;
filter->map[RMAP_OUT].name); epoch_tbuf = time(NULL) - tbuf;
vty_out(vty, " MRAI value (seconds): %d\n", updgrp->conf->v_routeadv); json_time = json_object_new_object();
if (updgrp->conf->change_local_as) json_object_int_add(json_time, "epoch", epoch_tbuf);
vty_out(vty, " Local AS %u%s%s\n", json_object_string_add(json_time, "epochString",
updgrp->conf->change_local_as, ctime(&epoch_tbuf));
CHECK_FLAG(updgrp->conf->flags, json_object_object_add(json_updgrp, "groupCreateTime",
PEER_FLAG_LOCAL_AS_NO_PREPEND) json_time);
? " no-prepend" json_object_string_add(json_updgrp, "afi",
: "", afi2str(updgrp->afi));
CHECK_FLAG(updgrp->conf->flags, json_object_string_add(json_updgrp, "safi",
PEER_FLAG_LOCAL_AS_REPLACE_AS) safi2str(updgrp->safi));
? " replace-as" } else {
: ""); vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id);
vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime));
}
filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi];
if (filter->map[RMAP_OUT].name) {
if (ctx->uj)
json_object_string_add(json_updgrp, "outRouteMap",
filter->map[RMAP_OUT].name);
else
vty_out(vty, " Outgoing route map: %s\n",
filter->map[RMAP_OUT].name);
}
if (ctx->uj)
json_object_int_add(json_updgrp, "minRouteAdvInt",
updgrp->conf->v_routeadv);
else
vty_out(vty, " MRAI value (seconds): %d\n",
updgrp->conf->v_routeadv);
if (updgrp->conf->change_local_as) {
if (ctx->uj) {
json_object_int_add(json_updgrp, "localAs",
updgrp->conf->change_local_as);
json_object_boolean_add(
json_updgrp, "noPrepend",
CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_NO_PREPEND));
json_object_boolean_add(
json_updgrp, "replaceLocalAs",
CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_REPLACE_AS));
} else {
vty_out(vty, " Local AS %u%s%s\n",
updgrp->conf->change_local_as,
CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_NO_PREPEND)
? " no-prepend"
: "",
CHECK_FLAG(updgrp->conf->flags,
PEER_FLAG_LOCAL_AS_REPLACE_AS)
? " replace-as"
: "");
}
}
json_subgrps = json_object_new_array();
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) { UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id)) if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
continue; continue;
vty_out(vty, "\n"); if (ctx->uj) {
vty_out(vty, " Update-subgroup %" PRIu64 ":\n", subgrp->id); json_subgrp = json_object_new_object();
vty_out(vty, " Created: %s", json_object_int_add(json_subgrp, "subGroupId",
timestamp_string(subgrp->uptime)); subgrp->id);
tbuf = monotime(NULL);
tbuf -= subgrp->uptime;
epoch_tbuf = time(NULL) - tbuf;
json_subgrp_time = json_object_new_object();
json_object_int_add(json_subgrp_time, "epoch",
epoch_tbuf);
json_object_string_add(json_subgrp_time, "epochString",
ctime(&epoch_tbuf));
json_object_object_add(json_subgrp, "groupCreateTime",
json_subgrp_time);
} else {
vty_out(vty, "\n");
vty_out(vty, " Update-subgroup %" PRIu64 ":\n",
subgrp->id);
vty_out(vty, " Created: %s",
timestamp_string(subgrp->uptime));
}
if (subgrp->split_from.update_group_id if (subgrp->split_from.update_group_id
|| subgrp->split_from.subgroup_id) { || subgrp->split_from.subgroup_id) {
vty_out(vty, " Split from group id: %" PRIu64 "\n", if (ctx->uj) {
subgrp->split_from.update_group_id); json_object_int_add(
vty_out(vty, json_subgrp, "splitGroupId",
" Split from subgroup id: %" PRIu64 "\n", subgrp->split_from.update_group_id);
subgrp->split_from.subgroup_id); json_object_int_add(
json_subgrp, "splitSubGroupId",
subgrp->split_from.subgroup_id);
} else {
vty_out(vty,
" Split from group id: %" PRIu64
"\n",
subgrp->split_from.update_group_id);
vty_out(vty,
" Split from subgroup id: %" PRIu64
"\n",
subgrp->split_from.subgroup_id);
}
} }
vty_out(vty, " Join events: %u\n", subgrp->join_events); if (ctx->uj) {
vty_out(vty, " Prune events: %u\n", subgrp->prune_events); json_subgrp_event = json_object_new_object();
vty_out(vty, " Merge events: %u\n", subgrp->merge_events); json_object_int_add(json_subgrp_event, "joinEvents",
vty_out(vty, " Split events: %u\n", subgrp->split_events); subgrp->join_events);
vty_out(vty, " Update group switch events: %u\n", json_object_int_add(json_subgrp_event, "pruneEvents",
subgrp->updgrp_switch_events); subgrp->prune_events);
vty_out(vty, " Peer refreshes combined: %u\n", json_object_int_add(json_subgrp_event, "mergeEvents",
subgrp->peer_refreshes_combined); subgrp->merge_events);
vty_out(vty, " Merge checks triggered: %u\n", json_object_int_add(json_subgrp_event, "splitEvents",
subgrp->merge_checks_triggered); subgrp->split_events);
vty_out(vty, " Coalesce Time: %u%s\n", json_object_int_add(json_subgrp_event, "switchEvents",
(UPDGRP_INST(subgrp->update_group))->coalesce_time, subgrp->updgrp_switch_events);
subgrp->t_coalesce ? "(Running)" : ""); json_object_int_add(json_subgrp_event,
vty_out(vty, " Version: %" PRIu64 "\n", subgrp->version); "peerRefreshEvents",
vty_out(vty, " Packet queue length: %d\n", subgrp->peer_refreshes_combined);
bpacket_queue_length(SUBGRP_PKTQ(subgrp))); json_object_int_add(json_subgrp_event,
vty_out(vty, " Total packets enqueued: %u\n", "mergeCheckEvents",
subgroup_total_packets_enqueued(subgrp)); subgrp->merge_checks_triggered);
vty_out(vty, " Packet queue high watermark: %d\n", json_object_object_add(json_subgrp, "statistics",
bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp))); json_subgrp_event);
vty_out(vty, " Adj-out list count: %u\n", subgrp->adj_count); json_object_int_add(json_subgrp, "coalesceTime",
vty_out(vty, " Advertise list: %s\n", (UPDGRP_INST(subgrp->update_group))
advertise_list_is_empty(subgrp) ? "empty" ->coalesce_time);
: "not empty"); json_object_int_add(json_subgrp, "version",
vty_out(vty, " Flags: %s\n", subgrp->version);
CHECK_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH) json_pkt_info = json_object_new_object();
? "R" json_object_int_add(
: ""); json_pkt_info, "qeueueLen",
if (peer) bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
vty_out(vty, " Max packet size: %d\n", json_object_int_add(
peer->max_packet_size); json_pkt_info, "queuedTotal",
if (subgrp->peer_count > 0) { subgroup_total_packets_enqueued(subgrp));
vty_out(vty, " Peers:\n"); json_object_int_add(
SUBGRP_FOREACH_PEER (subgrp, paf) json_pkt_info, "queueHwmLen",
vty_out(vty, " - %s\n", paf->peer->host); bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
json_object_int_add(
json_pkt_info, "totalEnqueued",
subgroup_total_packets_enqueued(subgrp));
json_object_object_add(json_subgrp, "packetQueueInfo",
json_pkt_info);
json_object_int_add(json_subgrp, "adjListCount",
subgrp->adj_count);
json_object_boolean_add(
json_subgrp, "needsRefresh",
CHECK_FLAG(subgrp->flags,
SUBGRP_FLAG_NEEDS_REFRESH));
} else {
vty_out(vty, " Join events: %u\n",
subgrp->join_events);
vty_out(vty, " Prune events: %u\n",
subgrp->prune_events);
vty_out(vty, " Merge events: %u\n",
subgrp->merge_events);
vty_out(vty, " Split events: %u\n",
subgrp->split_events);
vty_out(vty, " Update group switch events: %u\n",
subgrp->updgrp_switch_events);
vty_out(vty, " Peer refreshes combined: %u\n",
subgrp->peer_refreshes_combined);
vty_out(vty, " Merge checks triggered: %u\n",
subgrp->merge_checks_triggered);
vty_out(vty, " Coalesce Time: %u%s\n",
(UPDGRP_INST(subgrp->update_group))
->coalesce_time,
subgrp->t_coalesce ? "(Running)" : "");
vty_out(vty, " Version: %" PRIu64 "\n",
subgrp->version);
vty_out(vty, " Packet queue length: %d\n",
bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
vty_out(vty, " Total packets enqueued: %u\n",
subgroup_total_packets_enqueued(subgrp));
vty_out(vty, " Packet queue high watermark: %d\n",
bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
vty_out(vty, " Adj-out list count: %u\n",
subgrp->adj_count);
vty_out(vty, " Advertise list: %s\n",
advertise_list_is_empty(subgrp) ? "empty"
: "not empty");
vty_out(vty, " Flags: %s\n",
CHECK_FLAG(subgrp->flags,
SUBGRP_FLAG_NEEDS_REFRESH)
? "R"
: "");
if (peer)
vty_out(vty, " Max packet size: %d\n",
peer->max_packet_size);
} }
if (subgrp->peer_count > 0) {
if (ctx->uj) {
json_peers = json_object_new_array();
SUBGRP_FOREACH_PEER (subgrp, paf) {
json_object *peer =
json_object_new_string(
paf->peer->host);
json_object_array_add(json_peers, peer);
}
json_object_object_add(json_subgrp, "peers",
json_peers);
} else {
vty_out(vty, " Peers:\n");
SUBGRP_FOREACH_PEER (subgrp, paf)
vty_out(vty, " - %s\n",
paf->peer->host);
}
}
if (ctx->uj)
json_object_array_add(json_subgrps, json_subgrp);
} }
if (ctx->uj) {
json_object_object_add(json_updgrp, "subGroup", json_subgrps);
json_object_object_addf(ctx->json_updategrps, json_updgrp,
"%" PRIu64, updgrp->id);
}
return UPDWALK_CONTINUE; return UPDWALK_CONTINUE;
} }
@ -1708,14 +1870,34 @@ void update_bgp_group_free(struct bgp *bgp)
} }
void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty, void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty,
uint64_t subgrp_id) uint64_t subgrp_id, bool uj)
{ {
struct updwalk_context ctx; struct updwalk_context ctx;
json_object *json_vrf_obj = NULL;
memset(&ctx, 0, sizeof(ctx)); memset(&ctx, 0, sizeof(ctx));
ctx.vty = vty; ctx.vty = vty;
ctx.subgrp_id = subgrp_id; ctx.subgrp_id = subgrp_id;
ctx.uj = uj;
if (uj) {
ctx.json_updategrps = json_object_new_object();
json_vrf_obj = json_object_new_object();
}
update_group_af_walk(bgp, afi, safi, update_group_show_walkcb, &ctx); update_group_af_walk(bgp, afi, safi, update_group_show_walkcb, &ctx);
if (uj) {
const char *vname;
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
vname = VRF_DEFAULT_NAME;
else
vname = bgp->name;
json_object_object_add(json_vrf_obj, vname,
ctx.json_updategrps);
vty_json(vty, json_vrf_obj);
}
} }
/* /*

View File

@ -304,6 +304,8 @@ struct updwalk_context {
updgrp_walkcb cb; updgrp_walkcb cb;
void *context; void *context;
uint8_t flags; uint8_t flags;
bool uj;
json_object *json_updategrps;
#define UPDWALK_FLAGS_ADVQUEUE (1 << 0) #define UPDWALK_FLAGS_ADVQUEUE (1 << 0)
#define UPDWALK_FLAGS_ADVERTISED (1 << 1) #define UPDWALK_FLAGS_ADVERTISED (1 << 1)
@ -365,7 +367,7 @@ extern void update_bgp_group_init(struct bgp *);
extern void udpate_bgp_group_free(struct bgp *); extern void udpate_bgp_group_free(struct bgp *);
extern void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, extern void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi,
struct vty *vty, uint64_t subgrp_id); struct vty *vty, uint64_t subgrp_id, bool uj);
extern void update_group_show_stats(struct bgp *bgp, struct vty *vty); extern void update_group_show_stats(struct bgp *bgp, struct vty *vty);
extern void update_group_adjust_peer(struct peer_af *paf); extern void update_group_adjust_peer(struct peer_af *paf);
extern int update_group_adjust_soloness(struct peer *peer, int set); extern int update_group_adjust_soloness(struct peer *peer, int set);

View File

@ -15531,28 +15531,30 @@ DEFUN (show_ip_bgp_route_leak,
} }
static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi, static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi,
safi_t safi) safi_t safi, bool uj)
{ {
struct listnode *node, *nnode; struct listnode *node, *nnode;
struct bgp *bgp; struct bgp *bgp;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
vty_out(vty, "\nInstance %s:\n", if (!uj)
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) vty_out(vty, "\nInstance %s:\n",
? VRF_DEFAULT_NAME (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
: bgp->name); ? VRF_DEFAULT_NAME
update_group_show(bgp, afi, safi, vty, 0); : bgp->name);
update_group_show(bgp, afi, safi, vty, 0, uj);
} }
} }
static int bgp_show_update_groups(struct vty *vty, const char *name, int afi, static int bgp_show_update_groups(struct vty *vty, const char *name, int afi,
int safi, uint64_t subgrp_id) int safi, uint64_t subgrp_id, bool uj)
{ {
struct bgp *bgp; struct bgp *bgp;
if (name) { if (name) {
if (strmatch(name, "all")) { if (strmatch(name, "all")) {
bgp_show_all_instances_updgrps_vty(vty, afi, safi); bgp_show_all_instances_updgrps_vty(vty, afi, safi, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} else { } else {
bgp = bgp_lookup_by_name(name); bgp = bgp_lookup_by_name(name);
@ -15562,13 +15564,13 @@ static int bgp_show_update_groups(struct vty *vty, const char *name, int afi,
} }
if (bgp) if (bgp)
update_group_show(bgp, afi, safi, vty, subgrp_id); update_group_show(bgp, afi, safi, vty, subgrp_id, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_ip_bgp_updgrps, DEFUN (show_ip_bgp_updgrps,
show_ip_bgp_updgrps_cmd, show_ip_bgp_updgrps_cmd,
"show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] update-groups [SUBGROUP-ID]", "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] update-groups [SUBGROUP-ID] [json]",
SHOW_STR SHOW_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -15576,7 +15578,8 @@ DEFUN (show_ip_bgp_updgrps,
BGP_AFI_HELP_STR BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR BGP_SAFI_WITH_LABEL_HELP_STR
"Detailed info about dynamic update groups\n" "Detailed info about dynamic update groups\n"
"Specific subgroup to display detailed info for\n") "Specific subgroup to display detailed info for\n"
JSON_STR)
{ {
char *vrf = NULL; char *vrf = NULL;
afi_t afi = AFI_IP6; afi_t afi = AFI_IP6;
@ -15585,6 +15588,8 @@ DEFUN (show_ip_bgp_updgrps,
int idx = 0; int idx = 0;
bool uj = use_json(argc, argv);
/* show [ip] bgp */ /* show [ip] bgp */
if (argv_find(argv, argc, "ip", &idx)) if (argv_find(argv, argc, "ip", &idx))
afi = AFI_IP; afi = AFI_IP;
@ -15606,19 +15611,22 @@ DEFUN (show_ip_bgp_updgrps,
if (argv[idx]->type == VARIABLE_TKN) if (argv[idx]->type == VARIABLE_TKN)
subgrp_id = strtoull(argv[idx]->arg, NULL, 10); subgrp_id = strtoull(argv[idx]->arg, NULL, 10);
return (bgp_show_update_groups(vty, vrf, afi, safi, subgrp_id)); return (bgp_show_update_groups(vty, vrf, afi, safi, subgrp_id, uj));
} }
DEFUN (show_bgp_instance_all_ipv6_updgrps, DEFUN (show_bgp_instance_all_ipv6_updgrps,
show_bgp_instance_all_ipv6_updgrps_cmd, show_bgp_instance_all_ipv6_updgrps_cmd,
"show [ip] bgp <view|vrf> all update-groups", "show [ip] bgp <view|vrf> all update-groups [json]",
SHOW_STR SHOW_STR
IP_STR IP_STR
BGP_STR BGP_STR
BGP_INSTANCE_ALL_HELP_STR BGP_INSTANCE_ALL_HELP_STR
"Detailed info about dynamic update groups\n") "Detailed info about dynamic update groups\n"
JSON_STR)
{ {
bgp_show_all_instances_updgrps_vty(vty, AFI_IP6, SAFI_UNICAST); bool uj = use_json(argc, argv);
bgp_show_all_instances_updgrps_vty(vty, AFI_IP6, SAFI_UNICAST, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -15635,7 +15643,7 @@ DEFUN (show_bgp_l2vpn_evpn_updgrps,
char *vrf = NULL; char *vrf = NULL;
uint64_t subgrp_id = 0; uint64_t subgrp_id = 0;
bgp_show_update_groups(vty, vrf, AFI_L2VPN, SAFI_EVPN, subgrp_id); bgp_show_update_groups(vty, vrf, AFI_L2VPN, SAFI_EVPN, subgrp_id, 0);
return CMD_SUCCESS; return CMD_SUCCESS;
} }

View File

@ -296,7 +296,7 @@ the default route.
Allow IPv6 nexthop tracking to resolve via the default route. This parameter Allow IPv6 nexthop tracking to resolve via the default route. This parameter
is configured per-VRF, so the command is also available in the VRF subnode. is configured per-VRF, so the command is also available in the VRF subnode.
.. clicmd:: show ip nht [vrf NAME] [A.B.C.D|X:X::X:X] [mrib] .. clicmd:: show ip nht [vrf NAME] [A.B.C.D|X:X::X:X] [mrib] [json]
Show nexthop tracking status for address resolution. If vrf is not specified Show nexthop tracking status for address resolution. If vrf is not specified
then display the default vrf. If ``all`` is specified show all vrf address then display the default vrf. If ``all`` is specified show all vrf address
@ -305,6 +305,7 @@ the default route.
indicates that the operator wants to see the multicast rib address resolution indicates that the operator wants to see the multicast rib address resolution
table. An alternative form of the command is ``show ip import-check`` and this table. An alternative form of the command is ``show ip import-check`` and this
form of the command is deprecated at this point in time. form of the command is deprecated at this point in time.
If the ``json`` option is specified, output is displayed in JSON format.
PBR dataplane programming PBR dataplane programming
========================= =========================