diff options
author | whitespace / reindent <invalid@invalid.invalid> | 2017-07-17 14:03:14 +0200 |
---|---|---|
committer | whitespace / reindent <invalid@invalid.invalid> | 2017-07-17 14:04:07 +0200 |
commit | d62a17aedeb0eebdba98238874bb13d62c48dbf9 (patch) | |
tree | 3b319b1d61c8b85b4d1f06adf8b844bb8a9b5107 /ospfd/ospf_spf.c | |
parent | *: add indent control files (diff) | |
download | frr-d62a17aedeb0eebdba98238874bb13d62c48dbf9.tar.xz frr-d62a17aedeb0eebdba98238874bb13d62c48dbf9.zip |
*: reindentreindent-master-after
indent.py `git ls-files | pcregrep '\.[ch]$' | pcregrep -v '^(ldpd|babeld|nhrpd)/'`
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'ospfd/ospf_spf.c')
-rw-r--r-- | ospfd/ospf_spf.c | 2371 |
1 files changed, 1185 insertions, 1186 deletions
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 173c4e91d..c520a3126 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -29,7 +29,7 @@ #include "if.h" #include "table.h" #include "log.h" -#include "sockunion.h" /* for inet_ntop () */ +#include "sockunion.h" /* for inet_ntop () */ #include "pqueue.h" #include "ospfd/ospfd.h" @@ -51,326 +51,304 @@ static unsigned int spf_reason_flags = 0; -static void -ospf_clear_spf_reason_flags (void) +static void ospf_clear_spf_reason_flags(void) { - spf_reason_flags = 0; + spf_reason_flags = 0; } -static void -ospf_spf_set_reason (ospf_spf_reason_t reason) +static void ospf_spf_set_reason(ospf_spf_reason_t reason) { - spf_reason_flags |= 1 << reason; + spf_reason_flags |= 1 << reason; } -static void ospf_vertex_free (void *); +static void ospf_vertex_free(void *); /* List of allocated vertices, to simplify cleanup of SPF. * Not thread-safe obviously. If it ever needs to be, it'd have to be * dynamically allocated at begin of ospf_spf_calculate */ -static struct list vertex_list = { .del = ospf_vertex_free }; +static struct list vertex_list = {.del = ospf_vertex_free}; /* Heap related functions, for the managment of the candidates, to * be used with pqueue. */ -static int -cmp (void * node1 , void * node2) +static int cmp(void *node1, void *node2) { - struct vertex * v1 = (struct vertex *) node1; - struct vertex * v2 = (struct vertex *) node2; - if (v1 != NULL && v2 != NULL ) - { - /* network vertices must be chosen before router vertices of same - * cost in order to find all shortest paths - */ - if ( ((v1->distance - v2->distance) == 0) - && (v1->type != v2->type)) - { - switch (v1->type) - { - case OSPF_VERTEX_NETWORK: - return -1; - case OSPF_VERTEX_ROUTER: - return 1; - } - } - else - return (v1->distance - v2->distance); - } - return 0; + struct vertex *v1 = (struct vertex *)node1; + struct vertex *v2 = (struct vertex *)node2; + if (v1 != NULL && v2 != NULL) { + /* network vertices must be chosen before router vertices of + * same + * cost in order to find all shortest paths + */ + if (((v1->distance - v2->distance) == 0) + && (v1->type != v2->type)) { + switch (v1->type) { + case OSPF_VERTEX_NETWORK: + return -1; + case OSPF_VERTEX_ROUTER: + return 1; + } + } else + return (v1->distance - v2->distance); + } + return 0; } -static void -update_stat (void *node , int position) +static void update_stat(void *node, int position) { - struct vertex *v = node; + struct vertex *v = node; - /* Set the status of the vertex, when its position changes. */ - *(v->stat) = position; + /* Set the status of the vertex, when its position changes. */ + *(v->stat) = position; } -static struct vertex_nexthop * -vertex_nexthop_new (void) +static struct vertex_nexthop *vertex_nexthop_new(void) { - return XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop)); + return XCALLOC(MTYPE_OSPF_NEXTHOP, sizeof(struct vertex_nexthop)); } -static void -vertex_nexthop_free (struct vertex_nexthop *nh) +static void vertex_nexthop_free(struct vertex_nexthop *nh) { - XFREE (MTYPE_OSPF_NEXTHOP, nh); + XFREE(MTYPE_OSPF_NEXTHOP, nh); } /* Free the canonical nexthop objects for an area, ie the nexthop objects * attached to the first-hop router vertices, and any intervening network * vertices. */ -static void -ospf_canonical_nexthops_free (struct vertex *root) +static void ospf_canonical_nexthops_free(struct vertex *root) { - struct listnode *node, *nnode; - struct vertex *child; - - for (ALL_LIST_ELEMENTS (root->children, node, nnode, child)) - { - struct listnode *n2, *nn2; - struct vertex_parent *vp; - - /* router vertices through an attached network each - * have a distinct (canonical / not inherited) nexthop - * which must be freed. - * - * A network vertex can only have router vertices as its - * children, so only one level of recursion is possible. - */ - if (child->type == OSPF_VERTEX_NETWORK) - ospf_canonical_nexthops_free (child); - - /* Free child nexthops pointing back to this root vertex */ - for (ALL_LIST_ELEMENTS (child->parents, n2, nn2, vp)) - if (vp->parent == root && vp->nexthop) - vertex_nexthop_free (vp->nexthop); - } -} + struct listnode *node, *nnode; + struct vertex *child; + + for (ALL_LIST_ELEMENTS(root->children, node, nnode, child)) { + struct listnode *n2, *nn2; + struct vertex_parent *vp; + + /* router vertices through an attached network each + * have a distinct (canonical / not inherited) nexthop + * which must be freed. + * + * A network vertex can only have router vertices as its + * children, so only one level of recursion is possible. + */ + if (child->type == OSPF_VERTEX_NETWORK) + ospf_canonical_nexthops_free(child); + + /* Free child nexthops pointing back to this root vertex */ + for (ALL_LIST_ELEMENTS(child->parents, n2, nn2, vp)) + if (vp->parent == root && vp->nexthop) + vertex_nexthop_free(vp->nexthop); + } +} /* TODO: Parent list should be excised, in favour of maintaining only * vertex_nexthop, with refcounts. */ -static struct vertex_parent * -vertex_parent_new (struct vertex *v, int backlink, struct vertex_nexthop *hop) +static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink, + struct vertex_nexthop *hop) { - struct vertex_parent *new; - - new = XMALLOC (MTYPE_OSPF_VERTEX_PARENT, sizeof (struct vertex_parent)); - - if (new == NULL) - return NULL; - - new->parent = v; - new->backlink = backlink; - new->nexthop = hop; - return new; + struct vertex_parent *new; + + new = XMALLOC(MTYPE_OSPF_VERTEX_PARENT, sizeof(struct vertex_parent)); + + if (new == NULL) + return NULL; + + new->parent = v; + new->backlink = backlink; + new->nexthop = hop; + return new; } -static void -vertex_parent_free (void *p) +static void vertex_parent_free(void *p) { - XFREE (MTYPE_OSPF_VERTEX_PARENT, p); + XFREE(MTYPE_OSPF_VERTEX_PARENT, p); } -static struct vertex * -ospf_vertex_new (struct ospf_lsa *lsa) +static struct vertex *ospf_vertex_new(struct ospf_lsa *lsa) { - struct vertex *new; - - new = XCALLOC (MTYPE_OSPF_VERTEX, sizeof (struct vertex)); - - new->flags = 0; - new->stat = &(lsa->stat); - new->type = lsa->data->type; - new->id = lsa->data->id; - new->lsa = lsa->data; - new->children = list_new (); - new->parents = list_new (); - new->parents->del = vertex_parent_free; - - listnode_add (&vertex_list, new); - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("%s: Created %s vertex %s", __func__, - new->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", - inet_ntoa (new->lsa->id)); - return new; + struct vertex *new; + + new = XCALLOC(MTYPE_OSPF_VERTEX, sizeof(struct vertex)); + + new->flags = 0; + new->stat = &(lsa->stat); + new->type = lsa->data->type; + new->id = lsa->data->id; + new->lsa = lsa->data; + new->children = list_new(); + new->parents = list_new(); + new->parents->del = vertex_parent_free; + + listnode_add(&vertex_list, new); + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Created %s vertex %s", __func__, + new->type == OSPF_VERTEX_ROUTER ? "Router" + : "Network", + inet_ntoa(new->lsa->id)); + return new; } -static void -ospf_vertex_free (void *data) +static void ospf_vertex_free(void *data) { - struct vertex *v = data; - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("%s: Free %s vertex %s", __func__, - v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", - inet_ntoa (v->lsa->id)); - - /* There should be no parents potentially holding references to this vertex - * Children however may still be there, but presumably referenced by other - * vertices - */ - //assert (listcount (v->parents) == 0); - - if (v->children) - list_delete (v->children); - v->children = NULL; - - if (v->parents) - list_delete (v->parents); - v->parents = NULL; - - v->lsa = NULL; - - XFREE (MTYPE_OSPF_VERTEX, v); + struct vertex *v = data; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Free %s vertex %s", __func__, + v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", + inet_ntoa(v->lsa->id)); + + /* There should be no parents potentially holding references to this + * vertex + * Children however may still be there, but presumably referenced by + * other + * vertices + */ + // assert (listcount (v->parents) == 0); + + if (v->children) + list_delete(v->children); + v->children = NULL; + + if (v->parents) + list_delete(v->parents); + v->parents = NULL; + + v->lsa = NULL; + + XFREE(MTYPE_OSPF_VERTEX, v); } -static void -ospf_vertex_dump(const char *msg, struct vertex *v, - int print_parents, int print_children) +static void ospf_vertex_dump(const char *msg, struct vertex *v, + int print_parents, int print_children) { - if ( ! IS_DEBUG_OSPF_EVENT) - return; - - zlog_debug("%s %s vertex %s distance %u flags %u", - msg, - v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", - inet_ntoa(v->lsa->id), - v->distance, - (unsigned int)v->flags); - - if (print_parents) - { - struct listnode *node; - struct vertex_parent *vp; - - for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) - { - char buf1[BUFSIZ]; - - if (vp) - { - zlog_debug ("parent %s backlink %d nexthop %s interface %s", - inet_ntoa(vp->parent->lsa->id), vp->backlink, - inet_ntop(AF_INET, &vp->nexthop->router, buf1, BUFSIZ), - vp->nexthop->oi ? IF_NAME(vp->nexthop->oi) : "NULL"); - } + if (!IS_DEBUG_OSPF_EVENT) + return; + + zlog_debug("%s %s vertex %s distance %u flags %u", msg, + v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", + inet_ntoa(v->lsa->id), v->distance, (unsigned int)v->flags); + + if (print_parents) { + struct listnode *node; + struct vertex_parent *vp; + + for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) { + char buf1[BUFSIZ]; + + if (vp) { + zlog_debug( + "parent %s backlink %d nexthop %s interface %s", + inet_ntoa(vp->parent->lsa->id), + vp->backlink, + inet_ntop(AF_INET, &vp->nexthop->router, + buf1, BUFSIZ), + vp->nexthop->oi + ? IF_NAME(vp->nexthop->oi) + : "NULL"); + } + } + } + + if (print_children) { + struct listnode *cnode; + struct vertex *cv; + + for (ALL_LIST_ELEMENTS_RO(v->children, cnode, cv)) + ospf_vertex_dump(" child:", cv, 0, 0); } - } - - if (print_children) - { - struct listnode *cnode; - struct vertex *cv; - - for (ALL_LIST_ELEMENTS_RO (v->children, cnode, cv)) - ospf_vertex_dump(" child:", cv, 0, 0); - } } /* Add a vertex to the list of children in each of its parents. */ -static void -ospf_vertex_add_parent (struct vertex *v) +static void ospf_vertex_add_parent(struct vertex *v) { - struct vertex_parent *vp; - struct listnode *node; - - assert (v && v->parents); - - for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) - { - assert (vp->parent && vp->parent->children); - - /* No need to add two links from the same parent. */ - if (listnode_lookup (vp->parent->children, v) == NULL) - listnode_add (vp->parent->children, v); - } + struct vertex_parent *vp; + struct listnode *node; + + assert(v && v->parents); + + for (ALL_LIST_ELEMENTS_RO(v->parents, node, vp)) { + assert(vp->parent && vp->parent->children); + + /* No need to add two links from the same parent. */ + if (listnode_lookup(vp->parent->children, v) == NULL) + listnode_add(vp->parent->children, v); + } } -static void -ospf_spf_init (struct ospf_area *area) +static void ospf_spf_init(struct ospf_area *area) { - struct vertex *v; - - /* Create root node. */ - v = ospf_vertex_new (area->router_lsa_self); - - area->spf = v; - - /* Reset ABR and ASBR router counts. */ - area->abr_count = 0; - area->asbr_count = 0; + struct vertex *v; + + /* Create root node. */ + v = ospf_vertex_new(area->router_lsa_self); + + area->spf = v; + + /* Reset ABR and ASBR router counts. */ + area->abr_count = 0; + area->asbr_count = 0; } /* return index of link back to V from W, or -1 if no link found */ -static int -ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v) +static int ospf_lsa_has_link(struct lsa_header *w, struct lsa_header *v) { - unsigned int i, length; - struct router_lsa *rl; - struct network_lsa *nl; - - /* In case of W is Network LSA. */ - if (w->type == OSPF_NETWORK_LSA) - { - if (v->type == OSPF_NETWORK_LSA) - return -1; - - nl = (struct network_lsa *) w; - length = (ntohs (w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4; - - for (i = 0; i < length; i++) - if (IPV4_ADDR_SAME (&nl->routers[i], &v->id)) - return i; - return -1; - } - - /* In case of W is Router LSA. */ - if (w->type == OSPF_ROUTER_LSA) - { - rl = (struct router_lsa *) w; - - length = ntohs (w->length); - - for (i = 0; - i < ntohs (rl->links) && length >= sizeof (struct router_lsa); - i++, length -= 12) - { - switch (rl->link[i].type) - { - case LSA_LINK_TYPE_POINTOPOINT: - case LSA_LINK_TYPE_VIRTUALLINK: - /* Router LSA ID. */ - if (v->type == OSPF_ROUTER_LSA && - IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) - { - return i; - } - break; - case LSA_LINK_TYPE_TRANSIT: - /* Network LSA ID. */ - if (v->type == OSPF_NETWORK_LSA && - IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) - { - return i; - } - break; - case LSA_LINK_TYPE_STUB: - /* Stub can't lead anywhere, carry on */ - continue; - default: - break; - } - } - } - return -1; + unsigned int i, length; + struct router_lsa *rl; + struct network_lsa *nl; + + /* In case of W is Network LSA. */ + if (w->type == OSPF_NETWORK_LSA) { + if (v->type == OSPF_NETWORK_LSA) + return -1; + + nl = (struct network_lsa *)w; + length = (ntohs(w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4; + + for (i = 0; i < length; i++) + if (IPV4_ADDR_SAME(&nl->routers[i], &v->id)) + return i; + return -1; + } + + /* In case of W is Router LSA. */ + if (w->type == OSPF_ROUTER_LSA) { + rl = (struct router_lsa *)w; + + length = ntohs(w->length); + + for (i = 0; i < ntohs(rl->links) + && length >= sizeof(struct router_lsa); + i++, length -= 12) { + switch (rl->link[i].type) { + case LSA_LINK_TYPE_POINTOPOINT: + case LSA_LINK_TYPE_VIRTUALLINK: + /* Router LSA ID. */ + if (v->type == OSPF_ROUTER_LSA + && IPV4_ADDR_SAME(&rl->link[i].link_id, + &v->id)) { + return i; + } + break; + case LSA_LINK_TYPE_TRANSIT: + /* Network LSA ID. */ + if (v->type == OSPF_NETWORK_LSA + && IPV4_ADDR_SAME(&rl->link[i].link_id, + &v->id)) { + return i; + } + break; + case LSA_LINK_TYPE_STUB: + /* Stub can't lead anywhere, carry on */ + continue; + default: + break; + } + } + } + return -1; } /* Find the next link after prev_link from v to w. If prev_link is @@ -378,119 +356,117 @@ ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v) * these link types will never be returned. */ static struct router_lsa_link * -ospf_get_next_link (struct vertex *v, struct vertex *w, - struct router_lsa_link *prev_link) +ospf_get_next_link(struct vertex *v, struct vertex *w, + struct router_lsa_link *prev_link) { - u_char *p; - u_char *lim; - u_char lsa_type = LSA_LINK_TYPE_TRANSIT; - struct router_lsa_link *l; - - if (w->type == OSPF_VERTEX_ROUTER) - lsa_type = LSA_LINK_TYPE_POINTOPOINT; - - if (prev_link == NULL) - p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; - else - { - p = (u_char *) prev_link; - p += (OSPF_ROUTER_LSA_LINK_SIZE + - (prev_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); - } + u_char *p; + u_char *lim; + u_char lsa_type = LSA_LINK_TYPE_TRANSIT; + struct router_lsa_link *l; + + if (w->type == OSPF_VERTEX_ROUTER) + lsa_type = LSA_LINK_TYPE_POINTOPOINT; + + if (prev_link == NULL) + p = ((u_char *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4; + else { + p = (u_char *)prev_link; + p += (OSPF_ROUTER_LSA_LINK_SIZE + + (prev_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); + } - lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); + lim = ((u_char *)v->lsa) + ntohs(v->lsa->length); - while (p < lim) - { - l = (struct router_lsa_link *) p; + 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)); + p += (OSPF_ROUTER_LSA_LINK_SIZE + + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); - if (l->m[0].type != lsa_type) - continue; + if (l->m[0].type != lsa_type) + continue; - if (IPV4_ADDR_SAME (&l->link_id, &w->id)) - return l; - } + if (IPV4_ADDR_SAME(&l->link_id, &w->id)) + return l; + } - return NULL; + return NULL; } -static void -ospf_spf_flush_parents (struct vertex *w) +static void ospf_spf_flush_parents(struct vertex *w) { - struct vertex_parent *vp; - struct listnode *ln, *nn; - - /* delete the existing nexthops */ - for (ALL_LIST_ELEMENTS (w->parents, ln, nn, vp)) - { - list_delete_node (w->parents, ln); - vertex_parent_free (vp); - } + struct vertex_parent *vp; + struct listnode *ln, *nn; + + /* delete the existing nexthops */ + for (ALL_LIST_ELEMENTS(w->parents, ln, nn, vp)) { + list_delete_node(w->parents, ln); + vertex_parent_free(vp); + } } -/* +/* * Consider supplied next-hop for inclusion to the supplied list of - * equal-cost next-hops, adjust list as neccessary. + * equal-cost next-hops, adjust list as neccessary. */ -static void -ospf_spf_add_parent (struct vertex *v, struct vertex *w, - struct vertex_nexthop *newhop, - unsigned int distance) +static void ospf_spf_add_parent(struct vertex *v, struct vertex *w, + struct vertex_nexthop *newhop, + unsigned int distance) { - struct vertex_parent *vp, *wp; - struct listnode *node; - - /* we must have a newhop, and a distance */ - assert (v && w && newhop); - assert (distance); - - /* IFF w has already been assigned a distance, then we shouldn't get here - * unless callers have determined V(l)->W is shortest / equal-shortest - * path (0 is a special case distance (no distance yet assigned)). - */ - if (w->distance) - assert (distance <= w->distance); - else - w->distance = distance; - - if (IS_DEBUG_OSPF_EVENT) - { - char buf[2][INET_ADDRSTRLEN]; - zlog_debug ("%s: Adding %s as parent of %s", - __func__, - inet_ntop(AF_INET, &v->lsa->id, buf[0], sizeof(buf[0])), - inet_ntop(AF_INET, &w->lsa->id, buf[1], sizeof(buf[1]))); - } - - /* Adding parent for a new, better path: flush existing parents from W. */ - if (distance < w->distance) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("%s: distance %d better than %d, flushing existing parents", - __func__, distance, w->distance); - ospf_spf_flush_parents (w); - w->distance = distance; - } - - /* new parent is <= existing parents, add it to parent list (if nexthop - * not on parent list) - */ - for (ALL_LIST_ELEMENTS_RO(w->parents, node, wp)) - { - if (memcmp(newhop, wp->nexthop, sizeof(*newhop)) == 0) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("%s: ... nexthop already on parent list, skipping add", __func__); - return; - } - } + struct vertex_parent *vp, *wp; + struct listnode *node; + + /* we must have a newhop, and a distance */ + assert(v && w && newhop); + assert(distance); + + /* IFF w has already been assigned a distance, then we shouldn't get + * here + * unless callers have determined V(l)->W is shortest / equal-shortest + * path (0 is a special case distance (no distance yet assigned)). + */ + if (w->distance) + assert(distance <= w->distance); + else + w->distance = distance; + + if (IS_DEBUG_OSPF_EVENT) { + char buf[2][INET_ADDRSTRLEN]; + zlog_debug( + "%s: Adding %s as parent of %s", __func__, + inet_ntop(AF_INET, &v->lsa->id, buf[0], sizeof(buf[0])), + inet_ntop(AF_INET, &w->lsa->id, buf[1], + sizeof(buf[1]))); + } + + /* Adding parent for a new, better path: flush existing parents from W. + */ + if (distance < w->distance) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "%s: distance %d better than %d, flushing existing parents", + __func__, distance, w->distance); + ospf_spf_flush_parents(w); + w->distance = distance; + } + + /* new parent is <= existing parents, add it to parent list (if nexthop + * not on parent list) + */ + for (ALL_LIST_ELEMENTS_RO(w->parents, node, wp)) { + if (memcmp(newhop, wp->nexthop, sizeof(*newhop)) == 0) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "%s: ... nexthop already on parent list, skipping add", + __func__); + return; + } + } - vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop); - listnode_add (w->parents, vp); + vp = vertex_parent_new(v, ospf_lsa_has_link(w->lsa, v->lsa), newhop); + listnode_add(w->parents, vp); - return; + return; } /* 16.1.1. Calculate nexthop from root through V (parent) to @@ -504,256 +480,298 @@ ospf_spf_add_parent (struct vertex *v, struct vertex *w, * this function returns. This function will update the W vertex with the * provided distance as appropriate. */ -static unsigned int -ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, - struct vertex *w, struct router_lsa_link *l, - unsigned int distance, int lsa_pos) +static unsigned int ospf_nexthop_calculation(struct ospf_area *area, + struct vertex *v, struct vertex *w, + struct router_lsa_link *l, + unsigned int distance, int lsa_pos) { - struct listnode *node, *nnode; - struct vertex_nexthop *nh; - struct vertex_parent *vp; - struct ospf_interface *oi = NULL; - unsigned int added = 0; - char buf1[BUFSIZ]; - char buf2[BUFSIZ]; - - if (IS_DEBUG_OSPF_EVENT) - { - zlog_debug ("ospf_nexthop_calculation(): Start"); - ospf_vertex_dump("V (parent):", v, 1, 1); - ospf_vertex_dump("W (dest) :", w, 1, 1); - zlog_debug ("V->W distance: %d", distance); - } - - if (v == area->spf) - { - /* 16.1.1 para 4. In the first case, the parent vertex (V) is the - root (the calculating router itself). This means that the - destination is either a directly connected network or directly - connected router. The outgoing interface in this case is simply - the OSPF interface connecting to the destination network/router. - */ - - /* we *must* be supplied with the link data */ - assert (l != NULL); - 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 (IS_DEBUG_OSPF_EVENT) - { - zlog_debug("%s: considering link:%s " - "type:%d link_id:%s link_data:%s", - __func__, oi->ifp->name, l->m[0].type, - inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ), - inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ)); + struct listnode *node, *nnode; + struct vertex_nexthop *nh; + struct vertex_parent *vp; + struct ospf_interface *oi = NULL; + unsigned int added = 0; + char buf1[BUFSIZ]; + char buf2[BUFSIZ]; + + if (IS_DEBUG_OSPF_EVENT) { + zlog_debug("ospf_nexthop_calculation(): Start"); + ospf_vertex_dump("V (parent):", v, 1, 1); + ospf_vertex_dump("W (dest) :", w, 1, 1); + zlog_debug("V->W distance: %d", distance); } - if (w->type == OSPF_VERTEX_ROUTER) - { - /* l is a link from v to w - * l2 will be link from w to v - */ - struct router_lsa_link *l2 = NULL; - - if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) - { - struct in_addr nexthop = { .s_addr = 0 }; - - /* If the destination is a router which connects to - the calculating router via a Point-to-MultiPoint - network, the destination's next hop IP address(es) - can be determined by examining the destination's - router-LSA: each link pointing back to the - calculating router and having a Link Data field - belonging to the Point-to-MultiPoint network - provides an IP address of the next hop router. - - At this point l is a link from V to W, and V is the - root ("us"). If it is a point-to-multipoint interface, - then look through the links in the opposite direction (W to V). - If any of them have an address that lands within the - subnet declared by the PtMP link, then that link - is a constituent of the PtMP link, and its address is - a nexthop address for V. - */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT) - { - /* Having nexthop = 0 is tempting, but NOT acceptable. - It breaks AS-External routes with a forwarding address, - since ospf_ase_complete_direct_routes() will mistakenly - assume we've reached the last hop and should place the - forwarding address as nexthop. - Also, users may configure multi-access links in p2p mode, - so we need the IP to ARP the nexthop. - */ - struct ospf_neighbor *nbr_w; - - nbr_w = ospf_nbr_lookup_by_routerid (oi->nbrs, &l->link_id); - if (nbr_w != NULL) - { - added = 1; - nexthop = nbr_w->src; - } + if (v == area->spf) { + /* 16.1.1 para 4. In the first case, the parent vertex (V) is + the + root (the calculating router itself). This means that the + destination is either a directly connected network or + directly + connected router. The outgoing interface in this case is + simply + the OSPF interface connecting to the destination + network/router. + */ + + /* we *must* be supplied with the link data */ + assert(l != NULL); + 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; } - else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) - { - struct prefix_ipv4 la; - - la.family = AF_INET; - la.prefixlen = oi->address->prefixlen; - /* V links to W on PtMP interface - - find the interface address on W */ - while ((l2 = ospf_get_next_link (w, v, l2))) - { - la.prefix = l2->link_data; + if (IS_DEBUG_OSPF_EVENT) { + zlog_debug( + "%s: considering link:%s " + "type:%d link_id:%s link_data:%s", + __func__, oi->ifp->name, l->m[0].type, + inet_ntop(AF_INET, &l->link_id, buf1, BUFSIZ), + inet_ntop(AF_INET, &l->link_data, buf2, + BUFSIZ)); + } - if (prefix_cmp ((struct prefix *) &la, - oi->address) != 0) - continue; - /* link_data is on our PtMP network */ - added = 1; - nexthop = l2->link_data; - break; - } + if (w->type == OSPF_VERTEX_ROUTER) { + /* l is a link from v to w + * l2 will be link from w to v + */ + struct router_lsa_link *l2 = NULL; + + if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) { + struct in_addr nexthop = {.s_addr = 0}; + + /* If the destination is a router which connects + to + the calculating router via a + Point-to-MultiPoint + network, the destination's next hop IP + address(es) + can be determined by examining the + destination's + router-LSA: each link pointing back to the + calculating router and having a Link Data + field + belonging to the Point-to-MultiPoint network + provides an IP address of the next hop + router. + + At this point l is a link from V to W, and V + is the + root ("us"). If it is a point-to-multipoint + interface, + then look through the links in the opposite + direction (W to V). + If any of them have an address that lands + within the + subnet declared by the PtMP link, then that + link + is a constituent of the PtMP link, and its + address is + a nexthop address for V. + */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT) { + /* Having nexthop = 0 is tempting, but + NOT acceptable. + It breaks AS-External routes with a + forwarding address, + since + ospf_ase_complete_direct_routes() + will mistakenly + assume we've reached the last hop and + should place the + forwarding address as nexthop. + Also, users may configure + multi-access links in p2p mode, + so we need the IP to ARP the nexthop. + */ + struct ospf_neighbor *nbr_w; + + nbr_w = ospf_nbr_lookup_by_routerid( + oi->nbrs, &l->link_id); + if (nbr_w != NULL) { + added = 1; + nexthop = nbr_w->src; + } + } else if (oi->type + == OSPF_IFTYPE_POINTOMULTIPOINT) { + struct prefix_ipv4 la; + + la.family = AF_INET; + la.prefixlen = oi->address->prefixlen; + + /* V links to W on PtMP interface + - find the interface address on W */ + while ((l2 = ospf_get_next_link(w, v, + l2))) { + la.prefix = l2->link_data; + + if (prefix_cmp((struct prefix + *)&la, + oi->address) + != 0) + continue; + /* link_data is on our PtMP + * network */ + added = 1; + nexthop = l2->link_data; + break; + } + } + + if (added) { + /* found all necessary info to build + * nexthop */ + nh = vertex_nexthop_new(); + nh->oi = oi; + nh->router = nexthop; + ospf_spf_add_parent(v, w, nh, distance); + return 1; + } else + zlog_info( + "%s: could not determine nexthop for link %s", + __func__, oi->ifp->name); + } /* end point-to-point link from V to W */ + else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) { + struct ospf_vl_data *vl_data; + + /* VLink implementation limitations: + * a) vl_data can only reference one nexthop, so + * no ECMP + * to backbone through VLinks. Though + * transit-area + * summaries may be considered, and those can + * be ECMP. + * b) We can only use /one/ VLink, even if + * multiple ones + * exist this router through multiple + * transit-areas. + */ + vl_data = ospf_vl_lookup(area->ospf, NULL, + l->link_id); + + if (vl_data + && CHECK_FLAG(vl_data->flags, + OSPF_VL_FLAG_APPROVED)) { + nh = vertex_nexthop_new(); + nh->oi = vl_data->nexthop.oi; + nh->router = vl_data->nexthop.router; + ospf_spf_add_parent(v, w, nh, distance); + return 1; + } else + zlog_info( + "ospf_nexthop_calculation(): " + "vl_data for VL link not found"); + } /* end virtual-link from V to W */ + return 0; + } /* end W is a Router vertex */ + else { + assert(w->type == OSPF_VERTEX_NETWORK); + + nh = vertex_nexthop_new(); + nh->oi = oi; + nh->router.s_addr = 0; /* Nexthop not required */ + ospf_spf_add_parent(v, w, nh, distance); + return 1; + } + } /* end V is the root */ + /* Check if W's parent is a network connected to root. */ + else if (v->type == OSPF_VERTEX_NETWORK) { + /* See if any of V's parents are the root. */ + for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) { + if (vp->parent == area->spf) /* connects to root? */ + { + /* 16.1.1 para 5. ...the parent vertex is a + * network that + * directly connects the calculating router to + * the destination + * router. The list of next hops is then + * determined by + * examining the destination's router-LSA... + */ + + assert(w->type == OSPF_VERTEX_ROUTER); + while ((l = ospf_get_next_link(w, v, l))) { + /* ...For each link in the router-LSA + * that points back to the + * parent network, the link's Link Data + * field provides the IP + * address of a next hop router. The + * outgoing interface to + * use can then be derived from the next + * hop IP address (or + * it can be inherited from the parent + * network). + */ + nh = vertex_nexthop_new(); + nh->oi = vp->nexthop->oi; + nh->router = l->link_data; + added = 1; + ospf_spf_add_parent(v, w, nh, distance); + } + /* Note lack of return is deliberate. See next + * comment. */ + } } + /* NB: This code is non-trivial. + * + * E.g. it is not enough to know that V connects to the root. It + * is + * also important that the while above, looping through all + * links from + * W->V found at least one link, so that we know there is + * bi-directional connectivity between V and W (which need not + * be the + * case, e.g. when OSPF has not yet converged fully). + * Otherwise, if + * we /always/ return here, without having checked that + * root->V->-W + * actually resulted in a valid nexthop being created, then we + * we will + * prevent SPF from finding/using higher cost paths. + * + * It is important, if root->V->W has not been added, that we + * continue + * through to the intervening-router nexthop code below. So as + * to + * ensure other paths to V may be used. This avoids unnecessary + * blackholes while OSPF is convergening. + * + * I.e. we may have arrived at this function, examining V -> W, + * via + * workable paths other than root -> V, and it's important to + * avoid + * getting "confused" by non-working root->V->W path - it's + * important + * to *not* lose the working non-root paths, just because of a + * non-viable root->V->W. + * + * See also bug #330 (required reading!), and: + * + * http://blogs.oracle.com/paulj/entry/the_difference_a_line_makes + */ + if (added) + return added; + } - if (added) - { - /* found all necessary info to build nexthop */ - nh = vertex_nexthop_new (); - nh->oi = oi; - nh->router = nexthop; - ospf_spf_add_parent (v, w, nh, distance); - return 1; - } - else - zlog_info("%s: could not determine nexthop for link %s", - __func__, oi->ifp->name); - } /* end point-to-point link from V to W */ - else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) - { - struct ospf_vl_data *vl_data; - - /* VLink implementation limitations: - * a) vl_data can only reference one nexthop, so no ECMP - * to backbone through VLinks. Though transit-area - * summaries may be considered, and those can be ECMP. - * b) We can only use /one/ VLink, even if multiple ones - * exist this router through multiple transit-areas. - */ - vl_data = ospf_vl_lookup (area->ospf, NULL, l->link_id); - - if (vl_data - && CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED)) - { - nh = vertex_nexthop_new (); - nh->oi = vl_data->nexthop.oi; - nh->router = vl_data->nexthop.router; - ospf_spf_add_parent (v, w, nh, distance); - return 1; - } - else - zlog_info("ospf_nexthop_calculation(): " - "vl_data for VL link not found"); - } /* end virtual-link from V to W */ - return 0; - } /* end W is a Router vertex */ - else - { - assert(w->type == OSPF_VERTEX_NETWORK); + /* 16.1.1 para 4. If there is at least one intervening router in the + * current shortest path between the destination and the root, the + * destination simply inherits the set of next hops from the + * parent. + */ + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Intervening routers, adding parent(s)", + __func__); + + for (ALL_LIST_ELEMENTS(v->parents, node, nnode, vp)) { + added = 1; + ospf_spf_add_parent(v, w, vp->nexthop, distance); + } - nh = vertex_nexthop_new (); - nh->oi = oi; - nh->router.s_addr = 0; /* Nexthop not required */ - ospf_spf_add_parent (v, w, nh, distance); - return 1; - } - } /* end V is the root */ - /* Check if W's parent is a network connected to root. */ - else if (v->type == OSPF_VERTEX_NETWORK) - { - /* See if any of V's parents are the root. */ - for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp)) - { - if (vp->parent == area->spf) /* connects to root? */ - { - /* 16.1.1 para 5. ...the parent vertex is a network that - * directly connects the calculating router to the destination - * router. The list of next hops is then determined by - * examining the destination's router-LSA... - */ - - assert(w->type == OSPF_VERTEX_ROUTER); - while ((l = ospf_get_next_link (w, v, l))) - { - /* ...For each link in the router-LSA that points back to the - * parent network, the link's Link Data field provides the IP - * address of a next hop router. The outgoing interface to - * use can then be derived from the next hop IP address (or - * it can be inherited from the parent network). - */ - nh = vertex_nexthop_new (); - nh->oi = vp->nexthop->oi; - nh->router = l->link_data; - added = 1; - ospf_spf_add_parent (v, w, nh, distance); - } - /* Note lack of return is deliberate. See next comment. */ - } - } - /* NB: This code is non-trivial. - * - * E.g. it is not enough to know that V connects to the root. It is - * also important that the while above, looping through all links from - * W->V found at least one link, so that we know there is - * bi-directional connectivity between V and W (which need not be the - * case, e.g. when OSPF has not yet converged fully). Otherwise, if - * we /always/ return here, without having checked that root->V->-W - * actually resulted in a valid nexthop being created, then we we will - * prevent SPF from finding/using higher cost paths. - * - * It is important, if root->V->W has not been added, that we continue - * through to the intervening-router nexthop code below. So as to - * ensure other paths to V may be used. This avoids unnecessary - * blackholes while OSPF is convergening. - * - * I.e. we may have arrived at this function, examining V -> W, via - * workable paths other than root -> V, and it's important to avoid - * getting "confused" by non-working root->V->W path - it's important - * to *not* lose the working non-root paths, just because of a - * non-viable root->V->W. - * - * See also bug #330 (required reading!), and: - * - * http://blogs.oracle.com/paulj/entry/the_difference_a_line_makes - */ - if (added) - return added; - } - - /* 16.1.1 para 4. If there is at least one intervening router in the - * current shortest path between the destination and the root, the - * destination simply inherits the set of next hops from the - * parent. - */ - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("%s: Intervening routers, adding parent(s)", __func__); - - for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp)) - { - added = 1; - ospf_spf_add_parent (v, w, vp->nexthop, distance); - } - - return added; + return added; } /* RFC2328 Section 16.1 (2). @@ -761,329 +779,319 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, * of candidates with any vertices not already on the list. If a lower-cost * path is found to a vertex already on the candidate list, store the new cost. */ -static void -ospf_spf_next (struct vertex *v, struct ospf_area *area, - struct pqueue * candidate) +static void ospf_spf_next(struct vertex *v, struct ospf_area *area, + struct pqueue *candidate) { - struct ospf_lsa *w_lsa = NULL; - u_char *p; - u_char *lim; - struct router_lsa_link *l = NULL; - struct in_addr *r; - int type = 0, lsa_pos=-1, lsa_pos_next=0; - - /* If this is a router-LSA, and bit V of the router-LSA (see Section - A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */ - if (v->type == OSPF_VERTEX_ROUTER) - { - if (IS_ROUTER_LSA_VIRTUAL ((struct router_lsa *) v->lsa)) - area->transit = OSPF_TRANSIT_TRUE; - } - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("%s: Next vertex of %s vertex %s", - __func__, - v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", - inet_ntoa(v->lsa->id)); - - p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; - lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); - - while (p < lim) - { - struct vertex *w; - unsigned int distance; - - /* In case of V is Router-LSA. */ - if (v->lsa->type == OSPF_ROUTER_LSA) - { - l = (struct router_lsa_link *) p; - - lsa_pos = lsa_pos_next; /* LSA link position */ - lsa_pos_next++; - p += (OSPF_ROUTER_LSA_LINK_SIZE + - (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); - - /* (a) If this is a link to a stub network, examine the next - link in V's LSA. Links to stub networks will be - considered in the second stage of the shortest path - calculation. */ - if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB) - 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 database. */ - switch (type) - { - case LSA_LINK_TYPE_POINTOPOINT: - case LSA_LINK_TYPE_VIRTUALLINK: - if (type == LSA_LINK_TYPE_VIRTUALLINK) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("looking up LSA through VL: %s", - inet_ntoa (l->link_id)); - } + struct ospf_lsa *w_lsa = NULL; + u_char *p; + u_char *lim; + struct router_lsa_link *l = NULL; + struct in_addr *r; + int type = 0, lsa_pos = -1, lsa_pos_next = 0; + + /* If this is a router-LSA, and bit V of the router-LSA (see Section + A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */ + if (v->type == OSPF_VERTEX_ROUTER) { + if (IS_ROUTER_LSA_VIRTUAL((struct router_lsa *)v->lsa)) + area->transit = OSPF_TRANSIT_TRUE; + } - w_lsa = ospf_lsa_lookup (area, OSPF_ROUTER_LSA, l->link_id, - l->link_id); - if (w_lsa) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("found Router LSA %s", inet_ntoa (l->link_id)); - } - break; - case LSA_LINK_TYPE_TRANSIT: - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Looking up Network LSA, ID: %s", - inet_ntoa (l->link_id)); - w_lsa = ospf_lsa_lookup_by_id (area, OSPF_NETWORK_LSA, - l->link_id); - if (w_lsa) - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("found the LSA"); - break; - default: - zlog_warn ("Invalid LSA link type %d", type); - continue; - } - } - else - { - /* In case of V is Network-LSA. */ - r = (struct in_addr *) p; - p += sizeof (struct in_addr); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("%s: Next vertex of %s vertex %s", __func__, + v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", + inet_ntoa(v->lsa->id)); + + p = ((u_char *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4; + lim = ((u_char *)v->lsa) + ntohs(v->lsa->length); + + while (p < lim) { + struct vertex *w; + unsigned int distance; + + /* In case of V is Router-LSA. */ + if (v->lsa->type == OSPF_ROUTER_LSA) { + l = (struct router_lsa_link *)p; + + lsa_pos = lsa_pos_next; /* LSA link position */ + lsa_pos_next++; + p += (OSPF_ROUTER_LSA_LINK_SIZE + + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); + + /* (a) If this is a link to a stub network, examine the + next + link in V's LSA. Links to stub networks will be + considered in the second stage of the shortest path + calculation. */ + if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB) + 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 database. */ + switch (type) { + case LSA_LINK_TYPE_POINTOPOINT: + case LSA_LINK_TYPE_VIRTUALLINK: + if (type == LSA_LINK_TYPE_VIRTUALLINK) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "looking up LSA through VL: %s", + inet_ntoa(l->link_id)); + } + + w_lsa = ospf_lsa_lookup(area, OSPF_ROUTER_LSA, + l->link_id, l->link_id); + if (w_lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "found Router LSA %s", + inet_ntoa(l->link_id)); + } + break; + case LSA_LINK_TYPE_TRANSIT: + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "Looking up Network LSA, ID: %s", + inet_ntoa(l->link_id)); + w_lsa = ospf_lsa_lookup_by_id( + area, OSPF_NETWORK_LSA, l->link_id); + if (w_lsa) + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("found the LSA"); + break; + default: + zlog_warn("Invalid LSA link type %d", type); + continue; + } + } else { + /* In case of V is Network-LSA. */ + r = (struct in_addr *)p; + p += sizeof(struct in_addr); + + /* Lookup the vertex W's LSA. */ + w_lsa = ospf_lsa_lookup_by_id(area, OSPF_ROUTER_LSA, + *r); + if (w_lsa) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("found Router LSA %s", + inet_ntoa(w_lsa->data->id)); + } + } - /* Lookup the vertex W's LSA. */ - w_lsa = ospf_lsa_lookup_by_id (area, OSPF_ROUTER_LSA, *r); - if (w_lsa) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("found Router LSA %s", inet_ntoa (w_lsa->data->id)); - } - } + /* (b cont.) If the LSA does not exist, or its LS age is equal + to MaxAge, or it does not have a link back to vertex V, + examine the next link in V's LSA.[23] */ + if (w_lsa == NULL) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("No LSA found"); + continue; + } - /* (b cont.) If the LSA does not exist, or its LS age is equal - to MaxAge, or it does not have a link back to vertex V, - examine the next link in V's LSA.[23] */ - if (w_lsa == NULL) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("No LSA found"); - continue; - } + if (IS_LSA_MAXAGE(w_lsa)) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("LSA is MaxAge"); + continue; + } - if (IS_LSA_MAXAGE (w_lsa)) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("LSA is MaxAge"); - continue; - } + if (ospf_lsa_has_link(w_lsa->data, v->lsa) < 0) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("The LSA doesn't have a link back"); + continue; + } - if (ospf_lsa_has_link (w_lsa->data, v->lsa) < 0 ) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("The LSA doesn't have a link back"); - continue; - } + /* (c) If vertex W is already on the shortest-path tree, examine + the next link in the LSA. */ + if (w_lsa->stat == LSA_SPF_IN_SPFTREE) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("The LSA is already in SPF"); + continue; + } - /* (c) If vertex W is already on the shortest-path tree, examine - the next link in the LSA. */ - if (w_lsa->stat == LSA_SPF_IN_SPFTREE) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("The LSA is already in SPF"); - continue; - } + /* (d) Calculate the link state cost D of the resulting path + from the root to vertex W. D is equal to the sum of the link + state cost of the (already calculated) shortest path to + vertex V and the advertised cost of the link between vertices + V and W. If D is: */ + + /* calculate link cost D. */ + if (v->lsa->type == OSPF_ROUTER_LSA) + distance = v->distance + ntohs(l->m[0].metric); + else /* v is not a Router-LSA */ + distance = v->distance; + + /* Is there already vertex W in candidate list? */ + if (w_lsa->stat == LSA_SPF_NOT_EXPLORED) { + /* prepare vertex W. */ + w = ospf_vertex_new(w_lsa); + + /* Calculate nexthop to W. */ + if (ospf_nexthop_calculation(area, v, w, l, distance, + lsa_pos)) + pqueue_enqueue(w, candidate); + else if (IS_DEBUG_OSPF_EVENT) + zlog_debug("Nexthop Calc failed"); + } else if (w_lsa->stat >= 0) { + /* Get the vertex from candidates. */ + w = candidate->array[w_lsa->stat]; + + /* if D is greater than. */ + if (w->distance < distance) { + continue; + } + /* equal to. */ + else if (w->distance == distance) { + /* Found an equal-cost path to W. + * Calculate nexthop of to W from V. */ + ospf_nexthop_calculation(area, v, w, l, + distance, lsa_pos); + } + /* less than. */ + else { + /* Found a lower-cost path to W. + * nexthop_calculation is conditional, if it + * finds + * valid nexthop it will call spf_add_parents, + * which + * will flush the old parents + */ + if (ospf_nexthop_calculation(area, v, w, l, + distance, lsa_pos)) + /* Decrease the key of the node in the + * heap. + * trickle-sort it up towards root, just + * in case this + * node should now be the new root due + * the cost change. + * (next pqueu_{de,en}queue will fully + * re-heap the queue). + */ + trickle_up(w_lsa->stat, candidate); + } + } /* end W is already on the candidate list */ + } /* end loop over the links in V's LSA */ +} - /* (d) Calculate the link state cost D of the resulting path - from the root to vertex W. D is equal to the sum of the link - state cost of the (already calculated) shortest path to - vertex V and the advertised cost of the link between vertices - V and W. If D is: */ - - /* calculate link cost D. */ - if (v->lsa->type == OSPF_ROUTER_LSA) - distance = v->distance + ntohs (l->m[0].metric); - else /* v is not a Router-LSA */ - distance = v->distance; - - /* Is there already vertex W in candidate list? */ - if (w_lsa->stat == LSA_SPF_NOT_EXPLORED) - { - /* prepare vertex W. */ - w = ospf_vertex_new (w_lsa); - - /* Calculate nexthop to W. */ - if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) - pqueue_enqueue (w, candidate); - else if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Nexthop Calc failed"); +static void ospf_spf_dump(struct vertex *v, int i) +{ + struct listnode *cnode; + struct listnode *nnode; + struct vertex_parent *parent; + + if (v->type == OSPF_VERTEX_ROUTER) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("SPF Result: %d [R] %s", i, + inet_ntoa(v->lsa->id)); + } else { + struct network_lsa *lsa = (struct network_lsa *)v->lsa; + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("SPF Result: %d [N] %s/%d", i, + inet_ntoa(v->lsa->id), + ip_masklen(lsa->mask)); } - else if (w_lsa->stat >= 0) - { - /* Get the vertex from candidates. */ - w = candidate->array[w_lsa->stat]; - /* if D is greater than. */ - if (w->distance < distance) - { - continue; - } - /* equal to. */ - else if (w->distance == distance) - { - /* Found an equal-cost path to W. - * Calculate nexthop of to W from V. */ - ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos); - } - /* less than. */ - else - { - /* Found a lower-cost path to W. - * nexthop_calculation is conditional, if it finds - * valid nexthop it will call spf_add_parents, which - * will flush the old parents - */ - if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) - /* Decrease the key of the node in the heap. - * trickle-sort it up towards root, just in case this - * node should now be the new root due the cost change. - * (next pqueu_{de,en}queue will fully re-heap the queue). - */ - trickle_up (w_lsa->stat, candidate); - } - } /* end W is already on the candidate list */ - } /* end loop over the links in V's LSA */ -} + if (IS_DEBUG_OSPF_EVENT) + for (ALL_LIST_ELEMENTS_RO(v->parents, nnode, parent)) { + zlog_debug(" nexthop %p %s %s", (void *)parent->nexthop, + inet_ntoa(parent->nexthop->router), + parent->nexthop->oi + ? IF_NAME(parent->nexthop->oi) + : "NULL"); + } -static void -ospf_spf_dump (struct vertex *v, int i) -{ - struct listnode *cnode; - struct listnode *nnode; - struct vertex_parent *parent; - - if (v->type == OSPF_VERTEX_ROUTER) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("SPF Result: %d [R] %s", i, inet_ntoa (v->lsa->id)); - } - else - { - struct network_lsa *lsa = (struct network_lsa *) v->lsa; - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("SPF Result: %d [N] %s/%d", i, inet_ntoa (v->lsa->id), - ip_masklen (lsa->mask)); - } + i++; - if (IS_DEBUG_OSPF_EVENT) - for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent)) - { - zlog_debug (" nexthop %p %s %s", - (void *)parent->nexthop, - inet_ntoa (parent->nexthop->router), - parent->nexthop->oi ? IF_NAME(parent->nexthop->oi) - : "NULL"); - } - - i++; - - for (ALL_LIST_ELEMENTS_RO (v->children, cnode, v)) - ospf_spf_dump (v, i); + for (ALL_LIST_ELEMENTS_RO(v->children, cnode, v)) + ospf_spf_dump(v, i); } /* Second stage of SPF calculation. */ -static void -ospf_spf_process_stubs (struct ospf_area *area, struct vertex *v, - struct route_table *rt, - int parent_is_root) +static void ospf_spf_process_stubs(struct ospf_area *area, struct vertex *v, + struct route_table *rt, int parent_is_root) { - struct listnode *cnode, *cnnode; - struct vertex *child; + struct listnode *cnode, *cnnode; + struct vertex *child; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("ospf_process_stub():processing stubs for area %s", + inet_ntoa(area->area_id)); + if (v->type == OSPF_VERTEX_ROUTER) { + u_char *p; + u_char *lim; + struct router_lsa_link *l; + struct router_lsa *rlsa; + int lsa_pos = 0; + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "ospf_process_stubs():processing router LSA, id: %s", + inet_ntoa(v->lsa->id)); + rlsa = (struct router_lsa *)v->lsa; + + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "ospf_process_stubs(): we have %d links to process", + ntohs(rlsa->links)); + p = ((u_char *)v->lsa) + OSPF_LSA_HEADER_SIZE + 4; + lim = ((u_char *)v->lsa) + ntohs(v->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)); + + if (l->m[0].type == LSA_LINK_TYPE_STUB) + ospf_intra_add_stub(rt, l, v, area, + parent_is_root, lsa_pos); + lsa_pos++; + } + } - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_process_stub():processing stubs for area %s", - inet_ntoa (area->area_id)); - if (v->type == OSPF_VERTEX_ROUTER) - { - u_char *p; - u_char *lim; - struct router_lsa_link *l; - struct router_lsa *rlsa; - int lsa_pos = 0; - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_process_stubs():processing router LSA, id: %s", - inet_ntoa (v->lsa->id)); - rlsa = (struct router_lsa *) v->lsa; - - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_process_stubs(): we have %d links to process", - ntohs (rlsa->links)); - p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; - lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); - - while (p < lim) - { - l = (struct router_lsa_link *) p; + ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1, + 1); - p += (OSPF_ROUTER_LSA_LINK_SIZE + - (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); + for (ALL_LIST_ELEMENTS(v->children, cnode, cnnode, child)) { + if (CHECK_FLAG(child->flags, OSPF_VERTEX_PROCESSED)) + continue; - if (l->m[0].type == LSA_LINK_TYPE_STUB) - ospf_intra_add_stub (rt, l, v, area, parent_is_root, lsa_pos); - lsa_pos++; - } - } - - ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1, 1); - - for (ALL_LIST_ELEMENTS (v->children, cnode, cnnode, child)) - { - if (CHECK_FLAG (child->flags, OSPF_VERTEX_PROCESSED)) - continue; - - /* the first level of routers connected to the root - * should have 'parent_is_root' set, including those - * connected via a network vertex. - */ - if (area->spf == v) - parent_is_root = 1; - else if (v->type == OSPF_VERTEX_ROUTER) - parent_is_root = 0; - - ospf_spf_process_stubs (area, child, rt, parent_is_root); - - SET_FLAG (child->flags, OSPF_VERTEX_PROCESSED); - } + /* the first level of routers connected to the root + * should have 'parent_is_root' set, including those + * connected via a network vertex. + */ + if (area->spf == v) + parent_is_root = 1; + else if (v->type == OSPF_VERTEX_ROUTER) + parent_is_root = 0; + + ospf_spf_process_stubs(area, child, rt, parent_is_root); + + SET_FLAG(child->flags, OSPF_VERTEX_PROCESSED); + } } -void -ospf_rtrs_free (struct route_table *rtrs) +void ospf_rtrs_free(struct route_table *rtrs) { - struct route_node *rn; - struct list *or_list; - struct ospf_route *or; - struct listnode *node, *nnode; + struct route_node *rn; + struct list *or_list; + struct ospf_route * or ; + struct listnode *node, *nnode; - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("Route: Router Routing Table free"); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("Route: Router Routing Table free"); - for (rn = route_top (rtrs); rn; rn = route_next (rn)) - if ((or_list = rn->info) != NULL) - { - for (ALL_LIST_ELEMENTS (or_list, node, nnode, or)) - ospf_route_free (or); + for (rn = route_top(rtrs); rn; rn = route_next(rn)) + if ((or_list = rn->info) != NULL) { + for (ALL_LIST_ELEMENTS(or_list, node, nnode, or)) + ospf_route_free(or); - list_delete (or_list); + list_delete(or_list); - /* Unlock the node. */ - rn->info = NULL; - route_unlock_node (rn); - } - route_table_finish (rtrs); + /* Unlock the node. */ + rn->info = NULL; + route_unlock_node(rn); + } + route_table_finish(rtrs); } #if 0 @@ -1149,318 +1157,309 @@ ospf_rtrs_print (struct route_table *rtrs) #endif /* Calculating the shortest-path tree for an area. */ -static void -ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, - struct route_table *new_rtrs) +static void ospf_spf_calculate(struct ospf_area *area, + struct route_table *new_table, + struct route_table *new_rtrs) { - struct pqueue *candidate; - struct vertex *v; - - if (IS_DEBUG_OSPF_EVENT) - { - zlog_debug ("ospf_spf_calculate: Start"); - zlog_debug ("ospf_spf_calculate: running Dijkstra for area %s", - inet_ntoa (area->area_id)); - } - - /* Check router-lsa-self. If self-router-lsa is not yet allocated, - return this area's calculation. */ - if (!area->router_lsa_self) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_spf_calculate: " - "Skip area %s's calculation due to empty router_lsa_self", - inet_ntoa (area->area_id)); - return; - } - - /* RFC2328 16.1. (1). */ - /* Initialize the algorithm's data structures. */ - - /* This function scans all the LSA database and set the stat field to - * LSA_SPF_NOT_EXPLORED. */ - ospf_lsdb_clean_stat (area->lsdb); - /* Create a new heap for the candidates. */ - candidate = pqueue_create(); - candidate->cmp = cmp; - candidate->update = update_stat; - - /* Initialize the shortest-path tree to only the root (which is the - router doing the calculation). */ - ospf_spf_init (area); - v = area->spf; - /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the - * spanning tree. */ - *(v->stat) = LSA_SPF_IN_SPFTREE; - - /* Set Area A's TransitCapability to FALSE. */ - area->transit = OSPF_TRANSIT_FALSE; - area->shortcut_capability = 1; - - for (;;) - { - /* RFC2328 16.1. (2). */ - ospf_spf_next (v, area, candidate); - - /* RFC2328 16.1. (3). */ - /* If at this step the candidate list is empty, the shortest- - path tree (of transit vertices) has been completely built and - this stage of the procedure terminates. */ - if (candidate->size == 0) - break; - - /* Otherwise, choose the vertex belonging to the candidate list - that is closest to the root, and add it to the shortest-path - tree (removing it from the candidate list in the - process). */ - /* Extract from the candidates the node with the lower key. */ - v = (struct vertex *) pqueue_dequeue (candidate); - /* Update stat field in vertex. */ - *(v->stat) = LSA_SPF_IN_SPFTREE; - - ospf_vertex_add_parent (v); - - /* RFC2328 16.1. (4). */ - if (v->type == OSPF_VERTEX_ROUTER) - ospf_intra_add_router (new_rtrs, v, area); - else - ospf_intra_add_transit (new_table, v, area); - - /* RFC2328 16.1. (5). */ - /* Iterate the algorithm by returning to Step 2. */ - - } /* end loop until no more candidate vertices */ + struct pqueue *candidate; + struct vertex *v; - if (IS_DEBUG_OSPF_EVENT) - { - ospf_spf_dump (area->spf, 0); - ospf_route_table_dump (new_table); - } + if (IS_DEBUG_OSPF_EVENT) { + zlog_debug("ospf_spf_calculate: Start"); + zlog_debug("ospf_spf_calculate: running Dijkstra for area %s", + inet_ntoa(area->area_id)); + } - /* Second stage of SPF calculation procedure's */ - ospf_spf_process_stubs (area, area->spf, new_table, 0); + /* Check router-lsa-self. If self-router-lsa is not yet allocated, + return this area's calculation. */ + if (!area->router_lsa_self) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "ospf_spf_calculate: " + "Skip area %s's calculation due to empty router_lsa_self", + inet_ntoa(area->area_id)); + return; + } - /* Free candidate queue. */ - pqueue_delete (candidate); + /* RFC2328 16.1. (1). */ + /* Initialize the algorithm's data structures. */ + + /* This function scans all the LSA database and set the stat field to + * LSA_SPF_NOT_EXPLORED. */ + ospf_lsdb_clean_stat(area->lsdb); + /* Create a new heap for the candidates. */ + candidate = pqueue_create(); + candidate->cmp = cmp; + candidate->update = update_stat; + + /* Initialize the shortest-path tree to only the root (which is the + router doing the calculation). */ + ospf_spf_init(area); + v = area->spf; + /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of + * the + * spanning tree. */ + *(v->stat) = LSA_SPF_IN_SPFTREE; + + /* Set Area A's TransitCapability to FALSE. */ + area->transit = OSPF_TRANSIT_FALSE; + area->shortcut_capability = 1; + + for (;;) { + /* RFC2328 16.1. (2). */ + ospf_spf_next(v, area, candidate); + + /* RFC2328 16.1. (3). */ + /* If at this step the candidate list is empty, the shortest- + path tree (of transit vertices) has been completely built and + this stage of the procedure terminates. */ + if (candidate->size == 0) + break; + + /* Otherwise, choose the vertex belonging to the candidate list + that is closest to the root, and add it to the shortest-path + tree (removing it from the candidate list in the + process). */ + /* Extract from the candidates the node with the lower key. */ + v = (struct vertex *)pqueue_dequeue(candidate); + /* Update stat field in vertex. */ + *(v->stat) = LSA_SPF_IN_SPFTREE; + + ospf_vertex_add_parent(v); + + /* RFC2328 16.1. (4). */ + if (v->type == OSPF_VERTEX_ROUTER) + ospf_intra_add_router(new_rtrs, v, area); + else + ospf_intra_add_transit(new_table, v, area); + + /* RFC2328 16.1. (5). */ + /* Iterate the algorithm by returning to Step 2. */ + + } /* end loop until no more candidate vertices */ + + if (IS_DEBUG_OSPF_EVENT) { + ospf_spf_dump(area->spf, 0); + ospf_route_table_dump(new_table); + } - ospf_vertex_dump (__func__, area->spf, 0, 1); - /* Free nexthop information, canonical versions of which are attached - * the first level of router vertices attached to the root vertex, see - * ospf_nexthop_calculation. - */ - ospf_canonical_nexthops_free (area->spf); + /* Second stage of SPF calculation procedure's */ + ospf_spf_process_stubs(area, area->spf, new_table, 0); - /* Increment SPF Calculation Counter. */ - area->spf_calculation++; + /* Free candidate queue. */ + pqueue_delete(candidate); - monotime(&area->ospf->ts_spf); - area->ts_spf = area->ospf->ts_spf; + ospf_vertex_dump(__func__, area->spf, 0, 1); + /* Free nexthop information, canonical versions of which are attached + * the first level of router vertices attached to the root vertex, see + * ospf_nexthop_calculation. + */ + ospf_canonical_nexthops_free(area->spf); - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("ospf_spf_calculate: Stop. %zd vertices", - mtype_stats_alloc(MTYPE_OSPF_VERTEX)); + /* Increment SPF Calculation Counter. */ + area->spf_calculation++; + + monotime(&area->ospf->ts_spf); + area->ts_spf = area->ospf->ts_spf; - /* Free SPF vertices, but not the list. List has ospf_vertex_free - * as deconstructor. - */ - list_delete_all_node (&vertex_list); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("ospf_spf_calculate: Stop. %zd vertices", + mtype_stats_alloc(MTYPE_OSPF_VERTEX)); + + /* Free SPF vertices, but not the list. List has ospf_vertex_free + * as deconstructor. + */ + list_delete_all_node(&vertex_list); } /* Timer for SPF calculation. */ -static int -ospf_spf_calculate_timer (struct thread *thread) +static int ospf_spf_calculate_timer(struct thread *thread) { - struct ospf *ospf = THREAD_ARG (thread); - struct route_table *new_table, *new_rtrs; - struct ospf_area *area; - struct listnode *node, *nnode; - struct timeval start_time, spf_start_time; - int areas_processed = 0; - unsigned long ia_time, prune_time, rt_time; - unsigned long abr_time, total_spf_time, spf_time; - char rbuf[32]; /* reason_buf */ - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("SPF: Timer (SPF calculation expire)"); - - ospf->t_spf_calc = NULL; - - monotime(&spf_start_time); - /* Allocate new table tree. */ - new_table = route_table_init (); - new_rtrs = route_table_init (); - - ospf_vl_unapprove (ospf); - - /* Calculate SPF for each area. */ - for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) - { - /* Do backbone last, so as to first discover intra-area paths - * for any back-bone virtual-links - */ - if (ospf->backbone && ospf->backbone == area) - continue; - - ospf_spf_calculate (area, new_table, new_rtrs); - areas_processed++; - } - - /* SPF for backbone, if required */ - if (ospf->backbone) - { - ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); - areas_processed++; - } - - spf_time = monotime_since(&spf_start_time, NULL); - - ospf_vl_shut_unapproved (ospf); - - monotime(&start_time); - ospf_ia_routing (ospf, new_table, new_rtrs); - ia_time = monotime_since(&start_time, NULL); - - monotime(&start_time); - ospf_prune_unreachable_networks (new_table); - ospf_prune_unreachable_routers (new_rtrs); - prune_time = monotime_since(&start_time, NULL); - - /* AS-external-LSA calculation should not be performed here. */ - - /* If new Router Route is installed, - then schedule re-calculate External routes. */ - if (1) - ospf_ase_calculate_schedule (ospf); - - ospf_ase_calculate_timer_add (ospf); - - /* Update routing table. */ - monotime(&start_time); - ospf_route_install (ospf, new_table); - rt_time = monotime_since(&start_time, NULL); - - /* Update ABR/ASBR routing table */ - if (ospf->old_rtrs) - { - /* old_rtrs's node holds linked list of ospf_route. --kunihiro. */ - /* ospf_route_delete (ospf->old_rtrs); */ - ospf_rtrs_free (ospf->old_rtrs); - } - - ospf->old_rtrs = ospf->new_rtrs; - ospf->new_rtrs = new_rtrs; - - monotime(&start_time); - if (IS_OSPF_ABR (ospf)) - ospf_abr_task (ospf); - abr_time = monotime_since(&start_time, NULL); - - total_spf_time = monotime_since(&spf_start_time, &ospf->ts_spf_duration); - - rbuf[0] = '\0'; - if (spf_reason_flags) - { - if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL) - strncat (rbuf, "R, ", sizeof(rbuf) - strlen(rbuf) - 1); - if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL) - strncat (rbuf, "N, ", sizeof(rbuf) - strlen(rbuf) - 1); - if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL) - strncat (rbuf, "S, ", sizeof(rbuf) - strlen(rbuf) - 1); - if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL) - strncat (rbuf, "AS, ", sizeof(rbuf) - strlen(rbuf) - 1); - if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE) - strncat (rbuf, "ABR, ", sizeof(rbuf) - strlen(rbuf) - 1); - if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE) - strncat (rbuf, "ASBR, ", sizeof(rbuf) - strlen(rbuf) - 1); - if (spf_reason_flags & SPF_FLAG_MAXAGE) - strncat (rbuf, "M, ", sizeof(rbuf) - strlen(rbuf) - 1); - - size_t rbuflen = strlen(rbuf); - if (rbuflen >= 2) - rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */ - else - rbuf[0] = '\0'; - } + struct ospf *ospf = THREAD_ARG(thread); + struct route_table *new_table, *new_rtrs; + struct ospf_area *area; + struct listnode *node, *nnode; + struct timeval start_time, spf_start_time; + int areas_processed = 0; + unsigned long ia_time, prune_time, rt_time; + unsigned long abr_time, total_spf_time, spf_time; + char rbuf[32]; /* reason_buf */ + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("SPF: Timer (SPF calculation expire)"); + + ospf->t_spf_calc = NULL; + + monotime(&spf_start_time); + /* Allocate new table tree. */ + new_table = route_table_init(); + new_rtrs = route_table_init(); + + ospf_vl_unapprove(ospf); + + /* Calculate SPF for each area. */ + for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) { + /* Do backbone last, so as to first discover intra-area paths + * for any back-bone virtual-links + */ + if (ospf->backbone && ospf->backbone == area) + continue; - if (IS_DEBUG_OSPF_EVENT) - { - zlog_info ("SPF Processing Time(usecs): %ld", total_spf_time); - zlog_info ("\t SPF Time: %ld", spf_time); - zlog_info ("\t InterArea: %ld", ia_time); - zlog_info ("\t Prune: %ld", prune_time); - zlog_info ("\tRouteInstall: %ld", rt_time); - if (IS_OSPF_ABR (ospf)) - zlog_info ("\t ABR: %ld (%d areas)", - abr_time, areas_processed); - zlog_info ("Reason(s) for SPF: %s", rbuf); - } - - ospf_clear_spf_reason_flags (); - - return 0; + ospf_spf_calculate(area, new_table, new_rtrs); + areas_processed++; + } + + /* SPF for backbone, if required */ + if (ospf->backbone) { + ospf_spf_calculate(ospf->backbone, new_table, new_rtrs); + areas_processed++; + } + + spf_time = monotime_since(&spf_start_time, NULL); + + ospf_vl_shut_unapproved(ospf); + + monotime(&start_time); + ospf_ia_routing(ospf, new_table, new_rtrs); + ia_time = monotime_since(&start_time, NULL); + + monotime(&start_time); + ospf_prune_unreachable_networks(new_table); + ospf_prune_unreachable_routers(new_rtrs); + prune_time = monotime_since(&start_time, NULL); + + /* AS-external-LSA calculation should not be performed here. */ + + /* If new Router Route is installed, + then schedule re-calculate External routes. */ + if (1) + ospf_ase_calculate_schedule(ospf); + + ospf_ase_calculate_timer_add(ospf); + + /* Update routing table. */ + monotime(&start_time); + ospf_route_install(ospf, new_table); + rt_time = monotime_since(&start_time, NULL); + + /* Update ABR/ASBR routing table */ + if (ospf->old_rtrs) { + /* old_rtrs's node holds linked list of ospf_route. --kunihiro. + */ + /* ospf_route_delete (ospf->old_rtrs); */ + ospf_rtrs_free(ospf->old_rtrs); + } + + ospf->old_rtrs = ospf->new_rtrs; + ospf->new_rtrs = new_rtrs; + + monotime(&start_time); + if (IS_OSPF_ABR(ospf)) + ospf_abr_task(ospf); + abr_time = monotime_since(&start_time, NULL); + + total_spf_time = + monotime_since(&spf_start_time, &ospf->ts_spf_duration); + + rbuf[0] = '\0'; + if (spf_reason_flags) { + if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL) + strncat(rbuf, "R, ", sizeof(rbuf) - strlen(rbuf) - 1); + if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL) + strncat(rbuf, "N, ", sizeof(rbuf) - strlen(rbuf) - 1); + if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL) + strncat(rbuf, "S, ", sizeof(rbuf) - strlen(rbuf) - 1); + if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL) + strncat(rbuf, "AS, ", sizeof(rbuf) - strlen(rbuf) - 1); + if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE) + strncat(rbuf, "ABR, ", sizeof(rbuf) - strlen(rbuf) - 1); + if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE) + strncat(rbuf, "ASBR, ", + sizeof(rbuf) - strlen(rbuf) - 1); + if (spf_reason_flags & SPF_FLAG_MAXAGE) + strncat(rbuf, "M, ", sizeof(rbuf) - strlen(rbuf) - 1); + + size_t rbuflen = strlen(rbuf); + if (rbuflen >= 2) + rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */ + else + rbuf[0] = '\0'; + } + + if (IS_DEBUG_OSPF_EVENT) { + zlog_info("SPF Processing Time(usecs): %ld", total_spf_time); + zlog_info("\t SPF Time: %ld", spf_time); + zlog_info("\t InterArea: %ld", ia_time); + zlog_info("\t Prune: %ld", prune_time); + zlog_info("\tRouteInstall: %ld", rt_time); + if (IS_OSPF_ABR(ospf)) + zlog_info("\t ABR: %ld (%d areas)", abr_time, + areas_processed); + zlog_info("Reason(s) for SPF: %s", rbuf); + } + + ospf_clear_spf_reason_flags(); + + return 0; } /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer for SPF calc. */ -void -ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason) +void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason) { - unsigned long delay, elapsed, ht; + unsigned long delay, elapsed, ht; - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("SPF: calculation timer scheduled"); - - /* OSPF instance does not exist. */ - if (ospf == NULL) - return; - - ospf_spf_set_reason (reason); - - /* SPF calculation timer is already scheduled. */ - if (ospf->t_spf_calc) - { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("SPF: calculation timer is already scheduled: %p", - (void *)ospf->t_spf_calc); - return; - } - - elapsed = monotime_since (&ospf->ts_spf, NULL) / 1000; - - ht = ospf->spf_holdtime * ospf->spf_hold_multiplier; - - if (ht > ospf->spf_max_holdtime) - ht = ospf->spf_max_holdtime; - - /* Get SPF calculation delay time. */ - if (elapsed < ht) - { - /* Got an event within the hold time of last SPF. We need to - * increase the hold_multiplier, if it's not already at/past - * maximum value, and wasn't already increased.. - */ - if (ht < ospf->spf_max_holdtime) - ospf->spf_hold_multiplier++; - - /* always honour the SPF initial delay */ - if ( (ht - elapsed) < ospf->spf_delay) - delay = ospf->spf_delay; - else - delay = ht - elapsed; - } - else - { - /* Event is past required hold-time of last SPF */ - delay = ospf->spf_delay; - ospf->spf_hold_multiplier = 1; - } - - if (IS_DEBUG_OSPF_EVENT) - zlog_debug ("SPF: calculation timer delay = %ld", delay); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("SPF: calculation timer scheduled"); + + /* OSPF instance does not exist. */ + if (ospf == NULL) + return; + + ospf_spf_set_reason(reason); + + /* SPF calculation timer is already scheduled. */ + if (ospf->t_spf_calc) { + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "SPF: calculation timer is already scheduled: %p", + (void *)ospf->t_spf_calc); + return; + } + + elapsed = monotime_since(&ospf->ts_spf, NULL) / 1000; + + ht = ospf->spf_holdtime * ospf->spf_hold_multiplier; + + if (ht > ospf->spf_max_holdtime) + ht = ospf->spf_max_holdtime; + + /* Get SPF calculation delay time. */ + if (elapsed < ht) { + /* Got an event within the hold time of last SPF. We need to + * increase the hold_multiplier, if it's not already at/past + * maximum value, and wasn't already increased.. + */ + if (ht < ospf->spf_max_holdtime) + ospf->spf_hold_multiplier++; + + /* always honour the SPF initial delay */ + if ((ht - elapsed) < ospf->spf_delay) + delay = ospf->spf_delay; + else + delay = ht - elapsed; + } else { + /* Event is past required hold-time of last SPF */ + delay = ospf->spf_delay; + ospf->spf_hold_multiplier = 1; + } + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("SPF: calculation timer delay = %ld", delay); - zlog_info ("SPF: Scheduled in %ld msec", delay); + zlog_info("SPF: Scheduled in %ld msec", delay); - ospf->t_spf_calc = NULL; - thread_add_timer_msec(master, ospf_spf_calculate_timer, ospf, delay, - &ospf->t_spf_calc); + ospf->t_spf_calc = NULL; + thread_add_timer_msec(master, ospf_spf_calculate_timer, ospf, delay, + &ospf->t_spf_calc); } |