mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-08 07:37:29 +00:00
[ospfd] Bug #330: SPF must consider that nexthop-calc may fail
2007-01-24 Paul Jakma <paul.jakma@sun.com> * ospf_spf.c: Bug #330: Nexthop calculation sometimes may fail, and it needs to indicate this result to SPF. (ospf_spf_add_parent) Flush of parent list needs to be done here, for simplicity. (ospf_nexthop_calculation) Caller needs to know whether nexthop calculation succeeded. Every return statement must correctly indicate such. (ospf_spf_next) Queueing/prioritisation of vertices in SPF must take into account whether nexthop_calculation succeeded, or SPF may fail to find best paths.
This commit is contained in:
parent
fb6724a6b9
commit
bc20c1a463
@ -1,3 +1,16 @@
|
|||||||
|
2007-01-24 Paul Jakma <paul.jakma@sun.com>
|
||||||
|
|
||||||
|
* ospf_spf.c: Bug #330: Nexthop calculation sometimes may fail,
|
||||||
|
and it needs to indicate this result to SPF.
|
||||||
|
(ospf_spf_add_parent) Flush of parent list needs to be done here,
|
||||||
|
for simplicity.
|
||||||
|
(ospf_nexthop_calculation) Caller needs to know whether
|
||||||
|
nexthop calculation succeeded. Every return statement must
|
||||||
|
correctly indicate such.
|
||||||
|
(ospf_spf_next) Queueing/prioritisation of vertices in SPF
|
||||||
|
must take into account whether nexthop_calculation succeeded,
|
||||||
|
or SPF may fail to find best paths.
|
||||||
|
|
||||||
2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
|
2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
|
||||||
|
|
||||||
* ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix,
|
* ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix,
|
||||||
|
121
ospfd/ospf_spf.c
121
ospfd/ospf_spf.c
@ -405,37 +405,6 @@ ospf_get_next_link (struct vertex *v, struct vertex *w,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Consider supplied next-hop for inclusion to the supplied list of
|
|
||||||
* equal-cost next-hops, adjust list as neccessary.
|
|
||||||
*
|
|
||||||
* (Discussed on GNU Zebra list 27 May 2003, [zebra 19184])
|
|
||||||
*
|
|
||||||
* Note that below is a bit of a hack, and limits ECMP to paths that go to
|
|
||||||
* same nexthop. Where as paths via inequal output_cost interfaces could
|
|
||||||
* still quite easily be ECMP due to remote cost differences.
|
|
||||||
*
|
|
||||||
* TODO: It really should be done by way of recording currently valid
|
|
||||||
* backlinks and determining the appropriate nexthops from the list of
|
|
||||||
* backlinks, or even simpler, just flushing nexthop list if we find a lower
|
|
||||||
* cost path to a candidate vertex in SPF, maybe.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
ospf_spf_add_parent (struct vertex *v, struct vertex *w,
|
|
||||||
struct vertex_nexthop *newhop)
|
|
||||||
{
|
|
||||||
struct vertex_parent *vp;
|
|
||||||
|
|
||||||
/* we must have a newhop.. */
|
|
||||||
assert (v && w && newhop);
|
|
||||||
|
|
||||||
/* new parent is <= existing parents, add it */
|
|
||||||
vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop);
|
|
||||||
listnode_add (w->parents, vp);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ospf_spf_flush_parents (struct vertex *w)
|
ospf_spf_flush_parents (struct vertex *w)
|
||||||
{
|
{
|
||||||
@ -450,13 +419,49 @@ ospf_spf_flush_parents (struct vertex *w)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Consider supplied next-hop for inclusion to the supplied list of
|
||||||
|
* equal-cost next-hops, adjust list as neccessary.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ospf_spf_add_parent (struct vertex *v, struct vertex *w,
|
||||||
|
struct vertex_nexthop *newhop,
|
||||||
|
struct router_lsa_link *l)
|
||||||
|
{
|
||||||
|
struct vertex_parent *vp;
|
||||||
|
unsigned int new_distance;
|
||||||
|
|
||||||
|
/* we must have a newhop.. */
|
||||||
|
assert (v && w && l && newhop);
|
||||||
|
|
||||||
|
new_distance = v->distance + ntohs (l->m[0].metric);
|
||||||
|
|
||||||
|
/* We shouldn't get here unless callers have determined V(l)->W is
|
||||||
|
* shortest / equal-shortest path.
|
||||||
|
*/
|
||||||
|
assert (new_distance <= w->distance);
|
||||||
|
|
||||||
|
/* Adding parent for a new, better path: flush existing parents from W. */
|
||||||
|
if (new_distance < w->distance)
|
||||||
|
{
|
||||||
|
ospf_spf_flush_parents (w);
|
||||||
|
w->distance = new_distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* new parent is <= existing parents, add it to parent list */
|
||||||
|
vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop);
|
||||||
|
listnode_add (w->parents, vp);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* 16.1.1. Calculate nexthop from root through V (parent) to
|
/* 16.1.1. Calculate nexthop from root through V (parent) to
|
||||||
* vertex W (destination).
|
* vertex W (destination).
|
||||||
*
|
*
|
||||||
* The link must be supplied if V is the root vertex. In all other cases
|
* The link must be supplied if V is the root vertex. In all other cases
|
||||||
* it may be NULL.
|
* it may be NULL.
|
||||||
*/
|
*/
|
||||||
static void
|
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)
|
||||||
{
|
{
|
||||||
@ -464,6 +469,7 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
|
|||||||
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;
|
||||||
|
|
||||||
if (IS_DEBUG_OSPF_EVENT)
|
if (IS_DEBUG_OSPF_EVENT)
|
||||||
{
|
{
|
||||||
@ -571,7 +577,8 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
|
|||||||
nh = vertex_nexthop_new ();
|
nh = vertex_nexthop_new ();
|
||||||
nh->oi = oi;
|
nh->oi = oi;
|
||||||
nh->router = l2->link_data;
|
nh->router = l2->link_data;
|
||||||
ospf_spf_add_parent (v, w, nh);
|
ospf_spf_add_parent (v, w, nh, l);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
zlog_info("ospf_nexthop_calculation(): "
|
zlog_info("ospf_nexthop_calculation(): "
|
||||||
@ -596,13 +603,14 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
|
|||||||
nh = vertex_nexthop_new ();
|
nh = vertex_nexthop_new ();
|
||||||
nh->oi = vl_data->nexthop.oi;
|
nh->oi = vl_data->nexthop.oi;
|
||||||
nh->router = vl_data->nexthop.router;
|
nh->router = vl_data->nexthop.router;
|
||||||
ospf_spf_add_parent (v, w, nh);
|
ospf_spf_add_parent (v, w, nh, l);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
zlog_info("ospf_nexthop_calculation(): "
|
zlog_info("ospf_nexthop_calculation(): "
|
||||||
"vl_data for VL link not found");
|
"vl_data for VL link not found");
|
||||||
} /* end virtual-link from V to W */
|
} /* end virtual-link from V to W */
|
||||||
return;
|
return 0;
|
||||||
} /* end W is a Router vertex */
|
} /* end W is a Router vertex */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -613,13 +621,13 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
|
|||||||
nh = vertex_nexthop_new ();
|
nh = vertex_nexthop_new ();
|
||||||
nh->oi = oi;
|
nh->oi = oi;
|
||||||
nh->router.s_addr = 0;
|
nh->router.s_addr = 0;
|
||||||
ospf_spf_add_parent (v, w, nh);
|
ospf_spf_add_parent (v, w, nh, l);
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
zlog_info("ospf_nexthop_calculation(): "
|
zlog_info("ospf_nexthop_calculation(): "
|
||||||
"Unknown attached link");
|
"Unknown attached link");
|
||||||
return;
|
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)
|
||||||
@ -647,12 +655,13 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
|
|||||||
nh = vertex_nexthop_new ();
|
nh = vertex_nexthop_new ();
|
||||||
nh->oi = vp->nexthop->oi;
|
nh->oi = vp->nexthop->oi;
|
||||||
nh->router = l->link_data;
|
nh->router = l->link_data;
|
||||||
ospf_spf_add_parent (v, w, nh);
|
added = 1;
|
||||||
}
|
ospf_spf_add_parent (v, w, nh, l);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
/* 16.1.1 para 4. If there is at least one intervening router in the
|
/* 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
|
* current shortest path between the destination and the root, the
|
||||||
@ -660,9 +669,12 @@ ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v,
|
|||||||
* parent.
|
* parent.
|
||||||
*/
|
*/
|
||||||
for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp))
|
for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp))
|
||||||
ospf_spf_add_parent (v, w, vp->nexthop);
|
{
|
||||||
|
added = 1;
|
||||||
|
ospf_spf_add_parent (v, w, vp->nexthop, l);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RFC2328 Section 16.1 (2).
|
/* RFC2328 Section 16.1 (2).
|
||||||
@ -801,11 +813,10 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
|
|||||||
{
|
{
|
||||||
/* prepare vertex W. */
|
/* prepare vertex W. */
|
||||||
w = ospf_vertex_new (w_lsa);
|
w = ospf_vertex_new (w_lsa);
|
||||||
|
|
||||||
/* Calculate nexthop to W. */
|
|
||||||
w->distance = distance;
|
w->distance = distance;
|
||||||
|
|
||||||
ospf_nexthop_calculation (area, v, w, l);
|
/* Calculate nexthop to W. */
|
||||||
|
if (ospf_nexthop_calculation (area, v, w, l))
|
||||||
pqueue_enqueue (w, candidate);
|
pqueue_enqueue (w, candidate);
|
||||||
}
|
}
|
||||||
else if (w_lsa->stat >= 0)
|
else if (w_lsa->stat >= 0)
|
||||||
@ -828,16 +839,14 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
|
|||||||
/* less than. */
|
/* less than. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Found a lower-cost path to W. */
|
/* Found a lower-cost path to W.
|
||||||
w->distance = distance;
|
* nexthop_calculation is conditional, if it finds
|
||||||
|
* valid nexthop it will call spf_add_parents, which
|
||||||
/* Flush existing parent list from W */
|
* will flush the old parents
|
||||||
ospf_spf_flush_parents (w);
|
*/
|
||||||
|
if (ospf_nexthop_calculation (area, v, w, l))
|
||||||
/* Calculate new nexthop(s) to W. */
|
/* Decrease the key of the node in the heap,
|
||||||
ospf_nexthop_calculation (area, v, w, l);
|
* re-sort the heap. */
|
||||||
|
|
||||||
/* Decrease the key of the node in the heap, re-sort the heap. */
|
|
||||||
trickle_down (w_lsa->stat, candidate);
|
trickle_down (w_lsa->stat, candidate);
|
||||||
}
|
}
|
||||||
} /* end W is already on the candidate list */
|
} /* end W is already on the candidate list */
|
||||||
|
Loading…
Reference in New Issue
Block a user