From 780563cc8b03cb32899440b1fa2ecb9d35c639aa Mon Sep 17 00:00:00 2001 From: Sindhu Parvathi Gopinathan Date: Mon, 14 Nov 2022 19:33:56 -0800 Subject: [PATCH] zebra: json support for show ip nht show ip/ipv6 nht vrf json support added. Commands enhanced with JSON: ---------------------------- show ip nht json show ip nht json show ipv6 nht json show ipv6 nht json show ip nht vrf json show ip nht vrf all json show ipv6 nht vrf json show ipv6 nht vrf all json show ip nht vrf default json show ipv6 nht vrf default 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 Signed-off-by: Sindhu Parvathi Gopinathan --- doc/user/zebra.rst | 3 +- zebra/zebra_rnh.c | 185 +++++++++++++++++++++++++++++++++++---------- zebra/zebra_rnh.h | 3 +- zebra/zebra_vty.c | 57 ++++++++++++-- 4 files changed, 200 insertions(+), 48 deletions(-) diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index c44642a788..a78731ca94 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -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 ========================= diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 7934a9d206..599c679864 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -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, diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 70eda725c4..44ce65b4b6 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -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); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 6561ac95fa..91a0c1dd31 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -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 $type [$addr|vrf NAME$vrf_name [$addr]|vrf all$vrf_all] [mrib$mrib]", + "show $type [$addr|vrf NAME$vrf_name [$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; } -- 2.39.5