]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: include backup nexthops in nexthop-tracking
authorMark Stapp <mjs@voltanet.io>
Wed, 27 May 2020 16:53:20 +0000 (12:53 -0400)
committerMark Stapp <mjs@voltanet.io>
Tue, 7 Jul 2020 17:14:01 +0000 (13:14 -0400)
Include backup nexthops when examining routes that resolve
NHT requests. Include installed backups when sending nexthops
in zapi messages to client daemons.

Signed-off-by: Mark Stapp <mjs@voltanet.io>
zebra/zebra_rnh.c

index 20af96a55771dda4441a386e77ab5ab1c3c094a9..d1a5cf2a9d332fcdef28d7546b60301cde054f7a 100644 (file)
@@ -419,7 +419,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf,
                                at_least_one++; /* at least one valid NH */
                        else {
                                SET_FLAG(nexthop->flags,
-                                               NEXTHOP_FLAG_RNH_FILTERED);
+                                        NEXTHOP_FLAG_RNH_FILTERED);
                        }
                }
        }
@@ -458,12 +458,12 @@ zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi,
 
        if (IS_ZEBRA_DEBUG_NHT_DETAILED) {
                char buf[PREFIX_STRLEN];
-               char buf1[PREFIX_STRLEN];
+               char buf1[SRCDEST2STR_BUFFER];
 
                zlog_debug("%s: %u:%s Resolved Import Entry to %s", __func__,
                           rnh->vrf_id,
                           prefix2str(&rnh->node->p, buf, sizeof(buf)),
-                          srcdest_rnode2str(rn, buf1, sizeof(buf)));
+                          srcdest_rnode2str(rn, buf1, sizeof(buf1)));
        }
 
        /* Identify appropriate route entry. */
@@ -974,12 +974,131 @@ static void copy_state(struct rnh *rnh, const struct route_entry *re,
        state->vrf_id = re->vrf_id;
        state->status = re->status;
 
-       state->nhe = zebra_nhg_alloc();
+       state->nhe = zebra_nhe_copy(re->nhe, 0);
+
+       /* Copy the 'fib' nexthops also, if present - we want to capture
+        * the true installed nexthops.
+        */
+       if (re->fib_ng.nexthop)
+               nexthop_group_copy(&state->fib_ng, &re->fib_ng);
+       if (re->fib_backup_ng.nexthop)
+               nexthop_group_copy(&state->fib_backup_ng, &re->fib_backup_ng);
 
-       nexthop_group_copy(&(state->nhe->nhg), &(re->nhe->nhg));
        rnh->state = state;
 }
 
+/*
+ * Compare two route_entries' nexthops.
+ */
+static bool compare_valid_nexthops(struct route_entry *r1,
+                                  struct route_entry *r2)
+{
+       bool matched_p = false;
+       struct nexthop_group *nhg1, *nhg2;
+       struct nexthop *nh1, *nh2;
+
+       /* Account for backup nexthops and for the 'fib' nexthop lists,
+        * if present.
+        */
+       nhg1 = rib_get_fib_nhg(r1);
+       nhg2 = rib_get_fib_nhg(r2);
+
+       nh1 = nhg1->nexthop;
+       nh2 = nhg2->nexthop;
+
+       while (1) {
+               /* Find each list's next valid nexthop */
+               while ((nh1 != NULL) && !rnh_nexthop_valid(r1, nh1))
+                       nh1 = nexthop_next(nh1);
+
+               while ((nh2 != NULL) && !rnh_nexthop_valid(r2, nh2))
+                       nh2 = nexthop_next(nh2);
+
+               if (nh1 && nh2) {
+                       /* Any difference is a no-match */
+                       if (nexthop_cmp(nh1, nh2) != 0) {
+                               if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                                       zlog_debug("%s: nh1, nh2 differ",
+                                                  __func__);
+                               goto done;
+                       }
+
+                       nh1 = nexthop_next(nh1);
+                       nh2 = nexthop_next(nh2);
+               } else if (nh1 || nh2) {
+                       /* One list has more valid nexthops than the other */
+                       if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                               zlog_debug("%s: nh1 %s, nh2 %s", __func__,
+                                          nh1 ? "non-NULL" : "NULL",
+                                          nh2 ? "non-NULL" : "NULL");
+                       goto done;
+               } else
+                       break; /* Done with both lists */
+       }
+
+       /* The test for the backups is slightly different: the only installed
+        * backups will be in the 'fib' list.
+        */
+       nhg1 = rib_get_fib_backup_nhg(r1);
+       if (nhg1 == zebra_nhg_get_backup_nhg(r1->nhe))
+               nhg1 = NULL;
+
+       nhg2 = rib_get_fib_backup_nhg(r2);
+       if (nhg2 == zebra_nhg_get_backup_nhg(r2->nhe))
+               nhg2 = NULL;
+
+       if (nhg1)
+               nh1 = nhg1->nexthop;
+       else
+               nh1 = NULL;
+
+       if (nhg2)
+               nh2 = nhg2->nexthop;
+       else
+               nh2 = NULL;
+
+       while (1) {
+               /* Find each backup list's next valid nexthop */
+               while ((nh1 != NULL) && !rnh_nexthop_valid(r1, nh1))
+                       nh1 = nexthop_next(nh1);
+
+               while ((nh2 != NULL) && !rnh_nexthop_valid(r2, nh2))
+                       nh2 = nexthop_next(nh2);
+
+               if (nh1 && nh2) {
+                       /* Any difference is a no-match */
+                       if (nexthop_cmp(nh1, nh2) != 0) {
+                               if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                                       zlog_debug("%s: backup nh1, nh2 differ",
+                                                  __func__);
+                               goto done;
+                       }
+
+                       nh1 = nexthop_next(nh1);
+                       nh2 = nexthop_next(nh2);
+               } else if (nh1 || nh2) {
+                       /* One list has more valid nexthops than the other */
+                       if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+                               zlog_debug("%s: backup nh1 %s, nh2 %s",
+                                          __func__,
+                                          nh1 ? "non-NULL" : "NULL",
+                                          nh2 ? "non-NULL" : "NULL");
+                       goto done;
+               } else
+                       break; /* Done with both lists */
+       }
+
+       /* Well, it's a match */
+       if (IS_ZEBRA_DEBUG_NHT_DETAILED)
+               zlog_debug("%s: matched", __func__);
+
+       matched_p = true;
+
+done:
+
+       return matched_p;
+}
+
 static int compare_state(struct route_entry *r1, struct route_entry *r2)
 {
        if (!r1 && !r2)
@@ -994,12 +1113,7 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2)
        if (r1->metric != r2->metric)
                return 1;
 
-       if (nexthop_group_nexthop_num(&(r1->nhe->nhg))
-           != nexthop_group_nexthop_num(&(r2->nhe->nhg)))
-               return 1;
-
-       if (nexthop_group_hash(&(r1->nhe->nhg)) !=
-           nexthop_group_hash(&(r2->nhe->nhg)))
+       if (!compare_valid_nexthops(r1, r2))
                return 1;
 
        return 0;
@@ -1044,6 +1158,7 @@ static int send_client(struct rnh *rnh, struct zserv *client,
        }
        if (re) {
                struct zapi_nexthop znh;
+               struct nexthop_group *nhg;
 
                stream_putc(s, re->type);
                stream_putw(s, re->instance);
@@ -1052,7 +1167,9 @@ static int send_client(struct rnh *rnh, struct zserv *client,
                num = 0;
                nump = stream_get_endp(s);
                stream_putc(s, 0);
-               for (ALL_NEXTHOPS(re->nhe->nhg, nh))
+
+               nhg = rib_get_fib_nhg(re);
+               for (ALL_NEXTHOPS_PTR(nhg, nh))
                        if (rnh_nexthop_valid(re, nh)) {
                                zapi_nexthop_from_nexthop(&znh, nh);
                                ret = zapi_nexthop_encode(s, &znh, 0/*flags*/);
@@ -1061,6 +1178,21 @@ static int send_client(struct rnh *rnh, struct zserv *client,
 
                                num++;
                        }
+
+               nhg = rib_get_fib_backup_nhg(re);
+               if (nhg == zebra_nhg_get_backup_nhg(re->nhe))
+                       nhg = NULL;
+
+               if (nhg) {
+                       for (ALL_NEXTHOPS_PTR(nhg, nh))
+                               if (rnh_nexthop_valid(re, nh)) {
+                                       zapi_nexthop_from_nexthop(&znh, nh);
+                                       zapi_nexthop_encode(s, &znh,
+                                                           0 /* flags */);
+                                       num++;
+                               }
+               }
+
                stream_putc_at(s, nump, num);
        } else {
                stream_putc(s, 0); // type