version 1.1.1.1, 2012/02/21 17:26:12
|
version 1.1.1.4, 2016/11/02 10:09:12
|
Line 46 Software Foundation, Inc., 59 Temple Place - Suite 330
|
Line 46 Software Foundation, Inc., 59 Temple Place - Suite 330
|
#include "ospfd/ospf_abr.h" |
#include "ospfd/ospf_abr.h" |
#include "ospfd/ospf_dump.h" |
#include "ospfd/ospf_dump.h" |
|
|
|
/* Variables to ensure a SPF scheduled log message is printed only once */ |
|
|
|
static unsigned int spf_reason_flags = 0; |
|
|
|
static void |
|
ospf_clear_spf_reason_flags () |
|
{ |
|
spf_reason_flags = 0; |
|
} |
|
|
|
static void |
|
ospf_spf_set_reason (ospf_spf_reason_t reason) |
|
{ |
|
spf_reason_flags |= 1 << reason; |
|
} |
|
|
|
static void |
|
ospf_get_spf_reason_str (char *buf) |
|
{ |
|
if (!buf) |
|
return; |
|
|
|
buf[0] = '\0'; |
|
if (spf_reason_flags) |
|
{ |
|
if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL) |
|
strcat (buf, "R, "); |
|
if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL) |
|
strcat (buf, "N, "); |
|
if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL) |
|
strcat (buf, "S, "); |
|
if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL) |
|
strcat (buf, "AS, "); |
|
if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE) |
|
strcat (buf, "ABR, "); |
|
if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE) |
|
strcat (buf, "ASBR, "); |
|
if (spf_reason_flags & SPF_FLAG_MAXAGE) |
|
strcat (buf, "M, "); |
|
buf[strlen(buf)-2] = '\0'; /* skip the last ", " */ |
|
} |
|
} |
|
|
static void ospf_vertex_free (void *); |
static void ospf_vertex_free (void *); |
/* List of allocated vertices, to simplify cleanup of SPF. |
/* List of allocated vertices, to simplify cleanup of SPF. |
* Not thread-safe obviously. If it ever needs to be, it'd have to be |
* Not thread-safe obviously. If it ever needs to be, it'd have to be |
* dynamically allocated at begin of ospf_spf_calculate |
* 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 |
/* Heap related functions, for the managment of the candidates, to |
* be used with pqueue. */ |
* be used with pqueue. */ |
static int |
static int |
Line 90 update_stat (void *node , int position)
|
Line 133 update_stat (void *node , int position)
|
/* Set the status of the vertex, when its position changes. */ |
/* Set the status of the vertex, when its position changes. */ |
*(v->stat) = position; |
*(v->stat) = position; |
} |
} |
| |
static struct vertex_nexthop * |
static struct vertex_nexthop * |
vertex_nexthop_new (void) |
vertex_nexthop_new (void) |
{ |
{ |
Line 134 ospf_canonical_nexthops_free (struct vertex *root)
|
Line 177 ospf_canonical_nexthops_free (struct vertex *root)
|
vertex_nexthop_free (vp->nexthop); |
vertex_nexthop_free (vp->nexthop); |
} |
} |
} |
} |
| |
/* TODO: Parent list should be excised, in favour of maintaining only |
/* TODO: Parent list should be excised, in favour of maintaining only |
* vertex_nexthop, with refcounts. |
* vertex_nexthop, with refcounts. |
*/ |
*/ |
Line 159 vertex_parent_free (void *p)
|
Line 202 vertex_parent_free (void *p)
|
{ |
{ |
XFREE (MTYPE_OSPF_VERTEX_PARENT, p); |
XFREE (MTYPE_OSPF_VERTEX_PARENT, p); |
} |
} |
| |
static struct vertex * |
static struct vertex * |
ospf_vertex_new (struct ospf_lsa *lsa) |
ospf_vertex_new (struct ospf_lsa *lsa) |
{ |
{ |
Line 276 ospf_vertex_add_parent (struct vertex *v)
|
Line 319 ospf_vertex_add_parent (struct vertex *v)
|
listnode_add (vp->parent->children, v); |
listnode_add (vp->parent->children, v); |
} |
} |
} |
} |
| |
static void |
static void |
ospf_spf_init (struct ospf_area *area) |
ospf_spf_init (struct ospf_area *area) |
{ |
{ |
Line 422 ospf_spf_add_parent (struct vertex *v, struct vertex *
|
Line 465 ospf_spf_add_parent (struct vertex *v, struct vertex *
|
struct vertex_nexthop *newhop, |
struct vertex_nexthop *newhop, |
unsigned int distance) |
unsigned int distance) |
{ |
{ |
struct vertex_parent *vp; | struct vertex_parent *vp, *wp; |
| struct listnode *node; |
|
|
/* we must have a newhop, and a distance */ |
/* we must have a newhop, and a distance */ |
assert (v && w && newhop); |
assert (v && w && newhop); |
Line 456 ospf_spf_add_parent (struct vertex *v, struct vertex *
|
Line 500 ospf_spf_add_parent (struct vertex *v, struct vertex *
|
w->distance = distance; |
w->distance = distance; |
} |
} |
|
|
/* new parent is <= existing parents, add it to parent list */ | /* 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); |
vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop); |
listnode_add (w->parents, vp); |
listnode_add (w->parents, vp); |
|
|
Line 477 ospf_spf_add_parent (struct vertex *v, struct vertex *
|
Line 533 ospf_spf_add_parent (struct vertex *v, struct vertex *
|
static unsigned int |
static unsigned int |
ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, |
ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, |
struct vertex *w, struct router_lsa_link *l, |
struct vertex *w, struct router_lsa_link *l, |
unsigned int distance) | unsigned int distance, int lsa_pos) |
{ |
{ |
struct listnode *node, *nnode; |
struct listnode *node, *nnode; |
struct vertex_nexthop *nh; |
struct vertex_nexthop *nh; |
struct vertex_parent *vp; |
struct vertex_parent *vp; |
struct ospf_interface *oi = NULL; |
struct ospf_interface *oi = NULL; |
unsigned int added = 0; |
unsigned int added = 0; |
|
char buf1[BUFSIZ]; |
|
char buf2[BUFSIZ]; |
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
{ |
{ |
Line 502 ospf_nexthop_calculation (struct ospf_area *area, stru
|
Line 560 ospf_nexthop_calculation (struct ospf_area *area, stru
|
the OSPF interface connecting to the destination network/router. |
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)); |
|
} |
|
|
if (w->type == OSPF_VERTEX_ROUTER) |
if (w->type == OSPF_VERTEX_ROUTER) |
{ |
{ |
/* l is a link from v to w |
/* l is a link from v to w |
* l2 will be link from w to v |
* l2 will be link from w to v |
*/ |
*/ |
struct router_lsa_link *l2 = NULL; |
struct router_lsa_link *l2 = NULL; |
|
|
/* we *must* be supplied with the link data */ |
|
assert (l != NULL); |
|
|
|
if (IS_DEBUG_OSPF_EVENT) |
|
{ |
|
char buf1[BUFSIZ]; |
|
char buf2[BUFSIZ]; |
|
|
|
zlog_debug("ospf_nexthop_calculation(): considering link " |
|
"type %d link_id %s link_data %s", |
|
l->m[0].type, |
|
inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ), |
|
inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ)); |
|
} |
|
|
|
if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) |
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 |
/* If the destination is a router which connects to |
the calculating router via a Point-to-MultiPoint |
the calculating router via a Point-to-MultiPoint |
network, the destination's next hop IP address(es) |
network, the destination's next hop IP address(es) |
Line 536 ospf_nexthop_calculation (struct ospf_area *area, stru
|
Line 602 ospf_nexthop_calculation (struct ospf_area *area, stru
|
provides an IP address of the next hop router. |
provides an IP address of the next hop router. |
|
|
At this point l is a link from V to W, and V is the |
At this point l is a link from V to W, and V is the |
root ("us"). Find the local interface associated | root ("us"). If it is a point-to-multipoint interface, |
with l (its address is in l->link_data). If it | then look through the links in the opposite direction (W to V). |
is a point-to-multipoint interface, then look through | If any of them have an address that lands within the |
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 |
subnet declared by the PtMP link, then that link |
is a constituent of the PtMP link, and its address is | is a constituent of the PtMP link, and its address is |
a nexthop address for V. |
a nexthop address for V. |
*/ |
*/ |
oi = ospf_if_is_configured (area->ospf, &l->link_data); | if (oi->type == OSPF_IFTYPE_POINTOPOINT) |
if (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) | { |
{ | /* Having nexthop = 0 is tempting, but NOT acceptable. |
struct prefix_ipv4 la; | 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; |
|
|
la.family = AF_INET; | nbr_w = ospf_nbr_lookup_by_routerid (oi->nbrs, &l->link_id); |
la.prefixlen = oi->address->prefixlen; | if (nbr_w != NULL) |
| { |
| added = 1; |
| nexthop = nbr_w->src; |
| } |
| } |
| else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) |
| { |
| struct prefix_ipv4 la; |
|
|
/* V links to W on PtMP interface | la.family = AF_INET; |
- find the interface address on W */ | la.prefixlen = oi->address->prefixlen; |
while ((l2 = ospf_get_next_link (w, v, l2))) | |
{ | |
la.prefix = l2->link_data; | |
|
|
if (prefix_cmp ((struct prefix *) &la, | /* V links to W on PtMP interface |
oi->address) == 0) | - find the interface address on W */ |
/* link_data is on our PtMP network */ | while ((l2 = ospf_get_next_link (w, v, l2))) |
break; | { |
} | la.prefix = l2->link_data; |
} /* end l is on point-to-multipoint link */ | |
else | |
{ | |
/* l is a regular point-to-point link. | |
Look for a link from W to V. | |
*/ | |
while ((l2 = ospf_get_next_link (w, v, l2))) | |
{ | |
oi = ospf_if_is_configured (area->ospf, | |
&(l2->link_data)); | |
|
|
if (oi == NULL) | if (prefix_cmp ((struct prefix *) &la, |
continue; | oi->address) != 0) |
| continue; |
| /* link_data is on our PtMP network */ |
| added = 1; |
| nexthop = l2->link_data; |
| break; |
| } |
| } |
|
|
if (!IPV4_ADDR_SAME (&oi->address->u.prefix4, | if (added) |
&l->link_data)) | |
continue; | |
| |
break; | |
} | |
} | |
| |
if (oi && l2) | |
{ |
{ |
/* found all necessary info to build nexthop */ |
/* found all necessary info to build nexthop */ |
nh = vertex_nexthop_new (); |
nh = vertex_nexthop_new (); |
nh->oi = oi; |
nh->oi = oi; |
nh->router = l2->link_data; | nh->router = nexthop; |
ospf_spf_add_parent (v, w, nh, distance); |
ospf_spf_add_parent (v, w, nh, distance); |
return 1; |
return 1; |
} |
} |
else |
else |
zlog_info("ospf_nexthop_calculation(): " | zlog_info("%s: could not determine nexthop for link %s", |
"could not determine nexthop for link"); | __func__, oi->ifp->name); |
} /* end point-to-point link from V to W */ |
} /* end point-to-point link from V to W */ |
else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) |
else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) |
{ |
{ |
Line 630 ospf_nexthop_calculation (struct ospf_area *area, stru
|
Line 695 ospf_nexthop_calculation (struct ospf_area *area, stru
|
else |
else |
{ |
{ |
assert(w->type == OSPF_VERTEX_NETWORK); |
assert(w->type == OSPF_VERTEX_NETWORK); |
oi = ospf_if_is_configured (area->ospf, &(l->link_data)); | |
if (oi) | nh = vertex_nexthop_new (); |
{ | nh->oi = oi; |
nh = vertex_nexthop_new (); | nh->router.s_addr = 0; /* Nexthop not required */ |
nh->oi = oi; | ospf_spf_add_parent (v, w, nh, distance); |
nh->router.s_addr = 0; | return 1; |
ospf_spf_add_parent (v, w, nh, distance); | |
return 1; | |
} | |
} |
} |
zlog_info("ospf_nexthop_calculation(): " |
|
"Unknown attached link"); |
|
return 0; |
|
} /* end V is the root */ |
} /* end V is the root */ |
/* Check if W's parent is a network connected to root. */ |
/* Check if W's parent is a network connected to root. */ |
else if (v->type == OSPF_VERTEX_NETWORK) |
else if (v->type == OSPF_VERTEX_NETWORK) |
Line 673 ospf_nexthop_calculation (struct ospf_area *area, stru
|
Line 732 ospf_nexthop_calculation (struct ospf_area *area, stru
|
added = 1; |
added = 1; |
ospf_spf_add_parent (v, w, nh, distance); |
ospf_spf_add_parent (v, w, nh, distance); |
} |
} |
} | /* Note lack of return is deliberate. See next comment. */ |
| } |
} |
} |
/* NB: This code is non-trivial. |
/* NB: This code is non-trivial. |
* |
* |
* E.g. it is not enough to know that V connects to the root. It is |
* 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 |
* also important that the while above, looping through all links from |
* W->V found at least one link, so that we know there is |
* W->V found at least one link, so that we know there is |
* bi-directional connectivity between V and W. Otherwise, if we | * bi-directional connectivity between V and W (which need not be the |
* /always/ return here, but don't check that W->V exists then we | * case, e.g. when OSPF has not yet converged fully). Otherwise, if |
* we will prevent SPF from finding/using higher cost paths.. | * 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. |
* |
* |
* See also bug #330, and also: | * 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. |
* |
* |
* http://blogs.sun.com/paulj/entry/the_difference_a_line_makes | * 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) |
if (added) |
return added; |
return added; |
Line 723 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
Line 796 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
u_char *lim; |
u_char *lim; |
struct router_lsa_link *l = NULL; |
struct router_lsa_link *l = NULL; |
struct in_addr *r; |
struct in_addr *r; |
int type = 0; | 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 |
/* 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. */ |
A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */ |
Line 752 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
Line 825 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
{ |
{ |
l = (struct router_lsa_link *) p; |
l = (struct router_lsa_link *) p; |
|
|
|
lsa_pos = lsa_pos_next; /* LSA link position */ |
|
lsa_pos_next++; |
p += (OSPF_ROUTER_LSA_LINK_SIZE + |
p += (OSPF_ROUTER_LSA_LINK_SIZE + |
(l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); |
(l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); |
|
|
Line 873 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
Line 948 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
w = ospf_vertex_new (w_lsa); |
w = ospf_vertex_new (w_lsa); |
|
|
/* Calculate nexthop to W. */ |
/* Calculate nexthop to W. */ |
if (ospf_nexthop_calculation (area, v, w, l, distance)) | if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) |
pqueue_enqueue (w, candidate); |
pqueue_enqueue (w, candidate); |
else if (IS_DEBUG_OSPF_EVENT) |
else if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("Nexthop Calc failed"); |
zlog_debug ("Nexthop Calc failed"); |
Line 893 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
Line 968 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
{ |
{ |
/* Found an equal-cost path to W. |
/* Found an equal-cost path to W. |
* Calculate nexthop of to W from V. */ |
* Calculate nexthop of to W from V. */ |
ospf_nexthop_calculation (area, v, w, l, distance); | ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos); |
} |
} |
/* less than. */ |
/* less than. */ |
else |
else |
Line 903 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
Line 978 ospf_spf_next (struct vertex *v, struct ospf_area *are
|
* valid nexthop it will call spf_add_parents, which |
* valid nexthop it will call spf_add_parents, which |
* will flush the old parents |
* will flush the old parents |
*/ |
*/ |
if (ospf_nexthop_calculation (area, v, w, l, distance)) | if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) |
/* Decrease the key of the node in the heap. |
/* Decrease the key of the node in the heap. |
* trickle-sort it up towards root, just in case this |
* trickle-sort it up towards root, just in case this |
* node should now be the new root due the cost change. |
* node should now be the new root due the cost change. |
Line 939 ospf_spf_dump (struct vertex *v, int i)
|
Line 1014 ospf_spf_dump (struct vertex *v, int i)
|
for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent)) |
for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent)) |
{ |
{ |
zlog_debug (" nexthop %p %s %s", |
zlog_debug (" nexthop %p %s %s", |
parent->nexthop, | (void *)parent->nexthop, |
inet_ntoa (parent->nexthop->router), |
inet_ntoa (parent->nexthop->router), |
parent->nexthop->oi ? IF_NAME(parent->nexthop->oi) |
parent->nexthop->oi ? IF_NAME(parent->nexthop->oi) |
: "NULL"); |
: "NULL"); |
Line 969 ospf_spf_process_stubs (struct ospf_area *area, struct
|
Line 1044 ospf_spf_process_stubs (struct ospf_area *area, struct
|
u_char *lim; |
u_char *lim; |
struct router_lsa_link *l; |
struct router_lsa_link *l; |
struct router_lsa *rlsa; |
struct router_lsa *rlsa; |
|
int lsa_pos = 0; |
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("ospf_process_stubs():processing router LSA, id: %s", |
zlog_debug ("ospf_process_stubs():processing router LSA, id: %s", |
Line 990 ospf_spf_process_stubs (struct ospf_area *area, struct
|
Line 1066 ospf_spf_process_stubs (struct ospf_area *area, struct
|
(l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); |
(l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); |
|
|
if (l->m[0].type == LSA_LINK_TYPE_STUB) |
if (l->m[0].type == LSA_LINK_TYPE_STUB) |
ospf_intra_add_stub (rt, l, v, area, parent_is_root); | ospf_intra_add_stub (rt, l, v, area, parent_is_root, lsa_pos); |
| lsa_pos++; |
} |
} |
} |
} |
|
|
Line 1042 ospf_rtrs_free (struct route_table *rtrs)
|
Line 1119 ospf_rtrs_free (struct route_table *rtrs)
|
route_table_finish (rtrs); |
route_table_finish (rtrs); |
} |
} |
|
|
|
#if 0 |
static void |
static void |
ospf_rtrs_print (struct route_table *rtrs) |
ospf_rtrs_print (struct route_table *rtrs) |
{ |
{ |
Line 1101 ospf_rtrs_print (struct route_table *rtrs)
|
Line 1179 ospf_rtrs_print (struct route_table *rtrs)
|
|
|
zlog_debug ("ospf_rtrs_print() end"); |
zlog_debug ("ospf_rtrs_print() end"); |
} |
} |
|
#endif |
|
|
/* Calculating the shortest-path tree for an area. */ |
/* Calculating the shortest-path tree for an area. */ |
static void |
static void |
Line 1196 ospf_spf_calculate (struct ospf_area *area, struct rou
|
Line 1275 ospf_spf_calculate (struct ospf_area *area, struct rou
|
|
|
/* Free candidate queue. */ |
/* Free candidate queue. */ |
pqueue_delete (candidate); |
pqueue_delete (candidate); |
| |
ospf_vertex_dump (__func__, area->spf, 0, 1); |
ospf_vertex_dump (__func__, area->spf, 0, 1); |
/* Free nexthop information, canonical versions of which are attached |
/* Free nexthop information, canonical versions of which are attached |
* the first level of router vertices attached to the root vertex, see |
* the first level of router vertices attached to the root vertex, see |
* ospf_nexthop_calculation. |
* ospf_nexthop_calculation. |
*/ |
*/ |
ospf_canonical_nexthops_free (area->spf); |
ospf_canonical_nexthops_free (area->spf); |
| |
/* Free SPF vertices, but not the list. List has ospf_vertex_free | |
* as deconstructor. | |
*/ | |
list_delete_all_node (&vertex_list); | |
| |
/* Increment SPF Calculation Counter. */ |
/* Increment SPF Calculation Counter. */ |
area->spf_calculation++; |
area->spf_calculation++; |
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf); |
quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf); |
|
area->ts_spf = area->ospf->ts_spf; |
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", |
zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", |
mtype_stats_alloc(MTYPE_OSPF_VERTEX)); |
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. */ |
/* Timer for SPF calculation. */ |
static int |
static int |
ospf_spf_calculate_timer (struct thread *thread) |
ospf_spf_calculate_timer (struct thread *thread) |
Line 1227 ospf_spf_calculate_timer (struct thread *thread)
|
Line 1307 ospf_spf_calculate_timer (struct thread *thread)
|
struct route_table *new_table, *new_rtrs; |
struct route_table *new_table, *new_rtrs; |
struct ospf_area *area; |
struct ospf_area *area; |
struct listnode *node, *nnode; |
struct listnode *node, *nnode; |
| struct timeval start_time, stop_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) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("SPF: Timer (SPF calculation expire)"); |
zlog_debug ("SPF: Timer (SPF calculation expire)"); |
|
|
ospf->t_spf_calc = NULL; |
ospf->t_spf_calc = NULL; |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &spf_start_time); |
/* Allocate new table tree. */ |
/* Allocate new table tree. */ |
new_table = route_table_init (); |
new_table = route_table_init (); |
new_rtrs = route_table_init (); |
new_rtrs = route_table_init (); |
Line 1247 ospf_spf_calculate_timer (struct thread *thread)
|
Line 1333 ospf_spf_calculate_timer (struct thread *thread)
|
*/ |
*/ |
if (ospf->backbone && ospf->backbone == area) |
if (ospf->backbone && ospf->backbone == area) |
continue; |
continue; |
| |
ospf_spf_calculate (area, new_table, new_rtrs); |
ospf_spf_calculate (area, new_table, new_rtrs); |
|
areas_processed++; |
} |
} |
| |
/* SPF for backbone, if required */ |
/* SPF for backbone, if required */ |
if (ospf->backbone) |
if (ospf->backbone) |
ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); | { |
| ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); |
| areas_processed++; |
| } |
| |
| quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
| spf_time = timeval_elapsed (stop_time, spf_start_time); |
| |
ospf_vl_shut_unapproved (ospf); |
ospf_vl_shut_unapproved (ospf); |
|
|
|
start_time = stop_time; /* saving a call */ |
|
|
ospf_ia_routing (ospf, new_table, new_rtrs); |
ospf_ia_routing (ospf, new_table, new_rtrs); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
ia_time = timeval_elapsed (stop_time, start_time); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); |
ospf_prune_unreachable_networks (new_table); |
ospf_prune_unreachable_networks (new_table); |
ospf_prune_unreachable_routers (new_rtrs); |
ospf_prune_unreachable_routers (new_rtrs); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
prune_time = timeval_elapsed (stop_time, start_time); |
/* AS-external-LSA calculation should not be performed here. */ |
/* AS-external-LSA calculation should not be performed here. */ |
|
|
/* If new Router Route is installed, |
/* If new Router Route is installed, |
Line 1271 ospf_spf_calculate_timer (struct thread *thread)
|
Line 1372 ospf_spf_calculate_timer (struct thread *thread)
|
|
|
ospf_ase_calculate_timer_add (ospf); |
ospf_ase_calculate_timer_add (ospf); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); |
|
|
/* Update routing table. */ |
/* Update routing table. */ |
ospf_route_install (ospf, new_table); |
ospf_route_install (ospf, new_table); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
rt_time = timeval_elapsed (stop_time, start_time); |
/* Update ABR/ASBR routing table */ |
/* Update ABR/ASBR routing table */ |
if (ospf->old_rtrs) |
if (ospf->old_rtrs) |
{ |
{ |
Line 1285 ospf_spf_calculate_timer (struct thread *thread)
|
Line 1390 ospf_spf_calculate_timer (struct thread *thread)
|
ospf->old_rtrs = ospf->new_rtrs; |
ospf->old_rtrs = ospf->new_rtrs; |
ospf->new_rtrs = new_rtrs; |
ospf->new_rtrs = new_rtrs; |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); |
if (IS_OSPF_ABR (ospf)) |
if (IS_OSPF_ABR (ospf)) |
ospf_abr_task (ospf); |
ospf_abr_task (ospf); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
abr_time = timeval_elapsed (stop_time, start_time); |
|
|
|
quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); |
|
total_spf_time = timeval_elapsed (stop_time, spf_start_time); |
|
ospf->ts_spf_duration.tv_sec = total_spf_time/1000000; |
|
ospf->ts_spf_duration.tv_usec = total_spf_time % 1000000; |
|
|
|
ospf_get_spf_reason_str (rbuf); |
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("SPF: calculation complete"); | { |
| 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; |
return 0; |
} |
} |
|
|
/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we |
/* Add schedule for SPF calculation. To avoid frequenst SPF calc, we |
set timer for SPF calc. */ |
set timer for SPF calc. */ |
void |
void |
ospf_spf_calculate_schedule (struct ospf *ospf) | ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason) |
{ |
{ |
unsigned long delay, elapsed, ht; |
unsigned long delay, elapsed, ht; |
struct timeval result; |
struct timeval result; |
Line 1309 ospf_spf_calculate_schedule (struct ospf *ospf)
|
Line 1437 ospf_spf_calculate_schedule (struct ospf *ospf)
|
if (ospf == NULL) |
if (ospf == NULL) |
return; |
return; |
|
|
|
ospf_spf_set_reason (reason); |
|
|
/* SPF calculation timer is already scheduled. */ |
/* SPF calculation timer is already scheduled. */ |
if (ospf->t_spf_calc) |
if (ospf->t_spf_calc) |
{ |
{ |
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("SPF: calculation timer is already scheduled: %p", |
zlog_debug ("SPF: calculation timer is already scheduled: %p", |
ospf->t_spf_calc); | (void *)ospf->t_spf_calc); |
return; |
return; |
} |
} |
|
|
Line 1352 ospf_spf_calculate_schedule (struct ospf *ospf)
|
Line 1482 ospf_spf_calculate_schedule (struct ospf *ospf)
|
|
|
if (IS_DEBUG_OSPF_EVENT) |
if (IS_DEBUG_OSPF_EVENT) |
zlog_debug ("SPF: calculation timer delay = %ld", delay); |
zlog_debug ("SPF: calculation timer delay = %ld", delay); |
|
|
|
zlog_info ("SPF: Scheduled in %ld msec", delay); |
|
|
ospf->t_spf_calc = |
ospf->t_spf_calc = |
thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay); |
thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay); |