From a625e9373be06671b0b9e3cafb026dec5a0cb9b5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sun, 12 Feb 2017 20:16:08 -0500 Subject: [PATCH] pimd: Make ifchannel lookup a hash lookup When we are at scale, it is possible that we have a very large number of ifchannels per interface. So make lookup for that situation to be a hash lookup. Signed-off-by: Donald Sharp --- pimd/pim_iface.c | 10 ++++++++++ pimd/pim_iface.h | 1 + pimd/pim_ifchannel.c | 43 ++++++++++++++++++++++++++++++------------- pimd/pim_ifchannel.h | 3 +++ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index c1289a3ba7..8f7d40bb36 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -27,6 +27,7 @@ #include "vrf.h" #include "linklist.h" #include "plist.h" +#include "hash.h" #include "pimd.h" #include "pim_iface.h" @@ -86,6 +87,9 @@ static void *if_list_clean(struct pim_interface *pim_ifp) list_delete(pim_ifp->pim_ifchannel_list); } + if (pim_ifp->pim_ifchannel_hash) + hash_free (pim_ifp->pim_ifchannel_hash); + XFREE(MTYPE_PIM_INTERFACE, pim_ifp); return 0; @@ -131,6 +135,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) pim_ifp->igmp_socket_list = NULL; pim_ifp->pim_neighbor_list = NULL; pim_ifp->pim_ifchannel_list = NULL; + pim_ifp->pim_ifchannel_hash = NULL; pim_ifp->pim_generation_id = 0; /* list of struct igmp_sock */ @@ -161,6 +166,9 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free; 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); + ifp->info = pim_ifp; pim_sock_reset(ifp); @@ -197,6 +205,8 @@ void pim_if_delete(struct interface *ifp) list_delete(pim_ifp->pim_neighbor_list); list_delete(pim_ifp->pim_ifchannel_list); + hash_free (pim_ifp->pim_ifchannel_hash); + XFREE(MTYPE_PIM_INTERFACE, pim_ifp); ifp->info = NULL; diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 244de598db..7c0d57a5d1 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -98,6 +98,7 @@ struct pim_interface { uint16_t pim_override_interval_msec; /* config */ struct list *pim_neighbor_list; /* list of struct pim_neighbor */ struct list *pim_ifchannel_list; /* list of struct pim_ifchannel */ + struct hash *pim_ifchannel_hash; /* neighbors without lan_delay */ int pim_number_of_nonlandelay_neighbors; diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 6bff65c1ad..021e43a4ad 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -25,6 +25,8 @@ #include "memory.h" #include "if.h" #include "vrf.h" +#include "hash.h" +#include "jhash.h" #include "pimd.h" #include "pim_str.h" @@ -193,6 +195,7 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch) called by list_delete_all_node() */ listnode_delete(pim_ifp->pim_ifchannel_list, ch); + hash_release(pim_ifp->pim_ifchannel_hash, ch); listnode_delete(pim_ifchannel_list, ch); pim_ifchannel_free(ch); @@ -373,10 +376,8 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, struct prefix_sg *sg) { struct pim_interface *pim_ifp; - struct listnode *ch_node; struct pim_ifchannel *ch; - - zassert(ifp); + struct pim_ifchannel lookup; pim_ifp = ifp->info; @@ -385,19 +386,13 @@ struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, __PRETTY_FUNCTION__, pim_str_sg_dump (sg), ifp->name); - return 0; + return NULL; } - for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { - if ( - (sg->src.s_addr == ch->sg.src.s_addr) && - (sg->grp.s_addr == ch->sg.grp.s_addr) - ) { - return ch; - } - } + lookup.sg = *sg; + ch = hash_lookup (pim_ifp->pim_ifchannel_hash, &lookup); - return 0; + return ch; } static void ifmembership_set(struct pim_ifchannel *ch, @@ -553,6 +548,7 @@ pim_ifchannel_add(struct interface *ifp, /* Attach to list */ listnode_add_sort(pim_ifp->pim_ifchannel_list, ch); + ch = hash_get (pim_ifp->pim_ifchannel_hash, ch, hash_alloc_intern); listnode_add_sort(pim_ifchannel_list, ch); return ch; @@ -1228,3 +1224,24 @@ pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom) } } } + +unsigned int +pim_ifchannel_hash_key (void *arg) +{ + struct pim_ifchannel *ch = (struct pim_ifchannel *)arg; + + return jhash_2words (ch->sg.src.s_addr, ch->sg.grp.s_addr, 0); +} + +int +pim_ifchannel_equal (const void *arg1, const void *arg2) +{ + const struct pim_ifchannel *ch1 = (const struct pim_ifchannel *)arg1; + const struct pim_ifchannel *ch2 = (const struct pim_ifchannel *)arg2; + + if ((ch1->sg.grp.s_addr == ch2->sg.grp.s_addr) && + (ch1->sg.src.s_addr == ch2->sg.src.s_addr)) + return 1; + + return 0; +} diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index 5cac0318c6..c7084034a0 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -154,4 +154,7 @@ void pim_ifchannel_scan_forward_start (struct interface *new_ifp); void pim_ifchannel_set_star_g_join_state (struct pim_ifchannel *ch, int eom); int pim_ifchannel_compare (struct pim_ifchannel *ch1, struct pim_ifchannel *ch2); + +unsigned int pim_ifchannel_hash_key (void *arg); +int pim_ifchannel_equal (const void *arg1, const void *arg2); #endif /* PIM_IFCHANNEL_H */