mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 15:16:20 +00:00
ospfd: replace pqueue_* with DECLARE_SKIPLIST
This replaces the SPF pqueue_* with a DECLARE_SKIPLIST_* skiplist. Signed-off-by: David Lamparter <equinox@diac24.net>
This commit is contained in:
parent
4ab0496e38
commit
c971918aec
@ -69,6 +69,8 @@ struct lsa_header {
|
||||
uint16_t length;
|
||||
};
|
||||
|
||||
struct vertex;
|
||||
|
||||
/* OSPF LSA. */
|
||||
struct ospf_lsa {
|
||||
/* LSA origination flag. */
|
||||
@ -95,10 +97,7 @@ struct ospf_lsa {
|
||||
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. */
|
||||
struct vertex *stat;
|
||||
|
||||
/* References to this LSA in neighbor retransmission lists*/
|
||||
int retransmit_counter;
|
||||
|
@ -169,21 +169,6 @@ void 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 *ospf_lsdb_lookup(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
|
||||
{
|
||||
struct route_table *table;
|
||||
|
@ -67,8 +67,6 @@ extern void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa);
|
||||
extern void ospf_lsdb_add(struct ospf_lsdb *, struct ospf_lsa *);
|
||||
extern void ospf_lsdb_delete(struct ospf_lsdb *, struct ospf_lsa *);
|
||||
extern void ospf_lsdb_delete_all(struct ospf_lsdb *);
|
||||
/* Set all stats to -1 (LSA_SPF_NOT_EXPLORED). */
|
||||
extern void ospf_lsdb_clean_stat(struct ospf_lsdb *lsdb);
|
||||
extern struct ospf_lsa *ospf_lsdb_lookup(struct ospf_lsdb *, struct ospf_lsa *);
|
||||
extern struct ospf_lsa *ospf_lsdb_lookup_by_id(struct ospf_lsdb *, uint8_t,
|
||||
struct in_addr, struct in_addr);
|
||||
|
105
ospfd/ospf_spf.c
105
ospfd/ospf_spf.c
@ -30,7 +30,6 @@
|
||||
#include "table.h"
|
||||
#include "log.h"
|
||||
#include "sockunion.h" /* for inet_ntop () */
|
||||
#include "pqueue.h"
|
||||
|
||||
#include "ospfd/ospfd.h"
|
||||
#include "ospfd/ospf_interface.h"
|
||||
@ -53,6 +52,11 @@
|
||||
|
||||
static unsigned int spf_reason_flags = 0;
|
||||
|
||||
/* dummy vertex to flag "in spftree" */
|
||||
static const struct vertex vertex_in_spftree = {};
|
||||
#define LSA_SPF_IN_SPFTREE (struct vertex *)&vertex_in_spftree
|
||||
#define LSA_SPF_NOT_EXPLORED NULL
|
||||
|
||||
static void ospf_clear_spf_reason_flags(void)
|
||||
{
|
||||
spf_reason_flags = 0;
|
||||
@ -72,35 +76,36 @@ 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 vertex_cmp(const struct vertex *v1, const struct vertex *v2)
|
||||
{
|
||||
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);
|
||||
if (v1->distance != v2->distance)
|
||||
return v1->distance - v2->distance;
|
||||
|
||||
if (v1->type != v2->type) {
|
||||
switch (v1->type) {
|
||||
case OSPF_VERTEX_NETWORK:
|
||||
return -1;
|
||||
case OSPF_VERTEX_ROUTER:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct vertex, pqi, vertex_cmp)
|
||||
|
||||
static void update_stat(void *node, int position)
|
||||
static void lsdb_clean_stat(struct ospf_lsdb *lsdb)
|
||||
{
|
||||
struct vertex *v = node;
|
||||
struct route_table *table;
|
||||
struct route_node *rn;
|
||||
struct ospf_lsa *lsa;
|
||||
int i;
|
||||
|
||||
/* Set the status of the vertex, when its position changes. */
|
||||
*(v->stat) = position;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static struct vertex_nexthop *vertex_nexthop_new(void)
|
||||
@ -179,7 +184,6 @@ static struct vertex *ospf_vertex_new(struct ospf_lsa *lsa)
|
||||
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;
|
||||
@ -187,6 +191,9 @@ static struct vertex *ospf_vertex_new(struct ospf_lsa *lsa)
|
||||
new->parents = list_new();
|
||||
new->parents->del = vertex_parent_free;
|
||||
new->parents->cmp = vertex_parent_cmp;
|
||||
new->lsa_p = lsa;
|
||||
|
||||
lsa->stat = new;
|
||||
|
||||
listnode_add(&vertex_list, new);
|
||||
|
||||
@ -786,7 +793,8 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area,
|
||||
* 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 *ospf,
|
||||
struct ospf_area *area, struct pqueue *candidate)
|
||||
struct ospf_area *area,
|
||||
struct vertex_pqueue_head *candidate)
|
||||
{
|
||||
struct ospf_lsa *w_lsa = NULL;
|
||||
uint8_t *p;
|
||||
@ -935,13 +943,11 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
|
||||
/* Calculate nexthop to W. */
|
||||
if (ospf_nexthop_calculation(area, v, w, l, distance,
|
||||
lsa_pos))
|
||||
pqueue_enqueue(w, candidate);
|
||||
vertex_pqueue_add(candidate, w);
|
||||
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];
|
||||
|
||||
} else if (w_lsa->stat != LSA_SPF_IN_SPFTREE) {
|
||||
w = w_lsa->stat;
|
||||
/* if D is greater than. */
|
||||
if (w->distance < distance) {
|
||||
continue;
|
||||
@ -962,18 +968,10 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
|
||||
* 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);
|
||||
vertex_pqueue_del(candidate, w);
|
||||
ospf_nexthop_calculation(area, v, w, l,
|
||||
distance, lsa_pos);
|
||||
vertex_pqueue_add(candidate, w);
|
||||
}
|
||||
} /* end W is already on the candidate list */
|
||||
} /* end loop over the links in V's LSA */
|
||||
@ -1169,7 +1167,7 @@ static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
|
||||
struct route_table *new_table,
|
||||
struct route_table *new_rtrs)
|
||||
{
|
||||
struct pqueue *candidate;
|
||||
struct vertex_pqueue_head candidate;
|
||||
struct vertex *v;
|
||||
|
||||
if (IS_DEBUG_OSPF_EVENT) {
|
||||
@ -1194,11 +1192,9 @@ static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
|
||||
|
||||
/* This function scans all the LSA database and set the stat field to
|
||||
* LSA_SPF_NOT_EXPLORED. */
|
||||
ospf_lsdb_clean_stat(area->lsdb);
|
||||
lsdb_clean_stat(area->lsdb);
|
||||
/* Create a new heap for the candidates. */
|
||||
candidate = pqueue_create();
|
||||
candidate->cmp = cmp;
|
||||
candidate->update = update_stat;
|
||||
vertex_pqueue_init(&candidate);
|
||||
|
||||
/* Initialize the shortest-path tree to only the root (which is the
|
||||
router doing the calculation). */
|
||||
@ -1207,7 +1203,7 @@ static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
|
||||
/* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of
|
||||
* the
|
||||
* spanning tree. */
|
||||
*(v->stat) = LSA_SPF_IN_SPFTREE;
|
||||
v->lsa_p->stat = LSA_SPF_IN_SPFTREE;
|
||||
|
||||
/* Set Area A's TransitCapability to FALSE. */
|
||||
area->transit = OSPF_TRANSIT_FALSE;
|
||||
@ -1215,23 +1211,22 @@ static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
|
||||
|
||||
for (;;) {
|
||||
/* RFC2328 16.1. (2). */
|
||||
ospf_spf_next(v, ospf, area, candidate);
|
||||
ospf_spf_next(v, ospf, 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);
|
||||
v = vertex_pqueue_pop(&candidate);
|
||||
if (!v)
|
||||
break;
|
||||
/* Update stat field in vertex. */
|
||||
*(v->stat) = LSA_SPF_IN_SPFTREE;
|
||||
v->lsa_p->stat = LSA_SPF_IN_SPFTREE;
|
||||
|
||||
ospf_vertex_add_parent(v);
|
||||
|
||||
@ -1255,7 +1250,7 @@ static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
|
||||
ospf_spf_process_stubs(area, area->spf, new_table, 0);
|
||||
|
||||
/* Free candidate queue. */
|
||||
pqueue_delete(candidate);
|
||||
//vertex_pqueue_fini(&candidate);
|
||||
|
||||
ospf_vertex_dump(__func__, area->spf, 0, 1);
|
||||
/* Free nexthop information, canonical versions of which are attached
|
||||
|
@ -22,6 +22,8 @@
|
||||
#ifndef _QUAGGA_OSPF_SPF_H
|
||||
#define _QUAGGA_OSPF_SPF_H
|
||||
|
||||
#include "typesafe.h"
|
||||
|
||||
/* values for vertex->type */
|
||||
#define OSPF_VERTEX_ROUTER 1 /* for a Router-LSA */
|
||||
#define OSPF_VERTEX_NETWORK 2 /* for a Network-LSA */
|
||||
@ -31,13 +33,15 @@
|
||||
|
||||
/* The "root" is the node running the SPF calculation */
|
||||
|
||||
PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue)
|
||||
/* A router or network in an area */
|
||||
struct vertex {
|
||||
struct vertex_pqueue_item pqi;
|
||||
uint8_t flags;
|
||||
uint8_t type; /* copied from LSA header */
|
||||
struct in_addr id; /* copied from LSA header */
|
||||
struct ospf_lsa *lsa_p;
|
||||
struct lsa_header *lsa; /* Router or Network LSA */
|
||||
int *stat; /* Link to LSA status. */
|
||||
uint32_t distance; /* from root to this vertex */
|
||||
struct list *parents; /* list of parents in SPF tree */
|
||||
struct list *children; /* list of children in SPF tree*/
|
||||
|
Loading…
Reference in New Issue
Block a user