mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-16 20:43:41 +00:00
ldpd: use red-black trees to store 'l2vpn_if' 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
2db4e1fca1
commit
7a09a2b1c4
26
ldpd/l2vpn.c
26
ldpd/l2vpn.c
@ -28,8 +28,10 @@
|
|||||||
|
|
||||||
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 *);
|
static __inline int l2vpn_compare(struct l2vpn *, struct l2vpn *);
|
||||||
|
static __inline int l2vpn_if_compare(struct l2vpn_if *, struct l2vpn_if *);
|
||||||
|
|
||||||
RB_GENERATE(l2vpn_head, l2vpn, entry, l2vpn_compare)
|
RB_GENERATE(l2vpn_head, l2vpn, entry, l2vpn_compare)
|
||||||
|
RB_GENERATE(l2vpn_if_head, l2vpn_if, entry, l2vpn_if_compare)
|
||||||
|
|
||||||
static __inline int
|
static __inline int
|
||||||
l2vpn_compare(struct l2vpn *a, struct l2vpn *b)
|
l2vpn_compare(struct l2vpn *a, struct l2vpn *b)
|
||||||
@ -51,7 +53,7 @@ l2vpn_new(const char *name)
|
|||||||
l2vpn->mtu = DEFAULT_L2VPN_MTU;
|
l2vpn->mtu = DEFAULT_L2VPN_MTU;
|
||||||
l2vpn->pw_type = DEFAULT_PW_TYPE;
|
l2vpn->pw_type = DEFAULT_PW_TYPE;
|
||||||
|
|
||||||
LIST_INIT(&l2vpn->if_list);
|
RB_INIT(&l2vpn->if_tree);
|
||||||
LIST_INIT(&l2vpn->pw_list);
|
LIST_INIT(&l2vpn->pw_list);
|
||||||
LIST_INIT(&l2vpn->pw_inactive_list);
|
LIST_INIT(&l2vpn->pw_inactive_list);
|
||||||
|
|
||||||
@ -72,8 +74,8 @@ l2vpn_del(struct l2vpn *l2vpn)
|
|||||||
struct l2vpn_if *lif;
|
struct l2vpn_if *lif;
|
||||||
struct l2vpn_pw *pw;
|
struct l2vpn_pw *pw;
|
||||||
|
|
||||||
while ((lif = LIST_FIRST(&l2vpn->if_list)) != NULL) {
|
while ((lif = RB_ROOT(&l2vpn->if_tree)) != NULL) {
|
||||||
LIST_REMOVE(lif, entry);
|
RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
|
||||||
free(lif);
|
free(lif);
|
||||||
}
|
}
|
||||||
while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) {
|
while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) {
|
||||||
@ -106,6 +108,12 @@ l2vpn_exit(struct l2vpn *l2vpn)
|
|||||||
l2vpn_pw_exit(pw);
|
l2vpn_pw_exit(pw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __inline int
|
||||||
|
l2vpn_if_compare(struct l2vpn_if *a, struct l2vpn_if *b)
|
||||||
|
{
|
||||||
|
return (strcmp(a->ifname, b->ifname));
|
||||||
|
}
|
||||||
|
|
||||||
struct l2vpn_if *
|
struct l2vpn_if *
|
||||||
l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)
|
l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)
|
||||||
{
|
{
|
||||||
@ -127,7 +135,7 @@ l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex)
|
|||||||
{
|
{
|
||||||
struct l2vpn_if *lif;
|
struct l2vpn_if *lif;
|
||||||
|
|
||||||
LIST_FOREACH(lif, &l2vpn->if_list, entry)
|
RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree)
|
||||||
if (lif->ifindex == ifindex)
|
if (lif->ifindex == ifindex)
|
||||||
return (lif);
|
return (lif);
|
||||||
|
|
||||||
@ -137,13 +145,9 @@ l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex)
|
|||||||
struct l2vpn_if *
|
struct l2vpn_if *
|
||||||
l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname)
|
l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname)
|
||||||
{
|
{
|
||||||
struct l2vpn_if *lif;
|
struct l2vpn_if lif;
|
||||||
|
strlcpy(lif.ifname, ifname, sizeof(lif.ifname));
|
||||||
LIST_FOREACH(lif, &l2vpn->if_list, entry)
|
return (RB_FIND(l2vpn_if_head, &l2vpn->if_tree, &lif));
|
||||||
if (strcmp(lif->ifname, ifname) == 0)
|
|
||||||
return (lif);
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -509,7 +509,7 @@ lde_dispatch_parent(struct thread *thread)
|
|||||||
fatal(NULL);
|
fatal(NULL);
|
||||||
memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
|
memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
|
||||||
|
|
||||||
LIST_INIT(&nl2vpn->if_list);
|
RB_INIT(&nl2vpn->if_tree);
|
||||||
LIST_INIT(&nl2vpn->pw_list);
|
LIST_INIT(&nl2vpn->pw_list);
|
||||||
LIST_INIT(&nl2vpn->pw_inactive_list);
|
LIST_INIT(&nl2vpn->pw_inactive_list);
|
||||||
|
|
||||||
@ -521,7 +521,7 @@ lde_dispatch_parent(struct thread *thread)
|
|||||||
memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
|
memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
|
||||||
|
|
||||||
nlif->l2vpn = nl2vpn;
|
nlif->l2vpn = nl2vpn;
|
||||||
LIST_INSERT_HEAD(&nl2vpn->if_list, nlif, entry);
|
RB_INSERT(l2vpn_if_head, &nl2vpn->if_tree, nlif);
|
||||||
break;
|
break;
|
||||||
case IMSG_RECONF_L2VPN_PW:
|
case IMSG_RECONF_L2VPN_PW:
|
||||||
if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
|
if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
|
||||||
|
@ -354,7 +354,7 @@ ldp_l2vpn_config_write(struct vty *vty)
|
|||||||
vty_out(vty, " bridge %s%s", l2vpn->br_ifname,
|
vty_out(vty, " bridge %s%s", l2vpn->br_ifname,
|
||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
|
|
||||||
LIST_FOREACH(lif, &l2vpn->if_list, entry)
|
RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree)
|
||||||
vty_out(vty, " member interface %s%s", lif->ifname,
|
vty_out(vty, " member interface %s%s", lif->ifname,
|
||||||
VTY_NEWLINE);
|
VTY_NEWLINE);
|
||||||
|
|
||||||
@ -1369,7 +1369,7 @@ ldp_vty_l2vpn_interface(struct vty *vty, struct vty_arg *args[])
|
|||||||
if (lif == NULL)
|
if (lif == NULL)
|
||||||
goto cancel;
|
goto cancel;
|
||||||
|
|
||||||
LIST_REMOVE(lif, entry);
|
RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
|
||||||
free(lif);
|
free(lif);
|
||||||
ldp_reload(vty_conf);
|
ldp_reload(vty_conf);
|
||||||
return (CMD_SUCCESS);
|
return (CMD_SUCCESS);
|
||||||
@ -1392,7 +1392,7 @@ ldp_vty_l2vpn_interface(struct vty *vty, struct vty_arg *args[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
lif = l2vpn_if_new(l2vpn, &kif);
|
lif = l2vpn_if_new(l2vpn, &kif);
|
||||||
LIST_INSERT_HEAD(&l2vpn->if_list, lif, entry);
|
RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, lif);
|
||||||
|
|
||||||
ldp_reload_ref(vty_conf, (void **)&l2vpn);
|
ldp_reload_ref(vty_conf, (void **)&l2vpn);
|
||||||
|
|
||||||
@ -1723,8 +1723,8 @@ l2vpn_del_api(struct ldpd_conf *conf, struct l2vpn *l2vpn)
|
|||||||
struct l2vpn_if *lif;
|
struct l2vpn_if *lif;
|
||||||
struct l2vpn_pw *pw;
|
struct l2vpn_pw *pw;
|
||||||
|
|
||||||
while ((lif = LIST_FIRST(&l2vpn->if_list)) != NULL) {
|
while ((lif = RB_ROOT(&l2vpn->if_tree)) != NULL) {
|
||||||
LIST_REMOVE(lif, entry);
|
RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
|
||||||
free(lif);
|
free(lif);
|
||||||
}
|
}
|
||||||
while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) {
|
while ((pw = LIST_FIRST(&l2vpn->pw_list)) != NULL) {
|
||||||
@ -1759,14 +1759,14 @@ l2vpn_if_new_api(struct ldpd_conf *conf, struct l2vpn *l2vpn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
lif = l2vpn_if_new(l2vpn, &kif);
|
lif = l2vpn_if_new(l2vpn, &kif);
|
||||||
LIST_INSERT_HEAD(&l2vpn->if_list, lif, entry);
|
RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, lif);
|
||||||
return (lif);
|
return (lif);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
l2vpn_if_del_api(struct l2vpn_if *lif)
|
l2vpn_if_del_api(struct l2vpn *l2vpn, struct l2vpn_if *lif)
|
||||||
{
|
{
|
||||||
LIST_REMOVE(lif, entry);
|
RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
|
||||||
free(lif);
|
free(lif);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
ldpd/ldpd.c
22
ldpd/ldpd.c
@ -914,7 +914,7 @@ main_imsg_send_config(struct ldpd_conf *xconf)
|
|||||||
sizeof(*l2vpn)) == -1)
|
sizeof(*l2vpn)) == -1)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
LIST_FOREACH(lif, &l2vpn->if_list, entry) {
|
RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree) {
|
||||||
if (main_imsg_compose_both(IMSG_RECONF_L2VPN_IF, lif,
|
if (main_imsg_compose_both(IMSG_RECONF_L2VPN_IF, lif,
|
||||||
sizeof(*lif)) == -1)
|
sizeof(*lif)) == -1)
|
||||||
return (-1);
|
return (-1);
|
||||||
@ -1094,15 +1094,15 @@ ldp_dup_config_ref(struct ldpd_conf *conf, void **ref)
|
|||||||
}
|
}
|
||||||
RB_FOREACH(l2vpn, l2vpn_head, &conf->l2vpn_tree) {
|
RB_FOREACH(l2vpn, l2vpn_head, &conf->l2vpn_tree) {
|
||||||
COPY(xl, l2vpn);
|
COPY(xl, l2vpn);
|
||||||
LIST_INIT(&xl->if_list);
|
RB_INIT(&xl->if_tree);
|
||||||
LIST_INIT(&xl->pw_list);
|
LIST_INIT(&xl->pw_list);
|
||||||
LIST_INIT(&xl->pw_inactive_list);
|
LIST_INIT(&xl->pw_inactive_list);
|
||||||
RB_INSERT(l2vpn_head, &xconf->l2vpn_tree, xl);
|
RB_INSERT(l2vpn_head, &xconf->l2vpn_tree, xl);
|
||||||
|
|
||||||
LIST_FOREACH(lif, &l2vpn->if_list, entry) {
|
RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree) {
|
||||||
COPY(xf, lif);
|
COPY(xf, lif);
|
||||||
xf->l2vpn = xl;
|
xf->l2vpn = xl;
|
||||||
LIST_INSERT_HEAD(&xl->if_list, xf, entry);
|
RB_INSERT(l2vpn_if_head, &xl->if_tree, xf);
|
||||||
}
|
}
|
||||||
LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
|
LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
|
||||||
COPY(xp, pw);
|
COPY(xp, pw);
|
||||||
@ -1523,7 +1523,7 @@ merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf, void **ref)
|
|||||||
ldpe_l2vpn_exit(l2vpn);
|
ldpe_l2vpn_exit(l2vpn);
|
||||||
break;
|
break;
|
||||||
case PROC_MAIN:
|
case PROC_MAIN:
|
||||||
LIST_FOREACH(lif, &l2vpn->if_list, entry)
|
RB_FOREACH(lif, l2vpn_if_head, &l2vpn->if_tree)
|
||||||
QOBJ_UNREG (lif);
|
QOBJ_UNREG (lif);
|
||||||
LIST_FOREACH(pw, &l2vpn->pw_list, entry)
|
LIST_FOREACH(pw, &l2vpn->pw_list, entry)
|
||||||
QOBJ_UNREG (pw);
|
QOBJ_UNREG (pw);
|
||||||
@ -1578,27 +1578,27 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl, void
|
|||||||
previous_mtu = l2vpn->mtu;
|
previous_mtu = l2vpn->mtu;
|
||||||
|
|
||||||
/* merge intefaces */
|
/* merge intefaces */
|
||||||
LIST_FOREACH_SAFE(lif, &l2vpn->if_list, entry, ftmp) {
|
RB_FOREACH_SAFE(lif, l2vpn_if_head, &l2vpn->if_tree, ftmp) {
|
||||||
/* find deleted interfaces */
|
/* find deleted interfaces */
|
||||||
if ((xf = l2vpn_if_find_name(xl, lif->ifname)) == NULL) {
|
if ((xf = l2vpn_if_find_name(xl, lif->ifname)) == NULL) {
|
||||||
if (ldpd_process == PROC_MAIN)
|
if (ldpd_process == PROC_MAIN)
|
||||||
QOBJ_UNREG (lif);
|
QOBJ_UNREG (lif);
|
||||||
LIST_REMOVE(lif, entry);
|
RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif);
|
||||||
free(lif);
|
free(lif);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LIST_FOREACH_SAFE(xf, &xl->if_list, entry, ftmp) {
|
RB_FOREACH_SAFE(xf, l2vpn_if_head, &xl->if_tree, ftmp) {
|
||||||
/* find new interfaces */
|
/* find new interfaces */
|
||||||
if ((lif = l2vpn_if_find_name(l2vpn, xf->ifname)) == NULL) {
|
if ((lif = l2vpn_if_find_name(l2vpn, xf->ifname)) == NULL) {
|
||||||
LIST_REMOVE(xf, entry);
|
RB_REMOVE(l2vpn_if_head, &xl->if_tree, xf);
|
||||||
LIST_INSERT_HEAD(&l2vpn->if_list, xf, entry);
|
RB_INSERT(l2vpn_if_head, &l2vpn->if_tree, xf);
|
||||||
xf->l2vpn = l2vpn;
|
xf->l2vpn = l2vpn;
|
||||||
if (ldpd_process == PROC_MAIN)
|
if (ldpd_process == PROC_MAIN)
|
||||||
QOBJ_REG (xf, l2vpn_if);
|
QOBJ_REG (xf, l2vpn_if);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIST_REMOVE(xf, entry);
|
RB_REMOVE(l2vpn_if_head, &xl->if_tree, xf);
|
||||||
if (ref && *ref == xf)
|
if (ref && *ref == xf)
|
||||||
*ref = lif;
|
*ref = lif;
|
||||||
free(xf);
|
free(xf);
|
||||||
|
@ -325,13 +325,15 @@ DECLARE_QOBJ_TYPE(nbr_params)
|
|||||||
#define F_NBRP_GTSM_HOPS 0x04
|
#define F_NBRP_GTSM_HOPS 0x04
|
||||||
|
|
||||||
struct l2vpn_if {
|
struct l2vpn_if {
|
||||||
LIST_ENTRY(l2vpn_if) entry;
|
RB_ENTRY(l2vpn_if) entry;
|
||||||
struct l2vpn *l2vpn;
|
struct l2vpn *l2vpn;
|
||||||
char ifname[IF_NAMESIZE];
|
char ifname[IF_NAMESIZE];
|
||||||
unsigned int ifindex;
|
unsigned int ifindex;
|
||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
QOBJ_FIELDS
|
QOBJ_FIELDS
|
||||||
};
|
};
|
||||||
|
RB_HEAD(l2vpn_if_head, l2vpn_if);
|
||||||
|
RB_PROTOTYPE(l2vpn_if_head, l2vpn_if, entry, l2vpn_if_compare);
|
||||||
DECLARE_QOBJ_TYPE(l2vpn_if)
|
DECLARE_QOBJ_TYPE(l2vpn_if)
|
||||||
|
|
||||||
struct l2vpn_pw {
|
struct l2vpn_pw {
|
||||||
@ -365,7 +367,7 @@ struct l2vpn {
|
|||||||
int mtu;
|
int mtu;
|
||||||
char br_ifname[IF_NAMESIZE];
|
char br_ifname[IF_NAMESIZE];
|
||||||
unsigned int br_ifindex;
|
unsigned int br_ifindex;
|
||||||
LIST_HEAD(, l2vpn_if) if_list;
|
struct l2vpn_if_head if_tree;
|
||||||
LIST_HEAD(, l2vpn_pw) pw_list;
|
LIST_HEAD(, l2vpn_pw) pw_list;
|
||||||
LIST_HEAD(, l2vpn_pw) pw_inactive_list;
|
LIST_HEAD(, l2vpn_pw) pw_inactive_list;
|
||||||
QOBJ_FIELDS
|
QOBJ_FIELDS
|
||||||
@ -651,7 +653,8 @@ void l2vpn_del_api(struct ldpd_conf *conf,
|
|||||||
struct l2vpn *l2vpn);
|
struct l2vpn *l2vpn);
|
||||||
struct l2vpn_if *l2vpn_if_new_api(struct ldpd_conf *conf,
|
struct l2vpn_if *l2vpn_if_new_api(struct ldpd_conf *conf,
|
||||||
struct l2vpn *l2vpn, const char *ifname);
|
struct l2vpn *l2vpn, const char *ifname);
|
||||||
void l2vpn_if_del_api(struct l2vpn_if *lif);
|
void l2vpn_if_del_api(struct l2vpn *l2vpn,
|
||||||
|
struct l2vpn_if *lif);
|
||||||
struct l2vpn_pw *l2vpn_pw_new_api(struct ldpd_conf *conf,
|
struct l2vpn_pw *l2vpn_pw_new_api(struct ldpd_conf *conf,
|
||||||
struct l2vpn *l2vpn, const char *ifname);
|
struct l2vpn *l2vpn, const char *ifname);
|
||||||
void l2vpn_pw_del_api(struct l2vpn_pw *pw);
|
void l2vpn_pw_del_api(struct l2vpn_pw *pw);
|
||||||
|
@ -452,7 +452,7 @@ ldpe_dispatch_main(struct thread *thread)
|
|||||||
fatal(NULL);
|
fatal(NULL);
|
||||||
memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
|
memcpy(nl2vpn, imsg.data, sizeof(struct l2vpn));
|
||||||
|
|
||||||
LIST_INIT(&nl2vpn->if_list);
|
RB_INIT(&nl2vpn->if_tree);
|
||||||
LIST_INIT(&nl2vpn->pw_list);
|
LIST_INIT(&nl2vpn->pw_list);
|
||||||
LIST_INIT(&nl2vpn->pw_inactive_list);
|
LIST_INIT(&nl2vpn->pw_inactive_list);
|
||||||
|
|
||||||
@ -464,7 +464,7 @@ ldpe_dispatch_main(struct thread *thread)
|
|||||||
memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
|
memcpy(nlif, imsg.data, sizeof(struct l2vpn_if));
|
||||||
|
|
||||||
nlif->l2vpn = nl2vpn;
|
nlif->l2vpn = nl2vpn;
|
||||||
LIST_INSERT_HEAD(&nl2vpn->if_list, nlif, entry);
|
RB_INSERT(l2vpn_if_head, &nl2vpn->if_tree, nlif);
|
||||||
break;
|
break;
|
||||||
case IMSG_RECONF_L2VPN_PW:
|
case IMSG_RECONF_L2VPN_PW:
|
||||||
if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
|
if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
|
||||||
|
Loading…
Reference in New Issue
Block a user