From patchwork Mon Sep 14 12:07:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1363547 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=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nvidia.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BqlVl3CWrz9sR4 for ; Mon, 14 Sep 2020 22:07:58 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 6BDE685A7D; Mon, 14 Sep 2020 12:07:56 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id euTx8mSWHeO0; Mon, 14 Sep 2020 12:07:55 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id E1B81859D9; Mon, 14 Sep 2020 12:07:55 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id C0752C088B; Mon, 14 Sep 2020 12:07:55 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 98B9BC0859 for ; Mon, 14 Sep 2020 12:07:53 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 945058707E for ; Mon, 14 Sep 2020 12:07:53 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id yORASfJELTr1 for ; Mon, 14 Sep 2020 12:07:53 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id 5DF0B8707A for ; Mon, 14 Sep 2020 12:07:52 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 14 Sep 2020 15:07:50 +0300 Received: from dev-r630-04.mtbc.labs.mlnx (dev-r630-04.mtbc.labs.mlnx [10.75.205.14]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 08EC7l4k018898; Mon, 14 Sep 2020 15:07:49 +0300 From: Chris Mi To: dev@openvswitch.org Date: Mon, 14 Sep 2020 20:07:38 +0800 Message-Id: <20200914120745.16373-2-cmi@nvidia.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200914120745.16373-1-cmi@nvidia.com> References: <20200914120745.16373-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, Chris Mi Subject: [ovs-dev] [PATCH v2 1/8] 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: , 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 --- utilities/ovs-kmod-ctl.in | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/utilities/ovs-kmod-ctl.in b/utilities/ovs-kmod-ctl.in index 19f100964..1ca44fa33 100644 --- a/utilities/ovs-kmod-ctl.in +++ b/utilities/ovs-kmod-ctl.in @@ -30,6 +30,9 @@ done insert_mods () { # Try loading openvswitch kernel module. action "Inserting openvswitch module" modprobe openvswitch + + # Try loading psample kernel module. + action "Inserting psample module" modprobe psample } insert_kmods_if_required() { @@ -95,6 +98,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 Mon Sep 14 12:07:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1363553 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=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nvidia.com Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BqlW43GfKz9sR4 for ; Mon, 14 Sep 2020 22:08:16 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id C60388723E; Mon, 14 Sep 2020 12:08:14 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id CXx4cdzSh7NE; Mon, 14 Sep 2020 12:08:13 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 3CB7987232; Mon, 14 Sep 2020 12:08:12 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1C34CC089E; Mon, 14 Sep 2020 12:08:12 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id E9E03C08A6 for ; Mon, 14 Sep 2020 12:08:06 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by silver.osuosl.org (Postfix) with ESMTP id 8E0AD2153D for ; Mon, 14 Sep 2020 12:08:05 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from silver.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id DduS7N0PKyHi for ; Mon, 14 Sep 2020 12:07:58 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by silver.osuosl.org (Postfix) with ESMTP id D6DA9204D0 for ; Mon, 14 Sep 2020 12:07:56 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 14 Sep 2020 15:07:51 +0300 Received: from dev-r630-04.mtbc.labs.mlnx (dev-r630-04.mtbc.labs.mlnx [10.75.205.14]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 08EC7l4l018898; Mon, 14 Sep 2020 15:07:50 +0300 From: Chris Mi To: dev@openvswitch.org Date: Mon, 14 Sep 2020 20:07:39 +0800 Message-Id: <20200914120745.16373-3-cmi@nvidia.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200914120745.16373-1-cmi@nvidia.com> References: <20200914120745.16373-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, Chris Mi Subject: [ovs-dev] [PATCH v2 2/8] dpif-netlink: Create psample netlink socket 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Create psample netlink socket as a pre-step towards receiving sampled packets. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- lib/dpif-netlink.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 7da4fb54d..79afef5f1 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -208,6 +209,9 @@ struct dpif_netlink { /* Change notification. */ struct nl_sock *port_notifier; /* vport multicast group subscriber. */ bool refresh_channels; + + /* receive sampled packets from psample */ + struct nl_sock *psample_sock; }; static void report_loss(struct dpif_netlink *, struct dpif_channel *, @@ -224,11 +228,13 @@ static int ovs_flow_family; static int ovs_packet_family; static int ovs_meter_family; static int ovs_ct_limit_family; +static int psample_family; /* Generic Netlink multicast groups for OVS. * * Initialized by dpif_netlink_init(). */ static unsigned int ovs_vport_mcgroup; +static unsigned int psample_mcgroup; /* If true, tunnel devices are created using OVS compat/genetlink. * If false, tunnel devices are created with rtnetlink and using light weight @@ -371,6 +377,34 @@ dpif_netlink_open(const struct dpif_class *class OVS_UNUSED, const char *name, return error; } +static int +open_dpif_psample(struct dpif_netlink *dpif) +{ + struct nl_sock *sock; + int error; + + dpif->psample_sock = NULL; + if (!netdev_is_flow_api_enabled() || !psample_mcgroup) { + return 0; + } + + error = nl_sock_create(NETLINK_GENERIC, &sock); + if (error) { + VLOG_WARN("%s: failed to create psample socket", __func__); + return error; + } + + error = nl_sock_join_mcgroup(sock, psample_mcgroup); + if (error) { + VLOG_WARN("%s: failed to join psample mcgroup", __func__); + nl_sock_destroy(sock); + return error; + } + dpif->psample_sock = sock; + + return 0; +} + static int open_dpif(const struct dpif_netlink_dp *dp, struct dpif **dpifp) { @@ -378,6 +412,7 @@ open_dpif(const struct dpif_netlink_dp *dp, struct dpif **dpifp) dpif = xzalloc(sizeof *dpif); dpif->port_notifier = NULL; + open_dpif_psample(dpif); fat_rwlock_init(&dpif->upcall_lock); dpif_init(&dpif->dpif, &dpif_netlink_class, dp->name, @@ -615,6 +650,7 @@ dpif_netlink_close(struct dpif *dpif_) struct dpif_netlink *dpif = dpif_netlink_cast(dpif_); nl_sock_destroy(dpif->port_notifier); + nl_sock_destroy(dpif->psample_sock); fat_rwlock_wrlock(&dpif->upcall_lock); destroy_all_channels(dpif); @@ -4098,6 +4134,18 @@ dpif_netlink_init(void) "Please update the Open vSwitch kernel module to enable " "the conntrack limit feature.", OVS_CT_LIMIT_FAMILY); } + if (nl_lookup_genl_family(PSAMPLE_GENL_NAME, &psample_family) < 0) { + VLOG_INFO("Generic Netlink family '%s' does not exist. " + "Please make sure the kernel module psample is loaded", + PSAMPLE_GENL_NAME); + } + if (nl_lookup_genl_mcgroup(PSAMPLE_GENL_NAME, + PSAMPLE_NL_MCGRP_SAMPLE_NAME, + &psample_mcgroup) < 0) { + VLOG_INFO("Failed to join multicast group '%s' for Generic " + "Netlink family '%s'", PSAMPLE_NL_MCGRP_SAMPLE_NAME, + PSAMPLE_GENL_NAME); + } ovs_tunnels_out_of_tree = dpif_netlink_rtnl_probe_oot_tunnels(); From patchwork Mon Sep 14 12:07:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1363550 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=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nvidia.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BqlVs2dG3z9sTm for ; Mon, 14 Sep 2020 22:08:05 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 46DF785F94; Mon, 14 Sep 2020 12:08:03 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5izfDM6T-pdL; Mon, 14 Sep 2020 12:08:01 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 9D69485FA4; Mon, 14 Sep 2020 12:08:01 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 71D11C089F; Mon, 14 Sep 2020 12:08:01 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 02FE6C088B for ; Mon, 14 Sep 2020 12:07:59 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id DF917869A2 for ; Mon, 14 Sep 2020 12:07:58 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 4jd8u1gWTJT4 for ; Mon, 14 Sep 2020 12:07:57 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by whitealder.osuosl.org (Postfix) with ESMTP id D42B1867F3 for ; Mon, 14 Sep 2020 12:07:56 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 14 Sep 2020 15:07:52 +0300 Received: from dev-r630-04.mtbc.labs.mlnx (dev-r630-04.mtbc.labs.mlnx [10.75.205.14]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 08EC7l4m018898; Mon, 14 Sep 2020 15:07:51 +0300 From: Chris Mi To: dev@openvswitch.org Date: Mon, 14 Sep 2020 20:07:40 +0800 Message-Id: <20200914120745.16373-4-cmi@nvidia.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200914120745.16373-1-cmi@nvidia.com> References: <20200914120745.16373-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, Chris Mi Subject: [ovs-dev] [PATCH v2 3/8] netdev-offload: Introduce sFlow attributes query by group ID 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" OVS maintains a group ID to sFlow attribute mapping when offloading sFlow action to TC. Introduce sFlow attributes query by group ID API. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- lib/netdev-offload-provider.h | 5 +++++ lib/netdev-offload.c | 11 +++++++++++ lib/netdev-offload.h | 1 + 3 files changed, 17 insertions(+) diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h index 0bed7bf61..8edffcbbd 100644 --- a/lib/netdev-offload-provider.h +++ b/lib/netdev-offload-provider.h @@ -86,6 +86,11 @@ struct netdev_flow_api { /* Initializies the netdev flow api. * Return 0 if successful, otherwise returns a positive errno value. */ int (*init_flow_api)(struct netdev *); + + /* Query sFlow attribute by group ID. + * + * On success returns a const pointer, on failure returns NULL */ + const struct dpif_sflow_attr *(*sflow_attr_get)(uint32_t gid); }; int netdev_register_flow_api_provider(const struct netdev_flow_api *); diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c index 2da3bc701..084ce25a9 100644 --- a/lib/netdev-offload.c +++ b/lib/netdev-offload.c @@ -666,3 +666,14 @@ netdev_set_flow_api_enabled(const struct smap *ovs_other_config) } } } + +const struct dpif_sflow_attr * +netdev_sflow_attr_get(struct netdev *netdev, uint32_t gid) +{ + const struct netdev_flow_api *flow_api = + ovsrcu_get(const struct netdev_flow_api *, &netdev->flow_api); + + return (flow_api && flow_api->sflow_attr_get) + ? flow_api->sflow_attr_get(gid) + : NULL; +} diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h index 4c0ed2ae8..9f167e1a5 100644 --- a/lib/netdev-offload.h +++ b/lib/netdev-offload.h @@ -124,6 +124,7 @@ int netdev_ports_flow_get(const char *dpif_type, struct match *match, struct dpif_flow_stats *stats, struct dpif_flow_attrs *attrs, struct ofpbuf *buf); +const struct dpif_sflow_attr *netdev_sflow_attr_get(struct netdev *, uint32_t); #ifdef __cplusplus } From patchwork Mon Sep 14 12:07:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1363549 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=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nvidia.com Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BqlVr2wwMz9sR4 for ; Mon, 14 Sep 2020 22:08:04 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 787AA8707E; Mon, 14 Sep 2020 12:08:01 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id NUWAnKQCKFRd; Mon, 14 Sep 2020 12:08:00 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id AB3A8871B7; Mon, 14 Sep 2020 12:08:00 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8B760C0859; Mon, 14 Sep 2020 12:08:00 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id E20F1C0859 for ; Mon, 14 Sep 2020 12:07:58 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id DC603867F6 for ; Mon, 14 Sep 2020 12:07:58 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id CFMZl61G7EUb for ; Mon, 14 Sep 2020 12:07:57 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by whitealder.osuosl.org (Postfix) with ESMTP id DA1D68677E for ; Mon, 14 Sep 2020 12:07:56 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 14 Sep 2020 15:07:54 +0300 Received: from dev-r630-04.mtbc.labs.mlnx (dev-r630-04.mtbc.labs.mlnx [10.75.205.14]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 08EC7l4n018898; Mon, 14 Sep 2020 15:07:53 +0300 From: Chris Mi To: dev@openvswitch.org Date: Mon, 14 Sep 2020 20:07:41 +0800 Message-Id: <20200914120745.16373-5-cmi@nvidia.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200914120745.16373-1-cmi@nvidia.com> References: <20200914120745.16373-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, Chris Mi Subject: [ovs-dev] [PATCH v2 4/8] dpif: Introduce psample offload 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Introduce offload API to receive sampled packet from psample netlink socket. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- lib/dpif-netdev.c | 3 +++ lib/dpif-netlink.c | 3 +++ lib/dpif-provider.h | 11 +++++++++++ lib/dpif.c | 24 ++++++++++++++++++++++++ lib/dpif.h | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 02df8f11e..6dd5ff055 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -8459,6 +8459,9 @@ const struct dpif_class dpif_netdev_class = { dpif_netdev_bond_add, dpif_netdev_bond_del, dpif_netdev_bond_stats_get, + NULL, /* psample_enabled */ + NULL, /* psample_poll */ + NULL, /* psample_poll_wait */ }; static void diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 79afef5f1..55199d35e 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -4093,6 +4093,9 @@ const struct dpif_class dpif_netlink_class = { NULL, /* bond_add */ NULL, /* bond_del */ NULL, /* bond_stats_get */ + NULL, /* psample_enabled */ + NULL, /* psample_poll */ + NULL, /* psample_poll_wait */ }; static int diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 0e024c1c9..bfebf4b01 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -628,6 +628,17 @@ 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); + + /* Check if psample thread should be created or not */ + bool (*psample_enabled)(const struct dpif *dpif); + + /* psample thread was created. Poll psample netlink to receive sampled + * packets */ + int (*psample_poll)(const struct dpif *dpif, + struct dpif_upcall_psample *dupcall); + + /* Arranges for the poll loop to wake up when 'psample_poll' returns */ + void (*psample_poll_wait)(const struct dpif *dpif); }; extern const struct dpif_class dpif_netlink_class; diff --git a/lib/dpif.c b/lib/dpif.c index 7cac3a629..b39ec8560 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -2018,3 +2018,27 @@ dpif_bond_stats_get(struct dpif *dpif, uint32_t bond_id, ? dpif->dpif_class->bond_stats_get(dpif, bond_id, n_bytes) : EOPNOTSUPP; } + +int +dpif_psample_poll(struct dpif *dpif, struct dpif_upcall_psample *dupcall) +{ + return dpif->dpif_class->psample_poll + ? dpif->dpif_class->psample_poll(dpif, dupcall) + : EOPNOTSUPP; +} + +void +dpif_psample_poll_wait(struct dpif *dpif) +{ + if (dpif->dpif_class->psample_poll_wait) { + dpif->dpif_class->psample_poll_wait(dpif); + } +} + +bool +dpif_psample_enabled(struct dpif *dpif) +{ + return dpif->dpif_class->psample_enabled + ? dpif->dpif_class->psample_enabled(dpif) + : false; +} diff --git a/lib/dpif.h b/lib/dpif.h index 2d52f0186..49f7a4238 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -825,6 +825,33 @@ struct dpif_upcall { struct nlattr *actions; /* Argument to OVS_ACTION_ATTR_USERSPACE. */ }; +/* 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. + */ +struct dpif_sflow_attr { + const struct nlattr *sflow; /* sFlow action */ + size_t sflow_len; /* Length of 'sflow' in bytes. */ + + void *userdata; /* struct user_action_cookie */ + size_t userdata_len; /* struct user_action_cookie length */ + + struct flow_tnl *tunnel; /* Tunnel info */ +}; + +/* A sampled packet passed up from driver to userspace. + * + * After offloading sample action to TC, driver will send sampled packets + * to userspace using psample. + */ +struct dpif_upcall_psample { + struct dp_packet packet; /* packet data */ + uint32_t iifindex; /* input ifindex */ + const struct dpif_sflow_attr *sflow_attr; +}; + /* A callback to notify higher layer of dpif about to be purged, so that * higher layer could try reacting to this (e.g. grabbing all flow stats * before they are gone). This function is currently implemented only by @@ -903,6 +930,11 @@ int dpif_bond_del(struct dpif *, uint32_t bond_id); int dpif_bond_stats_get(struct dpif *, uint32_t bond_id, uint64_t *n_bytes); bool dpif_supports_lb_output_action(const struct dpif *); +/* psample */ +int dpif_psample_poll(struct dpif *, struct dpif_upcall_psample *); +void dpif_psample_poll_wait(struct dpif *); +bool dpif_psample_enabled(struct dpif *); + /* Miscellaneous. */ From patchwork Mon Sep 14 12:07:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1363551 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=hemlock.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nvidia.com Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BqlVv1M7kz9sR4 for ; Mon, 14 Sep 2020 22:08:07 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id AA26187218; Mon, 14 Sep 2020 12:08:05 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id OOM+bubHJpLO; Mon, 14 Sep 2020 12:08:03 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by hemlock.osuosl.org (Postfix) with ESMTP id 87550871E3; Mon, 14 Sep 2020 12:08:03 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 67723C088B; Mon, 14 Sep 2020 12:08:03 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id ED981C089E for ; Mon, 14 Sep 2020 12:07:59 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id BFF4E87211 for ; Mon, 14 Sep 2020 12:07:59 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id T0Gt5oWNuhDA for ; Mon, 14 Sep 2020 12:07:57 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id E1539871C8 for ; Mon, 14 Sep 2020 12:07:56 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 14 Sep 2020 15:07:55 +0300 Received: from dev-r630-04.mtbc.labs.mlnx (dev-r630-04.mtbc.labs.mlnx [10.75.205.14]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 08EC7l4o018898; Mon, 14 Sep 2020 15:07:54 +0300 From: Chris Mi To: dev@openvswitch.org Date: Mon, 14 Sep 2020 20:07:42 +0800 Message-Id: <20200914120745.16373-6-cmi@nvidia.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200914120745.16373-1-cmi@nvidia.com> References: <20200914120745.16373-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, Chris Mi Subject: [ovs-dev] [PATCH v2 5/8] dpif-netlink: Implement psample offload 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Implement offload API to receive sampled packet from psample netlink socket. Parse sampled packet to ovs format. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- lib/dpif-netlink.c | 133 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 3 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 55199d35e..fc08623ea 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -4016,6 +4016,133 @@ probe_broken_meters(struct dpif *dpif) } return broken_meters; } + +struct dpif_netlink_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 bool +dpif_netlink_psample_enabled(const struct dpif *dpif_) +{ + struct dpif_netlink *dpif = dpif_netlink_cast(dpif_); + + return dpif->psample_sock != NULL; +} + +static int +dpif_netlink_psample_from_ofpbuf(struct dpif_netlink_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 +parse_psample_packet(struct dpif_netlink *dpif, + struct dpif_netlink_psample *psample, + struct dpif_upcall_psample *dupcall) +{ + const char *dpif_type_str = dpif_normalize_type(dpif_type(&dpif->dpif)); + struct netdev *dev; + odp_port_t port; + + dp_packet_use_stub(&dupcall->packet, + CONST_CAST(struct nlattr *, + nl_attr_get(psample->packet)) - 1, + nl_attr_get_size(psample->packet) + + sizeof(struct nlattr)); + dp_packet_set_data(&dupcall->packet, + (char *)dp_packet_data(&dupcall->packet) + + sizeof(struct nlattr)); + dp_packet_set_size(&dupcall->packet, nl_attr_get_size(psample->packet)); + + dupcall->iifindex = psample->iifindex; + port = netdev_ifindex_to_odp_port(dupcall->iifindex); + dev = netdev_ports_get(port, dpif_type_str); + if (!dev) { + return EOPNOTSUPP; + } + dupcall->sflow_attr = netdev_sflow_attr_get(dev, psample->dp_group_id); + netdev_close(dev); + + return 0; +} + +static int +dpif_netlink_psample_poll(const struct dpif *dpif_, + struct dpif_upcall_psample *dupcall) +{ + for (;;) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + struct dpif_netlink *dpif = dpif_netlink_cast(dpif_); + struct dpif_netlink_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(dpif->psample_sock, &buf, NULL, false); + + if (!error) { + error = dpif_netlink_psample_from_ofpbuf(&psample, &buf); + if (!error) { + ofpbuf_uninit(&buf); + error = parse_psample_packet(dpif, &psample, dupcall); + return error; + } + } else if (error != EAGAIN) { + VLOG_WARN_RL(&rl, "error reading or parsing netlink (%s)", + ovs_strerror(error)); + nl_sock_drain(dpif->psample_sock); + error = ENOBUFS; + } + + ofpbuf_uninit(&buf); + if (error) { + return error; + } + } +} + +static void +dpif_netlink_psample_poll_wait(const struct dpif *dpif_) +{ + const struct dpif_netlink *dpif = dpif_netlink_cast(dpif_); + + if (dpif->psample_sock) { + nl_sock_wait(dpif->psample_sock, POLLIN); + } else { + poll_immediate_wake(); + } +} + const struct dpif_class dpif_netlink_class = { "system", @@ -4093,9 +4220,9 @@ const struct dpif_class dpif_netlink_class = { NULL, /* bond_add */ NULL, /* bond_del */ NULL, /* bond_stats_get */ - NULL, /* psample_enabled */ - NULL, /* psample_poll */ - NULL, /* psample_poll_wait */ + dpif_netlink_psample_enabled, + dpif_netlink_psample_poll, + dpif_netlink_psample_poll_wait, }; static int From patchwork Mon Sep 14 12:07:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1363552 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=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nvidia.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BqlW05q6kz9sR4 for ; Mon, 14 Sep 2020 22:08:12 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 5708D85F9B; Mon, 14 Sep 2020 12:08:11 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id K0krqwPMncM0; Mon, 14 Sep 2020 12:08:08 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 7BB2885FB4; Mon, 14 Sep 2020 12:08:06 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3D1F5C0890; Mon, 14 Sep 2020 12:08:06 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3F4F5C0859 for ; Mon, 14 Sep 2020 12:08:03 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 3BE57871D5 for ; Mon, 14 Sep 2020 12:08:03 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qiu-W56gpEPx for ; Mon, 14 Sep 2020 12:08:02 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id E73A287212 for ; Mon, 14 Sep 2020 12:08:01 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 14 Sep 2020 15:07:56 +0300 Received: from dev-r630-04.mtbc.labs.mlnx (dev-r630-04.mtbc.labs.mlnx [10.75.205.14]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 08EC7l4p018898; Mon, 14 Sep 2020 15:07:55 +0300 From: Chris Mi To: dev@openvswitch.org Date: Mon, 14 Sep 2020 20:07:43 +0800 Message-Id: <20200914120745.16373-7-cmi@nvidia.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200914120745.16373-1-cmi@nvidia.com> References: <20200914120745.16373-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, Chris Mi Subject: [ovs-dev] [PATCH v2 6/8] ofproto: Add psample receive handler 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: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Create a dedicated thread to poll psample netlink socket, receive sampled packet, parse it to sFlow format and send it to sFlow monitoring host. Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- ofproto/ofproto-dpif-upcall.c | 78 +++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index 72a5b4d73..ac904a50e 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -133,6 +133,8 @@ struct udpif { struct revalidator *revalidators; /* Flow revalidators. */ size_t n_revalidators; + struct handler phandler; /* psample handler */ + struct latch exit_latch; /* Tells child threads to exit. */ /* Revalidation. */ @@ -339,6 +341,7 @@ static void udpif_start_threads(struct udpif *, size_t n_handlers, static void udpif_pause_revalidators(struct udpif *); static void udpif_resume_revalidators(struct udpif *); static void *udpif_upcall_handler(void *); +static void *udpif_psample_handler(void *); static void *udpif_revalidator(void *); static unsigned long udpif_get_n_flows(struct udpif *); static void revalidate(struct revalidator *); @@ -530,6 +533,9 @@ udpif_stop_threads(struct udpif *udpif, bool delete_flows) for (i = 0; i < udpif->n_revalidators; i++) { xpthread_join(udpif->revalidators[i].thread, NULL); } + if (dpif_psample_enabled(udpif->dpif)) { + xpthread_join(udpif->phandler.thread, NULL); + } dpif_disable_upcall(udpif->dpif); ovsrcu_quiesce_end(); @@ -594,6 +600,14 @@ udpif_start_threads(struct udpif *udpif, size_t n_handlers_, revalidator->thread = ovs_thread_create( "revalidator", udpif_revalidator, revalidator); } + + if (dpif_psample_enabled(udpif->dpif)) { + struct handler *phandler = &udpif->phandler; + + phandler->udpif = udpif; + phandler->thread = ovs_thread_create( + "psample_handler", udpif_psample_handler, phandler); + } ovsrcu_quiesce_end(); } } @@ -857,6 +871,70 @@ free_dupcall: return n_upcalls; } +static int +recv_psample(struct handler *handler) +{ + struct dpif *dpif = handler->udpif->dpif; + const struct dpif_sflow_attr *sflow_attr; + struct dpif_upcall_psample dupcall; + int ret; + + memset(&dupcall, 0, sizeof dupcall); + ret = dpif_psample_poll(dpif, &dupcall); + if (ret) { + VLOG_WARN_RL(&rl, "dpif_psample_poll err: %d", ret); + return ret; + } + + sflow_attr = dupcall.sflow_attr; + if (sflow_attr) { + struct user_action_cookie *cookie; + struct ofproto_dpif *ofproto; + struct dpif_sflow *sflow; + uint32_t iifindex; + struct flow flow; + + cookie = sflow_attr->userdata; + ofproto = ofproto_dpif_lookup_by_uuid(&cookie->ofproto_uuid); + if (!ofproto) { + VLOG_WARN_RL(&rl, "upcall could not find ofproto"); + return ENODEV; + } + sflow = ofproto->sflow; + if (!sflow) { + VLOG_WARN_RL(&rl, "upcall could not find sflow"); + return ENODEV; + } + + memset(&flow, 0, sizeof flow); + if (sflow_attr->tunnel) { + memcpy(&flow.tunnel, sflow_attr->tunnel, sizeof flow.tunnel); + } + iifindex = dupcall.iifindex; + dpif_sflow_received(sflow, &dupcall.packet, &flow, + netdev_ifindex_to_odp_port(iifindex), + cookie, NULL); + } + + return 0; +} + +static void * +udpif_psample_handler(void *arg) +{ + struct handler *handler = arg; + struct udpif *udpif = handler->udpif; + + while (!latch_is_set(&handler->udpif->exit_latch)) { + recv_psample(handler); + dpif_psample_poll_wait(udpif->dpif); + latch_wait(&udpif->exit_latch); + poll_block(); + } + + return NULL; +} + static void udpif_run_flow_rebalance(struct udpif *udpif) { From patchwork Mon Sep 14 12:07:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1363555 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=whitealder.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nvidia.com Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BqlWd0sz5z9sR4 for ; Mon, 14 Sep 2020 22:08:45 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 6940886A00; Mon, 14 Sep 2020 12:08:43 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id A5t2daysguBo; Mon, 14 Sep 2020 12:08:35 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id AD00486A1F; Mon, 14 Sep 2020 12:08:13 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 543BCC1AE8; Mon, 14 Sep 2020 12:08:13 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by lists.linuxfoundation.org (Postfix) with ESMTP id ACD4CC088B for ; Mon, 14 Sep 2020 12:08:10 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 8EBF086A74 for ; Mon, 14 Sep 2020 12:08:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id urdis653XReE for ; Mon, 14 Sep 2020 12:08:03 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by whitealder.osuosl.org (Postfix) with ESMTP id E057E869A2 for ; Mon, 14 Sep 2020 12:08:01 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 14 Sep 2020 15:07:58 +0300 Received: from dev-r630-04.mtbc.labs.mlnx (dev-r630-04.mtbc.labs.mlnx [10.75.205.14]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 08EC7l4q018898; Mon, 14 Sep 2020 15:07:57 +0300 From: Chris Mi To: dev@openvswitch.org Date: Mon, 14 Sep 2020 20:07:44 +0800 Message-Id: <20200914120745.16373-8-cmi@nvidia.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200914120745.16373-1-cmi@nvidia.com> References: <20200914120745.16373-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, Chris Mi Subject: [ovs-dev] [PATCH v2 7/8] 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: , 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/netdev-offload-tc.c | 261 ++++++++++++++++++++++++++++++++++++++++ lib/tc.h | 1 + 2 files changed, 262 insertions(+) diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 18ff380f9..50b6f0142 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -39,6 +39,7 @@ #include "unaligned.h" #include "util.h" #include "dpif-provider.h" +#include "cmap.h" VLOG_DEFINE_THIS_MODULE(netdev_offload_tc); @@ -55,6 +56,256 @@ struct netlink_field { int size; }; +/* This maps a psample group ID to struct dpif_sflow_attr for sFlow */ +struct gid_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 gid_rwlock = OVS_RWLOCK_INITIALIZER; + +static long long int gid_last_run OVS_GUARDED_BY(gid_rwlock); + +static struct cmap gid_map = CMAP_INITIALIZER; +static struct cmap gid_metadata_map = CMAP_INITIALIZER; + +static struct ovs_list gid_expiring OVS_GUARDED_BY(gid_rwlock) + = OVS_LIST_INITIALIZER(&gid_expiring); +static struct ovs_list gid_expired OVS_GUARDED_BY(gid_rwlock) + = OVS_LIST_INITIALIZER(&gid_expired); + +static uint32_t next_group_id OVS_GUARDED_BY(gid_rwlock) = 1; + +#define GID_RUN_INTERVAL 250 /* msec */ + +static void +gid_node_free(struct gid_node *node) +{ + if (node->sflow.tunnel) { + free(node->sflow.tunnel); + } + free(CONST_CAST(void *, node->sflow.sflow)); + free(node->sflow.userdata); + free(node); +} + +static void +gid_cleanup(void) +{ + long long int now = time_msec(); + struct gid_node *node; + + /* Do maintenance at most 4 times / sec. */ + ovs_rwlock_rdlock(&gid_rwlock); + if (now - gid_last_run < GID_RUN_INTERVAL) { + ovs_rwlock_unlock(&gid_rwlock); + return; + } + ovs_rwlock_unlock(&gid_rwlock); + + ovs_rwlock_wrlock(&gid_rwlock); + gid_last_run = now; + + LIST_FOR_EACH_POP (node, exp_node, &gid_expired) { + cmap_remove(&gid_map, &node->id_node, node->id); + ovsrcu_postpone(gid_node_free, node); + } + + if (!ovs_list_is_empty(&gid_expiring)) { + /* 'gid_expired' is now empty, move nodes in + * 'gid_expiring' to it. */ + ovs_list_splice(&gid_expired, + ovs_list_front(&gid_expiring), + &gid_expiring); + } + ovs_rwlock_unlock(&gid_rwlock); +} + +/* Lockless RCU protected lookup. If node is needed accross RCU quiescent + * state, caller should copy the contents. */ +static const struct gid_node * +gid_find(uint32_t id) +{ + const struct cmap_node *node = cmap_find(&gid_map, id); + + return node + ? CONTAINER_OF(node, const struct gid_node, id_node) + : NULL; +} + +static uint32_t +dpif_sflow_attr_hash(const struct dpif_sflow_attr *sflow) +{ + uint32_t hash1 = hash_bytes(sflow->sflow, sflow->sflow_len, 0); + uint32_t hash2; + + if (!sflow->tunnel) { + return hash1; + } + + hash2 = hash_bytes(sflow->tunnel, sizeof *sflow->tunnel, 0); + return hash_add(hash1, hash2); +} + +static bool +dpif_sflow_attr_equal(const struct dpif_sflow_attr *a, + const struct dpif_sflow_attr *b) +{ + if (a->sflow_len != b->sflow_len + || memcmp(a->sflow, b->sflow, a->sflow_len)) { + return false; + } + if (!a->tunnel && !b->tunnel) { + return true; + } + if (a->tunnel && b->tunnel) { + return !memcmp(a->tunnel, b->tunnel, sizeof *a->tunnel); + } + + return false; +} + +/* Lockless RCU protected lookup. If node is needed accross RCU quiescent + * state, caller should take a reference. */ +static struct gid_node * +gid_find_equal(const struct dpif_sflow_attr *target, uint32_t hash) +{ + struct gid_node *node; + + CMAP_FOR_EACH_WITH_HASH (node, metadata_node, hash, &gid_metadata_map) { + if (dpif_sflow_attr_equal(&node->sflow, target)) { + return node; + } + } + return NULL; +} + +static struct gid_node * +gid_ref_equal(const struct dpif_sflow_attr *target, uint32_t hash) +{ + struct gid_node *node; + + do { + node = gid_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->sflow_len = old->sflow_len; + new->sflow = xmalloc(new->sflow_len); + memcpy(CONST_CAST(void *, new->sflow), old->sflow, new->sflow_len); + + new->userdata_len = old->userdata_len; + new->userdata = xmalloc(new->userdata_len); + memcpy(new->userdata, old->userdata, new->userdata_len); + + if (old->tunnel) { + new->tunnel = xzalloc(sizeof *new->tunnel); + memcpy(new->tunnel, old->tunnel, sizeof *new->tunnel); + } else { + new->tunnel = NULL; + } +} + +/* 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 gid_node * +gid_find__(uint32_t id) + OVS_REQUIRES(gid_wrlock) +{ + struct cmap_node *node = cmap_find_protected(&gid_map, id); + + return node ? CONTAINER_OF(node, struct gid_node, id_node) : NULL; +} + +/* Allocate a unique group id for the given set of flow metadata. + * The ID space is 2^^32, so there should never be a situation in which all + * the IDs are used up. We loop until we find a free one. */ +static struct gid_node * +gid_alloc__(const struct dpif_sflow_attr *sflow, uint32_t hash) +{ + struct gid_node *node = xzalloc(sizeof *node); + + node->hash = hash; + ovs_refcount_init(&node->refcount); + dpif_sflow_attr_clone(CONST_CAST(struct dpif_sflow_attr *, &node->sflow), + sflow); + + ovs_rwlock_wrlock(&gid_rwlock); + for (;;) { + node->id = next_group_id++; + if (OVS_UNLIKELY(!node->id)) { + next_group_id = 1; + node->id = next_group_id++; + } + /* Find if the id is free. */ + if (OVS_LIKELY(!gid_find__(node->id))) { + break; + } + } + cmap_insert(&gid_map, &node->id_node, node->id); + cmap_insert(&gid_metadata_map, &node->metadata_node, node->hash); + ovs_rwlock_unlock(&gid_rwlock); + return node; +} + +/* Allocate a unique group id for the given set of flow metadata and + optional actions. */ +static uint32_t +gid_alloc_ctx(const struct dpif_sflow_attr *sflow) +{ + uint32_t hash = dpif_sflow_attr_hash(sflow); + struct gid_node *node = gid_ref_equal(sflow, hash); + + if (!node) { + node = gid_alloc__(sflow, hash); + } + return node->id; +} + +static void +gid_node_unref(const struct gid_node *node_) + OVS_EXCLUDED(gid_rwlock) +{ + struct gid_node *node = CONST_CAST(struct gid_node *, node_); + + ovs_rwlock_wrlock(&gid_rwlock); + if (node && ovs_refcount_unref(&node->refcount) == 1) { + /* Prevent re-use of this node by removing the node from + * gid_metadata_map' */ + cmap_remove(&gid_metadata_map, &node->metadata_node, node->hash); + /* We keep the node in the 'gid_map' so that it can be found as + * long as it lingers, and add it to the 'gid_expiring' list. */ + ovs_list_insert(&gid_expiring, &node->exp_node); + } + ovs_rwlock_unlock(&gid_rwlock); +} + +static void +gid_free(uint32_t id) +{ + const struct gid_node *node; + + node = gid_find(id); + if (node) { + gid_node_unref(node); + } else { + VLOG_ERR("Freeing nonexistent group ID: %"PRIu32, id); + } +} + static bool is_internal_port(const char *type) { @@ -199,6 +450,9 @@ del_filter_and_ufid_mapping(struct tcf_id *id, const ovs_u128 *ufid) err = tc_del_filter(id); del_ufid_tc_mapping(ufid); + if (id->sflow_group_id) { + gid_free(id->sflow_group_id); + } return err; } @@ -394,6 +648,8 @@ netdev_tc_flow_dump_create(struct netdev *netdev, *dump_out = dump; + gid_cleanup(); + return 0; } @@ -1793,6 +2049,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); + gid_alloc_ctx(&sflow_attr); } else { VLOG_DBG_RL(&rl, "unsupported put action type: %d", nl_attr_type(nla)); diff --git a/lib/tc.h b/lib/tc.h index 281231c0d..cc2ad025d 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -273,6 +273,7 @@ struct tcf_id { uint32_t chain; uint16_t prio; uint32_t handle; + uint32_t sflow_group_id; }; static inline struct tcf_id From patchwork Mon Sep 14 12:07:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Mi X-Patchwork-Id: 1363554 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=whitealder.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nvidia.com Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BqlWC1bbfz9sR4 for ; Mon, 14 Sep 2020 22:08:23 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id B093A866C1; Mon, 14 Sep 2020 12:08:21 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id oV04nlbw+aKm; Mon, 14 Sep 2020 12:08:13 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by whitealder.osuosl.org (Postfix) with ESMTP id B33B886A37; Mon, 14 Sep 2020 12:08:07 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 5B87EC08A6; Mon, 14 Sep 2020 12:08:07 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id A08F7C0859 for ; Mon, 14 Sep 2020 12:08:03 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 9B8D787213 for ; Mon, 14 Sep 2020 12:08:03 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 31lahEciEsNW for ; Mon, 14 Sep 2020 12:08:02 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id EA46887201 for ; Mon, 14 Sep 2020 12:08:01 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from cmi@nvidia.com) with SMTP; 14 Sep 2020 15:07:59 +0300 Received: from dev-r630-04.mtbc.labs.mlnx (dev-r630-04.mtbc.labs.mlnx [10.75.205.14]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 08EC7l4r018898; Mon, 14 Sep 2020 15:07:58 +0300 From: Chris Mi To: dev@openvswitch.org Date: Mon, 14 Sep 2020 20:07:45 +0800 Message-Id: <20200914120745.16373-9-cmi@nvidia.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200914120745.16373-1-cmi@nvidia.com> References: <20200914120745.16373-1-cmi@nvidia.com> MIME-Version: 1.0 Cc: elibr@nvidia.com, Chris Mi Subject: [ovs-dev] [PATCH v2 8/8] 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: , 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. Change-Id: I71ef18c70c86f030cae9159485e5ae11bc608301 Signed-off-by: Chris Mi Reviewed-by: Eli Britstein --- lib/netdev-offload-tc.c | 131 +++++++++++++++++++++++++++++++++++++--- lib/tc.c | 59 ++++++++++++++++++ lib/tc.h | 9 ++- 3 files changed, 188 insertions(+), 11 deletions(-) diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 50b6f0142..0d7382609 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -981,6 +981,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 gid_node *node; + + node = gid_find(action->sample.action_group_id); + if (!node) { + VLOG_ERR_RL(&error_rl, "gid node is NULL, gid: %d", + action->sample.action_group_id); + return ENOENT; + } + nl_msg_put(buf, node->sflow.sflow, node->sflow.sflow_len); + } + break; case TC_ACT_VLAN_POP: { nl_msg_put_flag(buf, OVS_ACTION_ATTR_POP_VLAN); } @@ -1660,6 +1672,74 @@ flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl, flower->mask.tunnel.metadata.present.len = tnl->metadata.present.len; } +static int +parse_userspace_userdata(const struct nlattr *actions, + struct dpif_sflow_attr *sflow_attr) +{ + const struct nlattr *nla; + unsigned int left; + + NL_NESTED_FOR_EACH_UNSAFE (nla, left, actions) { + if (nl_attr_type(nla) == OVS_USERSPACE_ATTR_USERDATA) { + sflow_attr->userdata = CONST_CAST(void *, nl_attr_get(nla)); + sflow_attr->userdata_len = nl_attr_get_size(nla); + return 0; + } + } + + VLOG_ERR_RL(&error_rl, "%s: no OVS_USERSPACE_ATTR_USERDATA attribute", + __func__); + return EINVAL; +} + +static int +parse_action_userspace(const struct nlattr *actions, + struct dpif_sflow_attr *sflow_attr) +{ + const struct nlattr *nla; + unsigned int left; + + NL_NESTED_FOR_EACH_UNSAFE (nla, left, actions) { + if (nl_attr_type(nla) == OVS_ACTION_ATTR_USERSPACE) { + return parse_userspace_userdata(nla, sflow_attr); + } + } + + VLOG_ERR_RL(&error_rl, "%s: no OVS_ACTION_ATTR_USERSPACE attribute", + __func__); + return EINVAL; +} + +static int +parse_sample_action(const struct nlattr *actions, + struct dpif_sflow_attr *sflow_attr, + struct tc_action *tc_action) +{ + const struct nlattr *nla; + unsigned int left; + int ret = EINVAL; + + sflow_attr->sflow = actions; + sflow_attr->sflow_len = actions->nla_len; + + NL_NESTED_FOR_EACH_UNSAFE (nla, left, actions) { + if (nl_attr_type(nla) == OVS_SAMPLE_ATTR_ACTIONS) { + ret = parse_action_userspace(nla, sflow_attr); + } else if (nl_attr_type(nla) == OVS_SAMPLE_ATTR_PROBABILITY) { + tc_action->type = TC_ACT_SAMPLE; + tc_action->sample.action_rate = UINT32_MAX / nl_attr_get_u32(nla); + } else { + return EINVAL; + } + } + + if (tc_action->sample.action_rate) { + return ret; + } + + return EINVAL; +} + static int netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct nlattr *actions, size_t actions_len, @@ -1676,6 +1756,7 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct tc_action *action; bool recirc_act = false; uint32_t block_id = 0; + uint32_t group_id = 0; struct nlattr *nla; struct tcf_id id; uint32_t chain; @@ -1965,7 +2046,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) { @@ -1975,7 +2057,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)); @@ -2013,7 +2096,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; @@ -2026,7 +2109,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); @@ -2034,7 +2117,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; @@ -2053,17 +2136,25 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, struct dpif_sflow_attr sflow_attr; memset(&sflow_attr, 0, sizeof sflow_attr); - gid_alloc_ctx(&sflow_attr); + if (flower.tunnel) { + sflow_attr.tunnel = CONST_CAST(struct flow_tnl *, tnl); + } + parse_sample_action(nla, &sflow_attr, action); + group_id = gid_alloc_ctx(&sflow_attr); + action->sample.action_group_id = group_id; + flower.action_count++; } 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) { @@ -2075,20 +2166,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_chain(ifindex, block_id, chain, prio, hook, group_id); 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 (group_id) { + gid_free(group_id); } return err; @@ -2298,6 +2399,15 @@ netdev_tc_init_flow_api(struct netdev *netdev) return 0; } +static const struct dpif_sflow_attr * +netdev_tc_sflow_attr_get(uint32_t gid) +{ + const struct gid_node *node; + + node = gid_find(gid); + return node ? &node->sflow : NULL; +} + const struct netdev_flow_api netdev_offload_tc = { .type = "linux_tc", .flow_flush = netdev_tc_flow_flush, @@ -2308,4 +2418,5 @@ const struct netdev_flow_api netdev_offload_tc = { .flow_get = netdev_tc_flow_get, .flow_del = netdev_tc_flow_del, .init_flow_api = netdev_tc_init_flow_api, + .sflow_attr_get = netdev_tc_sflow_attr_get, }; diff --git a/lib/tc.c b/lib/tc.c index 8761304c9..128d7f637 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -1289,6 +1290,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.action_group_id = + nl_attr_get_u32(sample_attrs[TCA_SAMPLE_PSAMPLE_GROUP]); + action->sample.action_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), @@ -1697,6 +1730,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; @@ -2292,6 +2327,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) { @@ -2551,6 +2603,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.action_rate, + action->sample.action_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 cc2ad025d..143e225d1 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -171,6 +171,7 @@ enum tc_action_type { TC_ACT_MPLS_SET, TC_ACT_GOTO, TC_ACT_CT, + TC_ACT_SAMPLE, }; enum nat_type { @@ -253,6 +254,11 @@ struct tc_action { bool force; bool commit; } ct; + + struct { + uint32_t action_rate; + uint32_t action_group_id; + } sample; }; enum tc_action_type type; @@ -292,11 +298,12 @@ 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) + uint16_t prio, enum tc_qdisc_hook hook, uint32_t group_id) { struct tcf_id id = tc_make_tcf_id(ifindex, block_id, prio, hook); id.chain = chain; + id.sflow_group_id = group_id; return id; }