forked from Mirror/frr
commit
c6200b5467
|
@ -267,7 +267,7 @@ bgp_sync_init (struct peer *peer)
|
||||||
BGP_ADV_FIFO_INIT (&sync->withdraw);
|
BGP_ADV_FIFO_INIT (&sync->withdraw);
|
||||||
BGP_ADV_FIFO_INIT (&sync->withdraw_low);
|
BGP_ADV_FIFO_INIT (&sync->withdraw_low);
|
||||||
peer->sync[afi][safi] = sync;
|
peer->sync[afi][safi] = sync;
|
||||||
peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp);
|
peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2134,7 +2134,7 @@ aspath_cmp (const void *arg1, const void *arg2)
|
||||||
void
|
void
|
||||||
aspath_init (void)
|
aspath_init (void)
|
||||||
{
|
{
|
||||||
ashash = hash_create_size (32768, aspath_key_make, aspath_cmp);
|
ashash = hash_create_size (32768, aspath_key_make, aspath_cmp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -215,7 +215,7 @@ cluster_unintern (struct cluster_list *cluster)
|
||||||
static void
|
static void
|
||||||
cluster_init (void)
|
cluster_init (void)
|
||||||
{
|
{
|
||||||
cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
|
cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -403,9 +403,9 @@ encap_hash_cmp (const void *p1, const void *p2)
|
||||||
static void
|
static void
|
||||||
encap_init (void)
|
encap_init (void)
|
||||||
{
|
{
|
||||||
encap_hash = hash_create (encap_hash_key_make, encap_hash_cmp);
|
encap_hash = hash_create (encap_hash_key_make, encap_hash_cmp, NULL);
|
||||||
#if ENABLE_BGP_VNC
|
#if ENABLE_BGP_VNC
|
||||||
vnc_hash = hash_create (encap_hash_key_make, encap_hash_cmp);
|
vnc_hash = hash_create (encap_hash_key_make, encap_hash_cmp, NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +517,7 @@ transit_hash_cmp (const void *p1, const void *p2)
|
||||||
static void
|
static void
|
||||||
transit_init (void)
|
transit_init (void)
|
||||||
{
|
{
|
||||||
transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
|
transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -765,7 +765,7 @@ attrhash_cmp (const void *p1, const void *p2)
|
||||||
static void
|
static void
|
||||||
attrhash_init (void)
|
attrhash_init (void)
|
||||||
{
|
{
|
||||||
attrhash = hash_create (attrhash_key_make, attrhash_cmp);
|
attrhash = hash_create (attrhash_key_make, attrhash_cmp, "BGP Attributes");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -686,7 +686,7 @@ void
|
||||||
community_init (void)
|
community_init (void)
|
||||||
{
|
{
|
||||||
comhash = hash_create ((unsigned int (*) (void *))community_hash_make,
|
comhash = hash_create ((unsigned int (*) (void *))community_hash_make,
|
||||||
(int (*) (const void *, const void *))community_cmp);
|
(int (*) (const void *, const void *))community_cmp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -284,7 +284,7 @@ ecommunity_cmp (const void *arg1, const void *arg2)
|
||||||
void
|
void
|
||||||
ecommunity_init (void)
|
ecommunity_init (void)
|
||||||
{
|
{
|
||||||
ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
|
ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -286,7 +286,7 @@ lcommunity_hash (void)
|
||||||
void
|
void
|
||||||
lcommunity_init (void)
|
lcommunity_init (void)
|
||||||
{
|
{
|
||||||
lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp);
|
lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -140,7 +140,7 @@ void
|
||||||
bgp_address_init (struct bgp *bgp)
|
bgp_address_init (struct bgp *bgp)
|
||||||
{
|
{
|
||||||
bgp->address_hash = hash_create (bgp_address_hash_key_make,
|
bgp->address_hash = hash_create (bgp_address_hash_key_make,
|
||||||
bgp_address_hash_cmp);
|
bgp_address_hash_cmp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -87,7 +87,7 @@ sync_init (struct update_subgroup *subgrp)
|
||||||
BGP_ADV_FIFO_INIT (&subgrp->sync->update);
|
BGP_ADV_FIFO_INIT (&subgrp->sync->update);
|
||||||
BGP_ADV_FIFO_INIT (&subgrp->sync->withdraw);
|
BGP_ADV_FIFO_INIT (&subgrp->sync->withdraw);
|
||||||
BGP_ADV_FIFO_INIT (&subgrp->sync->withdraw_low);
|
BGP_ADV_FIFO_INIT (&subgrp->sync->withdraw_low);
|
||||||
subgrp->hash = hash_create (baa_hash_key, baa_hash_cmp);
|
subgrp->hash = hash_create (baa_hash_key, baa_hash_cmp, NULL);
|
||||||
|
|
||||||
/* We use a larger buffer for subgrp->work in the event that:
|
/* We use a larger buffer for subgrp->work in the event that:
|
||||||
* - We RX a BGP_UPDATE where the attributes alone are just
|
* - We RX a BGP_UPDATE where the attributes alone are just
|
||||||
|
@ -1559,7 +1559,7 @@ update_bgp_group_init (struct bgp *bgp)
|
||||||
|
|
||||||
AF_FOREACH (afid)
|
AF_FOREACH (afid)
|
||||||
bgp->update_groups[afid] = hash_create (updgrp_hash_key_make,
|
bgp->update_groups[afid] = hash_create (updgrp_hash_key_make,
|
||||||
updgrp_hash_cmp);
|
updgrp_hash_cmp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -2910,7 +2910,7 @@ bgp_create (as_t *as, const char *name, enum bgp_instance_type inst_type)
|
||||||
bgp->peer_self->host = XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
|
bgp->peer_self->host = XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
|
||||||
bgp->peer = list_new ();
|
bgp->peer = list_new ();
|
||||||
bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp;
|
bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp;
|
||||||
bgp->peerhash = hash_create (peer_hash_key_make, peer_hash_cmp);
|
bgp->peerhash = hash_create (peer_hash_key_make, peer_hash_cmp, NULL);
|
||||||
|
|
||||||
bgp->group = list_new ();
|
bgp->group = list_new ();
|
||||||
bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp;
|
bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp;
|
||||||
|
|
|
@ -1589,6 +1589,11 @@ AM_CONDITIONAL([SNMP], [test "x${SNMP_METHOD}" != "x"])
|
||||||
AC_SUBST(SNMP_LIBS)
|
AC_SUBST(SNMP_LIBS)
|
||||||
AC_SUBST(SNMP_CFLAGS)
|
AC_SUBST(SNMP_CFLAGS)
|
||||||
|
|
||||||
|
dnl ---------------
|
||||||
|
dnl math
|
||||||
|
dnl ---------------
|
||||||
|
AC_SEARCH_LIBS([sqrt], [m])
|
||||||
|
|
||||||
dnl ---------------
|
dnl ---------------
|
||||||
dnl dlopen & dlinfo
|
dnl dlopen & dlinfo
|
||||||
dnl ---------------
|
dnl ---------------
|
||||||
|
|
|
@ -233,7 +233,7 @@ install_node (struct cmd_node *node,
|
||||||
// add start node
|
// add start node
|
||||||
struct cmd_token *token = cmd_token_new (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
|
struct cmd_token *token = cmd_token_new (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
|
||||||
graph_new_node (node->cmdgraph, token, (void (*)(void *)) &cmd_token_del);
|
graph_new_node (node->cmdgraph, token, (void (*)(void *)) &cmd_token_del);
|
||||||
node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp);
|
node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2520,6 +2520,7 @@ cmd_init (int terminal)
|
||||||
|
|
||||||
thread_cmd_init ();
|
thread_cmd_init ();
|
||||||
workqueue_cmd_init ();
|
workqueue_cmd_init ();
|
||||||
|
hash_cmd_init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
install_element (CONFIG_NODE, &hostname_cmd);
|
install_element (CONFIG_NODE, &hostname_cmd);
|
||||||
|
|
|
@ -522,7 +522,8 @@ void
|
||||||
distribute_list_init (int node)
|
distribute_list_init (int node)
|
||||||
{
|
{
|
||||||
disthash = hash_create (distribute_hash_make,
|
disthash = hash_create (distribute_hash_make,
|
||||||
(int (*) (const void *, const void *)) distribute_cmp);
|
(int (*) (const void *, const void *))
|
||||||
|
distribute_cmp, NULL);
|
||||||
|
|
||||||
/* vtysh command-extraction doesn't grok install_element(node, ) */
|
/* vtysh command-extraction doesn't grok install_element(node, ) */
|
||||||
if (node == RIP_NODE) {
|
if (node == RIP_NODE) {
|
||||||
|
|
|
@ -55,7 +55,7 @@ void frr_pthread_init()
|
||||||
pthread_mutex_lock(&pthread_table_mtx);
|
pthread_mutex_lock(&pthread_table_mtx);
|
||||||
{
|
{
|
||||||
pthread_table =
|
pthread_table =
|
||||||
hash_create(pthread_table_hash_key, pthread_table_hash_cmp);
|
hash_create(pthread_table_hash_key, pthread_table_hash_cmp, NULL);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&pthread_table_mtx);
|
pthread_mutex_unlock(&pthread_table_mtx);
|
||||||
}
|
}
|
||||||
|
|
234
lib/hash.c
234
lib/hash.c
|
@ -19,23 +19,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <zebra.h>
|
#include <zebra.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "linklist.h"
|
||||||
|
#include "termtable.h"
|
||||||
|
#include "vty.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "libfrr.h"
|
||||||
|
|
||||||
DEFINE_MTYPE( LIB, HASH, "Hash")
|
DEFINE_MTYPE( LIB, HASH, "Hash")
|
||||||
DEFINE_MTYPE( LIB, HASH_BACKET, "Hash Bucket")
|
DEFINE_MTYPE( LIB, HASH_BACKET, "Hash Bucket")
|
||||||
DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index")
|
DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index")
|
||||||
|
|
||||||
|
pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
static struct list *_hashes;
|
||||||
|
|
||||||
/* Allocate a new hash. */
|
/* Allocate a new hash. */
|
||||||
struct hash *
|
struct hash *
|
||||||
hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
|
hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
|
||||||
int (*hash_cmp) (const void *, const void *))
|
int (*hash_cmp) (const void *, const void *),
|
||||||
|
const char *name)
|
||||||
{
|
{
|
||||||
struct hash *hash;
|
struct hash *hash;
|
||||||
|
|
||||||
assert ((size & (size-1)) == 0);
|
assert ((size & (size-1)) == 0);
|
||||||
hash = XMALLOC (MTYPE_HASH, sizeof (struct hash));
|
hash = XCALLOC (MTYPE_HASH, sizeof (struct hash));
|
||||||
hash->index = XCALLOC (MTYPE_HASH_INDEX,
|
hash->index = XCALLOC (MTYPE_HASH_INDEX,
|
||||||
sizeof (struct hash_backet *) * size);
|
sizeof (struct hash_backet *) * size);
|
||||||
hash->size = size;
|
hash->size = size;
|
||||||
|
@ -43,6 +53,17 @@ hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
|
||||||
hash->hash_key = hash_key;
|
hash->hash_key = hash_key;
|
||||||
hash->hash_cmp = hash_cmp;
|
hash->hash_cmp = hash_cmp;
|
||||||
hash->count = 0;
|
hash->count = 0;
|
||||||
|
hash->name = name ? XSTRDUP(MTYPE_HASH, name) : NULL;
|
||||||
|
hash->stats.empty = hash->size;
|
||||||
|
|
||||||
|
pthread_mutex_lock (&_hashes_mtx);
|
||||||
|
{
|
||||||
|
if (!_hashes)
|
||||||
|
_hashes = list_new();
|
||||||
|
|
||||||
|
listnode_add (_hashes, hash);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock (&_hashes_mtx);
|
||||||
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
@ -50,9 +71,10 @@ hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
|
||||||
/* Allocate a new hash with default hash size. */
|
/* Allocate a new hash with default hash size. */
|
||||||
struct hash *
|
struct hash *
|
||||||
hash_create (unsigned int (*hash_key) (void *),
|
hash_create (unsigned int (*hash_key) (void *),
|
||||||
int (*hash_cmp) (const void *, const void *))
|
int (*hash_cmp) (const void *, const void *),
|
||||||
|
const char *name)
|
||||||
{
|
{
|
||||||
return hash_create_size (HASH_INITIAL_SIZE, hash_key, hash_cmp);
|
return hash_create_size (HASH_INITIAL_SIZE, hash_key, hash_cmp, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Utility function for hash_get(). When this function is specified
|
/* Utility function for hash_get(). When this function is specified
|
||||||
|
@ -64,6 +86,15 @@ hash_alloc_intern (void *arg)
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define hash_update_ssq(hz, old, new) \
|
||||||
|
do { \
|
||||||
|
long double res; \
|
||||||
|
res = powl(old, 2.0); \
|
||||||
|
hz->stats.ssq -= (uint64_t) res;\
|
||||||
|
res = powl(new, 2.0); \
|
||||||
|
hz->stats.ssq += (uint64_t) res; \
|
||||||
|
} while (0); \
|
||||||
|
|
||||||
/* Expand hash if the chain length exceeds the threshold. */
|
/* Expand hash if the chain length exceeds the threshold. */
|
||||||
static void hash_expand (struct hash *hash)
|
static void hash_expand (struct hash *hash)
|
||||||
{
|
{
|
||||||
|
@ -75,6 +106,8 @@ static void hash_expand (struct hash *hash)
|
||||||
if (new_index == NULL)
|
if (new_index == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
hash->stats.empty = new_size;
|
||||||
|
|
||||||
for (i = 0; i < hash->size; i++)
|
for (i = 0; i < hash->size; i++)
|
||||||
for (hb = hash->index[i]; hb; hb = hbnext)
|
for (hb = hash->index[i]; hb; hb = hbnext)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +115,19 @@ static void hash_expand (struct hash *hash)
|
||||||
|
|
||||||
hbnext = hb->next;
|
hbnext = hb->next;
|
||||||
hb->next = new_index[h];
|
hb->next = new_index[h];
|
||||||
|
|
||||||
|
int oldlen = hb->next ? hb->next->len : 0;
|
||||||
|
int newlen = oldlen + 1;
|
||||||
|
|
||||||
|
if (newlen == 1)
|
||||||
|
hash->stats.empty--;
|
||||||
|
else
|
||||||
|
hb->next->len = 0;
|
||||||
|
|
||||||
|
hb->len = newlen;
|
||||||
|
|
||||||
|
hash_update_ssq(hash, oldlen, newlen);
|
||||||
|
|
||||||
new_index[h] = hb;
|
new_index[h] = hb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,19 +137,17 @@ static void hash_expand (struct hash *hash)
|
||||||
hash->index = new_index;
|
hash->index = new_index;
|
||||||
|
|
||||||
/* Ideally, new index should have chains half as long as the original.
|
/* Ideally, new index should have chains half as long as the original.
|
||||||
If expansion didn't help, then not worth expanding again,
|
* If expansion didn't help, then not worth expanding again,
|
||||||
the problem is the hash function. */
|
* the problem is the hash function. */
|
||||||
losers = 0;
|
losers = 0;
|
||||||
for (i = 0; i < hash->size; i++)
|
for (i = 0; i < hash->size; i++)
|
||||||
{
|
{
|
||||||
unsigned int len = 0;
|
unsigned int len = hash->index[i] ? hash->index[i]->len : 0;
|
||||||
for (hb = hash->index[i]; hb; hb = hb->next)
|
|
||||||
{
|
if (len > HASH_THRESHOLD/2)
|
||||||
if (++len > HASH_THRESHOLD/2)
|
++losers;
|
||||||
++losers;
|
if (len >= HASH_THRESHOLD)
|
||||||
if (len >= HASH_THRESHOLD)
|
hash->no_expand = 1;
|
||||||
hash->no_expand = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (losers > hash->count / 2)
|
if (losers > hash->count / 2)
|
||||||
|
@ -145,12 +189,25 @@ hash_get (struct hash *hash, void *data, void * (*alloc_func) (void *))
|
||||||
index = key & (hash->size - 1);
|
index = key & (hash->size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
|
backet = XCALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
|
||||||
backet->data = newdata;
|
backet->data = newdata;
|
||||||
backet->key = key;
|
backet->key = key;
|
||||||
backet->next = hash->index[index];
|
backet->next = hash->index[index];
|
||||||
hash->index[index] = backet;
|
hash->index[index] = backet;
|
||||||
hash->count++;
|
hash->count++;
|
||||||
|
|
||||||
|
int oldlen = backet->next ? backet->next->len : 0;
|
||||||
|
int newlen = oldlen + 1;
|
||||||
|
|
||||||
|
if (newlen == 1)
|
||||||
|
hash->stats.empty--;
|
||||||
|
else
|
||||||
|
backet->next->len = 0;
|
||||||
|
|
||||||
|
backet->len = newlen;
|
||||||
|
|
||||||
|
hash_update_ssq(hash, oldlen, newlen);
|
||||||
|
|
||||||
return backet->data;
|
return backet->data;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -193,11 +250,21 @@ hash_release (struct hash *hash, void *data)
|
||||||
{
|
{
|
||||||
if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
|
if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
|
||||||
{
|
{
|
||||||
if (backet == pp)
|
int oldlen = hash->index[index]->len;
|
||||||
|
int newlen = oldlen - 1;
|
||||||
|
|
||||||
|
if (backet == pp)
|
||||||
hash->index[index] = backet->next;
|
hash->index[index] = backet->next;
|
||||||
else
|
else
|
||||||
pp->next = backet->next;
|
pp->next = backet->next;
|
||||||
|
|
||||||
|
if (hash->index[index])
|
||||||
|
hash->index[index]->len = newlen;
|
||||||
|
else
|
||||||
|
hash->stats.empty++;
|
||||||
|
|
||||||
|
hash_update_ssq(hash, oldlen, newlen);
|
||||||
|
|
||||||
ret = backet->data;
|
ret = backet->data;
|
||||||
XFREE (MTYPE_HASH_BACKET, backet);
|
XFREE (MTYPE_HASH_BACKET, backet);
|
||||||
hash->count--;
|
hash->count--;
|
||||||
|
@ -275,6 +342,9 @@ hash_clean (struct hash *hash, void (*free_func) (void *))
|
||||||
}
|
}
|
||||||
hash->index[i] = NULL;
|
hash->index[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash->stats.ssq = 0;
|
||||||
|
hash->stats.empty = hash->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free hash memory. You may call hash_clean before call this
|
/* Free hash memory. You may call hash_clean before call this
|
||||||
|
@ -282,6 +352,136 @@ hash_clean (struct hash *hash, void (*free_func) (void *))
|
||||||
void
|
void
|
||||||
hash_free (struct hash *hash)
|
hash_free (struct hash *hash)
|
||||||
{
|
{
|
||||||
|
pthread_mutex_lock (&_hashes_mtx);
|
||||||
|
{
|
||||||
|
if (_hashes)
|
||||||
|
{
|
||||||
|
listnode_delete (_hashes, hash);
|
||||||
|
if (_hashes->count == 0)
|
||||||
|
{
|
||||||
|
list_delete (_hashes);
|
||||||
|
_hashes = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock (&_hashes_mtx);
|
||||||
|
|
||||||
|
if (hash->name)
|
||||||
|
XFREE (MTYPE_HASH, hash->name);
|
||||||
|
|
||||||
XFREE (MTYPE_HASH_INDEX, hash->index);
|
XFREE (MTYPE_HASH_INDEX, hash->index);
|
||||||
XFREE (MTYPE_HASH, hash);
|
XFREE (MTYPE_HASH, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* CLI commands ------------------------------------------------------------ */
|
||||||
|
|
||||||
|
DEFUN(show_hash_stats,
|
||||||
|
show_hash_stats_cmd,
|
||||||
|
"show hashtable [statistics]",
|
||||||
|
SHOW_STR
|
||||||
|
"Statistics about hash tables\n"
|
||||||
|
"Statistics about hash tables\n")
|
||||||
|
{
|
||||||
|
struct hash *h;
|
||||||
|
struct listnode *ln;
|
||||||
|
struct ttable *tt = ttable_new (&ttable_styles[TTSTYLE_BLANK]);
|
||||||
|
|
||||||
|
ttable_add_row (tt, "Hash table|Buckets|Entries|Empty|LF|SD|FLF|SD");
|
||||||
|
tt->style.cell.lpad = 2;
|
||||||
|
tt->style.cell.rpad = 1;
|
||||||
|
tt->style.corner = '+';
|
||||||
|
ttable_restyle (tt);
|
||||||
|
ttable_rowseps (tt, 0, BOTTOM, true, '-');
|
||||||
|
|
||||||
|
/* Summary statistics calculated are:
|
||||||
|
*
|
||||||
|
* - Load factor: This is the number of elements in the table divided by the
|
||||||
|
* number of buckets. Since this hash table implementation uses chaining,
|
||||||
|
* this value can be greater than 1. This number provides information on
|
||||||
|
* how 'full' the table is, but does not provide information on how evenly
|
||||||
|
* distributed the elements are. Notably, a load factor >= 1 does not 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 divided by
|
||||||
|
* the number of buckets that have some elements in them.
|
||||||
|
*
|
||||||
|
* - Std. Dev.: This is the standard deviation calculated from the relevant
|
||||||
|
* load factor. If the load factor is the mean of number of elements per
|
||||||
|
* bucket, the standard deviation measures how much any particular bucket
|
||||||
|
* is likely to deviate from the mean. As a rule of thumb this number
|
||||||
|
* 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 flf; // full load factor
|
||||||
|
double var; // overall variance
|
||||||
|
double fvar; // full variance
|
||||||
|
double stdv; // overall stddev
|
||||||
|
double fstdv; // full stddev
|
||||||
|
|
||||||
|
long double x2; // h->count ^ 2
|
||||||
|
long double ldc; // (long double) h->count
|
||||||
|
long double full; // h->size - h->stats.empty
|
||||||
|
long double ssq; // ssq casted to long double
|
||||||
|
|
||||||
|
pthread_mutex_lock (&_hashes_mtx);
|
||||||
|
for (ALL_LIST_ELEMENTS_RO (_hashes, ln, h))
|
||||||
|
{
|
||||||
|
if (!h->name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ssq = (long double) h->stats.ssq;
|
||||||
|
x2 = powl(h->count, 2.0);
|
||||||
|
ldc = (long double) h->count;
|
||||||
|
full = h->size - h->stats.empty;
|
||||||
|
lf = h->count / (double) h->size;
|
||||||
|
flf = full ? h->count / (double) (full) : 0;
|
||||||
|
var = ldc ? (1.0 / ldc) * (ssq - x2 / ldc) : 0;
|
||||||
|
fvar = full ? (1.0 / full) * (ssq - x2 / full) : 0;
|
||||||
|
var = (var < .0001) ? 0 : var;
|
||||||
|
fvar = (fvar < .0001) ? 0 : fvar;
|
||||||
|
stdv = sqrt(var);
|
||||||
|
fstdv = sqrt(fvar);
|
||||||
|
|
||||||
|
ttable_add_row (tt, "%s|%d|%ld|%.0f%%|%.2lf|%.2lf|%.2lf|%.2lf", h->name,
|
||||||
|
h->size, h->count,
|
||||||
|
(h->stats.empty / (double) h->size)*100, lf, stdv, flf,
|
||||||
|
fstdv);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock (&_hashes_mtx);
|
||||||
|
|
||||||
|
/* display header */
|
||||||
|
char header[] = "Showing hash table statistics for ";
|
||||||
|
char underln[sizeof(header) + strlen(frr_protonameinst)];
|
||||||
|
memset (underln, '-', sizeof(underln));
|
||||||
|
underln[sizeof(underln) - 1] = '\0';
|
||||||
|
vty_outln (vty, "%s%s", header, frr_protonameinst);
|
||||||
|
vty_outln (vty, "%s", underln);
|
||||||
|
|
||||||
|
vty_outln (vty, "# allocated: %d", _hashes->count);
|
||||||
|
vty_outln (vty, "# named: %d%s", tt->nrows - 1, VTYNL);
|
||||||
|
|
||||||
|
if (tt->nrows > 1)
|
||||||
|
{
|
||||||
|
ttable_colseps (tt, 0, RIGHT, true, '|');
|
||||||
|
char *table = ttable_dump (tt, VTYNL);
|
||||||
|
vty_out (vty, "%s%s", table, VTYNL);
|
||||||
|
XFREE (MTYPE_TMP, table);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vty_outln (vty, "No named hash tables to display.");
|
||||||
|
|
||||||
|
ttable_del (tt);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
hash_cmd_init ()
|
||||||
|
{
|
||||||
|
_hashes = list_new();
|
||||||
|
install_element (ENABLE_NODE, &show_hash_stats_cmd);
|
||||||
|
}
|
||||||
|
|
26
lib/hash.h
26
lib/hash.h
|
@ -22,6 +22,7 @@
|
||||||
#define _ZEBRA_HASH_H
|
#define _ZEBRA_HASH_H
|
||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
#include "frratomic.h"
|
||||||
|
|
||||||
DECLARE_MTYPE(HASH)
|
DECLARE_MTYPE(HASH)
|
||||||
DECLARE_MTYPE(HASH_BACKET)
|
DECLARE_MTYPE(HASH_BACKET)
|
||||||
|
@ -35,6 +36,10 @@ DECLARE_MTYPE(HASH_BACKET)
|
||||||
|
|
||||||
struct hash_backet
|
struct hash_backet
|
||||||
{
|
{
|
||||||
|
/* if this backet is the head of the linked listed, len denotes the number of
|
||||||
|
* elements in the list */
|
||||||
|
int len;
|
||||||
|
|
||||||
/* Linked list. */
|
/* Linked list. */
|
||||||
struct hash_backet *next;
|
struct hash_backet *next;
|
||||||
|
|
||||||
|
@ -45,6 +50,14 @@ struct hash_backet
|
||||||
void *data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct hashstats
|
||||||
|
{
|
||||||
|
/* number of empty hash buckets */
|
||||||
|
_Atomic int empty;
|
||||||
|
/* sum of squares of bucket length */
|
||||||
|
_Atomic uint64_t ssq;
|
||||||
|
};
|
||||||
|
|
||||||
struct hash
|
struct hash
|
||||||
{
|
{
|
||||||
/* Hash backet. */
|
/* Hash backet. */
|
||||||
|
@ -64,12 +77,19 @@ struct hash
|
||||||
|
|
||||||
/* Backet alloc. */
|
/* Backet alloc. */
|
||||||
unsigned long count;
|
unsigned long count;
|
||||||
|
|
||||||
|
struct hashstats stats;
|
||||||
|
|
||||||
|
/* hash name */
|
||||||
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct hash *hash_create (unsigned int (*) (void *),
|
extern struct hash *hash_create (unsigned int (*) (void *),
|
||||||
int (*) (const void *, const void *));
|
int (*) (const void *, const void *),
|
||||||
|
const char *);
|
||||||
extern struct hash *hash_create_size (unsigned int, unsigned int (*) (void *),
|
extern struct hash *hash_create_size (unsigned int, unsigned int (*) (void *),
|
||||||
int (*) (const void *, const void *));
|
int (*) (const void *, const void *),
|
||||||
|
const char *);
|
||||||
|
|
||||||
extern void *hash_get (struct hash *, void *, void * (*) (void *));
|
extern void *hash_get (struct hash *, void *, void * (*) (void *));
|
||||||
extern void *hash_alloc_intern (void *);
|
extern void *hash_alloc_intern (void *);
|
||||||
|
@ -87,4 +107,6 @@ extern void hash_free (struct hash *);
|
||||||
|
|
||||||
extern unsigned int string_hash_make (const char *);
|
extern unsigned int string_hash_make (const char *);
|
||||||
|
|
||||||
|
extern void hash_cmd_init (void);
|
||||||
|
|
||||||
#endif /* _ZEBRA_HASH_H */
|
#endif /* _ZEBRA_HASH_H */
|
||||||
|
|
|
@ -316,7 +316,7 @@ if_rmap_reset ()
|
||||||
void
|
void
|
||||||
if_rmap_init (int node)
|
if_rmap_init (int node)
|
||||||
{
|
{
|
||||||
ifrmaphash = hash_create (if_rmap_hash_make, if_rmap_hash_cmp);
|
ifrmaphash = hash_create (if_rmap_hash_make, if_rmap_hash_cmp, NULL);
|
||||||
if (node == RIPNG_NODE) {
|
if (node == RIPNG_NODE) {
|
||||||
} else if (node == RIP_NODE) {
|
} else if (node == RIP_NODE) {
|
||||||
install_element (RIP_NODE, &if_rmap_cmd);
|
install_element (RIP_NODE, &if_rmap_cmd);
|
||||||
|
|
|
@ -97,7 +97,7 @@ void qobj_init (void)
|
||||||
if (!nodes)
|
if (!nodes)
|
||||||
{
|
{
|
||||||
pthread_rwlock_init (&nodes_lock, NULL);
|
pthread_rwlock_init (&nodes_lock, NULL);
|
||||||
nodes = hash_create (qobj_key, qobj_cmp);
|
nodes = hash_create (qobj_key, qobj_cmp, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1767,7 +1767,7 @@ route_map_dep_hash_alloc(void *p)
|
||||||
dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
|
dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
|
||||||
dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
|
dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
|
||||||
dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
|
dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
|
||||||
route_map_rmap_hash_cmp);
|
route_map_rmap_hash_cmp, NULL);
|
||||||
dep_entry->this_hash = NULL;
|
dep_entry->this_hash = NULL;
|
||||||
|
|
||||||
return((void *)dep_entry);
|
return((void *)dep_entry);
|
||||||
|
@ -2986,11 +2986,11 @@ route_map_init (void)
|
||||||
/* Make vector for match and set. */
|
/* Make vector for match and set. */
|
||||||
route_match_vec = vector_init (1);
|
route_match_vec = vector_init (1);
|
||||||
route_set_vec = vector_init (1);
|
route_set_vec = vector_init (1);
|
||||||
route_map_master_hash = hash_create(route_map_hash_key_make, route_map_hash_cmp);
|
route_map_master_hash = hash_create(route_map_hash_key_make, route_map_hash_cmp, NULL);
|
||||||
|
|
||||||
for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
|
for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
|
||||||
route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
|
route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
|
||||||
route_map_dep_hash_cmp);
|
route_map_dep_hash_cmp, NULL);
|
||||||
|
|
||||||
cmd_variable_handler_register(rmap_var_handlers);
|
cmd_variable_handler_register(rmap_var_handlers);
|
||||||
|
|
||||||
|
|
|
@ -388,7 +388,7 @@ thread_master_create (const char *name)
|
||||||
|
|
||||||
rv->cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
|
rv->cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
|
||||||
(int (*) (const void *, const void *))
|
(int (*) (const void *, const void *))
|
||||||
cpu_record_hash_cmp);
|
cpu_record_hash_cmp, NULL);
|
||||||
|
|
||||||
|
|
||||||
/* Initialize the timer queues */
|
/* Initialize the timer queues */
|
||||||
|
|
|
@ -81,7 +81,7 @@ struct nhrp_cache *nhrp_cache_get(struct interface *ifp, union sockunion *remote
|
||||||
struct nhrp_cache key;
|
struct nhrp_cache key;
|
||||||
|
|
||||||
if (!nifp->cache_hash) {
|
if (!nifp->cache_hash) {
|
||||||
nifp->cache_hash = hash_create(nhrp_cache_protocol_key, nhrp_cache_protocol_cmp);
|
nifp->cache_hash = hash_create(nhrp_cache_protocol_key, nhrp_cache_protocol_cmp, NULL);
|
||||||
if (!nifp->cache_hash)
|
if (!nifp->cache_hash)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,7 @@ struct nhrp_peer *nhrp_peer_get(struct interface *ifp, const union sockunion *re
|
||||||
struct nhrp_vc *vc;
|
struct nhrp_vc *vc;
|
||||||
|
|
||||||
if (!nifp->peer_hash) {
|
if (!nifp->peer_hash) {
|
||||||
nifp->peer_hash = hash_create(nhrp_peer_key, nhrp_peer_cmp);
|
nifp->peer_hash = hash_create(nhrp_peer_key, nhrp_peer_cmp, NULL);
|
||||||
if (!nifp->peer_hash) return NULL;
|
if (!nifp->peer_hash) return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ void nhrp_vc_init(void)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp);
|
nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp, NULL);
|
||||||
for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++)
|
for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++)
|
||||||
list_init(&childlist_head[i]);
|
list_init(&childlist_head[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ static int nhrp_reqid_cmp(const void *data, const void *key)
|
||||||
uint32_t nhrp_reqid_alloc(struct nhrp_reqid_pool *p, struct nhrp_reqid *r, void (*cb)(struct nhrp_reqid *, void *))
|
uint32_t nhrp_reqid_alloc(struct nhrp_reqid_pool *p, struct nhrp_reqid *r, void (*cb)(struct nhrp_reqid *, void *))
|
||||||
{
|
{
|
||||||
if (!p->reqid_hash) {
|
if (!p->reqid_hash) {
|
||||||
p->reqid_hash = hash_create(nhrp_reqid_key, nhrp_reqid_cmp);
|
p->reqid_hash = hash_create(nhrp_reqid_key, nhrp_reqid_cmp, NULL);
|
||||||
p->next_request_id = 1;
|
p->next_request_id = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
|
||||||
pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
|
pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
|
||||||
|
|
||||||
pim_ifp->pim_ifchannel_hash = hash_create (pim_ifchannel_hash_key,
|
pim_ifp->pim_ifchannel_hash = hash_create (pim_ifchannel_hash_key,
|
||||||
pim_ifchannel_equal);
|
pim_ifchannel_equal, NULL);
|
||||||
|
|
||||||
ifp->info = pim_ifp;
|
ifp->info = pim_ifp;
|
||||||
|
|
||||||
|
|
|
@ -822,7 +822,7 @@ static struct igmp_sock *igmp_sock_new(int fd,
|
||||||
igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free;
|
igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free;
|
||||||
|
|
||||||
igmp->igmp_group_hash = hash_create (igmp_group_hash_key,
|
igmp->igmp_group_hash = hash_create (igmp_group_hash_key,
|
||||||
igmp_group_hash_equal);
|
igmp_group_hash_equal, NULL);
|
||||||
|
|
||||||
igmp->fd = fd;
|
igmp->fd = fd;
|
||||||
igmp->interface = ifp;
|
igmp->interface = ifp;
|
||||||
|
|
|
@ -1570,13 +1570,13 @@ pim_msdp_init(struct thread_master *master)
|
||||||
msdp->master = master;
|
msdp->master = master;
|
||||||
|
|
||||||
msdp->peer_hash = hash_create(pim_msdp_peer_hash_key_make,
|
msdp->peer_hash = hash_create(pim_msdp_peer_hash_key_make,
|
||||||
pim_msdp_peer_hash_eq);
|
pim_msdp_peer_hash_eq, NULL);
|
||||||
msdp->peer_list = list_new();
|
msdp->peer_list = list_new();
|
||||||
msdp->peer_list->del = (void (*)(void *))pim_msdp_peer_free;
|
msdp->peer_list->del = (void (*)(void *))pim_msdp_peer_free;
|
||||||
msdp->peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp;
|
msdp->peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp;
|
||||||
|
|
||||||
msdp->sa_hash = hash_create(pim_msdp_sa_hash_key_make,
|
msdp->sa_hash = hash_create(pim_msdp_sa_hash_key_make,
|
||||||
pim_msdp_sa_hash_eq);
|
pim_msdp_sa_hash_eq, NULL);
|
||||||
msdp->sa_list = list_new();
|
msdp->sa_list = list_new();
|
||||||
msdp->sa_list->del = (void (*)(void *))pim_msdp_sa_free;
|
msdp->sa_list->del = (void (*)(void *))pim_msdp_sa_free;
|
||||||
msdp->sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp;
|
msdp->sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp;
|
||||||
|
|
|
@ -103,7 +103,7 @@ void
|
||||||
pim_oil_init (void)
|
pim_oil_init (void)
|
||||||
{
|
{
|
||||||
pim_channel_oil_hash = hash_create_size (8192, pim_oil_hash_key,
|
pim_channel_oil_hash = hash_create_size (8192, pim_oil_hash_key,
|
||||||
pim_oil_equal);
|
pim_oil_equal, NULL);
|
||||||
|
|
||||||
pim_channel_oil_list = list_new();
|
pim_channel_oil_list = list_new();
|
||||||
if (!pim_channel_oil_list) {
|
if (!pim_channel_oil_list) {
|
||||||
|
|
|
@ -1760,7 +1760,7 @@ pim_upstream_init (void)
|
||||||
pim_upstream_hash_key,
|
pim_upstream_hash_key,
|
||||||
pim_upstream_sg_running);
|
pim_upstream_sg_running);
|
||||||
pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
|
pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
|
||||||
pim_upstream_equal);
|
pim_upstream_equal, NULL);
|
||||||
|
|
||||||
pim_upstream_list = list_new ();
|
pim_upstream_list = list_new ();
|
||||||
pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
|
pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;
|
||||||
|
|
|
@ -250,7 +250,7 @@ pim_instance_init (vrf_id_t vrf_id, afi_t afi)
|
||||||
pim->spt.switchover = PIM_SPT_IMMEDIATE;
|
pim->spt.switchover = PIM_SPT_IMMEDIATE;
|
||||||
pim->spt.plist = NULL;
|
pim->spt.plist = NULL;
|
||||||
|
|
||||||
pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal);
|
pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal, NULL);
|
||||||
|
|
||||||
if (PIM_DEBUG_ZEBRA)
|
if (PIM_DEBUG_ZEBRA)
|
||||||
zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);
|
zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);
|
||||||
|
|
|
@ -140,7 +140,7 @@ test_state_new(void)
|
||||||
rv->table = srcdest_table_init();
|
rv->table = srcdest_table_init();
|
||||||
assert(rv->table);
|
assert(rv->table);
|
||||||
|
|
||||||
rv->log = hash_create(log_key, log_cmp);
|
rv->log = hash_create(log_key, log_cmp, NULL);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2103,6 +2103,33 @@ DEFUN (vtysh_show_work_queues_daemon,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFUN (vtysh_show_hashtable,
|
||||||
|
vtysh_show_hashtable_cmd,
|
||||||
|
"show hashtable [statistics]",
|
||||||
|
SHOW_STR
|
||||||
|
"Statistics about hash tables\n"
|
||||||
|
"Statistics about hash tables\n")
|
||||||
|
{
|
||||||
|
char cmd[] = "do show hashtable statistics";
|
||||||
|
unsigned long i;
|
||||||
|
int ret = CMD_SUCCESS;
|
||||||
|
|
||||||
|
fprintf (stdout, "\n");
|
||||||
|
fprintf (stdout, "Load factor (LF) - average number of elements across all buckets\n");
|
||||||
|
fprintf (stdout, "Full load factor (FLF) - average number of elements across full buckets\n\n");
|
||||||
|
|
||||||
|
fprintf (stdout, "Standard deviation (SD) is calculated for both the LF and FLF\n");
|
||||||
|
fprintf (stdout, "and indicates the typical deviation of bucket chain length\n");
|
||||||
|
fprintf (stdout, "from the value in the corresponding load factor.\n\n");
|
||||||
|
|
||||||
|
for (i = 0; i < array_size(vtysh_client); i++)
|
||||||
|
if ( vtysh_client[i].fd >= 0 ) {
|
||||||
|
ret = vtysh_client_execute (&vtysh_client[i], cmd, stdout);
|
||||||
|
fprintf (stdout, "\n");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
DEFUNSH (VTYSH_ZEBRA,
|
DEFUNSH (VTYSH_ZEBRA,
|
||||||
vtysh_link_params,
|
vtysh_link_params,
|
||||||
vtysh_link_params_cmd,
|
vtysh_link_params_cmd,
|
||||||
|
@ -3575,6 +3602,8 @@ vtysh_init_vty (void)
|
||||||
install_element (VIEW_NODE, &vtysh_show_work_queues_cmd);
|
install_element (VIEW_NODE, &vtysh_show_work_queues_cmd);
|
||||||
install_element (VIEW_NODE, &vtysh_show_work_queues_daemon_cmd);
|
install_element (VIEW_NODE, &vtysh_show_work_queues_daemon_cmd);
|
||||||
|
|
||||||
|
install_element (VIEW_NODE, &vtysh_show_hashtable_cmd);
|
||||||
|
|
||||||
install_element (VIEW_NODE, &vtysh_show_thread_cmd);
|
install_element (VIEW_NODE, &vtysh_show_thread_cmd);
|
||||||
|
|
||||||
/* Logging */
|
/* Logging */
|
||||||
|
|
|
@ -2994,8 +2994,8 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf)
|
||||||
{
|
{
|
||||||
if (!zvrf)
|
if (!zvrf)
|
||||||
return;
|
return;
|
||||||
zvrf->slsp_table = hash_create(label_hash, label_cmp);
|
zvrf->slsp_table = hash_create(label_hash, label_cmp, NULL);
|
||||||
zvrf->lsp_table = hash_create(label_hash, label_cmp);
|
zvrf->lsp_table = hash_create(label_hash, label_cmp, NULL);
|
||||||
zvrf->fec_table[AFI_IP] = route_table_init();
|
zvrf->fec_table[AFI_IP] = route_table_init();
|
||||||
zvrf->fec_table[AFI_IP6] = route_table_init();
|
zvrf->fec_table[AFI_IP6] = route_table_init();
|
||||||
zvrf->mpls_flags = 0;
|
zvrf->mpls_flags = 0;
|
||||||
|
|
Loading…
Reference in a new issue