diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 46a017f914..4b012430d9 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -24,6 +24,7 @@ #include "lib/json.h" #include "lib_errors.h" #include "lib/zclient.h" +#include "lib/printfrr.h" #include "prefix.h" #include "plist.h" #include "buffer.h" @@ -15464,7 +15465,8 @@ DEFPY(show_ip_bgp_instance_updgrps_adj_s, return CMD_SUCCESS; } -static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) +static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group, + json_object *json) { struct listnode *node, *nnode; struct prefix *range; @@ -15473,64 +15475,143 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) afi_t afi; safi_t safi; const char *peer_status; - const char *af_str; int lr_count; int dynamic; - int af_cfgd; + bool af_cfgd; + json_object *json_peer_group = NULL; + json_object *json_peer_group_afc = NULL; + json_object *json_peer_group_members = NULL; + json_object *json_peer_group_dynamic = NULL; + json_object *json_peer_group_dynamic_af = NULL; + json_object *json_peer_group_ranges = NULL; conf = group->conf; - if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %u\n", - group->name, conf->as); - } else if (conf->as_type == AS_INTERNAL) { - vty_out(vty, "\nBGP peer-group %s, remote AS %u\n", - group->name, group->bgp->as); - } else { - vty_out(vty, "\nBGP peer-group %s\n", group->name); + if (json) { + json_peer_group = json_object_new_object(); + json_peer_group_afc = json_object_new_array(); } - if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) - vty_out(vty, " Peer-group type is internal\n"); - else - vty_out(vty, " Peer-group type is external\n"); + if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) { + if (json) + json_object_int_add(json_peer_group, "remoteAs", + conf->as); + else + vty_out(vty, "\nBGP peer-group %s, remote AS %u\n", + group->name, conf->as); + } else if (conf->as_type == AS_INTERNAL) { + if (json) + json_object_int_add(json_peer_group, "remoteAs", + group->bgp->as); + else + vty_out(vty, "\nBGP peer-group %s, remote AS %u\n", + group->name, group->bgp->as); + } else { + if (!json) + vty_out(vty, "\nBGP peer-group %s\n", group->name); + } + + if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) { + if (json) + json_object_string_add(json_peer_group, "type", + "internal"); + else + vty_out(vty, " Peer-group type is internal\n"); + } else { + if (json) + json_object_string_add(json_peer_group, "type", + "external"); + else + vty_out(vty, " Peer-group type is external\n"); + } /* Display AFs configured. */ - vty_out(vty, " Configured address-families:"); + if (!json) + vty_out(vty, " Configured address-families:"); + FOREACH_AFI_SAFI (afi, safi) { if (conf->afc[afi][safi]) { - af_cfgd = 1; - vty_out(vty, " %s;", get_afi_safi_str(afi, safi, false)); + af_cfgd = true; + if (json) + json_object_array_add( + json_peer_group_afc, + json_object_new_string(get_afi_safi_str( + afi, safi, false))); + else + vty_out(vty, " %s;", + get_afi_safi_str(afi, safi, false)); } } - if (!af_cfgd) - vty_out(vty, " none\n"); - else - vty_out(vty, "\n"); + + if (json) { + json_object_object_add(json_peer_group, + "addressFamiliesConfigured", + json_peer_group_afc); + } else { + if (!af_cfgd) + vty_out(vty, " none\n"); + else + vty_out(vty, "\n"); + } /* Display listen ranges (for dynamic neighbors), if any */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { - if (afi == AFI_IP) - af_str = "IPv4"; - else if (afi == AFI_IP6) - af_str = "IPv6"; - else - af_str = "???"; lr_count = listcount(group->listen_range[afi]); if (lr_count) { - vty_out(vty, " %d %s listen range(s)\n", lr_count, - af_str); + if (json) { + if (!json_peer_group_dynamic) + json_peer_group_dynamic = + json_object_new_object(); + json_peer_group_dynamic_af = + json_object_new_object(); + json_peer_group_ranges = + json_object_new_array(); + json_object_int_add(json_peer_group_dynamic_af, + "count", lr_count); + } else { + vty_out(vty, " %d %s listen range(s)\n", + lr_count, afi2str(afi)); + } for (ALL_LIST_ELEMENTS(group->listen_range[afi], node, - nnode, range)) - vty_out(vty, " %pFX\n", range); + nnode, range)) { + if (json) { + char buf[BUFSIZ]; + + snprintfrr(buf, sizeof(buf), "%pFX", + range); + + json_object_array_add( + json_peer_group_ranges, + json_object_new_string(buf)); + } else { + vty_out(vty, " %pFX\n", range); + } + } + + if (json) { + json_object_object_add( + json_peer_group_dynamic_af, "ranges", + json_peer_group_ranges); + + json_object_object_add( + json_peer_group_dynamic, afi2str(afi), + json_peer_group_dynamic_af); + } } } + if (json_peer_group_dynamic) + json_object_object_add(json_peer_group, "dynamicRanges", + json_peer_group_dynamic); + /* Display group members and their status */ if (listcount(group->peer)) { - vty_out(vty, " Peer-group members:\n"); + if (json) + json_peer_group_members = json_object_new_object(); + else + vty_out(vty, " Peer-group members:\n"); for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN) || CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN)) @@ -15543,65 +15624,106 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group) peer->status, NULL); dynamic = peer_dynamic_neighbor(peer); - vty_out(vty, " %s %s %s \n", peer->host, - dynamic ? "(dynamic)" : "", peer_status); + + if (json) { + json_object *json_peer_group_member = + json_object_new_object(); + + json_object_string_add(json_peer_group_member, + "status", peer_status); + + if (dynamic) + json_object_boolean_true_add( + json_peer_group_member, + "dynamic"); + + json_object_object_add(json_peer_group_members, + peer->host, + json_peer_group_member); + } else { + vty_out(vty, " %s %s %s \n", peer->host, + dynamic ? "(dynamic)" : "", + peer_status); + } } + if (json) + json_object_object_add(json_peer_group, "members", + json_peer_group_members); } + if (json) + json_object_object_add(json, group->name, json_peer_group); + return CMD_SUCCESS; } static int bgp_show_peer_group_vty(struct vty *vty, const char *name, - const char *group_name) + const char *group_name, bool uj) { struct bgp *bgp; struct listnode *node, *nnode; struct peer_group *group; bool found = false; + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); if (!bgp) { - vty_out(vty, "%% BGP instance not found\n"); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + vty_out(vty, "%% BGP instance not found\n"); + } + return CMD_WARNING; } for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) { if (group_name) { if (strmatch(group->name, group_name)) { - bgp_show_one_peer_group(vty, group); + bgp_show_one_peer_group(vty, group, json); found = true; break; } } else { - bgp_show_one_peer_group(vty, group); + bgp_show_one_peer_group(vty, group, json); } } - if (group_name && !found) + if (group_name && !found && !uj) vty_out(vty, "%% No such peer-group\n"); + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } + return CMD_SUCCESS; } -DEFUN (show_ip_bgp_peer_groups, - show_ip_bgp_peer_groups_cmd, - "show [ip] bgp [ VIEWVRFNAME] peer-group [PGNAME]", - SHOW_STR - IP_STR - BGP_STR - BGP_INSTANCE_HELP_STR - "Detailed information on BGP peer groups\n" - "Peer group name\n") +DEFUN(show_ip_bgp_peer_groups, show_ip_bgp_peer_groups_cmd, + "show [ip] bgp [ VIEWVRFNAME] peer-group [PGNAME] [json]", + SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR + "Detailed information on BGP peer groups\n" + "Peer group name\n" JSON_STR) { char *vrf, *pg; int idx = 0; + bool uj = use_json(argc, argv); vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg : NULL; pg = argv_find(argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL; - return bgp_show_peer_group_vty(vty, vrf, pg); + return bgp_show_peer_group_vty(vty, vrf, pg, uj); } diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index da6c0d9824..a121595972 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1667,6 +1667,74 @@ and will share updates. should not be reflected back to the peer. This command only is only meaningful when there is a single peer defined in the peer-group. +.. clicmd:: show [ip] bgp peer-group [json] + + This command displays configured BGP peer-groups. + + .. code-block:: frr + + exit1-debian-9# show bgp peer-group + + BGP peer-group test1, remote AS 65001 + Peer-group type is external + Configured address-families: IPv4 Unicast; IPv6 Unicast; + 1 IPv4 listen range(s) + 192.168.100.0/24 + 2 IPv6 listen range(s) + 2001:db8:1::/64 + 2001:db8:2::/64 + Peer-group members: + 192.168.200.1 Active + 2001:db8::1 Active + + BGP peer-group test2 + Peer-group type is external + Configured address-families: IPv4 Unicast; + + Optional ``json`` parameter is used to display JSON output. + + .. code-block:: frr + + { + "test1":{ + "remoteAs":65001, + "type":"external", + "addressFamiliesConfigured":[ + "IPv4 Unicast", + "IPv6 Unicast" + ], + "dynamicRanges":{ + "IPv4":{ + "count":1, + "ranges":[ + "192.168.100.0\/24" + ] + }, + "IPv6":{ + "count":2, + "ranges":[ + "2001:db8:1::\/64", + "2001:db8:2::\/64" + ] + } + }, + "members":{ + "192.168.200.1":{ + "status":"Active" + }, + "2001:db8::1":{ + "status":"Active" + } + } + }, + "test2":{ + "type":"external", + "addressFamiliesConfigured":[ + "IPv4 Unicast" + ] + } + } + Capability Negotiation ^^^^^^^^^^^^^^^^^^^^^^