]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: Add `--asic-offload` command
authorDonald Sharp <sharpd@nvidia.com>
Mon, 28 Sep 2020 19:22:52 +0000 (15:22 -0400)
committerDonald Sharp <sharpd@nvidia.com>
Sun, 15 Nov 2020 15:19:25 +0000 (10:19 -0500)
Add a command that allows FRR to know it's being used with
an underlying asic offload, from the linux kernel perspective.

Signed-off-by: Donald Sharp <sharpd@nvidia.com>
doc/user/zebra.rst
zebra/connected.c
zebra/main.c
zebra/rt_netlink.c
zebra/zebra_rib.c
zebra/zebra_router.c
zebra/zebra_router.h
zebra/zebra_vty.c

index 624e3cfe1a3ac4c1cf64253683160cbd4023cf94..5c7f4ac7731cbc07e89b3af971f5be47f1ac43f9 100644 (file)
@@ -72,6 +72,19 @@ Besides the common invocation options (:ref:`common-invocation-options`), the
    option and we will use Route Replace Semantics instead of delete
    than add.
 
+.. option:: --asic-offload [notify_on_offload|notify_on_ack]
+
+   The linux kernel has the ability to use asic-offload ( see switchdev
+   development ).  When the operator knows that FRR will be working in
+   this way, allow them to specify this with FRR.  At this point this
+   code only supports asynchronous notification of the offload state.
+   In other words the initial ACK received for linux kernel installation
+   does not give zebra any data about what the state of the offload
+   is.  This option takes the optional paramegers notify_on_offload
+   or notify_on_ack.  This signals to zebra to notify upper level
+   protocols about route installation/update on ack received from
+   the linux kernel or from offload notification.
+
 .. _interface-commands:
 
 Configuration Addresses behaviour
index 6a1efc3e65d4cc168262fe7a60eb2271c27a7d59..70ea2e38050d01dba382cb55dcc5a53d4053c44a 100644 (file)
@@ -41,6 +41,7 @@
 #include "zebra/zebra_mpls.h"
 #include "zebra/debug.h"
 #include "zebra/zebra_errors.h"
+#include "zebra/zebra_router.h"
 
 /* communicate the withdrawal of a connected address */
 static void connected_withdraw(struct connected *ifc)
@@ -207,6 +208,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
        };
        struct zebra_vrf *zvrf;
        uint32_t metric;
+       uint32_t flags = 0;
 
        zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
        if (!zvrf) {
@@ -251,11 +253,22 @@ void connected_up(struct interface *ifp, struct connected *ifc)
 
        metric = (ifc->metric < (uint32_t)METRIC_MAX) ?
                                ifc->metric : ifp->metric;
-       rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
-               0, 0, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0);
 
-       rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
-               0, 0, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0);
+       /*
+        * Since we are hand creating the connected routes
+        * in our main routing table, *if* we are working
+        * in an offloaded environment then we need to
+        * pretend like the route is offloaded so everything
+        * else will work
+        */
+       if (zrouter.asic_offloaded)
+               flags |= ZEBRA_FLAG_OFFLOADED;
+
+       rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
+               flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0);
+
+       rib_add(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
+               flags, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0);
 
        /* Schedule LSP forwarding entries for processing, if appropriate. */
        if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
index ced29e1a25fc1550d8c0292b0ecdaab1ea4b6474..55fd3244cb022c89bb1bbbcc0509d09424f47016 100644 (file)
@@ -83,6 +83,8 @@ uint32_t nl_rcvbufsize = 4194304;
 #endif /* HAVE_NETLINK */
 
 #define OPTION_V6_RR_SEMANTICS 2000
+#define OPTION_ASIC_OFFLOAD    2001
+
 /* Command line options. */
 const struct option longopts[] = {
        {"batch", no_argument, NULL, 'b'},
@@ -92,6 +94,7 @@ const struct option longopts[] = {
        {"retain", no_argument, NULL, 'r'},
        {"vrfdefaultname", required_argument, NULL, 'o'},
        {"graceful_restart", required_argument, NULL, 'K'},
+       {"asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD},
 #ifdef HAVE_NETLINK
        {"vrfwnetns", no_argument, NULL, 'n'},
        {"nl-bufsize", required_argument, NULL, 's'},
@@ -281,6 +284,8 @@ int main(int argc, char **argv)
        char *vrf_default_name_configured = NULL;
        struct sockaddr_storage dummy;
        socklen_t dummylen;
+       bool asic_offload = false;
+       bool notify_on_ack = true;
 
        graceful_restart = 0;
        vrf_configure_backend(VRF_BACKEND_VRF_LITE);
@@ -301,6 +306,7 @@ int main(int argc, char **argv)
                "  -r, --retain             When program terminates, retain added route by zebra.\n"
                "  -o, --vrfdefaultname     Set default VRF name.\n"
                "  -K, --graceful_restart   Graceful restart at the kernel level, timer in seconds for expiration\n"
+               "  -A, --asic-offload       FRR is interacting with an asic underneath the linux kernel\n"
 #ifdef HAVE_NETLINK
                "  -n, --vrfwnetns          Use NetNS as VRF backend\n"
                "  -s, --nl-bufsize         Set netlink receive buffer size\n"
@@ -366,6 +372,13 @@ int main(int argc, char **argv)
                case OPTION_V6_RR_SEMANTICS:
                        v6_rr_semantics = true;
                        break;
+               case OPTION_ASIC_OFFLOAD:
+                       if (!strcmp(optarg, "notify_on_offload"))
+                               notify_on_ack = false;
+                       if (!strcmp(optarg, "notify_on_ack"))
+                               notify_on_ack = true;
+                       asic_offload = true;
+                       break;
 #endif /* HAVE_NETLINK */
                default:
                        frr_help_exit(1);
@@ -376,7 +389,7 @@ int main(int argc, char **argv)
        zrouter.master = frr_init();
 
        /* Zebra related initialize. */
-       zebra_router_init();
+       zebra_router_init(asic_offload, notify_on_ack);
        zserv_init();
        rib_init();
        zebra_if_init();
index c0c1c4e7f26531dd48ff21b10d4b4827f56a3a62..3402edf467b3ec4d3b9358a49eabe73e68b883cb 100644 (file)
@@ -642,7 +642,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
 
        selfroute = is_selfroute(rtm->rtm_protocol);
 
-       if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE) {
+       if (!startup && selfroute
+           && h->nlmsg_type == RTM_NEWROUTE
+           && !zrouter.asic_offloaded) {
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug("Route type: %d Received that we think we have originated, ignoring",
                                   rtm->rtm_protocol);
index b688704962d880cae7197e5bdd700bf4e4dba100..569b23573c9297cce90e30a6ab6a9c9fef525702 100644 (file)
@@ -1821,8 +1821,12 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                                        "%s(%u):%pFX Stale dplane result for re %p",
                                        VRF_LOGNAME(vrf),
                                        dplane_ctx_get_vrf(ctx), dest_pfx, re);
-               } else
-                       UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+               } else {
+                       if (!zrouter.asic_offloaded ||
+                           (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED) ||
+                            CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED)))
+                               UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+               }
        }
 
        if (old_re) {
@@ -1899,8 +1903,23 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                                zvrf->installs++;
 
                        /* Notify route owner */
-                       zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED);
-
+                       if (zebra_router_notify_on_ack())
+                               zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED);
+                       else {
+                               if (re) {
+                                       if (CHECK_FLAG(re->flags,
+                                                      ZEBRA_FLAG_OFFLOADED))
+                                               zsend_route_notify_owner_ctx(
+                                                       ctx,
+                                                       ZAPI_ROUTE_INSTALLED);
+                                       if (CHECK_FLAG(
+                                                   re->flags,
+                                                   ZEBRA_FLAG_OFFLOAD_FAILED))
+                                               zsend_route_notify_owner_ctx(
+                                                       ctx,
+                                                       ZAPI_ROUTE_FAIL_INSTALL);
+                               }
+                       }
                } else {
                        if (re) {
                                SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
@@ -2067,7 +2086,8 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
        }
 
        /* Ensure we clear the QUEUED flag */
-       UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+       if (!zrouter.asic_offloaded)
+               UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
 
        /* Is this a notification that ... matters? We mostly care about
         * the route that is currently selected for installation; we may also
index fc4390f7f84479dc9d178e51838bb9406a1d55ed..249ec38a69bffa626eb8a6269b8613ba1f343449 100644 (file)
@@ -257,7 +257,12 @@ void zebra_router_terminate(void)
        hash_free(zrouter.iptable_hash);
 }
 
-void zebra_router_init(void)
+bool zebra_router_notify_on_ack(void)
+{
+       return !zrouter.asic_offloaded || zrouter.notify_on_ack;
+}
+
+void zebra_router_init(bool asic_offload, bool notify_on_ack)
 {
        zrouter.sequence_num = 0;
 
@@ -291,5 +296,6 @@ void zebra_router_init(void)
                hash_create_size(8, zebra_nhg_id_key, zebra_nhg_hash_id_equal,
                                 "Zebra Router Nexthop Groups ID index");
 
-       zrouter.asic_offloaded = false;
+       zrouter.asic_offloaded = asic_offload;
+       zrouter.notify_on_ack = notify_on_ack;
 }
index 8651a01e9fec06320b20ea4c63948bb9f589c8c7..08c5fcaf8d982d787a40b182a376c19d2190f1f0 100644 (file)
@@ -210,13 +210,14 @@ struct zebra_router {
         * Does the underlying system provide an asic offload
         */
        bool asic_offloaded;
+       bool notify_on_ack;
 };
 
 #define GRACEFUL_RESTART_TIME 60
 
 extern struct zebra_router zrouter;
 
-extern void zebra_router_init(void);
+extern void zebra_router_init(bool asic_offload, bool notify_on_ack);
 extern void zebra_router_cleanup(void);
 extern void zebra_router_terminate(void);
 
@@ -255,6 +256,8 @@ extern void multicast_mode_ipv4_set(enum multicast_mode mode);
 
 extern enum multicast_mode multicast_mode_ipv4_get(void);
 
+extern bool zebra_router_notify_on_ack(void);
+
 /* zebra_northbound.c */
 extern const struct frr_yang_module_info frr_zebra_info;
 
index 68487ea245549ff99621f4a53896a1925bc9d164..20f271a147c55a28a8ddafd8c053a8949577da13 100644 (file)
@@ -204,6 +204,10 @@ static char re_status_output_char(const struct route_entry *re,
                                star_p = true;
                }
 
+               if (zrouter.asic_offloaded &&
+                   CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
+                       return 'q';
+
                if (zrouter.asic_offloaded
                    && CHECK_FLAG(re->flags, ZEBRA_FLAG_TRAPPED))
                        return 't';