summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_advertise.c2
-rw-r--r--bgpd/bgp_aspath.c2
-rw-r--r--bgpd/bgp_attr.c10
-rw-r--r--bgpd/bgp_community.c2
-rw-r--r--bgpd/bgp_ecommunity.c2
-rw-r--r--bgpd/bgp_lcommunity.c2
-rw-r--r--bgpd/bgp_nexthop.c2
-rw-r--r--bgpd/bgp_updgrp.c4
-rw-r--r--bgpd/bgpd.c2
-rwxr-xr-xconfigure.ac5
-rw-r--r--lib/command.c3
-rw-r--r--lib/distribute.c3
-rw-r--r--lib/frr_pthread.c2
-rw-r--r--lib/hash.c234
-rw-r--r--lib/hash.h26
-rw-r--r--lib/if_rmap.c2
-rw-r--r--lib/qobj.c2
-rw-r--r--lib/routemap.c6
-rw-r--r--lib/thread.c2
-rw-r--r--nhrpd/nhrp_cache.c2
-rw-r--r--nhrpd/nhrp_peer.c2
-rw-r--r--nhrpd/nhrp_vc.c2
-rw-r--r--nhrpd/reqid.c2
-rw-r--r--pimd/pim_iface.c2
-rw-r--r--pimd/pim_igmp.c2
-rw-r--r--pimd/pim_msdp.c4
-rw-r--r--pimd/pim_oil.c2
-rw-r--r--pimd/pim_upstream.c2
-rw-r--r--pimd/pimd.c2
-rw-r--r--tests/lib/test_srcdest_table.c2
-rw-r--r--vtysh/vtysh.c29
-rw-r--r--zebra/zebra_mpls.c4
32 files changed, 314 insertions, 56 deletions
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index f005b20183..c44e067732 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -267,7 +267,7 @@ bgp_sync_init (struct peer *peer)
BGP_ADV_FIFO_INIT (&sync->withdraw);
BGP_ADV_FIFO_INIT (&sync->withdraw_low);
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);
}
}
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index f9daeb2ed3..f304b3a1b7 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -2134,7 +2134,7 @@ aspath_cmp (const void *arg1, const void *arg2)
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
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 6a7ec473b8..d343ce236b 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -215,7 +215,7 @@ cluster_unintern (struct cluster_list *cluster)
static 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
@@ -403,9 +403,9 @@ encap_hash_cmp (const void *p1, const void *p2)
static 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
- vnc_hash = hash_create (encap_hash_key_make, encap_hash_cmp);
+ vnc_hash = hash_create (encap_hash_key_make, encap_hash_cmp, NULL);
#endif
}
@@ -517,7 +517,7 @@ transit_hash_cmp (const void *p1, const void *p2)
static 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
@@ -765,7 +765,7 @@ attrhash_cmp (const void *p1, const void *p2)
static void
attrhash_init (void)
{
- attrhash = hash_create (attrhash_key_make, attrhash_cmp);
+ attrhash = hash_create (attrhash_key_make, attrhash_cmp, "BGP Attributes");
}
/*
diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c
index bd67829d77..be4cdac0ac 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -686,7 +686,7 @@ void
community_init (void)
{
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
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index fa1ad813f1..0555d1bbe3 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -284,7 +284,7 @@ ecommunity_cmp (const void *arg1, const void *arg2)
void
ecommunity_init (void)
{
- ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp);
+ ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp, NULL);
}
void
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c
index 4a969c8b90..23c19f70ce 100644
--- a/bgpd/bgp_lcommunity.c
+++ b/bgpd/bgp_lcommunity.c
@@ -286,7 +286,7 @@ lcommunity_hash (void)
void
lcommunity_init (void)
{
- lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp);
+ lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp, NULL);
}
void
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 4216a2d49b..d0c4d2c945 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -140,7 +140,7 @@ void
bgp_address_init (struct bgp *bgp)
{
bgp->address_hash = hash_create (bgp_address_hash_key_make,
- bgp_address_hash_cmp);
+ bgp_address_hash_cmp, NULL);
}
void
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index b1b3336363..722eed91c0 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -87,7 +87,7 @@ sync_init (struct update_subgroup *subgrp)
BGP_ADV_FIFO_INIT (&subgrp->sync->update);
BGP_ADV_FIFO_INIT (&subgrp->sync->withdraw);
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 RX a BGP_UPDATE where the attributes alone are just
@@ -1559,7 +1559,7 @@ update_bgp_group_init (struct bgp *bgp)
AF_FOREACH (afid)
bgp->update_groups[afid] = hash_create (updgrp_hash_key_make,
- updgrp_hash_cmp);
+ updgrp_hash_cmp, NULL);
}
void
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 033a3d194d..65b53be653 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -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 = list_new ();
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->cmp = (int (*)(void *, void *)) peer_group_cmp;
diff --git a/configure.ac b/configure.ac
index c47c185bfe..03951503c1 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1590,6 +1590,11 @@ AC_SUBST(SNMP_LIBS)
AC_SUBST(SNMP_CFLAGS)
dnl ---------------
+dnl math
+dnl ---------------
+AC_SEARCH_LIBS([sqrt], [m])
+
+dnl ---------------
dnl dlopen & dlinfo
dnl ---------------
AC_SEARCH_LIBS(dlopen, [dl dld], [], [
diff --git a/lib/command.c b/lib/command.c
index f019473308..de8899687c 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -233,7 +233,7 @@ install_node (struct cmd_node *node,
// add start node
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);
- 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 ();
workqueue_cmd_init ();
+ hash_cmd_init ();
}
install_element (CONFIG_NODE, &hostname_cmd);
diff --git a/lib/distribute.c b/lib/distribute.c
index c771f018c2..79d7b18ff5 100644
--- a/lib/distribute.c
+++ b/lib/distribute.c
@@ -522,7 +522,8 @@ void
distribute_list_init (int node)
{
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, ) */
if (node == RIP_NODE) {
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index 614c722be1..4b9bed4524 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -55,7 +55,7 @@ void frr_pthread_init()
pthread_mutex_lock(&pthread_table_mtx);
{
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);
}
diff --git a/lib/hash.c b/lib/hash.c
index 553a137eb6..95643bbae0 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -19,23 +19,33 @@
*/
#include <zebra.h>
+#include <math.h>
#include "hash.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_BACKET, "Hash Bucket")
DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index")
+pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER;
+static struct list *_hashes;
+
/* Allocate a new hash. */
struct hash *
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;
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,
sizeof (struct hash_backet *) * 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_cmp = hash_cmp;
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;
}
@@ -50,9 +71,10 @@ hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
/* Allocate a new hash with default hash size. */
struct hash *
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
@@ -64,6 +86,15 @@ hash_alloc_intern (void *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. */
static void hash_expand (struct hash *hash)
{
@@ -75,6 +106,8 @@ static void hash_expand (struct hash *hash)
if (new_index == NULL)
return;
+ hash->stats.empty = new_size;
+
for (i = 0; i < hash->size; i++)
for (hb = hash->index[i]; hb; hb = hbnext)
{
@@ -82,6 +115,19 @@ static void hash_expand (struct hash *hash)
hbnext = hb->next;
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;
}
@@ -91,19 +137,17 @@ static void hash_expand (struct hash *hash)
hash->index = new_index;
/* Ideally, new index should have chains half as long as the original.
- If expansion didn't help, then not worth expanding again,
- the problem is the hash function. */
+ * If expansion didn't help, then not worth expanding again,
+ * the problem is the hash function. */
losers = 0;
for (i = 0; i < hash->size; i++)
{
- unsigned int len = 0;
- for (hb = hash->index[i]; hb; hb = hb->next)
- {
- if (++len > HASH_THRESHOLD/2)
- ++losers;
- if (len >= HASH_THRESHOLD)
- hash->no_expand = 1;
- }
+ unsigned int len = hash->index[i] ? hash->index[i]->len : 0;
+
+ if (len > HASH_THRESHOLD/2)
+ ++losers;
+ if (len >= HASH_THRESHOLD)
+ hash->no_expand = 1;
}
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);
}
- backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
+ backet = XCALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
backet->data = newdata;
backet->key = key;
backet->next = hash->index[index];
hash->index[index] = backet;
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 NULL;
@@ -193,11 +250,21 @@ hash_release (struct hash *hash, void *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;
- else
+ else
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;
XFREE (MTYPE_HASH_BACKET, backet);
hash->count--;
@@ -275,6 +342,9 @@ hash_clean (struct hash *hash, void (*free_func) (void *))
}
hash->index[i] = NULL;
}
+
+ hash->stats.ssq = 0;
+ hash->stats.empty = hash->size;
}
/* 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
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, 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);
+}
diff --git a/lib/hash.h b/lib/hash.h
index bafb35a2a3..9395440acb 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -22,6 +22,7 @@
#define _ZEBRA_HASH_H
#include "memory.h"
+#include "frratomic.h"
DECLARE_MTYPE(HASH)
DECLARE_MTYPE(HASH_BACKET)
@@ -35,6 +36,10 @@ DECLARE_MTYPE(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. */
struct hash_backet *next;
@@ -45,6 +50,14 @@ struct hash_backet
void *data;
};
+struct hashstats
+{
+ /* number of empty hash buckets */
+ _Atomic int empty;
+ /* sum of squares of bucket length */
+ _Atomic uint64_t ssq;
+};
+
struct hash
{
/* Hash backet. */
@@ -64,12 +77,19 @@ struct hash
/* Backet alloc. */
unsigned long count;
+
+ struct hashstats stats;
+
+ /* hash name */
+ char *name;
};
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 *),
- int (*) (const void *, const void *));
+ int (*) (const void *, const void *),
+ const char *);
extern void *hash_get (struct hash *, void *, void * (*) (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 void hash_cmd_init (void);
+
#endif /* _ZEBRA_HASH_H */
diff --git a/lib/if_rmap.c b/lib/if_rmap.c
index f9c6a55d7b..32bebd67ff 100644
--- a/lib/if_rmap.c
+++ b/lib/if_rmap.c
@@ -316,7 +316,7 @@ if_rmap_reset ()
void
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) {
} else if (node == RIP_NODE) {
install_element (RIP_NODE, &if_rmap_cmd);
diff --git a/lib/qobj.c b/lib/qobj.c
index 4cf7fbca7b..8fa8163970 100644
--- a/lib/qobj.c
+++ b/lib/qobj.c
@@ -97,7 +97,7 @@ void qobj_init (void)
if (!nodes)
{
pthread_rwlock_init (&nodes_lock, NULL);
- nodes = hash_create (qobj_key, qobj_cmp);
+ nodes = hash_create (qobj_key, qobj_cmp, NULL);
}
}
diff --git a/lib/routemap.c b/lib/routemap.c
index 9eb28888ad..caba8afd71 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -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->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
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;
return((void *)dep_entry);
@@ -2986,11 +2986,11 @@ route_map_init (void)
/* Make vector for match and set. */
route_match_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++)
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);
diff --git a/lib/thread.c b/lib/thread.c
index 71b0bb2aed..4e72d4c96f 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -388,7 +388,7 @@ thread_master_create (const char *name)
rv->cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
(int (*) (const void *, const void *))
- cpu_record_hash_cmp);
+ cpu_record_hash_cmp, NULL);
/* Initialize the timer queues */
diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c
index 2d92842b5c..bd884bbc51 100644
--- a/nhrpd/nhrp_cache.c
+++ b/nhrpd/nhrp_cache.c
@@ -81,7 +81,7 @@ struct nhrp_cache *nhrp_cache_get(struct interface *ifp, union sockunion *remote
struct nhrp_cache key;
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)
return NULL;
}
diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c
index d9e8627a14..95541b88b6 100644
--- a/nhrpd/nhrp_peer.c
+++ b/nhrpd/nhrp_peer.c
@@ -182,7 +182,7 @@ struct nhrp_peer *nhrp_peer_get(struct interface *ifp, const union sockunion *re
struct nhrp_vc *vc;
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;
}
diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c
index 57fb462ab6..a5547a7a7e 100644
--- a/nhrpd/nhrp_vc.c
+++ b/nhrpd/nhrp_vc.c
@@ -196,7 +196,7 @@ void nhrp_vc_init(void)
{
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++)
list_init(&childlist_head[i]);
}
diff --git a/nhrpd/reqid.c b/nhrpd/reqid.c
index 24b3199397..61fbfd7795 100644
--- a/nhrpd/reqid.c
+++ b/nhrpd/reqid.c
@@ -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 *))
{
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;
}
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index afaa951724..f4125af9b4 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -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_hash = hash_create (pim_ifchannel_hash_key,
- pim_ifchannel_equal);
+ pim_ifchannel_equal, NULL);
ifp->info = pim_ifp;
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index c883a2c8bb..ae5f365b82 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -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_hash = hash_create (igmp_group_hash_key,
- igmp_group_hash_equal);
+ igmp_group_hash_equal, NULL);
igmp->fd = fd;
igmp->interface = ifp;
diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c
index 18e24dae32..71a2869818 100644
--- a/pimd/pim_msdp.c
+++ b/pimd/pim_msdp.c
@@ -1570,13 +1570,13 @@ pim_msdp_init(struct thread_master *master)
msdp->master = master;
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->del = (void (*)(void *))pim_msdp_peer_free;
msdp->peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp;
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->del = (void (*)(void *))pim_msdp_sa_free;
msdp->sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp;
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 71ca576d93..66be2be6f5 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -103,7 +103,7 @@ void
pim_oil_init (void)
{
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();
if (!pim_channel_oil_list) {
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index d7ebdea45d..442cb02a15 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -1760,7 +1760,7 @@ pim_upstream_init (void)
pim_upstream_hash_key,
pim_upstream_sg_running);
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->del = (void (*)(void *)) pim_upstream_free;
diff --git a/pimd/pimd.c b/pimd/pimd.c
index ec1fe5b6d0..b1d566f51b 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -250,7 +250,7 @@ pim_instance_init (vrf_id_t vrf_id, afi_t afi)
pim->spt.switchover = PIM_SPT_IMMEDIATE;
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)
zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);
diff --git a/tests/lib/test_srcdest_table.c b/tests/lib/test_srcdest_table.c
index 07f60668e7..792e2696e9 100644
--- a/tests/lib/test_srcdest_table.c
+++ b/tests/lib/test_srcdest_table.c
@@ -140,7 +140,7 @@ test_state_new(void)
rv->table = srcdest_table_init();
assert(rv->table);
- rv->log = hash_create(log_key, log_cmp);
+ rv->log = hash_create(log_key, log_cmp, NULL);
return rv;
}
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index d10861a668..0e04f4bf8e 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -2103,6 +2103,33 @@ DEFUN (vtysh_show_work_queues_daemon,
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,
vtysh_link_params,
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_daemon_cmd);
+ install_element (VIEW_NODE, &vtysh_show_hashtable_cmd);
+
install_element (VIEW_NODE, &vtysh_show_thread_cmd);
/* Logging */
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index a8e7f5372c..e08ff08cf6 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -2994,8 +2994,8 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf)
{
if (!zvrf)
return;
- zvrf->slsp_table = hash_create(label_hash, label_cmp);
- zvrf->lsp_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, NULL);
zvrf->fec_table[AFI_IP] = route_table_init();
zvrf->fec_table[AFI_IP6] = route_table_init();
zvrf->mpls_flags = 0;