From a21177f28059ba068dbcbb62c16f71dc7f2d16fb Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Thu, 24 Feb 2022 09:33:53 +0100 Subject: [PATCH] isisd: Add json to show isis neighbor command. Signed-off-by: Javier Garcia --- doc/user/isisd.rst | 2 +- isisd/isis_adjacency.c | 214 +++++++++++++++++++++++++++++++++++++++++ isisd/isis_adjacency.h | 2 + isisd/isisd.c | 194 ++++++++++++++++++++++++++++++------- 4 files changed, 374 insertions(+), 38 deletions(-) diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index d9497ea6ec..f1dfd11258 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -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 ] 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. diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index d75613f300..7681e37b26 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -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] */ diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index af70775a87..b8e2d6f577 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -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); diff --git a/isisd/isisd.c b/isisd/isisd.c index 5f9985ae83..ea027f9b9d 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -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 ] neighbor", + "show " PROTO_NAME " [vrf ] 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 ] neighbor detail", + "show " PROTO_NAME " [vrf ] 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 ] neighbor WORD", + "show " PROTO_NAME " [vrf ] 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, -- 2.39.5