From 7b36d36e0ed2a233c3a908c9e821e3f45c68d4e8 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Sun, 23 Aug 2020 00:22:32 -0300 Subject: [PATCH] isisd: make the SPF code more modular The goal of modularizing the SPF code is to make it possible for isisd to run SPF in the behalf of other nodes in the network, which is going to be necessary later when implementing the R-LFA/TI-LFA solutions. On top of that, a modularized SPF opens the door for much needed unit testing. Summary of the changes: * Change the isis_spf_preload_tent() function to use the local LSP as an input (as per the ISO specification) instead of populating the TENT based on the list of local interfaces; * Introduce the "isis_spf_adj" structure to represent an SPF adjacency. SPF adjacencies are inferred from the LSPDB, different from normal adjacencies formed using IIH messages; * Introduce the F_SPFTREE_NO_ROUTES flag to control whether the SPT should create routes or not; * Introduce the F_SPFTREE_NO_ADJACENCIES flag to specify whether IS-IS adjacency information is available or not. When running SPF in the behalf of other nodes, or under the context of an unit test, no adjacency information will be present. * On isis_area_create(), move some code around so that the area's isis backpointer is set as early as possible. Signed-off-by: Renato Westphal --- isisd/fabricd.c | 4 +- isisd/isis_route.c | 8 +- isisd/isis_spf.c | 837 ++++++++++++++++++++++----------------- isisd/isis_spf.h | 20 +- isisd/isis_spf_private.h | 19 +- isisd/isisd.c | 42 +- 6 files changed, 542 insertions(+), 388 deletions(-) diff --git a/isisd/fabricd.c b/isisd/fabricd.c index ebaf14461e..2953ee681c 100644 --- a/isisd/fabricd.c +++ b/isisd/fabricd.c @@ -221,7 +221,9 @@ struct fabricd *fabricd_new(struct isis_area *area) rv->area = area; rv->initial_sync_state = FABRICD_SYNC_PENDING; - rv->spftree = isis_spftree_new(area); + rv->spftree = isis_spftree_new(area, &area->lspdb[IS_LEVEL_2 - 1], + area->isis->sysid, ISIS_LEVEL2, + SPFTREE_IPV4, F_SPFTREE_HOPCOUNT_METRIC); rv->neighbors = skiplist_new(0, neighbor_entry_list_cmp, neighbor_entry_del_void); rv->neighbors_neighbors = hash_create(neighbor_entry_hash_key, diff --git a/isisd/isis_route.c b/isisd/isis_route.c index 7b761f5cda..c12f9fd339 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -46,6 +46,7 @@ #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_spf.h" +#include "isis_spf_private.h" #include "isis_route.h" #include "isis_zebra.h" @@ -165,13 +166,16 @@ static struct isis_route_info *isis_route_info_new(struct prefix *prefix, struct list *adjacencies) { struct isis_route_info *rinfo; - struct isis_adjacency *adj; + struct isis_vertex_adj *vadj; struct listnode *node; rinfo = XCALLOC(MTYPE_ISIS_ROUTE_INFO, sizeof(struct isis_route_info)); rinfo->nexthops = list_new(); - for (ALL_LIST_ELEMENTS_RO(adjacencies, node, adj)) { + for (ALL_LIST_ELEMENTS_RO(adjacencies, node, vadj)) { + struct isis_spf_adj *sadj = vadj->sadj; + struct isis_adjacency *adj = sadj->adj; + /* check for force resync this route */ if (CHECK_FLAG(adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 01affb1597..72f2beaafe 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -57,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 ? @@ -81,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; @@ -104,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; @@ -171,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) @@ -182,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); @@ -193,21 +215,68 @@ 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, uint8_t flags) { struct isis_spftree *tree; @@ -217,15 +286,25 @@ 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; + 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); @@ -257,7 +336,9 @@ 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, 0); } } } @@ -305,7 +386,7 @@ static int spf_adj_state_change(struct isis_adjacency *adj) * 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; @@ -314,7 +395,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; @@ -323,28 +404,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); @@ -379,12 +453,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); @@ -412,14 +485,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 @@ -436,7 +511,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; @@ -446,10 +521,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)) @@ -465,7 +542,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; } @@ -480,7 +557,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; @@ -530,16 +607,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); @@ -622,7 +703,9 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, /* 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, @@ -651,12 +734,19 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, 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, @@ -770,236 +860,238 @@ static int isis_spf_process_lsp(struct isis_spftree *spftree, 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); - } + } +} + +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; } - 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; + + 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); } /* @@ -1022,10 +1114,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); @@ -1039,18 +1131,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, @@ -1091,19 +1179,30 @@ 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, + 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); @@ -1111,54 +1210,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 @@ -1166,19 +1267,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) @@ -1202,8 +1300,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; @@ -1221,15 +1319,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); @@ -1243,7 +1347,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) @@ -1342,7 +1446,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 ", @@ -1353,10 +1457,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) { @@ -1371,14 +1475,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)", @@ -1392,13 +1500,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) +static 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; @@ -1413,16 +1522,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"); } @@ -1444,16 +1546,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]); } } @@ -1574,15 +1679,25 @@ static void isis_print_routes(struct vty *vty, struct isis_spftree *spftree) char buf_nhop[BUFSIZ]; char buf_labels[BUFSIZ] = {}; - 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); + 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, diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index a85e596bb0..e3c0fbc8b8 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -26,7 +26,24 @@ struct isis_spftree; -struct isis_spftree *isis_spftree_new(struct isis_area *area); +struct isis_spf_adj { + uint8_t id[ISIS_SYS_ID_LEN + 1]; + struct isis_adjacency *adj; + uint32_t metric; + struct isis_ext_subtlvs *subtlvs; + struct { + uint8_t desig_is_id[ISIS_SYS_ID_LEN + 1]; + struct isis_lsp *lsp_pseudo; + } lan; + uint8_t flags; +#define F_ISIS_SPF_ADJ_BROADCAST 0x01 +#define F_ISIS_SPF_ADJ_OLDMETRIC 0x02 +}; + +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, uint8_t flags); void isis_spf_invalidate_routes(struct isis_spftree *tree); void isis_spf_verify_routes(struct isis_area *area, struct isis_spftree **trees); @@ -40,6 +57,7 @@ int _isis_spf_schedule(struct isis_area *area, int level, const char *func, const char *file, int line); void isis_spf_init(void); void isis_spf_print(struct isis_spftree *spftree, struct vty *vty); +void isis_run_spf(struct isis_spftree *spftree); struct isis_spftree *isis_run_hopcount_spf(struct isis_area *area, uint8_t *sysid, struct isis_spftree *spftree); diff --git a/isisd/isis_spf_private.h b/isisd/isis_spf_private.h index 05aae14b94..6bdf900d1c 100644 --- a/isisd/isis_spf_private.h +++ b/isisd/isis_spf_private.h @@ -50,6 +50,11 @@ struct prefix_pair { struct prefix_ipv6 src; }; +struct isis_vertex_adj { + struct isis_spf_adj *sadj; + struct mpls_label_stack *label_stack; +}; + /* * Triple */ @@ -180,6 +185,10 @@ static void isis_vertex_del(struct isis_vertex *vertex) XFREE(MTYPE_ISIS_VERTEX, vertex); } +bool isis_vertex_adj_exists(const struct isis_spftree *spftree, + const struct isis_vertex *vertex, + const struct isis_spf_adj *sadj); + __attribute__((__unused__)) static void isis_vertex_queue_clear(struct isis_vertex_queue *queue) { @@ -297,18 +306,25 @@ struct isis_spftree { struct isis_vertex_queue paths; /* the SPT */ struct isis_vertex_queue tents; /* TENT */ struct route_table *route_table; + struct lspdb_head *lspdb; /* link-state db */ + struct list *sadj_list; struct isis_area *area; /* back pointer to area */ unsigned int runcount; /* number of runs since uptime */ time_t last_run_timestamp; /* last run timestamp as wall time for display */ time_t last_run_monotime; /* last run as monotime for scheduling */ time_t last_run_duration; /* last run duration in msec */ + uint8_t sysid[ISIS_SYS_ID_LEN]; uint16_t mtid; int family; int level; enum spf_tree_id tree_id; bool hopcount_metric; + uint8_t flags; }; +#define F_SPFTREE_HOPCOUNT_METRIC 0x01 +#define F_SPFTREE_NO_ROUTES 0x02 +#define F_SPFTREE_NO_ADJACENCIES 0x04 __attribute__((__unused__)) static void isis_vertex_id_init(struct isis_vertex *vertex, const void *id, @@ -347,8 +363,7 @@ static struct isis_lsp *lsp_for_vertex(struct isis_spftree *spftree, memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT(lsp_id) = 0; - struct lspdb_head *lspdb = &spftree->area->lspdb[spftree->level - 1]; - struct isis_lsp *lsp = lsp_search(lspdb, lsp_id); + struct isis_lsp *lsp = lsp_search(spftree->lspdb, lsp_id); if (lsp && lsp->hdr.rem_lifetime != 0) return lsp; diff --git a/isisd/isisd.c b/isisd/isisd.c index 453b440e23..1ce3829548 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -218,6 +218,27 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) struct vrf *vrf = NULL; area = XCALLOC(MTYPE_ISIS_AREA, sizeof(struct isis_area)); + if (vrf_name) { + vrf = vrf_lookup_by_name(vrf_name); + if (vrf) { + isis = isis_lookup_by_vrfid(vrf->vrf_id); + if (isis == NULL) { + isis = isis_new(vrf->vrf_id); + isis_add(isis); + } + } else + return NULL; + } else { + isis = isis_lookup_by_vrfid(VRF_DEFAULT); + if (isis == NULL) { + isis = isis_new(VRF_DEFAULT); + isis_add(isis); + } + } + + listnode_add(isis->area_list, area); + area->isis = isis; + /* * Fabricd runs only as level-2. * For IS-IS, the default is level-1-2 @@ -297,27 +318,6 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->area_tag = strdup(area_tag); - if (vrf_name) { - vrf = vrf_lookup_by_name(vrf_name); - if (vrf) { - isis = isis_lookup_by_vrfid(vrf->vrf_id); - if (isis == NULL) { - isis = isis_new(vrf->vrf_id); - isis_add(isis); - } - } else - return NULL; - } else { - isis = isis_lookup_by_vrfid(VRF_DEFAULT); - if (isis == NULL) { - isis = isis_new(VRF_DEFAULT); - isis_add(isis); - } - } - - listnode_add(isis->area_list, area); - area->isis = isis; - if (fabricd) area->fabricd = fabricd_new(area);