summaryrefslogtreecommitdiff
path: root/isisd/isis_spf.c
diff options
context:
space:
mode:
Diffstat (limited to 'isisd/isis_spf.c')
-rw-r--r--isisd/isis_spf.c1103
1 files changed, 744 insertions, 359 deletions
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index ebce86bed9..dd0a6ec824 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -29,6 +29,7 @@
#include "vty.h"
#include "log.h"
#include "command.h"
+#include "termtable.h"
#include "memory.h"
#include "prefix.h"
#include "if.h"
@@ -56,6 +57,13 @@
#include "isis_spf_private.h"
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ, "ISIS SPF Adjacency");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX_ADJ, "ISIS SPF Vertex Adjacency");
+
+static void spf_adj_list_parse_lsp(struct isis_spftree *spftree,
+ struct list *adj_list, struct isis_lsp *lsp,
+ const uint8_t *pseudo_nodeid,
+ uint32_t pseudo_metric);
/*
* supports the given af ?
@@ -80,22 +88,29 @@ struct isis_spf_run {
static void remove_excess_adjs(struct list *adjs)
{
struct listnode *node, *excess = NULL;
- struct isis_adjacency *adj, *candidate = NULL;
+ struct isis_vertex_adj *vadj, *candidate = NULL;
int comp;
- for (ALL_LIST_ELEMENTS_RO(adjs, node, adj)) {
+ for (ALL_LIST_ELEMENTS_RO(adjs, node, vadj)) {
+ struct isis_adjacency *adj, *candidate_adj;
+
+ adj = vadj->sadj->adj;
+ assert(adj);
+
if (excess == NULL)
excess = node;
candidate = listgetdata(excess);
+ candidate_adj = candidate->sadj->adj;
- if (candidate->sys_type < adj->sys_type) {
+ if (candidate_adj->sys_type < adj->sys_type) {
excess = node;
continue;
}
- if (candidate->sys_type > adj->sys_type)
+ if (candidate_adj->sys_type > adj->sys_type)
continue;
- comp = memcmp(candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN);
+ comp = memcmp(candidate_adj->sysid, adj->sysid,
+ ISIS_SYS_ID_LEN);
if (comp > 0) {
excess = node;
continue;
@@ -103,15 +118,15 @@ static void remove_excess_adjs(struct list *adjs)
if (comp < 0)
continue;
- if (candidate->circuit->idx > adj->circuit->idx) {
+ if (candidate_adj->circuit->idx > adj->circuit->idx) {
excess = node;
continue;
}
- if (candidate->circuit->idx < adj->circuit->idx)
+ if (candidate_adj->circuit->idx < adj->circuit->idx)
continue;
- comp = memcmp(candidate->snpa, adj->snpa, ETH_ALEN);
+ comp = memcmp(candidate_adj->snpa, adj->snpa, ETH_ALEN);
if (comp > 0) {
excess = node;
continue;
@@ -155,7 +170,9 @@ static const char *vtype2string(enum vertextype vtype)
const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
{
if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
- return print_sys_hostname(vertex->N.id);
+ const char *hostname = print_sys_hostname(vertex->N.id);
+ strlcpy(buff, hostname, size);
+ return buff;
}
if (VTYPE_IP(vertex->type)) {
@@ -168,6 +185,13 @@ const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
return "UNKNOWN";
}
+static void isis_vertex_adj_free(void *arg)
+{
+ struct isis_vertex_adj *vadj = arg;
+
+ XFREE(MTYPE_ISIS_VERTEX_ADJ, vadj);
+}
+
static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree,
void *id,
enum vertextype vtype)
@@ -179,9 +203,10 @@ static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree,
isis_vertex_id_init(vertex, id, vtype);
vertex->Adj_N = list_new();
+ vertex->Adj_N->del = isis_vertex_adj_free;
vertex->parents = list_new();
- if (spftree->hopcount_metric) {
+ if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)) {
vertex->firsthops = hash_create(isis_vertex_queue_hash_key,
isis_vertex_queue_hash_cmp,
NULL);
@@ -190,21 +215,69 @@ static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree,
return vertex;
}
+static struct isis_vertex_adj *isis_vertex_adj_add(struct isis_vertex *vertex,
+ struct isis_spf_adj *sadj)
+{
+ struct isis_vertex_adj *vadj;
+
+ vadj = XCALLOC(MTYPE_ISIS_VERTEX_ADJ, sizeof(*vadj));
+ vadj->sadj = sadj;
+ listnode_add(vertex->Adj_N, vadj);
+
+ return vadj;
+}
+
static void isis_vertex_adj_del(struct isis_vertex *vertex,
struct isis_adjacency *adj)
{
+ struct isis_vertex_adj *vadj;
struct listnode *node, *nextnode;
+
if (!vertex)
return;
- for (node = listhead(vertex->Adj_N); node; node = nextnode) {
- nextnode = listnextnode(node);
- if (listgetdata(node) == adj)
- list_delete_node(vertex->Adj_N, node);
+
+ for (ALL_LIST_ELEMENTS(vertex->Adj_N, node, nextnode, vadj)) {
+ if (vadj->sadj->adj == adj) {
+ listnode_delete(vertex->Adj_N, vadj);
+ isis_vertex_adj_free(vadj);
+ }
}
return;
}
-struct isis_spftree *isis_spftree_new(struct isis_area *area)
+bool isis_vertex_adj_exists(const struct isis_spftree *spftree,
+ const struct isis_vertex *vertex,
+ const struct isis_spf_adj *sadj)
+{
+ struct isis_vertex_adj *tmp;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(vertex->Adj_N, node, tmp)) {
+ if (CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)) {
+ if (memcmp(sadj->id, tmp->sadj->id, sizeof(sadj->id))
+ == 0)
+ return true;
+ } else {
+ if (sadj->adj == tmp->sadj->adj)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void isis_spf_adj_free(void *arg)
+{
+ struct isis_spf_adj *sadj = arg;
+
+ XFREE(MTYPE_ISIS_SPF_ADJ, sadj);
+}
+
+struct isis_spftree *isis_spftree_new(struct isis_area *area,
+ struct lspdb_head *lspdb,
+ const uint8_t *sysid, int level,
+ enum spf_tree_id tree_id,
+ enum spf_type type, uint8_t flags)
{
struct isis_spftree *tree;
@@ -214,15 +287,26 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area)
isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
tree->route_table = srcdest_table_init();
tree->area = area;
+ tree->lspdb = lspdb;
+ tree->sadj_list = list_new();
+ tree->sadj_list->del = isis_spf_adj_free;
tree->last_run_timestamp = 0;
tree->last_run_monotime = 0;
tree->last_run_duration = 0;
tree->runcount = 0;
+ tree->type = type;
+ memcpy(tree->sysid, sysid, ISIS_SYS_ID_LEN);
+ tree->level = level;
+ tree->tree_id = tree_id;
+ tree->family = (tree->tree_id == SPFTREE_IPV4) ? AF_INET : AF_INET6;
+ tree->flags = flags;
+
return tree;
}
void isis_spftree_del(struct isis_spftree *spftree)
{
+ list_delete(&spftree->sadj_list);
isis_vertex_queue_free(&spftree->tents);
isis_vertex_queue_free(&spftree->paths);
route_table_finish(spftree->route_table);
@@ -254,7 +338,10 @@ void spftree_area_init(struct isis_area *area)
if (area->spftree[tree][level - 1])
continue;
- area->spftree[tree][level - 1] = isis_spftree_new(area);
+ area->spftree[tree][level - 1] =
+ isis_spftree_new(area, &area->lspdb[level - 1],
+ area->isis->sysid, level, tree,
+ SPF_TYPE_FORWARD, 0);
}
}
}
@@ -273,8 +360,14 @@ void spftree_area_del(struct isis_area *area)
}
}
-void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj)
+static int spf_adj_state_change(struct isis_adjacency *adj)
{
+ struct isis_area *area = adj->circuit->area;
+
+ if (adj->adj_state == ISIS_ADJ_UP)
+ return 0;
+
+ /* Remove adjacency from all SPF trees. */
for (int tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
if (!(area->is_type & level))
@@ -288,13 +381,15 @@ void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj)
if (fabricd_spftree(area) != NULL)
isis_spftree_adj_del(fabricd_spftree(area), adj);
+
+ return 0;
}
/*
* Find the system LSP: returns the LSP in our LSP database
* associated with the given system ID.
*/
-static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level,
+static struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb,
uint8_t *sysid)
{
struct isis_lsp *lsp;
@@ -303,7 +398,7 @@ static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level,
memcpy(lspid, sysid, ISIS_SYS_ID_LEN);
LSP_PSEUDO_ID(lspid) = 0;
LSP_FRAGMENT(lspid) = 0;
- lsp = lsp_search(&area->lspdb[level - 1], lspid);
+ lsp = lsp_search(lspdb, lspid);
if (lsp && lsp->hdr.rem_lifetime != 0)
return lsp;
return NULL;
@@ -312,28 +407,21 @@ static struct isis_lsp *isis_root_system_lsp(struct isis_area *area, int level,
/*
* Add this IS to the root of SPT
*/
-static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
- uint8_t *sysid)
+static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree)
{
struct isis_vertex *vertex;
- struct isis_lsp *lsp;
#ifdef EXTREME_DEBUG
char buff[VID2STR_BUFFER];
#endif /* EXTREME_DEBUG */
- lsp = isis_root_system_lsp(spftree->area, spftree->level, sysid);
- if (lsp == NULL)
- zlog_warn("ISIS-Spf: could not find own l%d LSP!",
- spftree->level);
-
- vertex = isis_vertex_new(spftree, sysid,
+ vertex = isis_vertex_new(spftree, spftree->sysid,
spftree->area->oldmetric
? VTYPE_NONPSEUDO_IS
: VTYPE_NONPSEUDO_TE_IS);
isis_vertex_queue_append(&spftree->paths, vertex);
#ifdef EXTREME_DEBUG
- zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
+ zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
vtype2string(vertex->type),
vid2string(vertex, buff, sizeof(buff)), vertex->depth,
vertex->d_N);
@@ -368,12 +456,11 @@ static void vertex_update_firsthops(struct isis_vertex *vertex,
static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
enum vertextype vtype, void *id,
uint32_t cost, int depth,
- struct isis_adjacency *adj,
+ struct isis_spf_adj *sadj,
struct isis_vertex *parent)
{
struct isis_vertex *vertex;
struct listnode *node;
- struct isis_adjacency *parent_adj;
char buff[VID2STR_BUFFER];
vertex = isis_find_vertex(&spftree->paths, id, vtype);
@@ -401,14 +488,16 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
listnode_add(vertex->parents, parent);
}
- if (spftree->hopcount_metric)
+ if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC))
vertex_update_firsthops(vertex, parent);
if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) {
- for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_adj))
- listnode_add(vertex->Adj_N, parent_adj);
- } else if (adj) {
- listnode_add(vertex->Adj_N, adj);
+ struct isis_vertex_adj *parent_vadj;
+
+ for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node, parent_vadj))
+ isis_vertex_adj_add(vertex, parent_vadj->sadj);
+ } else if (sadj) {
+ isis_vertex_adj_add(vertex, sadj);
}
#ifdef EXTREME_DEBUG
@@ -425,7 +514,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
static void isis_spf_add_local(struct isis_spftree *spftree,
enum vertextype vtype, void *id,
- struct isis_adjacency *adj, uint32_t cost,
+ struct isis_spf_adj *sadj, uint32_t cost,
struct isis_vertex *parent)
{
struct isis_vertex *vertex;
@@ -435,10 +524,12 @@ static void isis_spf_add_local(struct isis_spftree *spftree,
if (vertex) {
/* C.2.5 c) */
if (vertex->d_N == cost) {
- if (adj)
- listnode_add(vertex->Adj_N, adj);
+ if (sadj)
+ isis_vertex_adj_add(vertex, sadj);
/* d) */
- if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
+ if (!CHECK_FLAG(spftree->flags,
+ F_SPFTREE_NO_ADJACENCIES)
+ && listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
remove_excess_adjs(vertex->Adj_N);
if (parent && (listnode_lookup(vertex->parents, parent)
== NULL))
@@ -454,7 +545,7 @@ static void isis_spf_add_local(struct isis_spftree *spftree,
}
}
- isis_spf_add2tent(spftree, vtype, id, cost, 1, adj, parent);
+ isis_spf_add2tent(spftree, vtype, id, cost, 1, sadj, parent);
return;
}
@@ -469,7 +560,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
assert(spftree && parent);
- if (spftree->hopcount_metric
+ if (CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)
&& !VTYPE_IS(vtype))
return;
@@ -519,16 +610,20 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
#endif /* EXTREME_DEBUG */
if (vertex->d_N == dist) {
struct listnode *node;
- struct isis_adjacency *parent_adj;
+ struct isis_vertex_adj *parent_vadj;
for (ALL_LIST_ELEMENTS_RO(parent->Adj_N, node,
- parent_adj))
- if (listnode_lookup(vertex->Adj_N, parent_adj)
- == NULL)
- listnode_add(vertex->Adj_N, parent_adj);
- if (spftree->hopcount_metric)
+ parent_vadj))
+ if (!isis_vertex_adj_exists(spftree, vertex,
+ parent_vadj->sadj))
+ isis_vertex_adj_add(vertex,
+ parent_vadj->sadj);
+ if (CHECK_FLAG(spftree->flags,
+ F_SPFTREE_HOPCOUNT_METRIC))
vertex_update_firsthops(vertex, parent);
/* 2) */
- if (listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
+ if (!CHECK_FLAG(spftree->flags,
+ F_SPFTREE_NO_ADJACENCIES)
+ && listcount(vertex->Adj_N) > ISIS_MAX_PATH_SPLITS)
remove_excess_adjs(vertex->Adj_N);
if (listnode_lookup(vertex->parents, parent) == NULL)
listnode_add(vertex->parents, parent);
@@ -611,7 +706,9 @@ lspfragloop:
/* C.2.6 a) */
/* Two way connectivity */
- if (!memcmp(r->id, root_sysid, ISIS_SYS_ID_LEN))
+ if (!LSP_PSEUDO_ID(r->id)
+ && !memcmp(r->id, root_sysid,
+ ISIS_SYS_ID_LEN))
continue;
if (!pseudo_lsp
&& !memcmp(r->id, null_sysid,
@@ -640,12 +737,19 @@ lspfragloop:
te_neighs->head
: NULL;
er; er = er->next) {
- if (!memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN))
+ /* C.2.6 a) */
+ /* Two way connectivity */
+ if (!LSP_PSEUDO_ID(er->id)
+ && !memcmp(er->id, root_sysid, ISIS_SYS_ID_LEN))
continue;
if (!pseudo_lsp
&& !memcmp(er->id, null_sysid, ISIS_SYS_ID_LEN))
continue;
- dist = cost + (spftree->hopcount_metric ? 1 : er->metric);
+ dist = cost
+ + (CHECK_FLAG(spftree->flags,
+ F_SPFTREE_HOPCOUNT_METRIC)
+ ? 1
+ : er->metric);
process_N(spftree,
LSP_PSEUDO_ID(er->id) ? VTYPE_PSEUDO_TE_IS
: VTYPE_NONPSEUDO_TE_IS,
@@ -759,236 +863,311 @@ lspfragloop:
return ISIS_OK;
}
-static int isis_spf_preload_tent(struct isis_spftree *spftree,
- uint8_t *root_sysid,
- struct isis_vertex *parent)
+static struct isis_adjacency *adj_find(struct list *adj_list, const uint8_t *id,
+ int level, uint16_t mtid, int family)
{
- struct isis_circuit *circuit;
- struct listnode *cnode, *anode, *ipnode;
struct isis_adjacency *adj;
- struct isis_lsp *lsp;
- struct list *adj_list;
- struct list *adjdb;
- struct prefix_ipv4 *ipv4;
- struct prefix_pair ip_info;
- int retval = ISIS_OK;
- uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
- static uint8_t null_lsp_id[ISIS_SYS_ID_LEN + 2];
- struct prefix_ipv6 *ipv6;
- struct isis_circuit_mt_setting *circuit_mt;
-
- for (ALL_LIST_ELEMENTS_RO(spftree->area->circuit_list, cnode,
- circuit)) {
- circuit_mt = circuit_lookup_mt_setting(circuit, spftree->mtid);
- if (circuit_mt && !circuit_mt->enabled)
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(adj_list, node, adj)) {
+ if (!(adj->level & level))
continue;
- if (circuit->state != C_STATE_UP)
+ if (memcmp(adj->sysid, id, ISIS_SYS_ID_LEN) != 0)
continue;
- if (!(circuit->is_type & spftree->level))
+ if (adj->adj_state != ISIS_ADJ_UP)
continue;
- if (spftree->family == AF_INET && !circuit->ip_router)
+ if (!adj_has_mt(adj, mtid))
continue;
- if (spftree->family == AF_INET6 && !circuit->ipv6_router)
+ if (mtid == ISIS_MT_IPV4_UNICAST
+ && !speaks(adj->nlpids.nlpids, adj->nlpids.count, family))
continue;
- /*
- * Add IP(v6) addresses of this circuit
- */
- if (spftree->family == AF_INET && !spftree->hopcount_metric) {
- memset(&ip_info, 0, sizeof(ip_info));
- ip_info.dest.family = AF_INET;
- for (ALL_LIST_ELEMENTS_RO(circuit->ip_addrs, ipnode,
- ipv4)) {
- ip_info.dest.u.prefix4 = ipv4->prefix;
- ip_info.dest.prefixlen = ipv4->prefixlen;
- apply_mask(&ip_info.dest);
- isis_spf_add_local(spftree,
- VTYPE_IPREACH_INTERNAL,
- &ip_info, NULL, 0, parent);
- }
+ return adj;
+ }
+
+ return NULL;
+}
+
+struct spf_preload_tent_ip_reach_args {
+ struct isis_spftree *spftree;
+ struct isis_vertex *parent;
+};
+
+static int isis_spf_preload_tent_ip_reach_cb(const struct prefix *prefix,
+ uint32_t metric, bool external,
+ struct isis_subtlvs *subtlvs,
+ void *arg)
+{
+ struct spf_preload_tent_ip_reach_args *args = arg;
+ struct isis_spftree *spftree = args->spftree;
+ struct isis_vertex *parent = args->parent;
+ struct prefix_pair ip_info;
+ enum vertextype vtype;
+
+ if (external)
+ return LSP_ITER_CONTINUE;
+
+ assert(spftree->family == prefix->family);
+ memset(&ip_info, 0, sizeof(ip_info));
+ prefix_copy(&ip_info.dest, prefix);
+ apply_mask(&ip_info.dest);
+
+ if (prefix->family == AF_INET)
+ vtype = VTYPE_IPREACH_INTERNAL;
+ else
+ vtype = VTYPE_IP6REACH_INTERNAL;
+
+ isis_spf_add_local(spftree, vtype, &ip_info, NULL, 0, parent);
+
+ return LSP_ITER_CONTINUE;
+}
+
+static void isis_spf_preload_tent(struct isis_spftree *spftree,
+ uint8_t *root_sysid,
+ struct isis_lsp *root_lsp,
+ struct isis_vertex *parent)
+{
+ struct spf_preload_tent_ip_reach_args ip_reach_args;
+ struct isis_spf_adj *sadj;
+ struct listnode *node;
+
+ if (!CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)) {
+ ip_reach_args.spftree = spftree;
+ ip_reach_args.parent = parent;
+ isis_lsp_iterate_ip_reach(
+ root_lsp, spftree->family, spftree->mtid,
+ isis_spf_preload_tent_ip_reach_cb, &ip_reach_args);
+ }
+
+ /* Iterate over adjacencies. */
+ for (ALL_LIST_ELEMENTS_RO(spftree->sadj_list, node, sadj)) {
+ uint32_t metric;
+
+ metric = CHECK_FLAG(spftree->flags, F_SPFTREE_HOPCOUNT_METRIC)
+ ? 1
+ : sadj->metric;
+ if (!LSP_PSEUDO_ID(sadj->id)) {
+ isis_spf_add_local(spftree,
+ CHECK_FLAG(sadj->flags,
+ F_ISIS_SPF_ADJ_OLDMETRIC)
+ ? VTYPE_NONPSEUDO_IS
+ : VTYPE_NONPSEUDO_TE_IS,
+ sadj->id, sadj, metric, parent);
+ } else if (sadj->lan.lsp_pseudo) {
+ isis_spf_process_lsp(spftree, sadj->lan.lsp_pseudo,
+ metric, 0, spftree->sysid, parent);
}
- if (spftree->family == AF_INET6 && !spftree->hopcount_metric) {
- memset(&ip_info, 0, sizeof(ip_info));
- ip_info.dest.family = AF_INET6;
- for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
- ipnode, ipv6)) {
- ip_info.dest.u.prefix6 = ipv6->prefix;
- ip_info.dest.prefixlen = ipv6->prefixlen;
- apply_mask(&ip_info.dest);
- isis_spf_add_local(spftree,
- VTYPE_IP6REACH_INTERNAL,
- &ip_info, NULL, 0, parent);
- }
+ }
+}
+
+struct spf_adj_find_reverse_metric_args {
+ const uint8_t *id_self;
+ uint32_t reverse_metric;
+};
+
+static int spf_adj_find_reverse_metric_cb(const uint8_t *id, uint32_t metric,
+ bool oldmetric,
+ struct isis_ext_subtlvs *subtlvs,
+ void *arg)
+{
+ struct spf_adj_find_reverse_metric_args *args = arg;
+
+ if (memcmp(id, args->id_self, ISIS_SYS_ID_LEN))
+ return LSP_ITER_CONTINUE;
+
+ args->reverse_metric = metric;
+
+ return LSP_ITER_STOP;
+}
+
+/*
+ * Change all SPF adjacencies to use the link cost in the direction from the
+ * next hop back towards root in place of the link cost in the direction away
+ * from root towards the next hop.
+ */
+static void spf_adj_get_reverse_metrics(struct isis_spftree *spftree)
+{
+ struct isis_spf_adj *sadj;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS(spftree->sadj_list, node, nnode, sadj)) {
+ uint8_t lspid[ISIS_SYS_ID_LEN + 2];
+ struct isis_lsp *lsp_adj;
+ const uint8_t *id_self;
+ struct spf_adj_find_reverse_metric_args args;
+
+ /* Skip pseudonodes. */
+ if (LSP_PSEUDO_ID(sadj->id))
+ continue;
+
+ /* Find LSP of the corresponding adjacency. */
+ memcpy(lspid, sadj->id, ISIS_SYS_ID_LEN);
+ LSP_PSEUDO_ID(lspid) = 0;
+ LSP_FRAGMENT(lspid) = 0;
+ lsp_adj = lsp_search(spftree->lspdb, lspid);
+ if (lsp_adj == NULL || lsp_adj->hdr.rem_lifetime == 0) {
+ /* Delete one-way adjacency. */
+ listnode_delete(spftree->sadj_list, sadj);
+ continue;
}
- if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
- /*
- * Add the adjacencies
- */
- adj_list = list_new();
- adjdb = circuit->u.bc.adjdb[spftree->level - 1];
- isis_adj_build_up_list(adjdb, adj_list);
- if (listcount(adj_list) == 0) {
- list_delete(&adj_list);
- if (IS_DEBUG_SPF_EVENTS)
- zlog_debug(
- "ISIS-Spf: no L%d adjacencies on circuit %s",
- spftree->level,
- circuit->interface->name);
- continue;
- }
- for (ALL_LIST_ELEMENTS_RO(adj_list, anode, adj)) {
- if (!adj_has_mt(adj, spftree->mtid))
- continue;
- if (spftree->mtid == ISIS_MT_IPV4_UNICAST
- && !speaks(adj->nlpids.nlpids,
- adj->nlpids.count,
- spftree->family))
- continue;
- switch (adj->sys_type) {
- case ISIS_SYSTYPE_ES:
- memcpy(lsp_id, adj->sysid,
- ISIS_SYS_ID_LEN);
- LSP_PSEUDO_ID(lsp_id) = 0;
- isis_spf_add_local(
- spftree, VTYPE_ES, lsp_id, adj,
- spftree->hopcount_metric ? 1 :
- circuit->te_metric
- [spftree->level - 1],
- parent);
- break;
- case ISIS_SYSTYPE_IS:
- case ISIS_SYSTYPE_L1_IS:
- case ISIS_SYSTYPE_L2_IS:
- memcpy(lsp_id, adj->sysid,
- ISIS_SYS_ID_LEN);
- LSP_PSEUDO_ID(lsp_id) = 0;
- LSP_FRAGMENT(lsp_id) = 0;
- isis_spf_add_local(
- spftree,
- spftree->area->oldmetric
- ? VTYPE_NONPSEUDO_IS
- : VTYPE_NONPSEUDO_TE_IS,
- lsp_id, adj,
- spftree->hopcount_metric ? 1 :
- circuit->te_metric
- [spftree->level - 1],
- parent);
- lsp = lsp_search(
- &spftree->area->lspdb[spftree->level- 1],
- lsp_id);
- if (lsp == NULL
- || lsp->hdr.rem_lifetime == 0)
- zlog_warn(
- "ISIS-Spf: No LSP %s found for IS adjacency L%d on %s (ID %u)",
- rawlspid_print(lsp_id),
- spftree->level,
- circuit->interface->name,
- circuit->circuit_id);
- break;
- case ISIS_SYSTYPE_UNKNOWN:
- default:
- zlog_warn(
- "isis_spf_preload_tent unknown adj type");
- }
- }
- list_delete(&adj_list);
- /*
- * Add the pseudonode
- */
- if (spftree->level == 1)
- memcpy(lsp_id, circuit->u.bc.l1_desig_is,
- ISIS_SYS_ID_LEN + 1);
- else
- memcpy(lsp_id, circuit->u.bc.l2_desig_is,
- ISIS_SYS_ID_LEN + 1);
- /* can happen during DR reboot */
- if (memcmp(lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1)
- == 0) {
- if (IS_DEBUG_SPF_EVENTS)
- zlog_debug(
- "ISIS-Spf: No L%d DR on %s (ID %d)",
- spftree->level,
- circuit->interface->name,
- circuit->circuit_id);
- continue;
- }
- adj = isis_adj_lookup(lsp_id, adjdb);
- /* if no adj, we are the dis or error */
- if (!adj && !circuit->u.bc.is_dr[spftree->level - 1]) {
- zlog_warn(
- "ISIS-Spf: No adjacency found from root to L%d DR %s on %s (ID %d)",
- spftree->level, rawlspid_print(lsp_id),
- circuit->interface->name,
- circuit->circuit_id);
- continue;
- }
- lsp = lsp_search(
- &spftree->area->lspdb[spftree->level - 1],
- lsp_id);
- if (lsp == NULL || lsp->hdr.rem_lifetime == 0) {
- zlog_warn(
- "ISIS-Spf: No lsp (%p) found from root to L%d DR %s on %s (ID %d)",
- (void *)lsp, spftree->level,
- rawlspid_print(lsp_id),
- circuit->interface->name,
- circuit->circuit_id);
- continue;
+
+ /* Find root node in the LSP of the adjacent router. */
+ if (CHECK_FLAG(sadj->flags, F_ISIS_SPF_ADJ_BROADCAST))
+ id_self = sadj->lan.desig_is_id;
+ else
+ id_self = spftree->sysid;
+ args.id_self = id_self;
+ args.reverse_metric = UINT32_MAX;
+ isis_lsp_iterate_is_reach(lsp_adj, spftree->mtid,
+ spf_adj_find_reverse_metric_cb,
+ &args);
+ if (args.reverse_metric == UINT32_MAX) {
+ /* Delete one-way adjacency. */
+ listnode_delete(spftree->sadj_list, sadj);
+ continue;
+ }
+ sadj->metric = args.reverse_metric;
+ }
+}
+
+static void spf_adj_list_parse_tlv(struct isis_spftree *spftree,
+ struct list *adj_list, const uint8_t *id,
+ const uint8_t *desig_is_id,
+ uint32_t pseudo_metric, uint32_t metric,
+ bool oldmetric,
+ struct isis_ext_subtlvs *subtlvs)
+{
+ struct isis_spf_adj *sadj;
+ uint8_t flags = 0;
+
+ /* Skip self in the pseudonode. */
+ if (desig_is_id && !memcmp(id, spftree->sysid, ISIS_SYS_ID_LEN))
+ return;
+
+ sadj = XCALLOC(MTYPE_ISIS_SPF_ADJ, sizeof(*sadj));
+ memcpy(sadj->id, id, sizeof(sadj->id));
+ if (desig_is_id) {
+ memcpy(sadj->lan.desig_is_id, desig_is_id,
+ sizeof(sadj->lan.desig_is_id));
+ SET_FLAG(flags, F_ISIS_SPF_ADJ_BROADCAST);
+ sadj->metric = pseudo_metric;
+ } else
+ sadj->metric = metric;
+ if (oldmetric)
+ SET_FLAG(flags, F_ISIS_SPF_ADJ_OLDMETRIC);
+ sadj->subtlvs = subtlvs;
+ sadj->flags = flags;
+
+ /* Set real adjacency. */
+ if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES)
+ && !LSP_PSEUDO_ID(id)) {
+ struct isis_adjacency *adj;
+
+ adj = adj_find(adj_list, id, spftree->level, spftree->mtid,
+ spftree->family);
+ if (!adj) {
+ XFREE(MTYPE_ISIS_SPF_ADJ, sadj);
+ return;
+ }
+
+ listnode_delete(adj_list, adj);
+ sadj->adj = adj;
+ }
+
+ /* Add adjacency to the list. */
+ listnode_add(spftree->sadj_list, sadj);
+
+ /* Parse pseudonode LSP too. */
+ if (LSP_PSEUDO_ID(id)) {
+ uint8_t lspid[ISIS_SYS_ID_LEN + 2];
+ struct isis_lsp *lsp_pseudo;
+
+ memcpy(lspid, id, ISIS_SYS_ID_LEN + 1);
+ LSP_FRAGMENT(lspid) = 0;
+ lsp_pseudo = lsp_search(spftree->lspdb, lspid);
+ if (lsp_pseudo == NULL || lsp_pseudo->hdr.rem_lifetime == 0) {
+ zlog_warn(
+ "ISIS-Spf: No LSP found from root to L%d DR %s",
+ spftree->level, rawlspid_print(id));
+ return;
+ }
+
+ sadj->lan.lsp_pseudo = lsp_pseudo;
+ spf_adj_list_parse_lsp(spftree, adj_list, lsp_pseudo, id,
+ metric);
+ }
+}
+
+static void spf_adj_list_parse_lsp(struct isis_spftree *spftree,
+ struct list *adj_list, struct isis_lsp *lsp,
+ const uint8_t *pseudo_nodeid,
+ uint32_t pseudo_metric)
+{
+ bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id);
+ struct isis_lsp *frag;
+ struct listnode *node;
+ struct isis_item *head;
+ struct isis_item_list *te_neighs;
+
+ if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0)
+ return;
+
+ /* Parse main LSP. */
+ if (lsp->tlvs) {
+ if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST) {
+ head = lsp->tlvs->oldstyle_reach.head;
+ for (struct isis_oldstyle_reach *reach =
+ (struct isis_oldstyle_reach *)head;
+ reach; reach = reach->next) {
+ spf_adj_list_parse_tlv(
+ spftree, adj_list, reach->id,
+ pseudo_nodeid, pseudo_metric,
+ reach->metric, true, NULL);
}
- isis_spf_process_lsp(spftree, lsp,
- spftree->hopcount_metric ?
- 1 : circuit->te_metric[spftree->level - 1],
- 0, root_sysid, parent);
- } else if (circuit->circ_type == CIRCUIT_T_P2P) {
- adj = circuit->u.p2p.neighbor;
- if (!adj || adj->adj_state != ISIS_ADJ_UP)
- continue;
- if (!adj_has_mt(adj, spftree->mtid))
- continue;
- switch (adj->sys_type) {
- case ISIS_SYSTYPE_ES:
- memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
- LSP_PSEUDO_ID(lsp_id) = 0;
- isis_spf_add_local(
- spftree, VTYPE_ES, lsp_id, adj,
- spftree->hopcount_metric ? 1 :
- circuit->te_metric[spftree->level - 1],
- parent);
- break;
- case ISIS_SYSTYPE_IS:
- case ISIS_SYSTYPE_L1_IS:
- case ISIS_SYSTYPE_L2_IS:
- memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
- LSP_PSEUDO_ID(lsp_id) = 0;
- LSP_FRAGMENT(lsp_id) = 0;
- if (spftree->mtid != ISIS_MT_IPV4_UNICAST
- || speaks(adj->nlpids.nlpids,
- adj->nlpids.count,
- spftree->family))
- isis_spf_add_local(
- spftree,
- spftree->area->oldmetric
- ? VTYPE_NONPSEUDO_IS
- : VTYPE_NONPSEUDO_TE_IS,
- lsp_id, adj,
- spftree->hopcount_metric ? 1 :
- circuit->te_metric
- [spftree->level - 1],
- parent);
- break;
- case ISIS_SYSTYPE_UNKNOWN:
- default:
- zlog_warn(
- "isis_spf_preload_tent unknown adj type");
- break;
+ }
+
+ if (pseudo_lsp || spftree->mtid == ISIS_MT_IPV4_UNICAST)
+ te_neighs = &lsp->tlvs->extended_reach;
+ else
+ te_neighs = isis_get_mt_items(&lsp->tlvs->mt_reach,
+ spftree->mtid);
+ if (te_neighs) {
+ head = te_neighs->head;
+ for (struct isis_extended_reach *reach =
+ (struct isis_extended_reach *)head;
+ reach; reach = reach->next) {
+ spf_adj_list_parse_tlv(
+ spftree, adj_list, reach->id,
+ pseudo_nodeid, pseudo_metric,
+ reach->metric, false, reach->subtlvs);
}
- } else if (circuit->circ_type == CIRCUIT_T_LOOPBACK) {
- continue;
- } else {
- zlog_warn("isis_spf_preload_tent unsupported media");
- retval = ISIS_WARNING;
}
}
- return retval;
+ /* Parse LSP fragments. */
+ for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) {
+ if (!frag->tlvs)
+ continue;
+
+ spf_adj_list_parse_lsp(spftree, adj_list, frag, pseudo_nodeid,
+ pseudo_metric);
+ }
+}
+
+static void isis_spf_build_adj_list(struct isis_spftree *spftree,
+ struct isis_lsp *lsp)
+{
+ struct list *adj_list = NULL;
+
+ if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
+ adj_list = list_dup(spftree->area->adjacency_list);
+
+ spf_adj_list_parse_lsp(spftree, adj_list, lsp, NULL, 0);
+
+ if (!CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
+ list_delete(&adj_list);
+
+ if (spftree->type == SPF_TYPE_REVERSE)
+ spf_adj_get_reverse_metrics(spftree);
}
/*
@@ -1011,10 +1190,10 @@ static void add_to_paths(struct isis_spftree *spftree,
vertex->d_N);
#endif /* EXTREME_DEBUG */
- if (VTYPE_IP(vertex->type)) {
+ if (VTYPE_IP(vertex->type)
+ && !CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ROUTES)) {
if (listcount(vertex->Adj_N) > 0)
- isis_route_create(&vertex->N.ip.dest,
- &vertex->N.ip.src,
+ isis_route_create(&vertex->N.ip.dest, &vertex->N.ip.src,
vertex->d_N, vertex->depth,
vertex->Adj_N, spftree->area,
spftree->route_table);
@@ -1028,18 +1207,14 @@ static void add_to_paths(struct isis_spftree *spftree,
return;
}
-static void init_spt(struct isis_spftree *spftree, int mtid, int level,
- int family, enum spf_tree_id tree_id,
- bool hopcount_metric)
+static void init_spt(struct isis_spftree *spftree, int mtid)
{
+ /* Clear data from previous run. */
+ list_delete_all_node(spftree->sadj_list);
isis_vertex_queue_clear(&spftree->tents);
isis_vertex_queue_clear(&spftree->paths);
spftree->mtid = mtid;
- spftree->level = level;
- spftree->family = family;
- spftree->tree_id = tree_id;
- spftree->hopcount_metric = hopcount_metric;
}
static void isis_spf_loop(struct isis_spftree *spftree,
@@ -1080,19 +1255,31 @@ struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
struct isis_spftree *spftree)
{
if (!spftree)
- spftree = isis_spftree_new(area);
-
- init_spt(spftree, ISIS_MT_IPV4_UNICAST, ISIS_LEVEL2,
- AF_INET, SPFTREE_IPV4, true);
+ spftree = isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1],
+ sysid, ISIS_LEVEL2, SPFTREE_IPV4,
+ SPF_TYPE_FORWARD,
+ F_SPFTREE_HOPCOUNT_METRIC);
+ init_spt(spftree, ISIS_MT_IPV4_UNICAST);
if (!memcmp(sysid, area->isis->sysid, ISIS_SYS_ID_LEN)) {
- /* If we are running locally, initialize with information from adjacencies */
- struct isis_vertex *root = isis_spf_add_root(spftree, sysid);
- isis_spf_preload_tent(spftree, sysid, root);
+ struct isis_lsp *root_lsp;
+ struct isis_vertex *root_vertex;
+
+ root_lsp = isis_root_system_lsp(spftree->lspdb, spftree->sysid);
+ if (root_lsp) {
+ /*
+ * If we are running locally, initialize with
+ * information from adjacencies
+ */
+ root_vertex = isis_spf_add_root(spftree);
+
+ isis_spf_preload_tent(spftree, sysid, root_lsp,
+ root_vertex);
+ }
} else {
- isis_vertex_queue_insert(&spftree->tents, isis_vertex_new(
- spftree, sysid,
- VTYPE_NONPSEUDO_TE_IS));
+ isis_vertex_queue_insert(
+ &spftree->tents,
+ isis_vertex_new(spftree, sysid, VTYPE_NONPSEUDO_TE_IS));
}
isis_spf_loop(spftree, sysid);
@@ -1100,54 +1287,56 @@ struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area,
return spftree;
}
-static int isis_run_spf(struct isis_area *area, int level,
- enum spf_tree_id tree_id, uint8_t *sysid)
+void isis_run_spf(struct isis_spftree *spftree)
{
- int retval = ISIS_OK;
+ struct isis_lsp *root_lsp;
struct isis_vertex *root_vertex;
- struct isis_spftree *spftree = area->spftree[tree_id][level - 1];
struct timeval time_start;
struct timeval time_end;
+ struct isis_mt_router_info *mt_router_info;
uint16_t mtid = 0;
/* Get time that can't roll backwards. */
monotime(&time_start);
- int family = -1;
- switch (tree_id) {
+ root_lsp = isis_root_system_lsp(spftree->lspdb, spftree->sysid);
+ if (root_lsp == NULL) {
+ zlog_err("ISIS-Spf: could not find own l%d LSP!",
+ spftree->level);
+ return;
+ }
+
+ /* Get Multi-Topology ID. */
+ switch (spftree->tree_id) {
case SPFTREE_IPV4:
- family = AF_INET;
mtid = ISIS_MT_IPV4_UNICAST;
break;
case SPFTREE_IPV6:
- family = AF_INET6;
- mtid = isis_area_ipv6_topology(area);
+ mt_router_info = isis_tlvs_lookup_mt_router_info(
+ root_lsp->tlvs, ISIS_MT_IPV6_UNICAST);
+ if (mt_router_info)
+ mtid = ISIS_MT_IPV6_UNICAST;
+ else
+ mtid = ISIS_MT_IPV4_UNICAST;
break;
case SPFTREE_DSTSRC:
- family = AF_INET6;
mtid = ISIS_MT_IPV6_DSTSRC;
break;
case SPFTREE_COUNT:
- assert(!"isis_run_spf should never be called with SPFTREE_COUNT as argument!");
- return ISIS_WARNING;
+ zlog_err(
+ "isis_run_spf should never be called with SPFTREE_COUNT as argument!");
+ exit(1);
}
- assert(spftree);
- assert(sysid);
-
/*
* C.2.5 Step 0
*/
- init_spt(spftree, mtid, level, family, tree_id, false);
+ init_spt(spftree, mtid);
/* a) */
- root_vertex = isis_spf_add_root(spftree, sysid);
+ root_vertex = isis_spf_add_root(spftree);
/* b) */
- retval = isis_spf_preload_tent(spftree, sysid, root_vertex);
- if (retval != ISIS_OK) {
- zlog_warn("ISIS-Spf: failed to load TENT SPF-root:%s",
- print_sys_hostname(sysid));
- goto out;
- }
+ isis_spf_build_adj_list(spftree, root_lsp);
+ isis_spf_preload_tent(spftree, spftree->sysid, root_lsp, root_vertex);
/*
* C.2.7 Step 2
@@ -1155,19 +1344,16 @@ static int isis_run_spf(struct isis_area *area, int level,
if (!isis_vertex_queue_count(&spftree->tents)
&& (IS_DEBUG_SPF_EVENTS)) {
zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s",
- print_sys_hostname(sysid));
+ print_sys_hostname(spftree->sysid));
}
- isis_spf_loop(spftree, sysid);
-out:
+ isis_spf_loop(spftree, spftree->sysid);
spftree->runcount++;
spftree->last_run_timestamp = time(NULL);
spftree->last_run_monotime = monotime(&time_end);
spftree->last_run_duration =
((time_end.tv_sec - time_start.tv_sec) * 1000000)
+ (time_end.tv_usec - time_start.tv_usec);
-
- return retval;
}
void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees)
@@ -1191,8 +1377,8 @@ static int isis_run_spf_cb(struct thread *thread)
{
struct isis_spf_run *run = THREAD_ARG(thread);
struct isis_area *area = run->area;
+ struct isis_spftree *spftree;
int level = run->level;
- int retval = ISIS_OK;
XFREE(MTYPE_ISIS_SPF_RUN, run);
area->spf_timer[level - 1] = NULL;
@@ -1210,15 +1396,21 @@ static int isis_run_spf_cb(struct thread *thread)
zlog_debug("ISIS-Spf (%s) L%d SPF needed, periodic SPF",
area->area_tag, level);
- if (area->ip_circuits)
- retval = isis_run_spf(area, level, SPFTREE_IPV4,
- area->isis->sysid);
- if (area->ipv6_circuits)
- retval = isis_run_spf(area, level, SPFTREE_IPV6,
- area->isis->sysid);
- if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area))
- retval = isis_run_spf(area, level, SPFTREE_DSTSRC,
- area->isis->sysid);
+ if (area->ip_circuits) {
+ spftree = area->spftree[SPFTREE_IPV4][level - 1];
+ memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN);
+ isis_run_spf(spftree);
+ }
+ if (area->ipv6_circuits) {
+ spftree = area->spftree[SPFTREE_IPV6][level - 1];
+ memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN);
+ isis_run_spf(spftree);
+ }
+ if (area->ipv6_circuits && isis_area_ipv6_dstsrc_enabled(area)) {
+ spftree = area->spftree[SPFTREE_DSTSRC][level - 1];
+ memcpy(spftree->sysid, area->isis->sysid, ISIS_SYS_ID_LEN);
+ isis_run_spf(spftree);
+ }
isis_area_verify_routes(area);
@@ -1232,7 +1424,7 @@ static int isis_run_spf_cb(struct thread *thread)
fabricd_run_spf(area);
- return retval;
+ return 0;
}
static struct isis_spf_run *isis_run_spf_arg(struct isis_area *area, int level)
@@ -1252,6 +1444,9 @@ int _isis_spf_schedule(struct isis_area *area, int level,
time_t now = monotime(NULL);
int diff = now - spftree->last_run_monotime;
+ if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
+ return 0;
+
assert(diff >= 0);
assert(area->is_type & level);
@@ -1331,7 +1526,7 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
int rows = 0;
struct listnode *anode = listhead(vertex->Adj_N);
struct listnode *pnode = listhead(vertex->parents);
- struct isis_adjacency *adj;
+ struct isis_vertex_adj *vadj;
struct isis_vertex *pvertex;
vty_out(vty, "%-20s %-12s %-6u ",
@@ -1342,10 +1537,10 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
vertex->parents ? listcount(vertex->parents) : 0);
i++) {
if (anode) {
- adj = listgetdata(anode);
+ vadj = listgetdata(anode);
anode = anode->next;
} else {
- adj = NULL;
+ vadj = NULL;
}
if (pnode) {
@@ -1360,14 +1555,18 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
vty_out(vty, "%-20s %-12s %-6s ", "", "", "");
}
- if (adj) {
+ if (vadj) {
+ struct isis_spf_adj *sadj = vadj->sadj;
+
vty_out(vty, "%-20s %-9s ",
- print_sys_hostname(adj->sysid),
- adj->circuit->interface->name);
+ print_sys_hostname(sadj->id),
+ sadj->adj ? sadj->adj->circuit
+ ->interface->name
+ : "-");
}
if (pvertex) {
- if (!adj)
+ if (!vadj)
vty_out(vty, "%-20s %-9s ", "", "");
vty_out(vty, "%s(%d)",
@@ -1381,13 +1580,14 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
}
}
-static void isis_print_spftree(struct vty *vty, int level,
- struct isis_area *area,
- enum spf_tree_id tree_id)
+void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree)
{
const char *tree_id_text = NULL;
- switch (tree_id) {
+ if (!spftree || !isis_vertex_queue_count(&spftree->paths))
+ return;
+
+ switch (spftree->tree_id) {
case SPFTREE_IPV4:
tree_id_text = "that speak IP";
break;
@@ -1402,16 +1602,9 @@ static void isis_print_spftree(struct vty *vty, int level,
return;
}
- if (!area->spftree[tree_id][level - 1]
- || !isis_vertex_queue_count(
- &area->spftree[tree_id][level - 1]->paths))
- return;
-
- vty_out(vty, "IS-IS paths to level-%d routers %s\n",
- level, tree_id_text);
- isis_print_paths(vty, &area->spftree[tree_id][level - 1]->paths,
- area->isis->sysid);
-
+ vty_out(vty, "IS-IS paths to level-%d routers %s\n", spftree->level,
+ tree_id_text);
+ isis_print_paths(vty, &spftree->paths, spftree->sysid);
vty_out(vty, "\n");
}
@@ -1433,16 +1626,19 @@ static void show_isis_topology_common(struct vty *vty, int levels,
continue;
if (area->ip_circuits > 0) {
- isis_print_spftree(vty, level, area,
- SPFTREE_IPV4);
+ isis_print_spftree(
+ vty,
+ area->spftree[SPFTREE_IPV4][level - 1]);
}
if (area->ipv6_circuits > 0) {
- isis_print_spftree(vty, level, area,
- SPFTREE_IPV6);
+ isis_print_spftree(
+ vty,
+ area->spftree[SPFTREE_IPV6][level - 1]);
}
if (isis_area_ipv6_dstsrc_enabled(area)) {
- isis_print_spftree(vty, level, area,
- SPFTREE_DSTSRC);
+ isis_print_spftree(vty,
+ area->spftree[SPFTREE_DSTSRC]
+ [level - 1]);
}
}
@@ -1474,7 +1670,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
)
{
int levels = ISIS_LEVELS;
- struct listnode *inode, *nnode;
+ struct listnode *node;
struct isis *isis = NULL;
int idx = 0;
const char *vrf_name = VRF_DEFAULT_NAME;
@@ -1498,10 +1694,9 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
if (vrf_name) {
if (all_vrf) {
- for (ALL_LIST_ELEMENTS(im->isis, nnode, inode, isis)) {
+ for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
show_isis_topology_common(vty, levels, isis);
- }
- return 0;
+ return CMD_SUCCESS;
}
isis = isis_lookup_by_vrfname(vrf_name);
if (isis != NULL)
@@ -1511,9 +1706,199 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
return CMD_SUCCESS;
}
-void isis_spf_cmds_init(void)
+void isis_print_routes(struct vty *vty, struct isis_spftree *spftree)
+{
+ struct ttable *tt;
+ struct route_node *rn;
+ const char *tree_id_text = NULL;
+
+ if (!spftree)
+ return;
+
+ switch (spftree->tree_id) {
+ case SPFTREE_IPV4:
+ tree_id_text = "IPv4";
+ break;
+ case SPFTREE_IPV6:
+ tree_id_text = "IPv6";
+ break;
+ case SPFTREE_DSTSRC:
+ tree_id_text = "IPv6 (dst-src routing)";
+ break;
+ case SPFTREE_COUNT:
+ assert(!"isis_print_routes shouldn't be called with SPFTREE_COUNT as type");
+ return;
+ }
+
+ vty_out(vty, "IS-IS %s %s routing table:\n\n",
+ circuit_t2string(spftree->level), tree_id_text);
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Prefix|Metric|Interface|Nexthop|Label(s)");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+ for (rn = route_top(spftree->route_table); rn; rn = route_next(rn)) {
+ struct isis_route_info *rinfo;
+ struct isis_nexthop *nexthop;
+ struct listnode *node;
+ bool first = true;
+ char buf_prefix[BUFSIZ];
+
+ rinfo = rn->info;
+ if (!rinfo)
+ continue;
+
+ (void)prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
+ for (ALL_LIST_ELEMENTS_RO(rinfo->nexthops, node, nexthop)) {
+ struct interface *ifp;
+ char buf_iface[BUFSIZ];
+ char buf_nhop[BUFSIZ];
+ char buf_labels[BUFSIZ] = {};
+
+ if (!CHECK_FLAG(spftree->flags,
+ F_SPFTREE_NO_ADJACENCIES)) {
+ inet_ntop(nexthop->family, &nexthop->ip,
+ buf_nhop, sizeof(buf_nhop));
+ ifp = if_lookup_by_index(nexthop->ifindex,
+ VRF_DEFAULT);
+ if (ifp)
+ strlcpy(buf_iface, ifp->name,
+ sizeof(buf_iface));
+ else
+ snprintf(buf_iface, sizeof(buf_iface),
+ "ifindex %u",
+ nexthop->ifindex);
+ } else {
+ strlcpy(buf_nhop,
+ print_sys_hostname(nexthop->sysid),
+ sizeof(buf_nhop));
+ strlcpy(buf_iface, "-", sizeof(buf_iface));
+ }
+
+ if (nexthop->sr.label != MPLS_INVALID_LABEL)
+ label2str(nexthop->sr.label, buf_labels,
+ sizeof(buf_labels));
+ else
+ strlcpy(buf_labels, "-", sizeof(buf_labels));
+
+ if (first) {
+ ttable_add_row(tt, "%s|%u|%s|%s|%s", buf_prefix,
+ rinfo->cost, buf_iface, buf_nhop,
+ buf_labels);
+ first = false;
+ } else
+ ttable_add_row(tt, "||%s|%s|%s", buf_iface,
+ buf_nhop, buf_labels);
+ }
+ }
+
+ /* Dump the generated table. */
+ if (tt->nrows > 1) {
+ char *table;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ }
+ ttable_del(tt);
+}
+
+static void show_isis_route_common(struct vty *vty, int levels,
+ struct isis *isis)
+{
+ struct listnode *node;
+ struct isis_area *area;
+
+ if (!isis->area_list || isis->area_list->count == 0)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ vty_out(vty, "Area %s:\n",
+ area->area_tag ? area->area_tag : "null");
+
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ if ((level & levels) == 0)
+ continue;
+
+ if (area->ip_circuits > 0) {
+ isis_print_routes(
+ vty,
+ area->spftree[SPFTREE_IPV4][level - 1]);
+ }
+ if (area->ipv6_circuits > 0) {
+ isis_print_routes(
+ vty,
+ area->spftree[SPFTREE_IPV6][level - 1]);
+ }
+ if (isis_area_ipv6_dstsrc_enabled(area)) {
+ isis_print_routes(vty,
+ area->spftree[SPFTREE_DSTSRC]
+ [level - 1]);
+ }
+ }
+ }
+}
+
+DEFUN(show_isis_route, show_isis_route_cmd,
+ "show " PROTO_NAME
+ " [vrf <NAME|all>] route"
+#ifndef FABRICD
+ " [<level-1|level-2>]"
+#endif
+ ,
+ SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
+ "IS-IS routing table\n"
+#ifndef FABRICD
+ "level-1 routes\n"
+ "level-2 routes\n"
+#endif
+)
+{
+ int levels;
+ struct isis *isis;
+ struct listnode *node;
+ const char *vrf_name = VRF_DEFAULT_NAME;
+ bool all_vrf = false;
+ int idx = 0;
+
+ if (argv_find(argv, argc, "level-1", &idx))
+ levels = ISIS_LEVEL1;
+ else if (argv_find(argv, argc, "level-2", &idx))
+ levels = ISIS_LEVEL2;
+ else
+ levels = ISIS_LEVEL1 | ISIS_LEVEL2;
+
+ if (!im) {
+ vty_out(vty, "IS-IS Routing Process not enabled\n");
+ return CMD_SUCCESS;
+ }
+ ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf);
+
+ if (vrf_name) {
+ if (all_vrf) {
+ for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
+ show_isis_route_common(vty, levels, isis);
+ return CMD_SUCCESS;
+ }
+ isis = isis_lookup_by_vrfname(vrf_name);
+ if (isis != NULL)
+ show_isis_route_common(vty, levels, isis);
+ }
+
+ return CMD_SUCCESS;
+}
+
+void isis_spf_init(void)
{
install_element(VIEW_NODE, &show_isis_topology_cmd);
+ install_element(VIEW_NODE, &show_isis_route_cmd);
+
+ /* Register hook(s). */
+ hook_register(isis_adj_state_change_hook, spf_adj_state_change);
}
void isis_spf_print(struct isis_spftree *spftree, struct vty *vty)