diff --git a/isisd/fabricd.c b/isisd/fabricd.c index ebaf14461eff..2953ee681ca3 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 7b761f5cda35..c12f9fd339d2 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 01affb1597c5..72f2beaafee0 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 a85e596bb05c..e3c0fbc8b878 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 05aae14b94e8..6bdf900d1cb0 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 453b440e2384..1ce3829548f4 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);