]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: json support for show ip nht 12375/head
authorSindhu Parvathi Gopinathan <sgopinathan@nvidia.com>
Tue, 15 Nov 2022 03:33:56 +0000 (19:33 -0800)
committerChirag Shah <chirag@nvidia.com>
Mon, 28 Nov 2022 23:38:09 +0000 (15:38 -0800)
show ip/ipv6 nht vrf <all | name> json support added.

Commands enhanced with JSON:
----------------------------
show ip nht json
show ip nht <addr> json
show ipv6 nht json
show ipv6 nht <addr> json
show ip nht vrf <name> json
show ip nht vrf all json
show ipv6 nht vrf <name> json
show ipv6 nht vrf all json
show ip nht vrf default <addr> json
show ipv6 nht vrf default <addr> json

Sample JSON output:
-------------------

tor-1# show ip nht vrf default json
{
  "default":{
    "nexthops":{
      "27.0.0.5":{
        "nhtConnected":false,
        "clientList":[
          {
            "protocol":"bgp",
            "socket":70,
            "protocolFiltered":"none"
          }
        ],
        "gates":[
          {
            "ip":"fe80::202:ff:fe00:2b",
            "interface":"uplink_1"
          },
          {
            "ip":"fe80::202:ff:fe00:35",
            "interface":"uplink_2"
          }
        ],
        "resolvedProtocol":"bgp"
      },
      "27.0.0.6":{
        "nhtConnected":false,
        "clientList":[
          {
            "protocol":"bgp",
            "socket":70,
            "protocolFiltered":"none"
          }
        ],
        "gates":[
          {
            "ip":"fe80::202:ff:fe00:2b",
            "interface":"uplink_1"
          },
          {
            "ip":"fe80::202:ff:fe00:35",
            "interface":"uplink_2"
          }
        ],
        "resolvedProtocol":"bgp"
      }
    }
  }
}

tor-1# show ipv6 nht vrf default json
{
  "default": {
    "nexthops": {
      "fe80::202:ff:fe00:25": {
        "nhtConnected": true,
        "clientList": [
          {
            "protocol": "bgp",
            "socket": 45,
            "protocolFiltered": "none"
          }
        ],
        "gates": [
          {
            "interface": "swp1",
            "directlyConnected": true
          }
        ],
        "resolvedProtocol": "connected"
      },
      "fe80::202:ff:fe00:2b": {
        "nhtConnected": true,
        "clientList": [
          {
            "protocol": "bgp",
            "socket": 45,
            "protocolFiltered": "none"
          }
        ],
        "gates": [
          {
            "interface": "swp1",
            "directlyConnected": true
          }
        ],
        "resolvedProtocol": "connected"
      }
    }
  }
}

tor-1# show ipv6 nht vrf all json
{
  "default": {
    "nexthops": {
      "fe80::202:ff:fe00:25": {
        "nhtConnected": true,
        "clientList": [
          {
            "protocol": "bgp",
            "socket": 45,
            "protocolFiltered": "none"
          }
        ],
        "gates": [
          {
            "interface": "swp1",
            "directlyConnected": true
          }
        ],
        "resolvedProtocol": "connected"
      },
      "fe80::202:ff:fe00:2b": {
        "nhtConnected": true,
        "clientList": [
          {
            "protocol": "bgp",
            "socket": 45,
            "protocolFiltered": "none"
          }
        ],
        "gates": [
          {
            "interface": "swp1",
            "directlyConnected": true
          }
        ],
        "resolvedProtocol": "connected"
      }
    }
  },
  "mgmt": {
    "nexthops": {}
  },
  "sym_1": {
    "nexthops": {}
  }
}

Ticket:#3229013
Issue:3229013

Testing Done: Unit test completed.

Signed-off-by: Chirag Shah <chirag@nvidia.com>
Signed-off-by: Sindhu Parvathi Gopinathan <sgopinathan@nvidia.com>
doc/user/zebra.rst
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zebra_vty.c

index c44642a788af3509a1db2a6f3ce45982715d6a21..a78731ca942f4774a57f31c56dd2e8d6ef552bc6 100644 (file)
@@ -305,7 +305,8 @@ the default route.
    indicates that the operator wants to see the multicast rib address resolution
    table.  An alternative form of the command is ``show ip import-check`` and this
    form of the command is deprecated at this point in time.
-   If the ``json`` option is specified, output is displayed in JSON format.
+   User can get that information as JSON string when ``json`` key word
+   at the end of cli is presented.
 
 PBR dataplane programming
 =========================
index 7934a9d2066e34b7875413399eb78f430da85e15..599c679864e908221afbfdd31b4634f4f21f8f60 100644 (file)
@@ -62,7 +62,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
 static void copy_state(struct rnh *rnh, const struct route_entry *re,
                       struct route_node *rn);
 static bool compare_state(struct route_entry *r1, struct route_entry *r2);
-static void print_rnh(struct route_node *rn, struct vty *vty);
+static void print_rnh(struct route_node *rn, struct vty *vty,
+                     json_object *json);
 static int zebra_client_cleanup_rnh(struct zserv *client);
 
 void zebra_rnh_init(void)
@@ -803,7 +804,8 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
 }
 
 void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
-                          struct vty *vty, const struct prefix *p)
+                          struct vty *vty, const struct prefix *p,
+                          json_object *json)
 {
        struct route_table *table;
        struct route_node *rn;
@@ -820,7 +822,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
                        continue;
 
                if (rn->info)
-                       print_rnh(rn, vty);
+                       print_rnh(rn, vty, json);
        }
 }
 
@@ -1268,73 +1270,178 @@ failure:
        return -1;
 }
 
-static void print_nh(struct nexthop *nexthop, struct vty *vty)
+static void print_nh(struct nexthop *nexthop, struct vty *vty,
+                    json_object *json)
 {
-       char buf[BUFSIZ];
        struct zebra_ns *zns = zebra_ns_lookup(nexthop->vrf_id);
 
        switch (nexthop->type) {
        case NEXTHOP_TYPE_IPV4:
        case NEXTHOP_TYPE_IPV4_IFINDEX:
-               vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
-               if (nexthop->ifindex)
-                       vty_out(vty, ", %s",
-                               ifindex2ifname_per_ns(zns, nexthop->ifindex));
+               if (json) {
+                       json_object_string_addf(json, "ip", "%pI4",
+                                               &nexthop->gate.ipv4);
+                       if (nexthop->ifindex)
+                               json_object_string_add(
+                                       json, "interface",
+                                       ifindex2ifname_per_ns(
+                                               zns, nexthop->ifindex));
+               } else {
+                       vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
+                       if (nexthop->ifindex)
+                               vty_out(vty, ", %s",
+                                       ifindex2ifname_per_ns(
+                                               zns, nexthop->ifindex));
+               }
                break;
        case NEXTHOP_TYPE_IPV6:
        case NEXTHOP_TYPE_IPV6_IFINDEX:
-               vty_out(vty, " %s",
-                       inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
-               if (nexthop->ifindex)
-                       vty_out(vty, ", via %s",
-                               ifindex2ifname_per_ns(zns, nexthop->ifindex));
+               if (json) {
+                       json_object_string_addf(json, "ip", "%pI6",
+                                               &nexthop->gate.ipv6);
+                       if (nexthop->ifindex)
+                               json_object_string_add(
+                                       json, "interface",
+                                       ifindex2ifname_per_ns(
+                                               zns, nexthop->ifindex));
+               } else {
+                       vty_out(vty, " %pI6", &nexthop->gate.ipv6);
+                       if (nexthop->ifindex)
+                               vty_out(vty, ", via %s",
+                                       ifindex2ifname_per_ns(
+                                               zns, nexthop->ifindex));
+               }
                break;
        case NEXTHOP_TYPE_IFINDEX:
-               vty_out(vty, " is directly connected, %s",
-                       ifindex2ifname_per_ns(zns, nexthop->ifindex));
+               if (json) {
+                       json_object_string_add(
+                               json, "interface",
+                               ifindex2ifname_per_ns(zns, nexthop->ifindex));
+                       json_object_boolean_true_add(json, "directlyConnected");
+               } else {
+                       vty_out(vty, " is directly connected, %s",
+                               ifindex2ifname_per_ns(zns, nexthop->ifindex));
+               }
                break;
        case NEXTHOP_TYPE_BLACKHOLE:
-               vty_out(vty, " is directly connected, Null0");
+               if (json) {
+                       json_object_string_add(json, "interface", "Null0");
+                       json_object_boolean_true_add(json, "directlyConnected");
+               } else {
+                       vty_out(vty, " is directly connected, Null0");
+               }
                break;
        default:
                break;
        }
-       vty_out(vty, "\n");
+
+       if (!json)
+               vty_out(vty, "\n");
 }
 
-static void print_rnh(struct route_node *rn, struct vty *vty)
+static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json)
 {
        struct rnh *rnh;
        struct nexthop *nexthop;
        struct listnode *node;
        struct zserv *client;
        char buf[BUFSIZ];
+       json_object *json_nht = NULL;
+       json_object *json_client_array = NULL;
+       json_object *json_client = NULL;
+       json_object *json_nexthop_array = NULL;
+       json_object *json_nexthop = NULL;
 
        rnh = rn->info;
-       vty_out(vty, "%s%s\n",
-               inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
-               CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)"
-                                                           : "");
-       if (rnh->state) {
-               vty_out(vty, " resolved via %s\n",
-                       zebra_route_string(rnh->state->type));
-               for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
-                    nexthop = nexthop->next)
-                       print_nh(nexthop, vty);
-       } else
-               vty_out(vty, " unresolved%s\n",
+
+       if (json) {
+               json_nht = json_object_new_object();
+               json_nexthop_array = json_object_new_array();
+               json_client_array = json_object_new_array();
+
+               json_object_object_add(
+                       json,
+                       inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
+                       json_nht);
+               json_object_boolean_add(
+                       json_nht, "nhtConnected",
+                       CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED));
+               json_object_object_add(json_nht, "clientList",
+                                      json_client_array);
+               json_object_object_add(json_nht, "gates", json_nexthop_array);
+       } else {
+               vty_out(vty, "%s%s\n",
+                       inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
                        CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
                                ? "(Connected)"
                                : "");
+       }
+
+       if (rnh->state) {
+               if (json)
+                       json_object_string_add(
+                               json_nht, "resolvedProtocol",
+                               zebra_route_string(rnh->state->type));
+               else
+                       vty_out(vty, " resolved via %s\n",
+                               zebra_route_string(rnh->state->type));
+
+               for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
+                    nexthop = nexthop->next) {
+                       if (json) {
+                               json_nexthop = json_object_new_object();
+                               json_object_array_add(json_nexthop_array,
+                                                     json_nexthop);
+                       }
+                       print_nh(nexthop, vty, json_nexthop);
+               }
+       } else {
+               if (json)
+                       json_object_boolean_add(
+                               json_nht, "unresolved",
+                               CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED));
+               else
+                       vty_out(vty, " unresolved%s\n",
+                               CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
+                                       ? "(Connected)"
+                                       : "");
+       }
+
+       if (!json)
+               vty_out(vty, " Client list:");
+
+       for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
+               if (json) {
+                       json_client = json_object_new_object();
+                       json_object_array_add(json_client_array, json_client);
+
+                       json_object_string_add(
+                               json_client, "protocol",
+                               zebra_route_string(client->proto));
+                       json_object_int_add(json_client, "socket",
+                                           client->sock);
+                       json_object_string_add(json_client, "protocolFiltered",
+                                              (rnh->filtered[client->proto]
+                                                       ? "(filtered)"
+                                                       : "none"));
+               } else {
+                       vty_out(vty, " %s(fd %d)%s",
+                               zebra_route_string(client->proto), client->sock,
+                               rnh->filtered[client->proto] ? "(filtered)"
+                                                            : "");
+               }
+       }
+
+       if (!list_isempty(rnh->zebra_pseudowire_list)) {
+               if (json)
+                       json_object_boolean_true_add(json_nht,
+                                                    "zebraPseudowires");
+               else
+                       vty_out(vty, " zebra[pseudowires]");
+       }
 
-       vty_out(vty, " Client list:");
-       for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
-               vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
-                       client->sock,
-                       rnh->filtered[client->proto] ? "(filtered)" : "");
-       if (!list_isempty(rnh->zebra_pseudowire_list))
-               vty_out(vty, " zebra[pseudowires]");
-       vty_out(vty, "\n");
+       if (!json)
+               vty_out(vty, "\n");
 }
 
 static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, safi_t safi,
index 70eda725c4a71d46d47aab9e876a2fa7939dc885..44ce65b4b650a31a839c47f5e1ff5ce99ca17702 100644 (file)
@@ -46,7 +46,8 @@ extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client);
 extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
                               const struct prefix *p, safi_t safi);
 extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
-                                 struct vty *vty, const struct prefix *p);
+                                 struct vty *vty, const struct prefix *p,
+                                 json_object *json);
 
 extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family);
 
index 6561ac95fa3d81808f41eeb0a997010bedeae59c..91a0c1dd31b8d062c1e8385079bb763146cafbf9 100644 (file)
@@ -1370,7 +1370,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
 
 DEFPY (show_ip_nht,
        show_ip_nht_cmd,
-       "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib]",
+       "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib] [json]",
        SHOW_STR
        IP_STR
        IP6_STR
@@ -1382,23 +1382,48 @@ DEFPY (show_ip_nht,
        "IPv4 Address\n"
        "IPv6 Address\n"
        VRF_ALL_CMD_HELP_STR
-       "Show Multicast (MRIB) NHT state\n")
+       "Show Multicast (MRIB) NHT state\n"
+       JSON_STR)
 {
        afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
        vrf_id_t vrf_id = VRF_DEFAULT;
        struct prefix prefix, *p = NULL;
        safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL;
+       json_object *json_vrf = NULL;
+       json_object *json_nexthop = NULL;
+
+       if (uj)
+               json = json_object_new_object();
 
        if (vrf_all) {
                struct vrf *vrf;
                struct zebra_vrf *zvrf;
 
-               RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
+               RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
                        if ((zvrf = vrf->info) != NULL) {
-                               vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf));
+                               if (uj) {
+                                       json_vrf = json_object_new_object();
+                                       json_nexthop = json_object_new_object();
+                                       json_object_object_add(json,
+                                                              zvrf_name(zvrf),
+                                                              json_vrf);
+                                       json_object_object_add(json_vrf,
+                                                              "nexthops",
+                                                              json_nexthop);
+                               } else {
+                                       vty_out(vty, "\nVRF %s:\n",
+                                               zvrf_name(zvrf));
+                               }
                                zebra_print_rnh_table(zvrf_id(zvrf), afi, safi,
-                                                     vty, NULL);
+                                                     vty, NULL, json_nexthop);
                        }
+               }
+
+               if (uj)
+                       vty_json(vty, json);
+
                return CMD_SUCCESS;
        }
        if (vrf_name)
@@ -1407,11 +1432,29 @@ DEFPY (show_ip_nht,
        memset(&prefix, 0, sizeof(prefix));
        if (addr) {
                p = sockunion2hostprefix(addr, &prefix);
-               if (!p)
+               if (!p) {
+                       if (uj)
+                               json_object_free(json);
                        return CMD_WARNING;
+               }
        }
 
-       zebra_print_rnh_table(vrf_id, afi, safi, vty, p);
+       if (uj) {
+               json_vrf = json_object_new_object();
+               json_nexthop = json_object_new_object();
+               if (vrf_name)
+                       json_object_object_add(json, vrf_name, json_vrf);
+               else
+                       json_object_object_add(json, "default", json_vrf);
+
+               json_object_object_add(json_vrf, "nexthops", json_nexthop);
+       }
+
+       zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop);
+
+       if (uj)
+               vty_json(vty, json);
+
        return CMD_SUCCESS;
 }