]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: revise pw reachability logic
authorMark Stapp <mjs@voltanet.io>
Wed, 10 Mar 2021 15:36:46 +0000 (10:36 -0500)
committermergify-bot <noreply@mergify.io>
Sat, 24 Jul 2021 17:16:59 +0000 (17:16 +0000)
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>
(cherry picked from commit 0d145d47c89263caeb2ae21fe09ac6d5e99de789)

zebra/zebra_pw.c

index 5afb3e5926ec083b3bf72c7aa1b9e04af46fe979..6b4a815151c3b70389ea32dec6fca2622c4702c0 100644 (file)
@@ -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;
 }