isisd, yang: implement read-only list of adjacencies

The new "adjacency-state" grouping is almost a 1:1 copy of the
same grouping from the IETF IS-IS module, except for the "usage"
and "lastuptime" leafs that were skipped (more work needs to be
done to support those).

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
Renato Westphal 2019-09-23 09:38:01 -03:00
parent e206450bd9
commit aec5ef490c
2 changed files with 316 additions and 14 deletions

View File

@ -48,6 +48,23 @@
#include "lib/lib_errors.h"
#include "lib/vrf.h"
/*
* Helper functions.
*/
static const char *isis_yang_adj_state(enum isis_adj_state state)
{
switch (state) {
case ISIS_ADJ_DOWN:
return "down";
case ISIS_ADJ_UP:
return "up";
case ISIS_ADJ_INITIALIZING:
return "init";
default:
return "failed";
}
}
/*
* XPath: /frr-isisd:isis/instance
*/
@ -2303,6 +2320,169 @@ static int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
ISIS_MT_IPV6_DSTSRC);
}
/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency
*/
static const void *
lib_interface_isis_adjacencies_adjacency_get_next(const void *parent_list_entry,
const void *list_entry)
{
struct interface *ifp;
struct isis_circuit *circuit;
struct isis_adjacency *adj, *adj_next = NULL;
struct list *list;
struct listnode *node, *node_next;
/* Get first adjacency. */
if (list_entry == NULL) {
ifp = (struct interface *)parent_list_entry;
if (!ifp)
return NULL;
circuit = circuit_scan_by_ifp(ifp);
if (!circuit)
return NULL;
switch (circuit->circ_type) {
case CIRCUIT_T_BROADCAST:
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
level++) {
adj = listnode_head(
circuit->u.bc.adjdb[level - 1]);
if (adj)
break;
}
break;
case CIRCUIT_T_P2P:
adj = circuit->u.p2p.neighbor;
break;
default:
adj = NULL;
break;
}
return adj;
}
/* Get next adjacency. */
adj = (struct isis_adjacency *)list_entry;
circuit = adj->circuit;
switch (circuit->circ_type) {
case CIRCUIT_T_BROADCAST:
list = circuit->u.bc.adjdb[adj->level - 1];
node = listnode_lookup(list, adj);
node_next = listnextnode(node);
if (node_next)
adj_next = listgetdata(node_next);
else if (adj->level == ISIS_LEVEL1) {
/*
* Once we finish the L1 adjacencies, move to the L2
* adjacencies list.
*/
list = circuit->u.bc.adjdb[ISIS_LEVEL2 - 1];
adj_next = listnode_head(list);
}
break;
case CIRCUIT_T_P2P:
/* P2P circuits have at most one adjacency. */
default:
break;
}
return adj_next;
}
/*
* XPath:
* /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type
*/
static struct yang_data *
lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
const char *xpath, const void *list_entry)
{
const struct isis_adjacency *adj = list_entry;
return yang_data_new_enum(xpath, adj->level);
}
/*
* XPath:
* /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid
*/
static struct yang_data *
lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
const char *xpath, const void *list_entry)
{
const struct isis_adjacency *adj = list_entry;
return yang_data_new_string(xpath, sysid_print(adj->sysid));
}
/*
* XPath:
* /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id
*/
static struct yang_data *
lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
const char *xpath, const void *list_entry)
{
const struct isis_adjacency *adj = list_entry;
return yang_data_new_uint32(xpath, adj->circuit->circuit_id);
}
/*
* XPath:
* /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa
*/
static struct yang_data *
lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
const char *xpath, const void *list_entry)
{
const struct isis_adjacency *adj = list_entry;
return yang_data_new_string(xpath, snpa_print(adj->snpa));
}
/*
* XPath:
* /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer
*/
static struct yang_data *
lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem(
const char *xpath, const void *list_entry)
{
const struct isis_adjacency *adj = list_entry;
return yang_data_new_uint16(xpath, adj->hold_time);
}
/*
* XPath:
* /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority
*/
static struct yang_data *
lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem(
const char *xpath, const void *list_entry)
{
const struct isis_adjacency *adj = list_entry;
return yang_data_new_uint8(xpath, adj->prio[adj->level - 1]);
}
/*
* XPath:
* /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state
*/
static struct yang_data *
lib_interface_isis_adjacencies_adjacency_state_get_elem(const char *xpath,
const void *list_entry)
{
const struct isis_adjacency *adj = list_entry;
return yang_data_new_string(xpath, isis_yang_adj_state(adj->adj_state));
}
/*
* NOTIFICATIONS
*/
@ -2545,19 +2725,7 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj,
listnode_add(arguments, data);
snprintf(xpath_arg, sizeof(xpath_arg), "%s/state", xpath);
switch (new_state) {
case ISIS_ADJ_DOWN:
data = yang_data_new_string(xpath_arg, "down");
break;
case ISIS_ADJ_UP:
data = yang_data_new_string(xpath_arg, "up");
break;
case ISIS_ADJ_INITIALIZING:
data = yang_data_new_string(xpath_arg, "init");
break;
default:
data = yang_data_new_string(xpath_arg, "failed");
}
data = yang_data_new_string(xpath_arg, isis_yang_adj_state(new_state));
listnode_add(arguments, data);
if (new_state == ISIS_ADJ_DOWN) {
snprintf(xpath_arg, sizeof(xpath_arg), "%s/reason", xpath);
@ -3483,6 +3651,54 @@ const struct frr_yang_module_info frr_isisd_info = {
.modify = lib_interface_isis_multi_topology_ipv6_dstsrc_modify,
},
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency",
.cbs = {
.get_next = lib_interface_isis_adjacencies_adjacency_get_next,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type",
.cbs = {
.get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid",
.cbs = {
.get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id",
.cbs = {
.get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa",
.cbs = {
.get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer",
.cbs = {
.get_elem = lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority",
.cbs = {
.get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem,
}
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state",
.cbs = {
.get_elem = lib_interface_isis_adjacencies_adjacency_state_get_elem,
}
},
{
.xpath = NULL,
},

View File

@ -61,6 +61,13 @@ module frr-isisd {
"This type defines IS-IS level of an object.";
}
typedef extended-circuit-id {
type uint32;
description
"This type defines the extended circuit ID
associated with an interface.";
}
typedef network-type {
type enumeration {
enum "unknown" {
@ -95,6 +102,20 @@ module frr-isisd {
pattern, An example LSP ID is 0143.0438.AeF0.02-01";
}
typedef snpa {
type string {
length "0 .. 20";
}
description
"This type defines the Subnetwork Point
of Attachment (SNPA) format.
The SNPA should be encoded according to the rules
specified for the particular type of subnetwork
being used. As an example, for an ethernet subnetwork,
the SNPA is encoded as a MAC address like
'00aa.bbcc.ddee'.";
}
typedef system-id {
type string {
pattern "[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}\\.[0-9A-Fa-f]{4}";
@ -544,6 +565,70 @@ module frr-isisd {
}
}
grouping adjacency-state {
container adjacencies {
config false;
list adjacency {
leaf neighbor-sys-type {
type level;
description
"Level capability of neighboring system";
}
leaf neighbor-sysid {
type system-id;
description
"The system-id of the neighbor";
}
leaf neighbor-extended-circuit-id {
type extended-circuit-id;
description
"Circuit ID of the neighbor";
}
leaf neighbor-snpa {
type snpa;
description
"SNPA of the neighbor";
}
leaf hold-timer {
type uint16;
units seconds;
description
"The holding time in seconds for this
adjacency. This value is based on
received hello PDUs and the elapsed
time since receipt.";
}
leaf neighbor-priority {
type uint8 {
range "0 .. 127";
}
description
"Priority of the neighboring IS for becoming
the DIS.";
}
leaf state {
type adj-state-type;
description
"This leaf describes the state of the interface.";
}
description
"List of operational adjacencies.";
}
description
"This container lists the adjacencies of
the local node.";
}
description
"Adjacency state";
}
grouping interface-state {
description
"IS-IS interface operational state.";
uses adjacency-state;
}
grouping notification-instance-hdr {
description
"Instance specific IS-IS notification data grouping";
@ -582,7 +667,7 @@ module frr-isisd {
}
leaf extended-circuit-id {
type uint32;
type extended-circuit-id;
description
"Eextended circuit-id of the interface.";
}
@ -1003,6 +1088,7 @@ module frr-isisd {
description
"IS-IS interface parameters.";
uses interface-config;
uses interface-state;
}
}