From patchwork Wed Sep 15 12:43:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1528341 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4H8fz12Kd0z9t0k for ; Wed, 15 Sep 2021 22:43:41 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 38B4D4018B; Wed, 15 Sep 2021 12:43:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id lEDM4cCHfgcc; Wed, 15 Sep 2021 12:43:36 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 13B8D40586; Wed, 15 Sep 2021 12:43:34 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 65FA8C0024; Wed, 15 Sep 2021 12:43:32 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 394DCC001D for ; Wed, 15 Sep 2021 12:43:30 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 6509B60BA9 for ; Wed, 15 Sep 2021 12:43:29 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Ca6P8kTGSwzg for ; Wed, 15 Sep 2021 12:43:28 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp3.osuosl.org (Postfix) with ESMTP id 18ED360B65 for ; Wed, 15 Sep 2021 12:43:27 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Sep 2021 15:43:21 +0300 Received: from c-141-46-1-010.mtl.labs.mlnx (c-141-46-1-010.mtl.labs.mlnx [10.141.46.10]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 18FChLbV010242; Wed, 15 Sep 2021 15:43:21 +0300 To: dev@openvswitch.org Date: Wed, 15 Sep 2021 15:43:13 +0300 Message-Id: <20210915124319.1683219-2-cmi@nvidia.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210915124319.1683219-1-cmi@nvidia.com> References: <20210915124319.1683219-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, simon.horman@netronome.com, roniba@nvidia.com, i.maximets@ovn.org Subject: [ovs-dev] [PATCH v15 1/7] compat: Add psample and tc sample action defines for older kernels X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Chris Mi via dev From: Chris Mi Reply-To: Chris Mi Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Update kernel UAPI to support psample and the tc sample action. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein Acked-by: Eelco Chaudron --- include/linux/automake.mk | 4 ++- include/linux/psample.h | 62 ++++++++++++++++++++++++++++++++ include/linux/tc_act/tc_sample.h | 25 +++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 include/linux/psample.h create mode 100644 include/linux/tc_act/tc_sample.h diff --git a/include/linux/automake.mk b/include/linux/automake.mk index 8f063f482..c48d9699a 100644 --- a/include/linux/automake.mk +++ b/include/linux/automake.mk @@ -7,4 +7,6 @@ noinst_HEADERS += \ include/linux/tc_act/tc_skbedit.h \ include/linux/tc_act/tc_tunnel_key.h \ include/linux/tc_act/tc_vlan.h \ - include/linux/tc_act/tc_ct.h + include/linux/tc_act/tc_ct.h \ + include/linux/tc_act/tc_sample.h \ + include/linux/psample.h diff --git a/include/linux/psample.h b/include/linux/psample.h new file mode 100644 index 000000000..e585db5bf --- /dev/null +++ b/include/linux/psample.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __UAPI_PSAMPLE_H +#define __UAPI_PSAMPLE_H + +enum { + PSAMPLE_ATTR_IIFINDEX, + PSAMPLE_ATTR_OIFINDEX, + PSAMPLE_ATTR_ORIGSIZE, + PSAMPLE_ATTR_SAMPLE_GROUP, + PSAMPLE_ATTR_GROUP_SEQ, + PSAMPLE_ATTR_SAMPLE_RATE, + PSAMPLE_ATTR_DATA, + PSAMPLE_ATTR_GROUP_REFCOUNT, + PSAMPLE_ATTR_TUNNEL, + + PSAMPLE_ATTR_PAD, + PSAMPLE_ATTR_OUT_TC, /* u16 */ + PSAMPLE_ATTR_OUT_TC_OCC, /* u64, bytes */ + PSAMPLE_ATTR_LATENCY, /* u64, nanoseconds */ + PSAMPLE_ATTR_TIMESTAMP, /* u64, nanoseconds */ + PSAMPLE_ATTR_PROTO, /* u16 */ + + __PSAMPLE_ATTR_MAX +}; + +enum psample_command { + PSAMPLE_CMD_SAMPLE, + PSAMPLE_CMD_GET_GROUP, + PSAMPLE_CMD_NEW_GROUP, + PSAMPLE_CMD_DEL_GROUP, +}; + +enum psample_tunnel_key_attr { + PSAMPLE_TUNNEL_KEY_ATTR_ID, /* be64 Tunnel ID */ + PSAMPLE_TUNNEL_KEY_ATTR_IPV4_SRC, /* be32 src IP address. */ + PSAMPLE_TUNNEL_KEY_ATTR_IPV4_DST, /* be32 dst IP address. */ + PSAMPLE_TUNNEL_KEY_ATTR_TOS, /* u8 Tunnel IP ToS. */ + PSAMPLE_TUNNEL_KEY_ATTR_TTL, /* u8 Tunnel IP TTL. */ + PSAMPLE_TUNNEL_KEY_ATTR_DONT_FRAGMENT, /* No argument, set DF. */ + PSAMPLE_TUNNEL_KEY_ATTR_CSUM, /* No argument. CSUM packet. */ + PSAMPLE_TUNNEL_KEY_ATTR_OAM, /* No argument. OAM frame. */ + PSAMPLE_TUNNEL_KEY_ATTR_GENEVE_OPTS, /* Array of Geneve options. */ + PSAMPLE_TUNNEL_KEY_ATTR_TP_SRC, /* be16 src Transport Port. */ + PSAMPLE_TUNNEL_KEY_ATTR_TP_DST, /* be16 dst Transport Port. */ + PSAMPLE_TUNNEL_KEY_ATTR_VXLAN_OPTS, /* Nested VXLAN opts* */ + PSAMPLE_TUNNEL_KEY_ATTR_IPV6_SRC, /* struct in6_addr src IPv6 address. */ + PSAMPLE_TUNNEL_KEY_ATTR_IPV6_DST, /* struct in6_addr dst IPv6 address. */ + PSAMPLE_TUNNEL_KEY_ATTR_PAD, + PSAMPLE_TUNNEL_KEY_ATTR_ERSPAN_OPTS, /* struct erspan_metadata */ + PSAMPLE_TUNNEL_KEY_ATTR_IPV4_INFO_BRIDGE, /* No argument. IPV4_INFO_BRIDGE mode.*/ + __PSAMPLE_TUNNEL_KEY_ATTR_MAX +}; + +/* Can be overridden at runtime by module option */ +#define PSAMPLE_ATTR_MAX (__PSAMPLE_ATTR_MAX - 1) + +#define PSAMPLE_NL_MCGRP_CONFIG_NAME "config" +#define PSAMPLE_NL_MCGRP_SAMPLE_NAME "packets" +#define PSAMPLE_GENL_NAME "psample" +#define PSAMPLE_GENL_VERSION 1 + +#endif diff --git a/include/linux/tc_act/tc_sample.h b/include/linux/tc_act/tc_sample.h new file mode 100644 index 000000000..fee1bcc20 --- /dev/null +++ b/include/linux/tc_act/tc_sample.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_TC_SAMPLE_H +#define __LINUX_TC_SAMPLE_H + +#include +#include +#include + +struct tc_sample { + tc_gen; +}; + +enum { + TCA_SAMPLE_UNSPEC, + TCA_SAMPLE_TM, + TCA_SAMPLE_PARMS, + TCA_SAMPLE_RATE, + TCA_SAMPLE_TRUNC_SIZE, + TCA_SAMPLE_PSAMPLE_GROUP, + TCA_SAMPLE_PAD, + __TCA_SAMPLE_MAX +}; +#define TCA_SAMPLE_MAX (__TCA_SAMPLE_MAX - 1) + +#endif From patchwork Wed Sep 15 12:43:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1528337 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4H8fyv1RGhz9ssD for ; Wed, 15 Sep 2021 22:43:34 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 6839860B89; Wed, 15 Sep 2021 12:43:32 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id l4AykGfMe3u0; Wed, 15 Sep 2021 12:43:31 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id C57BA60AD6; Wed, 15 Sep 2021 12:43:30 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 75AA8C001D; Wed, 15 Sep 2021 12:43:30 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6EC76C0011 for ; Wed, 15 Sep 2021 12:43:29 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 53A2D60BA4 for ; Wed, 15 Sep 2021 12:43:29 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id OcvewYMslUkt for ; Wed, 15 Sep 2021 12:43:28 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp3.osuosl.org (Postfix) with ESMTP id 19D3E60B71 for ; Wed, 15 Sep 2021 12:43:27 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Sep 2021 15:43:21 +0300 Received: from c-141-46-1-010.mtl.labs.mlnx (c-141-46-1-010.mtl.labs.mlnx [10.141.46.10]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 18FChLbW010242; Wed, 15 Sep 2021 15:43:21 +0300 To: dev@openvswitch.org Date: Wed, 15 Sep 2021 15:43:14 +0300 Message-Id: <20210915124319.1683219-3-cmi@nvidia.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210915124319.1683219-1-cmi@nvidia.com> References: <20210915124319.1683219-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, simon.horman@netronome.com, roniba@nvidia.com, i.maximets@ovn.org Subject: [ovs-dev] [PATCH v15 2/7] ovs-kmod-ctl: Load kernel module psample X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Chris Mi via dev From: Chris Mi Reply-To: Chris Mi Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Load kernel module psample to receive sampled packets from TC. Before removing kernel module psample, remove act_sample first. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein Acked-by: Eelco Chaudron --- utilities/ovs-kmod-ctl.in | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/utilities/ovs-kmod-ctl.in b/utilities/ovs-kmod-ctl.in index 19f100964..6fa945a83 100644 --- a/utilities/ovs-kmod-ctl.in +++ b/utilities/ovs-kmod-ctl.in @@ -28,6 +28,14 @@ for dir in "$sbindir" "$bindir" /sbin /bin /usr/sbin /usr/bin; do done insert_mods () { + # Try loading psample kernel module. + modinfo psample > /dev/null 2>&1 + if test $? = 0; then + action "Inserting psample module" modprobe psample + else + log_warning_msg "No psample module, can't offload sFlow action" + fi + # Try loading openvswitch kernel module. action "Inserting openvswitch module" modprobe openvswitch } @@ -95,6 +103,12 @@ remove_kmods() { if test -e /sys/module/vxlan; then action "Forcing removal of vxlan module" rmmod vxlan fi + if test -e /sys/module/act_sample; then + action "Forcing removal of act_sample module" rmmod act_sample + fi + if test -e /sys/module/psample; then + action "Forcing removal of psample module" rmmod psample + fi } usage () { From patchwork Wed Sep 15 12:43:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1528340 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4H8fz10qRjz9ssD for ; Wed, 15 Sep 2021 22:43:40 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 7801D82A2D; Wed, 15 Sep 2021 12:43:34 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id vEoiRe0mxGxw; Wed, 15 Sep 2021 12:43:33 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 74C18829B1; Wed, 15 Sep 2021 12:43:32 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 7E5F3C0023; Wed, 15 Sep 2021 12:43:31 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 22704C0011 for ; Wed, 15 Sep 2021 12:43:30 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 1D6D3401C8 for ; Wed, 15 Sep 2021 12:43:30 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id WlsSVYY8ruu0 for ; Wed, 15 Sep 2021 12:43:28 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp2.osuosl.org (Postfix) with ESMTP id 312E040101 for ; Wed, 15 Sep 2021 12:43:27 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Sep 2021 15:43:21 +0300 Received: from c-141-46-1-010.mtl.labs.mlnx (c-141-46-1-010.mtl.labs.mlnx [10.141.46.10]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 18FChLbX010242; Wed, 15 Sep 2021 15:43:21 +0300 To: dev@openvswitch.org Date: Wed, 15 Sep 2021 15:43:15 +0300 Message-Id: <20210915124319.1683219-4-cmi@nvidia.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210915124319.1683219-1-cmi@nvidia.com> References: <20210915124319.1683219-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, simon.horman@netronome.com, roniba@nvidia.com, i.maximets@ovn.org Subject: [ovs-dev] [PATCH v15 3/7] dpif-offload-provider: Introduce dpif-offload-provider layer X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Chris Mi via dev From: Chris Mi Reply-To: Chris Mi Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Some offload actions require functionality that is not netdev based, but dpif. For example, sFlow action requires to create a psample netlink socket to receive the sampled packets from TC or kernel driver. Create dpif-offload-provider layer to support such actions. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- lib/automake.mk | 2 ++ lib/dpif-netdev.c | 1 + lib/dpif-netlink.c | 2 ++ lib/dpif-offload-provider.h | 47 +++++++++++++++++++++++++++++++++++++ lib/dpif-offload.c | 43 +++++++++++++++++++++++++++++++++ lib/dpif-provider.h | 8 ++++++- lib/dpif.c | 10 ++++++++ 7 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 lib/dpif-offload-provider.h create mode 100644 lib/dpif-offload.c diff --git a/lib/automake.mk b/lib/automake.mk index 46f869a33..9259f57de 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -127,6 +127,8 @@ lib_libopenvswitch_la_SOURCES = \ lib/dpif-netdev-private.h \ lib/dpif-netdev-perf.c \ lib/dpif-netdev-perf.h \ + lib/dpif-offload.c \ + lib/dpif-offload-provider.h \ lib/dpif-provider.h \ lib/dpif.c \ lib/dpif.h \ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 4cd0e9ebd..1645b44b0 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -8801,6 +8801,7 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_bond_add, dpif_netdev_bond_del, dpif_netdev_bond_stats_get, + NULL, /* dpif_offload_api */ }; static void diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 34fc04237..f546b48e5 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -34,6 +34,7 @@ #include "bitmap.h" #include "dpif-netlink-rtnl.h" +#include "dpif-offload-provider.h" #include "dpif-provider.h" #include "fat-rwlock.h" #include "flow.h" @@ -4340,6 +4341,7 @@ const struct dpif_class dpif_netlink_class = { NULL, /* bond_add */ NULL, /* bond_del */ NULL, /* bond_stats_get */ + NULL, /* dpif_offload_api */ }; static int diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h new file mode 100644 index 000000000..75238c4cb --- /dev/null +++ b/lib/dpif-offload-provider.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * 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 DPIF_OFFLOAD_PROVIDER_H +#define DPIF_OFFLOAD_PROVIDER_H + +struct dpif; +struct dpif_offload_sflow; + +/* Datapath interface offload structure, to be defined by each implementation + * of a datapath interface. + */ +struct dpif_offload_api { + /* Called when the dpif provider is registered and right after dpif + * provider init function. */ + void (*init)(void); + + /* Free all dpif offload resources. */ + void (*destroy)(void); + + /* Arranges for the poll loop for an upcall handler to wake up when psample + * has a message queued to be received. */ + void (*sflow_recv_wait)(void); + + /* Polls for an upcall from psample for an upcall handler. + * Return 0 for success. */ + int (*sflow_recv)(struct dpif_offload_sflow *sflow); +}; + +void dpif_offload_sflow_recv_wait(const struct dpif *dpif); +int dpif_offload_sflow_recv(const struct dpif *dpif, + struct dpif_offload_sflow *sflow); + +#endif /* DPIF_OFFLOAD_PROVIDER_H */ diff --git a/lib/dpif-offload.c b/lib/dpif-offload.c new file mode 100644 index 000000000..842e05798 --- /dev/null +++ b/lib/dpif-offload.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * 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 + +#include "dpif-provider.h" + +void +dpif_offload_sflow_recv_wait(const struct dpif *dpif) +{ + const struct dpif_offload_api *offload_api = dpif->dpif_class->offload_api; + + if (offload_api && offload_api->sflow_recv_wait) { + offload_api->sflow_recv_wait(); + } +} + +int +dpif_offload_sflow_recv(const struct dpif *dpif, + struct dpif_offload_sflow *sflow) +{ + const struct dpif_offload_api *offload_api = dpif->dpif_class->offload_api; + + if (offload_api && offload_api->sflow_recv) { + return offload_api->sflow_recv(sflow); + } + + return EOPNOTSUPP; +} diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 7e11b9697..ce20cdeb1 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -22,8 +22,9 @@ * exposed over OpenFlow as a single switch. Datapaths and the collections of * ports that they contain may be fixed or dynamic. */ -#include "openflow/openflow.h" #include "dpif.h" +#include "dpif-offload-provider.h" +#include "openflow/openflow.h" #include "util.h" #ifdef __cplusplus @@ -635,6 +636,11 @@ struct dpif_class { * sufficient to store BOND_BUCKETS number of elements. */ int (*bond_stats_get)(struct dpif *dpif, uint32_t bond_id, uint64_t *n_bytes); + + /* Some offload actions require functionality that is not netdev based, + * but dpif. Add dpif-offload-provider layer API to support such + * offload actions. */ + const struct dpif_offload_api *offload_api; }; extern const struct dpif_class dpif_netlink_class; diff --git a/lib/dpif.c b/lib/dpif.c index 8c4aed47b..13a3cd0d4 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -153,6 +153,10 @@ dp_register_provider__(const struct dpif_class *new_class) return error; } + if (new_class->offload_api && new_class->offload_api->init) { + new_class->offload_api->init(); + } + registered_class = xmalloc(sizeof *registered_class); registered_class->dpif_class = new_class; registered_class->refcount = 0; @@ -183,6 +187,7 @@ static int dp_unregister_provider__(const char *type) { struct shash_node *node; + const struct dpif_class *dpif_class; struct registered_dpif_class *registered_class; node = shash_find(&dpif_classes, type); @@ -196,6 +201,11 @@ dp_unregister_provider__(const char *type) return EBUSY; } + dpif_class = registered_class->dpif_class; + if (dpif_class->offload_api && dpif_class->offload_api->destroy) { + dpif_class->offload_api->destroy(); + } + shash_delete(&dpif_classes, node); free(registered_class); From patchwork Wed Sep 15 12:43:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1528344 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4H8fzJ3Jz0z9sjJ for ; Wed, 15 Sep 2021 22:43:56 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 3422F82CC7; Wed, 15 Sep 2021 12:43:53 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id DBuHctzuj0ui; Wed, 15 Sep 2021 12:43:44 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 3064F82BE7; Wed, 15 Sep 2021 12:43:41 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8BF3DC0039; Wed, 15 Sep 2021 12:43:36 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4493BC0027 for ; Wed, 15 Sep 2021 12:43:32 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id DF76060B89 for ; Wed, 15 Sep 2021 12:43:29 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id uD2t2DbC-2ua for ; Wed, 15 Sep 2021 12:43:29 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp3.osuosl.org (Postfix) with ESMTP id 5A4D460B90 for ; Wed, 15 Sep 2021 12:43:28 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Sep 2021 15:43:21 +0300 Received: from c-141-46-1-010.mtl.labs.mlnx (c-141-46-1-010.mtl.labs.mlnx [10.141.46.10]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 18FChLbY010242; Wed, 15 Sep 2021 15:43:21 +0300 To: dev@openvswitch.org Date: Wed, 15 Sep 2021 15:43:16 +0300 Message-Id: <20210915124319.1683219-5-cmi@nvidia.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210915124319.1683219-1-cmi@nvidia.com> References: <20210915124319.1683219-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, simon.horman@netronome.com, roniba@nvidia.com, i.maximets@ovn.org Subject: [ovs-dev] [PATCH v15 4/7] netdev-offload-tc: Introduce group ID management API X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Chris Mi via dev From: Chris Mi Reply-To: Chris Mi Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" When offloading sample action to TC, userspace creates a unique ID to map sFlow action and tunnel info and passes this ID to kernel instead of the sFlow info. psample will send this ID and sampled packet to userspace. Using the ID, userspace can recover the sFlow info and send sampled packet to the right sFlow monitoring host. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- lib/dpif-offload-provider.h | 17 +++ lib/netdev-offload-tc.c | 247 +++++++++++++++++++++++++++++++++++- lib/netdev-offload.h | 1 + lib/tc.h | 1 + 4 files changed, 260 insertions(+), 6 deletions(-) diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h index 75238c4cb..95c29c0d8 100644 --- a/lib/dpif-offload-provider.h +++ b/lib/dpif-offload-provider.h @@ -17,9 +17,26 @@ #ifndef DPIF_OFFLOAD_PROVIDER_H #define DPIF_OFFLOAD_PROVIDER_H +#include "netlink-protocol.h" +#include "openvswitch/packets.h" +#include "openvswitch/types.h" + struct dpif; struct dpif_offload_sflow; +/* When offloading sample action, userspace creates a unique ID to map + * sFlow action and tunnel info and passes this ID to datapath instead + * of the sFlow info. Datapath will send this ID and sampled packet to + * userspace. Using the ID, userspace can recover the sFlow info and send + * sampled packet to the right sFlow monitoring host. + */ +struct dpif_sflow_attr { + const struct nlattr *action; /* SFlow action. */ + const struct nlattr *userdata; /* Struct user_action_cookie. */ + struct flow_tnl *tunnel; /* Tunnel info. */ + ovs_u128 ufid; /* Flow ufid. */ +}; + /* Datapath interface offload structure, to be defined by each implementation * of a datapath interface. */ diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 9845e8d3f..5d817b6cf 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -40,6 +40,7 @@ #include "unaligned.h" #include "util.h" #include "dpif-provider.h" +#include "cmap.h" VLOG_DEFINE_THIS_MODULE(netdev_offload_tc); @@ -62,6 +63,234 @@ struct chain_node { uint32_t chain; }; +/* This maps a psample group ID to struct dpif_sflow_attr for sFlow */ +struct sgid_node { + struct ovs_list exp_node OVS_GUARDED; + struct cmap_node metadata_node; + struct cmap_node id_node; + struct ovs_refcount refcount; + uint32_t hash; + uint32_t id; + const struct dpif_sflow_attr sflow; +}; + +static struct ovs_rwlock sgid_rwlock = OVS_RWLOCK_INITIALIZER; +static struct cmap sgid_map = CMAP_INITIALIZER; +static struct cmap sgid_metadata_map = CMAP_INITIALIZER; +static struct ovs_list sgid_expiring OVS_GUARDED_BY(sgid_rwlock) + = OVS_LIST_INITIALIZER(&sgid_expiring); +static uint32_t next_sample_group_id OVS_GUARDED_BY(sgid_rwlock) = 1; + +static void +sgid_node_free(struct sgid_node *node) +{ + free(node->sflow.tunnel); + free(CONST_CAST(void *, node->sflow.action)); + free(CONST_CAST(void *, node->sflow.userdata)); + free(node); +} + +/* Lockless RCU protected lookup. If node is needed accross RCU quiescent + * state, caller should copy the contents. */ +static const struct sgid_node * +sgid_find(uint32_t id) +{ + const struct cmap_node *node = cmap_find(&sgid_map, id); + + return node ? CONTAINER_OF(node, const struct sgid_node, id_node) : NULL; +} + +const struct dpif_sflow_attr * +dpif_offload_sflow_attr_find(uint32_t id) +{ + const struct sgid_node *node; + + node = sgid_find(id); + if (!node) { + return NULL; + } + + return &node->sflow; +} + +static uint32_t +dpif_sflow_attr_hash(const struct dpif_sflow_attr *sflow) +{ + return hash_bytes(&sflow->ufid, sizeof sflow->ufid, 0); +} + +static bool +dpif_sflow_attr_equal(const struct dpif_sflow_attr *a, + const struct dpif_sflow_attr *b) +{ + if (!ovs_u128_equals(a->ufid, b->ufid)) { + return false; + } + if (!a->action || !b->action) { + return false; + } + if (a->action->nla_len != b->action->nla_len + || memcmp(a->action, b->action, a->action->nla_len)) { + return false; + } + if (!a->tunnel && !b->tunnel) { + return true; + } + if (!a->tunnel || !b->tunnel) { + return false; + } + + return !memcmp(a->tunnel, b->tunnel, sizeof *a->tunnel); +} + +/* Lockless RCU protected lookup. If node is needed accross RCU quiescent + * state, caller should take a reference. */ +static struct sgid_node * +sgid_find_equal(const struct dpif_sflow_attr *target, uint32_t hash) +{ + struct sgid_node *node; + + CMAP_FOR_EACH_WITH_HASH (node, metadata_node, hash, &sgid_metadata_map) { + if (dpif_sflow_attr_equal(&node->sflow, target)) { + return node; + } + } + return NULL; +} + +static struct sgid_node * +sgid_ref_equal(const struct dpif_sflow_attr *target, uint32_t hash) +{ + struct sgid_node *node; + + do { + node = sgid_find_equal(target, hash); + /* Try again if the node was released before we get the reference. */ + } while (node && !ovs_refcount_try_ref_rcu(&node->refcount)); + + return node; +} + +static void +dpif_sflow_attr_clone(struct dpif_sflow_attr *new, + const struct dpif_sflow_attr *old) +{ + new->action = xmemdup(old->action, old->action->nla_len); + new->userdata = xmemdup(old->userdata, old->userdata->nla_len); + new->tunnel = old->tunnel + ? xmemdup(old->tunnel, sizeof *old->tunnel) + : NULL; + new->ufid = old->ufid; +} + +/* We use the id as the hash value, which works due to cmap internal rehashing. + * We also only insert nodes with unique IDs, so all possible hash collisions + * remain internal to the cmap. */ +static struct sgid_node * +sgid_find__(uint32_t id) + OVS_REQUIRES(sgid_rwlock) +{ + struct cmap_node *node = cmap_find_protected(&sgid_map, id); + + return node ? CONTAINER_OF(node, struct sgid_node, id_node) : NULL; +} + +/* Allocate a unique group id for the given set of flow metadata. The id + * space is 2^^32, but if looping too many times, we still can't find a + * free one, that means something is wrong, return NULL. + */ +#define SGID_ALLOC_RETRY_MAX 8192 +static struct sgid_node * +sgid_alloc__(const struct dpif_sflow_attr *sflow, uint32_t hash) +{ + struct sgid_node *node = xzalloc(sizeof *node); + int i = 0; + + node->hash = hash; + ovs_refcount_init(&node->refcount); + dpif_sflow_attr_clone(CONST_CAST(struct dpif_sflow_attr *, + &node->sflow), sflow); + + ovs_rwlock_wrlock(&sgid_rwlock); + for (;;) { + node->id = next_sample_group_id++; + if (OVS_UNLIKELY(!node->id)) { + next_sample_group_id = 1; + node->id = next_sample_group_id++; + } + /* Find if the id is free. */ + if (OVS_LIKELY(!sgid_find__(node->id))) { + break; + } + if (++i == SGID_ALLOC_RETRY_MAX) { + VLOG_ERR("%s: Can't find a free group ID after %d retries", + __func__, i); + ovs_rwlock_unlock(&sgid_rwlock); + sgid_node_free(node); + return NULL; + } + } + cmap_insert(&sgid_map, &node->id_node, node->id); + cmap_insert(&sgid_metadata_map, &node->metadata_node, node->hash); + ovs_rwlock_unlock(&sgid_rwlock); + return node; +} + +/* Allocate a unique group id for the given set of flow metadata and + optional actions. */ +static uint32_t +sgid_alloc_ctx(const struct dpif_sflow_attr *sflow) +{ + uint32_t hash = dpif_sflow_attr_hash(sflow); + struct sgid_node *node = sgid_ref_equal(sflow, hash); + + if (!node) { + node = sgid_alloc__(sflow, hash); + } + + return node ? node->id : 0; +} + +static void +sgid_node_unref(const struct sgid_node *node_) + OVS_EXCLUDED(sgid_rwlock) +{ + struct sgid_node *node = CONST_CAST(struct sgid_node *, node_); + + ovs_rwlock_wrlock(&sgid_rwlock); + if (node && ovs_refcount_unref(&node->refcount) == 1) { + cmap_remove(&sgid_metadata_map, &node->metadata_node, node->hash); + cmap_remove(&sgid_map, &node->id_node, node->id); + ovsrcu_postpone(sgid_node_free, node); + } + ovs_rwlock_unlock(&sgid_rwlock); +} + +static void +sgid_free(uint32_t id) +{ + const struct sgid_node *node; + + if (!id) { + return; + } + + node = sgid_find(id); + if (node) { + sgid_node_unref(node); + } else { + VLOG_ERR("%s: Freeing nonexistent group ID: %"PRIu32, __func__, id); + } +} + +static int +del_filter_and_sgid(struct tcf_id *id) +{ + sgid_free(id->sample_group_id); + id->sample_group_id = 0; + return tc_del_filter(id); +} + static bool is_internal_port(const char *type) { @@ -198,13 +427,13 @@ del_ufid_tc_mapping(const ovs_u128 *ufid) ovs_mutex_unlock(&ufid_lock); } -/* Wrapper function to delete filter and ufid tc mapping */ +/* Wrapper function to delete filter, sgid and ufid tc mapping */ static int -del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid) +del_filter_sgid_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid) { int err; - err = tc_del_filter(id); + err = del_filter_and_sgid(id); if (!err) { del_ufid_tc_mapping(ufid); } @@ -426,7 +655,7 @@ netdev_tc_flow_flush(struct netdev *netdev) continue; } - err = tc_del_filter(&data->id); + err = del_filter_and_sgid(&data->id); if (!err) { del_ufid_tc_mapping_unlocked(&data->ufid); } @@ -1917,6 +2146,11 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, action->type = TC_ACT_GOTO; action->chain = 0; /* 0 is reserved and not used by recirc. */ flower.action_count++; + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SAMPLE) { + struct dpif_sflow_attr sflow_attr; + + memset(&sflow_attr, 0, sizeof sflow_attr); + sgid_alloc_ctx(&sflow_attr); } else { VLOG_DBG_RL(&rl, "unsupported put action type: %d", nl_attr_type(nla)); @@ -1932,7 +2166,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, if (get_ufid_tc_mapping(ufid, &id) == 0) { VLOG_DBG_RL(&rl, "updating old handle: %d prio: %d", id.handle, id.prio); - info->tc_modify_flow_deleted = !del_filter_and_ufid_mapping(&id, ufid); + info->tc_modify_flow_deleted = !del_filter_sgid_ufid_mapping(&id, + ufid); } prio = get_prio_for_tc_flower(&flower); @@ -2021,7 +2256,7 @@ netdev_tc_flow_del(struct netdev *netdev OVS_UNUSED, } } - error = del_filter_and_ufid_mapping(&id, ufid); + error = del_filter_sgid_ufid_mapping(&id, ufid); return error; } diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h index e7fcedae9..d57d70470 100644 --- a/lib/netdev-offload.h +++ b/lib/netdev-offload.h @@ -138,6 +138,7 @@ int netdev_ports_flow_get(const char *dpif_type, struct match *match, int netdev_ports_get_n_flows(const char *dpif_type, odp_port_t port_no, uint64_t *n_flows); +const struct dpif_sflow_attr *dpif_offload_sflow_attr_find(uint32_t id); #ifdef __cplusplus } #endif diff --git a/lib/tc.h b/lib/tc.h index a147ca461..2e4084f48 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -276,6 +276,7 @@ struct tcf_id { uint32_t chain; uint16_t prio; uint32_t handle; + uint32_t sample_group_id; }; static inline struct tcf_id From patchwork Wed Sep 15 12:43:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1528339 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4H8fz06zWsz9sSs for ; Wed, 15 Sep 2021 22:43:40 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 9F85360BE6; Wed, 15 Sep 2021 12:43:37 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id htWCLFcvAeUK; Wed, 15 Sep 2021 12:43:36 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id 7001760BB0; Wed, 15 Sep 2021 12:43:35 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8640CC0027; Wed, 15 Sep 2021 12:43:33 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4CC7CC0011 for ; Wed, 15 Sep 2021 12:43:30 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 20B62401DA for ; Wed, 15 Sep 2021 12:43:30 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id k-QbkbYkNUbR for ; Wed, 15 Sep 2021 12:43:29 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp4.osuosl.org (Postfix) with ESMTP id 8DED640121 for ; Wed, 15 Sep 2021 12:43:28 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Sep 2021 15:43:21 +0300 Received: from c-141-46-1-010.mtl.labs.mlnx (c-141-46-1-010.mtl.labs.mlnx [10.141.46.10]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 18FChLbZ010242; Wed, 15 Sep 2021 15:43:21 +0300 To: dev@openvswitch.org Date: Wed, 15 Sep 2021 15:43:17 +0300 Message-Id: <20210915124319.1683219-6-cmi@nvidia.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210915124319.1683219-1-cmi@nvidia.com> References: <20210915124319.1683219-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, simon.horman@netronome.com, roniba@nvidia.com, i.maximets@ovn.org Subject: [ovs-dev] [PATCH v15 5/7] dpif-offload-netlink: Implement dpif-offload-provider API X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Chris Mi via dev From: Chris Mi Reply-To: Chris Mi Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Implement dpif-offload API for netlink datapath. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- lib/automake.mk | 1 + lib/dpif-netlink.c | 2 +- lib/dpif-offload-netlink.c | 208 ++++++++++++++++++++++++++++++++++++ lib/dpif-offload-provider.h | 13 ++- 4 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 lib/dpif-offload-netlink.c diff --git a/lib/automake.mk b/lib/automake.mk index 9259f57de..18cffa827 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -446,6 +446,7 @@ lib_libopenvswitch_la_SOURCES += \ lib/dpif-netlink.h \ lib/dpif-netlink-rtnl.c \ lib/dpif-netlink-rtnl.h \ + lib/dpif-offload-netlink.c \ lib/if-notifier.c \ lib/netdev-linux.c \ lib/netdev-linux.h \ diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index f546b48e5..19ae543e6 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -4341,7 +4341,7 @@ const struct dpif_class dpif_netlink_class = { NULL, /* bond_add */ NULL, /* bond_del */ NULL, /* bond_stats_get */ - NULL, /* dpif_offload_api */ + &dpif_offload_netlink, }; static int diff --git a/lib/dpif-offload-netlink.c b/lib/dpif-offload-netlink.c new file mode 100644 index 000000000..fc3712764 --- /dev/null +++ b/lib/dpif-offload-netlink.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * 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 +#include +#include + +#include "dpif-offload-provider.h" +#include "netdev-offload.h" +#include "netlink-protocol.h" +#include "netlink-socket.h" +#include "openvswitch/vlog.h" + +VLOG_DEFINE_THIS_MODULE(dpif_offload_netlink); + +static struct nl_sock *psample_sock; +static int psample_family; + +/* Receive psample netlink message and save the attributes. */ +struct offload_psample { + struct nlattr *packet; /* Packet data. */ + int dp_group_id; /* Mapping id for sFlow offload. */ + int iifindex; /* Input ifindex. */ +}; + +static void +dpif_offload_netlink_init(void) +{ + unsigned int psample_mcgroup; + int err; + + if (!netdev_is_flow_api_enabled()) { + VLOG_DBG("Flow API is not enabled."); + return; + } + + if (psample_sock) { + VLOG_DBG("Psample socket is already initialized."); + return; + } + + err = nl_lookup_genl_family(PSAMPLE_GENL_NAME, + &psample_family); + if (err) { + VLOG_INFO("%s: Generic Netlink family '%s' does not exist. " + "Please make sure the kernel module psample is loaded. " + "Error %d", __func__, PSAMPLE_GENL_NAME, err); + return; + } + + err = nl_lookup_genl_mcgroup(PSAMPLE_GENL_NAME, + PSAMPLE_NL_MCGRP_SAMPLE_NAME, + &psample_mcgroup); + if (err) { + VLOG_INFO("%s: Failed to join multicast group '%s' for Generic " + "Netlink family '%s' with error %d", __func__, + PSAMPLE_NL_MCGRP_SAMPLE_NAME, + PSAMPLE_GENL_NAME, err); + return; + } + + err = nl_sock_create(NETLINK_GENERIC, &psample_sock); + if (err) { + VLOG_INFO("%s: Failed to create psample socket with error %d", + __func__, err); + return; + } + + err = nl_sock_join_mcgroup(psample_sock, psample_mcgroup); + if (err) { + VLOG_INFO("%s: Failed to join psample mcgroup with error %d", + __func__, err); + nl_sock_destroy(psample_sock); + return; + } +} + +static void +dpif_offload_netlink_destroy(void) +{ + if (!psample_sock) { + return; + } + + nl_sock_destroy(psample_sock); + psample_sock = NULL; +} + +static void +dpif_offload_netlink_sflow_recv_wait(void) +{ + if (psample_sock) { + nl_sock_wait(psample_sock, POLLIN); + } +} + +static int +psample_from_ofpbuf(struct offload_psample *psample, + const struct ofpbuf *buf) +{ + static const struct nl_policy ovs_psample_policy[] = { + [PSAMPLE_ATTR_IIFINDEX] = { .type = NL_A_U16 }, + [PSAMPLE_ATTR_SAMPLE_GROUP] = { .type = NL_A_U32 }, + [PSAMPLE_ATTR_GROUP_SEQ] = { .type = NL_A_U32 }, + [PSAMPLE_ATTR_DATA] = { .type = NL_A_UNSPEC }, + }; + struct nlattr *a[ARRAY_SIZE(ovs_psample_policy)]; + struct genlmsghdr *genl; + struct nlmsghdr *nlmsg; + struct ofpbuf b; + + b = ofpbuf_const_initializer(buf->data, buf->size); + nlmsg = ofpbuf_try_pull(&b, sizeof *nlmsg); + genl = ofpbuf_try_pull(&b, sizeof *genl); + if (!nlmsg || !genl || nlmsg->nlmsg_type != psample_family + || !nl_policy_parse(&b, 0, ovs_psample_policy, a, + ARRAY_SIZE(ovs_psample_policy))) { + return EINVAL; + } + + psample->iifindex = nl_attr_get_u16(a[PSAMPLE_ATTR_IIFINDEX]); + psample->dp_group_id = nl_attr_get_u32(a[PSAMPLE_ATTR_SAMPLE_GROUP]); + psample->packet = a[PSAMPLE_ATTR_DATA]; + + return 0; +} + +static int +psample_parse_packet(struct offload_psample *psample, + struct dpif_offload_sflow *sflow) +{ + dp_packet_use_stub(&sflow->packet, + CONST_CAST(struct nlattr *, + nl_attr_get(psample->packet)) - 1, + nl_attr_get_size(psample->packet) + + sizeof(struct nlattr)); + dp_packet_set_data(&sflow->packet, + (char *) dp_packet_data(&sflow->packet) + + sizeof(struct nlattr)); + dp_packet_set_size(&sflow->packet, nl_attr_get_size(psample->packet)); + + sflow->attr = dpif_offload_sflow_attr_find(psample->dp_group_id); + if (!sflow->attr) { + return ENOENT; + } + sflow->iifindex = psample->iifindex; + + return 0; +} + +static int +dpif_offload_netlink_sflow_recv(struct dpif_offload_sflow *sflow) +{ + if (!psample_sock) { + return ENOENT; + } + + for (;;) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + struct offload_psample psample; + uint64_t buf_stub[4096 / 8]; + struct ofpbuf buf; + int error; + + ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub); + error = nl_sock_recv(psample_sock, &buf, NULL, false); + + if (!error) { + error = psample_from_ofpbuf(&psample, &buf); + if (!error) { + ofpbuf_uninit(&buf); + error = psample_parse_packet(&psample, sflow); + return error; + } + } else if (error != EAGAIN) { + VLOG_WARN_RL(&rl, "%s: error reading or parsing netlink (%s)", + __func__, ovs_strerror(error)); + nl_sock_drain(psample_sock); + error = ENOBUFS; + } + + ofpbuf_uninit(&buf); + if (error) { + return error; + } + } +} + +const struct dpif_offload_api dpif_offload_netlink = { + .init = dpif_offload_netlink_init, + .destroy = dpif_offload_netlink_destroy, + .sflow_recv_wait = dpif_offload_netlink_sflow_recv_wait, + .sflow_recv = dpif_offload_netlink_sflow_recv, +}; diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h index 95c29c0d8..db46209e1 100644 --- a/lib/dpif-offload-provider.h +++ b/lib/dpif-offload-provider.h @@ -17,12 +17,12 @@ #ifndef DPIF_OFFLOAD_PROVIDER_H #define DPIF_OFFLOAD_PROVIDER_H +#include "dp-packet.h" #include "netlink-protocol.h" #include "openvswitch/packets.h" #include "openvswitch/types.h" struct dpif; -struct dpif_offload_sflow; /* When offloading sample action, userspace creates a unique ID to map * sFlow action and tunnel info and passes this ID to datapath instead @@ -37,6 +37,13 @@ struct dpif_sflow_attr { ovs_u128 ufid; /* Flow ufid. */ }; +/* Parse the specific dpif message to sFlow. So OVS can process it. */ +struct dpif_offload_sflow { + struct dp_packet packet; /* Packet data. */ + uint32_t iifindex; /* Input ifindex. */ + const struct dpif_sflow_attr *attr; /* SFlow attribute. */ +}; + /* Datapath interface offload structure, to be defined by each implementation * of a datapath interface. */ @@ -61,4 +68,8 @@ void dpif_offload_sflow_recv_wait(const struct dpif *dpif); int dpif_offload_sflow_recv(const struct dpif *dpif, struct dpif_offload_sflow *sflow); +#ifdef __linux__ +extern const struct dpif_offload_api dpif_offload_netlink; +#endif + #endif /* DPIF_OFFLOAD_PROVIDER_H */ From patchwork Wed Sep 15 12:43:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1528343 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4H8fz55qXsz9t0k for ; Wed, 15 Sep 2021 22:43:45 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id A263F82BEB; Wed, 15 Sep 2021 12:43:41 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id BJmw6x_hJee4; Wed, 15 Sep 2021 12:43:40 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 927BA82B2F; Wed, 15 Sep 2021 12:43:38 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1B5C3C0031; Wed, 15 Sep 2021 12:43:35 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1DC63C000D for ; Wed, 15 Sep 2021 12:43:31 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 8A3A060BA4 for ; Wed, 15 Sep 2021 12:43:29 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Qg3lYJSqRWDQ for ; Wed, 15 Sep 2021 12:43:29 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp3.osuosl.org (Postfix) with ESMTP id 5778560B89 for ; Wed, 15 Sep 2021 12:43:28 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Sep 2021 15:43:21 +0300 Received: from c-141-46-1-010.mtl.labs.mlnx (c-141-46-1-010.mtl.labs.mlnx [10.141.46.10]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 18FChLba010242; Wed, 15 Sep 2021 15:43:21 +0300 To: dev@openvswitch.org Date: Wed, 15 Sep 2021 15:43:18 +0300 Message-Id: <20210915124319.1683219-7-cmi@nvidia.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210915124319.1683219-1-cmi@nvidia.com> References: <20210915124319.1683219-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, simon.horman@netronome.com, roniba@nvidia.com, i.maximets@ovn.org Subject: [ovs-dev] [PATCH v15 6/7] ofproto: Introduce API to process sFlow offload packet X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Chris Mi via dev From: Chris Mi Reply-To: Chris Mi Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Process sFlow offload packet in handler thread if handler id is 0. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- ofproto/ofproto-dpif-upcall.c | 63 +++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index 1c9c720f0..4a36a45bb 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -22,6 +22,7 @@ #include "connmgr.h" #include "coverage.h" #include "cmap.h" +#include "lib/dpif-offload-provider.h" #include "lib/dpif-provider.h" #include "dpif.h" #include "openvswitch/dynamic-string.h" @@ -779,6 +780,57 @@ udpif_get_n_flows(struct udpif *udpif) return flow_count; } +static void +process_offload_sflow(struct udpif *udpif, struct dpif_offload_sflow *sflow) +{ + const struct dpif_sflow_attr *attr = sflow->attr; + const struct user_action_cookie *cookie; + struct dpif_sflow *dpif_sflow; + struct ofproto_dpif *ofproto; + struct upcall upcall; + uint32_t iifindex; + struct flow flow; + + if (!attr) { + VLOG_WARN_RL(&rl, "%s: sFlow upcall is missing its attribute", + __func__); + return; + } + + cookie = nl_attr_get(attr->userdata); + if (!cookie) { + VLOG_WARN_RL(&rl, "%s: user action cookie is missing", __func__); + return; + } + ofproto = ofproto_dpif_lookup_by_uuid(&cookie->ofproto_uuid); + if (!ofproto) { + VLOG_WARN_RL(&rl, "%s: sFlow upcall can't find ofproto dpif for UUID " + UUID_FMT, __func__, UUID_ARGS(&cookie->ofproto_uuid)); + return; + } + dpif_sflow = ofproto->sflow; + if (!dpif_sflow) { + VLOG_WARN_RL(&rl, "%s: sFlow upcall is missing dpif information", + __func__); + return; + } + + memset(&flow, 0, sizeof flow); + if (attr->tunnel) { + memcpy(&flow.tunnel, attr->tunnel, sizeof flow.tunnel); + } + iifindex = sflow->iifindex; + flow.in_port.odp_port = netdev_ifindex_to_odp_port(iifindex); + memset(&upcall, 0, sizeof upcall); + upcall.flow = &flow; + upcall.cookie = *cookie; + upcall.packet = &sflow->packet; + upcall.sflow = dpif_sflow; + upcall.ufid = &attr->ufid; + upcall.type = SFLOW_UPCALL; + process_upcall(udpif, &upcall, NULL, NULL); +} + /* The upcall handler thread tries to read a batch of UPCALL_MAX_BATCH * upcalls from dpif, processes the batch and installs corresponding flows * in dpif. */ @@ -795,6 +847,17 @@ udpif_upcall_handler(void *arg) dpif_recv_wait(udpif->dpif, handler->handler_id); latch_wait(&udpif->exit_latch); } + /* Only handler id 0 thread process sFlow offload packet. */ + if (handler->handler_id == 0) { + struct dpif_offload_sflow sflow; + int err; + + dpif_offload_sflow_recv_wait(udpif->dpif); + err = dpif_offload_sflow_recv(udpif->dpif, &sflow); + if (!err) { + process_offload_sflow(udpif, &sflow); + } + } poll_block(); } From patchwork Wed Sep 15 12:43:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1528342 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4H8fz41MMyz9sSs for ; Wed, 15 Sep 2021 22:43:44 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id E44F660C02; Wed, 15 Sep 2021 12:43:39 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Bkj8X6z9c5zo; Wed, 15 Sep 2021 12:43:37 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTPS id E2B0360BBB; Wed, 15 Sep 2021 12:43:36 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 72658C002C; Wed, 15 Sep 2021 12:43:34 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 93770C0022 for ; Wed, 15 Sep 2021 12:43:30 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 42555827A0 for ; Wed, 15 Sep 2021 12:43:30 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3qAzCrajfqmL for ; Wed, 15 Sep 2021 12:43:29 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp1.osuosl.org (Postfix) with ESMTP id 4903C82702 for ; Wed, 15 Sep 2021 12:43:28 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Sep 2021 15:43:21 +0300 Received: from c-141-46-1-010.mtl.labs.mlnx (c-141-46-1-010.mtl.labs.mlnx [10.141.46.10]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 18FChLbb010242; Wed, 15 Sep 2021 15:43:21 +0300 To: dev@openvswitch.org Date: Wed, 15 Sep 2021 15:43:19 +0300 Message-Id: <20210915124319.1683219-8-cmi@nvidia.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210915124319.1683219-1-cmi@nvidia.com> References: <20210915124319.1683219-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, simon.horman@netronome.com, roniba@nvidia.com, i.maximets@ovn.org Subject: [ovs-dev] [PATCH v15 7/7] netdev-offload-tc: Add offload support for sFlow X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Chris Mi via dev From: Chris Mi Reply-To: Chris Mi Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Create a unique group ID to map the sFlow info when offloading sFlow action to TC. When showing the offloaded datapath flows, translate the group ID from TC sample action to sFlow info using the mapping. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- NEWS | 1 + lib/netdev-offload-tc.c | 220 ++++++++++++++++++++++++++++++++++++---- lib/tc.c | 61 ++++++++++- lib/tc.h | 15 ++- 4 files changed, 275 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index 1f2adf718..974a3e8e0 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ Post-v2.16.0 by default. 'other_config:dpdk-socket-limit' can be set equal to the 'other_config:dpdk-socket-mem' to preserve the legacy memory limiting behavior. + - Add sFlow offload support for kernel (netlink) datapath. v2.16.0 - 16 Aug 2021 diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 5d817b6cf..4f603566c 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -20,6 +20,7 @@ #include #include "dpif.h" +#include "dpif-offload-provider.h" #include "hash.h" #include "openvswitch/hmap.h" #include "openvswitch/match.h" @@ -1053,6 +1054,19 @@ parse_tc_flower_to_match(struct tc_flower *flower, action = flower->actions; for (i = 0; i < flower->action_count; i++, action++) { switch (action->type) { + case TC_ACT_SAMPLE: { + const struct sgid_node *node; + + node = sgid_find(action->sample.group_id); + if (!node) { + VLOG_WARN("%s: sgid node is NULL, sgid: %d", + __func__, action->sample.group_id); + return ENOENT; + } + nl_msg_put(buf, node->sflow.action, + node->sflow.action->nla_len); + } + break; case TC_ACT_VLAN_POP: { nl_msg_put_flag(buf, OVS_ACTION_ATTR_POP_VLAN); } @@ -1791,6 +1805,155 @@ parse_match_ct_state_to_flower(struct tc_flower *flower, struct match *match) } } +static int +parse_userspace_attributes(const struct nlattr *actions, + struct dpif_sflow_attr *sflow_attr) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + const struct nlattr *nla; + unsigned int left; + + NL_NESTED_FOR_EACH_UNSAFE (nla, left, actions) { + if (nl_attr_type(nla) == OVS_USERSPACE_ATTR_USERDATA) { + struct user_action_cookie *cookie; + + cookie = CONST_CAST(struct user_action_cookie *, nl_attr_get(nla)); + if (cookie->type == USER_ACTION_COOKIE_SFLOW) { + sflow_attr->userdata = nla; + return 0; + } + } + } + + VLOG_DBG_RL(&rl, "%s: cannot offload userspace action other than sFlow", + __func__); + return EOPNOTSUPP; +} + +static int +parse_sample_actions_attribute(const struct nlattr *actions, + struct dpif_sflow_attr *sflow_attr) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + const struct nlattr *nla; + unsigned int left; + int err = EINVAL; + + NL_NESTED_FOR_EACH_UNSAFE (nla, left, actions) { + if (nl_attr_type(nla) == OVS_ACTION_ATTR_USERSPACE) { + err = parse_userspace_attributes(nla, sflow_attr); + } else { + /* We can't offload other nested actions */ + VLOG_DBG_RL(&rl, "%s: can only offload " + "OVS_ACTION_ATTR_USERSPACE attribute", __func__); + return EINVAL; + } + } + + if (err) { + VLOG_ERR_RL(&error_rl, "%s: no OVS_ACTION_ATTR_USERSPACE attribute", + __func__); + } + return err; +} + +static int +parse_sample_action(struct tc_flower *flower, struct tc_action *tc_action, + const struct nlattr *sample_action, + const struct flow_tnl *tnl, uint32_t *group_id, + const ovs_u128 *ufid) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + struct dpif_sflow_attr sflow_attr; + const struct nlattr *nla; + unsigned int left; + int ret = EINVAL; + + if (*group_id) { + VLOG_ERR_RL(&error_rl, "%s: Only a single TC_SAMPLE action " + "per flow is supported", __func__); + return EOPNOTSUPP; + } + + memset(&sflow_attr, 0, sizeof sflow_attr); + sflow_attr.ufid = *ufid; + sflow_attr.action = sample_action; + + if (flower->tunnel) { + sflow_attr.tunnel = CONST_CAST(struct flow_tnl *, tnl); + } + + NL_NESTED_FOR_EACH_UNSAFE (nla, left, sample_action) { + if (nl_attr_type(nla) == OVS_SAMPLE_ATTR_ACTIONS) { + ret = parse_sample_actions_attribute(nla, &sflow_attr); + } else if (nl_attr_type(nla) == OVS_SAMPLE_ATTR_PROBABILITY) { + tc_action->type = TC_ACT_SAMPLE; + tc_action->sample.rate = UINT32_MAX / nl_attr_get_u32(nla); + } else { + return EINVAL; + } + } + + if (!tc_action->sample.rate || ret) { + return EINVAL; + } + + *group_id = sgid_alloc_ctx(&sflow_attr); + if (!*group_id) { + VLOG_DBG_RL(&rl, "%s: Failed allocating group id for sample action", + __func__); + return ENOENT; + } + tc_action->sample.group_id = *group_id; + flower->action_count++; + + return 0; +} + +static int +parse_userspace_action(struct tc_flower *flower, struct tc_action *tc_action, + const struct nlattr *userspace_action, + const struct flow_tnl *tnl, uint32_t *group_id, + const ovs_u128 *ufid) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); + struct dpif_sflow_attr sflow_attr; + int err; + + if (*group_id) { + VLOG_ERR_RL(&error_rl, "%s: Only a single TC_SAMPLE action " + "per flow is supported", __func__); + return EOPNOTSUPP; + } + + /* If sampling rate is 1, there is only a sFlow cookie inside of a + * userspace action, but no sample attribute. That means we can + * only offload userspace actions for sFlow. + */ + memset(&sflow_attr, 0, sizeof sflow_attr); + sflow_attr.ufid = *ufid; + if (flower->tunnel) { + sflow_attr.tunnel = CONST_CAST(struct flow_tnl *, tnl); + } + err = parse_userspace_attributes(userspace_action, &sflow_attr); + if (err) { + return err; + } + sflow_attr.action = userspace_action; + *group_id = sgid_alloc_ctx(&sflow_attr); + if (!*group_id) { + VLOG_DBG_RL(&rl, "%s: Failed allocating group id for sample action", + __func__); + return ENOENT; + } + tc_action->type = TC_ACT_SAMPLE; + tc_action->sample.group_id = *group_id; + tc_action->sample.rate = 1; + flower->action_count++; + + return 0; +} + static int netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct nlattr *actions, size_t actions_len, @@ -1806,6 +1969,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, const struct flow_tnl *tnl_mask = &mask->tunnel; struct tc_action *action; bool recirc_act = false; + uint32_t sample_gid = 0; uint32_t block_id = 0; struct nlattr *nla; struct tcf_id id; @@ -2058,7 +2222,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, NL_ATTR_FOR_EACH(nla, left, actions, actions_len) { if (flower.action_count >= TCA_ACT_MAX_NUM) { VLOG_DBG_RL(&rl, "Can only support %d actions", TCA_ACT_MAX_NUM); - return EOPNOTSUPP; + err = EOPNOTSUPP; + goto out; } action = &flower.actions[flower.action_count]; if (nl_attr_type(nla) == OVS_ACTION_ATTR_OUTPUT) { @@ -2068,7 +2233,8 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, if (!outdev) { VLOG_DBG_RL(&rl, "Can't find netdev for output port %d", port); - return ENODEV; + err = ENODEV; + goto out; } action->out.ifindex_out = netdev_get_ifindex(outdev); action->out.ingress = is_internal_port(netdev_get_type(outdev)); @@ -2106,7 +2272,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, err = parse_put_flow_set_action(&flower, action, set, set_len); if (err) { - return err; + goto out; } if (action->type == TC_ACT_ENCAP) { action->encap.tp_dst = info->tp_dst_port; @@ -2119,7 +2285,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, err = parse_put_flow_set_masked_action(&flower, action, set, set_len, true); if (err) { - return err; + goto out; } } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) { const struct nlattr *ct = nl_attr_get(nla); @@ -2131,7 +2297,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, err = parse_put_flow_ct_action(&flower, action, ct, ct_len); if (err) { - return err; + goto out; } } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT_CLEAR) { action->type = TC_ACT_CT; @@ -2147,20 +2313,29 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, action->chain = 0; /* 0 is reserved and not used by recirc. */ flower.action_count++; } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_SAMPLE) { - struct dpif_sflow_attr sflow_attr; - - memset(&sflow_attr, 0, sizeof sflow_attr); - sgid_alloc_ctx(&sflow_attr); + err = parse_sample_action(&flower, action, nla, tnl, &sample_gid, + ufid); + if (err) { + goto out; + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_USERSPACE) { + err = parse_userspace_action(&flower, action, nla, tnl, + &sample_gid, ufid); + if (err) { + goto out; + } } else { VLOG_DBG_RL(&rl, "unsupported put action type: %d", nl_attr_type(nla)); - return EOPNOTSUPP; + err = EOPNOTSUPP; + goto out; } } if ((chain || recirc_act) && !info->recirc_id_shared_with_tc) { VLOG_ERR_RL(&error_rl, "flow_put: recirc_id sharing not supported"); - return EOPNOTSUPP; + err = EOPNOTSUPP; + goto out; } if (get_ufid_tc_mapping(ufid, &id) == 0) { @@ -2173,20 +2348,29 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, prio = get_prio_for_tc_flower(&flower); if (prio == 0) { VLOG_ERR_RL(&rl, "couldn't get tc prio: %s", ovs_strerror(ENOSPC)); - return ENOSPC; + err = ENOSPC; + goto out; } flower.act_cookie.data = ufid; flower.act_cookie.len = sizeof *ufid; block_id = get_block_id_from_netdev(netdev); - id = tc_make_tcf_id_chain(ifindex, block_id, chain, prio, hook); + id = tc_make_tcf_id_all(ifindex, block_id, chain, prio, hook, sample_gid); err = tc_replace_flower(&id, &flower); - if (!err) { - if (stats) { - memset(stats, 0, sizeof *stats); - } - add_ufid_tc_mapping(netdev, ufid, &id); + if (err) { + goto out; + } + + if (stats) { + memset(stats, 0, sizeof *stats); + } + add_ufid_tc_mapping(netdev, ufid, &id); + return 0; + +out: + if (sample_gid) { + sgid_free(sample_gid); } return err; diff --git a/lib/tc.c b/lib/tc.c index 38a1dfc0e..dc8db6b22 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -23,14 +23,15 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include -#include #include #include #include @@ -1341,6 +1342,38 @@ nl_parse_act_gact(struct nlattr *options, struct tc_flower *flower) return 0; } +static const struct nl_policy sample_policy[] = { + [TCA_SAMPLE_PARMS] = { .type = NL_A_UNSPEC, + .min_len = sizeof(struct tc_sample), + .optional = false, }, + [TCA_SAMPLE_PSAMPLE_GROUP] = { .type = NL_A_U32, + .optional = false, }, + [TCA_SAMPLE_RATE] = { .type = NL_A_U32, + .optional = false, }, +}; + +static int +nl_parse_act_sample(struct nlattr *options, struct tc_flower *flower) +{ + struct nlattr *sample_attrs[ARRAY_SIZE(sample_policy)]; + struct tc_action *action; + + if (!nl_parse_nested(options, sample_policy, sample_attrs, + ARRAY_SIZE(sample_policy))) { + VLOG_ERR_RL(&error_rl, "failed to parse sample action options"); + return EPROTO; + } + + action = &flower->actions[flower->action_count++]; + action->type = TC_ACT_SAMPLE; + action->sample.group_id = + nl_attr_get_u32(sample_attrs[TCA_SAMPLE_PSAMPLE_GROUP]); + action->sample.rate = + nl_attr_get_u32(sample_attrs[TCA_SAMPLE_RATE]); + + return 0; +} + static const struct nl_policy mirred_policy[] = { [TCA_MIRRED_PARMS] = { .type = NL_A_UNSPEC, .min_len = sizeof(struct tc_mirred), @@ -1749,6 +1782,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower, /* Added for TC rule only (not in OvS rule) so ignore. */ } else if (!strcmp(act_kind, "ct")) { nl_parse_act_ct(act_options, flower); + } else if (!strcmp(act_kind, "sample")) { + nl_parse_act_sample(act_options, flower); } else { VLOG_ERR_RL(&error_rl, "unknown tc action kind: %s", act_kind); err = EINVAL; @@ -2375,6 +2410,23 @@ nl_msg_put_act_mirred(struct ofpbuf *request, int ifindex, int action, nl_msg_end_nested(request, offset); } +static void +nl_msg_put_act_sample(struct ofpbuf *request, uint32_t rate, uint32_t group_id) +{ + size_t offset; + + nl_msg_put_string(request, TCA_ACT_KIND, "sample"); + offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED); + { + struct tc_sample parm = { .action = TC_ACT_PIPE }; + + nl_msg_put_unspec(request, TCA_SAMPLE_PARMS, &parm, sizeof parm); + nl_msg_put_u32(request, TCA_SAMPLE_RATE, rate); + nl_msg_put_u32(request, TCA_SAMPLE_PSAMPLE_GROUP, group_id); + } + nl_msg_end_nested(request, offset); +} + static inline void nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) { if (ck->len) { @@ -2634,6 +2686,13 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) nl_msg_end_nested(request, act_offset); } break; + case TC_ACT_SAMPLE: { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_sample(request, action->sample.rate, + action->sample.group_id); + nl_msg_end_nested(request, act_offset); + } + break; case TC_ACT_OUTPUT: { if (!released && flower->tunnel) { act_offset = nl_msg_start_nested(request, act_index++); diff --git a/lib/tc.h b/lib/tc.h index 2e4084f48..f764d7d1e 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -174,6 +174,7 @@ enum tc_action_type { TC_ACT_MPLS_SET, TC_ACT_GOTO, TC_ACT_CT, + TC_ACT_SAMPLE, }; enum nat_type { @@ -256,6 +257,11 @@ struct tc_action { bool force; bool commit; } ct; + + struct { + uint32_t rate; + uint32_t group_id; + } sample; }; enum tc_action_type type; @@ -294,12 +300,14 @@ tc_make_tcf_id(int ifindex, uint32_t block_id, uint16_t prio, } static inline struct tcf_id -tc_make_tcf_id_chain(int ifindex, uint32_t block_id, uint32_t chain, - uint16_t prio, enum tc_qdisc_hook hook) +tc_make_tcf_id_all(int ifindex, uint32_t block_id, uint32_t chain, + uint16_t prio, enum tc_qdisc_hook hook, + uint32_t sample_group_id) { struct tcf_id id = tc_make_tcf_id(ifindex, block_id, prio, hook); id.chain = chain; + id.sample_group_id = sample_group_id; return id; } @@ -313,7 +321,8 @@ is_tcf_id_eq(struct tcf_id *id1, struct tcf_id *id2) && id1->hook == id2->hook && id1->block_id == id2->block_id && id1->ifindex == id2->ifindex - && id1->chain == id2->chain; + && id1->chain == id2->chain + && id1->sample_group_id == id2->sample_group_id; } enum tc_offload_policy {