zebra: json support for show ip nht

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>
This commit is contained in:
Sindhu Parvathi Gopinathan 2022-11-14 19:33:56 -08:00 committed by Chirag Shah
parent e7ae04259d
commit 780563cc8b
4 changed files with 200 additions and 48 deletions

View File

@ -305,7 +305,8 @@ the default route.
indicates that the operator wants to see the multicast rib address resolution 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 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. 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 PBR dataplane programming
========================= =========================

View 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, static void copy_state(struct rnh *rnh, const struct route_entry *re,
struct route_node *rn); struct route_node *rn);
static bool compare_state(struct route_entry *r1, struct route_entry *r2); 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); static int zebra_client_cleanup_rnh(struct zserv *client);
void zebra_rnh_init(void) 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, 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_table *table;
struct route_node *rn; struct route_node *rn;
@ -820,7 +822,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
continue; continue;
if (rn->info) if (rn->info)
print_rnh(rn, vty); print_rnh(rn, vty, json);
} }
} }
@ -1268,73 +1270,178 @@ failure:
return -1; 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); struct zebra_ns *zns = zebra_ns_lookup(nexthop->vrf_id);
switch (nexthop->type) { switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFINDEX:
vty_out(vty, " via %pI4", &nexthop->gate.ipv4); if (json) {
if (nexthop->ifindex) json_object_string_addf(json, "ip", "%pI4",
vty_out(vty, ", %s", &nexthop->gate.ipv4);
ifindex2ifname_per_ns(zns, nexthop->ifindex)); 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; break;
case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX: case NEXTHOP_TYPE_IPV6_IFINDEX:
vty_out(vty, " %s", if (json) {
inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); json_object_string_addf(json, "ip", "%pI6",
if (nexthop->ifindex) &nexthop->gate.ipv6);
vty_out(vty, ", via %s", if (nexthop->ifindex)
ifindex2ifname_per_ns(zns, 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; break;
case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFINDEX:
vty_out(vty, " is directly connected, %s", if (json) {
ifindex2ifname_per_ns(zns, nexthop->ifindex)); 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; break;
case NEXTHOP_TYPE_BLACKHOLE: 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; break;
default: default:
break; 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 rnh *rnh;
struct nexthop *nexthop; struct nexthop *nexthop;
struct listnode *node; struct listnode *node;
struct zserv *client; struct zserv *client;
char buf[BUFSIZ]; 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; rnh = rn->info;
vty_out(vty, "%s%s\n",
inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ), if (json) {
CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)" json_nht = json_object_new_object();
: ""); json_nexthop_array = json_object_new_array();
if (rnh->state) { json_client_array = json_object_new_array();
vty_out(vty, " resolved via %s\n",
zebra_route_string(rnh->state->type)); json_object_object_add(
for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop; json,
nexthop = nexthop->next) inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
print_nh(nexthop, vty); json_nht);
} else json_object_boolean_add(
vty_out(vty, " unresolved%s\n", 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) CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
? "(Connected)" ? "(Connected)"
: ""); : "");
}
vty_out(vty, " Client list:"); if (rnh->state) {
for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) if (json)
vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto), json_object_string_add(
client->sock, json_nht, "resolvedProtocol",
rnh->filtered[client->proto] ? "(filtered)" : ""); zebra_route_string(rnh->state->type));
if (!list_isempty(rnh->zebra_pseudowire_list)) else
vty_out(vty, " zebra[pseudowires]"); vty_out(vty, " resolved via %s\n",
vty_out(vty, "\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]");
}
if (!json)
vty_out(vty, "\n");
} }
static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, safi_t safi, static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, safi_t safi,

View 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, extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
const struct prefix *p, safi_t safi); const struct prefix *p, safi_t safi);
extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, 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); extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family);

View 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, DEFPY (show_ip_nht,
show_ip_nht_cmd, 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 SHOW_STR
IP_STR IP_STR
IP6_STR IP6_STR
@ -1382,23 +1382,48 @@ DEFPY (show_ip_nht,
"IPv4 Address\n" "IPv4 Address\n"
"IPv6 Address\n" "IPv6 Address\n"
VRF_ALL_CMD_HELP_STR 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; afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
vrf_id_t vrf_id = VRF_DEFAULT; vrf_id_t vrf_id = VRF_DEFAULT;
struct prefix prefix, *p = NULL; struct prefix prefix, *p = NULL;
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST; 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) { if (vrf_all) {
struct vrf *vrf; struct vrf *vrf;
struct zebra_vrf *zvrf; 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) { 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, zebra_print_rnh_table(zvrf_id(zvrf), afi, safi,
vty, NULL); vty, NULL, json_nexthop);
} }
}
if (uj)
vty_json(vty, json);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
if (vrf_name) if (vrf_name)
@ -1407,11 +1432,29 @@ DEFPY (show_ip_nht,
memset(&prefix, 0, sizeof(prefix)); memset(&prefix, 0, sizeof(prefix));
if (addr) { if (addr) {
p = sockunion2hostprefix(addr, &prefix); p = sockunion2hostprefix(addr, &prefix);
if (!p) if (!p) {
if (uj)
json_object_free(json);
return CMD_WARNING; 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; return CMD_SUCCESS;
} }