Merge pull request #12573 from Pdoijode/bgp-nexthop-json-changes

Bgp nexthop json changes
This commit is contained in:
Donatas Abraitis 2023-01-07 21:01:06 +02:00 committed by GitHub
commit a8adf1b3cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 400 additions and 90 deletions

View File

@ -23,6 +23,7 @@
#include "command.h" #include "command.h"
#include "thread.h" #include "thread.h"
#include "prefix.h" #include "prefix.h"
#include "lib/json.h"
#include "zclient.h" #include "zclient.h"
#include "stream.h" #include "stream.h"
#include "network.h" #include "network.h"
@ -731,16 +732,67 @@ bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
return false; 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_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);
}
static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp, 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_dest *dest;
struct bgp_path_info *path; struct bgp_path_info *path;
int afi; afi_t afi;
safi_t safi; safi_t safi;
struct bgp_table *table; struct bgp_table *table;
struct bgp *bgp_path; struct bgp *bgp_path;
json_object *paths = NULL;
json_object *json_path = NULL;
if (json)
paths = json_object_new_array();
else
vty_out(vty, " Paths:\n"); vty_out(vty, " Paths:\n");
LIST_FOREACH (path, &(bnc->paths), nh_thread) { LIST_FOREACH (path, &(bnc->paths), nh_thread) {
dest = path->net; dest = path->net;
@ -750,6 +802,25 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
safi = table->safi; safi = table->safi;
bgp_path = table->bgp; 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) if (dest->pdest)
vty_out(vty, " %d/%d %pBD RD %pRD %s flags 0x%x\n", vty_out(vty, " %d/%d %pBD RD %pRD %s flags 0x%x\n",
afi, safi, dest, afi, safi, dest,
@ -760,14 +831,86 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
vty_out(vty, " %d/%d %pBD %s flags 0x%x\n", vty_out(vty, " %d/%d %pBD %s flags 0x%x\n",
afi, safi, dest, bgp_path->name_pretty, path->flags); 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, 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; 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) { 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, "interfaceName",
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, "interfaceName",
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, "interfaceName",
ifindex2ifname(
bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
json_object_boolean_true_add(json_gate,
"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:
break;
}
json_object_array_add(json_gates, json_gate);
continue;
}
switch (nexthop->type) { switch (nexthop->type) {
case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6:
vty_out(vty, " gate %pI6\n", &nexthop->gate.ipv6); vty_out(vty, " gate %pI6\n", &nexthop->gate.ipv6);
@ -803,45 +946,96 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
nexthop->type); nexthop->type);
} }
} }
if (json)
json_object_object_add(json, "nexthops", json_gates);
} }
static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
struct bgp_nexthop_cache *bnc, struct bgp_nexthop_cache *bnc, bool specific,
bool specific) json_object *json)
{ {
char buf[PREFIX2STR_BUFFER]; char buf[PREFIX2STR_BUFFER];
time_t tbuf; time_t tbuf;
struct peer *peer; struct peer *peer;
json_object *json_last_update = NULL;
json_object *json_nexthop = NULL;
peer = (struct peer *)bnc->nht_info; peer = (struct peer *)bnc->nht_info;
if (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); 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)) { if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_VALID)) {
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", vty_out(vty, " %s valid [IGP metric %d], #paths %d",
inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, buf, bnc->metric, bnc->path_count);
buf, sizeof(buf)),
bnc->metric, bnc->path_count);
if (peer) if (peer)
vty_out(vty, ", peer %s", peer->host); vty_out(vty, ", peer %s", peer->host);
if (bnc->is_evpn_gwip_nexthop) if (bnc->is_evpn_gwip_nexthop)
vty_out(vty, " EVPN Gateway IP"); vty_out(vty, " EVPN Gateway IP");
vty_out(vty, "\n"); vty_out(vty, "\n");
bgp_show_nexthops_detail(vty, bgp, bnc); }
bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop);
} else if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) { } else if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) {
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, vty_out(vty,
" %s overlay index unresolved [IGP metric %d], #paths %d", " %s overlay index unresolved [IGP metric %d], #paths %d",
inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, buf, bnc->metric, bnc->path_count);
buf, sizeof(buf)),
bnc->metric, bnc->path_count);
if (bnc->is_evpn_gwip_nexthop) if (bnc->is_evpn_gwip_nexthop)
vty_out(vty, " EVPN Gateway IP"); vty_out(vty, " EVPN Gateway IP");
vty_out(vty, "\n"); vty_out(vty, "\n");
bgp_show_nexthops_detail(vty, bgp, bnc); }
bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop);
} else { } else {
vty_out(vty, " %s invalid, #paths %d", if (json) {
inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix, json_object_boolean_false_add(json_nexthop, "valid");
buf, sizeof(buf)), 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); bnc->path_count);
if (peer) if (peer)
vty_out(vty, ", peer %s", peer->host); vty_out(vty, ", peer %s", peer->host);
@ -853,46 +1047,88 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
vty_out(vty, " Is not Registered\n"); vty_out(vty, " Is not Registered\n");
} }
}
tbuf = time(NULL) - (monotime(NULL) - bnc->last_update); tbuf = time(NULL) - (monotime(NULL) - bnc->last_update);
if (json) {
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)); vty_out(vty, " Last update: %s", ctime(&tbuf));
}
/* show paths dependent on nexthop, if needed. */ /* show paths dependent on nexthop, if needed. */
if (specific) 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, static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp,
bool import_table) bool import_table, json_object *json, afi_t afi,
bool detail)
{ {
struct bgp_nexthop_cache *bnc; struct bgp_nexthop_cache *bnc;
afi_t afi;
struct bgp_nexthop_cache_head(*tree)[AFI_MAX]; struct bgp_nexthop_cache_head(*tree)[AFI_MAX];
json_object *json_afi = NULL;
bool found = false;
if (!json) {
if (import_table) if (import_table)
vty_out(vty, "Current BGP import check cache:\n"); vty_out(vty, "Current BGP import check cache:\n");
else else
vty_out(vty, "Current BGP nexthop cache:\n"); vty_out(vty, "Current BGP nexthop cache:\n");
}
if (import_table) if (import_table)
tree = &bgp->import_check_table; tree = &bgp->import_check_table;
else else
tree = &bgp->nexthop_cache_table; tree = &bgp->nexthop_cache_table;
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++) { 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) frr_each (bgp_nexthop_cache, &(*tree)[afi], bnc)
bgp_show_nexthop(vty, bgp, bnc, false); 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);
} }
} }
static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name, static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
const char *nhopip_str, const char *nhopip_str, bool import_table,
bool import_table) json_object *json, afi_t afi, bool detail)
{ {
struct bgp *bgp; struct bgp *bgp;
if (name) if (name && !strmatch(name, VRF_DEFAULT_NAME))
bgp = bgp_lookup_by_name(name); bgp = bgp_lookup_by_name(name);
else else
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) { if (!bgp) {
if (!json)
vty_out(vty, "%% No such BGP instance exist\n"); vty_out(vty, "%% No such BGP instance exist\n");
return CMD_WARNING; return CMD_WARNING;
} }
@ -902,46 +1138,69 @@ 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_head (*tree)[AFI_MAX];
struct bgp_nexthop_cache *bnc; struct bgp_nexthop_cache *bnc;
bool found = false; bool found = false;
json_object *json_afi = NULL;
if (!str2prefix(nhopip_str, &nhop)) { if (!str2prefix(nhopip_str, &nhop)) {
if (!json)
vty_out(vty, "nexthop address is malformed\n"); vty_out(vty, "nexthop address is malformed\n");
return CMD_WARNING; return CMD_WARNING;
} }
tree = import_table ? &bgp->import_check_table tree = import_table ? &bgp->import_check_table
: &bgp->nexthop_cache_table; : &bgp->nexthop_cache_table;
if (json)
json_afi = json_object_new_object();
frr_each (bgp_nexthop_cache, &(*tree)[family2afi(nhop.family)], frr_each (bgp_nexthop_cache, &(*tree)[family2afi(nhop.family)],
bnc) { bnc) {
if (prefix_cmp(&bnc->prefix, &nhop)) if (prefix_cmp(&bnc->prefix, &nhop))
continue; continue;
bgp_show_nexthop(vty, bgp, bnc, true); bgp_show_nexthop(vty, bgp, bnc, true, json_afi);
found = true; found = true;
} }
if (!found) if (json)
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", vty_out(vty, "nexthop %s does not have entry\n",
nhopip_str); nhopip_str);
} else } else
bgp_show_nexthops(vty, bgp, import_table); bgp_show_nexthops(vty, bgp, import_table, json, afi, detail);
return CMD_SUCCESS; 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, afi_t afi,
bool detail)
{ {
struct listnode *node, *nnode; struct listnode *node, *nnode;
struct bgp *bgp; struct bgp *bgp;
const char *inst_name;
json_object *json_instance = NULL;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
vty_out(vty, "\nInstance %s:\n", inst_name = (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
? VRF_DEFAULT_NAME ? VRF_DEFAULT_NAME
: bgp->name); : bgp->name;
bgp_show_nexthops(vty, bgp, false); 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, afi, detail);
if (json)
json_object_object_add(json, inst_name, json_instance);
} }
} }
DEFUN (show_ip_bgp_nexthop, #include "bgpd/bgp_nexthop_clippy.c"
DEFPY (show_ip_bgp_nexthop,
show_ip_bgp_nexthop_cmd, show_ip_bgp_nexthop_cmd,
"show [ip] bgp [<view|vrf> VIEWVRFNAME] nexthop [<A.B.C.D|X:X::X:X>] [detail]", "show [ip] bgp [<view|vrf> VIEWVRFNAME$vrf] nexthop [<A.B.C.D|X:X::X:X>$nhop] [<ipv4$afi [A.B.C.D$nhop]|ipv6$afi [X:X::X:X$nhop]>] [detail$detail] [json$uj]",
SHOW_STR SHOW_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -949,54 +1208,85 @@ DEFUN (show_ip_bgp_nexthop,
"BGP nexthop table\n" "BGP nexthop table\n"
"IPv4 nexthop address\n" "IPv4 nexthop address\n"
"IPv6 nexthop address\n" "IPv6 nexthop address\n"
"Show detailed information\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 idx = 0; int rc = 0;
int nh_idx = 0; json_object *json = NULL;
char *vrf = NULL; afi_t afiz = AFI_UNSPEC;
char *nhop_ip = NULL;
if (argv_find(argv, argc, "view", &idx) if (uj)
|| argv_find(argv, argc, "vrf", &idx)) json = json_object_new_object();
vrf = argv[++idx]->arg;
if (argv_find(argv, argc, "A.B.C.D", &nh_idx) if (afi)
|| argv_find(argv, argc, "X:X::X:X", &nh_idx)) afiz = bgp_vty_afi_from_str(afi);
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_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_import_check_cmd,
"show [ip] bgp [<view|vrf> VIEWVRFNAME] import-check-table [detail]", "show [ip] bgp [<view|vrf> VIEWVRFNAME$vrf] import-check-table [detail$detail] [json$uj]",
SHOW_STR SHOW_STR
IP_STR IP_STR
BGP_STR BGP_STR
BGP_INSTANCE_HELP_STR BGP_INSTANCE_HELP_STR
"BGP import check table\n" "BGP import check table\n"
"Show detailed information\n") "Show detailed information\n"
JSON_STR)
{ {
int idx = 0; int rc = 0;
char *vrf = NULL; json_object *json = NULL;
if (argv_find(argv, argc, "view", &idx) if (uj)
|| argv_find(argv, argc, "vrf", &idx)) json = json_object_new_object();
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, 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_instance_all_nexthop_cmd,
"show [ip] bgp <view|vrf> all nexthop", "show [ip] bgp <view|vrf> all nexthop [<ipv4|ipv6>$afi] [detail$detail] [json$uj]",
SHOW_STR SHOW_STR
IP_STR IP_STR
BGP_STR BGP_STR
BGP_INSTANCE_ALL_HELP_STR BGP_INSTANCE_ALL_HELP_STR
"BGP nexthop table\n") "BGP nexthop table\n"
"BGP IPv4 nexthop table\n"
"BGP IPv6 nexthop table\n"
"Show detailed information\n"
JSON_STR)
{ {
bgp_show_all_instances_nexthops_vty(vty); json_object *json = NULL;
afi_t afiz = AFI_UNSPEC;
if (uj)
json = json_object_new_object();
if (afi)
afiz = bgp_vty_afi_from_str(afi);
bgp_show_all_instances_nexthops_vty(vty, json, afiz, detail);
if (uj)
vty_json(vty, json);
return CMD_SUCCESS; return CMD_SUCCESS;
} }

View File

@ -215,6 +215,7 @@ clippy_scan += \
bgpd/bgp_routemap.c \ bgpd/bgp_routemap.c \
bgpd/bgp_rpki.c \ bgpd/bgp_rpki.c \
bgpd/bgp_vty.c \ bgpd/bgp_vty.c \
bgpd/bgp_nexthop.c \
# end # end
nodist_bgpd_bgpd_SOURCES = \ nodist_bgpd_bgpd_SOURCES = \

View File

@ -4492,6 +4492,25 @@ Displaying Update Group Information
Display Information about update-group events in FRR. Display Information about update-group events in FRR.
Displaying Nexthop Information
--------------------
.. clicmd:: show [ip] bgp [<view|vrf> VIEWVRFNAME] nexthop ipv4 [A.B.C.D] [detail] [json]
.. clicmd:: show [ip] bgp [<view|vrf> VIEWVRFNAME] nexthop ipv6 [X:X::X:X] [detail] [json]
.. clicmd:: show [ip] bgp [<view|vrf> VIEWVRFNAME] nexthop [<A.B.C.D|X:X::X:X>] [detail] [json]
.. clicmd:: show [ip] bgp <view|vrf> 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 [<view|vrf> 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 Segment-Routing IPv6
-------------------- --------------------