version 1.1.1.2, 2012/10/09 09:22:29
|
version 1.1.1.3, 2013/07/21 23:54:40
|
Line 422 ospf_spf_add_parent (struct vertex *v, struct vertex *
|
Line 422 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 457 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 490 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 517 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; |
|
|
/* 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 559 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) | { |
{ | added = 1; |
struct prefix_ipv4 la; | nexthop.s_addr = 0; /* Nexthop not required */ |
| } |
| else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) |
| { |
| struct prefix_ipv4 la; |
|
|
la.family = AF_INET; | la.family = AF_INET; |
la.prefixlen = oi->address->prefixlen; | la.prefixlen = oi->address->prefixlen; |
|
|
/* V links to W on PtMP interface | /* V links to W on PtMP interface |
- find the interface address on W */ | - find the interface address on W */ |
while ((l2 = ospf_get_next_link (w, v, l2))) | while ((l2 = ospf_get_next_link (w, v, l2))) |
{ | { |
la.prefix = l2->link_data; | la.prefix = l2->link_data; |
|
|
if (prefix_cmp ((struct prefix *) &la, | if (prefix_cmp ((struct prefix *) &la, |
oi->address) == 0) | oi->address) != 0) |
/* link_data is on our PtMP network */ | continue; |
break; | /* link_data is on our PtMP network */ |
} | added = 1; |
} /* end l is on point-to-multipoint link */ | nexthop = l2->link_data; |
else | break; |
{ | } |
/* 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 (added) |
continue; | |
| |
if (!IPV4_ADDR_SAME (&oi->address->u.prefix4, | |
&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 638 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 675 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 739 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 768 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 891 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 911 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 921 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 969 ospf_spf_process_stubs (struct ospf_area *area, struct
|
Line 987 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 1009 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++; |
} |
} |
} |
} |
|
|