ldpd: use red-black trees to store 'iface' 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 <renato@opensourcerouting.org>
This commit is contained in:
Renato Westphal 2016-12-13 15:29:35 -02:00
parent 9b127e5804
commit 39ec2dc9bb
7 changed files with 57 additions and 49 deletions

View File

@ -26,6 +26,7 @@
#include "sockopt.h" #include "sockopt.h"
static __inline int iface_compare(struct iface *, struct iface *);
static struct if_addr *if_addr_new(struct kaddr *); static struct if_addr *if_addr_new(struct kaddr *);
static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *); static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
static int if_start(struct iface *, int); static int if_start(struct iface *, int);
@ -39,6 +40,14 @@ static int if_leave_ipv4_group(struct iface *, struct in_addr *);
static int if_join_ipv6_group(struct iface *, struct in6_addr *); static int if_join_ipv6_group(struct iface *, struct in6_addr *);
static int if_leave_ipv6_group(struct iface *, struct in6_addr *); static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
RB_GENERATE(iface_head, iface, entry, iface_compare)
static __inline int
iface_compare(struct iface *a, struct iface *b)
{
return (strcmp(a->name, b->name));
}
struct iface * struct iface *
if_new(struct kif *kif) if_new(struct kif *kif)
{ {
@ -69,18 +78,6 @@ if_new(struct kif *kif)
return (iface); return (iface);
} }
struct iface *
if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
{
struct iface *iface;
LIST_FOREACH(iface, &xconf->iface_list, entry)
if (iface->ifindex == ifindex)
return (iface);
return (NULL);
}
void void
if_exit(struct iface *iface) if_exit(struct iface *iface)
{ {
@ -100,17 +97,25 @@ if_exit(struct iface *iface)
} }
struct iface * struct iface *
if_lookup_name(struct ldpd_conf *xconf, const char *ifname) if_lookup(struct ldpd_conf *xconf, unsigned short ifindex)
{ {
struct iface *iface; struct iface *iface;
LIST_FOREACH(iface, &xconf->iface_list, entry) RB_FOREACH(iface, iface_head, &xconf->iface_tree)
if (strcmp(iface->name, ifname) == 0) if (iface->ifindex == ifindex)
return (iface); return (iface);
return (NULL); return (NULL);
} }
struct iface *
if_lookup_name(struct ldpd_conf *xconf, const char *ifname)
{
struct iface iface;
strlcpy(iface.name, ifname, sizeof(iface.name));
return (RB_FIND(iface_head, &xconf->iface_tree, &iface));
}
void void
if_update_info(struct iface *iface, struct kif *kif) if_update_info(struct iface *iface, struct kif *kif)
{ {
@ -380,7 +385,7 @@ if_update_all(int af)
{ {
struct iface *iface; struct iface *iface;
LIST_FOREACH(iface, &leconf->iface_list, entry) RB_FOREACH(iface, iface_head, &leconf->iface_tree)
if_update(iface, af); if_update(iface, af);
} }

View File

@ -472,7 +472,7 @@ lde_dispatch_parent(struct thread *thread)
fatal(NULL); fatal(NULL);
memcpy(nconf, imsg.data, sizeof(struct ldpd_conf)); memcpy(nconf, imsg.data, sizeof(struct ldpd_conf));
LIST_INIT(&nconf->iface_list); RB_INIT(&nconf->iface_tree);
LIST_INIT(&nconf->tnbr_list); LIST_INIT(&nconf->tnbr_list);
LIST_INIT(&nconf->nbrp_list); LIST_INIT(&nconf->nbrp_list);
LIST_INIT(&nconf->l2vpn_list); LIST_INIT(&nconf->l2vpn_list);
@ -488,7 +488,7 @@ lde_dispatch_parent(struct thread *thread)
niface->ipv4.iface = niface; niface->ipv4.iface = niface;
niface->ipv6.iface = niface; niface->ipv6.iface = niface;
LIST_INSERT_HEAD(&nconf->iface_list, niface, entry); RB_INSERT(iface_head, &nconf->iface_tree, niface);
break; break;
case IMSG_RECONF_TNBR: case IMSG_RECONF_TNBR:
if ((ntnbr = malloc(sizeof(struct tnbr))) == NULL) if ((ntnbr = malloc(sizeof(struct tnbr))) == NULL)

View File

@ -142,7 +142,7 @@ ldp_af_iface_config_write(struct vty *vty, int af)
struct iface *iface; struct iface *iface;
struct iface_af *ia; struct iface_af *ia;
LIST_FOREACH(iface, &ldpd_conf->iface_list, entry) { RB_FOREACH(iface, iface_head, &ldpd_conf->iface_tree) {
ia = iface_af_get(iface, af); ia = iface_af_get(iface, af);
if (!ia->enabled) if (!ia->enabled)
continue; continue;
@ -857,7 +857,7 @@ ldp_vty_interface(struct vty *vty, struct vty_arg *args[])
ia = iface_af_get(iface, af); ia = iface_af_get(iface, af);
ia->enabled = 1; ia->enabled = 1;
LIST_INSERT_HEAD(&vty_conf->iface_list, iface, entry); RB_INSERT(iface_head, &vty_conf->iface_tree, iface);
ldp_reload_ref(vty_conf, (void **)&iface); ldp_reload_ref(vty_conf, (void **)&iface);
} else { } else {
memset(&kif, 0, sizeof(kif)); memset(&kif, 0, sizeof(kif));
@ -1648,14 +1648,14 @@ iface_new_api(struct ldpd_conf *conf, const char *name)
} }
iface = if_new(&kif); iface = if_new(&kif);
LIST_INSERT_HEAD(&conf->iface_list, iface, entry); RB_INSERT(iface_head, &conf->iface_tree, iface);
return (iface); return (iface);
} }
void void
iface_del_api(struct iface *iface) iface_del_api(struct ldpd_conf *conf, struct iface *iface)
{ {
LIST_REMOVE(iface, entry); RB_REMOVE(iface_head, &conf->iface_tree, iface);
free(iface); free(iface);
} }

View File

@ -891,7 +891,7 @@ main_imsg_send_config(struct ldpd_conf *xconf)
sizeof(*xconf)) == -1) sizeof(*xconf)) == -1)
return (-1); return (-1);
LIST_FOREACH(iface, &xconf->iface_list, entry) { RB_FOREACH(iface, iface_head, &xconf->iface_tree) {
if (main_imsg_compose_both(IMSG_RECONF_IFACE, iface, if (main_imsg_compose_both(IMSG_RECONF_IFACE, iface,
sizeof(*iface)) == -1) sizeof(*iface)) == -1)
return (-1); return (-1);
@ -995,10 +995,10 @@ ldp_config_reset_main(struct ldpd_conf *conf, void **ref)
struct iface *iface; struct iface *iface;
struct nbr_params *nbrp; struct nbr_params *nbrp;
while ((iface = LIST_FIRST(&conf->iface_list)) != NULL) { while ((iface = RB_ROOT(&conf->iface_tree)) != NULL) {
if (ref && *ref == iface) if (ref && *ref == iface)
*ref = NULL; *ref = NULL;
LIST_REMOVE(iface, entry); RB_REMOVE(iface_head, &conf->iface_tree, iface);
free(iface); free(iface);
} }
@ -1028,7 +1028,7 @@ ldp_config_reset_af(struct ldpd_conf *conf, int af, void **ref)
struct iface_af *ia; struct iface_af *ia;
struct tnbr *tnbr, *ttmp; struct tnbr *tnbr, *ttmp;
LIST_FOREACH(iface, &conf->iface_list, entry) { RB_FOREACH(iface, iface_head, &conf->iface_tree) {
ia = iface_af_get(iface, af); ia = iface_af_get(iface, af);
ia->enabled = 0; ia->enabled = 0;
} }
@ -1073,16 +1073,16 @@ ldp_dup_config_ref(struct ldpd_conf *conf, void **ref)
} while (0) } while (0)
COPY(xconf, conf); COPY(xconf, conf);
LIST_INIT(&xconf->iface_list); RB_INIT(&xconf->iface_tree);
LIST_INIT(&xconf->tnbr_list); LIST_INIT(&xconf->tnbr_list);
LIST_INIT(&xconf->nbrp_list); LIST_INIT(&xconf->nbrp_list);
LIST_INIT(&xconf->l2vpn_list); LIST_INIT(&xconf->l2vpn_list);
LIST_FOREACH(iface, &conf->iface_list, entry) { RB_FOREACH(iface, iface_head, &conf->iface_tree) {
COPY(xi, iface); COPY(xi, iface);
xi->ipv4.iface = xi; xi->ipv4.iface = xi;
xi->ipv6.iface = xi; xi->ipv6.iface = xi;
LIST_INSERT_HEAD(&xconf->iface_list, xi, entry); RB_INSERT(iface_head, &xconf->iface_tree, xi);
} }
LIST_FOREACH(tnbr, &conf->tnbr_list, entry) { LIST_FOREACH(tnbr, &conf->tnbr_list, entry) {
COPY(xt, tnbr); COPY(xt, tnbr);
@ -1134,8 +1134,8 @@ ldp_clear_config(struct ldpd_conf *xconf)
struct nbr_params *nbrp; struct nbr_params *nbrp;
struct l2vpn *l2vpn; struct l2vpn *l2vpn;
while ((iface = LIST_FIRST(&xconf->iface_list)) != NULL) { while ((iface = RB_ROOT(&xconf->iface_tree)) != NULL) {
LIST_REMOVE(iface, entry); RB_REMOVE(iface_head, &xconf->iface_tree, iface);
free(iface); free(iface);
} }
while ((tnbr = LIST_FIRST(&xconf->tnbr_list)) != NULL) { while ((tnbr = LIST_FIRST(&xconf->tnbr_list)) != NULL) {
@ -1277,10 +1277,10 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
{ {
struct iface *iface, *itmp, *xi; struct iface *iface, *itmp, *xi;
LIST_FOREACH_SAFE(iface, &conf->iface_list, entry, itmp) { RB_FOREACH_SAFE(iface, iface_head, &conf->iface_tree, itmp) {
/* find deleted interfaces */ /* find deleted interfaces */
if ((xi = if_lookup_name(xconf, iface->name)) == NULL) { if ((xi = if_lookup_name(xconf, iface->name)) == NULL) {
LIST_REMOVE(iface, entry); RB_REMOVE(iface_head, &conf->iface_tree, iface);
switch (ldpd_process) { switch (ldpd_process) {
case PROC_LDE_ENGINE: case PROC_LDE_ENGINE:
@ -1295,11 +1295,11 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
free(iface); free(iface);
} }
} }
LIST_FOREACH_SAFE(xi, &xconf->iface_list, entry, itmp) { RB_FOREACH_SAFE(xi, iface_head, &xconf->iface_tree, itmp) {
/* find new interfaces */ /* find new interfaces */
if ((iface = if_lookup_name(conf, xi->name)) == NULL) { if ((iface = if_lookup_name(conf, xi->name)) == NULL) {
LIST_REMOVE(xi, entry); RB_REMOVE(iface_head, &xconf->iface_tree, xi);
LIST_INSERT_HEAD(&conf->iface_list, xi, entry); RB_INSERT(iface_head, &conf->iface_tree, xi);
if (ldpd_process == PROC_MAIN) { if (ldpd_process == PROC_MAIN) {
QOBJ_REG (xi, iface); QOBJ_REG (xi, iface);
@ -1312,7 +1312,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
/* update existing interfaces */ /* update existing interfaces */
merge_iface_af(&iface->ipv4, &xi->ipv4); merge_iface_af(&iface->ipv4, &xi->ipv4);
merge_iface_af(&iface->ipv6, &xi->ipv6); merge_iface_af(&iface->ipv6, &xi->ipv6);
LIST_REMOVE(xi, entry); RB_REMOVE(iface_head, &xconf->iface_tree, xi);
if (ref && *ref == xi) if (ref && *ref == xi)
*ref = iface; *ref = iface;
free(xi); free(xi);
@ -1811,7 +1811,7 @@ config_new_empty(void)
if (xconf == NULL) if (xconf == NULL)
fatal(NULL); fatal(NULL);
LIST_INIT(&xconf->iface_list); RB_INIT(&xconf->iface_tree);
LIST_INIT(&xconf->tnbr_list); LIST_INIT(&xconf->tnbr_list);
LIST_INIT(&xconf->nbrp_list); LIST_INIT(&xconf->nbrp_list);
LIST_INIT(&xconf->l2vpn_list); LIST_INIT(&xconf->l2vpn_list);

View File

@ -264,7 +264,7 @@ struct iface_af {
}; };
struct iface { struct iface {
LIST_ENTRY(iface) entry; RB_ENTRY(iface) entry;
char name[IF_NAMESIZE]; char name[IF_NAMESIZE];
unsigned int ifindex; unsigned int ifindex;
struct if_addr_head addr_list; struct if_addr_head addr_list;
@ -275,6 +275,8 @@ struct iface {
struct iface_af ipv6; struct iface_af ipv6;
QOBJ_FIELDS QOBJ_FIELDS
}; };
RB_HEAD(iface_head, iface);
RB_PROTOTYPE(iface_head, iface, entry, iface_compare);
DECLARE_QOBJ_TYPE(iface) DECLARE_QOBJ_TYPE(iface)
/* source of targeted hellos */ /* source of targeted hellos */
@ -404,7 +406,7 @@ struct ldpd_conf {
struct in_addr rtr_id; struct in_addr rtr_id;
struct ldpd_af_conf ipv4; struct ldpd_af_conf ipv4;
struct ldpd_af_conf ipv6; struct ldpd_af_conf ipv6;
LIST_HEAD(, iface) iface_list; struct iface_head iface_tree;
LIST_HEAD(, tnbr) tnbr_list; LIST_HEAD(, tnbr) tnbr_list;
LIST_HEAD(, nbr_params) nbrp_list; LIST_HEAD(, nbr_params) nbrp_list;
LIST_HEAD(, l2vpn) l2vpn_list; LIST_HEAD(, l2vpn) l2vpn_list;
@ -627,9 +629,10 @@ void config_clear(struct ldpd_conf *);
/* ldp_vty_conf.c */ /* ldp_vty_conf.c */
/* NOTE: the parameters' names should be preserved because of codegen */ /* NOTE: the parameters' names should be preserved because of codegen */
struct iface *iface_new_api(struct ldpd_conf *cfg, struct iface *iface_new_api(struct ldpd_conf *conf,
const char *name); const char *name);
void iface_del_api(struct iface *iface); 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 *cfg, int af,
union ldpd_addr *addr); union ldpd_addr *addr);
void tnbr_del_api(struct tnbr *tnbr); void tnbr_del_api(struct tnbr *tnbr);

View File

@ -415,7 +415,7 @@ ldpe_dispatch_main(struct thread *thread)
fatal(NULL); fatal(NULL);
memcpy(nconf, imsg.data, sizeof(struct ldpd_conf)); memcpy(nconf, imsg.data, sizeof(struct ldpd_conf));
LIST_INIT(&nconf->iface_list); RB_INIT(&nconf->iface_tree);
LIST_INIT(&nconf->tnbr_list); LIST_INIT(&nconf->tnbr_list);
LIST_INIT(&nconf->nbrp_list); LIST_INIT(&nconf->nbrp_list);
LIST_INIT(&nconf->l2vpn_list); LIST_INIT(&nconf->l2vpn_list);
@ -431,7 +431,7 @@ ldpe_dispatch_main(struct thread *thread)
niface->ipv4.iface = niface; niface->ipv4.iface = niface;
niface->ipv6.iface = niface; niface->ipv6.iface = niface;
LIST_INSERT_HEAD(&nconf->iface_list, niface, entry); RB_INSERT(iface_head, &nconf->iface_tree, niface);
break; break;
case IMSG_RECONF_TNBR: case IMSG_RECONF_TNBR:
if ((ntnbr = malloc(sizeof(struct tnbr))) == NULL) if ((ntnbr = malloc(sizeof(struct tnbr))) == NULL)
@ -773,7 +773,7 @@ ldpe_iface_af_ctl(struct ctl_conn *c, int af, unsigned int idx)
struct iface_af *ia; struct iface_af *ia;
struct ctl_iface *ictl; struct ctl_iface *ictl;
LIST_FOREACH(iface, &leconf->iface_list, entry) { RB_FOREACH(iface, iface_head, &leconf->iface_tree) {
if (idx == 0 || idx == iface->ifindex) { if (idx == 0 || idx == iface->ifindex) {
ia = iface_af_get(iface, af); ia = iface_af_get(iface, af);
if (!ia->enabled) if (!ia->enabled)
@ -806,7 +806,7 @@ ldpe_adj_ctl(struct ctl_conn *c)
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0); imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0);
LIST_FOREACH(iface, &leconf->iface_list, entry) { RB_FOREACH(iface, iface_head, &leconf->iface_tree) {
memset(&ictl, 0, sizeof(ictl)); memset(&ictl, 0, sizeof(ictl));
ictl.active_v4 = (iface->ipv4.state == IF_STA_ACTIVE); ictl.active_v4 = (iface->ipv4.state == IF_STA_ACTIVE);
ictl.active_v6 = (iface->ipv6.state == IF_STA_ACTIVE); ictl.active_v6 = (iface->ipv6.state == IF_STA_ACTIVE);