mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-06 18:04:03 +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;
|
uint16_t length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct vertex;
|
||||||
|
|
||||||
/* OSPF LSA. */
|
/* OSPF LSA. */
|
||||||
struct ospf_lsa {
|
struct ospf_lsa {
|
||||||
/* LSA origination flag. */
|
/* LSA origination flag. */
|
||||||
@ -95,10 +97,7 @@ struct ospf_lsa {
|
|||||||
int lock;
|
int lock;
|
||||||
|
|
||||||
/* Flags for the SPF calculation. */
|
/* Flags for the SPF calculation. */
|
||||||
int stat;
|
struct vertex *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;
|
||||||
|
@ -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 ospf_lsa *ospf_lsdb_lookup(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
|
||||||
{
|
{
|
||||||
struct route_table *table;
|
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_add(struct ospf_lsdb *, struct ospf_lsa *);
|
||||||
extern void ospf_lsdb_delete(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 *);
|
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(struct ospf_lsdb *, struct ospf_lsa *);
|
||||||
extern struct ospf_lsa *ospf_lsdb_lookup_by_id(struct ospf_lsdb *, uint8_t,
|
extern struct ospf_lsa *ospf_lsdb_lookup_by_id(struct ospf_lsdb *, uint8_t,
|
||||||
struct in_addr, struct in_addr);
|
struct in_addr, struct in_addr);
|
||||||
|
105
ospfd/ospf_spf.c
105
ospfd/ospf_spf.c
@ -30,7 +30,6 @@
|
|||||||
#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"
|
||||||
@ -53,6 +52,11 @@
|
|||||||
|
|
||||||
static unsigned int spf_reason_flags = 0;
|
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)
|
static void ospf_clear_spf_reason_flags(void)
|
||||||
{
|
{
|
||||||
spf_reason_flags = 0;
|
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
|
/* Heap related functions, for the managment of the candidates, to
|
||||||
* be used with pqueue. */
|
* 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;
|
if (v1->distance != v2->distance)
|
||||||
struct vertex *v2 = (struct vertex *)node2;
|
return v1->distance - v2->distance;
|
||||||
if (v1 != NULL && v2 != NULL) {
|
|
||||||
/* network vertices must be chosen before router vertices of
|
if (v1->type != v2->type) {
|
||||||
* same
|
switch (v1->type) {
|
||||||
* cost in order to find all shortest paths
|
case OSPF_VERTEX_NETWORK:
|
||||||
*/
|
return -1;
|
||||||
if (((v1->distance - v2->distance) == 0)
|
case OSPF_VERTEX_ROUTER:
|
||||||
&& (v1->type != v2->type)) {
|
return 1;
|
||||||
switch (v1->type) {
|
}
|
||||||
case OSPF_VERTEX_NETWORK:
|
|
||||||
return -1;
|
|
||||||
case OSPF_VERTEX_ROUTER:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
return (v1->distance - v2->distance);
|
|
||||||
}
|
}
|
||||||
return 0;
|
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. */
|
for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) {
|
||||||
*(v->stat) = position;
|
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)
|
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 = XCALLOC(MTYPE_OSPF_VERTEX, 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;
|
||||||
@ -187,6 +191,9 @@ static struct vertex *ospf_vertex_new(struct ospf_lsa *lsa)
|
|||||||
new->parents = list_new();
|
new->parents = list_new();
|
||||||
new->parents->del = vertex_parent_free;
|
new->parents->del = vertex_parent_free;
|
||||||
new->parents->cmp = vertex_parent_cmp;
|
new->parents->cmp = vertex_parent_cmp;
|
||||||
|
new->lsa_p = lsa;
|
||||||
|
|
||||||
|
lsa->stat = new;
|
||||||
|
|
||||||
listnode_add(&vertex_list, 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.
|
* 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,
|
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;
|
struct ospf_lsa *w_lsa = NULL;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
@ -935,13 +943,11 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
|
|||||||
/* 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))
|
lsa_pos))
|
||||||
pqueue_enqueue(w, candidate);
|
vertex_pqueue_add(candidate, w);
|
||||||
else if (IS_DEBUG_OSPF_EVENT)
|
else if (IS_DEBUG_OSPF_EVENT)
|
||||||
zlog_debug("Nexthop Calc failed");
|
zlog_debug("Nexthop Calc failed");
|
||||||
} else if (w_lsa->stat >= 0) {
|
} else if (w_lsa->stat != LSA_SPF_IN_SPFTREE) {
|
||||||
/* Get the vertex from candidates. */
|
w = w_lsa->stat;
|
||||||
w = candidate->array[w_lsa->stat];
|
|
||||||
|
|
||||||
/* if D is greater than. */
|
/* if D is greater than. */
|
||||||
if (w->distance < distance) {
|
if (w->distance < distance) {
|
||||||
continue;
|
continue;
|
||||||
@ -962,18 +968,10 @@ static void ospf_spf_next(struct vertex *v, struct ospf *ospf,
|
|||||||
* which
|
* which
|
||||||
* will flush the old parents
|
* will flush the old parents
|
||||||
*/
|
*/
|
||||||
if (ospf_nexthop_calculation(area, v, w, l,
|
vertex_pqueue_del(candidate, w);
|
||||||
distance, lsa_pos))
|
ospf_nexthop_calculation(area, v, w, l,
|
||||||
/* Decrease the key of the node in the
|
distance, lsa_pos);
|
||||||
* heap.
|
vertex_pqueue_add(candidate, w);
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
} /* 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 */
|
||||||
@ -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_table,
|
||||||
struct route_table *new_rtrs)
|
struct route_table *new_rtrs)
|
||||||
{
|
{
|
||||||
struct pqueue *candidate;
|
struct vertex_pqueue_head candidate;
|
||||||
struct vertex *v;
|
struct vertex *v;
|
||||||
|
|
||||||
if (IS_DEBUG_OSPF_EVENT) {
|
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
|
/* This function scans all the LSA database and set the stat field to
|
||||||
* LSA_SPF_NOT_EXPLORED. */
|
* LSA_SPF_NOT_EXPLORED. */
|
||||||
ospf_lsdb_clean_stat(area->lsdb);
|
lsdb_clean_stat(area->lsdb);
|
||||||
/* Create a new heap for the candidates. */
|
/* Create a new heap for the candidates. */
|
||||||
candidate = pqueue_create();
|
vertex_pqueue_init(&candidate);
|
||||||
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). */
|
||||||
@ -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
|
/* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of
|
||||||
* the
|
* the
|
||||||
* spanning tree. */
|
* spanning tree. */
|
||||||
*(v->stat) = LSA_SPF_IN_SPFTREE;
|
v->lsa_p->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;
|
||||||
@ -1215,23 +1211,22 @@ static void ospf_spf_calculate(struct ospf *ospf, struct ospf_area *area,
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* RFC2328 16.1. (2). */
|
/* RFC2328 16.1. (2). */
|
||||||
ospf_spf_next(v, ospf, area, candidate);
|
ospf_spf_next(v, ospf, 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 (candidate->size == 0)
|
|
||||||
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). */
|
||||||
/* Extract from the candidates the node with the lower key. */
|
/* 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. */
|
/* Update stat field in vertex. */
|
||||||
*(v->stat) = LSA_SPF_IN_SPFTREE;
|
v->lsa_p->stat = LSA_SPF_IN_SPFTREE;
|
||||||
|
|
||||||
ospf_vertex_add_parent(v);
|
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);
|
ospf_spf_process_stubs(area, area->spf, new_table, 0);
|
||||||
|
|
||||||
/* Free candidate queue. */
|
/* Free candidate queue. */
|
||||||
pqueue_delete(candidate);
|
//vertex_pqueue_fini(&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
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#ifndef _QUAGGA_OSPF_SPF_H
|
#ifndef _QUAGGA_OSPF_SPF_H
|
||||||
#define _QUAGGA_OSPF_SPF_H
|
#define _QUAGGA_OSPF_SPF_H
|
||||||
|
|
||||||
|
#include "typesafe.h"
|
||||||
|
|
||||||
/* values for vertex->type */
|
/* values for vertex->type */
|
||||||
#define OSPF_VERTEX_ROUTER 1 /* for a Router-LSA */
|
#define OSPF_VERTEX_ROUTER 1 /* for a Router-LSA */
|
||||||
#define OSPF_VERTEX_NETWORK 2 /* for a Network-LSA */
|
#define OSPF_VERTEX_NETWORK 2 /* for a Network-LSA */
|
||||||
@ -31,13 +33,15 @@
|
|||||||
|
|
||||||
/* The "root" is the node running the SPF calculation */
|
/* The "root" is the node running the SPF calculation */
|
||||||
|
|
||||||
|
PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue)
|
||||||
/* A router or network in an area */
|
/* A router or network in an area */
|
||||||
struct vertex {
|
struct vertex {
|
||||||
|
struct vertex_pqueue_item pqi;
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
uint8_t type; /* copied from LSA header */
|
uint8_t type; /* copied from LSA header */
|
||||||
struct in_addr id; /* 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 */
|
struct lsa_header *lsa; /* Router or Network LSA */
|
||||||
int *stat; /* Link to LSA status. */
|
|
||||||
uint32_t distance; /* from root to this vertex */
|
uint32_t distance; /* from root to this vertex */
|
||||||
struct list *parents; /* list of parents in SPF tree */
|
struct list *parents; /* list of parents in SPF tree */
|
||||||
struct list *children; /* list of children in SPF tree*/
|
struct list *children; /* list of children in SPF tree*/
|
||||||
|
Loading…
Reference in New Issue
Block a user