From bf85e4c5f1008a12faea6e52de01b910d2b20e2c Mon Sep 17 00:00:00 2001 From: Pooja Jagadeesh Doijode Date: Tue, 27 Dec 2022 15:03:30 -0800 Subject: [PATCH 1/3] bgpd: add json option to show commands in bgp_nexthop Commands with json option: - show bgp nexthop - show bgp import-check-table Example output below, "nexthop" and "import-check-table" are only different in the nexthop entries, the format is the same ``` leaf-A# show bgp nexthop 10.11.10.1 detail json { "nexthops":{ "10.11.10.1":{ "valid":true, "complete":true, "igpMetric":0, "pathCount":1, "peer":"10.11.10.1", "gates":[ { "ifname":"eth1" } ], "lastUpdate":{ "epoch":1669161758, "string":"Wed Nov 23 00:02:38 2022\n" }, "paths":[ { "afi":"IPv4", "safi":"unicast", "prefix":"192.168.11.0/24", "vrf":"default", "flags":[ "valid", "dmedSelected", "counted" ] } ] } } } leaf-A# show bgp nexthop json { "nexthops":{ "10.10.10.1":{ "valid":true, "complete":true, "igpMetric":0, "pathCount":1, "peer":"10.10.10.1", "gates":[ { "ifname":"eth0" } ], "lastUpdate":{ "epoch":1669161758, "string":"Wed Nov 23 00:02:38 2022\n" } }, "10.11.10.1":{ "valid":true, "complete":true, "igpMetric":0, "pathCount":1, "peer":"10.11.10.1", "gates":[ { "ifname":"eth1" } ], "lastUpdate":{ "epoch":1669161758, "string":"Wed Nov 23 00:02:38 2022\n" } } } } ``` Signed-off-by: Yaroslav Fedoriachenko --- bgpd/bgp_nexthop.c | 386 +++++++++++++++++++++++++++++++++++++-------- doc/user/bgp.rst | 16 ++ 2 files changed, 332 insertions(+), 70 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 25a4a1b521..1c609c09dc 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -23,6 +23,7 @@ #include "command.h" #include "thread.h" #include "prefix.h" +#include "lib/json.h" #include "zclient.h" #include "stream.h" #include "network.h" @@ -734,17 +735,67 @@ bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop, return false; } +static void bgp_show_bgp_path_info_flags(uint32_t flags, json_object *json) +{ + json_object *json_flags = NULL; + if (!json) + return; + + json_flags = json_object_new_array(); + if (CHECK_FLAG(flags, BGP_PATH_IGP_CHANGED)) + json_array_string_add(json_flags, "igpChanged"); + if (CHECK_FLAG(flags, BGP_PATH_DAMPED)) + json_array_string_add(json_flags, "damped"); + if (CHECK_FLAG(flags, BGP_PATH_HISTORY)) + json_array_string_add(json_flags, "history"); + if (CHECK_FLAG(flags, BGP_PATH_SELECTED)) + json_array_string_add(json_flags, "selected"); + if (CHECK_FLAG(flags, BGP_PATH_VALID)) + json_array_string_add(json_flags, "valid"); + if (CHECK_FLAG(flags, BGP_PATH_ATTR_CHANGED)) + json_array_string_add(json_flags, "attrChanged"); + if (CHECK_FLAG(flags, BGP_PATH_DMED_CHECK)) + json_array_string_add(json_flags, "dmedCheck"); + if (CHECK_FLAG(flags, BGP_PATH_DMED_SELECTED)) + json_array_string_add(json_flags, "dmedSelected"); + if (CHECK_FLAG(flags, BGP_PATH_STALE)) + json_array_string_add(json_flags, "stale"); + if (CHECK_FLAG(flags, BGP_PATH_REMOVED)) + json_array_string_add(json_flags, "removed"); + if (CHECK_FLAG(flags, BGP_PATH_COUNTED)) + json_array_string_add(json_flags, "counted"); + if (CHECK_FLAG(flags, BGP_PATH_MULTIPATH)) + json_array_string_add(json_flags, "multipath"); + if (CHECK_FLAG(flags, BGP_PATH_MULTIPATH_CHG)) + json_array_string_add(json_flags, "multipathChanged"); + if (CHECK_FLAG(flags, BGP_PATH_RIB_ATTR_CHG)) + json_array_string_add(json_flags, "ribAttributeChanged"); + if (CHECK_FLAG(flags, BGP_PATH_ANNC_NH_SELF)) + json_array_string_add(json_flags, "anncNhSelf"); + if (CHECK_FLAG(flags, BGP_PATH_LINK_BW_CHG)) + json_array_string_add(json_flags, "linkBandwidthChanged"); + if (CHECK_FLAG(flags, BGP_PATH_ACCEPT_OWN)) + json_array_string_add(json_flags, "acceptOwn"); + json_object_object_add(json, "flags", json_flags); +} + static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp, - struct bgp_nexthop_cache *bnc) + struct bgp_nexthop_cache *bnc, + json_object *json) { struct bgp_dest *dest; struct bgp_path_info *path; - int afi; + afi_t afi; safi_t safi; struct bgp_table *table; struct bgp *bgp_path; + json_object *paths = NULL; + json_object *json_path = NULL; - vty_out(vty, " Paths:\n"); + if (json) + paths = json_object_new_array(); + else + vty_out(vty, " Paths:\n"); LIST_FOREACH (path, &(bnc->paths), nh_thread) { dest = path->net; assert(dest && bgp_dest_table(dest)); @@ -753,6 +804,25 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp, safi = table->safi; bgp_path = table->bgp; + if (json) { + json_path = json_object_new_object(); + json_object_string_add(json_path, "afi", afi2str(afi)); + json_object_string_add(json_path, "safi", + safi2str(safi)); + json_object_string_addf(json_path, "prefix", "%pBD", + dest); + if (dest->pdest) + json_object_string_addf( + json_path, "rd", "%pRD", + (struct prefix_rd *)bgp_dest_get_prefix( + dest->pdest)); + json_object_string_add( + json_path, "vrf", + vrf_id_to_name(bgp_path->vrf_id)); + bgp_show_bgp_path_info_flags(path->flags, json_path); + json_object_array_add(paths, json_path); + continue; + } if (dest->pdest) vty_out(vty, " %d/%d %pBD RD %pRD %s flags 0x%x\n", afi, safi, dest, @@ -763,14 +833,71 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp, vty_out(vty, " %d/%d %pBD %s flags 0x%x\n", afi, safi, dest, bgp_path->name_pretty, path->flags); } + if (json) + json_object_object_add(json, "paths", paths); } static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, - struct bgp_nexthop_cache *bnc) + struct bgp_nexthop_cache *bnc, + json_object *json) { struct nexthop *nexthop; + json_object *json_gates = NULL; + json_object *json_gate = NULL; + if (json) + json_gates = json_object_new_array(); for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) { + if (json) { + json_gate = json_object_new_object(); + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV6: + json_object_string_addf(json_gate, "ip", "%pI6", + &nexthop->gate.ipv6); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + json_object_string_addf(json_gate, "ip", "%pI6", + &nexthop->gate.ipv6); + json_object_string_add( + json_gate, "ifname", + ifindex2ifname( + bnc->ifindex ? bnc->ifindex + : nexthop->ifindex, + bgp->vrf_id)); + break; + case NEXTHOP_TYPE_IPV4: + json_object_string_addf(json_gate, "ip", "%pI4", + &nexthop->gate.ipv4); + break; + case NEXTHOP_TYPE_IFINDEX: + json_object_string_add( + json_gate, "ifname", + ifindex2ifname( + bnc->ifindex ? bnc->ifindex + : nexthop->ifindex, + bgp->vrf_id)); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + json_object_string_addf(json_gate, "ip", "%pI4", + &nexthop->gate.ipv4); + json_object_string_add( + json_gate, "ifname", + ifindex2ifname( + bnc->ifindex ? bnc->ifindex + : nexthop->ifindex, + bgp->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + json_object_boolean_true_add(json_gate, + "isBlackhole"); + break; + default: + json_object_boolean_false_add( + json_gate, "isValidNexthopType"); + } + json_object_array_add(json_gates, json_gate); + continue; + } switch (nexthop->type) { case NEXTHOP_TYPE_IPV6: vty_out(vty, " gate %pI6\n", &nexthop->gate.ipv6); @@ -806,97 +933,169 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, nexthop->type); } } + if (json) + json_object_object_add(json, "gates", json_gates); } static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, - struct bgp_nexthop_cache *bnc, - bool specific) + struct bgp_nexthop_cache *bnc, bool specific, + json_object *json) { char buf[PREFIX2STR_BUFFER]; time_t tbuf; struct peer *peer; + json_object *json_last_update = NULL; + json_object *json_nexthop = NULL; peer = (struct peer *)bnc->nht_info; - if (bnc->srte_color) - vty_out(vty, " SR-TE color %u -", bnc->srte_color); + if (json) + json_nexthop = json_object_new_object(); + if (bnc->srte_color) { + if (json) + json_object_int_add(json_nexthop, "srteColor", + bnc->srte_color); + else + vty_out(vty, " SR-TE color %u -", bnc->srte_color); + } + inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, buf, sizeof(buf)); if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) { - vty_out(vty, " %s valid [IGP metric %d], #paths %d", - inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, - buf, sizeof(buf)), - bnc->metric, bnc->path_count); - if (peer) - vty_out(vty, ", peer %s", peer->host); - if (bnc->is_evpn_gwip_nexthop) - vty_out(vty, " EVPN Gateway IP"); - vty_out(vty, "\n"); - bgp_show_nexthops_detail(vty, bgp, bnc); + if (json) { + json_object_boolean_true_add(json_nexthop, "valid"); + json_object_boolean_true_add(json_nexthop, "complete"); + json_object_int_add(json_nexthop, "igpMetric", + bnc->metric); + json_object_int_add(json_nexthop, "pathCount", + bnc->path_count); + if (peer) + json_object_string_add(json_nexthop, "peer", + peer->host); + if (bnc->is_evpn_gwip_nexthop) + json_object_boolean_true_add(json_nexthop, + "isEvpnGatewayIp"); + } else { + vty_out(vty, " %s valid [IGP metric %d], #paths %d", + buf, bnc->metric, bnc->path_count); + if (peer) + vty_out(vty, ", peer %s", peer->host); + if (bnc->is_evpn_gwip_nexthop) + vty_out(vty, " EVPN Gateway IP"); + vty_out(vty, "\n"); + } + bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); } else if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) { - vty_out(vty, - " %s overlay index unresolved [IGP metric %d], #paths %d", - inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, - buf, sizeof(buf)), - bnc->metric, bnc->path_count); - if (bnc->is_evpn_gwip_nexthop) - vty_out(vty, " EVPN Gateway IP"); - vty_out(vty, "\n"); - bgp_show_nexthops_detail(vty, bgp, bnc); + if (json) { + json_object_boolean_true_add(json_nexthop, "valid"); + json_object_boolean_false_add(json_nexthop, "complete"); + json_object_int_add(json_nexthop, "igpMetric", + bnc->metric); + json_object_int_add(json_nexthop, "pathCount", + bnc->path_count); + if (bnc->is_evpn_gwip_nexthop) + json_object_boolean_true_add(json_nexthop, + "isEvpnGatewayIp"); + } else { + vty_out(vty, + " %s overlay index unresolved [IGP metric %d], #paths %d", + buf, bnc->metric, bnc->path_count); + if (bnc->is_evpn_gwip_nexthop) + vty_out(vty, " EVPN Gateway IP"); + vty_out(vty, "\n"); + } + bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); } else { - vty_out(vty, " %s invalid, #paths %d", - inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, - buf, sizeof(buf)), - bnc->path_count); - if (peer) - vty_out(vty, ", peer %s", peer->host); - if (bnc->is_evpn_gwip_nexthop) - vty_out(vty, " EVPN Gateway IP"); - vty_out(vty, "\n"); - if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) - vty_out(vty, " Must be Connected\n"); - if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) - vty_out(vty, " Is not Registered\n"); + if (json) { + json_object_boolean_false_add(json_nexthop, "valid"); + json_object_boolean_false_add(json_nexthop, "complete"); + json_object_int_add(json_nexthop, "pathCount", + bnc->path_count); + if (peer) + json_object_string_add(json_nexthop, "peer", + peer->host); + if (bnc->is_evpn_gwip_nexthop) + json_object_boolean_true_add(json_nexthop, + "isEvpnGatewayIp"); + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) + json_object_boolean_false_add(json_nexthop, + "isConnected"); + if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) + json_object_boolean_false_add(json_nexthop, + "isRegistered"); + } else { + vty_out(vty, " %s invalid, #paths %d", buf, + bnc->path_count); + if (peer) + vty_out(vty, ", peer %s", peer->host); + if (bnc->is_evpn_gwip_nexthop) + vty_out(vty, " EVPN Gateway IP"); + vty_out(vty, "\n"); + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) + vty_out(vty, " Must be Connected\n"); + if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) + vty_out(vty, " Is not Registered\n"); + } } tbuf = time(NULL) - (monotime(NULL) - bnc->last_update); - vty_out(vty, " Last update: %s", ctime(&tbuf)); + if (json) { + json_last_update = json_object_new_object(); + json_object_int_add(json_last_update, "epoch", tbuf); + json_object_string_add(json_last_update, "string", + ctime(&tbuf)); + json_object_object_add(json_nexthop, "lastUpdate", + json_last_update); + } else { + vty_out(vty, " Last update: %s", ctime(&tbuf)); + } /* show paths dependent on nexthop, if needed. */ if (specific) - bgp_show_nexthop_paths(vty, bgp, bnc); + bgp_show_nexthop_paths(vty, bgp, bnc, json_nexthop); + if (json) + json_object_object_add(json, buf, json_nexthop); } static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, - bool import_table) + bool import_table, json_object *json) { struct bgp_nexthop_cache *bnc; afi_t afi; struct bgp_nexthop_cache_head(*tree)[AFI_MAX]; + json_object *json_nexthops = NULL; - if (import_table) - vty_out(vty, "Current BGP import check cache:\n"); - else - vty_out(vty, "Current BGP nexthop cache:\n"); + if (!json) { + if (import_table) + vty_out(vty, "Current BGP import check cache:\n"); + else + vty_out(vty, "Current BGP nexthop cache:\n"); + } if (import_table) tree = &bgp->import_check_table; else tree = &bgp->nexthop_cache_table; + if (json) + json_nexthops = json_object_new_object(); for (afi = AFI_IP; afi < AFI_MAX; afi++) { frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) - bgp_show_nexthop(vty, bgp, bnc, false); + bgp_show_nexthop(vty, bgp, bnc, false, json_nexthops); } + if (json) + json_object_object_add(json, "nexthops", json_nexthops); } static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, - const char *nhopip_str, - bool import_table) + const char *nhopip_str, bool import_table, + json_object *json) { struct bgp *bgp; + json_object *json_nexthops = NULL; if (name) bgp = bgp_lookup_by_name(name); else bgp = bgp_get_default(); if (!bgp) { - vty_out(vty, "%% No such BGP instance exist\n"); + if (!json) + vty_out(vty, "%% No such BGP instance exist\n"); return CMD_WARNING; } @@ -907,44 +1106,59 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, bool found = false; if (!str2prefix(nhopip_str, &nhop)) { - vty_out(vty, "nexthop address is malformed\n"); + if (!json) + 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_nexthops = json_object_new_object(); frr_each (bgp_nexthop_cache, &(*tree)[family2afi(nhop.family)], bnc) { if (prefix_cmp(&bnc->prefix, &nhop)) continue; - bgp_show_nexthop(vty, bgp, bnc, true); + bgp_show_nexthop(vty, bgp, bnc, true, json_nexthops); found = true; } - if (!found) + if (json) + json_object_object_add(json, "nexthops", json_nexthops); + if (!found && !json) vty_out(vty, "nexthop %s does not have entry\n", nhopip_str); } else - bgp_show_nexthops(vty, bgp, import_table); + bgp_show_nexthops(vty, bgp, import_table, json); 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, + json_object *json) { struct listnode *node, *nnode; struct bgp *bgp; + const char *inst_name; + json_object *json_instance = NULL; 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); - bgp_show_nexthops(vty, bgp, false); + inst_name = (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) + ? VRF_DEFAULT_NAME + : bgp->name; + if (json) + json_instance = json_object_new_object(); + else + vty_out(vty, "\nInstance %s:\n", inst_name); + + bgp_show_nexthops(vty, bgp, false, json_instance); + + if (json) + json_object_object_add(json, inst_name, json_instance); } } DEFUN (show_ip_bgp_nexthop, show_ip_bgp_nexthop_cmd, - "show [ip] bgp [ VIEWVRFNAME] nexthop [] [detail]", + "show [ip] bgp [ VIEWVRFNAME] nexthop [] [detail] [json]", SHOW_STR IP_STR BGP_STR @@ -952,12 +1166,19 @@ DEFUN (show_ip_bgp_nexthop, "BGP nexthop table\n" "IPv4 nexthop address\n" "IPv6 nexthop address\n" - "Show detailed information\n") + "Show detailed information\n" + JSON_STR) { + int rc = 0; int idx = 0; int nh_idx = 0; char *vrf = NULL; char *nhop_ip = NULL; + json_object *json = NULL; + bool uj = use_json(argc, argv); + + if (uj) + json = json_object_new_object(); if (argv_find(argv, argc, "view", &idx) || argv_find(argv, argc, "vrf", &idx)) @@ -967,39 +1188,64 @@ DEFUN (show_ip_bgp_nexthop, || argv_find(argv, argc, "X:X::X:X", &nh_idx)) nhop_ip = argv[nh_idx]->arg; - return show_ip_bgp_nexthop_table(vty, vrf, nhop_ip, false); + rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_ip, false, json); + + if (uj) + vty_json(vty, json); + return rc; } DEFUN (show_ip_bgp_import_check, show_ip_bgp_import_check_cmd, - "show [ip] bgp [ VIEWVRFNAME] import-check-table [detail]", + "show [ip] bgp [ VIEWVRFNAME] import-check-table [detail] [json]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR "BGP import check table\n" - "Show detailed information\n") + "Show detailed information\n" + JSON_STR) { + int rc = 0; int idx = 0; char *vrf = NULL; + json_object *json = NULL; + bool uj = use_json(argc, argv); + + if (uj) + json = json_object_new_object(); if (argv_find(argv, argc, "view", &idx) || argv_find(argv, argc, "vrf", &idx)) vrf = argv[++idx]->arg; - return show_ip_bgp_nexthop_table(vty, vrf, NULL, true); + rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, json); + + if (uj) + vty_json(vty, json); + return rc; } DEFUN (show_ip_bgp_instance_all_nexthop, show_ip_bgp_instance_all_nexthop_cmd, - "show [ip] bgp all nexthop", + "show [ip] bgp all nexthop [json]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_ALL_HELP_STR - "BGP nexthop table\n") + "BGP nexthop table\n" + JSON_STR) { - bgp_show_all_instances_nexthops_vty(vty); + json_object *json = NULL; + bool uj = use_json(argc, argv); + + if (uj) + json = json_object_new_object(); + + bgp_show_all_instances_nexthops_vty(vty, json); + + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 0b8e967264..a1e6f35e34 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -4481,6 +4481,22 @@ Displaying Update Group Information Display Information about update-group events in FRR. +Displaying Nexthop Information +-------------------- + +.. clicmd:: show [ip] bgp [ VIEWVRFNAME] nexthop [] [detail] [json] + +.. clicmd:: show [ip] bgp all nexthop [json] + + Display information about nexthops to bgp neighbors. If a certain nexthop is + specified, also provides information about paths associated with the nexthop. + With detail option provides information about gates of each nexthop. + +.. clicmd:: show [ip] bgp [ VIEWVRFNAME] import-check-table [detail] [json] + + Display information about nexthops from table that is used to check network's + existence in the rib for network statements. + Segment-Routing IPv6 -------------------- From 8da79d08ada15049d61573c01189c48580d5884b Mon Sep 17 00:00:00 2001 From: Pooja Jagadeesh Doijode Date: Wed, 28 Dec 2022 14:13:32 -0800 Subject: [PATCH 2/3] bgpd: Detail option for nexthop and import-check to display paths 1. Updated "show bgp vrf nexthop detail" and "show bgp vrf import-check-table detail" show commands to display paths associated with nexthop. "detail" option was previously unused. 2. Added 'ipv4' and 'ipv6' JSON object under top level JSON. 3. Removed the "nexthops" JSON object which was under the top level JSON object 4. Renamed "ifname" to "interfaceName" 5. Renamed "gates" JSON obejct to "nexthops" 6. Changed "flags" JSON array to JSON object and changed the flags from string to boolean 7. "lastUpdate" will display only epoch time for "detail" option JSON output: r4# show bgp vrf default nexthop detail json { "ipv4":{ "10.0.7.1":{ "valid":true, "complete":true, "igpMetric":0, "pathCount":3, "peer":"10.0.7.1", "nexthops":[ { "interfaceName":"r4-r2-eth0" } ], "lastUpdate":1672265350, "paths":[ { "afi":"IPv4", "safi":"unicast", "prefix":"11.0.20.2/32", "vrf":"default", "flags":{ "igpChanged":false, "damped":false, "history":false, "bestpath":true, "valid":true, "attrChanged":false, "deterministicMedCheck":false, "deterministicMedSelected":false, "stale":false, "removed":false, "counted":true, "multipath":false, "multipathChanged":false, "ribAttributeChanged":false, "nexthopSelf":false, "linkBandwidthChanged":false, "acceptOwn":false } } ] } } } } Signed-off-by: Pooja Jagadeesh Doijode --- bgpd/bgp_nexthop.c | 201 +++++++++++++++++++++++++++++---------------- 1 file changed, 131 insertions(+), 70 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 1c609c09dc..36c5699b04 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -741,41 +741,41 @@ static void bgp_show_bgp_path_info_flags(uint32_t flags, json_object *json) if (!json) return; - json_flags = json_object_new_array(); - if (CHECK_FLAG(flags, BGP_PATH_IGP_CHANGED)) - json_array_string_add(json_flags, "igpChanged"); - if (CHECK_FLAG(flags, BGP_PATH_DAMPED)) - json_array_string_add(json_flags, "damped"); - if (CHECK_FLAG(flags, BGP_PATH_HISTORY)) - json_array_string_add(json_flags, "history"); - if (CHECK_FLAG(flags, BGP_PATH_SELECTED)) - json_array_string_add(json_flags, "selected"); - if (CHECK_FLAG(flags, BGP_PATH_VALID)) - json_array_string_add(json_flags, "valid"); - if (CHECK_FLAG(flags, BGP_PATH_ATTR_CHANGED)) - json_array_string_add(json_flags, "attrChanged"); - if (CHECK_FLAG(flags, BGP_PATH_DMED_CHECK)) - json_array_string_add(json_flags, "dmedCheck"); - if (CHECK_FLAG(flags, BGP_PATH_DMED_SELECTED)) - json_array_string_add(json_flags, "dmedSelected"); - if (CHECK_FLAG(flags, BGP_PATH_STALE)) - json_array_string_add(json_flags, "stale"); - if (CHECK_FLAG(flags, BGP_PATH_REMOVED)) - json_array_string_add(json_flags, "removed"); - if (CHECK_FLAG(flags, BGP_PATH_COUNTED)) - json_array_string_add(json_flags, "counted"); - if (CHECK_FLAG(flags, BGP_PATH_MULTIPATH)) - json_array_string_add(json_flags, "multipath"); - if (CHECK_FLAG(flags, BGP_PATH_MULTIPATH_CHG)) - json_array_string_add(json_flags, "multipathChanged"); - if (CHECK_FLAG(flags, BGP_PATH_RIB_ATTR_CHG)) - json_array_string_add(json_flags, "ribAttributeChanged"); - if (CHECK_FLAG(flags, BGP_PATH_ANNC_NH_SELF)) - json_array_string_add(json_flags, "anncNhSelf"); - if (CHECK_FLAG(flags, BGP_PATH_LINK_BW_CHG)) - json_array_string_add(json_flags, "linkBandwidthChanged"); - if (CHECK_FLAG(flags, BGP_PATH_ACCEPT_OWN)) - json_array_string_add(json_flags, "acceptOwn"); + json_flags = json_object_new_object(); + json_object_boolean_add(json_flags, "igpChanged", + CHECK_FLAG(flags, BGP_PATH_IGP_CHANGED)); + json_object_boolean_add(json_flags, "damped", + CHECK_FLAG(flags, BGP_PATH_DAMPED)); + json_object_boolean_add(json_flags, "history", + CHECK_FLAG(flags, BGP_PATH_HISTORY)); + json_object_boolean_add(json_flags, "bestpath", + CHECK_FLAG(flags, BGP_PATH_SELECTED)); + json_object_boolean_add(json_flags, "valid", + CHECK_FLAG(flags, BGP_PATH_VALID)); + json_object_boolean_add(json_flags, "attrChanged", + CHECK_FLAG(flags, BGP_PATH_ATTR_CHANGED)); + json_object_boolean_add(json_flags, "deterministicMedCheck", + CHECK_FLAG(flags, BGP_PATH_DMED_CHECK)); + json_object_boolean_add(json_flags, "deterministicMedSelected", + CHECK_FLAG(flags, BGP_PATH_DMED_SELECTED)); + json_object_boolean_add(json_flags, "stale", + CHECK_FLAG(flags, BGP_PATH_STALE)); + json_object_boolean_add(json_flags, "removed", + CHECK_FLAG(flags, BGP_PATH_REMOVED)); + json_object_boolean_add(json_flags, "counted", + CHECK_FLAG(flags, BGP_PATH_COUNTED)); + json_object_boolean_add(json_flags, "multipath", + CHECK_FLAG(flags, BGP_PATH_MULTIPATH)); + json_object_boolean_add(json_flags, "multipathChanged", + CHECK_FLAG(flags, BGP_PATH_MULTIPATH_CHG)); + json_object_boolean_add(json_flags, "ribAttributeChanged", + CHECK_FLAG(flags, BGP_PATH_RIB_ATTR_CHG)); + json_object_boolean_add(json_flags, "nexthopSelf", + CHECK_FLAG(flags, BGP_PATH_ANNC_NH_SELF)); + json_object_boolean_add(json_flags, "linkBandwidthChanged", + CHECK_FLAG(flags, BGP_PATH_LINK_BW_CHG)); + json_object_boolean_add(json_flags, "acceptOwn", + CHECK_FLAG(flags, BGP_PATH_ACCEPT_OWN)); json_object_object_add(json, "flags", json_flags); } @@ -859,7 +859,7 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, json_object_string_addf(json_gate, "ip", "%pI6", &nexthop->gate.ipv6); json_object_string_add( - json_gate, "ifname", + json_gate, "interfaceName", ifindex2ifname( bnc->ifindex ? bnc->ifindex : nexthop->ifindex, @@ -871,7 +871,7 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, break; case NEXTHOP_TYPE_IFINDEX: json_object_string_add( - json_gate, "ifname", + json_gate, "interfaceName", ifindex2ifname( bnc->ifindex ? bnc->ifindex : nexthop->ifindex, @@ -881,7 +881,7 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, json_object_string_addf(json_gate, "ip", "%pI4", &nexthop->gate.ipv4); json_object_string_add( - json_gate, "ifname", + json_gate, "interfaceName", ifindex2ifname( bnc->ifindex ? bnc->ifindex : nexthop->ifindex, @@ -889,11 +889,26 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, break; case NEXTHOP_TYPE_BLACKHOLE: json_object_boolean_true_add(json_gate, - "isBlackhole"); + "unreachable"); + switch (nexthop->bh_type) { + case BLACKHOLE_REJECT: + json_object_boolean_true_add(json_gate, + "reject"); + break; + case BLACKHOLE_ADMINPROHIB: + json_object_boolean_true_add( + json_gate, "adminProhibited"); + break; + case BLACKHOLE_NULL: + json_object_boolean_true_add( + json_gate, "blackhole"); + break; + case BLACKHOLE_UNSPEC: + break; + } break; default: - json_object_boolean_false_add( - json_gate, "isValidNexthopType"); + break; } json_object_array_add(json_gates, json_gate); continue; @@ -934,7 +949,7 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp, } } if (json) - json_object_object_add(json, "gates", json_gates); + json_object_object_add(json, "nexthops", json_gates); } static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, @@ -1037,12 +1052,16 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } tbuf = time(NULL) - (monotime(NULL) - bnc->last_update); if (json) { - json_last_update = json_object_new_object(); - json_object_int_add(json_last_update, "epoch", tbuf); - json_object_string_add(json_last_update, "string", - ctime(&tbuf)); - json_object_object_add(json_nexthop, "lastUpdate", - json_last_update); + if (!specific) { + json_last_update = json_object_new_object(); + json_object_int_add(json_last_update, "epoch", tbuf); + json_object_string_add(json_last_update, "string", + ctime(&tbuf)); + json_object_object_add(json_nexthop, "lastUpdate", + json_last_update); + } else { + json_object_int_add(json_nexthop, "lastUpdate", tbuf); + } } else { vty_out(vty, " Last update: %s", ctime(&tbuf)); } @@ -1055,12 +1074,13 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, } static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, - bool import_table, json_object *json) + bool import_table, json_object *json, afi_t afi, + bool detail) { struct bgp_nexthop_cache *bnc; - afi_t afi; struct bgp_nexthop_cache_head(*tree)[AFI_MAX]; - json_object *json_nexthops = NULL; + json_object *json_afi = NULL; + bool found = false; if (!json) { if (import_table) @@ -1072,24 +1092,41 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, tree = &bgp->import_check_table; else tree = &bgp->nexthop_cache_table; - if (json) - json_nexthops = json_object_new_object(); - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) - bgp_show_nexthop(vty, bgp, bnc, false, json_nexthops); + + if (afi == AFI_IP || afi == AFI_IP6) { + if (json) + json_afi = json_object_new_object(); + frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc) { + bgp_show_nexthop(vty, bgp, bnc, detail, json_afi); + found = true; + } + if (found && json) + json_object_object_add( + json, (afi == AFI_IP) ? "ipv4" : "ipv6", + json_afi); + + 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 (json) - json_object_object_add(json, "nexthops", json_nexthops); } static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, const char *nhopip_str, bool import_table, - json_object *json) + json_object *json, afi_t afi, bool detail) { struct bgp *bgp; - json_object *json_nexthops = NULL; - if (name) + if (name && strcmp(name, VRF_DEFAULT_NAME) != 0) bgp = bgp_lookup_by_name(name); else bgp = bgp_get_default(); @@ -1104,6 +1141,7 @@ 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) @@ -1113,27 +1151,32 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, tree = import_table ? &bgp->import_check_table : &bgp->nexthop_cache_table; if (json) - json_nexthops = json_object_new_object(); + json_afi = json_object_new_object(); 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_nexthops); + bgp_show_nexthop(vty, bgp, bnc, true, json_afi); found = true; } if (json) - json_object_object_add(json, "nexthops", json_nexthops); + 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", nhopip_str); } else - bgp_show_nexthops(vty, bgp, import_table, json); + bgp_show_nexthops(vty, bgp, import_table, json, afi, detail); return CMD_SUCCESS; } static void bgp_show_all_instances_nexthops_vty(struct vty *vty, - json_object *json) + json_object *json, afi_t afi, + bool detail) { struct listnode *node, *nnode; struct bgp *bgp; @@ -1149,7 +1192,7 @@ static void bgp_show_all_instances_nexthops_vty(struct vty *vty, else vty_out(vty, "\nInstance %s:\n", inst_name); - bgp_show_nexthops(vty, bgp, false, json_instance); + bgp_show_nexthops(vty, bgp, false, json_instance, afi, detail); if (json) json_object_object_add(json, inst_name, json_instance); @@ -1176,6 +1219,7 @@ DEFUN (show_ip_bgp_nexthop, char *nhop_ip = NULL; json_object *json = NULL; bool uj = use_json(argc, argv); + bool detail = false; if (uj) json = json_object_new_object(); @@ -1188,7 +1232,11 @@ DEFUN (show_ip_bgp_nexthop, || argv_find(argv, argc, "X:X::X:X", &nh_idx)) nhop_ip = argv[nh_idx]->arg; - rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_ip, false, json); + if (argv_find(argv, argc, "detail", &idx)) + detail = true; + + rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_ip, false, json, + AFI_UNSPEC, detail); if (uj) vty_json(vty, json); @@ -1211,6 +1259,7 @@ DEFUN (show_ip_bgp_import_check, char *vrf = NULL; json_object *json = NULL; bool uj = use_json(argc, argv); + bool detail = false; if (uj) json = json_object_new_object(); @@ -1219,7 +1268,11 @@ DEFUN (show_ip_bgp_import_check, || argv_find(argv, argc, "vrf", &idx)) vrf = argv[++idx]->arg; - rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, json); + if (argv_find(argv, argc, "detail", &idx)) + detail = true; + + rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, json, AFI_UNSPEC, + detail); if (uj) vty_json(vty, json); @@ -1238,11 +1291,19 @@ DEFUN (show_ip_bgp_instance_all_nexthop, { json_object *json = NULL; bool uj = use_json(argc, argv); + int idx = 0; + afi_t afi = AFI_UNSPEC; + bool detail = false; if (uj) json = json_object_new_object(); - bgp_show_all_instances_nexthops_vty(vty, json); + argv_find_and_parse_afi(argv, argc, &idx, &afi); + + if (argv_find(argv, argc, "detail", &idx)) + detail = true; + + bgp_show_all_instances_nexthops_vty(vty, json, afi, detail); if (uj) vty_json(vty, json); From 071ec807cbbd388bde33e66486067358daa52ae6 Mon Sep 17 00:00:00 2001 From: Pooja Jagadeesh Doijode Date: Wed, 4 Jan 2023 18:53:12 -0800 Subject: [PATCH 3/3] bgpd: AFI option to query nexthops based on AFI Added ipv4 and ipv6 option to existing "show bgp nexthop" command to be able to query nexthops that belong to a particular address-family. Also fixed the warnings of MR 12171 Signed-off-by: Pooja Jagadeesh Doijode --- bgpd/bgp_nexthop.c | 75 ++++++++++++++++++---------------------------- bgpd/subdir.am | 1 + doc/user/bgp.rst | 3 ++ 3 files changed, 33 insertions(+), 46 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 36c5699b04..23a5aa2190 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -738,6 +738,7 @@ bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop, static void bgp_show_bgp_path_info_flags(uint32_t flags, json_object *json) { json_object *json_flags = NULL; + if (!json) return; @@ -1104,7 +1105,6 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, json_object_object_add( json, (afi == AFI_IP) ? "ipv4" : "ipv6", json_afi); - return; } @@ -1126,7 +1126,7 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, { struct bgp *bgp; - if (name && strcmp(name, VRF_DEFAULT_NAME) != 0) + if (name && !strmatch(name, VRF_DEFAULT_NAME)) bgp = bgp_lookup_by_name(name); else bgp = bgp_get_default(); @@ -1199,9 +1199,11 @@ static void bgp_show_all_instances_nexthops_vty(struct vty *vty, } } -DEFUN (show_ip_bgp_nexthop, +#include "bgpd/bgp_nexthop_clippy.c" + +DEFPY (show_ip_bgp_nexthop, show_ip_bgp_nexthop_cmd, - "show [ip] bgp [ VIEWVRFNAME] nexthop [] [detail] [json]", + "show [ip] bgp [ VIEWVRFNAME$vrf] nexthop [$nhop] [] [detail$detail] [json$uj]", SHOW_STR IP_STR BGP_STR @@ -1209,43 +1211,35 @@ DEFUN (show_ip_bgp_nexthop, "BGP nexthop table\n" "IPv4 nexthop address\n" "IPv6 nexthop address\n" + "BGP nexthop IPv4 table\n" + "IPv4 nexthop address\n" + "BGP nexthop IPv6 table\n" + "IPv6 nexthop address\n" "Show detailed information\n" JSON_STR) { int rc = 0; - int idx = 0; - int nh_idx = 0; - char *vrf = NULL; - char *nhop_ip = NULL; json_object *json = NULL; - bool uj = use_json(argc, argv); - bool detail = false; + afi_t afiz = AFI_UNSPEC; if (uj) json = json_object_new_object(); - if (argv_find(argv, argc, "view", &idx) - || argv_find(argv, argc, "vrf", &idx)) - vrf = argv[++idx]->arg; + if (afi) + afiz = bgp_vty_afi_from_str(afi); - if (argv_find(argv, argc, "A.B.C.D", &nh_idx) - || argv_find(argv, argc, "X:X::X:X", &nh_idx)) - nhop_ip = argv[nh_idx]->arg; - - if (argv_find(argv, argc, "detail", &idx)) - detail = true; - - rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_ip, false, json, - AFI_UNSPEC, detail); + rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, json, afiz, + detail); if (uj) vty_json(vty, json); + return rc; } -DEFUN (show_ip_bgp_import_check, +DEFPY (show_ip_bgp_import_check, show_ip_bgp_import_check_cmd, - "show [ip] bgp [ VIEWVRFNAME] import-check-table [detail] [json]", + "show [ip] bgp [ VIEWVRFNAME$vrf] import-check-table [detail$detail] [json$uj]", SHOW_STR IP_STR BGP_STR @@ -1255,58 +1249,47 @@ DEFUN (show_ip_bgp_import_check, JSON_STR) { int rc = 0; - int idx = 0; - char *vrf = NULL; json_object *json = NULL; - bool uj = use_json(argc, argv); - bool detail = false; if (uj) json = json_object_new_object(); - if (argv_find(argv, argc, "view", &idx) - || argv_find(argv, argc, "vrf", &idx)) - vrf = argv[++idx]->arg; - - if (argv_find(argv, argc, "detail", &idx)) - detail = true; - rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, json, AFI_UNSPEC, detail); if (uj) vty_json(vty, json); + return rc; } -DEFUN (show_ip_bgp_instance_all_nexthop, +DEFPY (show_ip_bgp_instance_all_nexthop, show_ip_bgp_instance_all_nexthop_cmd, - "show [ip] bgp all nexthop [json]", + "show [ip] bgp all nexthop [$afi] [detail$detail] [json$uj]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_ALL_HELP_STR "BGP nexthop table\n" + "BGP IPv4 nexthop table\n" + "BGP IPv6 nexthop table\n" + "Show detailed information\n" JSON_STR) { json_object *json = NULL; - bool uj = use_json(argc, argv); - int idx = 0; - afi_t afi = AFI_UNSPEC; - bool detail = false; + afi_t afiz = AFI_UNSPEC; if (uj) json = json_object_new_object(); - argv_find_and_parse_afi(argv, argc, &idx, &afi); + if (afi) + afiz = bgp_vty_afi_from_str(afi); - if (argv_find(argv, argc, "detail", &idx)) - detail = true; - - bgp_show_all_instances_nexthops_vty(vty, json, afi, detail); + bgp_show_all_instances_nexthops_vty(vty, json, afiz, detail); if (uj) vty_json(vty, json); + return CMD_SUCCESS; } diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 88f53da35e..c1f5a61438 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -215,6 +215,7 @@ clippy_scan += \ bgpd/bgp_routemap.c \ bgpd/bgp_rpki.c \ bgpd/bgp_vty.c \ + bgpd/bgp_nexthop.c \ # end nodist_bgpd_bgpd_SOURCES = \ diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index a1e6f35e34..cd5672511f 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -4483,6 +4483,9 @@ Displaying Update Group Information Displaying Nexthop Information -------------------- +.. clicmd:: show [ip] bgp [ VIEWVRFNAME] nexthop ipv4 [A.B.C.D] [detail] [json] + +.. clicmd:: show [ip] bgp [ VIEWVRFNAME] nexthop ipv6 [X:X::X:X] [detail] [json] .. clicmd:: show [ip] bgp [ VIEWVRFNAME] nexthop [] [detail] [json]