mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-16 02:30:52 +00:00
Merge pull request #909 from opensourcerouting/isis-perf
IS-IS: improve spf performance
This commit is contained in:
commit
6b36796215
@ -601,3 +601,24 @@ void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
|
|||||||
|
|
||||||
XFREE(MTYPE_TMP, p);
|
XFREE(MTYPE_TMP, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vty_out_timestr(struct vty *vty, time_t uptime)
|
||||||
|
{
|
||||||
|
struct tm *tm;
|
||||||
|
time_t difftime = time(NULL);
|
||||||
|
difftime -= uptime;
|
||||||
|
tm = gmtime(&difftime);
|
||||||
|
|
||||||
|
#define ONE_DAY_SECOND 60*60*24
|
||||||
|
#define ONE_WEEK_SECOND 60*60*24*7
|
||||||
|
if (difftime < ONE_DAY_SECOND)
|
||||||
|
vty_out(vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
|
||||||
|
tm->tm_sec);
|
||||||
|
else if (difftime < ONE_WEEK_SECOND)
|
||||||
|
vty_out(vty, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
|
||||||
|
tm->tm_min);
|
||||||
|
else
|
||||||
|
vty_out(vty, "%02dw%dd%02dh", tm->tm_yday / 7,
|
||||||
|
tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
|
||||||
|
vty_out(vty, " ago");
|
||||||
|
}
|
||||||
|
@ -84,4 +84,5 @@ void log_multiline(int priority, const char *prefix, const char *format, ...)
|
|||||||
struct vty;
|
struct vty;
|
||||||
void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
|
void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
|
||||||
PRINTF_ATTRIBUTE(3, 4);
|
PRINTF_ATTRIBUTE(3, 4);
|
||||||
|
void vty_out_timestr(struct vty *vty, time_t uptime);
|
||||||
#endif
|
#endif
|
||||||
|
330
isisd/isis_spf.c
330
isisd/isis_spf.c
@ -35,6 +35,7 @@
|
|||||||
#include "if.h"
|
#include "if.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "spf_backoff.h"
|
#include "spf_backoff.h"
|
||||||
|
#include "jhash.h"
|
||||||
|
|
||||||
#include "isis_constants.h"
|
#include "isis_constants.h"
|
||||||
#include "isis_common.h"
|
#include "isis_common.h"
|
||||||
@ -55,6 +56,160 @@
|
|||||||
|
|
||||||
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
|
DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
|
||||||
|
|
||||||
|
enum vertextype {
|
||||||
|
VTYPE_PSEUDO_IS = 1,
|
||||||
|
VTYPE_PSEUDO_TE_IS,
|
||||||
|
VTYPE_NONPSEUDO_IS,
|
||||||
|
VTYPE_NONPSEUDO_TE_IS,
|
||||||
|
VTYPE_ES,
|
||||||
|
VTYPE_IPREACH_INTERNAL,
|
||||||
|
VTYPE_IPREACH_EXTERNAL,
|
||||||
|
VTYPE_IPREACH_TE,
|
||||||
|
VTYPE_IP6REACH_INTERNAL,
|
||||||
|
VTYPE_IP6REACH_EXTERNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
|
||||||
|
#define VTYPE_ES(t) ((t) == VTYPE_ES)
|
||||||
|
#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Triple <N, d(N), {Adj(N)}>
|
||||||
|
*/
|
||||||
|
struct isis_vertex {
|
||||||
|
enum vertextype type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
u_char id[ISIS_SYS_ID_LEN + 1];
|
||||||
|
struct prefix prefix;
|
||||||
|
} N;
|
||||||
|
|
||||||
|
u_int32_t d_N; /* d(N) Distance from this IS */
|
||||||
|
u_int16_t depth; /* The depth in the imaginary tree */
|
||||||
|
struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */
|
||||||
|
struct list *parents; /* list of parents for ECMP */
|
||||||
|
struct list *children; /* list of children used for tree dump */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Vertex Queue and associated functions */
|
||||||
|
|
||||||
|
struct isis_vertex_queue {
|
||||||
|
struct list *list;
|
||||||
|
struct hash *hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned isis_vertex_queue_hash_key(void *vp)
|
||||||
|
{
|
||||||
|
struct isis_vertex *vertex = vp;
|
||||||
|
|
||||||
|
if (VTYPE_IP(vertex->type))
|
||||||
|
return prefix_hash_key(&vertex->N.prefix);
|
||||||
|
|
||||||
|
return jhash(vertex->N.id, ISIS_SYS_ID_LEN + 1, 0x55aa5a5a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int isis_vertex_queue_hash_cmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct isis_vertex *va = a, *vb = b;
|
||||||
|
|
||||||
|
if (va->type != vb->type)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (VTYPE_IP(va->type))
|
||||||
|
return prefix_cmp(&va->N.prefix, &vb->N.prefix) == 0;
|
||||||
|
|
||||||
|
return memcmp(va->N.id, vb->N.id, ISIS_SYS_ID_LEN + 1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void isis_vertex_queue_init(struct isis_vertex_queue *queue, const char *name)
|
||||||
|
{
|
||||||
|
queue->list = list_new();
|
||||||
|
queue->hash = hash_create(isis_vertex_queue_hash_key,
|
||||||
|
isis_vertex_queue_hash_cmp,
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void isis_vertex_del(struct isis_vertex *vertex);
|
||||||
|
|
||||||
|
static void isis_vertex_queue_clear(struct isis_vertex_queue *queue)
|
||||||
|
{
|
||||||
|
hash_clean(queue->hash, NULL);
|
||||||
|
|
||||||
|
queue->list->del = (void (*)(void *))isis_vertex_del;
|
||||||
|
list_delete_all_node(queue->list);
|
||||||
|
queue->list->del = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void isis_vertex_queue_free(struct isis_vertex_queue *queue)
|
||||||
|
{
|
||||||
|
isis_vertex_queue_clear(queue);
|
||||||
|
|
||||||
|
hash_free(queue->hash);
|
||||||
|
queue->hash = NULL;
|
||||||
|
|
||||||
|
list_delete(queue->list);
|
||||||
|
queue->list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int isis_vertex_queue_count(struct isis_vertex_queue *queue)
|
||||||
|
{
|
||||||
|
return listcount(queue->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void isis_vertex_queue_add(struct isis_vertex_queue *queue,
|
||||||
|
struct isis_vertex *vertex)
|
||||||
|
{
|
||||||
|
listnode_add(queue->list, vertex);
|
||||||
|
|
||||||
|
struct isis_vertex *inserted;
|
||||||
|
|
||||||
|
inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
|
||||||
|
assert(inserted == vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct isis_vertex *isis_vertex_queue_pop(struct isis_vertex_queue *queue)
|
||||||
|
{
|
||||||
|
struct listnode *node;
|
||||||
|
|
||||||
|
node = listhead(queue->list);
|
||||||
|
if (!node)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct isis_vertex *rv = listgetdata(node);
|
||||||
|
|
||||||
|
list_delete_node(queue->list, node);
|
||||||
|
hash_release(queue->hash, rv);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void isis_vertex_queue_delete(struct isis_vertex_queue *queue,
|
||||||
|
struct isis_vertex *vertex)
|
||||||
|
{
|
||||||
|
listnode_delete(queue->list, vertex);
|
||||||
|
hash_release(queue->hash, vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ALL_QUEUE_ELEMENTS_RO(queue, node, data) \
|
||||||
|
ALL_LIST_ELEMENTS_RO((queue)->list, node, data)
|
||||||
|
|
||||||
|
|
||||||
|
/* End of vertex queue definitions */
|
||||||
|
|
||||||
|
struct isis_spftree {
|
||||||
|
struct isis_vertex_queue paths; /* the SPT */
|
||||||
|
struct isis_vertex_queue tents; /* TENT */
|
||||||
|
struct isis_area *area; /* back pointer to area */
|
||||||
|
unsigned int runcount; /* number of runs since uptime */
|
||||||
|
time_t last_run_timestamp; /* last run timestamp for scheduling */
|
||||||
|
time_t last_run_duration; /* last run duration in msec */
|
||||||
|
|
||||||
|
uint16_t mtid;
|
||||||
|
int family;
|
||||||
|
int level;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* supports the given af ?
|
* supports the given af ?
|
||||||
*/
|
*/
|
||||||
@ -174,12 +329,8 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size)
|
|||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype)
|
static void isis_vertex_id_init(struct isis_vertex *vertex, void *id, enum vertextype vtype)
|
||||||
{
|
{
|
||||||
struct isis_vertex *vertex;
|
|
||||||
|
|
||||||
vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
|
|
||||||
|
|
||||||
vertex->type = vtype;
|
vertex->type = vtype;
|
||||||
|
|
||||||
if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
|
if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) {
|
||||||
@ -190,6 +341,15 @@ static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype)
|
|||||||
} else {
|
} else {
|
||||||
zlog_err("WTF!");
|
zlog_err("WTF!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype)
|
||||||
|
{
|
||||||
|
struct isis_vertex *vertex;
|
||||||
|
|
||||||
|
vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex));
|
||||||
|
|
||||||
|
isis_vertex_id_init(vertex, id, vtype);
|
||||||
|
|
||||||
vertex->Adj_N = list_new();
|
vertex->Adj_N = list_new();
|
||||||
vertex->parents = list_new();
|
vertex->parents = list_new();
|
||||||
@ -237,8 +397,8 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tree->tents = list_new();
|
isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents");
|
||||||
tree->paths = list_new();
|
isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths");
|
||||||
tree->area = area;
|
tree->area = area;
|
||||||
tree->last_run_timestamp = 0;
|
tree->last_run_timestamp = 0;
|
||||||
tree->last_run_duration = 0;
|
tree->last_run_duration = 0;
|
||||||
@ -248,15 +408,8 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area)
|
|||||||
|
|
||||||
void isis_spftree_del(struct isis_spftree *spftree)
|
void isis_spftree_del(struct isis_spftree *spftree)
|
||||||
{
|
{
|
||||||
|
isis_vertex_queue_free(&spftree->tents);
|
||||||
spftree->tents->del = (void (*)(void *))isis_vertex_del;
|
isis_vertex_queue_free(&spftree->paths);
|
||||||
list_delete(spftree->tents);
|
|
||||||
spftree->tents = NULL;
|
|
||||||
|
|
||||||
spftree->paths->del = (void (*)(void *))isis_vertex_del;
|
|
||||||
list_delete(spftree->paths);
|
|
||||||
spftree->paths = NULL;
|
|
||||||
|
|
||||||
XFREE(MTYPE_ISIS_SPFTREE, spftree);
|
XFREE(MTYPE_ISIS_SPFTREE, spftree);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -266,12 +419,13 @@ static void isis_spftree_adj_del(struct isis_spftree *spftree,
|
|||||||
struct isis_adjacency *adj)
|
struct isis_adjacency *adj)
|
||||||
{
|
{
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
|
struct isis_vertex *v;
|
||||||
if (!adj)
|
if (!adj)
|
||||||
return;
|
return;
|
||||||
for (node = listhead(spftree->tents); node; node = listnextnode(node))
|
for (ALL_QUEUE_ELEMENTS_RO(&spftree->tents, node, v))
|
||||||
isis_vertex_adj_del(listgetdata(node), adj);
|
isis_vertex_adj_del(v, adj);
|
||||||
for (node = listhead(spftree->paths); node; node = listnextnode(node))
|
for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, v))
|
||||||
isis_vertex_adj_del(listgetdata(node), adj);
|
isis_vertex_adj_del(v, adj);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +538,7 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
|
|||||||
spftree->area->oldmetric
|
spftree->area->oldmetric
|
||||||
? VTYPE_NONPSEUDO_IS
|
? VTYPE_NONPSEUDO_IS
|
||||||
: VTYPE_NONPSEUDO_TE_IS);
|
: VTYPE_NONPSEUDO_TE_IS);
|
||||||
listnode_add(spftree->paths, vertex);
|
isis_vertex_queue_add(&spftree->paths, vertex);
|
||||||
|
|
||||||
#ifdef EXTREME_DEBUG
|
#ifdef EXTREME_DEBUG
|
||||||
zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
|
zlog_debug("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS",
|
||||||
@ -396,35 +550,13 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree,
|
|||||||
return vertex;
|
return vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct isis_vertex *isis_find_vertex(struct list *list, void *id,
|
static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue, void *id,
|
||||||
enum vertextype vtype)
|
enum vertextype vtype)
|
||||||
{
|
{
|
||||||
struct listnode *node;
|
struct isis_vertex querier;
|
||||||
struct isis_vertex *vertex;
|
|
||||||
struct prefix *p1, *p2;
|
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(list, node, vertex)) {
|
isis_vertex_id_init(&querier, id, vtype);
|
||||||
if (vertex->type != vtype)
|
return hash_lookup(queue->hash, &querier);
|
||||||
continue;
|
|
||||||
if (VTYPE_IS(vertex->type) || VTYPE_ES(vertex->type)) {
|
|
||||||
if (memcmp((u_char *)id, vertex->N.id,
|
|
||||||
ISIS_SYS_ID_LEN + 1)
|
|
||||||
== 0)
|
|
||||||
return vertex;
|
|
||||||
}
|
|
||||||
if (VTYPE_IP(vertex->type)) {
|
|
||||||
p1 = (struct prefix *)id;
|
|
||||||
p2 = (struct prefix *)&vertex->N.id;
|
|
||||||
if (p1->family == p2->family
|
|
||||||
&& p1->prefixlen == p2->prefixlen
|
|
||||||
&& !memcmp(&p1->u.prefix, &p2->u.prefix,
|
|
||||||
PSIZE(p1->prefixlen))) {
|
|
||||||
return vertex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -442,6 +574,30 @@ static bool tent_cmp(struct isis_vertex *current, struct isis_vertex *candidate)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void isis_vertex_queue_insert(struct isis_vertex_queue *queue,
|
||||||
|
struct isis_vertex *vertex)
|
||||||
|
{
|
||||||
|
struct listnode *node;
|
||||||
|
struct isis_vertex *v;
|
||||||
|
|
||||||
|
/* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
|
||||||
|
for (node = listhead(queue->list); node; node = listnextnode(node)) {
|
||||||
|
v = listgetdata(node);
|
||||||
|
if (tent_cmp(v, vertex)) {
|
||||||
|
listnode_add_before(queue->list, node, vertex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == NULL)
|
||||||
|
listnode_add(queue->list, vertex);
|
||||||
|
|
||||||
|
struct isis_vertex *inserted;
|
||||||
|
|
||||||
|
inserted = hash_get(queue->hash, vertex, hash_alloc_intern);
|
||||||
|
assert(inserted == vertex);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a vertex to TENT sorted by cost and by vertextype on tie break situation
|
* Add a vertex to TENT sorted by cost and by vertextype on tie break situation
|
||||||
*/
|
*/
|
||||||
@ -451,15 +607,15 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
|
|||||||
struct isis_adjacency *adj,
|
struct isis_adjacency *adj,
|
||||||
struct isis_vertex *parent)
|
struct isis_vertex *parent)
|
||||||
{
|
{
|
||||||
struct isis_vertex *vertex, *v;
|
struct isis_vertex *vertex;
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
struct isis_adjacency *parent_adj;
|
struct isis_adjacency *parent_adj;
|
||||||
#ifdef EXTREME_DEBUG
|
#ifdef EXTREME_DEBUG
|
||||||
char buff[PREFIX2STR_BUFFER];
|
char buff[PREFIX2STR_BUFFER];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(isis_find_vertex(spftree->paths, id, vtype) == NULL);
|
assert(isis_find_vertex(&spftree->paths, id, vtype) == NULL);
|
||||||
assert(isis_find_vertex(spftree->tents, id, vtype) == NULL);
|
assert(isis_find_vertex(&spftree->tents, id, vtype) == NULL);
|
||||||
vertex = isis_vertex_new(id, vtype);
|
vertex = isis_vertex_new(id, vtype);
|
||||||
vertex->d_N = cost;
|
vertex->d_N = cost;
|
||||||
vertex->depth = depth;
|
vertex->depth = depth;
|
||||||
@ -485,23 +641,7 @@ static struct isis_vertex *isis_spf_add2tent(struct isis_spftree *spftree,
|
|||||||
vertex->d_N, listcount(vertex->Adj_N));
|
vertex->d_N, listcount(vertex->Adj_N));
|
||||||
#endif /* EXTREME_DEBUG */
|
#endif /* EXTREME_DEBUG */
|
||||||
|
|
||||||
if (list_isempty(spftree->tents)) {
|
isis_vertex_queue_insert(&spftree->tents, vertex);
|
||||||
listnode_add(spftree->tents, vertex);
|
|
||||||
return vertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */
|
|
||||||
for (node = listhead(spftree->tents); node; node = listnextnode(node)) {
|
|
||||||
v = listgetdata(node);
|
|
||||||
if (tent_cmp(v, vertex)) {
|
|
||||||
listnode_add_before(spftree->tents, node, vertex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node == NULL)
|
|
||||||
listnode_add(spftree->tents, vertex);
|
|
||||||
|
|
||||||
return vertex;
|
return vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,7 +652,7 @@ static void isis_spf_add_local(struct isis_spftree *spftree,
|
|||||||
{
|
{
|
||||||
struct isis_vertex *vertex;
|
struct isis_vertex *vertex;
|
||||||
|
|
||||||
vertex = isis_find_vertex(spftree->tents, id, vtype);
|
vertex = isis_find_vertex(&spftree->tents, id, vtype);
|
||||||
|
|
||||||
if (vertex) {
|
if (vertex) {
|
||||||
/* C.2.5 c) */
|
/* C.2.5 c) */
|
||||||
@ -536,7 +676,7 @@ static void isis_spf_add_local(struct isis_spftree *spftree,
|
|||||||
/* f) */
|
/* f) */
|
||||||
struct listnode *pnode, *pnextnode;
|
struct listnode *pnode, *pnextnode;
|
||||||
struct isis_vertex *pvertex;
|
struct isis_vertex *pvertex;
|
||||||
listnode_delete(spftree->tents, vertex);
|
isis_vertex_queue_delete(&spftree->tents, vertex);
|
||||||
assert(listcount(vertex->children) == 0);
|
assert(listcount(vertex->children) == 0);
|
||||||
for (ALL_LIST_ELEMENTS(vertex->parents, pnode,
|
for (ALL_LIST_ELEMENTS(vertex->parents, pnode,
|
||||||
pnextnode, pvertex))
|
pnextnode, pvertex))
|
||||||
@ -579,7 +719,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* c) */
|
/* c) */
|
||||||
vertex = isis_find_vertex(spftree->paths, id, vtype);
|
vertex = isis_find_vertex(&spftree->paths, id, vtype);
|
||||||
if (vertex) {
|
if (vertex) {
|
||||||
#ifdef EXTREME_DEBUG
|
#ifdef EXTREME_DEBUG
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
@ -591,7 +731,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex = isis_find_vertex(spftree->tents, id, vtype);
|
vertex = isis_find_vertex(&spftree->tents, id, vtype);
|
||||||
/* d) */
|
/* d) */
|
||||||
if (vertex) {
|
if (vertex) {
|
||||||
/* 1) */
|
/* 1) */
|
||||||
@ -626,7 +766,7 @@ static void process_N(struct isis_spftree *spftree, enum vertextype vtype,
|
|||||||
} else {
|
} else {
|
||||||
struct listnode *pnode, *pnextnode;
|
struct listnode *pnode, *pnextnode;
|
||||||
struct isis_vertex *pvertex;
|
struct isis_vertex *pvertex;
|
||||||
listnode_delete(spftree->tents, vertex);
|
isis_vertex_queue_delete(&spftree->tents, vertex);
|
||||||
assert(listcount(vertex->children) == 0);
|
assert(listcount(vertex->children) == 0);
|
||||||
for (ALL_LIST_ELEMENTS(vertex->parents, pnode,
|
for (ALL_LIST_ELEMENTS(vertex->parents, pnode,
|
||||||
pnextnode, pvertex))
|
pnextnode, pvertex))
|
||||||
@ -1056,9 +1196,9 @@ static void add_to_paths(struct isis_spftree *spftree,
|
|||||||
{
|
{
|
||||||
char buff[PREFIX2STR_BUFFER];
|
char buff[PREFIX2STR_BUFFER];
|
||||||
|
|
||||||
if (isis_find_vertex(spftree->paths, vertex->N.id, vertex->type))
|
if (isis_find_vertex(&spftree->paths, vertex->N.id, vertex->type))
|
||||||
return;
|
return;
|
||||||
listnode_add(spftree->paths, vertex);
|
isis_vertex_queue_add(&spftree->paths, vertex);
|
||||||
|
|
||||||
#ifdef EXTREME_DEBUG
|
#ifdef EXTREME_DEBUG
|
||||||
zlog_debug("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
|
zlog_debug("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS",
|
||||||
@ -1087,11 +1227,8 @@ static void add_to_paths(struct isis_spftree *spftree,
|
|||||||
static void init_spt(struct isis_spftree *spftree, int mtid, int level,
|
static void init_spt(struct isis_spftree *spftree, int mtid, int level,
|
||||||
int family)
|
int family)
|
||||||
{
|
{
|
||||||
spftree->tents->del = spftree->paths->del =
|
isis_vertex_queue_clear(&spftree->tents);
|
||||||
(void (*)(void *))isis_vertex_del;
|
isis_vertex_queue_clear(&spftree->paths);
|
||||||
list_delete_all_node(spftree->tents);
|
|
||||||
list_delete_all_node(spftree->paths);
|
|
||||||
spftree->tents->del = spftree->paths->del = NULL;
|
|
||||||
|
|
||||||
spftree->mtid = mtid;
|
spftree->mtid = mtid;
|
||||||
spftree->level = level;
|
spftree->level = level;
|
||||||
@ -1103,7 +1240,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
|
|||||||
u_char *sysid)
|
u_char *sysid)
|
||||||
{
|
{
|
||||||
int retval = ISIS_OK;
|
int retval = ISIS_OK;
|
||||||
struct listnode *node;
|
|
||||||
struct isis_vertex *vertex;
|
struct isis_vertex *vertex;
|
||||||
struct isis_vertex *root_vertex;
|
struct isis_vertex *root_vertex;
|
||||||
struct isis_spftree *spftree = NULL;
|
struct isis_spftree *spftree = NULL;
|
||||||
@ -1158,15 +1294,14 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
|
|||||||
/*
|
/*
|
||||||
* C.2.7 Step 2
|
* C.2.7 Step 2
|
||||||
*/
|
*/
|
||||||
if (listcount(spftree->tents) == 0) {
|
if (isis_vertex_queue_count(&spftree->tents) == 0) {
|
||||||
zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s",
|
zlog_warn("ISIS-Spf: TENT is empty SPF-root:%s",
|
||||||
print_sys_hostname(sysid));
|
print_sys_hostname(sysid));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (listcount(spftree->tents) > 0) {
|
while (isis_vertex_queue_count(&spftree->tents)) {
|
||||||
node = listhead(spftree->tents);
|
vertex = isis_vertex_queue_pop(&spftree->tents);
|
||||||
vertex = listgetdata(node);
|
|
||||||
|
|
||||||
#ifdef EXTREME_DEBUG
|
#ifdef EXTREME_DEBUG
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
@ -1175,8 +1310,6 @@ static int isis_run_spf(struct isis_area *area, int level, int family,
|
|||||||
vtype2string(vertex->type), vertex->depth, vertex->d_N);
|
vtype2string(vertex->type), vertex->depth, vertex->d_N);
|
||||||
#endif /* EXTREME_DEBUG */
|
#endif /* EXTREME_DEBUG */
|
||||||
|
|
||||||
/* Remove from tent list and add to paths list */
|
|
||||||
list_delete_node(spftree->tents, node);
|
|
||||||
add_to_paths(spftree, vertex);
|
add_to_paths(spftree, vertex);
|
||||||
if (VTYPE_IS(vertex->type)) {
|
if (VTYPE_IS(vertex->type)) {
|
||||||
memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
|
memcpy(lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1);
|
||||||
@ -1303,7 +1436,7 @@ int isis_spf_schedule(struct isis_area *area, int level)
|
|||||||
return ISIS_OK;
|
return ISIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void isis_print_paths(struct vty *vty, struct list *paths,
|
static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue,
|
||||||
u_char *root_sysid)
|
u_char *root_sysid)
|
||||||
{
|
{
|
||||||
struct listnode *node;
|
struct listnode *node;
|
||||||
@ -1315,7 +1448,7 @@ static void isis_print_paths(struct vty *vty, struct list *paths,
|
|||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"Vertex Type Metric Next-Hop Interface Parent\n");
|
"Vertex Type Metric Next-Hop Interface Parent\n");
|
||||||
|
|
||||||
for (ALL_LIST_ELEMENTS_RO(paths, node, vertex)) {
|
for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) {
|
||||||
if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
|
if (memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) {
|
||||||
vty_out(vty, "%-20s %-12s %-6s",
|
vty_out(vty, "%-20s %-12s %-6s",
|
||||||
print_sys_hostname(root_sysid), "", "");
|
print_sys_hostname(root_sysid), "", "");
|
||||||
@ -1399,22 +1532,22 @@ DEFUN (show_isis_topology,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (area->ip_circuits > 0 && area->spftree[level - 1]
|
if (area->ip_circuits > 0 && area->spftree[level - 1]
|
||||||
&& area->spftree[level - 1]->paths->count > 0) {
|
&& isis_vertex_queue_count(&area->spftree[level - 1]->paths) > 0) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"IS-IS paths to level-%d routers that speak IP\n",
|
"IS-IS paths to level-%d routers that speak IP\n",
|
||||||
level);
|
level);
|
||||||
isis_print_paths(
|
isis_print_paths(
|
||||||
vty, area->spftree[level - 1]->paths,
|
vty, &area->spftree[level - 1]->paths,
|
||||||
isis->sysid);
|
isis->sysid);
|
||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
}
|
}
|
||||||
if (area->ipv6_circuits > 0 && area->spftree6[level - 1]
|
if (area->ipv6_circuits > 0 && area->spftree6[level - 1]
|
||||||
&& area->spftree6[level - 1]->paths->count > 0) {
|
&& isis_vertex_queue_count(&area->spftree6[level - 1]->paths) > 0) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"IS-IS paths to level-%d routers that speak IPv6\n",
|
"IS-IS paths to level-%d routers that speak IPv6\n",
|
||||||
level);
|
level);
|
||||||
isis_print_paths(
|
isis_print_paths(
|
||||||
vty, area->spftree6[level - 1]->paths,
|
vty, &area->spftree6[level - 1]->paths,
|
||||||
isis->sysid);
|
isis->sysid);
|
||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
}
|
}
|
||||||
@ -1430,3 +1563,16 @@ void isis_spf_cmds_init()
|
|||||||
{
|
{
|
||||||
install_element(VIEW_NODE, &show_isis_topology_cmd);
|
install_element(VIEW_NODE, &show_isis_topology_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void isis_spf_print(struct isis_spftree *spftree, struct vty *vty)
|
||||||
|
{
|
||||||
|
vty_out(vty, " last run elapsed : ");
|
||||||
|
vty_out_timestr(vty, spftree->last_run_timestamp);
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
|
||||||
|
vty_out(vty, " last run duration : %u usec\n",
|
||||||
|
(u_int32_t)spftree->last_run_duration);
|
||||||
|
|
||||||
|
vty_out(vty, " run count : %u\n",
|
||||||
|
spftree->runcount);
|
||||||
|
}
|
||||||
|
@ -24,53 +24,7 @@
|
|||||||
#ifndef _ZEBRA_ISIS_SPF_H
|
#ifndef _ZEBRA_ISIS_SPF_H
|
||||||
#define _ZEBRA_ISIS_SPF_H
|
#define _ZEBRA_ISIS_SPF_H
|
||||||
|
|
||||||
enum vertextype {
|
struct isis_spftree;
|
||||||
VTYPE_PSEUDO_IS = 1,
|
|
||||||
VTYPE_PSEUDO_TE_IS,
|
|
||||||
VTYPE_NONPSEUDO_IS,
|
|
||||||
VTYPE_NONPSEUDO_TE_IS,
|
|
||||||
VTYPE_ES,
|
|
||||||
VTYPE_IPREACH_INTERNAL,
|
|
||||||
VTYPE_IPREACH_EXTERNAL,
|
|
||||||
VTYPE_IPREACH_TE,
|
|
||||||
VTYPE_IP6REACH_INTERNAL,
|
|
||||||
VTYPE_IP6REACH_EXTERNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VTYPE_IS(t) ((t) >= VTYPE_PSEUDO_IS && (t) <= VTYPE_NONPSEUDO_TE_IS)
|
|
||||||
#define VTYPE_ES(t) ((t) == VTYPE_ES)
|
|
||||||
#define VTYPE_IP(t) ((t) >= VTYPE_IPREACH_INTERNAL && (t) <= VTYPE_IP6REACH_EXTERNAL)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Triple <N, d(N), {Adj(N)}>
|
|
||||||
*/
|
|
||||||
struct isis_vertex {
|
|
||||||
enum vertextype type;
|
|
||||||
|
|
||||||
union {
|
|
||||||
u_char id[ISIS_SYS_ID_LEN + 1];
|
|
||||||
struct prefix prefix;
|
|
||||||
} N;
|
|
||||||
|
|
||||||
u_int32_t d_N; /* d(N) Distance from this IS */
|
|
||||||
u_int16_t depth; /* The depth in the imaginary tree */
|
|
||||||
struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */
|
|
||||||
struct list *parents; /* list of parents for ECMP */
|
|
||||||
struct list *children; /* list of children used for tree dump */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct isis_spftree {
|
|
||||||
struct list *paths; /* the SPT */
|
|
||||||
struct list *tents; /* TENT */
|
|
||||||
struct isis_area *area; /* back pointer to area */
|
|
||||||
unsigned int runcount; /* number of runs since uptime */
|
|
||||||
time_t last_run_timestamp; /* last run timestamp for scheduling */
|
|
||||||
time_t last_run_duration; /* last run duration in msec */
|
|
||||||
|
|
||||||
uint16_t mtid;
|
|
||||||
int family;
|
|
||||||
int level;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct isis_spftree *isis_spftree_new(struct isis_area *area);
|
struct isis_spftree *isis_spftree_new(struct isis_area *area);
|
||||||
void isis_spftree_del(struct isis_spftree *spftree);
|
void isis_spftree_del(struct isis_spftree *spftree);
|
||||||
@ -79,4 +33,5 @@ void spftree_area_del(struct isis_area *area);
|
|||||||
void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj);
|
void spftree_area_adj_del(struct isis_area *area, struct isis_adjacency *adj);
|
||||||
int isis_spf_schedule(struct isis_area *area, int level);
|
int isis_spf_schedule(struct isis_area *area, int level);
|
||||||
void isis_spf_cmds_init(void);
|
void isis_spf_cmds_init(void);
|
||||||
|
void isis_spf_print(struct isis_spftree *spftree, struct vty *vty);
|
||||||
#endif /* _ZEBRA_ISIS_SPF_H */
|
#endif /* _ZEBRA_ISIS_SPF_H */
|
||||||
|
@ -1231,27 +1231,6 @@ DEFUN (show_hostname,
|
|||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vty_out_timestr(struct vty *vty, time_t uptime)
|
|
||||||
{
|
|
||||||
struct tm *tm;
|
|
||||||
time_t difftime = time(NULL);
|
|
||||||
difftime -= uptime;
|
|
||||||
tm = gmtime(&difftime);
|
|
||||||
|
|
||||||
#define ONE_DAY_SECOND 60*60*24
|
|
||||||
#define ONE_WEEK_SECOND 60*60*24*7
|
|
||||||
if (difftime < ONE_DAY_SECOND)
|
|
||||||
vty_out(vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
|
|
||||||
tm->tm_sec);
|
|
||||||
else if (difftime < ONE_WEEK_SECOND)
|
|
||||||
vty_out(vty, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
|
|
||||||
tm->tm_min);
|
|
||||||
else
|
|
||||||
vty_out(vty, "%02dw%dd%02dh", tm->tm_yday / 7,
|
|
||||||
tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
|
|
||||||
vty_out(vty, " ago");
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFUN (show_isis_spf_ietf,
|
DEFUN (show_isis_spf_ietf,
|
||||||
show_isis_spf_ietf_cmd,
|
show_isis_spf_ietf_cmd,
|
||||||
"show isis spf-delay-ietf",
|
"show isis spf-delay-ietf",
|
||||||
@ -1308,7 +1287,6 @@ DEFUN (show_isis_summary,
|
|||||||
{
|
{
|
||||||
struct listnode *node, *node2;
|
struct listnode *node, *node2;
|
||||||
struct isis_area *area;
|
struct isis_area *area;
|
||||||
struct isis_spftree *spftree;
|
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
if (isis == NULL) {
|
if (isis == NULL) {
|
||||||
@ -1349,7 +1327,6 @@ DEFUN (show_isis_summary,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
vty_out(vty, " Level-%d:\n", level);
|
vty_out(vty, " Level-%d:\n", level);
|
||||||
spftree = area->spftree[level - 1];
|
|
||||||
if (area->spf_timer[level - 1])
|
if (area->spf_timer[level - 1])
|
||||||
vty_out(vty, " SPF: (pending)\n");
|
vty_out(vty, " SPF: (pending)\n");
|
||||||
else
|
else
|
||||||
@ -1363,28 +1340,10 @@ DEFUN (show_isis_summary,
|
|||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
|
|
||||||
vty_out(vty, " IPv4 route computation:\n");
|
vty_out(vty, " IPv4 route computation:\n");
|
||||||
vty_out(vty, " last run elapsed : ");
|
isis_spf_print(area->spftree[level - 1], vty);
|
||||||
vty_out_timestr(vty, spftree->last_run_timestamp);
|
|
||||||
vty_out(vty, "\n");
|
|
||||||
|
|
||||||
vty_out(vty, " last run duration : %u usec\n",
|
|
||||||
(u_int32_t)spftree->last_run_duration);
|
|
||||||
|
|
||||||
vty_out(vty, " run count : %d\n",
|
|
||||||
spftree->runcount);
|
|
||||||
|
|
||||||
spftree = area->spftree6[level - 1];
|
|
||||||
vty_out(vty, " IPv6 route computation:\n");
|
vty_out(vty, " IPv6 route computation:\n");
|
||||||
|
isis_spf_print(area->spftree6[level - 1], vty);
|
||||||
vty_out(vty, " last run elapsed : ");
|
|
||||||
vty_out_timestr(vty, spftree->last_run_timestamp);
|
|
||||||
vty_out(vty, "\n");
|
|
||||||
|
|
||||||
vty_out(vty, " last run duration : %llu msec\n",
|
|
||||||
(unsigned long long)spftree->last_run_duration);
|
|
||||||
|
|
||||||
vty_out(vty, " run count : %d\n",
|
|
||||||
spftree->runcount);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vty_out(vty, "\n");
|
vty_out(vty, "\n");
|
||||||
|
39
lib/hash.c
39
lib/hash.c
@ -358,33 +358,26 @@ DEFUN(show_hash_stats,
|
|||||||
|
|
||||||
/* Summary statistics calculated are:
|
/* Summary statistics calculated are:
|
||||||
*
|
*
|
||||||
* - Load factor: This is the number of elements in the table divided by
|
* - Load factor: This is the number of elements in the table divided
|
||||||
* the
|
* by the number of buckets. Since this hash table implementation
|
||||||
* number of buckets. Since this hash table implementation uses
|
* uses chaining, this value can be greater than 1.
|
||||||
* chaining,
|
* This number provides information on how 'full' the table is, but
|
||||||
* this value can be greater than 1. This number provides information
|
* does not provide information on how evenly distributed the
|
||||||
* on
|
* elements are.
|
||||||
* how 'full' the table is, but does not provide information on how
|
* Notably, a load factor >= 1 does not imply that every bucket has
|
||||||
* evenly
|
* an element; with a pathological hash function, all elements could
|
||||||
* distributed the elements are. Notably, a load factor >= 1 does not
|
* be in a single bucket.
|
||||||
* imply
|
|
||||||
* that every bucket has an element; with a pathological hash
|
|
||||||
* function, all
|
|
||||||
* elements could be in a single bucket.
|
|
||||||
*
|
*
|
||||||
* - Full load factor: this is the number of elements in the table
|
* - Full load factor: this is the number of elements in the table
|
||||||
* divided by
|
* divided by the number of buckets that have some elements in them.
|
||||||
* the number of buckets that have some elements in them.
|
|
||||||
*
|
*
|
||||||
* - Std. Dev.: This is the standard deviation calculated from the
|
* - Std. Dev.: This is the standard deviation calculated from the
|
||||||
* relevant
|
* relevant load factor. If the load factor is the mean of number of
|
||||||
* load factor. If the load factor is the mean of number of elements
|
* elements per bucket, the standard deviation measures how much any
|
||||||
* per
|
* particular bucket is likely to deviate from the mean.
|
||||||
* bucket, the standard deviation measures how much any particular
|
* As a rule of thumb this number should be less than 2, and ideally
|
||||||
* bucket
|
* <= 1 for optimal performance. A number larger than 3 generally
|
||||||
* is likely to deviate from the mean. As a rule of thumb this number
|
* indicates a poor hash function.
|
||||||
* should be less than 2, and ideally <= 1 for optimal performance. A
|
|
||||||
* number larger than 3 generally indicates a poor hash function.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
double lf; // load factor
|
double lf; // load factor
|
||||||
|
13
lib/prefix.c
13
lib/prefix.c
@ -26,6 +26,7 @@
|
|||||||
#include "sockunion.h"
|
#include "sockunion.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "jhash.h"
|
||||||
|
|
||||||
DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
|
DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
|
||||||
|
|
||||||
@ -1335,3 +1336,15 @@ char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size)
|
|||||||
(uint8_t)mac->octet[4], (uint8_t)mac->octet[5]);
|
(uint8_t)mac->octet[4], (uint8_t)mac->octet[5]);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned prefix_hash_key(void *pp)
|
||||||
|
{
|
||||||
|
struct prefix copy;
|
||||||
|
|
||||||
|
/* make sure *all* unused bits are zero, particularly including
|
||||||
|
* alignment /
|
||||||
|
* padding and unused prefix bytes. */
|
||||||
|
memset(©, 0, sizeof(copy));
|
||||||
|
prefix_copy(©, (struct prefix *)pp);
|
||||||
|
return jhash(©, sizeof(copy), 0x55aa5a5a);
|
||||||
|
}
|
||||||
|
@ -323,6 +323,8 @@ extern const char *inet6_ntoa(struct in6_addr);
|
|||||||
extern int prefix_str2mac(const char *str, struct ethaddr *mac);
|
extern int prefix_str2mac(const char *str, struct ethaddr *mac);
|
||||||
extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size);
|
extern char *prefix_mac2str(const struct ethaddr *mac, char *buf, int size);
|
||||||
|
|
||||||
|
extern unsigned prefix_hash_key(void *pp);
|
||||||
|
|
||||||
static inline int ipv6_martian(struct in6_addr *addr)
|
static inline int ipv6_martian(struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct in6_addr localhost_addr;
|
struct in6_addr localhost_addr;
|
||||||
|
15
lib/table.c
15
lib/table.c
@ -27,7 +27,6 @@
|
|||||||
#include "table.h"
|
#include "table.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "sockunion.h"
|
#include "sockunion.h"
|
||||||
#include "jhash.h"
|
|
||||||
|
|
||||||
DEFINE_MTYPE(LIB, ROUTE_TABLE, "Route table")
|
DEFINE_MTYPE(LIB, ROUTE_TABLE, "Route table")
|
||||||
DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node")
|
DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node")
|
||||||
@ -35,18 +34,6 @@ DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node")
|
|||||||
static void route_node_delete(struct route_node *);
|
static void route_node_delete(struct route_node *);
|
||||||
static void route_table_free(struct route_table *);
|
static void route_table_free(struct route_table *);
|
||||||
|
|
||||||
static unsigned route_table_hash_key(void *pp)
|
|
||||||
{
|
|
||||||
struct prefix copy;
|
|
||||||
|
|
||||||
/* make sure *all* unused bits are zero, particularly including
|
|
||||||
* alignment /
|
|
||||||
* padding and unused prefix bytes. */
|
|
||||||
memset(©, 0, sizeof(copy));
|
|
||||||
prefix_copy(©, (struct prefix *)pp);
|
|
||||||
return jhash(©, sizeof(copy), 0x55aa5a5a);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int route_table_hash_cmp(const void *a, const void *b)
|
static int route_table_hash_cmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
const struct prefix *pa = a, *pb = b;
|
const struct prefix *pa = a, *pb = b;
|
||||||
@ -63,7 +50,7 @@ route_table_init_with_delegate(route_table_delegate_t *delegate)
|
|||||||
|
|
||||||
rt = XCALLOC(MTYPE_ROUTE_TABLE, sizeof(struct route_table));
|
rt = XCALLOC(MTYPE_ROUTE_TABLE, sizeof(struct route_table));
|
||||||
rt->delegate = delegate;
|
rt->delegate = delegate;
|
||||||
rt->hash = hash_create(route_table_hash_key, route_table_hash_cmp,
|
rt->hash = hash_create(prefix_hash_key, route_table_hash_cmp,
|
||||||
"route table hash");
|
"route table hash");
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user