diff options
| author | Donatas Abraitis <donatas@opensourcerouting.org> | 2023-01-07 21:01:06 +0200 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-07 21:01:06 +0200 | 
| commit | a8adf1b3cb313490a3f2ef5c03256e04546e0de4 (patch) | |
| tree | 12cce951e67f721d6848533a014c1f71c3ef0a71 /bgpd/bgp_nexthop.c | |
| parent | fa1c9d3e2281990827391a2c9265df1a76688941 (diff) | |
| parent | 071ec807cbbd388bde33e66486067358daa52ae6 (diff) | |
Merge pull request #12573 from Pdoijode/bgp-nexthop-json-changes
Bgp nexthop json changes
Diffstat (limited to 'bgpd/bgp_nexthop.c')
| -rw-r--r-- | bgpd/bgp_nexthop.c | 470 | 
1 files changed, 380 insertions, 90 deletions
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 6bbdbdc1a9..d9822ee974 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" @@ -731,17 +732,68 @@ 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_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, -				   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)); @@ -750,6 +802,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, @@ -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",  				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, "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) {  		case NEXTHOP_TYPE_IPV6:  			vty_out(vty, "  gate %pI6\n", &nexthop->gate.ipv6); @@ -803,97 +946,190 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,  				nexthop->type);  		}  	} +	if (json) +		json_object_object_add(json, "nexthops", 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) { +		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)); +	}  	/* 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, afi_t afi, +			      bool detail)  {  	struct bgp_nexthop_cache *bnc; -	afi_t afi;  	struct bgp_nexthop_cache_head(*tree)[AFI_MAX]; +	json_object *json_afi = NULL; +	bool found = false; -	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 (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, 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, -				     const char *nhopip_str, -				     bool import_table) +				     const char *nhopip_str, bool import_table, +				     json_object *json, afi_t afi, bool detail)  {  	struct bgp *bgp; -	if (name) +	if (name && !strmatch(name, VRF_DEFAULT_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;  	} @@ -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 *bnc;  		bool found = false; +		json_object *json_afi = NULL;  		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_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); +			bgp_show_nexthop(vty, bgp, bnc, true, json_afi);  			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",  				nhopip_str);  	} else -		bgp_show_nexthops(vty, bgp, import_table); +		bgp_show_nexthops(vty, bgp, import_table, json, afi, detail);  	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 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, 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 [<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         IP_STR         BGP_STR @@ -949,54 +1208,85 @@ DEFUN (show_ip_bgp_nexthop,         "BGP nexthop table\n"         "IPv4 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 nh_idx = 0; -	char *vrf = NULL; -	char *nhop_ip = NULL; +	int rc = 0; +	json_object *json = NULL; +	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; +	rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, json, afiz, +				       detail); -	return show_ip_bgp_nexthop_table(vty, vrf, nhop_ip, false); +	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 [<view|vrf> VIEWVRFNAME] import-check-table [detail]", +       "show [ip] bgp [<view|vrf> VIEWVRFNAME$vrf] import-check-table [detail$detail] [json$uj]",         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 idx = 0; -	char *vrf = NULL; +	int rc = 0; +	json_object *json = NULL; + +	if (uj) +		json = json_object_new_object(); + +	rc = show_ip_bgp_nexthop_table(vty, vrf, NULL, true, json, AFI_UNSPEC, +				       detail); -	if (argv_find(argv, argc, "view", &idx) -	    || argv_find(argv, argc, "vrf", &idx)) -		vrf = argv[++idx]->arg; +	if (uj) +		vty_json(vty, json); -	return show_ip_bgp_nexthop_table(vty, vrf, NULL, true); +	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 <view|vrf> all nexthop", +       "show [ip] bgp <view|vrf> all nexthop [<ipv4|ipv6>$afi] [detail$detail] [json$uj]",         SHOW_STR         IP_STR         BGP_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;  }  | 
