]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: wip: early version of dplane result handler
authorMark Stapp <mjs@voltanet.io>
Tue, 26 Jun 2018 18:28:58 +0000 (14:28 -0400)
committerMark Stapp <mjs@voltanet.io>
Thu, 25 Oct 2018 12:34:30 +0000 (08:34 -0400)
Early try at a result handler for async dplane route updates

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

index 620dfef3b398b5e2a131ce050a27215ec75de27d..c99b5d784fbdd5873b19c427172444d99b77f772 100644 (file)
@@ -1868,6 +1868,252 @@ static void rib_process(struct route_node *rn)
        rib_gc_dest(rn);
 }
 
+/*
+ * Utility to match route with dplane context data
+ */
+static bool rib_route_match_ctx(const struct route_entry *re,
+                               const dplane_ctx_h ctx, bool is_update)
+{
+       bool result = false;
+
+       if (is_update) {
+               /*
+                * In 'update' case, we test info about the 'previous' or
+                * 'old' route
+                */
+               if ((re->type == dplane_ctx_get_old_type(ctx)) &&
+                   (re->instance == dplane_ctx_get_old_instance(ctx))) {
+                       result = true;
+
+                       /* TODO -- we're using this extra test, but it's not
+                        * exactly clear why.
+                        */
+                       if (re->type == ZEBRA_ROUTE_STATIC &&
+                           (re->distance != dplane_ctx_get_old_distance(ctx) ||
+                            re->tag != dplane_ctx_get_old_tag(ctx))) {
+                               result = false;
+                       }
+               }
+
+       } else {
+               /*
+                * Ordinary, single-route case using primary context info
+                */
+               if ((dplane_ctx_get_op(ctx) != DPLANE_OP_ROUTE_DELETE) &&
+                   CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) {
+                       /* Skip route that's been deleted */
+                       goto done;
+               }
+
+               if ((re->type == dplane_ctx_get_type(ctx)) &&
+                   (re->instance == dplane_ctx_get_instance(ctx))) {
+                       result = true;
+
+                       /* TODO -- we're using this extra test, but it's not
+                        * exactly clear why.
+                        */
+                       if (re->type == ZEBRA_ROUTE_STATIC &&
+                           (re->distance != dplane_ctx_get_distance(ctx) ||
+                            re->tag != dplane_ctx_get_tag(ctx))) {
+                               result = false;
+                       }
+               }
+       }
+
+done:
+
+       return (result);
+}
+
+/*
+ * TODO - WIP
+ */
+static void rib_process_after(dplane_ctx_h ctx)
+{
+       struct route_table *table = NULL;
+       struct route_node *rn = NULL;
+       struct route_entry *re = NULL, *old_re = NULL, *rib;
+       bool is_update = false;
+       struct nexthop *nexthop;
+       char dest_str[PREFIX_STRLEN];
+       dplane_op_e op;
+       enum zebra_dplane_result status;
+       const struct prefix *dest_pfx, *src_pfx;
+
+       /* Locate rn and re(s) from ctx */
+
+       table = zebra_vrf_table_with_table_id(dplane_ctx_get_afi(ctx),
+                                             dplane_ctx_get_safi(ctx),
+                                             dplane_ctx_get_vrf(ctx),
+                                             dplane_ctx_get_table(ctx));
+       if (table == NULL) {
+               if (IS_ZEBRA_DEBUG_DPLANE) {
+                       zlog_debug("Failed to process dplane results: no table "
+                                  "for afi %d, safi %d, vrf %u",
+                                  dplane_ctx_get_afi(ctx),
+                                  dplane_ctx_get_safi(ctx),
+                                  dplane_ctx_get_vrf(ctx));
+               }
+               goto done;
+       }
+
+       dest_pfx = dplane_ctx_get_dest(ctx);
+
+       /* Note well: only capturing the prefix string if debug is enabled here;
+        * unconditional log messages will have to generate the string.
+        */
+       if (IS_ZEBRA_DEBUG_DPLANE) {
+               prefix2str(dest_pfx, dest_str, sizeof(dest_str));
+       }
+
+       src_pfx = dplane_ctx_get_src(ctx);
+       rn = srcdest_rnode_get(table, dplane_ctx_get_dest(ctx),
+                              src_pfx ? (struct prefix_ipv6 * )src_pfx : NULL);
+       if (rn == NULL) {
+               if (IS_ZEBRA_DEBUG_DPLANE) {
+                       zlog_debug("Failed to process dplane results: no "
+                                  "route for %u:%s",
+                                  dplane_ctx_get_vrf(ctx), dest_str);
+               }
+               goto done;
+       }
+
+       srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx);
+
+       op = dplane_ctx_get_op(ctx);
+       status = dplane_ctx_get_status(ctx);
+
+       if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+               zlog_debug("%u:%s Processing dplane ctx %p, op %s result %d",
+                          dplane_ctx_get_vrf(ctx), dest_str, ctx,
+                          dplane_op2str(op), status);
+       }
+
+       if (op == DPLANE_OP_ROUTE_DELETE) {
+               /*
+                * In the delete case, the zebra core datastructs were
+                * updated (or removed) at the time the delete was issued,
+                * so we're just notifying the route owner.
+                */
+               if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
+                       zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED);
+               } else {
+                       zsend_route_notify_owner_ctx(ctx,
+                                                    ZAPI_ROUTE_FAIL_INSTALL);
+
+                       zlog_warn("%u:%s: Route Deletion failure",
+                                 dplane_ctx_get_vrf(ctx),
+                                 prefix2str(dest_pfx,
+                                            dest_str, sizeof(dest_str)));
+               }
+
+               /* Nothing more to do in delete case */
+               goto done;
+       }
+
+       /*
+        * Update is a bit of a special case, where we may have both old and new
+        * routes to post-process.
+        */
+       is_update = dplane_ctx_is_update(ctx);
+
+       /*
+        * Take a pass through the routes, look for matches with the context
+        * info.
+        */
+       RNODE_FOREACH_RE(rn, rib) {
+
+               if (re == NULL) {
+                       if (rib_route_match_ctx(rib, ctx, false)) {
+                               re = rib;
+                       }
+               }
+
+               /* Check for old route match */
+               if (is_update && (old_re == NULL)) {
+                       if (rib_route_match_ctx(rib, ctx, true /*is_update*/)) {
+                               old_re = rib;
+                       }
+               }
+
+               /* Have we found the routes we need to work on? */
+               if (re && ((!is_update || old_re))) {
+                       break;
+               }
+       }
+
+       /*
+        * Check sequence number(s) to detect stale results before continuing
+        */
+       if (re && (re->dplane_sequence != dplane_ctx_get_seq(ctx))) {
+               if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+                       zlog_debug("%u:%s Stale dplane result for re %p",
+                                  dplane_ctx_get_vrf(ctx), dest_str, re);
+               }
+               re = NULL;
+       }
+
+       if (old_re &&
+           (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx))) {
+               if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
+                       zlog_debug("%u:%s Stale dplane result for old_re %p",
+                                  dplane_ctx_get_vrf(ctx), dest_str, old_re);
+               }
+               old_re = NULL;
+       }
+
+       /*
+        * Here's sort of a tough one: the route update result is stale.
+        * Is it better to use the context block info to generate
+        * redist and owner notification, or is it better to wait
+        * for the up-to-date result to arrive?
+        */
+       if (re == NULL) {
+               /* TODO -- for now, only expose up-to-date results */
+               goto done;
+       }
+
+       if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
+               /* Set nexthop FIB flags */
+               for (ALL_NEXTHOPS(re->ng, nexthop)) {
+                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+                               continue;
+
+                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+                       else
+                               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+               }
+
+               /* Redistribute */
+               /* TODO -- still calling the redist api using the route_entries,
+                * and there's a corner-case here: if there's no client
+                * for the 'new' route, a redist deleting the 'old' route
+                * will be sent. But if the 'old' context info was stale,
+                * 'old_re' will be NULL here and that delete will not be sent.
+                */
+               redistribute_update(dest_pfx, src_pfx, re, old_re);
+
+               /* Notify route owner */
+               zsend_route_notify_owner(re,
+                                        dest_pfx, ZAPI_ROUTE_INSTALLED);
+
+       } else {
+               zsend_route_notify_owner(re, dest_pfx,
+                                        ZAPI_ROUTE_FAIL_INSTALL);
+
+               zlog_warn("%u:%s: Route install failed",
+                         dplane_ctx_get_vrf(ctx),
+                         prefix2str(dest_pfx,
+                                    dest_str, sizeof(dest_str)));
+       }
+
+done:
+
+       /* Return context to dataplane module */
+       dplane_ctx_fini(&ctx);
+}
+
 /* Take a list of route_node structs and return 1, if there was a record
  * picked from it and processed by rib_process(). Don't process more,
  * than one RN record; operate only in the specified sub-queue.
@@ -3029,7 +3275,7 @@ static int rib_process_dplane_results(struct thread *thread)
                pthread_mutex_unlock(&dplane_mutex);
 
                if (ctx) {
-                       dplane_ctx_fini(&ctx);
+                       rib_process_after(ctx);
                } else {
                        break;
                }