diff options
Diffstat (limited to 'ospfd/ospf_spf.c')
| -rw-r--r-- | ospfd/ospf_spf.c | 658 |
1 files changed, 541 insertions, 117 deletions
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 4665f53edb..82acd0829c 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -46,6 +46,7 @@ #include "ospfd/ospf_abr.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_sr.h" +#include "ospfd/ospf_ti_lfa.h" #include "ospfd/ospf_errors.h" /* Variables to ensure a SPF scheduled log message is printed only once */ @@ -141,11 +142,16 @@ static void ospf_canonical_nexthops_free(struct vertex *root) ospf_canonical_nexthops_free(child); /* Free child nexthops pointing back to this root vertex */ - for (ALL_LIST_ELEMENTS(child->parents, n2, nn2, vp)) + for (ALL_LIST_ELEMENTS(child->parents, n2, nn2, vp)) { if (vp->parent == root && vp->nexthop) { vertex_nexthop_free(vp->nexthop); vp->nexthop = NULL; + if (vp->local_nexthop) { + vertex_nexthop_free(vp->local_nexthop); + vp->local_nexthop = NULL; + } } + } } } @@ -154,7 +160,8 @@ static void ospf_canonical_nexthops_free(struct vertex *root) * vertex_nexthop, with refcounts. */ static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink, - struct vertex_nexthop *hop) + struct vertex_nexthop *hop, + struct vertex_nexthop *lhop) { struct vertex_parent *new; @@ -163,6 +170,7 @@ static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink, new->parent = v; new->backlink = backlink; new->nexthop = hop; + new->local_nexthop = lhop; return new; } @@ -172,7 +180,7 @@ static void vertex_parent_free(void *p) XFREE(MTYPE_OSPF_VERTEX_PARENT, p); } -static int vertex_parent_cmp(void *aa, void *bb) +int vertex_parent_cmp(void *aa, void *bb) { struct vertex_parent *a = aa, *b = bb; return IPV4_ADDR_CMP(&a->nexthop->router, &b->nexthop->router); @@ -284,6 +292,257 @@ static void ospf_vertex_add_parent(struct vertex *v) } } +/* Find a vertex according to its router id */ +struct vertex *ospf_spf_vertex_find(struct in_addr id, struct list *vertex_list) +{ + struct listnode *node; + struct vertex *found; + + for (ALL_LIST_ELEMENTS_RO(vertex_list, node, found)) { + if (found->id.s_addr == id.s_addr) + return found; + } + + return NULL; +} + +/* Find a vertex parent according to its router id */ +struct vertex_parent *ospf_spf_vertex_parent_find(struct in_addr id, + struct vertex *vertex) +{ + struct listnode *node; + struct vertex_parent *found; + + for (ALL_LIST_ELEMENTS_RO(vertex->parents, node, found)) { + if (found->parent->id.s_addr == id.s_addr) + return found; + } + + return NULL; +} + +struct vertex *ospf_spf_vertex_by_nexthop(struct vertex *root, + struct in_addr *nexthop) +{ + struct listnode *node; + struct vertex *child; + struct vertex_parent *vertex_parent; + + for (ALL_LIST_ELEMENTS_RO(root->children, node, child)) { + vertex_parent = ospf_spf_vertex_parent_find(root->id, child); + if (vertex_parent->nexthop->router.s_addr == nexthop->s_addr) + return child; + } + + return NULL; +} + +/* Create a deep copy of a SPF vertex without children and parents */ +static struct vertex *ospf_spf_vertex_copy(struct vertex *vertex) +{ + struct vertex *copy; + + copy = XCALLOC(MTYPE_OSPF_VERTEX, sizeof(struct vertex)); + + memcpy(copy, vertex, sizeof(struct vertex)); + copy->parents = list_new(); + copy->parents->del = vertex_parent_free; + copy->parents->cmp = vertex_parent_cmp; + copy->children = list_new(); + + return copy; +} + +/* Create a deep copy of a SPF vertex_parent */ +static struct vertex_parent * +ospf_spf_vertex_parent_copy(struct vertex_parent *vertex_parent) +{ + struct vertex_parent *vertex_parent_copy; + struct vertex_nexthop *nexthop_copy, *local_nexthop_copy; + + vertex_parent_copy = + XCALLOC(MTYPE_OSPF_VERTEX, sizeof(struct vertex_parent)); + + nexthop_copy = vertex_nexthop_new(); + local_nexthop_copy = vertex_nexthop_new(); + + memcpy(vertex_parent_copy, vertex_parent, sizeof(struct vertex_parent)); + memcpy(nexthop_copy, vertex_parent->nexthop, + sizeof(struct vertex_nexthop)); + memcpy(local_nexthop_copy, vertex_parent->local_nexthop, + sizeof(struct vertex_nexthop)); + + vertex_parent_copy->nexthop = nexthop_copy; + vertex_parent_copy->local_nexthop = local_nexthop_copy; + + return vertex_parent_copy; +} + +/* Create a deep copy of a SPF tree */ +void ospf_spf_copy(struct vertex *vertex, struct list *vertex_list) +{ + struct listnode *node; + struct vertex *vertex_copy, *child, *child_copy, *parent_copy; + struct vertex_parent *vertex_parent, *vertex_parent_copy; + + /* First check if the node is already in the vertex list */ + vertex_copy = ospf_spf_vertex_find(vertex->id, vertex_list); + if (!vertex_copy) { + vertex_copy = ospf_spf_vertex_copy(vertex); + listnode_add(vertex_list, vertex_copy); + } + + /* Copy all parents, create parent nodes if necessary */ + for (ALL_LIST_ELEMENTS_RO(vertex->parents, node, vertex_parent)) { + parent_copy = ospf_spf_vertex_find(vertex_parent->parent->id, + vertex_list); + if (!parent_copy) { + parent_copy = + ospf_spf_vertex_copy(vertex_parent->parent); + listnode_add(vertex_list, parent_copy); + } + vertex_parent_copy = ospf_spf_vertex_parent_copy(vertex_parent); + vertex_parent_copy->parent = parent_copy; + listnode_add(vertex_copy->parents, vertex_parent_copy); + } + + /* Copy all children, create child nodes if necessary */ + for (ALL_LIST_ELEMENTS_RO(vertex->children, node, child)) { + child_copy = ospf_spf_vertex_find(child->id, vertex_list); + if (!child_copy) { + child_copy = ospf_spf_vertex_copy(child); + listnode_add(vertex_list, child_copy); + } + listnode_add(vertex_copy->children, child_copy); + } + + /* Finally continue copying with child nodes */ + for (ALL_LIST_ELEMENTS_RO(vertex->children, node, child)) + ospf_spf_copy(child, vertex_list); +} + +static void ospf_spf_remove_branch(struct vertex_parent *vertex_parent, + struct vertex *child, + struct list *vertex_list) +{ + struct listnode *node, *nnode, *inner_node, *inner_nnode; + struct vertex *grandchild; + struct vertex_parent *vertex_parent_found; + bool has_more_links = false; + + /* + * First check if there are more nexthops for that parent to that child + */ + for (ALL_LIST_ELEMENTS_RO(child->parents, node, vertex_parent_found)) { + if (vertex_parent_found->parent->id.s_addr + == vertex_parent->parent->id.s_addr + && vertex_parent_found->nexthop->router.s_addr + != vertex_parent->nexthop->router.s_addr) + has_more_links = true; + } + + /* + * No more links from that parent? Then delete the child from its + * children list. + */ + if (!has_more_links) + listnode_delete(vertex_parent->parent->children, child); + + /* + * Delete the vertex_parent from the child parents list, this needs to + * be done anyway. + */ + listnode_delete(child->parents, vertex_parent); + + /* + * Are there actually more parents left? If not, then delete the child! + * This is done by recursively removing the links to the grandchildren, + * such that finally the child can be removed without leaving unused + * partial branches. + */ + if (child->parents->count == 0) { + for (ALL_LIST_ELEMENTS(child->children, node, nnode, + grandchild)) { + for (ALL_LIST_ELEMENTS(grandchild->parents, inner_node, + inner_nnode, + vertex_parent_found)) { + ospf_spf_remove_branch(vertex_parent_found, + grandchild, vertex_list); + } + } + listnode_delete(vertex_list, child); + ospf_vertex_free(child); + } +} + +static int ospf_spf_remove_link(struct vertex *vertex, struct list *vertex_list, + struct router_lsa_link *link) +{ + struct listnode *node, *inner_node; + struct vertex *child; + struct vertex_parent *vertex_parent; + + /* + * Identify the node who shares a subnet (given by the link) with a + * child and remove the branch of this particular child. + */ + for (ALL_LIST_ELEMENTS_RO(vertex->children, node, child)) { + for (ALL_LIST_ELEMENTS_RO(child->parents, inner_node, + vertex_parent)) { + if ((vertex_parent->local_nexthop->router.s_addr + & link->link_data.s_addr) + == (link->link_id.s_addr + & link->link_data.s_addr)) { + ospf_spf_remove_branch(vertex_parent, child, + vertex_list); + return 0; + } + } + } + + /* No link found yet, move on recursively */ + for (ALL_LIST_ELEMENTS_RO(vertex->children, node, child)) { + if (ospf_spf_remove_link(child, vertex_list, link) == 0) + return 0; + } + + /* link was not removed yet */ + return 1; +} + +void ospf_spf_remove_resource(struct vertex *vertex, struct list *vertex_list, + struct protected_resource *resource) +{ + struct listnode *node, *nnode; + struct vertex *found; + struct vertex_parent *vertex_parent; + + switch (resource->type) { + case OSPF_TI_LFA_LINK_PROTECTION: + ospf_spf_remove_link(vertex, vertex_list, resource->link); + break; + case OSPF_TI_LFA_NODE_PROTECTION: + found = ospf_spf_vertex_find(resource->router_id, vertex_list); + if (!found) + break; + + /* + * Remove the node by removing all links from its parents. Note + * that the child is automatically removed here with the last + * link from a parent, hence no explicit removal of the node. + */ + for (ALL_LIST_ELEMENTS(found->parents, node, nnode, + vertex_parent)) + ospf_spf_remove_branch(vertex_parent, found, + vertex_list); + + break; + default: + /* do nothing */ + break; + } +} + static void ospf_spf_init(struct ospf_area *area, struct ospf_lsa *root_lsa, bool is_dry_run, bool is_root_node) { @@ -427,6 +686,7 @@ static void ospf_spf_flush_parents(struct vertex *w) */ static void ospf_spf_add_parent(struct vertex *v, struct vertex *w, struct vertex_nexthop *newhop, + struct vertex_nexthop *newlhop, unsigned int distance) { struct vertex_parent *vp, *wp; @@ -482,7 +742,8 @@ static void ospf_spf_add_parent(struct vertex *v, struct vertex *w, } } - vp = vertex_parent_new(v, ospf_lsa_has_link(w->lsa, v->lsa), newhop); + vp = vertex_parent_new(v, ospf_lsa_has_link(w->lsa, v->lsa), newhop, + newlhop); listnode_add_sort(w->parents, vp); return; @@ -541,7 +802,7 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, unsigned int distance, int lsa_pos) { struct listnode *node, *nnode; - struct vertex_nexthop *nh; + struct vertex_nexthop *nh, *lnh; struct vertex_parent *vp; unsigned int added = 0; char buf1[BUFSIZ]; @@ -586,17 +847,22 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, struct ospf_interface *oi = NULL; struct in_addr nexthop = {.s_addr = 0}; - oi = ospf_if_lookup_by_lsa_pos(area, lsa_pos); - if (!oi) { - zlog_debug( - "%s: OI not found in LSA: lsa_pos: %d link_id:%s link_data:%s", - __func__, lsa_pos, - inet_ntop(AF_INET, &l->link_id, - buf1, BUFSIZ), - inet_ntop(AF_INET, - &l->link_data, buf2, - BUFSIZ)); - return 0; + if (area->spf_root_node) { + oi = ospf_if_lookup_by_lsa_pos(area, + lsa_pos); + if (!oi) { + zlog_debug( + "%s: OI not found in LSA: lsa_pos: %d link_id:%s link_data:%s", + __func__, lsa_pos, + inet_ntop(AF_INET, + &l->link_id, + buf1, BUFSIZ), + inet_ntop(AF_INET, + &l->link_data, + buf2, + BUFSIZ)); + return 0; + } } /* @@ -644,7 +910,21 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, * as described above using a reverse lookup to * figure out the nexthop. */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT) { + + /* + * HACK: we don't know (yet) how to distinguish + * between P2P and P2MP interfaces by just + * looking at LSAs, which is important for + * TI-LFA since you want to do SPF calculations + * from the perspective of other nodes. Since + * TI-LFA is currently not implemented for P2MP + * we just check here if it is enabled and then + * blindly assume that P2P is used. Ultimately + * the interface code needs to be removed + * somehow. + */ + if (area->ospf->ti_lfa_enabled + || (oi && oi->type == OSPF_IFTYPE_POINTOPOINT)) { struct ospf_neighbor *nbr_w = NULL; /* Calculating node is root node, link @@ -673,7 +953,7 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, } } } - } else if (oi->type + } else if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { struct prefix_ipv4 la; @@ -703,12 +983,22 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, nh = vertex_nexthop_new(); nh->router = nexthop; nh->lsa_pos = lsa_pos; - ospf_spf_add_parent(v, w, nh, distance); + + /* + * Since v is the root the nexthop and + * local nexthop are the same. + */ + lnh = vertex_nexthop_new(); + memcpy(lnh, nh, + sizeof(struct vertex_nexthop)); + + ospf_spf_add_parent(v, w, nh, lnh, + distance); return 1; } else zlog_info( "%s: could not determine nexthop for link %s", - __func__, oi->ifp->name); + __func__, oi ? oi->ifp->name : ""); } /* end point-to-point link from V to W */ else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) { /* @@ -733,7 +1023,17 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, nh = vertex_nexthop_new(); nh->router = vl_data->nexthop.router; nh->lsa_pos = vl_data->nexthop.lsa_pos; - ospf_spf_add_parent(v, w, nh, distance); + + /* + * Since v is the root the nexthop and + * local nexthop are the same. + */ + lnh = vertex_nexthop_new(); + memcpy(lnh, nh, + sizeof(struct vertex_nexthop)); + + ospf_spf_add_parent(v, w, nh, lnh, + distance); return 1; } else zlog_info( @@ -747,7 +1047,15 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, nh = vertex_nexthop_new(); nh->router.s_addr = 0; /* Nexthop not required */ nh->lsa_pos = lsa_pos; - ospf_spf_add_parent(v, w, nh, distance); + + /* + * Since v is the root the nexthop and + * local nexthop are the same. + */ + lnh = vertex_nexthop_new(); + memcpy(lnh, nh, sizeof(struct vertex_nexthop)); + + ospf_spf_add_parent(v, w, nh, lnh, distance); return 1; } } /* end V is the root */ @@ -780,8 +1088,18 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, nh = vertex_nexthop_new(); nh->router = l->link_data; nh->lsa_pos = vp->nexthop->lsa_pos; + + /* + * Since v is the root the nexthop and + * local nexthop are the same. + */ + lnh = vertex_nexthop_new(); + memcpy(lnh, nh, + sizeof(struct vertex_nexthop)); + added = 1; - ospf_spf_add_parent(v, w, nh, distance); + ospf_spf_add_parent(v, w, nh, lnh, + distance); } /* * Note lack of return is deliberate. See next @@ -829,12 +1147,154 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) { added = 1; - ospf_spf_add_parent(v, w, vp->nexthop, distance); + + /* + * The nexthop is inherited, but the local nexthop still needs + * to be created. + */ + if (l) { + lnh = vertex_nexthop_new(); + lnh->router = l->link_data; + lnh->lsa_pos = lsa_pos; + } else { + lnh = NULL; + } + + ospf_spf_add_parent(v, w, vp->nexthop, lnh, distance); } return added; } +static int ospf_spf_is_protected_resource(struct ospf_area *area, + struct router_lsa_link *link, + struct lsa_header *lsa) +{ + uint8_t *p, *lim; + struct router_lsa_link *p_link; + struct router_lsa_link *l = NULL; + struct in_addr router_id; + int link_type; + + if (!area->spf_protected_resource) + return 0; + + link_type = link->m[0].type; + + switch (area->spf_protected_resource->type) { + case OSPF_TI_LFA_LINK_PROTECTION: + p_link = area->spf_protected_resource->link; + if (!p_link) + return 0; + + /* For P2P: check if the link belongs to the same subnet */ + if (link_type == LSA_LINK_TYPE_POINTOPOINT + && (p_link->link_id.s_addr & p_link->link_data.s_addr) + == (link->link_data.s_addr + & p_link->link_data.s_addr)) + return 1; + + /* For stub: check if this the same subnet */ + if (link_type == LSA_LINK_TYPE_STUB + && (p_link->link_id.s_addr == link->link_id.s_addr) + && (p_link->link_data.s_addr == link->link_data.s_addr)) + return 1; + + break; + case OSPF_TI_LFA_NODE_PROTECTION: + router_id = area->spf_protected_resource->router_id; + if (router_id.s_addr == INADDR_ANY) + return 0; + + /* For P2P: check if the link leads to the protected node */ + if (link_type == LSA_LINK_TYPE_POINTOPOINT + && link->link_id.s_addr == router_id.s_addr) + return 1; + + /* The rest is about stub links! */ + if (link_type != LSA_LINK_TYPE_STUB) + return 0; + + /* + * Check if there's a P2P link in the router LSA with the + * corresponding link data in the same subnet. + */ + + p = ((uint8_t *)lsa) + OSPF_LSA_HEADER_SIZE + 4; + lim = ((uint8_t *)lsa) + ntohs(lsa->length); + + while (p < lim) { + l = (struct router_lsa_link *)p; + p += (OSPF_ROUTER_LSA_LINK_SIZE + + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); + + /* We only care about P2P with the proper link id */ + if ((l->m[0].type != LSA_LINK_TYPE_POINTOPOINT) + || (l->link_id.s_addr != router_id.s_addr)) + continue; + + /* Link data in the subnet given by the link? */ + if ((link->link_id.s_addr & link->link_data.s_addr) + == (l->link_data.s_addr & link->link_data.s_addr)) + return 1; + } + + break; + case OSPF_TI_LFA_UNDEFINED_PROTECTION: + break; + } + + return 0; +} + +/* + * For TI-LFA we need the reverse SPF for Q spaces. The reverse SPF is created + * by honoring the weight of the reverse 'edge', e.g. the edge from W to V, and + * NOT the weight of the 'edge' from V to W as usual. Hence we need to find the + * corresponding link in the LSA of W and extract the particular weight. + * + * TODO: Only P2P supported by now! + */ +static uint16_t get_reverse_distance(struct vertex *v, + struct router_lsa_link *l, + struct ospf_lsa *w_lsa) +{ + uint8_t *p, *lim; + struct router_lsa_link *w_link; + uint16_t distance = 0; + + assert(w_lsa && w_lsa->data); + + p = ((uint8_t *)w_lsa->data) + OSPF_LSA_HEADER_SIZE + 4; + lim = ((uint8_t *)w_lsa->data) + ntohs(w_lsa->data->length); + + while (p < lim) { + w_link = (struct router_lsa_link *)p; + p += (OSPF_ROUTER_LSA_LINK_SIZE + + (w_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); + + /* Only care about P2P with link ID equal to V's router id */ + if (w_link->m[0].type == LSA_LINK_TYPE_POINTOPOINT + && w_link->link_id.s_addr == v->id.s_addr) { + distance = ntohs(w_link->m[0].metric); + break; + } + } + + /* + * This might happen if the LSA for W is not complete yet. In this + * case we take the weight of the 'forward' link from V. When the LSA + * for W is completed the reverse SPF is run again anyway. + */ + if (distance == 0) + distance = ntohs(l->m[0].metric); + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: reversed distance is %u", __func__, distance); + + return distance; +} + /* * RFC2328 16.1 (2). * v is on the SPF tree. Examine the links in v's LSA. Update the list of @@ -850,6 +1310,7 @@ static void ospf_spf_next(struct vertex *v, struct ospf_area *area, struct router_lsa_link *l = NULL; struct in_addr *r; int type = 0, lsa_pos = -1, lsa_pos_next = 0; + uint16_t link_distance; /* * If this is a router-LSA, and bit V of the router-LSA (see Section @@ -892,6 +1353,16 @@ static void ospf_spf_next(struct vertex *v, struct ospf_area *area, continue; /* + * Don't process TI-LFA protected resources. + * + * TODO: Replace this by a proper solution, e.g. remove + * corresponding links from the LSDB and run the SPF + * algo with the stripped-down LSDB. + */ + if (ospf_spf_is_protected_resource(area, l, v->lsa)) + continue; + + /* * (b) Otherwise, W is a transit vertex (router or * transit network). Look up the vertex W's LSA * (router-LSA or network-LSA) in Area A's link state @@ -928,8 +1399,19 @@ static void ospf_spf_next(struct vertex *v, struct ospf_area *area, continue; } + /* + * For TI-LFA we might need the reverse SPF. + * Currently only works with P2P! + */ + if (type == LSA_LINK_TYPE_POINTOPOINT + && area->spf_reversed) + link_distance = + get_reverse_distance(v, l, w_lsa); + else + link_distance = ntohs(l->m[0].metric); + /* step (d) below */ - distance = v->distance + ntohs(l->m[0].metric); + distance = v->distance + link_distance; } else { /* In case of V is Network-LSA. */ r = (struct in_addr *)p; @@ -1069,8 +1551,7 @@ void ospf_spf_print(struct vty *vty, struct vertex *v, int i) struct vertex_parent *parent; if (v->type == OSPF_VERTEX_ROUTER) { - vty_out(vty, "SPF Result: depth %d [R] %pI4\n", i, - &v->lsa->id); + vty_out(vty, "SPF Result: depth %d [R] %pI4\n", i, &v->lsa->id); } else { struct network_lsa *lsa = (struct network_lsa *)v->lsa; vty_out(vty, "SPF Result: depth %d [N] %pI4/%d\n", i, @@ -1078,9 +1559,11 @@ void ospf_spf_print(struct vty *vty, struct vertex *v, int i) } for (ALL_LIST_ELEMENTS_RO(v->parents, nnode, parent)) { - vty_out(vty, " nexthop %pI4 lsa pos %d\n", - &parent->nexthop->router, - parent->nexthop->lsa_pos); + vty_out(vty, + " nexthop %pI4 lsa pos %d -- local nexthop %pI4 lsa pos %d\n", + &parent->nexthop->router, parent->nexthop->lsa_pos, + &parent->local_nexthop->router, + parent->local_nexthop->lsa_pos); } i++; @@ -1128,7 +1611,9 @@ static void ospf_spf_process_stubs(struct ospf_area *area, struct vertex *v, p += (OSPF_ROUTER_LSA_LINK_SIZE + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); - if (l->m[0].type == LSA_LINK_TYPE_STUB) + /* Don't process TI-LFA protected resources */ + if (l->m[0].type == LSA_LINK_TYPE_STUB + && !ospf_spf_is_protected_resource(area, l, v->lsa)) ospf_intra_add_stub(rt, l, v, area, parent_is_root, lsa_pos); lsa_pos++; @@ -1190,73 +1675,13 @@ void ospf_spf_cleanup(struct vertex *spf, struct list *vertex_list) * attached the first level of router vertices attached to the * root vertex, see ospf_nexthop_calculation. */ - ospf_canonical_nexthops_free(spf); + if (spf) + ospf_canonical_nexthops_free(spf); /* Free SPF vertices list with deconstructor ospf_vertex_free. */ - list_delete(&vertex_list); -} - -#if 0 -static void -ospf_rtrs_print (struct route_table *rtrs) -{ - struct route_node *rn; - struct list *or_list; - struct listnode *ln; - struct listnode *pnode; - struct ospf_route *or; - struct ospf_path *path; - char buf1[BUFSIZ]; - char buf2[BUFSIZ]; - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_rtrs_print() start"); - - for (rn = route_top (rtrs); rn; rn = route_next (rn)) - if ((or_list = rn->info) != NULL) - for (ALL_LIST_ELEMENTS_RO (or_list, ln, or)) - { - switch (or->path_type) - { - case OSPF_PATH_INTRA_AREA: - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("%s [%d] area: %s", - inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), - or->cost, inet_ntop (AF_INET, &or->u.std.area_id, - buf2, BUFSIZ)); - break; - case OSPF_PATH_INTER_AREA: - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("%s IA [%d] area: %s", - inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), - or->cost, inet_ntop (AF_INET, &or->u.std.area_id, - buf2, BUFSIZ)); - break; - default: - break; - } - - for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path)) - { - if (path->nexthop.s_addr == INADDR_ANY) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug (" directly attached to %s\r", - ifindex2ifname (path->ifindex), VRF_DEFAULT); - } - else - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug (" via %pI4, %s\r", - &path->nexthop, - ifindex2ifname (path->ifindex), VRF_DEFAULT); - } - } - } - - zlog_debug ("ospf_rtrs_print() end"); + if (vertex_list) + list_delete(&vertex_list); } -#endif /* Calculating the shortest-path tree for an area, see RFC2328 16.1. */ void ospf_spf_calculate(struct ospf_area *area, struct ospf_lsa *root_lsa, @@ -1359,19 +1784,27 @@ void ospf_spf_calculate(struct ospf_area *area, struct ospf_lsa *root_lsa, if (IS_DEBUG_OSPF_EVENT) zlog_debug("ospf_spf_calculate: Stop. %zd vertices", mtype_stats_alloc(MTYPE_OSPF_VERTEX)); +} + +void ospf_spf_calculate_area(struct ospf *ospf, struct ospf_area *area, + struct route_table *new_table, + struct route_table *new_rtrs) +{ + ospf_spf_calculate(area, area->router_lsa_self, new_table, new_rtrs, + false, true); - /* If this is a dry run then keep the SPF data in place */ - if (!area->spf_dry_run) - ospf_spf_cleanup(area->spf, area->spf_vertex_list); + if (ospf->ti_lfa_enabled) + ospf_ti_lfa_compute(area, new_table, + ospf->ti_lfa_protection_type); + + ospf_spf_cleanup(area->spf, area->spf_vertex_list); } -int ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table, - struct route_table *new_rtrs, bool is_dry_run, - bool is_root_node) +void ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table, + struct route_table *new_rtrs) { struct ospf_area *area; struct listnode *node, *nnode; - int areas_processed = 0; /* Calculate SPF for each area. */ for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { @@ -1380,20 +1813,13 @@ int ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table, if (ospf->backbone && ospf->backbone == area) continue; - ospf_spf_calculate(area, area->router_lsa_self, new_table, - new_rtrs, is_dry_run, is_root_node); - areas_processed++; + ospf_spf_calculate_area(ospf, area, new_table, new_rtrs); } /* SPF for backbone, if required */ - if (ospf->backbone) { - area = ospf->backbone; - ospf_spf_calculate(area, area->router_lsa_self, new_table, - new_rtrs, is_dry_run, is_root_node); - areas_processed++; - } - - return areas_processed; + if (ospf->backbone) + ospf_spf_calculate_area(ospf, ospf->backbone, new_table, + new_rtrs); } /* Worker for SPF calculation scheduler. */ @@ -1402,7 +1828,6 @@ static int ospf_spf_calculate_schedule_worker(struct thread *thread) struct ospf *ospf = THREAD_ARG(thread); struct route_table *new_table, *new_rtrs; struct timeval start_time, spf_start_time; - int areas_processed; unsigned long ia_time, prune_time, rt_time; unsigned long abr_time, total_spf_time, spf_time; char rbuf[32]; /* reason_buf */ @@ -1418,8 +1843,7 @@ static int ospf_spf_calculate_schedule_worker(struct thread *thread) monotime(&spf_start_time); new_table = route_table_init(); /* routing table */ new_rtrs = route_table_init(); /* ABR/ASBR routing table */ - areas_processed = ospf_spf_calculate_areas(ospf, new_table, new_rtrs, - false, true); + ospf_spf_calculate_areas(ospf, new_table, new_rtrs); spf_time = monotime_since(&spf_start_time, NULL); ospf_vl_shut_unapproved(ospf); @@ -1512,7 +1936,7 @@ static int ospf_spf_calculate_schedule_worker(struct thread *thread) zlog_info(" RouteInstall: %ld", rt_time); if (IS_OSPF_ABR(ospf)) zlog_info(" ABR: %ld (%d areas)", - abr_time, areas_processed); + abr_time, ospf->areas->count); zlog_info("Reason(s) for SPF: %s", rbuf); } |
