From patchwork Tue Jun 13 15:03:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 775289 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wnCpb34jKz9s81 for ; Wed, 14 Jun 2017 01:09:11 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 40E53BED; Tue, 13 Jun 2017 15:04:36 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 0820ABD0 for ; Tue, 13 Jun 2017 15:04:33 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp1.linuxfoundation.org (Postfix) with ESMTP id 86D0D1B4 for ; Tue, 13 Jun 2017 15:04:25 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 13 Jun 2017 18:04:21 +0300 Received: from dev-r-vrt-189.mtr.labs.mlnx (dev-r-vrt-189.mtr.labs.mlnx [10.212.189.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id v5DF4Kua027434; Tue, 13 Jun 2017 18:04:21 +0300 From: Roi Dayan To: dev@openvswitch.org Date: Tue, 13 Jun 2017 18:03:28 +0300 Message-Id: <1497366235-20892-7-git-send-email-roid@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1497366235-20892-1-git-send-email-roid@mellanox.com> References: <1497366235-20892-1-git-send-email-roid@mellanox.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Shahar Klein , Hadar Hen Zion , Rony Efraim , Flavio Leitner , Jiri Pirko , Marcelo Ricardo Leitner , Simon Horman , Or Gerlitz , Andy Gospodarek Subject: [ovs-dev] [PATCH V11 06/33] netdev: Adding a new netdev API to be used for offloading flows X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org From: Paul Blakey 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 Reviewed-by: Roi Dayan Reviewed-by: Simon Horman Acked-by: Flavio Leitner --- 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 +#include "netdev-tc-offloads.h" +#include +#include +#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 {