Skip to content

Commit

Permalink
zebra: revise pw reachability logic
Browse files Browse the repository at this point in the history
Modify the pseudowire reachability logic so that it returns
success if there is at least one installed labelled nexthop for
the route resolving the pw destination. We also check for
valid backup nexthops if necessary, in case there's been a
switchover event.
Only OpenBSD requires that _all_ nexthops be labelled, so we
have a more strict version of the logic also.

Signed-off-by: Mark Stapp <mjs@voltanet.io>
  • Loading branch information
Mark Stapp committed Jun 11, 2021
1 parent 6fb3580 commit 0d145d4
Showing 1 changed file with 111 additions and 13 deletions.
124 changes: 111 additions & 13 deletions zebra/zebra_pw.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static int zebra_pw_enabled(struct zebra_pw *);
static void zebra_pw_install(struct zebra_pw *);
static void zebra_pw_uninstall(struct zebra_pw *);
static int zebra_pw_install_retry(struct thread *);
static int zebra_pw_check_reachability(struct zebra_pw *);
static int zebra_pw_check_reachability(const struct zebra_pw *);
static void zebra_pw_update_status(struct zebra_pw *, int);

static inline int zebra_pw_compare(const struct zebra_pw *a,
Expand Down Expand Up @@ -243,14 +243,79 @@ static void zebra_pw_update_status(struct zebra_pw *pw, int status)
zsend_pw_update(pw->client, pw);
}

static int zebra_pw_check_reachability(struct zebra_pw *pw)
static int zebra_pw_check_reachability_strict(const struct zebra_pw *pw,
struct route_entry *re)
{
const struct nexthop *nexthop;
const struct nexthop_group *nhg;
bool found_p = false;
bool fail_p = false;

/* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */

/* All active nexthops must be labelled; look at
* primary and backup fib lists, in case there's been
* a backup nexthop activation.
*/
nhg = rib_get_fib_nhg(re);
if (nhg && nhg->nexthop) {
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;

if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
if (nexthop->nh_label != NULL)
found_p = true;
else {
fail_p = true;
break;
}
}
}
}

if (fail_p)
goto done;

nhg = rib_get_fib_backup_nhg(re);
if (nhg && nhg->nexthop) {
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;

if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
if (nexthop->nh_label != NULL)
found_p = true;
else {
fail_p = true;
break;
}
}
}
}

done:

if (fail_p || !found_p) {
if (IS_ZEBRA_DEBUG_PW)
zlog_debug("%s: unlabeled route for %s",
__func__, pw->ifname);
return -1;
}

return 0;
}

static int zebra_pw_check_reachability(const struct zebra_pw *pw)
{
struct route_entry *re;
struct nexthop *nexthop;
const struct nexthop *nexthop;
const struct nexthop_group *nhg;
bool found_p = false;

/* TODO: consider GRE/L2TPv3 tunnels in addition to MPLS LSPs */

/* find route to the remote end of the pseudowire */
/* Find route to the remote end of the pseudowire */
re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
&pw->nexthop, NULL);
if (!re) {
Expand All @@ -260,19 +325,52 @@ static int zebra_pw_check_reachability(struct zebra_pw *pw)
return -1;
}

/*
* Need to ensure that there's a label binding for all nexthops.
* Otherwise, ECMP for this route could render the pseudowire unusable.
/* Stricter checking for some OSes (OBSD, e.g.) */
if (mpls_pw_reach_strict)
return zebra_pw_check_reachability_strict(pw, re);

/* There must be at least one installed labelled nexthop;
* look at primary and backup fib lists, in case there's been
* a backup nexthop activation.
*/
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
if (!nexthop->nh_label) {
if (IS_ZEBRA_DEBUG_PW)
zlog_debug("%s: unlabeled route for %s",
__func__, pw->ifname);
return -1;
nhg = rib_get_fib_nhg(re);
if (nhg && nhg->nexthop) {
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;

if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
nexthop->nh_label != NULL) {
found_p = true;
break;
}
}
}

if (found_p)
return 0;

nhg = rib_get_fib_backup_nhg(re);
if (nhg && nhg->nexthop) {
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
continue;

if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) &&
nexthop->nh_label != NULL) {
found_p = true;
break;
}
}
}

if (!found_p) {
if (IS_ZEBRA_DEBUG_PW)
zlog_debug("%s: unlabeled route for %s",
__func__, pw->ifname);
return -1;
}

return 0;
}

Expand Down

0 comments on commit 0d145d4

Please sign in to comment.