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
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.

View 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]
*/

View 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);

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 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,