diff options
author | Mark Stapp <mjs@voltanet.io> | 2021-03-10 16:36:46 +0100 |
---|---|---|
committer | Mark Stapp <mjs@voltanet.io> | 2021-06-11 15:30:09 +0200 |
commit | 0d145d47c89263caeb2ae21fe09ac6d5e99de789 (patch) | |
tree | e5e8ead9d7c1df3c4243d0bc29972abdc2e66566 /zebra | |
parent | zebra: add boolean to control pw reachability checking (diff) | |
download | frr-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.c | 124 |
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; } |