]> git.proxmox.com Git - mirror_frr.git/commitdiff
pimd: Convert the channel_oil_list|hash to a rb_tree
authorDonald Sharp <sharpd@cumulusnetworks.com>
Sat, 21 Dec 2019 03:12:19 +0000 (22:12 -0500)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 3 Jan 2020 13:39:55 +0000 (08:39 -0500)
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>
pimd/pim_cmd.c
pimd/pim_instance.h
pimd/pim_oil.c
pimd/pim_oil.h
pimd/pim_zebra.c

index d165cca086b7ac9922de7a68f36ca0ff233e6ad3..4f5ad89f8f7c216c0a325e724ddbbcb9515dbf0f 100644 (file)
@@ -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++;
index dd3ac8fcb07bfcb6c1759cdf40158d93b7eba041..5a95043df9f116a41435e6e668f2c69c3c3cde4a 100644 (file)
@@ -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;
index 65c6bdd2bcfa1378f2ac500dd564e1be7f5a3ac6..5af3328a1aaddfd4f9e48eb5400dde0e9b9631bb 100644 (file)
@@ -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;
index de7fde05da03dbb5063a166047ad5ac57a65e0ae..788ddaa16c511e84a4cf8a9676cb892e44c09277 100644 (file)
@@ -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);
index 0417d0d063235cb2fe210311f0e55ed816c91f41..06507b1f4c60c0144187d609b3c03358ab6d4d73 100644 (file)
@@ -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)