]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: peer hash expands until we are out of memory 884/head
authorDaniel Walton <dwalton@cumulusnetworks.com>
Mon, 31 Jul 2017 21:22:23 +0000 (21:22 +0000)
committerDaniel Walton <dwalton@cumulusnetworks.com>
Mon, 31 Jul 2017 21:22:23 +0000 (21:22 +0000)
Signed-off-by: Daniel Walton <dwalton@cumulusnetworks.com>
swpX peers all start out with the same sockunion so initially they all
go into the same hash bucket. Once IPv6 ND has worked its magic they
will have different sockunions and will go in different buckets...life
is good.

Until then though, we are in a phase where all swpX peers have the same
socknunion. Once we have HASH_THRESHOLD (10) swpX peers and call
hash_get for a new swpX peer the hash code calls hash_expand(). This
happens because there are more than HASH_THRESHOLD entries in a single
bucket so the logic is "expand the hash to spread things out"...in our
case expanding doesn't spread out the swpX peers because all of their
sockunions are the same.

I looked at having peer_hash_make and peer_hash_same consider the ifname
of the swpX peer but that is a large change that we don't want to make
at the moment. So the fix is to put a cap on how large we are
willing to let the hash table get. By default there is no limit but if
max_size is set we will not allow the hash to expand above that.

bgpd/bgpd.c
bgpd/bgpd.h
lib/hash.c
lib/hash.h

index a0e2d6749a735064fe7b2a13c2eaf3d779e19977..b4e000f8bbede4da2151cc26d399bb2e482b55c3 100644 (file)
@@ -746,7 +746,7 @@ static unsigned int peer_hash_key_make(void *p)
        return sockunion_hash(&peer->su);
 }
 
-static int peer_hash_cmp(const void *p1, const void *p2)
+static int peer_hash_same(const void *p1, const void *p2)
 {
        const struct peer *peer1 = p1;
        const struct peer *peer2 = p2;
@@ -2757,7 +2757,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
                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, NULL);
+       bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, NULL);
+       bgp->peerhash->max_size = BGP_PEER_MAX_HASH_SIZE;
 
        bgp->group = list_new();
        bgp->group->cmp = (int (*)(void *, void *))peer_group_cmp;
index 67b8289c70bccbeddb890c88ff21b9cab2de3fc0..ff5e709dae78dd60a53bf6aa1f18326cd91f0d4c 100644 (file)
@@ -36,6 +36,7 @@
 #include "bitfield.h"
 
 #define BGP_MAX_HOSTNAME 64    /* Linux max, is larger than most other sys */
+#define BGP_PEER_MAX_HASH_SIZE 16384
 
 /* Default interval for IPv6 RAs when triggered by BGP unnumbered neighbor. */
 #define BGP_UNNUM_DEFAULT_RA_INTERVAL 10
index a7714f156930e8c4d46c3da45c1188c18a44956e..e74e4355dc99f6396ec64ad7827c41b5c33cf2fd 100644 (file)
@@ -94,6 +94,10 @@ static void hash_expand(struct hash *hash)
        struct hash_backet *hb, *hbnext, **new_index;
 
        new_size = hash->size * 2;
+
+       if (hash->max_size && new_size > hash->max_size)
+               return;
+
        new_index = XCALLOC(MTYPE_HASH_INDEX,
                            sizeof(struct hash_backet *) * new_size);
        if (new_index == NULL)
index 6ce29f0426dc6ff70afad24d8c0699b8b4988074..236abbbd6a2c573f34204dfa365343091c476f29 100644 (file)
@@ -64,6 +64,9 @@ struct hash {
        /* Hash table size. Must be power of 2 */
        unsigned int size;
 
+       /* If max_size is 0 there is no limit */
+       unsigned int max_size;
+
        /* Key make function. */
        unsigned int (*hash_key)(void *);