[ovs-dev,ovs,V4,02/24] netdev: Adding a new netdev api to be used for offloading flows

Submitted by Roi Dayan on March 13, 2017, 1:36 p.m.

Details

Message ID 1489412234-30916-3-git-send-email-roid@mellanox.com
State Superseded
Headers show

Commit Message

Roi Dayan March 13, 2017, 1:36 p.m.
From: Paul Blakey <paulb@mellanox.com>

Signed-off-by: Paul Blakey <paulb@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
---
 lib/automake.mk          |    2 +
 lib/netdev-bsd.c         |    2 +
 lib/netdev-dpdk.c        |    1 +
 lib/netdev-dummy.c       |    2 +
 lib/netdev-linux.c       |   15 +++-
 lib/netdev-linux.h       |    9 +++
 lib/netdev-provider.h    |   53 ++++++++++++++++
 lib/netdev-tc-offloads.c |  154 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/netdev-tc-offloads.h |   42 +++++++++++++
 lib/netdev-vport.c       |   11 +++-
 lib/netdev.c             |   98 +++++++++++++++++++++++++++++
 lib/netdev.h             |   23 +++++++
 12 files changed, 407 insertions(+), 5 deletions(-)
 create mode 100644 lib/netdev-tc-offloads.c
 create mode 100644 lib/netdev-tc-offloads.h

Patch hide | download patch | download mbox

diff --git a/lib/automake.mk b/lib/automake.mk
index a6141ea..66d8ab8 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -353,6 +353,8 @@  lib_libopenvswitch_la_SOURCES += \
 	lib/dpif-netlink.h \
 	lib/tc.h \
 	lib/tc.c \
+	lib/netdev-tc-offloads.h \
+	lib/netdev-tc-offloads.c \
 	lib/if-notifier.c \
 	lib/if-notifier.h \
 	lib/netdev-linux.c \
diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index 94c515d..5b54d79 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -1547,6 +1547,8 @@  netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
     netdev_bsd_rxq_recv,                             \
     netdev_bsd_rxq_wait,                             \
     netdev_bsd_rxq_drain,                            \
+                                                     \
+    NO_OFFLOAD_API                                   \
 }
 
 const struct netdev_class netdev_bsd_class =
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 94568a1..539e388 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -3310,6 +3310,7 @@  unlock:
     RXQ_RECV,                                                 \
     NULL,                       /* rx_wait */                 \
     NULL,                       /* rxq_drain */               \
+    NO_OFFLOAD_API                                            \
 }
 
 static const struct netdev_class dpdk_class =
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 0657434..7e1383f 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -1409,6 +1409,8 @@  netdev_dummy_update_flags(struct netdev *netdev_,
     netdev_dummy_rxq_recv,                                      \
     netdev_dummy_rxq_wait,                                      \
     netdev_dummy_rxq_drain,                                     \
+                                                                \
+    NO_OFFLOAD_API                                              \
 }
 
 static const struct netdev_class dummy_class =
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 085f530..0828d96 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -73,6 +73,7 @@ 
 #include "openvswitch/vlog.h"
 #include "util.h"
 #include "tc.h"
+#include "netdev-tc-offloads.h"
 
 VLOG_DEFINE_THIS_MODULE(netdev_linux);
 
@@ -2762,7 +2763,8 @@  netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
 }
 
 #define NETDEV_LINUX_CLASS(NAME, CONSTRUCT, GET_STATS,          \
-                           GET_FEATURES, GET_STATUS)            \
+                           GET_FEATURES, GET_STATUS,            \
+                           FLOW_OFFLOAD_API)                    \
 {                                                               \
     NAME,                                                       \
     false,                      /* is_pmd */                    \
@@ -2831,6 +2833,8 @@  netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
     netdev_linux_rxq_recv,                                      \
     netdev_linux_rxq_wait,                                      \
     netdev_linux_rxq_drain,                                     \
+                                                                \
+    FLOW_OFFLOAD_API                                            \
 }
 
 const struct netdev_class netdev_linux_class =
@@ -2839,7 +2843,8 @@  const struct netdev_class netdev_linux_class =
         netdev_linux_construct,
         netdev_linux_get_stats,
         netdev_linux_get_features,
-        netdev_linux_get_status);
+        netdev_linux_get_status,
+        LINUX_FLOW_OFFLOAD_API);
 
 const struct netdev_class netdev_tap_class =
     NETDEV_LINUX_CLASS(
@@ -2847,7 +2852,8 @@  const struct netdev_class netdev_tap_class =
         netdev_linux_construct_tap,
         netdev_tap_get_stats,
         netdev_linux_get_features,
-        netdev_linux_get_status);
+        netdev_linux_get_status,
+        NO_OFFLOAD_API);
 
 const struct netdev_class netdev_internal_class =
     NETDEV_LINUX_CLASS(
@@ -2855,7 +2861,8 @@  const struct netdev_class netdev_internal_class =
         netdev_linux_construct,
         netdev_internal_get_stats,
         NULL,                  /* get_features */
-        netdev_internal_get_status);
+        netdev_internal_get_status,
+        NO_OFFLOAD_API);
 
 
 #define CODEL_N_QUEUES 0x0000
diff --git a/lib/netdev-linux.h b/lib/netdev-linux.h
index 0c61bc9..d944691 100644
--- a/lib/netdev-linux.h
+++ b/lib/netdev-linux.h
@@ -28,4 +28,13 @@  struct netdev;
 int netdev_linux_ethtool_set_flag(struct netdev *netdev, uint32_t flag,
                                   const char *flag_name, bool enable);
 
+#define LINUX_FLOW_OFFLOAD_API                                  \
+            netdev_tc_flow_flush,                               \
+            netdev_tc_flow_dump_create,                         \
+            netdev_tc_flow_dump_destroy,                        \
+            netdev_tc_flow_dump_next,                           \
+            netdev_tc_flow_put,                                 \
+            netdev_tc_flow_get,                                 \
+            netdev_tc_flow_del,                                 \
+            netdev_tc_init_flow_api
 #endif /* netdev-linux.h */
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 8346fc4..bde9ef6 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -115,6 +115,14 @@  struct netdev_rxq {
 
 struct netdev *netdev_rxq_get_netdev(const struct netdev_rxq *);
 
+
+struct netdev_flow_dump {
+    struct netdev *netdev;
+    odp_port_t port;
+    struct nl_dump *nl_dump;
+    bool terse;
+};
+
 /* Network device class structure, to be defined by each implementation of a
  * network device.
  *
@@ -769,6 +777,49 @@  struct netdev_class {
 
     /* Discards all packets waiting to be received from 'rx'. */
     int (*rxq_drain)(struct netdev_rxq *rx);
+
+/* ## -------------------------------- ## */
+/* ## netdev flow offloading functions ## */
+/* ## -------------------------------- ## */
+
+/* If a particular netdev class does not support offloading flows, all these
+ * function pointers must be NULL. */
+
+    /* Deleting all offloaded flows from netdev */
+    int (*flow_flush)(struct netdev *);
+    /* Dumping interface:
+     * Usage is as with dpif_port_dump api (create, next, destory).
+     * Create sets dump on success or returns error status on failure. */
+    int (*flow_dump_create)(struct netdev *, struct netdev_flow_dump **dump);
+    int (*flow_dump_destroy)(struct netdev_flow_dump *);
+     /* rbuffer is for use of the implementation (e.g using nl_dump),
+     * and is usually shared for the given thread that runs flow_dump_next.
+     * wbuffer is the buffer that dumped actions will be stored in, and given
+     * pointers to. */
+    bool (*flow_dump_next)(struct netdev_flow_dump *, struct match *,
+                           struct nlattr **actions,
+                           struct dpif_flow_stats *stats, ovs_u128 *ufid,
+                           struct ofpbuf *rbuffer, struct ofpbuf *wbuffer);
+
+    /* Offload the given flow (match, actions, stats, ufid) on netdev.
+     * If stats isn't null, sets the given stats for that flow.
+     * To modify the flow, use the same ufid.
+     * actions are in netlink format, as with struct dpif_flow_put.
+     * info is anything else that is need to offload the flow. */
+    int (*flow_put)(struct netdev *, struct match *, struct nlattr *actions,
+                    size_t actions_len, struct dpif_flow_stats *,
+                    const ovs_u128 *ufid, struct offload_info *info);
+    /* Queries the flow with specified ufid on netdev.
+     * Fills match, actions, stats as with flow_dump_next */
+    int (*flow_get)(struct netdev *, struct match *, struct nlattr **actions,
+                    struct dpif_flow_stats *, const ovs_u128 *ufid,
+                    struct ofpbuf *);
+    /* Deletes the given flow specified by ufid from netdev.
+     * If stats is not null, fills it with flow stats. */
+    int (*flow_del)(struct netdev *, const ovs_u128 *ufid,
+                    struct dpif_flow_stats *);
+    /* Initializies the netdev flow api. */
+    int (*init_flow_api)(struct netdev *);
 };
 
 int netdev_register_provider(const struct netdev_class *);
@@ -788,4 +839,6 @@  extern const struct netdev_class netdev_tap_class;
 }
 #endif
 
+#define NO_OFFLOAD_API NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+
 #endif /* netdev.h */
diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c
new file mode 100644
index 0000000..946c2a6
--- /dev/null
+++ b/lib/netdev-tc-offloads.c
@@ -0,0 +1,154 @@ 
+/*
+ * Copyright (c) 2016 Mellanox Technologies, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "netdev-tc-offloads.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include <linux/filter.h>
+#include <linux/gen_stats.h>
+#include <linux/if_ether.h>
+#include <linux/if_tun.h>
+#include <linux/types.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/pkt_cls.h>
+#include <linux/pkt_sched.h>
+#include <linux/rtnetlink.h>
+#include <linux/sockios.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <netpacket/packet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_packet.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "coverage.h"
+#include "dp-packet.h"
+#include "dpif-netlink.h"
+#include "dpif-netdev.h"
+#include "openvswitch/dynamic-string.h"
+#include "fatal-signal.h"
+#include "hash.h"
+#include "openvswitch/hmap.h"
+#include "netdev-provider.h"
+#include "netdev-vport.h"
+#include "netlink-notifier.h"
+#include "netlink-socket.h"
+#include "netlink.h"
+#include "openvswitch/ofpbuf.h"
+#include "openflow/openflow.h"
+#include "ovs-atomic.h"
+#include "packets.h"
+#include "poll-loop.h"
+#include "rtnetlink.h"
+#include "openvswitch/shash.h"
+#include "netdev-provider.h"
+#include "openvswitch/match.h"
+#include "openvswitch/vlog.h"
+#include "tc.h"
+
+VLOG_DEFINE_THIS_MODULE(netdev_tc_offloads);
+
+int
+netdev_tc_flow_flush(struct netdev *netdev OVS_UNUSED)
+{
+    return EOPNOTSUPP;
+}
+
+int
+netdev_tc_flow_dump_create(struct netdev *netdev,
+                           struct netdev_flow_dump **dump_out)
+{
+    struct netdev_flow_dump *dump = xzalloc(sizeof *dump);
+
+    dump->netdev = netdev_ref(netdev);
+
+    *dump_out = dump;
+
+    return 0;
+}
+
+int
+netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump)
+{
+    netdev_close(dump->netdev);
+    free(dump);
+
+    return 0;
+}
+
+bool
+netdev_tc_flow_dump_next(struct netdev_flow_dump *dump OVS_UNUSED,
+                         struct match *match OVS_UNUSED,
+                         struct nlattr **actions OVS_UNUSED,
+                         struct dpif_flow_stats *stats OVS_UNUSED,
+                         ovs_u128 *ufid OVS_UNUSED,
+                         struct ofpbuf *rbuffer OVS_UNUSED,
+                         struct ofpbuf *wbuffer OVS_UNUSED)
+{
+    return false;
+}
+
+int
+netdev_tc_flow_put(struct netdev *netdev OVS_UNUSED,
+                   struct match *match OVS_UNUSED,
+                   struct nlattr *actions OVS_UNUSED,
+                   size_t actions_len OVS_UNUSED,
+                   struct dpif_flow_stats *stats OVS_UNUSED,
+                   const ovs_u128 *ufid OVS_UNUSED,
+                   struct offload_info *info OVS_UNUSED)
+{
+    return EOPNOTSUPP;
+}
+
+int
+netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED,
+                   struct match *match OVS_UNUSED,
+                   struct nlattr **actions OVS_UNUSED,
+                   struct dpif_flow_stats *stats OVS_UNUSED,
+                   const ovs_u128 *ufid OVS_UNUSED,
+                   struct ofpbuf *buf OVS_UNUSED)
+{
+    return EOPNOTSUPP;
+}
+
+int
+netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED,
+                   const ovs_u128 *ufid OVS_UNUSED,
+                   struct dpif_flow_stats *stats OVS_UNUSED)
+{
+    return EOPNOTSUPP;
+}
+
+int
+netdev_tc_init_flow_api(struct netdev *netdev OVS_UNUSED)
+{
+    return 0;
+}
+
diff --git a/lib/netdev-tc-offloads.h b/lib/netdev-tc-offloads.h
new file mode 100644
index 0000000..47c5d96
--- /dev/null
+++ b/lib/netdev-tc-offloads.h
@@ -0,0 +1,42 @@ 
+/*
+ * Copyright (c) 2016 Mellanox Technologies, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NETDEV_TC_OFFLOADS_H
+#define NETDEV_TC_OFFLOADS_H 1
+
+#include "netdev.h"
+
+int netdev_tc_flow_flush(struct netdev *);
+int netdev_tc_flow_dump_create(struct netdev *, struct netdev_flow_dump **);
+int netdev_tc_flow_dump_destroy(struct netdev_flow_dump *);
+bool netdev_tc_flow_dump_next(struct netdev_flow_dump *, struct match *,
+                              struct nlattr **actions,
+                              struct dpif_flow_stats *,
+                              ovs_u128 *ufid,
+                              struct ofpbuf *rbuffer, struct ofpbuf *wbuffer);
+int netdev_tc_flow_put(struct netdev *, struct match *,
+                       struct nlattr *actions,
+                       size_t actions_len,
+                       struct dpif_flow_stats *, const ovs_u128 *,
+                       struct offload_info *);
+int netdev_tc_flow_get(struct netdev *, struct match *,
+                       struct nlattr **actions, struct dpif_flow_stats *,
+                       const ovs_u128 *, struct ofpbuf *);
+int netdev_tc_flow_del(struct netdev *, const ovs_u128 *,
+                        struct dpif_flow_stats *);
+int netdev_tc_init_flow_api(struct netdev *);
+
+#endif /* netdev-tc-offloads.h */
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 2d0aa43..8cb03e6 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -847,7 +847,16 @@  get_stats(const struct netdev *netdev, struct netdev_stats *stats)
     NULL,                   /* rx_dealloc */                \
     NULL,                   /* rx_recv */                   \
     NULL,                   /* rx_wait */                   \
-    NULL,                   /* rx_drain */
+    NULL,                   /* rx_drain */                  \
+                                                            \
+    NULL,                   /* flow_flush */                \
+    NULL,                   /* flow_dump_create */          \
+    NULL,                   /* flow_dump_destroy */         \
+    NULL,                   /* flow_dump_next */            \
+    NULL,                   /* flow_put */                  \
+    NULL,                   /* flow_get */                  \
+    NULL,                   /* flow_del */                  \
+    NULL,                   /* init_flow_api */
 
 
 #define TUNNEL_CLASS(NAME, DPIF_PORT, BUILD_HEADER, PUSH_HEADER, POP_HEADER)   \
diff --git a/lib/netdev.c b/lib/netdev.c
index a8d8eda..f7b80b2 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -1998,3 +1998,101 @@  netdev_reconfigure(struct netdev *netdev)
             ? class->reconfigure(netdev)
             : EOPNOTSUPP);
 }
+
+int
+netdev_flow_flush(struct netdev *netdev)
+{
+    const struct netdev_class *class = netdev->netdev_class;
+
+    return (class->flow_flush
+            ? class->flow_flush(netdev)
+            : EOPNOTSUPP);
+}
+
+int
+netdev_flow_dump_create(struct netdev *netdev, struct netdev_flow_dump **dump)
+{
+    const struct netdev_class *class = netdev->netdev_class;
+
+    if (class->flow_dump_create) {
+        return class->flow_dump_create(netdev, dump);
+    }
+
+    return EOPNOTSUPP;
+}
+
+int
+netdev_flow_dump_destroy(struct netdev_flow_dump *dump)
+{
+    const struct netdev_class *class = dump->netdev->netdev_class;
+
+    if (class->flow_dump_destroy) {
+        return class->flow_dump_destroy(dump);
+    }
+
+    return EOPNOTSUPP;
+}
+
+bool
+netdev_flow_dump_next(struct netdev_flow_dump *dump,
+                      struct match *match,
+                      struct nlattr **actions,
+                      struct dpif_flow_stats *stats,
+                      ovs_u128 *ufid,
+                      struct ofpbuf *rbuffer,
+                      struct ofpbuf *wbuffer)
+{
+    const struct netdev_class *class = dump->netdev->netdev_class;
+
+    return (class->flow_dump_next
+            ? class->flow_dump_next(dump, match, actions, stats, ufid,
+                                    rbuffer, wbuffer)
+            : false);
+}
+
+int
+netdev_flow_put(struct netdev *netdev, struct match *match,
+                struct nlattr *actions, size_t act_len,
+                struct dpif_flow_stats *stats, const ovs_u128 *ufid,
+                struct offload_info *info)
+{
+    const struct netdev_class *class = netdev->netdev_class;
+
+    return (class->flow_put
+            ? class->flow_put(netdev, match, actions, act_len, stats, ufid,
+                              info)
+            : EOPNOTSUPP);
+}
+
+int
+netdev_flow_get(struct netdev *netdev, struct match *match,
+                struct nlattr **actions, struct dpif_flow_stats *stats,
+                const ovs_u128 *ufid, struct ofpbuf *buf)
+{
+    const struct netdev_class *class = netdev->netdev_class;
+
+    return (class->flow_get
+            ? class->flow_get(netdev, match, actions, stats, ufid, buf)
+            : EOPNOTSUPP);
+}
+
+int
+netdev_flow_del(struct netdev *netdev, const ovs_u128 *ufid,
+                struct dpif_flow_stats *stats)
+{
+    const struct netdev_class *class = netdev->netdev_class;
+
+    return (class->flow_del
+            ? class->flow_del(netdev, ufid, stats)
+            : EOPNOTSUPP);
+}
+
+int
+netdev_init_flow_api(struct netdev *netdev)
+{
+    const struct netdev_class *class = netdev->netdev_class;
+
+    return (class->init_flow_api
+            ? class->init_flow_api(netdev)
+            : EOPNOTSUPP);
+}
diff --git a/lib/netdev.h b/lib/netdev.h
index d6c07c1..6d2db7d 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -156,6 +156,29 @@  int netdev_send(struct netdev *, int qid, struct dp_packet_batch *,
                 bool may_steal, bool concurrent_txq);
 void netdev_send_wait(struct netdev *, int qid);
 
+/* Flow offloading. */
+struct offload_info {
+    const void *port_hmap_obj; /* To query ports info from netdev port map */
+    ovs_be16 tp_dst_port; /* Destination port for tunnel in SET action */
+};
+struct netdev_flow_dump;
+int netdev_flow_flush(struct netdev *);
+int netdev_flow_dump_create(struct netdev *, struct netdev_flow_dump **dump);
+int netdev_flow_dump_destroy(struct netdev_flow_dump *);
+bool netdev_flow_dump_next(struct netdev_flow_dump *, struct match *,
+                          struct nlattr **actions, struct dpif_flow_stats *,
+                          ovs_u128 *ufid, struct ofpbuf *rbuffer,
+                          struct ofpbuf *wbuffer);
+int netdev_flow_put(struct netdev *, struct match *, struct nlattr *actions,
+                    size_t actions_len, struct dpif_flow_stats *,
+                    const ovs_u128 *, struct offload_info *);
+int netdev_flow_get(struct netdev *, struct match *, struct nlattr **actions,
+                    struct dpif_flow_stats *, const ovs_u128 *,
+                    struct ofpbuf *);
+int netdev_flow_del(struct netdev *, const ovs_u128 *,
+                    struct dpif_flow_stats *);
+int netdev_init_flow_api(struct netdev *);
+
 /* native tunnel APIs */
 /* Structure to pass parameters required to build a tunnel header. */
 struct netdev_tnl_build_header_params {