]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_nexthop.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgp_nexthop.c
index 25a4a1b521ae41b098e5c175133b8482356e6527..00a0bc84023e91abf8ee4ed0d4bcd1f0255c8516 100644 (file)
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /* BGP nexthop scan
  * Copyright (C) 2000 Kunihiro Ishiguro
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
@@ -23,6 +8,7 @@
 #include "command.h"
 #include "thread.h"
 #include "prefix.h"
+#include "lib/json.h"
 #include "zclient.h"
 #include "stream.h"
 #include "network.h"
@@ -187,15 +173,30 @@ void bgp_tip_hash_destroy(struct bgp *bgp)
        bgp->tip_hash = NULL;
 }
 
-void bgp_tip_add(struct bgp *bgp, struct in_addr *tip)
+/* Add/Update Tunnel-IP entry of bgp martian next-hop table.
+ *
+ * Returns true only if we add a _new_ TIP so the caller knows that an
+ * actionable change has occurred. If we find an existing TIP then we
+ * only need to update the refcnt, since the collection of known TIPs
+ * has not changed.
+ */
+bool bgp_tip_add(struct bgp *bgp, struct in_addr *tip)
 {
        struct tip_addr tmp;
        struct tip_addr *addr;
+       bool tip_added = false;
 
        tmp.addr = *tip;
 
-       addr = hash_get(bgp->tip_hash, &tmp, bgp_tip_hash_alloc);
+       addr = hash_lookup(bgp->tip_hash, &tmp);
+       if (!addr) {
+               addr = hash_get(bgp->tip_hash, &tmp, bgp_tip_hash_alloc);
+               tip_added = true;
+       }
+
        addr->refcnt++;
+
+       return tip_added;
 }
 
 void bgp_tip_del(struct bgp *bgp, struct in_addr *tip)
@@ -500,11 +501,8 @@ static void bgp_connected_cleanup(struct route_table *table,
        if (!bc)
                return;
 
-       bc->refcnt--;
-       if (bc->refcnt == 0) {
-               XFREE(MTYPE_BGP_CONN, bc);
-               bgp_dest_set_bgp_connected_ref_info(bn, NULL);
-       }
+       XFREE(MTYPE_BGP_CONN, bc);
+       bgp_dest_set_bgp_connected_ref_info(bn, NULL);
 }
 
 bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
@@ -734,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));
@@ -753,24 +802,118 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
                safi = table->safi;
                bgp_path = table->bgp;
 
-               if (dest->pdest)
-                       vty_out(vty, "    %d/%d %pBD RD %pRD %s flags 0x%x\n",
-                               afi, safi, dest,
+
+               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",
+                                       BGP_RD_AS_FORMAT(bgp->asnotation),
+                                       (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 ", afi, safi, dest);
+                       vty_out(vty, BGP_RD_AS_FORMAT(bgp->asnotation),
                                (struct prefix_rd *)bgp_dest_get_prefix(
-                                       dest->pdest),
-                               bgp_path->name_pretty, path->flags);
-               else
+                                       dest->pdest));
+                       vty_out(vty, " %s flags 0x%x\n", bgp_path->name_pretty,
+                               path->flags);
+               } else
                        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);
@@ -806,97 +949,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;
        }
 
@@ -905,46 +1141,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
@@ -952,54 +1211,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 (afi)
+               afiz = bgp_vty_afi_from_str(afi);
 
-       if (argv_find(argv, argc, "view", &idx)
-           || argv_find(argv, argc, "vrf", &idx))
-               vrf = argv[++idx]->arg;
+       rc = show_ip_bgp_nexthop_table(vty, vrf, nhop_str, false, json, afiz,
+                                      detail);
 
-       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 (uj)
+               vty_json(vty, json);
 
-       return show_ip_bgp_nexthop_table(vty, vrf, nhop_ip, false);
+       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 (argv_find(argv, argc, "view", &idx)
-           || argv_find(argv, argc, "vrf", &idx))
-               vrf = argv[++idx]->arg;
+       if (uj)
+               json = json_object_new_object();
 
-       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 <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;
 }