From: Renato Westphal Date: Tue, 13 Dec 2016 18:19:15 +0000 (-0200) Subject: ldpd: use red-black trees to store 'tnbr' elements X-Git-Tag: frr-3.0-branchpoint~94^2~1^2~5 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=7989cdba45f631fb14d1bcaf7103c9db25605971;p=mirror%2Ffrr.git ldpd: use red-black trees to store 'tnbr' elements 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 --- diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c index d1a6facb30..3f478df38a 100644 --- a/ldpd/adjacency.c +++ b/ldpd/adjacency.c @@ -26,11 +26,14 @@ #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) @@ -165,7 +168,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; @@ -192,6 +195,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) { @@ -208,34 +222,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); } @@ -280,7 +290,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); } diff --git a/ldpd/hello.c b/ldpd/hello.c index 755b25aa85..0833ebbafb 100644 --- a/ldpd/hello.c +++ b/ldpd/hello.c @@ -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; diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index c0f6586854..dc9879ef23 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -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); } } diff --git a/ldpd/lde.c b/ldpd/lde.c index 1e362185d2..4b957c55e7 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -474,7 +474,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; @@ -496,7 +496,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) diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c index 689554d857..f5c98eb1ff 100644 --- a/ldpd/ldp_vty_conf.c +++ b/ldpd/ldp_vty_conf.c @@ -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); @@ -1665,14 +1665,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); } diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 14cfaffbb9..cf793f58c3 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -856,7 +856,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); @@ -992,13 +992,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); } @@ -1033,7 +1033,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); @@ -1043,9 +1043,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); @@ -1097,8 +1097,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) { @@ -1295,7 +1295,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; @@ -1303,26 +1303,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: @@ -1340,7 +1340,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); @@ -1771,7 +1771,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); diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 2c516c013b..7e5b4248a2 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -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); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 16910a3cc8..699ce502f5 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -415,7 +415,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; @@ -437,7 +437,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) @@ -743,12 +743,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); } } @@ -832,7 +832,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; diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index aab1a7fd9b..52899fd85c 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -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 *);