From patchwork Thu Jul 15 03:37:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1505529 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.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 4GQKpJ0Jk7z9sRN for ; Thu, 15 Jul 2021 13:38:15 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 8CF6A4067A; Thu, 15 Jul 2021 03:38:13 +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 PmW4frMSvH-I; Thu, 15 Jul 2021 03:38:12 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 5CA7A4053E; Thu, 15 Jul 2021 03:38:11 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A0914C0025; Thu, 15 Jul 2021 03:38:09 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id ADAD7C0010 for ; Thu, 15 Jul 2021 03:38:07 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 94D5682A4E for ; Thu, 15 Jul 2021 03:38:07 +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 Qqf-95LB2E7X for ; Thu, 15 Jul 2021 03:38:06 +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 20A12829F2 for ; Thu, 15 Jul 2021 03:38:05 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Jul 2021 06:38:02 +0300 Received: from c-141-18-1-005.mtl.labs.mlnx (c-141-18-1-005.mtl.labs.mlnx [10.141.18.5]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 16F3bxrB028407; Thu, 15 Jul 2021 06:38:02 +0300 To: dev@openvswitch.org Date: Thu, 15 Jul 2021 06:37:51 +0300 Message-Id: <20210715033757.30823-2-cmi@nvidia.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210715033757.30823-1-cmi@nvidia.com> References: <20210715033757.30823-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 v13 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 Thu Jul 15 03:37:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1505528 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (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 4GQKpF5px4z9sRN for ; Thu, 15 Jul 2021 13:38:13 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id CBBEF42212; Thu, 15 Jul 2021 03:38:10 +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 uAqUwcdPbe0P; Thu, 15 Jul 2021 03:38:09 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id C099E421FE; Thu, 15 Jul 2021 03:38:08 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 92FAFC001B; Thu, 15 Jul 2021 03:38:08 +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 A39F3C000E for ; Thu, 15 Jul 2021 03:38:07 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 83FFD42212 for ; Thu, 15 Jul 2021 03:38:07 +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 54PuQFTWLaLy for ; Thu, 15 Jul 2021 03:38:06 +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 2293E421FE for ; Thu, 15 Jul 2021 03:38:05 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Jul 2021 06:38:02 +0300 Received: from c-141-18-1-005.mtl.labs.mlnx (c-141-18-1-005.mtl.labs.mlnx [10.141.18.5]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 16F3bxrC028407; Thu, 15 Jul 2021 06:38:02 +0300 To: dev@openvswitch.org Date: Thu, 15 Jul 2021 06:37:52 +0300 Message-Id: <20210715033757.30823-3-cmi@nvidia.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210715033757.30823-1-cmi@nvidia.com> References: <20210715033757.30823-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 v13 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 Thu Jul 15 03:37:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1505533 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.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 4GQKpQ5p5Pz9sWk for ; Thu, 15 Jul 2021 13:38:22 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 459FD406A0; Thu, 15 Jul 2021 03:38:20 +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 hMpRaOUbAC6O; Thu, 15 Jul 2021 03:38:18 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id 2F0A04011D; Thu, 15 Jul 2021 03:38:17 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 42A7AC0029; Thu, 15 Jul 2021 03:38:15 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 46B1DC0010 for ; Thu, 15 Jul 2021 03:38:09 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id DB79140159 for ; Thu, 15 Jul 2021 03:38:07 +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 Gb_gJswImf6f for ; Thu, 15 Jul 2021 03:38:06 +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 20010400E5 for ; Thu, 15 Jul 2021 03:38:05 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Jul 2021 06:38:02 +0300 Received: from c-141-18-1-005.mtl.labs.mlnx (c-141-18-1-005.mtl.labs.mlnx [10.141.18.5]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 16F3bxrD028407; Thu, 15 Jul 2021 06:38:02 +0300 To: dev@openvswitch.org Date: Thu, 15 Jul 2021 06:37:53 +0300 Message-Id: <20210715033757.30823-4-cmi@nvidia.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210715033757.30823-1-cmi@nvidia.com> References: <20210715033757.30823-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 v13 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 | 34 +++++++++++++++++++++++++++++ lib/dpif-offload.c | 43 +++++++++++++++++++++++++++++++++++++ lib/dpif-provider.h | 8 ++++++- lib/dpif.c | 10 +++++++++ 7 files changed, 99 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 3c9523c1a..dc865b0ef 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -123,6 +123,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 610949f36..35d73542b 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -8269,6 +8269,7 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_bond_add, dpif_netdev_bond_del, dpif_netdev_bond_stats_get, + NULL, /* dpif_offlod_api */ }; static void diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 39dc8300e..6a7defb95 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" @@ -4036,6 +4037,7 @@ const struct dpif_class dpif_netlink_class = { NULL, /* bond_add */ NULL, /* bond_del */ NULL, /* bond_stats_get */ + NULL, /* dpif_offlod_api */ }; static int diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h new file mode 100644 index 000000000..97108402a --- /dev/null +++ b/lib/dpif-offload-provider.h @@ -0,0 +1,34 @@ +/* + * 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; + +struct dpif_offload_api { + void (*init)(void); + void (*uninit)(void); + void (*sflow_recv_wait)(void); + 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 59e0a3a9d..7fb93d69d 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 @@ -633,6 +634,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 26e8bfb7d..a0987988a 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->uninit) { + dpif_class->offload_api->uninit(); + } + shash_delete(&dpif_classes, node); free(registered_class); From patchwork Thu Jul 15 03:37:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1505532 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (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 4GQKpQ4vxNz9sRN for ; Thu, 15 Jul 2021 13:38:22 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id DD99A42266; Thu, 15 Jul 2021 03:38:18 +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 Te2rZCgFGyhi; Thu, 15 Jul 2021 03:38:15 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTPS id E07E342234; Thu, 15 Jul 2021 03:38:13 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 467C5C0029; Thu, 15 Jul 2021 03:38:12 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2633CC000E for ; Thu, 15 Jul 2021 03:38:08 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id C4304401C8 for ; Thu, 15 Jul 2021 03:38:07 +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 zn4xXZTtKtZy for ; Thu, 15 Jul 2021 03:38:06 +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 292FE40159 for ; Thu, 15 Jul 2021 03:38:05 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Jul 2021 06:38:02 +0300 Received: from c-141-18-1-005.mtl.labs.mlnx (c-141-18-1-005.mtl.labs.mlnx [10.141.18.5]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 16F3bxrE028407; Thu, 15 Jul 2021 06:38:02 +0300 To: dev@openvswitch.org Date: Thu, 15 Jul 2021 06:37:54 +0300 Message-Id: <20210715033757.30823-5-cmi@nvidia.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210715033757.30823-1-cmi@nvidia.com> References: <20210715033757.30823-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 v13 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 | 18 +++ lib/netdev-offload-tc.c | 272 +++++++++++++++++++++++++++++++++++- lib/netdev-offload.h | 1 + lib/tc.h | 1 + 4 files changed, 290 insertions(+), 2 deletions(-) diff --git a/lib/dpif-offload-provider.h b/lib/dpif-offload-provider.h index 97108402a..b765eb9a2 100644 --- a/lib/dpif-offload-provider.h +++ b/lib/dpif-offload-provider.h @@ -17,9 +17,27 @@ #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 */ + void *userdata; /* struct user_action_cookie */ + size_t userdata_len; /* struct user_action_cookie length */ + struct flow_tnl *tunnel; /* tunnel info */ + ovs_u128 ufid; /* flow ufid */ +}; + struct dpif_offload_api { void (*init)(void); void (*uninit)(void); diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 9845e8d3f..2f16cf279 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,262 @@ 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 long long int sgid_last_run OVS_GUARDED_BY(sgid_rwlock); + +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 struct ovs_list sgid_expired OVS_GUARDED_BY(sgid_rwlock) + = OVS_LIST_INITIALIZER(&sgid_expired); + +static uint32_t next_sample_group_id OVS_GUARDED_BY(sgid_rwlock) = 1; + +#define SGID_RUN_INTERVAL 250 /* msec */ + +static void +sgid_node_free(struct sgid_node *node) +{ + free(node->sflow.tunnel); + free(CONST_CAST(void *, node->sflow.action)); + free(node->sflow.userdata); + free(node); +} + +static void +sgid_cleanup(void) +{ + long long int now = time_msec(); + struct sgid_node *node; + + /* Do maintenance at most 4 times / sec. */ + ovs_rwlock_rdlock(&sgid_rwlock); + if (now - sgid_last_run < SGID_RUN_INTERVAL) { + ovs_rwlock_unlock(&sgid_rwlock); + return; + } + ovs_rwlock_unlock(&sgid_rwlock); + + ovs_rwlock_wrlock(&sgid_rwlock); + sgid_last_run = now; + + LIST_FOR_EACH_POP (node, exp_node, &sgid_expired) { + cmap_remove(&sgid_map, &node->id_node, node->id); + ovsrcu_postpone(sgid_node_free, node); + } + + if (!ovs_list_is_empty(&sgid_expiring)) { + /* 'sgid_expired' is now empty, move nodes in + * 'sgid_expiring' to it. */ + ovs_list_splice(&sgid_expired, + ovs_list_front(&sgid_expiring), + &sgid_expiring); + } + ovs_rwlock_unlock(&sgid_rwlock); +} + +/* 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) +{ + return ovs_u128_equals(a->ufid, b->ufid); +} + +/* 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_len); + new->userdata_len = old->userdata_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) { + /* Prevent re-use of this node by removing the node from + * sgid_metadata_map' */ + cmap_remove(&sgid_metadata_map, &node->metadata_node, node->hash); + /* We keep the node in the 'sgid_map' so that it can be found as + * long as it lingers, and add it to the 'sgid_expiring' list. */ + ovs_list_insert(&sgid_expiring, &node->exp_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) { @@ -204,7 +461,7 @@ del_filter_and_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 +683,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); } @@ -466,6 +723,12 @@ netdev_tc_flow_dump_create(struct netdev *netdev, *dump_out = dump; + /* Cleanup the sFlow group ID nodes in sgid_expired list. + * In order to avoid creating a dedicated thread to do it, put it in + * the revalidator thread. + */ + sgid_cleanup(); + return 0; } @@ -1917,6 +2180,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)); 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 Thu Jul 15 03:37:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1505535 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.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 4GQKpY66Gdz9sRN for ; Thu, 15 Jul 2021 13:38:29 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 2F8EA83DB3; Thu, 15 Jul 2021 03:38:26 +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 q0culDcu5usj; Thu, 15 Jul 2021 03:38:22 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 825E083D67; Thu, 15 Jul 2021 03:38:20 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 86F61C0027; Thu, 15 Jul 2021 03:38:17 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 273DAC0023 for ; Thu, 15 Jul 2021 03:38:10 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id AE598400E5 for ; Thu, 15 Jul 2021 03:38:08 +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 MAYUs887mfmd for ; Thu, 15 Jul 2021 03:38:06 +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 24AC34011D for ; Thu, 15 Jul 2021 03:38:05 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Jul 2021 06:38:02 +0300 Received: from c-141-18-1-005.mtl.labs.mlnx (c-141-18-1-005.mtl.labs.mlnx [10.141.18.5]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 16F3bxrF028407; Thu, 15 Jul 2021 06:38:02 +0300 To: dev@openvswitch.org Date: Thu, 15 Jul 2021 06:37:55 +0300 Message-Id: <20210715033757.30823-6-cmi@nvidia.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210715033757.30823-1-cmi@nvidia.com> References: <20210715033757.30823-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 v13 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 | 210 ++++++++++++++++++++++++++++++++++++ lib/dpif-offload-provider.h | 12 +++ 4 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 lib/dpif-offload-netlink.c diff --git a/lib/automake.mk b/lib/automake.mk index dc865b0ef..daa60c784 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -442,6 +442,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 6a7defb95..676934ef1 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -4037,7 +4037,7 @@ const struct dpif_class dpif_netlink_class = { NULL, /* bond_add */ NULL, /* bond_del */ NULL, /* bond_stats_get */ - NULL, /* dpif_offlod_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..f02a6b0eb --- /dev/null +++ b/lib/dpif-offload-netlink.c @@ -0,0 +1,210 @@ +/* + * 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 */ + int group_seq; /* group sequence */ +}; + +static void +dpif_offload_netlink_init(void) +{ + unsigned int psample_mcgroup; + int err; + + if (!netdev_is_flow_api_enabled()) { + return; + } + + if (psample_sock) { + 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", + __func__, PSAMPLE_GENL_NAME); + 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'", __func__, + PSAMPLE_NL_MCGRP_SAMPLE_NAME, + PSAMPLE_GENL_NAME); + return; + } + + err = nl_sock_create(NETLINK_GENERIC, &psample_sock); + if (err) { + VLOG_INFO("%s: Failed to create psample socket", __func__); + return; + } + + err = nl_sock_join_mcgroup(psample_sock, psample_mcgroup); + if (err) { + VLOG_INFO("%s: Failed to join psample mcgroup", __func__); + nl_sock_destroy(psample_sock); + return; + } +} + +static void +dpif_offload_netlink_uninit(void) +{ + if (!netdev_is_flow_api_enabled()) { + return; + } + + 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->group_seq = nl_attr_get_u16(a[PSAMPLE_ATTR_GROUP_SEQ]); + 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, + .uninit = dpif_offload_netlink_uninit, + .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 b765eb9a2..803c79ed2 100644 --- a/lib/dpif-offload-provider.h +++ b/lib/dpif-offload-provider.h @@ -17,6 +17,7 @@ #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" @@ -38,6 +39,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; +}; + struct dpif_offload_api { void (*init)(void); void (*uninit)(void); @@ -49,4 +57,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 Thu Jul 15 03:37:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1505531 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.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 4GQKpP2Nygz9sRN for ; Thu, 15 Jul 2021 13:38:21 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 2BA8683CE7; Thu, 15 Jul 2021 03:38:19 +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 sGF8WNzO3uZE; Thu, 15 Jul 2021 03:38:16 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 6D2FF83D26; Thu, 15 Jul 2021 03:38:15 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2FB22C001B; Thu, 15 Jul 2021 03:38:14 +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 916B4C0010 for ; Thu, 15 Jul 2021 03:38:08 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 978BC421FE for ; Thu, 15 Jul 2021 03:38:07 +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 9MyFjaqprl3l for ; Thu, 15 Jul 2021 03:38:06 +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 20C97415E7 for ; Thu, 15 Jul 2021 03:38:05 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Jul 2021 06:38:02 +0300 Received: from c-141-18-1-005.mtl.labs.mlnx (c-141-18-1-005.mtl.labs.mlnx [10.141.18.5]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 16F3bxrG028407; Thu, 15 Jul 2021 06:38:02 +0300 To: dev@openvswitch.org Date: Thu, 15 Jul 2021 06:37:56 +0300 Message-Id: <20210715033757.30823-7-cmi@nvidia.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210715033757.30823-1-cmi@nvidia.com> References: <20210715033757.30823-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 v13 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 | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index ccf97266c..7e934614d 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" @@ -742,6 +743,51 @@ 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; + 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: dpif_sflow_attr is NULL", __func__); + return; + } + + cookie = attr->userdata; + ofproto = ofproto_dpif_lookup_by_uuid(&cookie->ofproto_uuid); + if (!ofproto) { + VLOG_WARN_RL(&rl, "%s: could not find ofproto", __func__); + return; + } + + dpif_sflow = ofproto->sflow; + if (!sflow) { + VLOG_WARN_RL(&rl, "%s: could not find dpif_sflow", __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 = &sflow->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. */ @@ -756,8 +802,19 @@ udpif_upcall_handler(void *arg) poll_immediate_wake(); } else { dpif_recv_wait(udpif->dpif, handler->handler_id); + dpif_offload_sflow_recv_wait(udpif->dpif); 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; + + err = dpif_offload_sflow_recv(udpif->dpif, &sflow); + if (!err) { + process_offload_sflow(udpif, &sflow); + } + } poll_block(); } From patchwork Thu Jul 15 03:37:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1505534 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.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 4GQKpT56kJz9sRN for ; Thu, 15 Jul 2021 13:38:25 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 72AB860B61; Thu, 15 Jul 2021 03:38:23 +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 EXchZkSS2KLl; Thu, 15 Jul 2021 03:38:20 +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 B368460B60; Thu, 15 Jul 2021 03:38:18 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 53C22C0010; Thu, 15 Jul 2021 03:38:16 +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 97027C0023 for ; Thu, 15 Jul 2021 03:38:09 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 7050C415E7 for ; Thu, 15 Jul 2021 03:38:08 +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 YuFXaDbUJ5iP for ; Thu, 15 Jul 2021 03:38:07 +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 2A6EA42200 for ; Thu, 15 Jul 2021 03:38:05 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 15 Jul 2021 06:38:02 +0300 Received: from c-141-18-1-005.mtl.labs.mlnx (c-141-18-1-005.mtl.labs.mlnx [10.141.18.5]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 16F3bxrH028407; Thu, 15 Jul 2021 06:38:02 +0300 To: dev@openvswitch.org Date: Thu, 15 Jul 2021 06:37:57 +0300 Message-Id: <20210715033757.30823-8-cmi@nvidia.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210715033757.30823-1-cmi@nvidia.com> References: <20210715033757.30823-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 v13 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 | 211 +++++++++++++++++++++++++++++++++++++--- lib/tc.c | 61 +++++++++++- lib/tc.h | 15 ++- 4 files changed, 271 insertions(+), 17 deletions(-) diff --git a/NEWS b/NEWS index 6cdccc715..7c0361e18 100644 --- a/NEWS +++ b/NEWS @@ -50,6 +50,7 @@ Post-v2.15.0 - OVS now reports the datapath capability 'ct_zero_snat', which reflects whether the SNAT with all-zero IP address is supported. See ovs-vswitchd.conf.db(5) for details. + - Add sFlow offload support for kernel (netlink) datapath. v2.15.0 - 15 Feb 2021 diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 2f16cf279..b68b8df28 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" @@ -1087,6 +1088,18 @@ 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_ERR_RL(&error_rl, "%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); } @@ -1825,6 +1838,156 @@ 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 = CONST_CAST(void *, nl_attr_get(nla)); + sflow_attr->userdata_len = nl_attr_get_size(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, @@ -1840,6 +2003,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; @@ -2092,7 +2256,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) { @@ -2102,7 +2267,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)); @@ -2140,7 +2306,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; @@ -2153,7 +2319,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); @@ -2165,7 +2331,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; @@ -2181,20 +2347,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) { @@ -2206,20 +2381,30 @@ 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); + } else { + goto out; + } + + return 0; + +out: + if (sample_gid) { + sgid_free(sample_gid); } return err; diff --git a/lib/tc.c b/lib/tc.c index 33287ea05..c5788220f 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 {