mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-04 22:14:49 +00:00
ldpd: use red-black trees to store 'l2vpn' 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:
parent
c485351c52
commit
2db4e1fca1
25
ldpd/l2vpn.c
25
ldpd/l2vpn.c
@ -26,7 +26,16 @@
|
||||
#include "lde.h"
|
||||
#include "log.h"
|
||||
|
||||
static void l2vpn_pw_fec(struct l2vpn_pw *, struct fec *);
|
||||
static void l2vpn_pw_fec(struct l2vpn_pw *, struct fec *);
|
||||
static __inline int l2vpn_compare(struct l2vpn *, struct l2vpn *);
|
||||
|
||||
RB_GENERATE(l2vpn_head, l2vpn, entry, l2vpn_compare)
|
||||
|
||||
static __inline int
|
||||
l2vpn_compare(struct l2vpn *a, struct l2vpn *b)
|
||||
{
|
||||
return (strcmp(a->name, b->name));
|
||||
}
|
||||
|
||||
struct l2vpn *
|
||||
l2vpn_new(const char *name)
|
||||
@ -52,13 +61,9 @@ l2vpn_new(const char *name)
|
||||
struct l2vpn *
|
||||
l2vpn_find(struct ldpd_conf *xconf, const char *name)
|
||||
{
|
||||
struct l2vpn *l2vpn;
|
||||
|
||||
LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry)
|
||||
if (strcmp(l2vpn->name, name) == 0)
|
||||
return (l2vpn);
|
||||
|
||||
return (NULL);
|
||||
struct l2vpn l2vpn;
|
||||
strlcpy(l2vpn.name, name, sizeof(l2vpn.name));
|
||||
return (RB_FIND(l2vpn_head, &xconf->l2vpn_tree, &l2vpn));
|
||||
}
|
||||
|
||||
void
|
||||
@ -399,7 +404,7 @@ l2vpn_sync_pws(int af, union ldpd_addr *addr)
|
||||
struct fec_node *fn;
|
||||
struct fec_nh *fnh;
|
||||
|
||||
LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) {
|
||||
RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree) {
|
||||
LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
|
||||
if (af != pw->af || ldp_addrcmp(af, &pw->addr, addr))
|
||||
continue;
|
||||
@ -428,7 +433,7 @@ l2vpn_pw_ctl(pid_t pid)
|
||||
struct l2vpn_pw *pw;
|
||||
static struct ctl_pw pwctl;
|
||||
|
||||
LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
|
||||
RB_FOREACH(l2vpn, l2vpn_head, &ldeconf->l2vpn_tree)
|
||||
LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
|
||||
memset(&pwctl, 0, sizeof(pwctl));
|
||||
strlcpy(pwctl.l2vpn_name, pw->l2vpn->name,
|
||||
|
@ -475,7 +475,7 @@ lde_dispatch_parent(struct thread *thread)
|
||||
RB_INIT(&nconf->iface_tree);
|
||||
RB_INIT(&nconf->tnbr_tree);
|
||||
RB_INIT(&nconf->nbrp_tree);
|
||||
LIST_INIT(&nconf->l2vpn_list);
|
||||
RB_INIT(&nconf->l2vpn_tree);
|
||||
break;
|
||||
case IMSG_RECONF_IFACE:
|
||||
if ((niface = malloc(sizeof(struct iface))) == NULL)
|
||||
@ -513,7 +513,7 @@ lde_dispatch_parent(struct thread *thread)
|
||||
LIST_INIT(&nl2vpn->pw_list);
|
||||
LIST_INIT(&nl2vpn->pw_inactive_list);
|
||||
|
||||
LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);
|
||||
RB_INSERT(l2vpn_head, &nconf->l2vpn_tree, nl2vpn);
|
||||
break;
|
||||
case IMSG_RECONF_L2VPN_IF:
|
||||
if ((nlif = malloc(sizeof(struct l2vpn_if))) == NULL)
|
||||
|
@ -341,7 +341,7 @@ ldp_l2vpn_config_write(struct vty *vty)
|
||||
struct l2vpn_if *lif;
|
||||
struct l2vpn_pw *pw;
|
||||
|
||||
LIST_FOREACH(l2vpn, &ldpd_conf->l2vpn_list, entry) {
|
||||
RB_FOREACH(l2vpn, l2vpn_head, &ldpd_conf->l2vpn_tree) {
|
||||
vty_out(vty, "l2vpn %s type vpls%s", l2vpn->name, VTY_NEWLINE);
|
||||
|
||||
if (l2vpn->pw_type != DEFAULT_PW_TYPE)
|
||||
@ -393,7 +393,7 @@ ldp_iface_is_configured(struct ldpd_conf *xconf, const char *ifname)
|
||||
if (if_lookup_name(xconf, ifname))
|
||||
return (1);
|
||||
|
||||
LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) {
|
||||
RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) {
|
||||
if (l2vpn_if_find_name(l2vpn, ifname))
|
||||
return (1);
|
||||
if (l2vpn_pw_find_name(l2vpn, ifname))
|
||||
@ -1235,7 +1235,7 @@ ldp_vty_l2vpn(struct vty *vty, struct vty_arg *args[])
|
||||
if (l2vpn == NULL)
|
||||
goto cancel;
|
||||
|
||||
LIST_REMOVE(l2vpn, entry);
|
||||
RB_REMOVE(l2vpn_head, &vty_conf->l2vpn_tree, l2vpn);
|
||||
l2vpn_del(l2vpn);
|
||||
ldp_reload(vty_conf);
|
||||
return (CMD_SUCCESS);
|
||||
@ -1248,7 +1248,7 @@ ldp_vty_l2vpn(struct vty *vty, struct vty_arg *args[])
|
||||
|
||||
l2vpn = l2vpn_new(name_str);
|
||||
l2vpn->type = L2VPN_TYPE_VPLS;
|
||||
LIST_INSERT_HEAD(&vty_conf->l2vpn_list, l2vpn, entry);
|
||||
RB_INSERT(l2vpn_head, &vty_conf->l2vpn_tree, l2vpn);
|
||||
|
||||
ldp_reload(vty_conf);
|
||||
VTY_PUSH_CONTEXT(LDP_L2VPN_NODE, l2vpn);
|
||||
@ -1713,12 +1713,12 @@ l2vpn_new_api(struct ldpd_conf *conf, const char *name)
|
||||
|
||||
l2vpn = l2vpn_new(name);
|
||||
l2vpn->type = L2VPN_TYPE_VPLS;
|
||||
LIST_INSERT_HEAD(&conf->l2vpn_list, l2vpn, entry);
|
||||
RB_INSERT(l2vpn_head, &conf->l2vpn_tree, l2vpn);
|
||||
return (l2vpn);
|
||||
}
|
||||
|
||||
void
|
||||
l2vpn_del_api(struct l2vpn *l2vpn)
|
||||
l2vpn_del_api(struct ldpd_conf *conf, struct l2vpn *l2vpn)
|
||||
{
|
||||
struct l2vpn_if *lif;
|
||||
struct l2vpn_pw *pw;
|
||||
@ -1735,7 +1735,7 @@ l2vpn_del_api(struct l2vpn *l2vpn)
|
||||
LIST_REMOVE(pw, entry);
|
||||
free(pw);
|
||||
}
|
||||
LIST_REMOVE(l2vpn, entry);
|
||||
RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
|
||||
free(l2vpn);
|
||||
}
|
||||
|
||||
|
28
ldpd/ldpd.c
28
ldpd/ldpd.c
@ -909,7 +909,7 @@ main_imsg_send_config(struct ldpd_conf *xconf)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) {
|
||||
RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) {
|
||||
if (main_imsg_compose_both(IMSG_RECONF_L2VPN, l2vpn,
|
||||
sizeof(*l2vpn)) == -1)
|
||||
return (-1);
|
||||
@ -971,7 +971,7 @@ ldp_config_normalize(struct ldpd_conf *xconf, void **ref)
|
||||
ldp_config_reset_af(xconf, AF_INET6, ref);
|
||||
}
|
||||
|
||||
LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) {
|
||||
RB_FOREACH(l2vpn, l2vpn_head, &xconf->l2vpn_tree) {
|
||||
LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
|
||||
if (pw->flags & F_PW_STATIC_NBR_ADDR)
|
||||
continue;
|
||||
@ -1076,7 +1076,7 @@ ldp_dup_config_ref(struct ldpd_conf *conf, void **ref)
|
||||
RB_INIT(&xconf->iface_tree);
|
||||
RB_INIT(&xconf->tnbr_tree);
|
||||
RB_INIT(&xconf->nbrp_tree);
|
||||
LIST_INIT(&xconf->l2vpn_list);
|
||||
RB_INIT(&xconf->l2vpn_tree);
|
||||
|
||||
RB_FOREACH(iface, iface_head, &conf->iface_tree) {
|
||||
COPY(xi, iface);
|
||||
@ -1092,12 +1092,12 @@ ldp_dup_config_ref(struct ldpd_conf *conf, void **ref)
|
||||
COPY(xn, nbrp);
|
||||
RB_INSERT(nbrp_head, &xconf->nbrp_tree, xn);
|
||||
}
|
||||
LIST_FOREACH(l2vpn, &conf->l2vpn_list, entry) {
|
||||
RB_FOREACH(l2vpn, l2vpn_head, &conf->l2vpn_tree) {
|
||||
COPY(xl, l2vpn);
|
||||
LIST_INIT(&xl->if_list);
|
||||
LIST_INIT(&xl->pw_list);
|
||||
LIST_INIT(&xl->pw_inactive_list);
|
||||
LIST_INSERT_HEAD(&xconf->l2vpn_list, xl, entry);
|
||||
RB_INSERT(l2vpn_head, &xconf->l2vpn_tree, xl);
|
||||
|
||||
LIST_FOREACH(lif, &l2vpn->if_list, entry) {
|
||||
COPY(xf, lif);
|
||||
@ -1146,8 +1146,8 @@ ldp_clear_config(struct ldpd_conf *xconf)
|
||||
RB_REMOVE(nbrp_head, &xconf->nbrp_tree, nbrp);
|
||||
free(nbrp);
|
||||
}
|
||||
while ((l2vpn = LIST_FIRST(&xconf->l2vpn_list)) != NULL) {
|
||||
LIST_REMOVE(l2vpn, entry);
|
||||
while ((l2vpn = RB_ROOT(&xconf->l2vpn_tree)) != NULL) {
|
||||
RB_REMOVE(l2vpn_head, &xconf->l2vpn_tree, l2vpn);
|
||||
l2vpn_del(l2vpn);
|
||||
}
|
||||
|
||||
@ -1510,10 +1510,10 @@ merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
|
||||
struct l2vpn_if *lif;
|
||||
struct l2vpn_pw *pw;
|
||||
|
||||
LIST_FOREACH_SAFE(l2vpn, &conf->l2vpn_list, entry, ltmp) {
|
||||
RB_FOREACH_SAFE(l2vpn, l2vpn_head, &conf->l2vpn_tree, ltmp) {
|
||||
/* find deleted l2vpns */
|
||||
if ((xl = l2vpn_find(xconf, l2vpn->name)) == NULL) {
|
||||
LIST_REMOVE(l2vpn, entry);
|
||||
RB_REMOVE(l2vpn_head, &conf->l2vpn_tree, l2vpn);
|
||||
|
||||
switch (ldpd_process) {
|
||||
case PROC_LDE_ENGINE:
|
||||
@ -1535,11 +1535,11 @@ merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
|
||||
l2vpn_del(l2vpn);
|
||||
}
|
||||
}
|
||||
LIST_FOREACH_SAFE(xl, &xconf->l2vpn_list, entry, ltmp) {
|
||||
RB_FOREACH_SAFE(xl, l2vpn_head, &xconf->l2vpn_tree, ltmp) {
|
||||
/* find new l2vpns */
|
||||
if ((l2vpn = l2vpn_find(conf, xl->name)) == NULL) {
|
||||
LIST_REMOVE(xl, entry);
|
||||
LIST_INSERT_HEAD(&conf->l2vpn_list, xl, entry);
|
||||
RB_REMOVE(l2vpn_head, &xconf->l2vpn_tree, xl);
|
||||
RB_INSERT(l2vpn_head, &conf->l2vpn_tree, xl);
|
||||
|
||||
switch (ldpd_process) {
|
||||
case PROC_LDE_ENGINE:
|
||||
@ -1557,7 +1557,7 @@ merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
|
||||
|
||||
/* update existing l2vpns */
|
||||
merge_l2vpn(conf, l2vpn, xl, ref);
|
||||
LIST_REMOVE(xl, entry);
|
||||
RB_REMOVE(l2vpn_head, &xconf->l2vpn_tree, xl);
|
||||
if (ref && *ref == xl)
|
||||
*ref = l2vpn;
|
||||
free(xl);
|
||||
@ -1814,7 +1814,7 @@ config_new_empty(void)
|
||||
RB_INIT(&xconf->iface_tree);
|
||||
RB_INIT(&xconf->tnbr_tree);
|
||||
RB_INIT(&xconf->nbrp_tree);
|
||||
LIST_INIT(&xconf->l2vpn_list);
|
||||
RB_INIT(&xconf->l2vpn_tree);
|
||||
|
||||
return (xconf);
|
||||
}
|
||||
|
11
ldpd/ldpd.h
11
ldpd/ldpd.h
@ -358,7 +358,7 @@ DECLARE_QOBJ_TYPE(l2vpn_pw)
|
||||
#define F_PW_STATIC_NBR_ADDR 0x20 /* static neighbor address configured */
|
||||
|
||||
struct l2vpn {
|
||||
LIST_ENTRY(l2vpn) entry;
|
||||
RB_ENTRY(l2vpn) entry;
|
||||
char name[L2VPN_NAME_LEN];
|
||||
int type;
|
||||
int pw_type;
|
||||
@ -370,6 +370,8 @@ struct l2vpn {
|
||||
LIST_HEAD(, l2vpn_pw) pw_inactive_list;
|
||||
QOBJ_FIELDS
|
||||
};
|
||||
RB_HEAD(l2vpn_head, l2vpn);
|
||||
RB_PROTOTYPE(l2vpn_head, l2vpn, entry, l2vpn_compare);
|
||||
DECLARE_QOBJ_TYPE(l2vpn)
|
||||
#define L2VPN_TYPE_VPWS 1
|
||||
#define L2VPN_TYPE_VPLS 2
|
||||
@ -413,7 +415,7 @@ struct ldpd_conf {
|
||||
struct iface_head iface_tree;
|
||||
struct tnbr_head tnbr_tree;
|
||||
struct nbrp_head nbrp_tree;
|
||||
LIST_HEAD(, l2vpn) l2vpn_list;
|
||||
struct l2vpn_head l2vpn_tree;
|
||||
uint16_t lhello_holdtime;
|
||||
uint16_t lhello_interval;
|
||||
uint16_t thello_holdtime;
|
||||
@ -644,8 +646,9 @@ struct nbr_params *nbrp_new_api(struct ldpd_conf *conf,
|
||||
struct in_addr lsr_id);
|
||||
void nbrp_del_api(struct ldpd_conf *conf,
|
||||
struct nbr_params *nbrp);
|
||||
struct l2vpn *l2vpn_new_api(struct ldpd_conf *cfg, const char *name);
|
||||
void l2vpn_del_api(struct l2vpn *l2vpn);
|
||||
struct l2vpn *l2vpn_new_api(struct ldpd_conf *conf, const char *name);
|
||||
void l2vpn_del_api(struct ldpd_conf *conf,
|
||||
struct l2vpn *l2vpn);
|
||||
struct l2vpn_if *l2vpn_if_new_api(struct ldpd_conf *conf,
|
||||
struct l2vpn *l2vpn, const char *ifname);
|
||||
void l2vpn_if_del_api(struct l2vpn_if *lif);
|
||||
|
@ -418,7 +418,7 @@ ldpe_dispatch_main(struct thread *thread)
|
||||
RB_INIT(&nconf->iface_tree);
|
||||
RB_INIT(&nconf->tnbr_tree);
|
||||
RB_INIT(&nconf->nbrp_tree);
|
||||
LIST_INIT(&nconf->l2vpn_list);
|
||||
RB_INIT(&nconf->l2vpn_tree);
|
||||
break;
|
||||
case IMSG_RECONF_IFACE:
|
||||
if ((niface = malloc(sizeof(struct iface))) == NULL)
|
||||
@ -456,7 +456,7 @@ ldpe_dispatch_main(struct thread *thread)
|
||||
LIST_INIT(&nl2vpn->pw_list);
|
||||
LIST_INIT(&nl2vpn->pw_inactive_list);
|
||||
|
||||
LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);
|
||||
RB_INSERT(l2vpn_head, &nconf->l2vpn_tree, nl2vpn);
|
||||
break;
|
||||
case IMSG_RECONF_L2VPN_IF:
|
||||
if ((nlif = malloc(sizeof(struct l2vpn_if))) == NULL)
|
||||
|
Loading…
Reference in New Issue
Block a user