ldpd: fix pseudowire merge algorithm

The previous algorithm wasn't failsafe for full configuration reloads
where several pseudowires can be inserted or removed at the same
time. This patch introduces a much simpler logic that solves the problem
in a better way.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
Renato Westphal 2017-03-25 20:57:03 -03:00
parent 52bd4c2321
commit 5c3f00af13
3 changed files with 40 additions and 52 deletions

View File

@ -201,6 +201,24 @@ l2vpn_pw_find(struct l2vpn *l2vpn, const char *ifname)
return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_inactive_tree, &s));
}
struct l2vpn_pw *
l2vpn_pw_find_active(struct l2vpn *l2vpn, const char *ifname)
{
struct l2vpn_pw s;
strlcpy(s.ifname, ifname, sizeof(s.ifname));
return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_tree, &s));
}
struct l2vpn_pw *
l2vpn_pw_find_inactive(struct l2vpn *l2vpn, const char *ifname)
{
struct l2vpn_pw s;
strlcpy(s.ifname, ifname, sizeof(s.ifname));
return (RB_FIND(l2vpn_pw_head, &l2vpn->pw_inactive_tree, &s));
}
void
l2vpn_pw_init(struct l2vpn_pw *pw)
{

View File

@ -217,6 +217,8 @@ struct l2vpn_if *l2vpn_if_find(struct l2vpn *, const char *);
void l2vpn_if_update(struct l2vpn_if *);
struct l2vpn_pw *l2vpn_pw_new(struct l2vpn *, struct kif *);
struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, const char *);
struct l2vpn_pw *l2vpn_pw_find_active(struct l2vpn *, const char *);
struct l2vpn_pw *l2vpn_pw_find_inactive(struct l2vpn *, const char *);
void l2vpn_pw_init(struct l2vpn_pw *);
void l2vpn_pw_exit(struct l2vpn_pw *);
void l2vpn_pw_reset(struct l2vpn_pw *);

View File

@ -1591,6 +1591,22 @@ merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf)
}
}
RB_FOREACH_SAFE(xl, l2vpn_head, &xconf->l2vpn_tree, ltmp) {
struct l2vpn_pw *xp, *ptmp;
/* check if the pseudowires should be enabled or disabled */
RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_tree, ptmp) {
if (xp->lsr_id.s_addr != INADDR_ANY && xp->pwid != 0)
continue;
RB_REMOVE(l2vpn_pw_head, &xl->pw_tree, xp);
RB_INSERT(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
}
RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_inactive_tree, ptmp) {
if (xp->lsr_id.s_addr == INADDR_ANY || xp->pwid == 0)
continue;
RB_REMOVE(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
RB_INSERT(l2vpn_pw_head, &xl->pw_tree, xp);
}
/* find new l2vpns */
if ((l2vpn = l2vpn_find(conf, xl->name)) == NULL) {
RB_REMOVE(l2vpn_head, &xconf->l2vpn_tree, xl);
@ -1624,7 +1640,6 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
struct l2vpn_pw *pw, *ptmp, *xp;
struct nbr *nbr;
int reset_nbr, reinstall_pwfec, reinstall_tnbr;
struct l2vpn_pw_head pw_aux_list;
int previous_pw_type, previous_mtu;
previous_pw_type = l2vpn->pw_type;
@ -1656,10 +1671,9 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
}
/* merge active pseudowires */
RB_INIT(&pw_aux_list);
RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_tree, ptmp) {
/* find deleted active pseudowires */
if ((xp = l2vpn_pw_find(xl, pw->ifname)) == NULL) {
if ((xp = l2vpn_pw_find_active(xl, pw->ifname)) == NULL) {
switch (ldpd_process) {
case PROC_LDE_ENGINE:
l2vpn_pw_exit(pw);
@ -1678,7 +1692,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
}
RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_tree, ptmp) {
/* find new active pseudowires */
if ((pw = l2vpn_pw_find(l2vpn, xp->ifname)) == NULL) {
if ((pw = l2vpn_pw_find_active(l2vpn, xp->ifname)) == NULL) {
RB_REMOVE(l2vpn_pw_head, &xl->pw_tree, xp);
RB_INSERT(l2vpn_pw_head, &l2vpn->pw_tree, xp);
xp->l2vpn = l2vpn;
@ -1718,28 +1732,6 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
else
reinstall_pwfec = 0;
/* check if the pseudowire should be disabled */
if (xp->lsr_id.s_addr == INADDR_ANY || xp->pwid == 0) {
reinstall_tnbr = 0;
reset_nbr = 0;
reinstall_pwfec = 0;
switch (ldpd_process) {
case PROC_LDE_ENGINE:
l2vpn_pw_exit(pw);
break;
case PROC_LDP_ENGINE:
ldpe_l2vpn_pw_exit(pw);
break;
case PROC_MAIN:
break;
}
/* remove from active list */
RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
RB_INSERT(l2vpn_pw_head, &pw_aux_list, pw);
}
if (ldpd_process == PROC_LDP_ENGINE) {
if (reinstall_tnbr)
ldpe_l2vpn_pw_exit(pw);
@ -1788,7 +1780,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
/* merge inactive pseudowires */
RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree, ptmp) {
/* find deleted inactive pseudowires */
if ((xp = l2vpn_pw_find(xl, pw->ifname)) == NULL) {
if ((xp = l2vpn_pw_find_inactive(xl, pw->ifname)) == NULL) {
RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
if (ldpd_process == PROC_MAIN)
QOBJ_UNREG (pw);
@ -1797,7 +1789,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
}
RB_FOREACH_SAFE(xp, l2vpn_pw_head, &xl->pw_inactive_tree, ptmp) {
/* find new inactive pseudowires */
if ((pw = l2vpn_pw_find(l2vpn, xp->ifname)) == NULL) {
if ((pw = l2vpn_pw_find_inactive(l2vpn, xp->ifname)) == NULL) {
RB_REMOVE(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, xp);
xp->l2vpn = l2vpn;
@ -1815,34 +1807,10 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
pw->ifindex = xp->ifindex;
pw->flags = xp->flags;
/* check if the pseudowire should be activated */
if (pw->lsr_id.s_addr != INADDR_ANY && pw->pwid != 0) {
/* remove from inactive list */
RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
RB_INSERT(l2vpn_pw_head, &l2vpn->pw_tree, pw);
switch (ldpd_process) {
case PROC_LDE_ENGINE:
l2vpn_pw_init(pw);
break;
case PROC_LDP_ENGINE:
ldpe_l2vpn_pw_init(pw);
break;
case PROC_MAIN:
break;
}
}
RB_REMOVE(l2vpn_pw_head, &xl->pw_inactive_tree, xp);
free(xp);
}
/* insert pseudowires that were disabled in the inactive list */
RB_FOREACH_SAFE(pw, l2vpn_pw_head, &pw_aux_list, ptmp) {
RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_tree, pw);
RB_INSERT(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw);
}
l2vpn->pw_type = xl->pw_type;
l2vpn->mtu = xl->mtu;
strlcpy(l2vpn->br_ifname, xl->br_ifname, sizeof(l2vpn->br_ifname));