]> git.puffer.fish Git - matthieu/frr.git/commitdiff
pimd: Convert the upstream_list and hash to a rb tree
authorDonald Sharp <sharpd@cumulusnetworks.com>
Sat, 21 Dec 2019 04:00:31 +0000 (23:00 -0500)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 3 Jan 2020 13:39:55 +0000 (08:39 -0500)
Convert the upstream_list and hash to a rb tree, Significant
time was being spent in the listnode_add_sort.  This reduces
this time greatly.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
pimd/pim_cmd.c
pimd/pim_instance.h
pimd/pim_msdp.c
pimd/pim_nht.c
pimd/pim_oil.c
pimd/pim_rp.c
pimd/pim_upstream.c
pimd/pim_upstream.h

index 4f5ad89f8f7c216c0a325e724ddbbcb9515dbf0f..01bebebd290215e991f06fe213073e9d55c75c67 100644 (file)
@@ -914,7 +914,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
        struct in_addr ifaddr;
        struct interface *ifp;
        struct listnode *neighnode;
-       struct listnode *upnode;
        struct pim_interface *pim_ifp;
        struct pim_neighbor *neigh;
        struct pim_upstream *up;
@@ -1052,8 +1051,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
                                            pim_ifp->pim_dr_election_changes);
 
                        // FHR
-                       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
-                                                 up)) {
+                       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                                if (ifp != up->rpf.source_nexthop.interface)
                                        continue;
 
@@ -1215,8 +1213,7 @@ static void pim_show_interfaces_single(struct pim_instance *pim,
 
                        // FHR
                        print_header = 1;
-                       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
-                                                 up)) {
+                       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                                if (!up->rpf.source_nexthop.interface)
                                        continue;
 
@@ -1386,7 +1383,6 @@ static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty,
                                bool uj)
 {
        struct interface *ifp;
-       struct listnode *upnode;
        struct pim_interface *pim_ifp;
        struct pim_upstream *up;
        int fhr = 0;
@@ -1408,7 +1404,7 @@ static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty,
                pim_ifchannels = pim_if_ifchannel_count(pim_ifp);
                fhr = 0;
 
-               for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up))
+               frr_each (rb_pim_upstream, &pim->upstream_head, up)
                        if (ifp == up->rpf.source_nexthop.interface)
                                if (up->flags & PIM_UPSTREAM_FLAG_MASK_FHR)
                                        fhr++;
@@ -2428,7 +2424,6 @@ static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
 static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                              struct prefix_sg *sg, bool uj)
 {
-       struct listnode *upnode;
        struct pim_upstream *up;
        time_t now;
        json_object *json = NULL;
@@ -2443,7 +2438,7 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                vty_out(vty,
                        "Iif             Source          Group           State       Uptime   JoinTimer RSTimer   KATimer   RefCnt\n");
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                char src_str[INET_ADDRSTRLEN];
                char grp_str[INET_ADDRSTRLEN];
                char uptime[10];
@@ -2715,7 +2710,6 @@ static void pim_show_join_desired_helper(struct pim_instance *pim,
 static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty,
                                  bool uj)
 {
-       struct listnode *upnode;
        struct pim_upstream *up;
 
        json_object *json = NULL;
@@ -2726,7 +2720,7 @@ static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty,
                vty_out(vty,
                        "Source          Group           EvalJD\n");
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                /* scan all interfaces */
                pim_show_join_desired_helper(pim, vty, up,
                                json, uj);
@@ -2742,7 +2736,6 @@ static void pim_show_join_desired(struct pim_instance *pim, struct vty *vty,
 static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty,
                                  bool uj)
 {
-       struct listnode *upnode;
        struct pim_upstream *up;
        json_object *json = NULL;
        json_object *json_group = NULL;
@@ -2754,7 +2747,7 @@ static void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty,
                vty_out(vty,
                        "Source          Group           RpfIface         RibNextHop      RpfAddress     \n");
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                char src_str[INET_ADDRSTRLEN];
                char grp_str[INET_ADDRSTRLEN];
                char rpf_nexthop_str[PREFIX_STRLEN];
@@ -2875,7 +2868,6 @@ static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
 
 static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
 {
-       struct listnode *up_node;
        struct pim_upstream *up;
        time_t now = pim_time_monotonic_sec();
        json_object *json = NULL;
@@ -2892,7 +2884,7 @@ static void pim_show_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
                        "Source          Group           RpfIface         RpfAddress      RibNextHop      Metric Pref\n");
        }
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                char src_str[INET_ADDRSTRLEN];
                char grp_str[INET_ADDRSTRLEN];
                char rpf_addr_str[PREFIX_STRLEN];
@@ -3932,11 +3924,8 @@ static void clear_mroute(struct pim_instance *pim)
        }
 
        /* clean up all upstreams*/
-       if (pim->upstream_list) {
-               while (pim->upstream_list->count) {
-                       up = listnode_head(pim->upstream_list);
-                       pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
-               }
+       while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
+               pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
        }
 }
 
index 5a95043df9f116a41435e6e668f2c69c3c3cde4a..da0c75decb6c8b07b602207b7a42c5b782a6e76b 100644 (file)
@@ -29,6 +29,7 @@
 #include "pim_bsm.h"
 #include "pim_vxlan_instance.h"
 #include "pim_oil.h"
+#include "pim_upstream.h"
 
 #if defined(HAVE_LINUX_MROUTE_H)
 #include <linux/mroute.h>
@@ -108,8 +109,7 @@ struct pim_instance {
        struct list *static_routes;
 
        // Upstream vrf specific information
-       struct list *upstream_list;
-       struct hash *upstream_hash;
+       struct rb_pim_upstream_head upstream_head;
        struct timer_wheel *upstream_sg_wheel;
 
        /*
index 8a18594fd72969fa968a332edff8f685f406326e..58ebc6ce67d716d56f31a9259504894029e56ab7 100644 (file)
@@ -565,11 +565,9 @@ void pim_msdp_sa_local_update(struct pim_upstream *up)
 static void pim_msdp_sa_local_setup(struct pim_instance *pim)
 {
        struct pim_upstream *up;
-       struct listnode *up_node;
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, up_node, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up)
                pim_msdp_sa_local_update(up);
-       }
 }
 
 /* whenever the RP changes we need to re-evaluate the "local" SA-cache */
index bd8424b3e4047e9a506c23f3f98cef630b30e4fa..5cb9492ec36ae2c8e68162bad175f16ef3237ab0 100644 (file)
@@ -177,7 +177,6 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
        struct pim_nexthop_cache *pnc = NULL;
        struct pim_nexthop_cache lookup;
        struct zclient *zclient = NULL;
-       struct listnode *upnode = NULL;
        struct pim_upstream *upstream = NULL;
 
        zclient = pim_zebra_zclient_get();
@@ -190,8 +189,8 @@ void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr,
                        /* Release the (*, G)upstream from pnc->upstream_hash,
                         * whose Group belongs to the RP getting deleted
                         */
-                       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
-                               upstream)) {
+                       frr_each (rb_pim_upstream, &pim->upstream_head,
+                                 upstream) {
                                struct prefix grp;
                                struct rp_info *trp_info;
 
index 5af3328a1aaddfd4f9e48eb5400dde0e9b9631bb..598988f88f7704f9a8ee8cbe4f46db09903154d7 100644 (file)
@@ -86,26 +86,6 @@ int pim_channel_oil_compare(const struct channel_oil *c1,
        return 0;
 }
 
-static bool pim_oil_equal(const void *arg1, const void *arg2)
-{
-       const struct channel_oil *c1 = (const struct channel_oil *)arg1;
-       const struct channel_oil *c2 = (const struct channel_oil *)arg2;
-
-       if ((c1->oil.mfcc_mcastgrp.s_addr == c2->oil.mfcc_mcastgrp.s_addr)
-           && (c1->oil.mfcc_origin.s_addr == c2->oil.mfcc_origin.s_addr))
-               return true;
-
-       return false;
-}
-
-static unsigned int pim_oil_hash_key(const void *arg)
-{
-       const struct channel_oil *oil = arg;
-
-       return jhash_2words(oil->oil.mfcc_mcastgrp.s_addr,
-                           oil->oil.mfcc_origin.s_addr, 0);
-}
-
 void pim_oil_init(struct pim_instance *pim)
 {
        rb_pim_oil_init(&pim->channel_oil_head);
index bd295b0fef9a968224145e638f34d5aa4730dd50..2db39bac4bba1a0a362f57855a4f82f4b23557d8 100644 (file)
@@ -446,7 +446,6 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
        struct prefix nht_p;
        struct route_node *rn;
        struct pim_upstream *up;
-       struct listnode *upnode;
 
        if (rp_addr.s_addr == INADDR_ANY ||
            rp_addr.s_addr == INADDR_NONE)
@@ -554,8 +553,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
                                        __PRETTY_FUNCTION__, buf, buf1);
                        }
 
-                       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode,
-                                                 up)) {
+                       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                                /* Find (*, G) upstream whose RP is not
                                 * configured yet
                                 */
@@ -650,7 +648,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr,
                           rn->lock);
        }
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                if (up->sg.src.s_addr == INADDR_ANY) {
                        struct prefix grp;
                        struct rp_info *trp_info;
@@ -723,7 +721,6 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr,
        bool was_plist = false;
        struct rp_info *trp_info;
        struct pim_upstream *up;
-       struct listnode *upnode;
        struct bsgrp_node *bsgrp = NULL;
        struct bsm_rpinfo *bsrp = NULL;
        char grp_str[PREFIX2STR_BUFFER];
@@ -800,7 +797,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr,
        rp_all = pim_rp_find_match_group(pim, &g_all);
 
        if (rp_all == rp_info) {
-               for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+               frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                        /* Find the upstream (*, G) whose upstream address is
                         * same as the deleted RP
                         */
@@ -852,7 +849,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr,
 
        pim_rp_refresh_group_to_rp_mapping(pim);
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                /* Find the upstream (*, G) whose upstream address is same as
                 * the deleted RP
                 */
@@ -893,7 +890,6 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr,
        int result = 0;
        struct rp_info *rp_info = NULL;
        struct pim_upstream *up;
-       struct listnode *upnode;
 
        rn = route_node_lookup(pim->rp_table, &group);
        if (!rn) {
@@ -942,7 +938,7 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr,
 
        listnode_add_sort(pim->rp_list, rp_info);
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                if (up->sg.src.s_addr == INADDR_ANY) {
                        struct prefix grp;
                        struct rp_info *trp_info;
index a0387cdd4a9c58644e2fff5e59773ae40556bf29..afd10bd3dba6293b73b0f9873d196e2468ce37fd 100644 (file)
@@ -98,7 +98,6 @@ static void pim_upstream_find_new_children(struct pim_instance *pim,
                                           struct pim_upstream *up)
 {
        struct pim_upstream *child;
-       struct listnode *ch_node;
 
        if ((up->sg.src.s_addr != INADDR_ANY)
            && (up->sg.grp.s_addr != INADDR_ANY))
@@ -108,7 +107,7 @@ static void pim_upstream_find_new_children(struct pim_instance *pim,
            && (up->sg.grp.s_addr == INADDR_ANY))
                return;
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, ch_node, child)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, child) {
                if ((up->sg.grp.s_addr != INADDR_ANY)
                    && (child->sg.grp.s_addr == up->sg.grp.s_addr)
                    && (child != up)) {
@@ -191,9 +190,8 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
                return up;
 
        if (PIM_DEBUG_TRACE)
-               zlog_debug(
-                               "pim_upstream free vrf:%s %s flags 0x%x",
-                               pim->vrf->name, up->sg_str, up->flags);
+               zlog_debug("pim_upstream free vrf:%s %s flags 0x%x",
+                          pim->vrf->name, up->sg_str, up->flags);
 
        THREAD_OFF(up->t_ka_timer);
        THREAD_OFF(up->t_rs_timer);
@@ -235,8 +233,7 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim,
                listnode_delete(up->parent->sources, up);
        up->parent = NULL;
 
-       listnode_delete(pim->upstream_list, up);
-       hash_release(pim->upstream_hash, up);
+       rb_pim_upstream_del(&pim->upstream_head, up);
 
        if (notify_msdp) {
                pim_msdp_up_del(pim, &up->sg);
@@ -533,10 +530,9 @@ static int pim_upstream_could_register(struct pim_upstream *up)
  * we re-revaluate register setup for existing upstream entries */
 void pim_upstream_register_reevaluate(struct pim_instance *pim)
 {
-       struct listnode *upnode;
        struct pim_upstream *up;
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, upnode, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                /* If FHR is set CouldRegister is True. Also check if the flow
                 * is actually active; if it is not kat setup will trigger
                 * source
@@ -639,9 +635,8 @@ void pim_upstream_update_use_rpt(struct pim_upstream *up,
 void pim_upstream_reeval_use_rpt(struct pim_instance *pim)
 {
        struct pim_upstream *up;
-       struct listnode *node;
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                if (up->sg.src.s_addr == INADDR_ANY)
                        continue;
 
@@ -756,11 +751,9 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
        }
 }
 
-int pim_upstream_compare(void *arg1, void *arg2)
+int pim_upstream_compare(const struct pim_upstream *up1,
+                        const struct pim_upstream *up2)
 {
-       const struct pim_upstream *up1 = (const struct pim_upstream *)arg1;
-       const struct pim_upstream *up2 = (const struct pim_upstream *)arg2;
-
        if (ntohl(up1->sg.grp.s_addr) < ntohl(up2->sg.grp.s_addr))
                return -1;
 
@@ -811,7 +804,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
        if (ch)
                ch->upstream = up;
 
-       up = hash_get(pim->upstream_hash, up, hash_alloc_intern);
+       rb_pim_upstream_add(&pim->upstream_head, up);
        /* Set up->upstream_addr as INADDR_ANY, if RP is not
         * configured and retain the upstream data structure
         */
@@ -825,7 +818,8 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
        up->parent = pim_upstream_find_parent(pim, up);
        if (up->sg.src.s_addr == INADDR_ANY) {
                up->sources = list_new();
-               up->sources->cmp = pim_upstream_compare;
+               up->sources->cmp =
+                       (int (*)(void *, void *))pim_upstream_compare;
        } else
                up->sources = NULL;
 
@@ -889,8 +883,6 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim,
                }
        }
 
-       listnode_add_sort(pim->upstream_list, up);
-
        if (PIM_DEBUG_PIM_TRACE) {
                zlog_debug(
                        "%s: Created Upstream %s upstream_addr %s ref count %d increment",
@@ -908,7 +900,7 @@ struct pim_upstream *pim_upstream_find(struct pim_instance *pim,
        struct pim_upstream *up = NULL;
 
        lookup.sg = *sg;
-       up = hash_lookup(pim->upstream_hash, &lookup);
+       up = rb_pim_upstream_find(&pim->upstream_head, &lookup);
        return up;
 }
 
@@ -1168,15 +1160,12 @@ void pim_upstream_update_join_desired(struct pim_instance *pim,
 void pim_upstream_rpf_genid_changed(struct pim_instance *pim,
                                    struct in_addr neigh_addr)
 {
-       struct listnode *up_node;
-       struct listnode *up_nextnode;
        struct pim_upstream *up;
 
        /*
         * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
         */
-       for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
-
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                if (PIM_DEBUG_PIM_TRACE) {
                        char neigh_str[INET_ADDRSTRLEN];
                        char rpf_addr_str[PREFIX_STRLEN];
@@ -1788,8 +1777,6 @@ int pim_upstream_empty_inherited_olist(struct pim_upstream *up)
  */
 void pim_upstream_find_new_rpf(struct pim_instance *pim)
 {
-       struct listnode *up_node;
-       struct listnode *up_nextnode;
        struct pim_upstream *up;
        struct pim_rpf old;
        enum pim_rpf_result rpf_result;
@@ -1797,7 +1784,7 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim)
        /*
         * Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr
         */
-       for (ALL_LIST_ELEMENTS(pim->upstream_list, up_node, up_nextnode, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                if (up->upstream_addr.s_addr == INADDR_ANY) {
                        if (PIM_DEBUG_PIM_TRACE)
                                zlog_debug(
@@ -1837,18 +1824,11 @@ void pim_upstream_terminate(struct pim_instance *pim)
 {
        struct pim_upstream *up;
 
-       if (pim->upstream_list) {
-               while (pim->upstream_list->count) {
-                       up = listnode_head(pim->upstream_list);
-                       pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
-               }
-
-               list_delete(&pim->upstream_list);
+       while ((up = rb_pim_upstream_first(&pim->upstream_head))) {
+               pim_upstream_del(pim, up, __PRETTY_FUNCTION__);
        }
 
-       if (pim->upstream_hash)
-               hash_free(pim->upstream_hash);
-       pim->upstream_hash = NULL;
+       rb_pim_upstream_fini(&pim->upstream_head);
 
        if (pim->upstream_sg_wheel)
                wheel_delete(pim->upstream_sg_wheel);
@@ -1991,9 +1971,8 @@ static void pim_upstream_sg_running(void *arg)
 void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim)
 {
        struct pim_upstream *up;
-       struct listnode *node;
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                if (up->sg.src.s_addr != INADDR_ANY)
                        continue;
 
@@ -2031,7 +2010,6 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
                                         const char *nlist)
 {
        struct pim_upstream *up;
-       struct listnode *node;
        struct prefix_list *np;
        struct prefix g;
        enum prefix_list_type apply_new;
@@ -2041,7 +2019,7 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim,
        g.family = AF_INET;
        g.prefixlen = IPV4_MAX_PREFIXLEN;
 
-       for (ALL_LIST_ELEMENTS_RO(pim->upstream_list, node, up)) {
+       frr_each (rb_pim_upstream, &pim->upstream_head, up) {
                if (up->sg.src.s_addr != INADDR_ANY)
                        continue;
 
@@ -2075,11 +2053,5 @@ void pim_upstream_init(struct pim_instance *pim)
                wheel_init(router->master, 31000, 100, pim_upstream_hash_key,
                           pim_upstream_sg_running, name);
 
-       snprintf(name, 64, "PIM %s Upstream Hash",
-                pim->vrf->name);
-       pim->upstream_hash = hash_create_size(8192, pim_upstream_hash_key,
-                                             pim_upstream_equal, name);
-
-       pim->upstream_list = list_new();
-       pim->upstream_list->cmp = pim_upstream_compare;
+       rb_pim_upstream_init(&pim->upstream_head);
 }
index ab508205187c243c97d5004001b96ffaf6bf49be..1eb2052bb3380ac550f0923c479c6ab41d6029ea 100644 (file)
@@ -169,6 +169,7 @@ enum pim_upstream_sptbit {
        PIM_UPSTREAM_SPTBIT_TRUE
 };
 
+PREDECL_RBTREE_UNIQ(rb_pim_upstream);
 /*
   Upstream (S,G) channel in Joined state
   (S,G) in the "Not Joined" state is not represented
@@ -198,6 +199,7 @@ enum pim_upstream_sptbit {
 */
 struct pim_upstream {
        struct pim_instance *pim;
+       struct rb_pim_upstream_item upstream_rb;
        struct pim_upstream *parent;
        struct in_addr upstream_addr;     /* Who we are talking to */
        struct in_addr upstream_register; /*Who we received a register from*/
@@ -326,7 +328,11 @@ void pim_upstream_init(struct pim_instance *pim);
 void pim_upstream_terminate(struct pim_instance *pim);
 
 void join_timer_start(struct pim_upstream *up);
-int pim_upstream_compare(void *arg1, void *arg2);
+int pim_upstream_compare(const struct pim_upstream *up1,
+                        const struct pim_upstream *up2);
+DECLARE_RBTREE_UNIQ(rb_pim_upstream, struct pim_upstream, upstream_rb,
+                   pim_upstream_compare)
+
 void pim_upstream_register_reevaluate(struct pim_instance *pim);
 
 void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim);