isisd: Add json to show isis neighbor command.

Signed-off-by: Javier Garcia <javier.martin.garcia@ibm.com>
This commit is contained in:
Javier Garcia 2022-02-24 09:33:53 +01:00
parent 9fee4d4c60
commit a21177f280
4 changed files with 375 additions and 39 deletions

View file

@ -285,7 +285,7 @@ Showing ISIS information
Show state and configuration of ISIS specified interface, or all interfaces Show state and configuration of ISIS specified interface, or all interfaces
if no interface is given with or without details. 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 Show state and information of ISIS specified neighbor, or all neighbors if
no system id is given with or without details. no system id is given with or without details.

View file

@ -465,6 +465,220 @@ int isis_adj_expire(struct thread *thread)
return 0; 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] * show isis neighbor [detail]
*/ */

View file

@ -144,6 +144,8 @@ const char *isis_adj_yang_state(enum isis_adj_state state);
int isis_adj_expire(struct thread *thread); int isis_adj_expire(struct thread *thread);
void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
char detail); 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_neigh_list(struct list *adjdb, struct list *list);
void isis_adj_build_up_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); int isis_adj_usage2levels(enum isis_adj_usage usage);

View 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 isis_area_get(struct vty *, const char *);
int area_net_title(struct vty *, const char *); int area_net_title(struct vty *, const char *);
int area_clear_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, int show_isis_interface_common(struct vty *, struct json_object *json,
const char *ifname, char, const char *vrf_name, const char *ifname, char, const char *vrf_name,
bool all_vrf); 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, int show_isis_interface_common_json(struct json_object *json,
const char *ifname, char, const char *ifname, char,
const char *vrf_name, bool all_vrf); 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. */ /* Link ISIS instance to VRF. */
void isis_vrf_link(struct isis *isis, struct vrf *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_circuit *circuit;
struct isis *isis; struct isis *isis;
struct json_object *areas_json, *area_json; struct json_object *areas_json, *area_json;
struct json_object *circuits_json, *circuit_json;
if (!im) { if (!im) {
// IS-IS Routing Process not enabled // IS-IS Routing Process not enabled
json_object_string_add(json, "is-is-routing-process-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_json, "area",
area->area_tag ? area->area_tag area->area_tag ? area->area_tag
: "null"); : "null");
circuits_json = json_object_new_array();
json_object_object_add(area_json,
"circuits",
circuits_json);
for (ALL_LIST_ELEMENTS_RO( for (ALL_LIST_ELEMENTS_RO(
area->circuit_list, cnode, area->circuit_list, cnode,
circuit)) circuit)) {
circuit_json =
json_object_new_object();
json_object_int_add(
circuit_json, "circuit",
circuit->circuit_id);
if (!ifname) if (!ifname)
isis_circuit_print_json( isis_circuit_print_json(
circuit, circuit,
area_json, circuit_json,
detail); detail);
else if (strcmp(circuit->interface->name, ifname) == 0) else if (strcmp(circuit->interface->name, ifname) == 0)
isis_circuit_print_json( isis_circuit_print_json(
circuit, circuit,
area_json, circuit_json,
detail); detail);
json_object_array_add(
circuits_json,
circuit_json);
}
json_object_array_add(areas_json, json_object_array_add(areas_json,
area_json); area_json);
} }
@ -1011,18 +1026,28 @@ int show_isis_interface_common_json(struct json_object *json,
? area->area_tag ? area->area_tag
: "null"); : "null");
circuits_json = json_object_new_array();
json_object_object_add(area_json, "circuits",
circuits_json);
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, 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) if (!ifname)
isis_circuit_print_json( isis_circuit_print_json(
circuit, area_json, circuit, circuit_json,
detail); detail);
else if ( else if (
strcmp(circuit->interface->name, strcmp(circuit->interface->name,
ifname) == 0) ifname) == 0)
isis_circuit_print_json( isis_circuit_print_json(
circuit, area_json, circuit, circuit_json,
detail); detail);
json_object_array_add(circuits_json,
circuit_json);
}
json_object_array_add(areas_json, area_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; return 0;
} }
static void isis_neighbor_common(struct vty *vty, const char *id, char detail, static void isis_neighbor_common_json(struct json_object *json, const char *id,
struct isis *isis, uint8_t *sysid) 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 listnode *anode, *cnode, *node;
struct isis_area *area; 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) { if (adjdb && adjdb->count) {
for (ALL_LIST_ELEMENTS_RO( for (ALL_LIST_ELEMENTS_RO(
adjdb, node, adj)) adjdb, node, adj))
if (!id if (!id ||
|| !memcmp( !memcmp(adj->sysid,
adj->sysid,
sysid, sysid,
ISIS_SYS_ID_LEN)) ISIS_SYS_ID_LEN))
isis_adj_print_vty( isis_adj_print_vty(
@ -1237,24 +1318,35 @@ static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
detail); detail);
} }
} }
} else if (circuit->circ_type == CIRCUIT_T_P2P } else if (circuit->circ_type == CIRCUIT_T_P2P &&
&& circuit->u.p2p.neighbor) { circuit->u.p2p.neighbor) {
adj = circuit->u.p2p.neighbor; adj = circuit->u.p2p.neighbor;
if (!id if (!id ||
|| !memcmp(adj->sysid, sysid, !memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
ISIS_SYS_ID_LEN))
isis_adj_print_vty(adj, vty, detail); 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 * 'show isis neighbor' command
*/ */
int show_isis_neighbor_common(struct vty *vty, const char *id, char detail, int show_isis_neighbor_common(struct vty *vty, struct json_object *json,
const char *vrf_name, bool all_vrf) const char *id, char detail, const char *vrf_name,
bool all_vrf)
{ {
struct listnode *node; struct listnode *node;
uint8_t sysid[ISIS_SYS_ID_LEN]; 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); id);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
isis_neighbor_common(vty, id, detail, isis, isis_neighbor_common(vty, json, id, detail,
sysid); isis, sysid);
} }
return CMD_SUCCESS; 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); vty_out(vty, "Invalid system id %s\n", id);
return CMD_SUCCESS; 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, DEFUN(show_isis_neighbor,
show_isis_neighbor_cmd, show_isis_neighbor_cmd,
"show " PROTO_NAME " [vrf <NAME|all>] neighbor", "show " PROTO_NAME " [vrf <NAME|all>] neighbor [json]",
SHOW_STR SHOW_STR
PROTO_HELP PROTO_HELP
VRF_CMD_HELP_STR VRF_CMD_HELP_STR
"All vrfs\n" "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; const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false; bool all_vrf = false;
int idx_vrf = 0; 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); ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
return show_isis_neighbor_common(vty, NULL, ISIS_UI_LEVEL_BRIEF, if (uj)
json = json_object_new_object();
res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_BRIEF,
vrf_name, all_vrf); vrf_name, all_vrf);
if (uj)
vty_json(vty, json);
return res;
} }
DEFUN(show_isis_neighbor_detail, DEFUN(show_isis_neighbor_detail,
show_isis_neighbor_detail_cmd, show_isis_neighbor_detail_cmd,
"show " PROTO_NAME " [vrf <NAME|all>] neighbor detail", "show " PROTO_NAME " [vrf <NAME|all>] neighbor detail [json]",
SHOW_STR SHOW_STR
PROTO_HELP PROTO_HELP
VRF_CMD_HELP_STR VRF_CMD_HELP_STR
"all vrfs\n" "all vrfs\n"
"IS-IS neighbor adjacencies\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; const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false; bool all_vrf = false;
int idx_vrf = 0; 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); 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, res = show_isis_neighbor_common(vty, json, NULL, ISIS_UI_LEVEL_DETAIL,
vrf_name, all_vrf); vrf_name, all_vrf);
if (uj)
vty_json(vty, json);
return res;
} }
DEFUN(show_isis_neighbor_arg, DEFUN(show_isis_neighbor_arg,
show_isis_neighbor_arg_cmd, show_isis_neighbor_arg_cmd,
"show " PROTO_NAME " [vrf <NAME|all>] neighbor WORD", "show " PROTO_NAME " [vrf <NAME|all>] neighbor WORD [json]",
SHOW_STR SHOW_STR
PROTO_HELP PROTO_HELP
VRF_CMD_HELP_STR VRF_CMD_HELP_STR
"All vrfs\n" "All vrfs\n"
"IS-IS neighbor adjacencies\n" "IS-IS neighbor adjacencies\n"
"System id\n") "System id\n"
"json output\n")
{ {
int res = CMD_SUCCESS;
int idx_word = 0; int idx_word = 0;
const char *vrf_name = VRF_DEFAULT_NAME; const char *vrf_name = VRF_DEFAULT_NAME;
bool all_vrf = false; bool all_vrf = false;
int idx_vrf = 0; 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); 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) char *id = argv_find(argv, argc, "WORD", &idx_word)
? argv[idx_word]->arg ? argv[idx_word]->arg
: NULL; : NULL;
return show_isis_neighbor_common(vty, id, ISIS_UI_LEVEL_DETAIL, res = show_isis_neighbor_common(vty, json, id, ISIS_UI_LEVEL_DETAIL,
vrf_name, all_vrf); vrf_name, all_vrf);
if (uj)
vty_json(vty, json);
return res;
} }
DEFUN(clear_isis_neighbor, DEFUN(clear_isis_neighbor,