From: Ashwini Reddy Date: Mon, 7 Nov 2022 19:53:48 +0000 (-0800) Subject: bgpd: JSON support for show ip bgp vrf all update-group X-Git-Tag: base_8.5~218^2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=refs%2Fpull%2F12365%2Fhead;p=mirror%2Ffrr.git 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 Signed-off-by: Ashwini Reddy --- diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 9d550fd19b..6b5269efe2 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -677,6 +677,15 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) struct bgp_filter *filter; struct peer *peer = UPDGRP_PEER(updgrp); 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) return CMD_SUCCESS; @@ -703,79 +712,232 @@ static int update_group_show_walkcb(struct update_group *updgrp, void *arg) vty = ctx->vty; - vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id); - vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime)); + if (ctx->uj) { + json_updgrp = json_object_new_object(); + /* Display json o/p */ + tbuf = monotime(NULL); + tbuf -= updgrp->uptime; + epoch_tbuf = time(NULL) - tbuf; + json_time = json_object_new_object(); + json_object_int_add(json_time, "epoch", epoch_tbuf); + json_object_string_add(json_time, "epochString", + ctime(&epoch_tbuf)); + json_object_object_add(json_updgrp, "groupCreateTime", + json_time); + json_object_string_add(json_updgrp, "afi", + afi2str(updgrp->afi)); + json_object_string_add(json_updgrp, "safi", + safi2str(updgrp->safi)); + } 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) - vty_out(vty, " Outgoing route map: %s\n", - filter->map[RMAP_OUT].name); - vty_out(vty, " MRAI value (seconds): %d\n", updgrp->conf->v_routeadv); - if (updgrp->conf->change_local_as) - 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" - : ""); + 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) { if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id)) continue; - vty_out(vty, "\n"); - vty_out(vty, " Update-subgroup %" PRIu64 ":\n", subgrp->id); - vty_out(vty, " Created: %s", - timestamp_string(subgrp->uptime)); + if (ctx->uj) { + json_subgrp = json_object_new_object(); + json_object_int_add(json_subgrp, "subGroupId", + 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 || subgrp->split_from.subgroup_id) { - 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); + if (ctx->uj) { + json_object_int_add( + json_subgrp, "splitGroupId", + subgrp->split_from.update_group_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); - 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 (ctx->uj) { + json_subgrp_event = json_object_new_object(); + json_object_int_add(json_subgrp_event, "joinEvents", + subgrp->join_events); + json_object_int_add(json_subgrp_event, "pruneEvents", + subgrp->prune_events); + json_object_int_add(json_subgrp_event, "mergeEvents", + subgrp->merge_events); + json_object_int_add(json_subgrp_event, "splitEvents", + subgrp->split_events); + json_object_int_add(json_subgrp_event, "switchEvents", + subgrp->updgrp_switch_events); + json_object_int_add(json_subgrp_event, + "peerRefreshEvents", + subgrp->peer_refreshes_combined); + json_object_int_add(json_subgrp_event, + "mergeCheckEvents", + subgrp->merge_checks_triggered); + json_object_object_add(json_subgrp, "statistics", + json_subgrp_event); + json_object_int_add(json_subgrp, "coalesceTime", + (UPDGRP_INST(subgrp->update_group)) + ->coalesce_time); + json_object_int_add(json_subgrp, "version", + subgrp->version); + json_pkt_info = json_object_new_object(); + json_object_int_add( + json_pkt_info, "qeueueLen", + bpacket_queue_length(SUBGRP_PKTQ(subgrp))); + json_object_int_add( + json_pkt_info, "queuedTotal", + subgroup_total_packets_enqueued(subgrp)); + json_object_int_add( + json_pkt_info, "queueHwmLen", + 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) { - vty_out(vty, " Peers:\n"); - SUBGRP_FOREACH_PEER (subgrp, paf) - vty_out(vty, " - %s\n", paf->peer->host); + 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; } @@ -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, - uint64_t subgrp_id) + uint64_t subgrp_id, bool uj) { struct updwalk_context ctx; + json_object *json_vrf_obj = NULL; + memset(&ctx, 0, sizeof(ctx)); ctx.vty = vty; 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); + + 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); + } } /* diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h index ecd92a996e..16628158f9 100644 --- a/bgpd/bgp_updgrp.h +++ b/bgpd/bgp_updgrp.h @@ -304,6 +304,8 @@ struct updwalk_context { updgrp_walkcb cb; void *context; uint8_t flags; + bool uj; + json_object *json_updategrps; #define UPDWALK_FLAGS_ADVQUEUE (1 << 0) #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 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_adjust_peer(struct peer_af *paf); extern int update_group_adjust_soloness(struct peer *peer, int set); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 53fdce3a35..4b17d28968 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -15531,28 +15531,30 @@ DEFUN (show_ip_bgp_route_leak, } 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 bgp *bgp; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { - vty_out(vty, "\nInstance %s:\n", - (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) - ? VRF_DEFAULT_NAME - : bgp->name); - update_group_show(bgp, afi, safi, vty, 0); + if (!uj) + vty_out(vty, "\nInstance %s:\n", + (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) + ? VRF_DEFAULT_NAME + : 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, - int safi, uint64_t subgrp_id) + int safi, uint64_t subgrp_id, bool uj) { struct bgp *bgp; if (name) { 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; } else { 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) - update_group_show(bgp, afi, safi, vty, subgrp_id); + update_group_show(bgp, afi, safi, vty, subgrp_id, uj); return CMD_SUCCESS; } DEFUN (show_ip_bgp_updgrps, show_ip_bgp_updgrps_cmd, - "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] update-groups [SUBGROUP-ID]", + "show [ip] bgp [ VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] update-groups [SUBGROUP-ID] [json]", SHOW_STR IP_STR BGP_STR @@ -15576,7 +15578,8 @@ DEFUN (show_ip_bgp_updgrps, BGP_AFI_HELP_STR BGP_SAFI_WITH_LABEL_HELP_STR "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; afi_t afi = AFI_IP6; @@ -15585,6 +15588,8 @@ DEFUN (show_ip_bgp_updgrps, int idx = 0; + bool uj = use_json(argc, argv); + /* show [ip] bgp */ if (argv_find(argv, argc, "ip", &idx)) afi = AFI_IP; @@ -15606,19 +15611,22 @@ DEFUN (show_ip_bgp_updgrps, if (argv[idx]->type == VARIABLE_TKN) 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, show_bgp_instance_all_ipv6_updgrps_cmd, - "show [ip] bgp all update-groups", + "show [ip] bgp all update-groups [json]", SHOW_STR IP_STR BGP_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; } @@ -15635,7 +15643,7 @@ DEFUN (show_bgp_l2vpn_evpn_updgrps, char *vrf = NULL; 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; } diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index db43266d68..c44642a788 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -296,7 +296,7 @@ the default route. 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. -.. 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 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 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. + If the ``json`` option is specified, output is displayed in JSON format. PBR dataplane programming =========================