From patchwork Mon Mar 13 13:36:52 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 738136 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 3vhfBF5Sxcz9s0Z for ; Tue, 14 Mar 2017 00:40:05 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 21E1CBE4; Mon, 13 Mar 2017 13:37:32 +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 5109CBCC for ; Mon, 13 Mar 2017 13:37:26 +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 5824716D for ; Mon, 13 Mar 2017 13:37:23 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 13 Mar 2017 15:37:20 +0200 Received: from r-vnc05.mtr.labs.mlnx (r-vnc05.mtr.labs.mlnx [10.208.0.115]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id v2DDbJZ7028197; Mon, 13 Mar 2017 15:37:19 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Mon, 13 Mar 2017 15:36:52 +0200 Message-Id: <1489412234-30916-3-git-send-email-roid@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1489412234-30916-1-git-send-email-roid@mellanox.com> References: <1489412234-30916-1-git-send-email-roid@mellanox.com> X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,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 , Jiri Pirko , Marcelo Ricardo Leitner , Simon Horman , Or Gerlitz , Andy Gospodarek Subject: [ovs-dev] [PATCH ovs V4 02/24] 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 Signed-off-by: Paul Blakey Reviewed-by: Roi Dayan --- 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 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 + +#include "netdev-tc-offloads.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 {