]> git.puffer.fish Git - mirror/frr.git/commitdiff
ldpd: use red-black trees to store 'tnbr' elements
authorRenato Westphal <renato@opensourcerouting.org>
Tue, 13 Dec 2016 18:19:15 +0000 (16:19 -0200)
committerRenato Westphal <renato@opensourcerouting.org>
Wed, 15 Feb 2017 09:19:52 +0000 (07:19 -0200)
Using red-black trees instead of linked lists brings the following
benefits:
1 - Elements are naturally ordered (no need to reorder anything before
    outputting data to the user);
2 - Faster lookups/deletes: O(log n) time complexity against O(n).

The insert operation with red-black trees is more expensive though,
but that's not a big issue since lookups are much more frequent.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
ldpd/adjacency.c
ldpd/hello.c
ldpd/l2vpn.c
ldpd/lde.c
ldpd/ldp_vty_conf.c
ldpd/ldpd.c
ldpd/ldpd.h
ldpd/ldpe.c
ldpd/ldpe.h

index 3607ee96b3a29d093006b53cf84e417d6bd70ca6..f01f7a12fa91cbfcf2486da22f00b5680ceb3eb5 100644 (file)
 #include "log.h"
 
 static int      adj_itimer(struct thread *);
-static void     tnbr_del(struct tnbr *);
+static __inline int tnbr_compare(struct tnbr *, struct tnbr *);
+static void     tnbr_del(struct ldpd_conf *, struct tnbr *);
 static int      tnbr_hello_timer(struct thread *);
 static void     tnbr_start_hello_timer(struct tnbr *);
 static void     tnbr_stop_hello_timer(struct tnbr *);
 
+RB_GENERATE(tnbr_head, tnbr, entry, tnbr_compare)
+
 struct adj *
 adj_new(struct in_addr lsr_id, struct hello_source *source,
     union ldpd_addr *addr)
@@ -161,7 +164,7 @@ adj_itimer(struct thread *thread)
                if (!(adj->source.target->flags & F_TNBR_CONFIGURED) &&
                    adj->source.target->pw_count == 0) {
                        /* remove dynamic targeted neighbor */
-                       tnbr_del(adj->source.target);
+                       tnbr_del(leconf, adj->source.target);
                        return (0);
                }
                adj->source.target->adj = NULL;
@@ -188,6 +191,17 @@ adj_stop_itimer(struct adj *adj)
 
 /* targeted neighbors */
 
+static __inline int
+tnbr_compare(struct tnbr *a, struct tnbr *b)
+{
+       if (a->af < b->af)
+               return (-1);
+       if (a->af > b->af)
+               return (1);
+
+       return (ldp_addrcmp(a->af, &a->addr, &b->addr));
+}
+
 struct tnbr *
 tnbr_new(int af, union ldpd_addr *addr)
 {
@@ -204,34 +218,30 @@ tnbr_new(int af, union ldpd_addr *addr)
 }
 
 static void
-tnbr_del(struct tnbr *tnbr)
+tnbr_del(struct ldpd_conf *xconf, struct tnbr *tnbr)
 {
        tnbr_stop_hello_timer(tnbr);
        if (tnbr->adj)
                adj_del(tnbr->adj, S_SHUTDOWN);
-       LIST_REMOVE(tnbr, entry);
+       RB_REMOVE(tnbr_head, &xconf->tnbr_tree, tnbr);
        free(tnbr);
 }
 
 struct tnbr *
 tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
 {
-       struct tnbr *tnbr;
-
-       LIST_FOREACH(tnbr, &xconf->tnbr_list, entry)
-               if (af == tnbr->af &&
-                   ldp_addrcmp(af, addr, &tnbr->addr) == 0)
-                       return (tnbr);
-
-       return (NULL);
+       struct tnbr      tnbr;
+       tnbr.af = af;
+       tnbr.addr = *addr;
+       return (RB_FIND(tnbr_head, &xconf->tnbr_tree, &tnbr));
 }
 
 struct tnbr *
-tnbr_check(struct tnbr *tnbr)
+tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr)
 {
        if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) &&
            tnbr->pw_count == 0) {
-               tnbr_del(tnbr);
+               tnbr_del(xconf, tnbr);
                return (NULL);
        }
 
@@ -276,7 +286,7 @@ tnbr_update_all(int af)
        struct tnbr             *tnbr;
 
        /* update targeted neighbors */
-       LIST_FOREACH(tnbr, &leconf->tnbr_list, entry)
+       RB_FOREACH(tnbr, tnbr_head, &leconf->tnbr_tree)
                if (tnbr->af == af || af == AF_UNSPEC)
                        tnbr_update(tnbr);
 }
index 755b25aa85e639944fe13a005bd258304f998d42..0833ebbafb30e4b00681ac505b98677803b791b5 100644 (file)
@@ -261,7 +261,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                if (tnbr && (tnbr->flags & F_TNBR_DYNAMIC) &&
                    !((flags & F_HELLO_REQ_TARG))) {
                        tnbr->flags &= ~F_TNBR_DYNAMIC;
-                       tnbr = tnbr_check(tnbr);
+                       tnbr = tnbr_check(leconf, tnbr);
                }
 
                if (!tnbr) {
@@ -273,7 +273,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
                        tnbr = tnbr_new(af, src);
                        tnbr->flags |= F_TNBR_DYNAMIC;
                        tnbr_update(tnbr);
-                       LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
+                       RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
                }
 
                source.type = HELLO_TARGETED;
index 3159d47dd8d0aff8b940d110b9898a67b3708acc..b8c1728f6361e16623948288e2ab6e660e70f65d 100644 (file)
@@ -530,7 +530,7 @@ ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
        if (tnbr == NULL) {
                tnbr = tnbr_new(pw->af, &pw->addr);
                tnbr_update(tnbr);
-               LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
+               RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
        }
 
        tnbr->pw_count++;
@@ -544,6 +544,6 @@ ldpe_l2vpn_pw_exit(struct l2vpn_pw *pw)
        tnbr = tnbr_find(leconf, pw->af, &pw->addr);
        if (tnbr) {
                tnbr->pw_count--;
-               tnbr_check(tnbr);
+               tnbr_check(leconf, tnbr);
        }
 }
index 29e0fac3277fbc1a1457799a5a27156635a04aae..8b1632f33424a1b381afa63922f47680dd775c03 100644 (file)
@@ -473,7 +473,7 @@ lde_dispatch_parent(struct thread *thread)
                        memcpy(nconf, imsg.data, sizeof(struct ldpd_conf));
 
                        RB_INIT(&nconf->iface_tree);
-                       LIST_INIT(&nconf->tnbr_list);
+                       RB_INIT(&nconf->tnbr_tree);
                        LIST_INIT(&nconf->nbrp_list);
                        LIST_INIT(&nconf->l2vpn_list);
                        break;
@@ -495,7 +495,7 @@ lde_dispatch_parent(struct thread *thread)
                                fatal(NULL);
                        memcpy(ntnbr, imsg.data, sizeof(struct tnbr));
 
-                       LIST_INSERT_HEAD(&nconf->tnbr_list, ntnbr, entry);
+                       RB_INSERT(tnbr_head, &nconf->tnbr_tree, ntnbr);
                        break;
                case IMSG_RECONF_NBRP:
                        if ((nnbrp = malloc(sizeof(struct nbr_params))) == NULL)
index e94de950d80f031c7f5516e1c8d5c6cfe9378de2..4283ee93cce0d2a080795fbb4b77069ca14eb319 100644 (file)
@@ -213,7 +213,7 @@ ldp_af_config_write(struct vty *vty, int af, struct ldpd_conf *conf,
                vty_out(vty, "  session holdtime %u%s", af_conf->keepalive,
                    VTY_NEWLINE);
 
-       LIST_FOREACH(tnbr, &ldpd_conf->tnbr_list, entry) {
+       RB_FOREACH(tnbr, tnbr_head, &ldpd_conf->tnbr_tree) {
                if (tnbr->af == af) {
                        vty_out(vty, "  !%s", VTY_NEWLINE);
                        vty_out(vty, "  neighbor %s targeted%s",
@@ -955,7 +955,7 @@ ldp_vty_neighbor_targeted(struct vty *vty, struct vty_arg *args[])
                if (tnbr == NULL)
                        goto cancel;
 
-               LIST_REMOVE(tnbr, entry);
+               RB_REMOVE(tnbr_head, &vty_conf->tnbr_tree, tnbr);
                free(tnbr);
                ldp_reload(vty_conf);
                return (CMD_SUCCESS);
@@ -966,7 +966,7 @@ ldp_vty_neighbor_targeted(struct vty *vty, struct vty_arg *args[])
 
        tnbr = tnbr_new(af, &addr);
        tnbr->flags |= F_TNBR_CONFIGURED;
-       LIST_INSERT_HEAD(&vty_conf->tnbr_list, tnbr, entry);
+       RB_INSERT(tnbr_head, &vty_conf->tnbr_tree, tnbr);
 
        ldp_reload(vty_conf);
 
@@ -1672,14 +1672,14 @@ tnbr_new_api(struct ldpd_conf *conf, int af, union ldpd_addr *addr)
 
        tnbr = tnbr_new(af, addr);
        tnbr->flags |= F_TNBR_CONFIGURED;
-       LIST_INSERT_HEAD(&conf->tnbr_list, tnbr, entry);
+       RB_INSERT(tnbr_head, &conf->tnbr_tree, tnbr);
        return (tnbr);
 }
 
 void
-tnbr_del_api(struct tnbr *tnbr)
+tnbr_del_api(struct ldpd_conf *conf, struct tnbr *tnbr)
 {
-       LIST_REMOVE(tnbr, entry);
+       RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
        free(tnbr);
 }
 
index 21456b4d1ed5f84e6d0ec5ef276ea4aded71ea04..63cdfe6884f566e283b9e93fd0b3fbb4433a0c33 100644 (file)
@@ -897,7 +897,7 @@ main_imsg_send_config(struct ldpd_conf *xconf)
                        return (-1);
        }
 
-       LIST_FOREACH(tnbr, &xconf->tnbr_list, entry) {
+       RB_FOREACH(tnbr, tnbr_head, &xconf->tnbr_tree) {
                if (main_imsg_compose_both(IMSG_RECONF_TNBR, tnbr,
                    sizeof(*tnbr)) == -1)
                        return (-1);
@@ -1033,13 +1033,13 @@ ldp_config_reset_af(struct ldpd_conf *conf, int af, void **ref)
                ia->enabled = 0;
        }
 
-       LIST_FOREACH_SAFE(tnbr, &conf->tnbr_list, entry, ttmp) {
+       RB_FOREACH_SAFE(tnbr, tnbr_head, &conf->tnbr_tree, ttmp) {
                if (tnbr->af != af)
                        continue;
 
                if (ref && *ref == tnbr)
                        *ref = NULL;
-               LIST_REMOVE(tnbr, entry);
+               RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
                free(tnbr);
        }
 
@@ -1074,7 +1074,7 @@ ldp_dup_config_ref(struct ldpd_conf *conf, void **ref)
 
        COPY(xconf, conf);
        RB_INIT(&xconf->iface_tree);
-       LIST_INIT(&xconf->tnbr_list);
+       RB_INIT(&xconf->tnbr_tree);
        LIST_INIT(&xconf->nbrp_list);
        LIST_INIT(&xconf->l2vpn_list);
 
@@ -1084,9 +1084,9 @@ ldp_dup_config_ref(struct ldpd_conf *conf, void **ref)
                xi->ipv6.iface = xi;
                RB_INSERT(iface_head, &xconf->iface_tree, xi);
        }
-       LIST_FOREACH(tnbr, &conf->tnbr_list, entry) {
+       RB_FOREACH(tnbr, tnbr_head, &conf->tnbr_tree) {
                COPY(xt, tnbr);
-               LIST_INSERT_HEAD(&xconf->tnbr_list, xt, entry);
+               RB_INSERT(tnbr_head, &xconf->tnbr_tree, xt);
        }
        LIST_FOREACH(nbrp, &conf->nbrp_list, entry) {
                COPY(xn, nbrp);
@@ -1138,8 +1138,8 @@ ldp_clear_config(struct ldpd_conf *xconf)
                RB_REMOVE(iface_head, &xconf->iface_tree, iface);
                free(iface);
        }
-       while ((tnbr = LIST_FIRST(&xconf->tnbr_list)) != NULL) {
-               LIST_REMOVE(tnbr, entry);
+       while ((tnbr = RB_ROOT(&xconf->tnbr_tree)) != NULL) {
+               RB_REMOVE(tnbr_head, &xconf->tnbr_tree, tnbr);
                free(tnbr);
        }
        while ((nbrp = LIST_FIRST(&xconf->nbrp_list)) != NULL) {
@@ -1336,7 +1336,7 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
 {
        struct tnbr             *tnbr, *ttmp, *xt;
 
-       LIST_FOREACH_SAFE(tnbr, &conf->tnbr_list, entry, ttmp) {
+       RB_FOREACH_SAFE(tnbr, tnbr_head, &conf->tnbr_tree, ttmp) {
                if (!(tnbr->flags & F_TNBR_CONFIGURED))
                        continue;
 
@@ -1344,26 +1344,26 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                if ((xt = tnbr_find(xconf, tnbr->af, &tnbr->addr)) == NULL) {
                        switch (ldpd_process) {
                        case PROC_LDE_ENGINE:
-                               LIST_REMOVE(tnbr, entry);
+                               RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
                                free(tnbr);
                                break;
                        case PROC_LDP_ENGINE:
                                tnbr->flags &= ~F_TNBR_CONFIGURED;
-                               tnbr_check(tnbr);
+                               tnbr_check(conf, tnbr);
                                break;
                        case PROC_MAIN:
-                               LIST_REMOVE(tnbr, entry);
+                               RB_REMOVE(tnbr_head, &conf->tnbr_tree, tnbr);
                                QOBJ_UNREG (tnbr);
                                free(tnbr);
                                break;
                        }
                }
        }
-       LIST_FOREACH_SAFE(xt, &xconf->tnbr_list, entry, ttmp) {
+       RB_FOREACH_SAFE(xt, tnbr_head, &xconf->tnbr_tree, ttmp) {
                /* find new tnbrs */
                if ((tnbr = tnbr_find(conf, xt->af, &xt->addr)) == NULL) {
-                       LIST_REMOVE(xt, entry);
-                       LIST_INSERT_HEAD(&conf->tnbr_list, xt, entry);
+                       RB_REMOVE(tnbr_head, &xconf->tnbr_tree, xt);
+                       RB_INSERT(tnbr_head, &conf->tnbr_tree, xt);
 
                        switch (ldpd_process) {
                        case PROC_LDE_ENGINE:
@@ -1381,7 +1381,7 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
                /* update existing tnbrs */
                if (!(tnbr->flags & F_TNBR_CONFIGURED))
                        tnbr->flags |= F_TNBR_CONFIGURED;
-               LIST_REMOVE(xt, entry);
+               RB_REMOVE(tnbr_head, &xconf->tnbr_tree, xt);
                if (ref && *ref == xt)
                        *ref = tnbr;
                free(xt);
@@ -1812,7 +1812,7 @@ config_new_empty(void)
                fatal(NULL);
 
        RB_INIT(&xconf->iface_tree);
-       LIST_INIT(&xconf->tnbr_list);
+       RB_INIT(&xconf->tnbr_tree);
        LIST_INIT(&xconf->nbrp_list);
        LIST_INIT(&xconf->l2vpn_list);
 
index 3e046447f2fc65a22a7534a6fed1c3cfa0f044bd..55c61b6ef58fae625dfb0edbfa67ed93bfbaa873 100644 (file)
@@ -281,7 +281,7 @@ DECLARE_QOBJ_TYPE(iface)
 
 /* source of targeted hellos */
 struct tnbr {
-       LIST_ENTRY(tnbr)         entry;
+       RB_ENTRY(tnbr)           entry;
        struct thread           *hello_timer;
        struct adj              *adj;
        int                      af;
@@ -291,6 +291,8 @@ struct tnbr {
        uint8_t                  flags;
        QOBJ_FIELDS
 };
+RB_HEAD(tnbr_head, tnbr);
+RB_PROTOTYPE(tnbr_head, tnbr, entry, tnbr_compare);
 DECLARE_QOBJ_TYPE(tnbr)
 #define F_TNBR_CONFIGURED       0x01
 #define F_TNBR_DYNAMIC          0x02
@@ -407,7 +409,7 @@ struct ldpd_conf {
        struct ldpd_af_conf      ipv4;
        struct ldpd_af_conf      ipv6;
        struct iface_head        iface_tree;
-       LIST_HEAD(, tnbr)        tnbr_list;
+       struct tnbr_head         tnbr_tree;
        LIST_HEAD(, nbr_params)  nbrp_list;
        LIST_HEAD(, l2vpn)       l2vpn_list;
        uint16_t                 lhello_holdtime;
@@ -633,9 +635,9 @@ struct iface                *iface_new_api(struct ldpd_conf *conf,
                            const char *name);
 void                    iface_del_api(struct ldpd_conf *conf,
                            struct iface *iface);
-struct tnbr            *tnbr_new_api(struct ldpd_conf *cfg, int af,
+struct tnbr            *tnbr_new_api(struct ldpd_conf *conf, int af,
                            union ldpd_addr *addr);
-void                    tnbr_del_api(struct tnbr *tnbr);
+void                    tnbr_del_api(struct ldpd_conf *conf, struct tnbr *tnbr);
 struct nbr_params      *nbrp_new_api(struct ldpd_conf *cfg,
                            struct in_addr lsr_id);
 void                    nbrp_del_api(struct nbr_params *nbrp);
index 284d4cb35a33699345bac46a2b3304e3e8482bfb..159f584715b6613375cbb022907d4a53bac9a976 100644 (file)
@@ -416,7 +416,7 @@ ldpe_dispatch_main(struct thread *thread)
                        memcpy(nconf, imsg.data, sizeof(struct ldpd_conf));
 
                        RB_INIT(&nconf->iface_tree);
-                       LIST_INIT(&nconf->tnbr_list);
+                       RB_INIT(&nconf->tnbr_tree);
                        LIST_INIT(&nconf->nbrp_list);
                        LIST_INIT(&nconf->l2vpn_list);
                        break;
@@ -438,7 +438,7 @@ ldpe_dispatch_main(struct thread *thread)
                                fatal(NULL);
                        memcpy(ntnbr, imsg.data, sizeof(struct tnbr));
 
-                       LIST_INSERT_HEAD(&nconf->tnbr_list, ntnbr, entry);
+                       RB_INSERT(tnbr_head, &nconf->tnbr_tree, ntnbr);
                        break;
                case IMSG_RECONF_NBRP:
                        if ((nnbrp = malloc(sizeof(struct nbr_params))) == NULL)
@@ -744,12 +744,12 @@ ldpe_remove_dynamic_tnbrs(int af)
 {
        struct tnbr             *tnbr, *safe;
 
-       LIST_FOREACH_SAFE(tnbr, &leconf->tnbr_list, entry, safe) {
+       RB_FOREACH_SAFE(tnbr, tnbr_head, &leconf->tnbr_tree, safe) {
                if (tnbr->af != af)
                        continue;
 
                tnbr->flags &= ~F_TNBR_DYNAMIC;
-               tnbr_check(tnbr);
+               tnbr_check(leconf, tnbr);
        }
 }
 
@@ -833,7 +833,7 @@ ldpe_adj_ctl(struct ctl_conn *c)
                }
        }
 
-       LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) {
+       RB_FOREACH(tnbr, tnbr_head, &leconf->tnbr_tree) {
                memset(&tctl, 0, sizeof(tctl));
                tctl.af = tnbr->af;
                tctl.addr = tnbr->addr;
index da90c7cad777593480c5429da5704d199c1f7efe..a57727591a8edc67ac6f63e2c5009454656ed376 100644 (file)
@@ -225,7 +225,7 @@ void                 adj_start_itimer(struct adj *);
 void            adj_stop_itimer(struct adj *);
 struct tnbr    *tnbr_new(int, union ldpd_addr *);
 struct tnbr    *tnbr_find(struct ldpd_conf *, int, union ldpd_addr *);
-struct tnbr    *tnbr_check(struct tnbr *);
+struct tnbr    *tnbr_check(struct ldpd_conf *, struct tnbr *);
 void            tnbr_update(struct tnbr *);
 void            tnbr_update_all(int);
 uint16_t        tnbr_get_hello_holdtime(struct tnbr *);