summaryrefslogtreecommitdiffstats
path: root/zebra
diff options
context:
space:
mode:
authorMark Stapp <mjs@voltanet.io>2021-03-10 16:36:46 +0100
committerMark Stapp <mjs@voltanet.io>2021-06-11 15:30:09 +0200
commit0d145d47c89263caeb2ae21fe09ac6d5e99de789 (patch)
treee5e8ead9d7c1df3c4243d0bc29972abdc2e66566 /zebra
parentzebra: add boolean to control pw reachability checking (diff)
downloadfrr-0d145d47c89263caeb2ae21fe09ac6d5e99de789.tar.xz
frr-0d145d47c89263caeb2ae21fe09ac6d5e99de789.zip
zebra: revise pw reachability logic
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>
Diffstat (limited to 'zebra')
-rw-r--r--zebra/zebra_pw.c124
1 files changed, 111 insertions, 13 deletions
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index 5afb3e592..6b4a81515 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -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,
@@ -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) {
@@ -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;
}