[ovs-dev] [PATCH V11 06/33] netdev: Adding a new netdev API to be used for offloading flows
Roi Dayan
roid at mellanox.com
Tue Jun 13 15:03:28 UTC 2017
From: Paul Blakey <paulb at mellanox.com>
Add a new API interface for offloading dpif flows to netdev.
The API consist on the following:
flow_put - offload a new flow
flow_get - query an offloaded flow
flow_del - delete an offloaded flow
flow_flush - flush all offloaded flows
flow_dump_* - dump all offloaded flows
In upcoming commits we will introduce an implementation of this
API for netdev-linux.
Signed-off-by: Paul Blakey <paulb at mellanox.com>
Reviewed-by: Roi Dayan <roid at mellanox.com>
Reviewed-by: Simon Horman <simon.horman at netronome.com>
Acked-by: Flavio Leitner <fbl at sysclose.org>
---
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 | 72 ++++++++++++++++++++++++++++++
lib/netdev-tc-offloads.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++
lib/netdev-tc-offloads.h | 42 +++++++++++++++++
lib/netdev-vport.c | 11 ++++-
lib/netdev.c | 91 +++++++++++++++++++++++++++++++++++++
lib/netdev.h | 23 ++++++++++
12 files changed, 379 insertions(+), 5 deletions(-)
create mode 100644 lib/netdev-tc-offloads.c
create mode 100644 lib/netdev-tc-offloads.h
diff --git a/lib/automake.mk b/lib/automake.mk
index 0ac4708..54a1032 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -358,6 +358,8 @@ lib_libopenvswitch_la_SOURCES += \
lib/if-notifier.h \
lib/netdev-linux.c \
lib/netdev-linux.h \
+ lib/netdev-tc-offloads.c \
+ lib/netdev-tc-offloads.h \
lib/netlink-conntrack.c \
lib/netlink-conntrack.h \
lib/netlink-notifier.c \
diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index c51646a..f863a18 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -1548,6 +1548,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 b770b70..e8de47a 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -3303,6 +3303,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 d973d7e..d189a86 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -1414,6 +1414,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 c8145c6..44dfac5 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -54,6 +54,7 @@
#include "hash.h"
#include "openvswitch/hmap.h"
#include "netdev-provider.h"
+#include "netdev-tc-offloads.h"
#include "netdev-vport.h"
#include "netlink-notifier.h"
#include "netlink-socket.h"
@@ -2796,7 +2797,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 */ \
@@ -2865,6 +2867,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 =
@@ -2873,7 +2877,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(
@@ -2881,7 +2886,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(
@@ -2889,7 +2895,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..79143d2 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,68 @@ 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. */
+
+ /* Flush all offloaded flows from a netdev.
+ * Return 0 if successful, otherwise returns a positive errno value. */
+ int (*flow_flush)(struct netdev *);
+
+ /* Flow dumping interface.
+ *
+ * This is the back-end for the flow dumping interface described in
+ * dpif.h. Please read the comments there first, because this code
+ * closely follows it.
+ *
+ * On success returns 0 and allocates data, on failure returns
+ * positive errno. */
+ int (*flow_dump_create)(struct netdev *, struct netdev_flow_dump **dump);
+ int (*flow_dump_destroy)(struct netdev_flow_dump *);
+
+ /* Returns true if there are more flows to dump.
+ * 'rbuffer' is used as a temporary buffer and needs to be pre allocated
+ * by the caller. While there are more flows the same 'rbuffer'
+ * should be provided. 'wbuffer' is used to store dumped actions and needs
+ * to be pre allocated by the caller. */
+ 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 on netdev.
+ * To modify a flow, use the same ufid.
+ * 'actions' are in netlink format, as with struct dpif_flow_put.
+ * 'info' is extra info needed to offload the flow.
+ * 'stats' is populated according to the rules set out in the description
+ * above 'struct dpif_flow_put'.
+ * Return 0 if successful, otherwise returns a positive errno value. */
+ int (*flow_put)(struct netdev *, struct match *, struct nlattr *actions,
+ size_t actions_len, const ovs_u128 *ufid,
+ struct offload_info *info, struct dpif_flow_stats *);
+
+ /* Queries a flow specified by ufid on netdev.
+ * Fills output buffer as 'wbuffer' in flow_dump_next, which
+ * needs to be be pre allocated.
+ * Return 0 if successful, otherwise returns a positive errno value. */
+ int (*flow_get)(struct netdev *, struct match *, struct nlattr **actions,
+ const ovs_u128 *ufid, struct dpif_flow_stats *,
+ struct ofpbuf *wbuffer);
+
+ /* Delete a flow specified by ufid from netdev.
+ * 'stats' is populated according to the rules set out in the description
+ * above 'struct dpif_flow_del'.
+ * Return 0 if successful, otherwise returns a positive errno value. */
+ int (*flow_del)(struct netdev *, const ovs_u128 *ufid,
+ struct dpif_flow_stats *);
+
+ /* Initializies the netdev flow api.
+ * Return 0 if successful, otherwise returns a positive errno value. */
+ int (*init_flow_api)(struct netdev *);
};
int netdev_register_provider(const struct netdev_class *);
@@ -788,4 +858,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..d050adb
--- /dev/null
+++ b/lib/netdev-tc-offloads.c
@@ -0,0 +1,114 @@
+/*
+ * 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 <linux/if_ether.h>
+#include "openvswitch/hmap.h"
+#include "openvswitch/match.h"
+#include "openvswitch/ofpbuf.h"
+#include "openvswitch/thread.h"
+#include "openvswitch/types.h"
+#include "openvswitch/vlog.h"
+#include "netdev-provider.h"
+#include "netlink.h"
+#include "netlink-socket.h"
+#include "odp-netlink.h"
+#include "unaligned.h"
+#include "util.h"
+#include "hash.h"
+#include "dpif.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,
+ const ovs_u128 *ufid OVS_UNUSED,
+ struct offload_info *info OVS_UNUSED,
+ struct dpif_flow_stats *stats OVS_UNUSED)
+{
+ return EOPNOTSUPP;
+}
+
+int
+netdev_tc_flow_get(struct netdev *netdev OVS_UNUSED,
+ struct match *match OVS_UNUSED,
+ struct nlattr **actions OVS_UNUSED,
+ const ovs_u128 *ufid OVS_UNUSED,
+ struct dpif_flow_stats *stats 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..317347e
--- /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-provider.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,
+ const ovs_u128 *, struct offload_info *,
+ struct dpif_flow_stats *);
+int netdev_tc_flow_get(struct netdev *, struct match *,
+ struct nlattr **actions, const ovs_u128 *,
+ struct dpif_flow_stats *, 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 d390f37..fc02438 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -873,7 +873,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 657e07b..21d2b68 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -2020,3 +2020,94 @@ 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;
+
+ return (class->flow_dump_create
+ ? class->flow_dump_create(netdev, dump)
+ : EOPNOTSUPP);
+}
+
+int
+netdev_flow_dump_destroy(struct netdev_flow_dump *dump)
+{
+ const struct netdev_class *class = dump->netdev->netdev_class;
+
+ return (class->flow_dump_destroy
+ ? class->flow_dump_destroy(dump)
+ : 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,
+ const ovs_u128 *ufid, struct offload_info *info,
+ struct dpif_flow_stats *stats)
+{
+ const struct netdev_class *class = netdev->netdev_class;
+
+ return (class->flow_put
+ ? class->flow_put(netdev, match, actions, act_len, ufid,
+ info, stats)
+ : EOPNOTSUPP);
+}
+
+int
+netdev_flow_get(struct netdev *netdev, struct match *match,
+ struct nlattr **actions, const ovs_u128 *ufid,
+ struct dpif_flow_stats *stats, struct ofpbuf *buf)
+{
+ const struct netdev_class *class = netdev->netdev_class;
+
+ return (class->flow_get
+ ? class->flow_get(netdev, match, actions, ufid, stats, 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 416d2b7..87fa32a 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -157,6 +157,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, const ovs_u128 *,
+ struct offload_info *, struct dpif_flow_stats *);
+int netdev_flow_get(struct netdev *, struct match *, struct nlattr **actions,
+ const ovs_u128 *, struct dpif_flow_stats *,
+ struct ofpbuf *wbuffer);
+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 {
--
2.7.4
More information about the dev
mailing list