From dd793e4a9c15a9e70bf04560a262b25aeabedc74 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Fri, 23 Oct 2015 17:34:50 +0000 Subject: [PATCH] Use a hash to store BGP peer structures Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-5370 --- bgpd/bgp_network.c | 4 +++ bgpd/bgp_snmp.c | 4 ++- bgpd/bgpd.c | 61 +++++++++++++++++++++++++++++++++++++--------- bgpd/bgpd.h | 1 + lib/sockunion.c | 6 +++++ lib/sockunion.h | 1 + 6 files changed, 64 insertions(+), 13 deletions(-) diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 592c8416b6..bdb8e4c065 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -229,6 +229,8 @@ bgp_accept (struct thread *thread) struct peer *peer1; char buf[SU_ADDRSTRLEN]; + sockunion_init (&su); + /* Register accept thread. */ accept_sock = THREAD_FD (thread); if (accept_sock < 0) @@ -444,6 +446,8 @@ bgp_update_source (struct peer *peer) union sockunion addr; int ret = 0; + sockunion_init (&addr); + /* Source is specified with interface name. */ if (peer->update_if) { diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 0d1aa4df84..5de2bc4205 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -311,7 +311,7 @@ bgp_peer_lookup_next (struct in_addr *src) union sockunion su; int ret; - memset (&su, 0, sizeof (union sockunion)); + sockunion_init (&su); bgp = bgp_get_default (); if (! bgp) @@ -621,6 +621,8 @@ bgp4PathAttrLookup (struct variable *v, oid name[], size_t *length, unsigned int len; struct in_addr paddr; + sockunion_init (&su); + #define BGP_PATHATTR_ENTRY_OFFSET \ (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 3711c8fbd1..ef0ba846a0 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -39,6 +39,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "queue.h" #include "zclient.h" #include "bfd.h" +#include "hash.h" +#include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -698,6 +700,22 @@ peer_cmp (struct peer *p1, struct peer *p2) return sockunion_cmp (&p1->su, &p2->su); } +static unsigned int +peer_hash_key_make(void *p) +{ + struct peer *peer = p; + return sockunion_hash(&peer->su); +} + +static int +peer_hash_cmp (const void *p1, const void *p2) +{ + const struct peer *peer1 = p1; + const struct peer *peer2 = p2; + return (sockunion_same (&peer1->su, &peer2->su) && + CHECK_FLAG (peer1->flags, PEER_FLAG_CONFIG_NODE) == CHECK_FLAG (peer2->flags, PEER_FLAG_CONFIG_NODE)); +} + int peer_af_flag_check (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) { @@ -1309,6 +1327,10 @@ bgp_peer_conf_if_to_su_update (struct peer *peer) peer->su.sa.sa_family = AF_UNSPEC; memset(&peer->su.sin6.sin6_addr, 0, sizeof (struct in6_addr)); } + + /* Since our su changed we need to del/add peer to the peerhash */ + hash_release(peer->bgp->peerhash, peer); + hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); } /* Create new BGP peer. */ @@ -1350,6 +1372,7 @@ peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp, peer = peer_lock (peer); /* bgp peer list reference */ listnode_add_sort (bgp->peer, peer); + hash_get(bgp->peerhash, peer, hash_alloc_intern); active = peer_active (peer); @@ -1417,7 +1440,7 @@ peer_conf_interface_get(struct bgp *bgp, const char *conf_if, afi_t afi, return peer; } -/* Make accept BGP peer. Called from bgp_accept (). */ +/* Make accept BGP peer. This function is only called from the test code */ struct peer * peer_create_accept (struct bgp *bgp) { @@ -1824,6 +1847,7 @@ peer_delete (struct peer *peer) { peer_unlock (peer); /* bgp peer list reference */ list_delete_node (bgp->peer, pn); + hash_release(bgp->peerhash, peer); } if (peer_rsclient_active (peer) @@ -2733,6 +2757,7 @@ bgp_create (as_t *as, const char *name) 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->group = list_new (); bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; @@ -2996,6 +3021,8 @@ bgp_free (struct bgp *bgp) list_delete (bgp->group); list_delete (bgp->peer); list_delete (bgp->rsclient); + hash_free(bgp->peerhash); + bgp->peerhash = NULL; if (bgp->name) XFREE(MTYPE_BGP, bgp->name); @@ -3074,27 +3101,37 @@ peer_lookup_by_hostname (struct bgp *bgp, const char *hostname) struct peer * peer_lookup (struct bgp *bgp, union sockunion *su) { - struct peer *peer; - struct listnode *node, *nnode; + struct peer *peer = NULL; + struct peer tmp_peer; + + memset(&tmp_peer, 0, sizeof(struct peer)); + + /* + * We do not want to find the doppelganger peer so search for the peer in + * the hash that has PEER_FLAG_CONFIG_NODE + */ + SET_FLAG (tmp_peer.flags, PEER_FLAG_CONFIG_NODE); + + tmp_peer.su = *su; if (bgp != NULL) { - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) - if (sockunion_same (&peer->su, su) - && (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE))) - return peer; + peer = hash_lookup(bgp->peerhash, &tmp_peer); } else if (bm->bgp != NULL) { struct listnode *bgpnode, *nbgpnode; for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp)) - for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) - if (sockunion_same (&peer->su, su) - && (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE))) - return peer; + { + peer = hash_lookup(bgp->peerhash, &tmp_peer); + + if (peer) + break; + } } - return NULL; + + return peer; } struct peer * diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 22c4d20306..05dfecb4da 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -145,6 +145,7 @@ struct bgp /* BGP peer. */ struct list *peer; + struct hash *peerhash; /* BGP peer group. */ struct list *group; diff --git a/lib/sockunion.c b/lib/sockunion.c index b404cb78f4..968b126ee2 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -808,3 +808,9 @@ sockunion_free (union sockunion *su) { XFREE (MTYPE_SOCKUNION, su); } + +void +sockunion_init (union sockunion *su) +{ + memset(su, 0, sizeof(union sockunion)); +} diff --git a/lib/sockunion.h b/lib/sockunion.h index e66b0b8e83..195c2fff92 100644 --- a/lib/sockunion.h +++ b/lib/sockunion.h @@ -112,6 +112,7 @@ extern union sockunion *sockunion_getsockname (int); extern union sockunion *sockunion_getpeername (int); extern union sockunion *sockunion_dup (union sockunion *); extern void sockunion_free (union sockunion *); +extern void sockunion_init (union sockunion *); #ifndef HAVE_INET_NTOP extern const char * inet_ntop (int family, const void *addrptr, -- 2.39.5