* ospf_lsa.h: New flag to the LSA structure for the SPF calculation.

* ospf_lsdb.h: Export ospf_lsdb_clean_stat() function.
	* ospf_spf.h: Add link to the LSA stat structure into vertex.
	* ospf_spf.c: New functions cmp() and update_stat() to manage
	  candidates. Remove ospf_spf_has_vertex(), ospf_vertex_lookup(),
	  ospf_install_candidate() and ospf_spf_register() functions not needed
	  any more. Update ospf_vertex_new(), ospf_spf_next() and
	  ospf_spf_calculate() functions to use pqueue instead of linked list.
This commit is contained in:
hasso 2005-02-23 11:29:02 +00:00
parent c3c07f28dc
commit 462f20d50c
6 changed files with 107 additions and 171 deletions

View File

@ -1,3 +1,14 @@
2005-02-23 Vincenzo Eramo <eramo at infocom.ing.uniroma1.it>
* ospf_lsa.h: New flag to the LSA structure for the SPF calculation.
* ospf_lsdb.h: Export ospf_lsdb_clean_stat() function.
* ospf_spf.h: Add link to the LSA stat structure into vertex.
* ospf_spf.c: New functions cmp() and update_stat() to manage
candidates. Remove ospf_spf_has_vertex(), ospf_vertex_lookup(),
ospf_install_candidate() and ospf_spf_register() functions not needed
any more. Update ospf_vertex_new(), ospf_spf_next() and
ospf_spf_calculate() functions to use pqueue instead of linked list.
2005-02-21 Hasso Tepper <hasso at quagga.net> 2005-02-21 Hasso Tepper <hasso at quagga.net>
* ospf_ase.c: Don't show messages related to the ase calculations if * ospf_ase.c: Don't show messages related to the ase calculations if

View File

@ -90,6 +90,12 @@ struct ospf_lsa
/* All of reference count, also lock to remove. */ /* All of reference count, also lock to remove. */
int lock; int lock;
/* Flags for the SPF calculation. */
int stat;
#define LSA_SPF_NOT_EXPLORED -1
#define LSA_SPF_IN_SPFTREE -2
/* If stat >= 0, stat is LSA position in candidates heap. */
/* References to this LSA in neighbor retransmission lists*/ /* References to this LSA in neighbor retransmission lists*/
int retransmit_counter; int retransmit_counter;

View File

@ -180,6 +180,23 @@ ospf_lsdb_delete_all (struct ospf_lsdb *lsdb)
} }
} }
void
ospf_lsdb_clean_stat (struct ospf_lsdb *lsdb)
{
struct route_table *table;
struct route_node *rn;
struct ospf_lsa *lsa;
int i;
for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
{
table = lsdb->type[i].db;
for (rn = route_top (table); rn; rn = route_next (rn))
if ((lsa = (rn->info)) != NULL)
lsa->stat = LSA_SPF_NOT_EXPLORED;
}
}
struct ospf_lsa * struct ospf_lsa *
ospf_lsdb_lookup (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) ospf_lsdb_lookup (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
{ {

View File

@ -69,6 +69,8 @@ void ospf_lsdb_cleanup (struct ospf_lsdb *);
void ospf_lsdb_add (struct ospf_lsdb *, struct ospf_lsa *); void ospf_lsdb_add (struct ospf_lsdb *, struct ospf_lsa *);
void ospf_lsdb_delete (struct ospf_lsdb *, struct ospf_lsa *); void ospf_lsdb_delete (struct ospf_lsdb *, struct ospf_lsa *);
void ospf_lsdb_delete_all (struct ospf_lsdb *); void ospf_lsdb_delete_all (struct ospf_lsdb *);
/* Set all stats to -1 (LSA_SPF_NOT_EXPLORED). */
void ospf_lsdb_clean_stat (struct ospf_lsdb *lsdb);
struct ospf_lsa *ospf_lsdb_lookup (struct ospf_lsdb *, struct ospf_lsa *); struct ospf_lsa *ospf_lsdb_lookup (struct ospf_lsdb *, struct ospf_lsa *);
struct ospf_lsa *ospf_lsdb_lookup_by_id (struct ospf_lsdb *, u_char, struct ospf_lsa *ospf_lsdb_lookup_by_id (struct ospf_lsdb *, u_char,
struct in_addr, struct in_addr); struct in_addr, struct in_addr);

View File

@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "table.h" #include "table.h"
#include "log.h" #include "log.h"
#include "sockunion.h" /* for inet_ntop () */ #include "sockunion.h" /* for inet_ntop () */
#include "pqueue.h"
#include "ospfd/ospfd.h" #include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h" #include "ospfd/ospf_interface.h"
@ -47,6 +48,28 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define DEBUG #define DEBUG
/* Heap related functions, for the managment of the candidates, to
* be used with pqueue. */
static int
cmp (void * node1 , void * node2)
{
struct vertex * v1 = (struct vertex *) node1;
struct vertex * v2 = (struct vertex *) node2;
if (v1 != NULL && v2 != NULL )
return (v1->distance - v2->distance);
else
return 0;
}
static void
update_stat (void * node , int position)
{
struct vertex * v = (struct vertex *) node;
/* Set the status of the vertex, when its position changes. */
*(v->stat) = position;
}
/* End of the heap related functions. */
struct vertex_nexthop * struct vertex_nexthop *
vertex_nexthop_new (struct vertex *parent) vertex_nexthop_new (struct vertex *parent)
{ {
@ -87,6 +110,7 @@ ospf_vertex_new (struct ospf_lsa *lsa)
memset (new, 0, sizeof (struct vertex)); memset (new, 0, sizeof (struct vertex));
new->flags = 0; new->flags = 0;
new->stat = &(lsa->stat);
new->type = lsa->data->type; new->type = lsa->data->type;
new->id = lsa->data->id; new->id = lsa->data->id;
new->lsa = lsa->data; new->lsa = lsa->data;
@ -197,50 +221,6 @@ ospf_spf_init (struct ospf_area *area)
area->asbr_count = 0; area->asbr_count = 0;
} }
/* Check if the vertex represented by lsa is on the SPF tree. */
int
ospf_spf_has_vertex (struct route_table *rv, struct route_table *nv,
struct lsa_header *lsa)
{
struct prefix p;
struct route_node *rn;
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
p.u.prefix4 = lsa->id;
if (lsa->type == OSPF_ROUTER_LSA)
rn = route_node_get (rv, &p);
else
rn = route_node_get (nv, &p);
if (rn->info != NULL)
{
route_unlock_node (rn);
return 1;
}
return 0;
}
/* Find the vertex specified by the given id and LSA type
* in vlist (the candidate list).
*/
struct listnode *
ospf_vertex_lookup (struct list *vlist, struct in_addr id, int type)
{
struct listnode *node;
struct vertex *v;
for (node = listhead (vlist); node; nextnode (node))
{
v = (struct vertex *) getdata (node);
if (IPV4_ADDR_SAME (&id, &v->id) && type == v->type)
return node;
}
return NULL;
}
/* return index of link back to V from W, or -1 if no link found */ /* return index of link back to V from W, or -1 if no link found */
int int
ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v) ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v)
@ -643,48 +623,6 @@ ospf_nexthop_calculation (struct ospf_area *area,
} }
} }
/* Add a vertex to the SPF candidate list. */
void
ospf_install_candidate (struct list *candidate, struct vertex *w)
{
struct listnode *node;
struct vertex *cw;
ospf_vertex_dump("ospf_install_candidate(): add to candidate list", w, 1, 1);
if (list_isempty (candidate))
{
listnode_add (candidate, w);
return;
}
/* Install vertex with sorting by distance. */
for (node = listhead (candidate); node; nextnode (node))
{
cw = (struct vertex *) getdata (node);
if (cw->distance > w->distance)
{
list_add_node_prev (candidate, node, w);
break;
}
else if (node->next == NULL)
{
list_add_node_next (candidate, node, w);
break;
}
}
if (IS_DEBUG_OSPF_EVENT)
{
zlog_debug("ospf_install_candidate(): candidate list now contains:");
for (node = listhead (candidate); node; nextnode (node))
{
cw = (struct vertex *) getdata (node);
ospf_vertex_dump(" candidate:", cw, 0, 0);
}
}
}
/* RFC2328 Section 16.1 (2). /* RFC2328 Section 16.1 (2).
* v is on the SPF tree. Examine the links in v's LSA. Update the list * v is on the SPF tree. Examine the links in v's LSA. Update the list
* of candidates with any vertices not already on the list. If a lower-cost * of candidates with any vertices not already on the list. If a lower-cost
@ -692,8 +630,7 @@ ospf_install_candidate (struct list *candidate, struct vertex *w)
*/ */
void void
ospf_spf_next (struct vertex *v, struct ospf_area *area, ospf_spf_next (struct vertex *v, struct ospf_area *area,
struct list *candidate, struct route_table *rv, struct pqueue * candidate)
struct route_table *nv)
{ {
struct ospf_lsa *w_lsa = NULL; struct ospf_lsa *w_lsa = NULL;
struct vertex *w, *cw; struct vertex *w, *cw;
@ -701,7 +638,6 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
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;
struct listnode *node;
int type = 0; int type = 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
@ -799,7 +735,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
/* (c) If vertex W is already on the shortest-path tree, examine /* (c) If vertex W is already on the shortest-path tree, examine
the next link in the LSA. */ the next link in the LSA. */
if (ospf_spf_has_vertex (rv, nv, w_lsa->data)) if (w_lsa->stat == LSA_SPF_IN_SPFTREE)
{ {
if (IS_DEBUG_OSPF_EVENT) if (IS_DEBUG_OSPF_EVENT)
zlog_debug ("The LSA is already in SPF"); zlog_debug ("The LSA is already in SPF");
@ -825,33 +761,24 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
w->distance = v->distance; w->distance = v->distance;
/* Is there already vertex W in candidate list? */ /* Is there already vertex W in candidate list? */
node = ospf_vertex_lookup (candidate, w->id, w->type); if (w_lsa->stat == LSA_SPF_NOT_EXPLORED)
if (node == NULL)
{ {
/* W is a new candidate. Calculate nexthop to W and add W /* Calculate nexthop to W. */
* to the candidate list.
*/
ospf_nexthop_calculation (area, v, w); ospf_nexthop_calculation (area, v, w);
pqueue_enqueue (w, candidate);
ospf_install_candidate (candidate, w);
} }
else else if (w_lsa->stat >= 0)
{ {
/* W is already on the candidate list; call it cw. /* Get the vertex from candidates. */
* Compare the previously calculated cost (cw->distance) cw = (struct vertex *) candidate->array[w_lsa->stat];
* with the cost we just determined (w->distance) to see
* if we've found a shorter path.
*/
cw = (struct vertex *) getdata (node);
/* If the previous cost was lower, we didn't find a /* if D is greater than. */
* shorter path, so we're done with w.
*/
if (cw->distance < w->distance) if (cw->distance < w->distance)
{ {
ospf_vertex_free (w); ospf_vertex_free (w);
continue; continue;
} }
/* equal to. */
else if (cw->distance == w->distance) else if (cw->distance == w->distance)
{ {
/* Found an equal-cost path to W. Calculate nexthop to W. */ /* Found an equal-cost path to W. Calculate nexthop to W. */
@ -860,6 +787,7 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
list_delete_all_node (w->nexthop); list_delete_all_node (w->nexthop);
ospf_vertex_free (w); ospf_vertex_free (w);
} }
/* less than. */
else else
{ {
/* Found a lower-cost path to W. Calculate nexthop to W. */ /* Found a lower-cost path to W. Calculate nexthop to W. */
@ -867,37 +795,14 @@ ospf_spf_next (struct vertex *v, struct ospf_area *area,
/* Remove old vertex from candidate list. */ /* Remove old vertex from candidate list. */
ospf_vertex_free (cw); ospf_vertex_free (cw);
listnode_delete (candidate, cw); candidate->array[w_lsa->stat] = w;
/* Decrease the key of the node in the heap, re-sort the heap. */
/* Install new W to candidate list. */ trickle_down (w_lsa->stat, candidate);
ospf_install_candidate (candidate, w);
} }
} /* end W is already on the candidate list */ } /* end W is already on the candidate list */
} /* end loop over the links in V's LSA */ } /* end loop over the links in V's LSA */
} }
/* Add vertex V to SPF tree. */
void
ospf_spf_register (struct vertex *v, struct route_table *rv,
struct route_table *nv)
{
struct prefix p;
struct route_node *rn;
ospf_vertex_dump("ospf_spf_register(): adding to SPF tree:", v, 1, 1);
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
p.u.prefix4 = v->id;
if (v->type == OSPF_VERTEX_ROUTER)
rn = route_node_get (rv, &p);
else
rn = route_node_get (nv, &p);
rn->info = v;
}
void void
ospf_spf_route_free (struct route_table *table) ospf_spf_route_free (struct route_table *table)
{ {
@ -1103,11 +1008,8 @@ void
ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table,
struct route_table *new_rtrs) struct route_table *new_rtrs)
{ {
struct list *candidate; struct pqueue *candidate;
struct listnode *node;
struct vertex *v; struct vertex *v;
struct route_table *rv;
struct route_table *nv;
if (IS_DEBUG_OSPF_EVENT) if (IS_DEBUG_OSPF_EVENT)
{ {
@ -1129,17 +1031,22 @@ ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table,
/* RFC2328 16.1. (1). */ /* RFC2328 16.1. (1). */
/* Initialize the algorithm's data structures. */ /* Initialize the algorithm's data structures. */
rv = route_table_init ();
nv = route_table_init ();
/* Clear the list of candidate vertices. */ /* This function scans all the LSA database and set the stat field to
candidate = list_new (); * 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 /* Initialize the shortest-path tree to only the root (which is the
router doing the calculation). */ router doing the calculation). */
ospf_spf_init (area); ospf_spf_init (area);
v = area->spf; v = area->spf;
ospf_spf_register (v, rv, nv); /* 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. */ /* Set Area A's TransitCapability to FALSE. */
area->transit = OSPF_TRANSIT_FALSE; area->transit = OSPF_TRANSIT_FALSE;
@ -1148,29 +1055,25 @@ ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table,
for (;;) for (;;)
{ {
/* RFC2328 16.1. (2). */ /* RFC2328 16.1. (2). */
ospf_spf_next (v, area, candidate, rv, nv); ospf_spf_next (v, area, candidate);
/* RFC2328 16.1. (3). */ /* RFC2328 16.1. (3). */
/* If at this step the candidate list is empty, the shortest- /* If at this step the candidate list is empty, the shortest-
path tree (of transit vertices) has been completely built and path tree (of transit vertices) has been completely built and
this stage of the procedure terminates. */ this stage of the procedure terminates. */
if (listcount (candidate) == 0) if (candidate->size == 0)
break; break;
/* Otherwise, choose the vertex belonging to the candidate list /* Otherwise, choose the vertex belonging to the candidate list
that is closest to the root, and add it to the shortest-path that is closest to the root, and add it to the shortest-path
tree (removing it from the candidate list in the tree (removing it from the candidate list in the
process). */ process). */
node = listhead (candidate); /* Extract from the candidates the node with the lower key. */
v = getdata (node); v = (struct vertex *) pqueue_dequeue (candidate);
/* Update stat field in vertex. */
*(v->stat) = LSA_SPF_IN_SPFTREE;
ospf_vertex_add_parent (v); ospf_vertex_add_parent (v);
/* Remove from the candidate list. */
listnode_delete (candidate, v);
/* Add to SPF tree. */
ospf_spf_register (v, rv, nv);
/* Note that when there is a choice of vertices closest to the /* Note that when there is a choice of vertices closest to the
root, network vertices must be chosen before router vertices root, network vertices must be chosen before router vertices
in order to necessarily find all equal-cost paths. */ in order to necessarily find all equal-cost paths. */
@ -1197,12 +1100,8 @@ ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table,
/* Second stage of SPF calculation procedure's */ /* Second stage of SPF calculation procedure's */
ospf_spf_process_stubs (area, area->spf, new_table); ospf_spf_process_stubs (area, area->spf, new_table);
/* Free all vertices which allocated for SPF calculation */ /* Free candidates. */
ospf_spf_route_free (rv); pqueue_delete (candidate);
ospf_spf_route_free (nv);
/* Free candidate list */
list_free (candidate);
/* Increment SPF Calculation Counter. */ /* Increment SPF Calculation Counter. */
area->spf_calculation++; area->spf_calculation++;

View File

@ -36,6 +36,7 @@ struct vertex
u_char type; /* copied from LSA header */ u_char type; /* copied from LSA header */
struct in_addr id; /* copied from LSA header */ struct in_addr id; /* copied from LSA header */
struct lsa_header *lsa; /* Router or Network LSA */ struct lsa_header *lsa; /* Router or Network LSA */
int * stat; /* Link to LSA status. */
u_int32_t distance; /* from root to this vertex */ u_int32_t distance; /* from root to this vertex */
int backlink; /* link index of back-link */ int backlink; /* link index of back-link */
struct list *child; /* list of vertex: children in SPF tree*/ struct list *child; /* list of vertex: children in SPF tree*/