summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2019-12-21 04:12:19 +0100
committerDonald Sharp <sharpd@cumulusnetworks.com>2020-01-03 14:39:55 +0100
commit7315ecdabe2e06fb75b860b65c842f0083da730e (patch)
tree44ac8ffa0df3fcdec159ac4c7e4ded03b2883f85
parentMerge pull request #5613 from srimohans/ietf (diff)
downloadfrr-7315ecdabe2e06fb75b860b65c842f0083da730e.tar.xz
frr-7315ecdabe2e06fb75b860b65c842f0083da730e.zip
pimd: Convert the channel_oil_list|hash to a rb_tree
The channel_oil_list and hash are taking significant cpu at scale when adding to the sorted list. Replace with a RB_TREE. Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
-rw-r--r--pimd/pim_cmd.c11
-rw-r--r--pimd/pim_instance.h4
-rw-r--r--pimd/pim_oil.c33
-rw-r--r--pimd/pim_oil.h9
-rw-r--r--pimd/pim_zebra.c5
5 files changed, 28 insertions, 34 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index d165cca08..4f5ad89f8 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -1975,7 +1975,6 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
const char *src_or_group, const char *group, bool uj)
{
struct channel_oil *c_oil;
- struct listnode *node;
json_object *json = NULL;
json_object *json_group = NULL;
json_object *json_ifp_in = NULL;
@@ -1994,7 +1993,7 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
"\nActive Source Group RPT IIF OIL\n");
}
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
char grp_str[INET_ADDRSTRLEN];
char src_str[INET_ADDRSTRLEN];
char in_ifname[INTERFACE_NAMSIZ + 1];
@@ -5420,7 +5419,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
now = pim_time_monotonic_sec();
/* print list of PIM and IGMP routes */
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
found_oif = 0;
first = 1;
if (!c_oil->installed && !uj)
@@ -5828,7 +5827,7 @@ DEFUN (clear_ip_mroute_count,
return CMD_WARNING;
pim = vrf->info;
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each(rb_pim_oil, &pim->channel_oil_head, c_oil) {
if (!c_oil->installed)
continue;
@@ -5863,7 +5862,7 @@ static void show_mroute_count(struct pim_instance *pim, struct vty *vty)
"Source Group LastUsed Packets Bytes WrongIf \n");
/* Print PIM and IGMP route counts */
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
@@ -5968,7 +5967,7 @@ static void show_mroute_summary(struct pim_instance *pim, struct vty *vty)
vty_out(vty, "Mroute Type Installed/Total\n");
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
if (!c_oil->installed) {
if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
starg_sw_mroute_cnt++;
diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h
index dd3ac8fcb..5a95043df 100644
--- a/pimd/pim_instance.h
+++ b/pimd/pim_instance.h
@@ -28,6 +28,7 @@
#include "pim_assert.h"
#include "pim_bsm.h"
#include "pim_vxlan_instance.h"
+#include "pim_oil.h"
#if defined(HAVE_LINUX_MROUTE_H)
#include <linux/mroute.h>
@@ -119,8 +120,7 @@ struct pim_instance {
int iface_vif_index[MAXVIFS];
- struct list *channel_oil_list;
- struct hash *channel_oil_hash;
+ struct rb_pim_oil_head channel_oil_head;
struct pim_msdp msdp;
struct pim_vxlan_instance vxlan;
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 65c6bdd2b..5af3328a1 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -64,8 +64,8 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
return buf;
}
-static int pim_channel_oil_compare(struct channel_oil *c1,
- struct channel_oil *c2)
+int pim_channel_oil_compare(const struct channel_oil *c1,
+ const struct channel_oil *c2)
{
if (ntohl(c1->oil.mfcc_mcastgrp.s_addr)
< ntohl(c2->oil.mfcc_mcastgrp.s_addr))
@@ -108,26 +108,17 @@ static unsigned int pim_oil_hash_key(const void *arg)
void pim_oil_init(struct pim_instance *pim)
{
- char hash_name[64];
-
- snprintf(hash_name, 64, "PIM %s Oil Hash", pim->vrf->name);
- pim->channel_oil_hash = hash_create_size(8192, pim_oil_hash_key,
- pim_oil_equal, hash_name);
-
- pim->channel_oil_list = list_new();
- pim->channel_oil_list->del = (void (*)(void *))pim_channel_oil_free;
- pim->channel_oil_list->cmp =
- (int (*)(void *, void *))pim_channel_oil_compare;
+ rb_pim_oil_init(&pim->channel_oil_head);
}
void pim_oil_terminate(struct pim_instance *pim)
{
- if (pim->channel_oil_list)
- list_delete(&pim->channel_oil_list);
+ struct channel_oil *c_oil;
+
+ while ((c_oil = rb_pim_oil_pop(&pim->channel_oil_head)))
+ pim_channel_oil_free(c_oil);
- if (pim->channel_oil_hash)
- hash_free(pim->channel_oil_hash);
- pim->channel_oil_hash = NULL;
+ rb_pim_oil_fini(&pim->channel_oil_head);
}
void pim_channel_oil_free(struct channel_oil *c_oil)
@@ -144,7 +135,7 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
lookup.oil.mfcc_mcastgrp = sg->grp;
lookup.oil.mfcc_origin = sg->src;
- c_oil = hash_lookup(pim->channel_oil_hash, &lookup);
+ c_oil = rb_pim_oil_find(&pim->channel_oil_head, &lookup);
return c_oil;
}
@@ -187,7 +178,6 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
c_oil->oil.mfcc_mcastgrp = sg->grp;
c_oil->oil.mfcc_origin = sg->src;
- c_oil = hash_get(pim->channel_oil_hash, c_oil, hash_alloc_intern);
c_oil->oil.mfcc_parent = MAXVIFS;
c_oil->oil_ref_count = 1;
@@ -195,7 +185,7 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
c_oil->up = pim_upstream_find(pim, sg);
c_oil->pim = pim;
- listnode_add_sort(pim->channel_oil_list, c_oil);
+ rb_pim_oil_add(&pim->channel_oil_head, c_oil);
if (PIM_DEBUG_MROUTE)
zlog_debug("%s(%s): c_oil %s add",
@@ -224,8 +214,7 @@ struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil,
* called by list_delete_all_node()
*/
c_oil->up = NULL;
- listnode_delete(c_oil->pim->channel_oil_list, c_oil);
- hash_release(c_oil->pim->channel_oil_hash, c_oil);
+ rb_pim_oil_del(&c_oil->pim->channel_oil_head, c_oil);
pim_channel_oil_free(c_oil);
return NULL;
diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h
index de7fde05d..788ddaa16 100644
--- a/pimd/pim_oil.h
+++ b/pimd/pim_oil.h
@@ -90,10 +90,13 @@ struct channel_counts {
installed: indicate if this entry is installed in the kernel.
*/
+PREDECL_RBTREE_UNIQ(rb_pim_oil)
struct channel_oil {
struct pim_instance *pim;
+ struct rb_pim_oil_item oil_rb;
+
struct mfcctl oil;
int installed;
int oil_inherited_rescan;
@@ -106,6 +109,12 @@ struct channel_oil {
time_t mroute_creation;
};
+extern int pim_channel_oil_compare(const struct channel_oil *c1,
+ const struct channel_oil *c2);
+DECLARE_RBTREE_UNIQ(rb_pim_oil, struct channel_oil, oil_rb,
+ pim_channel_oil_compare)
+
+
extern struct list *pim_channel_oil_list;
void pim_oil_init(struct pim_instance *pim);
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 0417d0d06..06507b1f4 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -392,16 +392,13 @@ static void pim_zebra_vxlan_replay(void)
void pim_scan_oil(struct pim_instance *pim)
{
- struct listnode *node;
- struct listnode *nextnode;
struct channel_oil *c_oil;
pim->scan_oil_last = pim_time_monotonic_sec();
++pim->scan_oil_events;
- for (ALL_LIST_ELEMENTS(pim->channel_oil_list, node, nextnode, c_oil)) {
+ frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil)
pim_upstream_mroute_iif_update(c_oil, __func__);
- }
}
static int on_rpf_cache_refresh(struct thread *t)