]> git.puffer.fish Git - matthieu/frr.git/commitdiff
isisd: Add json to show isis neighbor command.
authorJavier Garcia <javier.martin.garcia@ibm.com>
Thu, 24 Feb 2022 08:33:53 +0000 (09:33 +0100)
committerJavier Garcia <javier.martin.garcia@ibm.com>
Tue, 1 Mar 2022 16:57:21 +0000 (17:57 +0100)
Signed-off-by: Javier Garcia <javier.martin.garcia@ibm.com>
doc/user/isisd.rst
isisd/isis_adjacency.c
isisd/isis_adjacency.h
isisd/isisd.c

index d9497ea6ec96e74917909e61293607f7a778f98b..f1dfd1125868a251380fdf269c8f352e3a2a16e7 100644 (file)
@@ -285,7 +285,7 @@ Showing ISIS information
    Show state and configuration of ISIS specified interface, or all interfaces
    if no interface is given with or without details.
 
-.. clicmd:: show isis neighbor [detail] [SYSTEMID]
+.. clicmd:: show isis [vrf <NAME|all>] neighbor [detail] [SYSTEMID] [json]
 
    Show state and information of ISIS specified neighbor, or all neighbors if
    no system id is given with or without details.
index d75613f300a1493a052759eb60679667fcaa0228..7681e37b263bcd57d087da5195c50ea8b46d9317 100644 (file)
@@ -465,6 +465,220 @@ int isis_adj_expire(struct thread *thread)
        return 0;
 }
 
+/*
+ * show isis neighbor [detail] json
+ */
+void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json,
+                        char detail)
+{
+       json_object *iface_json, *ipv4_addr_json, *ipv6_link_json,
+               *ipv6_non_link_json, *topo_json, *dis_flaps_json,
+               *area_addr_json, *adj_sid_json;
+       time_t now;
+       struct isis_dynhn *dyn;
+       int level;
+       char buf[256];
+
+       json_object_string_add(json, "adj", isis_adj_name(adj));
+
+       if (detail == ISIS_UI_LEVEL_BRIEF) {
+               if (adj->circuit)
+                       json_object_string_add(json, "interface",
+                                              adj->circuit->interface->name);
+               else
+                       json_object_string_add(json, "interface",
+                                              "NULL circuit!");
+               json_object_int_add(json, "level", adj->level);
+               json_object_string_add(json, "state",
+                                      adj_state2string(adj->adj_state));
+               now = time(NULL);
+               if (adj->last_upd) {
+                       if (adj->last_upd + adj->hold_time < now)
+                               json_object_string_add(json, "last-upd",
+                                                      "expiring");
+                       else
+                               json_object_string_add(
+                                       json, "expires-in",
+                                       time2string(adj->last_upd +
+                                                   adj->hold_time - now));
+               }
+               json_object_string_add(json, "snpa", snpa_print(adj->snpa));
+       }
+
+       if (detail == ISIS_UI_LEVEL_DETAIL) {
+               struct sr_adjacency *sra;
+               struct listnode *anode;
+
+               level = adj->level;
+               iface_json = json_object_new_object();
+               json_object_object_add(json, "interface", iface_json);
+               if (adj->circuit)
+                       json_object_string_add(iface_json, "name",
+                                              adj->circuit->interface->name);
+               else
+                       json_object_string_add(iface_json, "name",
+                                              "null-circuit");
+               json_object_int_add(json, "level", adj->level);
+               json_object_string_add(iface_json, "state",
+                                      adj_state2string(adj->adj_state));
+               now = time(NULL);
+               if (adj->last_upd) {
+                       if (adj->last_upd + adj->hold_time < now)
+                               json_object_string_add(iface_json, "last-upd",
+                                                      "expiring");
+                       else
+                               json_object_string_add(
+                                       json, "expires-in",
+                                       time2string(adj->last_upd +
+                                                   adj->hold_time - now));
+               } else
+                       json_object_string_add(json, "expires-in",
+                                              time2string(adj->hold_time));
+               json_object_int_add(iface_json, "adj-flaps", adj->flaps);
+               json_object_string_add(iface_json, "last-ago",
+                                      time2string(now - adj->last_flap));
+               json_object_string_add(iface_json, "circuit-type",
+                                      circuit_t2string(adj->circuit_t));
+               json_object_string_add(iface_json, "speaks",
+                                      nlpid2string(&adj->nlpids));
+               if (adj->mt_count != 1 ||
+                   adj->mt_set[0] != ISIS_MT_IPV4_UNICAST) {
+                       topo_json = json_object_new_object();
+                       json_object_object_add(iface_json, "topologies",
+                                              topo_json);
+                       for (unsigned int i = 0; i < adj->mt_count; i++) {
+                               snprintfrr(buf, sizeof(buf), "topo-%d", i);
+                               json_object_string_add(
+                                       topo_json, buf,
+                                       isis_mtid2str(adj->mt_set[i]));
+                       }
+               }
+               json_object_string_add(iface_json, "snpa",
+                                      snpa_print(adj->snpa));
+               if (adj->circuit &&
+                   (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
+                       dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
+                       if (dyn) {
+                               snprintfrr(buf, sizeof(buf), "%s-%02x",
+                                          dyn->hostname,
+                                          adj->lanid[ISIS_SYS_ID_LEN]);
+                               json_object_string_add(iface_json, "lan-id",
+                                                      buf);
+                       } else {
+                               snprintfrr(buf, sizeof(buf), "%s-%02x",
+                                          sysid_print(adj->lanid),
+                                          adj->lanid[ISIS_SYS_ID_LEN]);
+                               json_object_string_add(iface_json, "lan-id",
+                                                      buf);
+                       }
+
+                       json_object_int_add(iface_json, "lan-prio",
+                                           adj->prio[adj->level - 1]);
+
+                       dis_flaps_json = json_object_new_object();
+                       json_object_object_add(iface_json, "dis-flaps",
+                                              dis_flaps_json);
+                       json_object_string_add(
+                               dis_flaps_json, "dis-record",
+                               isis_disflag2string(
+                                       adj->dis_record[ISIS_LEVELS + level - 1]
+                                               .dis));
+                       json_object_int_add(dis_flaps_json, "last",
+                                           adj->dischanges[level - 1]);
+                       json_object_string_add(
+                               dis_flaps_json, "ago",
+                               time2string(now - (adj->dis_record[ISIS_LEVELS +
+                                                                  level - 1]
+                                                          .last_dis_change)));
+               }
+
+               if (adj->area_address_count) {
+                       area_addr_json = json_object_new_object();
+                       json_object_object_add(iface_json, "area-address",
+                                              area_addr_json);
+                       for (unsigned int i = 0; i < adj->area_address_count;
+                            i++) {
+                               json_object_string_add(
+                                       area_addr_json, "isonet",
+                                       isonet_print(adj->area_addresses[i]
+                                                            .area_addr,
+                                                    adj->area_addresses[i]
+                                                            .addr_len));
+                       }
+               }
+               if (adj->ipv4_address_count) {
+                       ipv4_addr_json = json_object_new_object();
+                       json_object_object_add(iface_json, "ipv4-address",
+                                              ipv4_addr_json);
+                       for (unsigned int i = 0; i < adj->ipv4_address_count;
+                            i++){
+                               inet_ntop(AF_INET, &adj->ipv4_addresses[i], buf,
+                                         sizeof(buf));
+                       json_object_string_add(ipv4_addr_json, "ipv4", buf);
+               }
+               }
+               if (adj->ll_ipv6_count) {
+                       ipv6_link_json = json_object_new_object();
+                       json_object_object_add(iface_json, "ipv6-link-local",
+                                              ipv6_link_json);
+                       for (unsigned int i = 0; i < adj->ll_ipv6_count; i++) {
+                               char buf[INET6_ADDRSTRLEN];
+                               inet_ntop(AF_INET6, &adj->ll_ipv6_addrs[i], buf,
+                                         sizeof(buf));
+                               json_object_string_add(ipv6_link_json, "ipv6",
+                                                      buf);
+                       }
+               }
+               if (adj->global_ipv6_count) {
+                       ipv6_non_link_json = json_object_new_object();
+                       json_object_object_add(iface_json, "ipv6-global",
+                                              ipv6_non_link_json);
+                       for (unsigned int i = 0; i < adj->global_ipv6_count;
+                            i++) {
+                               char buf[INET6_ADDRSTRLEN];
+                               inet_ntop(AF_INET6, &adj->global_ipv6_addrs[i],
+                                         buf, sizeof(buf));
+                               json_object_string_add(ipv6_non_link_json,
+                                                      "ipv6", buf);
+                       }
+               }
+
+               adj_sid_json = json_object_new_object();
+               json_object_object_add(iface_json, "adj-sid", adj_sid_json);
+               for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
+                       const char *adj_type;
+                       const char *backup;
+                       uint32_t sid;
+
+                       switch (sra->adj->circuit->circ_type) {
+                       case CIRCUIT_T_BROADCAST:
+                               adj_type = "LAN Adjacency-SID";
+                               sid = sra->u.ladj_sid->sid;
+                               break;
+                       case CIRCUIT_T_P2P:
+                               adj_type = "Adjacency-SID";
+                               sid = sra->u.adj_sid->sid;
+                               break;
+                       default:
+                               continue;
+                       }
+                       backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)"
+                                                                  : "";
+
+                       json_object_string_add(adj_sid_json, "nexthop",
+                                              (sra->nexthop.family == AF_INET)
+                                                      ? "IPv4"
+                                                      : "IPv6");
+                       json_object_string_add(adj_sid_json, "adj-type",
+                                              adj_type);
+                       json_object_string_add(adj_sid_json, "is-backup",
+                                              backup);
+                       json_object_int_add(adj_sid_json, "sid", sid);
+               }
+       }
+       return;
+}
+
 /*
  * show isis neighbor [detail]
  */
index af70775a87fe962fd5144ba70fba169e6545d284..b8e2d6f577cd52e6300593a16b31c5ef77b3ab13 100644 (file)
@@ -144,6 +144,8 @@ const char *isis_adj_yang_state(enum isis_adj_state state);
 int isis_adj_expire(struct thread *thread);
 void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
                        char detail);
+void isis_adj_print_json(struct isis_adjacency *adj, struct json_object *json,
+                        char detail);
 void isis_adj_build_neigh_list(struct list *adjdb, struct list *list);
 void isis_adj_build_up_list(struct list *adjdb, struct list *list);
 int isis_adj_usage2levels(enum isis_adj_usage usage);
index 5f9985ae831e9591735c0787d94db29bd7908a32..ea027f9b9dacabe106243742c410c09232ae82ad 100644 (file)
@@ -109,9 +109,6 @@ DEFINE_HOOK(isis_hook_db_overload, (const struct isis_area *area), (area));
 int isis_area_get(struct vty *, const char *);
 int area_net_title(struct vty *, const char *);
 int area_clear_net_title(struct vty *, const char *);
-int show_isis_neighbor_common(struct vty *, const char *id, char,
-                             const char *vrf_name, bool all_vrf);
-int clear_isis_neighbor_common(struct vty *, const char *id, const char *vrf_name,
 int show_isis_interface_common(struct vty *, struct json_object *json,
                               const char *ifname, char, const char *vrf_name,
                               bool all_vrf);
@@ -120,6 +117,11 @@ int show_isis_interface_common_vty(struct vty *, const char *ifname, char,
 int show_isis_interface_common_json(struct json_object *json,
                                    const char *ifname, char,
                                    const char *vrf_name, bool all_vrf);
+int show_isis_neighbor_common(struct vty *, struct json_object *json,
+                             const char *id, char, const char *vrf_name,
+                             bool all_vrf);
+int clear_isis_neighbor_common(struct vty *, const char *id,
+                              const char *vrf_name, bool all_vrf);
 
 /* Link ISIS instance to VRF. */
 void isis_vrf_link(struct isis *isis, struct vrf *vrf)
@@ -960,6 +962,7 @@ int show_isis_interface_common_json(struct json_object *json,
        struct isis_circuit *circuit;
        struct isis *isis;
        struct json_object *areas_json, *area_json;
+       struct json_object *circuits_json, *circuit_json;
        if (!im) {
                // IS-IS Routing Process not enabled
                json_object_string_add(json, "is-is-routing-process-enabled",
@@ -979,20 +982,32 @@ int show_isis_interface_common_json(struct json_object *json,
                                                area_json, "area",
                                                area->area_tag ? area->area_tag
                                                               : "null");
-
+                                       circuits_json = json_object_new_array();
+                                       json_object_object_add(area_json,
+                                                              "circuits",
+                                                              circuits_json);
                                        for (ALL_LIST_ELEMENTS_RO(
                                                     area->circuit_list, cnode,
-                                                    circuit))
+                                                    circuit)) {
+                                               circuit_json =
+                                                       json_object_new_object();
+                                               json_object_int_add(
+                                                       circuit_json, "circuit",
+                                                       circuit->circuit_id);
                                                if (!ifname)
                                                        isis_circuit_print_json(
                                                                circuit,
-                                                               area_json,
+                                                               circuit_json,
                                                                detail);
                                                else if (strcmp(circuit->interface->name, ifname) == 0)
                                                        isis_circuit_print_json(
                                                                circuit,
-                                                               area_json,
+                                                               circuit_json,
                                                                detail);
+                                               json_object_array_add(
+                                                       circuits_json,
+                                                       circuit_json);
+                                       }
                                        json_object_array_add(areas_json,
                                                              area_json);
                                }
@@ -1011,18 +1026,28 @@ int show_isis_interface_common_json(struct json_object *json,
                                                               ? area->area_tag
                                                               : "null");
 
+                               circuits_json = json_object_new_array();
+                               json_object_object_add(area_json, "circuits",
+                                                      circuits_json);
                                for (ALL_LIST_ELEMENTS_RO(area->circuit_list,
-                                                         cnode, circuit))
+                                                         cnode, circuit)) {
+                                       circuit_json = json_object_new_object();
+                                       json_object_int_add(
+                                               circuit_json, "circuit",
+                                               circuit->circuit_id);
                                        if (!ifname)
                                                isis_circuit_print_json(
-                                                       circuit, area_json,
+                                                       circuit, circuit_json,
                                                        detail);
                                        else if (
                                                strcmp(circuit->interface->name,
                                                       ifname) == 0)
                                                isis_circuit_print_json(
-                                                       circuit, area_json,
+                                                       circuit, circuit_json,
                                                        detail);
+                                       json_object_array_add(circuits_json,
+                                                             circuit_json);
+                               }
                                json_object_array_add(areas_json, area_json);
                        }
                }
@@ -1202,8 +1227,65 @@ static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid)
        return 0;
 }
 
-static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
-                                struct isis *isis, uint8_t *sysid)
+static void isis_neighbor_common_json(struct json_object *json, const char *id,
+                                     char detail, struct isis *isis,
+                                     uint8_t *sysid)
+{
+       struct listnode *anode, *cnode, *node;
+       struct isis_area *area;
+       struct isis_circuit *circuit;
+       struct list *adjdb;
+       struct isis_adjacency *adj;
+       struct json_object *areas_json, *area_json;
+       struct json_object *circuits_json, *circuit_json;
+       int i;
+
+       areas_json = json_object_new_array();
+       json_object_object_add(json, "areas", areas_json);
+       for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+               area_json = json_object_new_object();
+               json_object_string_add(area_json, "area",
+                                      area->area_tag ? area->area_tag
+                                                     : "null");
+               circuits_json = json_object_new_array();
+               json_object_object_add(area_json, "circuits", circuits_json);
+               for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) {
+                       circuit_json = json_object_new_object();
+                       json_object_int_add(circuit_json, "circuit",
+                                           circuit->circuit_id);
+                       if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+                               for (i = 0; i < 2; i++) {
+                                       adjdb = circuit->u.bc.adjdb[i];
+                                       if (adjdb && adjdb->count) {
+                                               for (ALL_LIST_ELEMENTS_RO(
+                                                            adjdb, node, adj))
+                                                       if (!id ||
+                                                           !memcmp(adj->sysid,
+                                                                   sysid,
+                                                                   ISIS_SYS_ID_LEN))
+                                                               isis_adj_print_json(
+                                                                       adj,
+                                                                       circuit_json,
+                                                                       detail);
+                                       }
+                               }
+                       } else if (circuit->circ_type == CIRCUIT_T_P2P &&
+                                  circuit->u.p2p.neighbor) {
+                               adj = circuit->u.p2p.neighbor;
+                               if (!id ||
+                                   !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
+                                       isis_adj_print_json(adj, circuit_json,
+                                                           detail);
+                       }
+                       json_object_array_add(circuits_json, circuit_json);
+               }
+               json_object_array_add(areas_json, area_json);
+       }
+}
+
+static void isis_neighbor_common_vty(struct vty *vty, const char *id,
+                                    char detail, struct isis *isis,
+                                    uint8_t *sysid)
 {
        struct listnode *anode, *cnode, *node;
        struct isis_area *area;
@@ -1226,9 +1308,8 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
                                        if (adjdb && adjdb->count) {
                                                for (ALL_LIST_ELEMENTS_RO(
                                                             adjdb, node, adj))
-                                                       if (!id
-                                                           || !memcmp(
-                                                                   adj->sysid,
+                                                       if (!id ||
+                                                           !memcmp(adj->sysid,
                                                                    sysid,
                                                                    ISIS_SYS_ID_LEN))
                                                                isis_adj_print_vty(
@@ -1237,24 +1318,35 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
                                                                        detail);
                                        }
                                }
-                       } else if (circuit->circ_type == CIRCUIT_T_P2P
-                                  && circuit->u.p2p.neighbor) {
+                       } else if (circuit->circ_type == CIRCUIT_T_P2P &&
+                                  circuit->u.p2p.neighbor) {
                                adj = circuit->u.p2p.neighbor;
-                               if (!id
-                                   || !memcmp(adj->sysid, sysid,
-                                              ISIS_SYS_ID_LEN))
+                               if (!id ||
+                                   !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
                                        isis_adj_print_vty(adj, vty, detail);
                        }
                }
        }
+}
 
+static void isis_neighbor_common(struct vty *vty, struct json_object *json,
+                                const char *id, char detail, struct isis *isis,
+                                uint8_t *sysid)
+{
+       if (json) {
+               isis_neighbor_common_json(json, id, detail,isis,sysid);
+       } else {
+               isis_neighbor_common_vty(vty, id, detail,isis,sysid);
+       }
 }
+
 /*
  * 'show isis neighbor' command
  */
 
-int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
-                             const char *vrf_name, bool all_vrf)
+int show_isis_neighbor_common(struct vty *vty, struct json_object *json,
+                             const char *id, char detail, const char *vrf_name,
+                             bool all_vrf)
 {
        struct listnode *node;
        uint8_t sysid[ISIS_SYS_ID_LEN];
@@ -1273,8 +1365,8 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
                                                id);
                                        return CMD_SUCCESS;
                                }
-                               isis_neighbor_common(vty, id, detail, isis,
-                                                    sysid);
+                               isis_neighbor_common(vty, json, id, detail,
+                                                    isis, sysid);
                        }
                        return CMD_SUCCESS;
                }
@@ -1284,7 +1376,8 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
                                vty_out(vty, "Invalid system id %s\n", id);
                                return CMD_SUCCESS;
                        }
-                       isis_neighbor_common(vty, id, detail, isis, sysid);
+                       isis_neighbor_common(vty, json, id, detail, isis,
+                                            sysid);
                }
        }
 
@@ -1377,64 +1470,91 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_
 
 DEFUN(show_isis_neighbor,
       show_isis_neighbor_cmd,
-      "show " PROTO_NAME " [vrf <NAME|all>] neighbor",
+      "show " PROTO_NAME " [vrf <NAME|all>] neighbor [json]",
       SHOW_STR
       PROTO_HELP
       VRF_CMD_HELP_STR
       "All vrfs\n"
-      "IS-IS neighbor adjacencies\n")
+      "IS-IS neighbor adjacencies\n"
+      "json output\n")
 {
+       int res = CMD_SUCCESS;
        const char *vrf_name = VRF_DEFAULT_NAME;
        bool all_vrf = false;
        int idx_vrf = 0;
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL;
 
        ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
-       return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_BRIEF,
-                                        vrf_name, all_vrf);
+       if (uj)
+               json = json_object_new_object();
+       res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_BRIEF,
+                                       vrf_name, all_vrf);
+       if (uj)
+               vty_json(vty, json);
+       return res;
 }
 
 DEFUN(show_isis_neighbor_detail,
       show_isis_neighbor_detail_cmd,
-      "show " PROTO_NAME " [vrf <NAME|all>] neighbor detail",
+      "show " PROTO_NAME " [vrf <NAME|all>] neighbor detail [json]",
       SHOW_STR
       PROTO_HELP
       VRF_CMD_HELP_STR
       "all vrfs\n"
       "IS-IS neighbor adjacencies\n"
-      "show detailed information\n")
+      "show detailed information\n"
+      "json output\n")
 {
+       int res = CMD_SUCCESS;
        const char *vrf_name = VRF_DEFAULT_NAME;
        bool all_vrf = false;
        int idx_vrf = 0;
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL;
 
        ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+       if (uj)
+               json = json_object_new_object();
 
-       return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_DETAIL,
-                                        vrf_name, all_vrf);
+       res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_DETAIL,
+                                       vrf_name, all_vrf);
+       if (uj)
+               vty_json(vty, json);
+       return res;
 }
 
 DEFUN(show_isis_neighbor_arg,
       show_isis_neighbor_arg_cmd,
-      "show " PROTO_NAME " [vrf <NAME|all>] neighbor WORD",
+      "show " PROTO_NAME " [vrf <NAME|all>] neighbor WORD [json]",
       SHOW_STR
       PROTO_HELP
       VRF_CMD_HELP_STR
       "All vrfs\n"
       "IS-IS neighbor adjacencies\n"
-      "System id\n")
+      "System id\n"
+      "json output\n")
 {
+       int res = CMD_SUCCESS;
        int idx_word = 0;
        const char *vrf_name = VRF_DEFAULT_NAME;
        bool all_vrf = false;
        int idx_vrf = 0;
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL;
 
        ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
+       if (uj)
+               json = json_object_new_object();
        char *id = argv_find(argv, argc, "WORD", &idx_word)
                           ? argv[idx_word]->arg
                           : NULL;
 
-       return show_isis_neighbor_common(vty, id, ISIS_UI_LEVEL_DETAIL,
-                                        vrf_name, all_vrf);
+       res = show_isis_neighbor_common(vty, json, id, ISIS_UI_LEVEL_DETAIL,
+                                       vrf_name, all_vrf);
+       if (uj)
+               vty_json(vty, json);
+       return res;
 }
 
 DEFUN(clear_isis_neighbor,