From patchwork Fri Sep 30 12:52:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117211 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 603DFA00C4; Fri, 30 Sep 2022 14:53:41 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 8C35E41109; Fri, 30 Sep 2022 14:53:38 +0200 (CEST) Received: from NAM12-DM6-obe.outbound.protection.outlook.com (mail-dm6nam12on2083.outbound.protection.outlook.com [40.107.243.83]) by mails.dpdk.org (Postfix) with ESMTP id 428DD410F1 for ; Fri, 30 Sep 2022 14:53:37 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Sz6Mo0Y8C2bE0JLLug/TY2QLgZI8qYjVBuyaevhgo9/Qx0WHHY/hB+f8Sbb8FYOIUMcXTFeeKbLKor937738VsKp7OmgRwBJoi/jkCYwBGnTF85M4Pafbbn7BRiur2/2SqUtsnBpZwSSQYjXRmvodD1QIci5NQEbl6U7seZjCLVXUgxhLswGiHEkMW2nuh2TTd7FwepWervKy4Edh/XeyKPV6XAFVCPha6vc3zvTkEhZzZD8Pld8UefLOiZa2KSmNjb/93wQDMdmvarqkzgI+V1GiMq9Bz/B77J5/p653h3gQlfBSCM/jh1IFqYs/FXVJU8X6CyqA570IJ9RPqeunQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=goiGszEK2wkTBVdfH60M4bQH5xVO0vR8E/E/a45ES0w=; b=bCm9uB0Q71iNf1uv3eDB0PCO6HILe3yfnaDbcY1UHYZ276N7q5VpdMYRH8KlI1GzOetrSmksRJbpe/RoH6K37dPAHIjWUHy7NIuRCc4IH0EpmesrLOV/myYeVH4C7CJ5RLBmdbiyxB6dJ+ZZUC4DfJXjiOW1IJ+xIN3yWyPzzflOiX+UoQYLx/wnTrho8dAQmIA7sIwoj9fnDz8dxqJOAFweVQ9xgH44uMWeUP5hIRWB8ofnoaKgrwnWQf36CUe0c0V37OJkmnoK6nRBEtQK5DKbQudy0gxOthHdT4SK7SIRG/yXHZY8BXg6NDSzivB2TqpdacMcCeI510jqwhSG8Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=goiGszEK2wkTBVdfH60M4bQH5xVO0vR8E/E/a45ES0w=; b=IUIb+7ORzjde4CVdT3PIix4OAELnGrJX4wegXHjChRWeWw2zTuyVtljpJ3xFcwYE/gkCNWXV1AxfMItaX98p5IcxX3QwlGLARuYkdgv6CYLDN26exl57VWc/3CRBcVgTw0EduqVV4ftar3mlZZINbX4sMk6oAb49lx5xmm/IUbMbbMY2nbdEPwOYdVsxRa/mwbChz36flneXI0MqZnJ7NQBflfG47x/xzIWbSEPsKVT7u1QblsDQYaovJG4VWs9sAlqXR7D8GtQXNV+YX+yhUlrUEiI033KTqrkTVBytYeLXG+ThD28Wnm8mLnkkcAnjd077RxJaGPgmgKuidEJPUQ== Received: from DS7PR06CA0041.namprd06.prod.outlook.com (2603:10b6:8:54::10) by CY8PR12MB7361.namprd12.prod.outlook.com (2603:10b6:930:53::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17; Fri, 30 Sep 2022 12:53:35 +0000 Received: from DM6NAM11FT031.eop-nam11.prod.protection.outlook.com (2603:10b6:8:54:cafe::1b) by DS7PR06CA0041.outlook.office365.com (2603:10b6:8:54::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23 via Frontend Transport; Fri, 30 Sep 2022 12:53:35 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT031.mail.protection.outlook.com (10.13.172.203) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:53:35 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:34 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:33 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , Subject: [PATCH v3 01/17] net/mlx5: fix invalid flow attributes Date: Fri, 30 Sep 2022 15:52:59 +0300 Message-ID: <20220930125315.5079-2-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT031:EE_|CY8PR12MB7361:EE_ X-MS-Office365-Filtering-Correlation-Id: 66939b0e-a08b-47ae-2082-08daa2e2c9a9 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: dA1ZiYsVe44JRwNfYiTKepkuPkVhefL6dx42MFSJchsQXDljHaM3etzfj+/WYqna56ixGA19D1UpOxKN4T6yi68XfvPYhT7X5ve//VHjJVHtYcwaYF0k1lojTKTKU+NR7zWSF54lKRmnVCdAGi61NCU4KoE2sO7MulxIDIcSLwerkGUDCFsciMQC3GvOSGdJRrWsa4h466UJxQIr6pHJwobJpd0+5SVGh9BK9ODCeTW+f5jR4JMffe/ozbV4SOrRN6oUz9kqQjNTrmlJebstiMybUl3dnrnsl3zaYvNsjoItXLteEErT7uDkhq5lFDWxoWthrV+hc11uhWVuEgtAf9YnCB6Htkf71P0fH+zYpYpDDF+o3ny6BE67RKmXlvO66RABGfPGc1LzhNKdREd2ebhPKJHmTfb46deUEtQ7vCgVQ9dzRZKE9+QUPPKjVOJIReVQhmg0Ji82R3SRI3FwcU0H20FB7u35uYVDY820LCIrTiulygY6m/m9NOOq8ak8HaPmQnYcREGxHdVtMqtG9NVITVuqRvWb7Z1//eGGgprymk7Vf9zDgder55iZQKHUCVvM55CtQ79s6j5oPlPSWi7esXCaVwYrCUjSIWIS8pkjxYfuwrvsj9JGMeCfu8UuEXNO7fQJ9fyPIJc+VV5YiKI+rnfGgIaM8/VJp39mJ5m2iozv27xui7hbTtWicqk16yBqs8YCKheKre71xRji+OQqJL5oEmsqaCoo/tQjZFMqQPX6s03yQfca6fCGcFZI8Fl+rx7mIDJhOKfPMJz17Q== X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(396003)(136003)(39860400002)(376002)(346002)(451199015)(46966006)(36840700001)(40470700004)(7636003)(1076003)(2616005)(2906002)(186003)(16526019)(336012)(82740400003)(70586007)(70206006)(4326008)(8676002)(41300700001)(6666004)(107886003)(478600001)(6636002)(316002)(86362001)(110136005)(55016003)(40460700003)(36756003)(40480700001)(7696005)(6286002)(26005)(82310400005)(8936002)(5660300002)(54906003)(356005)(47076005)(426003)(36860700001)(83380400001); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:53:35.4553 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 66939b0e-a08b-47ae-2082-08daa2e2c9a9 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT031.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY8PR12MB7361 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org In the function flow_get_drv_type(), attr will be read in non-HWS mode. In case user call the HWS API in SWS mode, attr should be placed in HWS functions, or it will cause crash. Fixes: 572801ab860f ("ethdev: backport upstream rte_flow_async codes") Signed-off-by: Suanming Mou --- drivers/net/mlx5/mlx5_flow.c | 38 ++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 45109001ca..3abb39aa92 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -3740,6 +3740,8 @@ flow_get_drv_type(struct rte_eth_dev *dev, const struct rte_flow_attr *attr) */ if (priv->sh->config.dv_flow_en == 2) return MLX5_FLOW_TYPE_HW; + if (!attr) + return MLX5_FLOW_TYPE_MIN; /* If no OS specific type - continue with DV/VERBS selection */ if (attr->transfer && priv->sh->config.dv_esw_en) type = MLX5_FLOW_TYPE_DV; @@ -8252,8 +8254,9 @@ mlx5_flow_info_get(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) + if (flow_get_drv_type(dev, &attr) != MLX5_FLOW_TYPE_HW) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8287,8 +8290,9 @@ mlx5_flow_port_configure(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) + if (flow_get_drv_type(dev, &attr) != MLX5_FLOW_TYPE_HW) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8319,8 +8323,9 @@ mlx5_flow_pattern_template_create(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr fattr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) { + if (flow_get_drv_type(dev, &fattr) != MLX5_FLOW_TYPE_HW) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8350,8 +8355,9 @@ mlx5_flow_pattern_template_destroy(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) + if (flow_get_drv_type(dev, &attr) != MLX5_FLOW_TYPE_HW) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8385,8 +8391,9 @@ mlx5_flow_actions_template_create(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr fattr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) { + if (flow_get_drv_type(dev, &fattr) != MLX5_FLOW_TYPE_HW) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8416,8 +8423,9 @@ mlx5_flow_actions_template_destroy(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) + if (flow_get_drv_type(dev, &attr) != MLX5_FLOW_TYPE_HW) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8457,8 +8465,9 @@ mlx5_flow_table_create(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr fattr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) { + if (flow_get_drv_type(dev, &fattr) != MLX5_FLOW_TYPE_HW) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8494,8 +8503,9 @@ mlx5_flow_table_destroy(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) + if (flow_get_drv_type(dev, &attr) != MLX5_FLOW_TYPE_HW) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8542,8 +8552,9 @@ mlx5_flow_async_flow_create(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr fattr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) { + if (flow_get_drv_type(dev, &fattr) != MLX5_FLOW_TYPE_HW) { rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8585,8 +8596,9 @@ mlx5_flow_async_flow_destroy(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr fattr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) + if (flow_get_drv_type(dev, &fattr) != MLX5_FLOW_TYPE_HW) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8621,8 +8633,9 @@ mlx5_flow_pull(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) + if (flow_get_drv_type(dev, &attr) != MLX5_FLOW_TYPE_HW) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -8650,8 +8663,9 @@ mlx5_flow_push(struct rte_eth_dev *dev, struct rte_flow_error *error) { const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = {0}; - if (flow_get_drv_type(dev, NULL) != MLX5_FLOW_TYPE_HW) + if (flow_get_drv_type(dev, &attr) != MLX5_FLOW_TYPE_HW) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, From patchwork Fri Sep 30 12:53:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117212 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 16528A00C4; Fri, 30 Sep 2022 14:53:47 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 99FF3427FF; Fri, 30 Sep 2022 14:53:41 +0200 (CEST) Received: from NAM11-DM6-obe.outbound.protection.outlook.com (mail-dm6nam11on2056.outbound.protection.outlook.com [40.107.223.56]) by mails.dpdk.org (Postfix) with ESMTP id 359A2427F7 for ; Fri, 30 Sep 2022 14:53:40 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=HNiX9VOsDM0Tww32Mu3WKGI7WgkFbSmWyrUvyH9rinXG9DeQzcsCjEVufHDnnrPzgDmxo2Tn+Jjdw89Ja30ounSlwhUKeaa3Z8tWYq9J1nxvHNxrpue5nnF6ygWM3BTZ6aUymz7fgi5igfLGMfToY0kHLF6lWWG/Rtje/xsFDIpXr2WkwNwlmpIyd1pXHDhDwoFLUSPJIYamJCUdk572xqy/cbAMSg4Mb0CzIjReBjCuateXa1FIG/0on2ZkCIOS1M+Rw/29GvrDMHKj5yjJkviVm+Pefy1Rv679cQS9ayfEPvepAk+/4NYN5IRHcob8ul2hLjMZaalNZbDi5csS+w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=xp1uG7lXWoJZED9yFGOon62/RzvbCOcMxRH4AQGbBSI=; b=exh0IlKTbrP74lsMfmKMPHB2yNWYvvE9FjcXElYHpnZhMZlzeYfwRq33Yznl3Z1+M1vkMKdczSmt1ZCXVwmLsckMmCw8D44U5h1ECJiQr9waBwJ5zQHG5LfM/20Ysa9kBfMKiZPkK2ePeCJvMoXpA7f06pNX6LZM8LyKmniN0hd5nBBPGE1m32Uhf4m6ei6y/TRcsxVnM9JmW7uHMzyGUuPWiLVingfi0EMUOuG19Un9kpk0L7kUlD/gEExNLuDwfxu9mq6lKsue8i7oHXSEuv0K9RPJziZszNwdTMwA7J190lUIH6A4fGgngIdkXNLjHL+5/S06TxwGpZLx3qvI7g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.161) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=xp1uG7lXWoJZED9yFGOon62/RzvbCOcMxRH4AQGbBSI=; b=LHZlR+bu9pwrJOz56qXba3RWvm4YYKOI4BV3B8eN5bJ+MdcFzlzHFPZ30yDhX5Mrq98Qwv6dAdq+fJYqTP2Mrw/7xivlbn4WkJR0KMiDwBNMzR8O0o4UXMXfqO7iUDrX23quf1ERAZrocfkjafhPMxbP81JHWUrC7YID5/WsTn96URQN9f+1oCbndDxRgZtJe6vbBw/5Li1yXUWY4r1xvQuPb9bOMCUvExNgBMChm79nHCXzpXgiTPyE+vwKfSVsPSDUa+AFoWm3pZznf7lr9quXcw2H8hTdlStiZNJ6rutxcAtinSANBs2tiCBOioIQK0+5Aapk0NtDz9J5KHcX0g== Received: from DM5PR07CA0056.namprd07.prod.outlook.com (2603:10b6:4:ad::21) by DM4PR12MB5391.namprd12.prod.outlook.com (2603:10b6:5:39a::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23; Fri, 30 Sep 2022 12:53:38 +0000 Received: from DM6NAM11FT105.eop-nam11.prod.protection.outlook.com (2603:10b6:4:ad:cafe::11) by DM5PR07CA0056.outlook.office365.com (2603:10b6:4:ad::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.18 via Frontend Transport; Fri, 30 Sep 2022 12:53:37 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.161) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.161 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.161; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.161) by DM6NAM11FT105.mail.protection.outlook.com (10.13.173.164) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:53:37 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.67) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:36 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:35 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , Subject: [PATCH v3 02/17] net/mlx5: fix IPv6 and TCP RSS hash fields Date: Fri, 30 Sep 2022 15:53:00 +0300 Message-ID: <20220930125315.5079-3-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT105:EE_|DM4PR12MB5391:EE_ X-MS-Office365-Filtering-Correlation-Id: 32b25d43-0a83-40c4-76f3-08daa2e2cb05 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: lpo0jFLiFASb6KgFN0yZNbqnxnxigA1L1OVZgPdYum6zqiA3ZdD4suRchvq7A9F/hCRG+Qq6CGO15OYbTESoNzesxyzSZoeCTdWIPpVcDF5AtfBrA7nSPE/uup22frK2NU6JgPiJzt0geFUqzBED1D2+cOQWM5lE0/d2V/KNOa11VhgvzNMQPfjVEpEA8ezQojVHwcN8ms4EvoENhNiITYUl3mnZdgA8i515XX+vAPubfP32V3LLEOx3uC2qCphR3GkkOXYBZKkKmvCn1ZAdIiQ4W3YVngwCQWaJkbGgvlwAT0P9NWYYNTRpdwpHeF7HgR9pQVrv75yl8zPI5i3iGte6VJKifagSZMF70cPva+gzSApbuW0r4bOuGfsBk+6CWw165ltz92Ub7agwkbXVQuzrg6wdtvP6Hb1IzT7t7HmqbYIOTcOFU4oKXD/bcT/Rt5sGwrKmvP6asBjnPKf99OvFnGf1GoF3LB77OB43kx1hUOh8d8DiCQhQ9tP6zrxZCmynK5KtyJ7gkDe65pZP8qcBvaPBKPq/lIJgJe8/AobdQtNseKYgTDtQXbGrBQ+YjrMDMdhWFeKpDwaadYuTobWd1i7IAoNzzdDbIynBUdVT319YBnEfKSzOrLKAlyyT/Z1I38Rq5u1s8Z7lJ7HZzQv3kvYNFKkOLiZAHoTufq98vty/+32zP9TjQFqivbC3S8yd+SQa/uB2a6mdlXm4lPz1rzwwnrVQUQzG/6vAUZuTDuhyiCcRR3GkzKfP1h+EGBsa93l+Obt9ySbKSnjZ8Q== X-Forefront-Antispam-Report: CIP:216.228.117.161; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge2.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(39860400002)(346002)(136003)(376002)(396003)(451199015)(46966006)(36840700001)(40470700004)(54906003)(6636002)(336012)(1076003)(55016003)(2906002)(110136005)(7636003)(356005)(40480700001)(40460700003)(36860700001)(36756003)(8936002)(70206006)(83380400001)(41300700001)(16526019)(8676002)(5660300002)(4326008)(70586007)(82740400003)(47076005)(426003)(316002)(2616005)(26005)(6286002)(86362001)(7696005)(107886003)(6666004)(82310400005)(478600001)(186003); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:53:37.7225 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 32b25d43-0a83-40c4-76f3-08daa2e2cb05 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.161]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT105.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM4PR12MB5391 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org In the flow_dv_hashfields_set() function, while item_flags was 0, the code went directly to the first if and the else case would never have chance be checked. This caused the IPv6 and TCP hash fileds in the else case would never be set. This commit adds the dedicate HW steering hash field set function to generate the RSS hash fields. Fixes: 6540da0b93b5 ("net/mlx5: fix RSS scaling issue") Signed-off-by: Suanming Mou --- drivers/net/mlx5/mlx5_flow_dv.c | 12 +++---- drivers/net/mlx5/mlx5_flow_hw.c | 59 ++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index fb08684114..cb034a01f9 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -11299,8 +11299,7 @@ flow_dv_hashfields_set(uint64_t item_flags, rss_inner = 1; #endif if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) || - (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4)) || - !items) { + (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) { if (rss_types & MLX5_IPV4_LAYER_TYPES) { if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) fields |= IBV_RX_HASH_SRC_IPV4; @@ -11310,8 +11309,7 @@ flow_dv_hashfields_set(uint64_t item_flags, fields |= MLX5_IPV4_IBV_RX_HASH; } } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) || - (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6)) || - !items) { + (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) { if (rss_types & MLX5_IPV6_LAYER_TYPES) { if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) fields |= IBV_RX_HASH_SRC_IPV6; @@ -11334,8 +11332,7 @@ flow_dv_hashfields_set(uint64_t item_flags, return; } if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) || - (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP)) || - !items) { + (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) { if (rss_types & RTE_ETH_RSS_UDP) { if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) fields |= IBV_RX_HASH_SRC_PORT_UDP; @@ -11345,8 +11342,7 @@ flow_dv_hashfields_set(uint64_t item_flags, fields |= MLX5_UDP_IBV_RX_HASH; } } else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) || - (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP)) || - !items) { + (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) { if (rss_types & RTE_ETH_RSS_TCP) { if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) fields |= IBV_RX_HASH_SRC_PORT_TCP; diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 7343d59f1f..46c4169b4f 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -62,6 +62,63 @@ flow_hw_rxq_flag_set(struct rte_eth_dev *dev, bool enable) priv->mark_enabled = enable; } +/** + * Set the hash fields according to the @p rss_desc information. + * + * @param[in] rss_desc + * Pointer to the mlx5_flow_rss_desc. + * @param[out] hash_fields + * Pointer to the RSS hash fields. + */ +static void +flow_hw_hashfields_set(struct mlx5_flow_rss_desc *rss_desc, + uint64_t *hash_fields) +{ + uint64_t fields = 0; + int rss_inner = 0; + uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types); + +#ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT + if (rss_desc->level >= 2) + rss_inner = 1; +#endif + if (rss_types & MLX5_IPV4_LAYER_TYPES) { + if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) + fields |= IBV_RX_HASH_SRC_IPV4; + else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) + fields |= IBV_RX_HASH_DST_IPV4; + else + fields |= MLX5_IPV4_IBV_RX_HASH; + } else if (rss_types & MLX5_IPV6_LAYER_TYPES) { + if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY) + fields |= IBV_RX_HASH_SRC_IPV6; + else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY) + fields |= IBV_RX_HASH_DST_IPV6; + else + fields |= MLX5_IPV6_IBV_RX_HASH; + } + if (rss_types & RTE_ETH_RSS_UDP) { + if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) + fields |= IBV_RX_HASH_SRC_PORT_UDP; + else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) + fields |= IBV_RX_HASH_DST_PORT_UDP; + else + fields |= MLX5_UDP_IBV_RX_HASH; + } else if (rss_types & RTE_ETH_RSS_TCP) { + if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY) + fields |= IBV_RX_HASH_SRC_PORT_TCP; + else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY) + fields |= IBV_RX_HASH_DST_PORT_TCP; + else + fields |= MLX5_TCP_IBV_RX_HASH; + } + if (rss_types & RTE_ETH_RSS_ESP) + fields |= IBV_RX_HASH_IPSEC_SPI; + if (rss_inner) + fields |= IBV_RX_HASH_INNER; + *hash_fields = fields; +} + /** * Generate the pattern item flags. * Will be used for shared RSS action. @@ -225,7 +282,7 @@ flow_hw_tir_action_register(struct rte_eth_dev *dev, MLX5_RSS_HASH_KEY_LEN); rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN; rss_desc.types = !rss->types ? RTE_ETH_RSS_IP : rss->types; - flow_dv_hashfields_set(0, &rss_desc, &rss_desc.hash_fields); + flow_hw_hashfields_set(&rss_desc, &rss_desc.hash_fields); flow_dv_action_rss_l34_hash_adjust(rss->types, &rss_desc.hash_fields); if (rss->level > 1) { From patchwork Fri Sep 30 12:53:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117213 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 38E64A00C4; Fri, 30 Sep 2022 14:53:55 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id D56044280E; Fri, 30 Sep 2022 14:53:47 +0200 (CEST) Received: from NAM11-CO1-obe.outbound.protection.outlook.com (mail-co1nam11on2053.outbound.protection.outlook.com [40.107.220.53]) by mails.dpdk.org (Postfix) with ESMTP id B0890427F7 for ; Fri, 30 Sep 2022 14:53:45 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=exRU0qYbjCaW5q7Z5NhmqXskkkJO4iJPVhTapXyhmpEjvthKpqKpFbd8DgVitiHaCspR/PB323jhYVxXUKRhBWcJpF1/pAZCuXEBFHWq/ACF+b3T1+NprGvxW2rqDUWDggoP40acIgDk+C/vjBNLMXX9zk6NSuskVK2+26kdt4lBCug6ZteoVyWDndQJTx/Ul3sqO55wlhcB5ivmayp84JacxB23HnSWUbHRPObIMEkRticvSvtf9xIzzxd/V3PQU1DWm2izONA/6tCPvWeeKZCqgbvUf+u8tu511oA4G+vkrH647l351kP3YuM/LlC8C+ozEMOkQnN4/AAv32A5QQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ybLPPrfAx5pOZBmLeKwO8WikZMPmbcU7ZawPMEOSslY=; b=jWsUm73LRqnMzxiL4vbBisgt+j9LScJ9sQEiEaNP5bHEJi36JQgOpYpQsf+VfZ/qStxfgzuQU23ZBw278u4pZeEtcT222Z1ANeibfzkX3qIySuDGqTLrgVvuhAq9OGo9jRGzuNz0ijEImjt5ExQHrVNI+gLZyJB3dDAFpl0LGAGmQKx72+TV8aubLcwXu2z0FGje7P3QaGm6m5U/Jt/9QGZgtfKUt8I76p+yiPEV2fzqAZFs9P4HaED0bPrsdUWLJ/9UViEkGnwtUBC3cQU3SBU5hvfdZ6IpZQxZ1qeuhy6RXmEtJSHt22WMvlnDaq/GqrBZOmnM3A4LJg3bbXMYQg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ybLPPrfAx5pOZBmLeKwO8WikZMPmbcU7ZawPMEOSslY=; b=hQ9NwbrmASgBLLg3AHxvR/xjZHAZfvYrH/C5sXsUC8+jE12/TaCYNIealgtsOhD3uwLntjOPaESzaWtKqnZ96/i0FsI0NFMaLWlQCTwvGQN41tFrlUtxQmnc/GMOaq0+rON8NNDR0pOJ0KwmuXKoIFM8SBzTu9MQB6cGV1eBoBQ2yKxjCbWwM2fCx4mhlzLpoMQi8N4VeRTylIFZuRg4aUJiRQ2LZhYwqLiUgzJx9k+WvXAnC6kJQMkCb/PFXc8V+QtVqsEp0juxXRRrjseCSvmUIgnSKm2FUUVqSJCH0Eq0+zPCgx9x84NcZVWk5SoSe9E30mvzEwLasfxk+7/4Jg== Received: from DS7PR06CA0038.namprd06.prod.outlook.com (2603:10b6:8:54::19) by LV2PR12MB5800.namprd12.prod.outlook.com (2603:10b6:408:178::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.20; Fri, 30 Sep 2022 12:53:43 +0000 Received: from DM6NAM11FT031.eop-nam11.prod.protection.outlook.com (2603:10b6:8:54:cafe::1e) by DS7PR06CA0038.outlook.office365.com (2603:10b6:8:54::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23 via Frontend Transport; Fri, 30 Sep 2022 12:53:43 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT031.mail.protection.outlook.com (10.13.172.203) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:53:43 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:39 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:37 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , Subject: [PATCH v3 03/17] net/mlx5: add shared header reformat support Date: Fri, 30 Sep 2022 15:53:01 +0300 Message-ID: <20220930125315.5079-4-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT031:EE_|LV2PR12MB5800:EE_ X-MS-Office365-Filtering-Correlation-Id: d248b72d-59cb-44f9-f8bc-08daa2e2ce68 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: vQiCeSYOa+CYrs4s/ZE3kAciGAOY517vUKn9J/bbSpqOf0W8C52DCM8+iDKKSWJcTI6CfuL8ldBRlOM4iZMUnZryWQ0JVo7+ZJAP4ZwKimYfpi5tLsHe1U6BAMb7dJuGwKByX8oRvPIpCCeqpnf7XGvTFsMp6PMBvPTR/Itl7RzXFqTE25kUKAUS6bzRo/Uwx58ojomgUCTHrthx986KlF2egTTbLKZqvfmv+6g31HofkSJtvYSpaqmsnOkq28J7jY0IqRXGDvxK8CZHT/JsFTIS6zYHWB/nUcYn0KgWgxjwRKvhdhwMXiel3DMhdIOySe5I/vZcA6mI5qB48kfo+HsoVrq524krqRRHPfpx0F4m8WZPyqx8a26I1EQnlfTiQYqfmVEIuuBeO3nFYvpaPksD6z/4PeldPCb0DpuE6g/ZClLQXeG3NalSmPEXHKSx5bKAfxEqCuRrcBpMIQvET6nSrjenLsiPJTeqaqf/XBByQ8cS10EVj3oOwc57arH/fTz0g56VEUsvTzj/HB7jDCznT5KIkzb/qexHWcqnmsacHTOVz4aBtKEgPCcLKIOHq42YoAidTEFVALNJuC7Kkelk/bXCAYmhQXL16+847TU4ZuTNamDOpgNDEBUJZaEOUVWMDxIIlYshC+//l0dg5u4s1rmbbZOtQr61okAMxpN5NJU7joSsybM/y+hgk3fDz0yYO20wzEKA8w40PVWCA5yvaOof5FOELtmhhyYGjsckieROyO2cJRbxUS/UkxUM9zZdoIg4CeS2DxZQV92vzg== X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(376002)(396003)(39860400002)(346002)(136003)(451199015)(40470700004)(46966006)(36840700001)(47076005)(7636003)(82310400005)(8676002)(336012)(316002)(4326008)(426003)(86362001)(54906003)(1076003)(186003)(110136005)(6636002)(2616005)(16526019)(82740400003)(478600001)(26005)(70206006)(40460700003)(70586007)(356005)(7696005)(6286002)(6666004)(107886003)(83380400001)(2906002)(55016003)(36756003)(36860700001)(40480700001)(5660300002)(41300700001)(8936002); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:53:43.4234 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: d248b72d-59cb-44f9-f8bc-08daa2e2ce68 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT031.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV2PR12MB5800 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org As the rte_flow_async API defines, the action mask with field value not be 0 means the action will be used as shared in all the flows in the table. The header reformat action with action mask field not be 0 will be created as constant shared action. For encapsulation header reformat action, there are two kinds of encapsulation data, raw_encap_data and rte_flow_item encap_data. Both of these two kinds of data can be identified from the action mask conf as constant or not. Examples: 1. VXLAN encap (encap_data: rte_flow_item) action conf (eth/ipv4/udp/vxlan_hdr) a. action mask conf (eth/ipv4/udp/vxlan_hdr) - items are constant. b. action mask conf (NULL) - items will change. 2. RAW encap (encap_data: raw) action conf (raw_data) a. action mask conf (not NULL) - encap_data constant. b. action mask conf (NULL) - encap_data will change. Signed-off-by: Suanming Mou --- drivers/net/mlx5/mlx5_flow.h | 6 +- drivers/net/mlx5/mlx5_flow_hw.c | 124 ++++++++++---------------------- 2 files changed, 39 insertions(+), 91 deletions(-) diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 4b53912b79..1c9f5fc1d5 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -1064,10 +1064,6 @@ struct mlx5_action_construct_data { uint16_t action_dst; /* mlx5dr_rule_action dst offset. */ union { struct { - /* encap src(item) offset. */ - uint16_t src; - /* encap dst data offset. */ - uint16_t dst; /* encap data len. */ uint16_t len; } encap; @@ -1110,6 +1106,8 @@ struct mlx5_hw_jump_action { /* Encap decap action struct. */ struct mlx5_hw_encap_decap_action { struct mlx5dr_action *action; /* Action object. */ + /* Is header_reformat action shared across flows in table. */ + bool shared; size_t data_size; /* Action metadata size. */ uint8_t data[]; /* Action data. */ }; diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 46c4169b4f..b6978bd051 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -402,10 +402,6 @@ __flow_hw_act_data_general_append(struct mlx5_priv *priv, * Offset of source rte flow action. * @param[in] action_dst * Offset of destination DR action. - * @param[in] encap_src - * Offset of source encap raw data. - * @param[in] encap_dst - * Offset of destination encap raw data. * @param[in] len * Length of the data to be updated. * @@ -418,16 +414,12 @@ __flow_hw_act_data_encap_append(struct mlx5_priv *priv, enum rte_flow_action_type type, uint16_t action_src, uint16_t action_dst, - uint16_t encap_src, - uint16_t encap_dst, uint16_t len) { struct mlx5_action_construct_data *act_data; act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst); if (!act_data) return -1; - act_data->encap.src = encap_src; - act_data->encap.dst = encap_dst; act_data->encap.len = len; LIST_INSERT_HEAD(&acts->act_list, act_data, next); return 0; @@ -523,53 +515,6 @@ flow_hw_shared_action_translate(struct rte_eth_dev *dev, return 0; } -/** - * Translate encap items to encapsulation list. - * - * @param[in] dev - * Pointer to the rte_eth_dev data structure. - * @param[in] acts - * Pointer to the template HW steering DR actions. - * @param[in] type - * Action type. - * @param[in] action_src - * Offset of source rte flow action. - * @param[in] action_dst - * Offset of destination DR action. - * @param[in] items - * Encap item pattern. - * @param[in] items_m - * Encap item mask indicates which part are constant and dynamic. - * - * @return - * 0 on success, negative value otherwise and rte_errno is set. - */ -static __rte_always_inline int -flow_hw_encap_item_translate(struct rte_eth_dev *dev, - struct mlx5_hw_actions *acts, - enum rte_flow_action_type type, - uint16_t action_src, - uint16_t action_dst, - const struct rte_flow_item *items, - const struct rte_flow_item *items_m) -{ - struct mlx5_priv *priv = dev->data->dev_private; - size_t len, total_len = 0; - uint32_t i = 0; - - for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++, items_m++, i++) { - len = flow_dv_get_item_hdr_len(items->type); - if ((!items_m->spec || - memcmp(items_m->spec, items->spec, len)) && - __flow_hw_act_data_encap_append(priv, acts, type, - action_src, action_dst, i, - total_len, len)) - return -1; - total_len += len; - } - return 0; -} - /** * Translate rte_flow actions to DR action. * @@ -611,7 +556,7 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, const struct rte_flow_action_raw_encap *raw_encap_data; const struct rte_flow_item *enc_item = NULL, *enc_item_m = NULL; uint16_t reformat_pos = MLX5_HW_MAX_ACTS, reformat_src = 0; - uint8_t *encap_data = NULL; + uint8_t *encap_data = NULL, *encap_data_m = NULL; size_t data_size = 0; bool actions_end = false; uint32_t type, i; @@ -718,9 +663,9 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS); enc_item = ((const struct rte_flow_action_vxlan_encap *) actions->conf)->definition; - enc_item_m = - ((const struct rte_flow_action_vxlan_encap *) - masks->conf)->definition; + if (masks->conf) + enc_item_m = ((const struct rte_flow_action_vxlan_encap *) + masks->conf)->definition; reformat_pos = i++; reformat_src = actions - action_start; refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2; @@ -729,9 +674,9 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS); enc_item = ((const struct rte_flow_action_nvgre_encap *) actions->conf)->definition; - enc_item_m = - ((const struct rte_flow_action_nvgre_encap *) - actions->conf)->definition; + if (masks->conf) + enc_item_m = ((const struct rte_flow_action_nvgre_encap *) + masks->conf)->definition; reformat_pos = i++; reformat_src = actions - action_start; refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2; @@ -743,6 +688,11 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2; break; case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: + raw_encap_data = + (const struct rte_flow_action_raw_encap *) + masks->conf; + if (raw_encap_data) + encap_data_m = raw_encap_data->data; raw_encap_data = (const struct rte_flow_action_raw_encap *) actions->conf; @@ -773,22 +723,17 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, } if (reformat_pos != MLX5_HW_MAX_ACTS) { uint8_t buf[MLX5_ENCAP_MAX_LEN]; + bool shared_rfmt = true; if (enc_item) { MLX5_ASSERT(!encap_data); - if (flow_dv_convert_encap_data - (enc_item, buf, &data_size, error) || - flow_hw_encap_item_translate - (dev, acts, (action_start + reformat_src)->type, - reformat_src, reformat_pos, - enc_item, enc_item_m)) + if (flow_dv_convert_encap_data(enc_item, buf, &data_size, error)) goto err; encap_data = buf; - } else if (encap_data && __flow_hw_act_data_encap_append - (priv, acts, - (action_start + reformat_src)->type, - reformat_src, reformat_pos, 0, 0, data_size)) { - goto err; + if (!enc_item_m) + shared_rfmt = false; + } else if (encap_data && !encap_data_m) { + shared_rfmt = false; } acts->encap_decap = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*acts->encap_decap) + data_size, @@ -802,12 +747,22 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, acts->encap_decap->action = mlx5dr_action_create_reformat (priv->dr_ctx, refmt_type, data_size, encap_data, - rte_log2_u32(table_attr->nb_flows), - mlx5_hw_act_flag[!!attr->group][type]); + shared_rfmt ? 0 : rte_log2_u32(table_attr->nb_flows), + mlx5_hw_act_flag[!!attr->group][type] | + (shared_rfmt ? MLX5DR_ACTION_FLAG_SHARED : 0)); if (!acts->encap_decap->action) goto err; acts->rule_acts[reformat_pos].action = acts->encap_decap->action; + acts->rule_acts[reformat_pos].reformat.data = + acts->encap_decap->data; + if (shared_rfmt) + acts->rule_acts[reformat_pos].reformat.offset = 0; + else if (__flow_hw_act_data_encap_append(priv, acts, + (action_start + reformat_src)->type, + reformat_src, reformat_pos, data_size)) + goto err; + acts->encap_decap->shared = shared_rfmt; acts->encap_decap_pos = reformat_pos; } acts->acts_num = i; @@ -972,6 +927,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, .ingress = 1, }; uint32_t ft_flag; + size_t encap_len = 0; memcpy(rule_acts, hw_acts->rule_acts, sizeof(*rule_acts) * hw_acts->acts_num); @@ -989,9 +945,6 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, } else { attr.ingress = 1; } - if (hw_acts->encap_decap && hw_acts->encap_decap->data_size) - memcpy(buf, hw_acts->encap_decap->data, - hw_acts->encap_decap->data_size); LIST_FOREACH(act_data, &hw_acts->act_list, next) { uint32_t jump_group; uint32_t tag; @@ -1050,23 +1003,20 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: enc_item = ((const struct rte_flow_action_vxlan_encap *) action->conf)->definition; - rte_memcpy((void *)&buf[act_data->encap.dst], - enc_item[act_data->encap.src].spec, - act_data->encap.len); + if (flow_dv_convert_encap_data(enc_item, buf, &encap_len, NULL)) + return -1; break; case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: enc_item = ((const struct rte_flow_action_nvgre_encap *) action->conf)->definition; - rte_memcpy((void *)&buf[act_data->encap.dst], - enc_item[act_data->encap.src].spec, - act_data->encap.len); + if (flow_dv_convert_encap_data(enc_item, buf, &encap_len, NULL)) + return -1; break; case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: raw_encap_data = (const struct rte_flow_action_raw_encap *) action->conf; - rte_memcpy((void *)&buf[act_data->encap.dst], - raw_encap_data->data, act_data->encap.len); + rte_memcpy((void *)buf, raw_encap_data->data, act_data->encap.len); MLX5_ASSERT(raw_encap_data->size == act_data->encap.len); break; @@ -1074,7 +1024,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, break; } } - if (hw_acts->encap_decap) { + if (hw_acts->encap_decap && !hw_acts->encap_decap->shared) { rule_acts[hw_acts->encap_decap_pos].reformat.offset = job->flow->idx - 1; rule_acts[hw_acts->encap_decap_pos].reformat.data = buf; From patchwork Fri Sep 30 12:53:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117214 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5CFD6A00C4; Fri, 30 Sep 2022 14:54:02 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id EBF9142847; Fri, 30 Sep 2022 14:53:53 +0200 (CEST) Received: from NAM04-DM6-obe.outbound.protection.outlook.com (mail-dm6nam04on2056.outbound.protection.outlook.com [40.107.102.56]) by mails.dpdk.org (Postfix) with ESMTP id 1FA95427F7 for ; Fri, 30 Sep 2022 14:53:52 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=htIQYt/IASC7gAjJ+Xb3h9ADoWZgAipQhV4z/tft6hgfds1//fbsz/6R5j/MYZedBIYFLZsTj5/Fvp2sfXB4MjymaeLyTT3JtWqhWujutSGfjNEAvWo9AX4NXWldxEVSy1XYTkCwwe2Y+oTGSFmCeXg4YwK0E6oxENp2A4jdsLmV10x8Ni07uf1gbRypalAkr18z4xmGAZNzg8LCrd/TOkvGiUBCqPOD1rhAeW1H+WGOZapaRyQ9bSMVPjLRuzerjcRjV+/f9G0OQl502FjCMjGP6n71B2Qyvvr4s5MdSmXOCw+vdgZYXQ1w1ojjmxCfDMvUtL9bgIimypLB2UvYzQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=SwnH895JNjd0D+dZH6rDvedX1FdoDvUdDIDhFxk4g8I=; b=d7zIdi/M1JqY1IZuKn5IUX9TLGQX8s+/HfSrd4vvEfPSWLHCHurVzEv/mEYXky+NWP9AAdB+ERwA8H37Ap0zXC5TYt2tIpKz0JJkhSwmTtOHlb9ZBC0uYrMjw2H1AQCN91m8Ycq/js8bQmFXLE+boEAM+KIOiaGZPZcXDBpZcAFaByKfdXf2g1qRn9cM0txifANiFRSshcpQniBrs0WBDAl17gSTmSDuOehgjHIb39SiVcHENtwYFzRwdILLa7IGq/vcNN93LYc8Plk4L74Hs4Caud4q6JlusaILscZNR6GQzDztcZTSZ1R/fPum0qCraLQiHgwN+6+BnA/abwCcXg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=SwnH895JNjd0D+dZH6rDvedX1FdoDvUdDIDhFxk4g8I=; b=bMXyrlWukUrDSqwpf1yV9Iv9hSTTmT208B3SthFqD1F4gwVa6RTejgztUMgNq8GgrbVjk2kInNFxdkt17Wl/b/cHNrXudbMWryfRMz6qpHpyk0SlcE8gB7sn0w4PhE3/S5B9ofMF7lfcRVjfsUoCPcD0BA6rCHA2q3Y4gBeoUwVHc1AQlms7ZAQBwZG4jQDdv4+LcfGZiQuygOcf+ZZj6h2cLNUwUbpjv7d/4B0xlMAjGomYvf1TAxrMto8tMtmPXdIjqT/LUZ2J+pcCBBiEDNWiq/lEvt4/ULw7af7buP7dyI7MeMffkLhd97kdMQ9PHE5yP632CTDCitWOheyncg== Received: from DM5PR07CA0109.namprd07.prod.outlook.com (2603:10b6:4:ae::38) by SA1PR12MB7039.namprd12.prod.outlook.com (2603:10b6:806:24e::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.20; Fri, 30 Sep 2022 12:53:49 +0000 Received: from DM6NAM11FT089.eop-nam11.prod.protection.outlook.com (2603:10b6:4:ae:cafe::36) by DM5PR07CA0109.outlook.office365.com (2603:10b6:4:ae::38) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5654.26 via Frontend Transport; Fri, 30 Sep 2022 12:53:49 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT089.mail.protection.outlook.com (10.13.173.82) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:53:48 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:41 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:39 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , "Dariusz Sosnowski" Subject: [PATCH v3 04/17] net/mlx5: add modify field hws support Date: Fri, 30 Sep 2022 15:53:02 +0300 Message-ID: <20220930125315.5079-5-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT089:EE_|SA1PR12MB7039:EE_ X-MS-Office365-Filtering-Correlation-Id: 03035460-fbc8-4392-6adb-08daa2e2d1ba X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: yTRaLlpgrp5IgmS0WJKTid0q88Q564N82CPzluK2bKiIPbovH+yfTOh2Dj17U2ruXtU8ymW32TGFRMj+Ka0CsuSx/BxeRse91PSXACQC8xHZCEhYy7WBs+p5bw7QsruHbcwxPEgR8eWC+b0jG9obx19kDzCy0rkPewUdb1Y+e6CNF6SKH1HBZv5yyPHddPul3V/1d72mXKj9m8HjBCpjOJz4Q6lDWYqSLB1j8epJyOamXm44agLcVSoauPwhvZ05wfvFiSOaCCyc2bKjKnSk1frP+6MWUzS2oQ43E7+UDFHnUdI+TerFfgGUuCf7iOg8Nsj5jwU6Cm3jONZqvojPcT/a3vhXHOV3PDSMNzBNPkxXnmIX+AN160sbgJrHlkplsRoWLkma/TeMpa7CWKuqVPXQKCaaY6VSqFHlZehQ19S3AuSqZlQnGfATH8SUs264dTNaEsuSx5eMlZ/k0XqGSo4mQr3EOlKN+z/KNJVmDaj3Mi24EEO/fD3IJ2TJHu/UVz/hBTLW3UFW48eFuceC60Vqi/mPX7INC+6EqWenkoHnFNHxIIa1OHmhq8z0oDXv3R6R+pljaOVm2kK41qTck1AF9sIjvCmM7e1H+0SPGj0W1UGB55TIAD5kygt35Jv7ql7ggPr2WUsQRtLs5QMKZ79/CmP5BGXMbas0ntOeanep3qw34ysQb4geZRDtjFveYHEf4Mn4zPUS15FRaGVhZt8fOJFOgxxi88RvBLb1LQXJclxq608yaS8EfxC+20nQQRsVf75pbmRKXeY+KYgZcg== X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(396003)(376002)(136003)(39860400002)(346002)(451199015)(40470700004)(36840700001)(46966006)(47076005)(7696005)(356005)(82310400005)(5660300002)(30864003)(86362001)(7636003)(2616005)(8676002)(8936002)(26005)(40460700003)(55016003)(4326008)(40480700001)(6286002)(336012)(2906002)(36756003)(426003)(83380400001)(70206006)(70586007)(41300700001)(316002)(107886003)(54906003)(6666004)(186003)(16526019)(6636002)(1076003)(110136005)(478600001)(36860700001)(82740400003)(579004)(559001); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:53:48.9747 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 03035460-fbc8-4392-6adb-08daa2e2d1ba X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT089.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA1PR12MB7039 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This patch introduces support for modify_field rte_flow actions in HWS mode. Support includes: - Ingress and egress domains, - SET and ADD operations, - usage of arbitrary bit offsets and widths for packet and metadata fields. Support is implemented in two phases: 1. On flow table creation the hardware commands are generated, based on rte_flow action templates, and stored alongside action template. 2. On flow rule creation/queueing the hardware commands are updated with values provided by the user. Any masks over immediate values, provided in action templates, are applied to these values before enqueueing rules for creation. Signed-off-by: Dariusz Sosnowski Signed-off-by: Suanming Mou --- drivers/common/mlx5/mlx5_prm.h | 2 + drivers/net/mlx5/linux/mlx5_os.c | 18 +- drivers/net/mlx5/mlx5.h | 1 + drivers/net/mlx5/mlx5_flow.h | 96 +++++ drivers/net/mlx5/mlx5_flow_dv.c | 551 ++++++++++++++------------- drivers/net/mlx5/mlx5_flow_hw.c | 614 ++++++++++++++++++++++++++++++- 6 files changed, 1007 insertions(+), 275 deletions(-) diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h index f832bd77cb..c82ec94465 100644 --- a/drivers/common/mlx5/mlx5_prm.h +++ b/drivers/common/mlx5/mlx5_prm.h @@ -746,6 +746,8 @@ enum mlx5_modification_field { MLX5_MODI_IN_TCP_ACK_NUM = 0x5C, MLX5_MODI_GTP_TEID = 0x6E, MLX5_MODI_OUT_IP_ECN = 0x73, + MLX5_MODI_TUNNEL_HDR_DW_1 = 0x75, + MLX5_MODI_GTPU_FIRST_EXT_DW_0 = 0x76, }; /* Total number of metadata reg_c's. */ diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index aed55e6a62..b7cc11a2ef 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -1540,6 +1540,15 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, mlx5_hrxq_clone_free_cb); if (!priv->hrxqs) goto error; + mlx5_set_metadata_mask(eth_dev); + if (sh->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && + !priv->sh->dv_regc0_mask) { + DRV_LOG(ERR, "metadata mode %u is not supported " + "(no metadata reg_c[0] is available)", + sh->config.dv_xmeta_en); + err = ENOTSUP; + goto error; + } rte_rwlock_init(&priv->ind_tbls_lock); if (priv->sh->config.dv_flow_en == 2) { #ifdef HAVE_IBV_FLOW_DV_SUPPORT @@ -1566,15 +1575,6 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, err = -err; goto error; } - mlx5_set_metadata_mask(eth_dev); - if (sh->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && - !priv->sh->dv_regc0_mask) { - DRV_LOG(ERR, "metadata mode %u is not supported " - "(no metadata reg_c[0] is available)", - sh->config.dv_xmeta_en); - err = ENOTSUP; - goto error; - } /* Query availability of metadata reg_c's. */ if (!priv->sh->metadata_regc_check_flag) { err = mlx5_flow_discover_mreg_c(eth_dev); diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index ea63c29bf9..d07f5b0d8a 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -343,6 +343,7 @@ struct mlx5_hw_q_job { struct rte_flow_hw *flow; /* Flow attached to the job. */ void *user_data; /* Job user data. */ uint8_t *encap_data; /* Encap data. */ + struct mlx5_modification_cmd *mhdr_cmd; }; /* HW steering job descriptor LIFO pool. */ diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 1c9f5fc1d5..0eab3a3797 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -1007,6 +1007,51 @@ flow_items_to_tunnel(const struct rte_flow_item items[]) return items[0].spec; } +/** + * Fetch 1, 2, 3 or 4 byte field from the byte array + * and return as unsigned integer in host-endian format. + * + * @param[in] data + * Pointer to data array. + * @param[in] size + * Size of field to extract. + * + * @return + * converted field in host endian format. + */ +static inline uint32_t +flow_dv_fetch_field(const uint8_t *data, uint32_t size) +{ + uint32_t ret; + + switch (size) { + case 1: + ret = *data; + break; + case 2: + ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); + break; + case 3: + ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); + ret = (ret << 8) | *(data + sizeof(uint16_t)); + break; + case 4: + ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data); + break; + default: + MLX5_ASSERT(false); + ret = 0; + break; + } + return ret; +} + +struct field_modify_info { + uint32_t size; /* Size of field in protocol header, in bytes. */ + uint32_t offset; /* Offset of field in protocol header, in bytes. */ + enum mlx5_modification_field id; +}; + /* HW steering flow attributes. */ struct mlx5_flow_attr { uint32_t port_id; /* Port index. */ @@ -1067,6 +1112,29 @@ struct mlx5_action_construct_data { /* encap data len. */ uint16_t len; } encap; + struct { + /* Modify header action offset in pattern. */ + uint16_t mhdr_cmds_off; + /* Offset in pattern after modify header actions. */ + uint16_t mhdr_cmds_end; + /* + * True if this action is masked and does not need to + * be generated. + */ + bool shared; + /* + * Modified field definitions in dst field (SET, ADD) + * or src field (COPY). + */ + struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS]; + /* Modified field definitions in dst field (COPY). */ + struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS]; + /* + * Masks applied to field values to generate + * PRM actions. + */ + uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS]; + } modify_header; struct { uint64_t types; /* RSS hash types. */ uint32_t level; /* RSS level. */ @@ -1092,6 +1160,7 @@ struct rte_flow_actions_template { struct rte_flow_actions_template_attr attr; struct rte_flow_action *actions; /* Cached flow actions. */ struct rte_flow_action *masks; /* Cached action masks.*/ + uint16_t mhdr_off; /* Offset of DR modify header action. */ uint32_t refcnt; /* Reference counter. */ }; @@ -1112,6 +1181,22 @@ struct mlx5_hw_encap_decap_action { uint8_t data[]; /* Action data. */ }; +#define MLX5_MHDR_MAX_CMD ((MLX5_MAX_MODIFY_NUM) * 2 + 1) + +/* Modify field action struct. */ +struct mlx5_hw_modify_header_action { + /* Reference to DR action */ + struct mlx5dr_action *action; + /* Modify header action position in action rule table. */ + uint16_t pos; + /* Is MODIFY_HEADER action shared across flows in table. */ + bool shared; + /* Amount of modification commands stored in the precompiled buffer. */ + uint32_t mhdr_cmds_num; + /* Precompiled modification commands. */ + struct mlx5_modification_cmd mhdr_cmds[MLX5_MHDR_MAX_CMD]; +}; + /* The maximum actions support in the flow. */ #define MLX5_HW_MAX_ACTS 16 @@ -1121,6 +1206,7 @@ struct mlx5_hw_actions { LIST_HEAD(act_list, mlx5_action_construct_data) act_list; struct mlx5_hw_jump_action *jump; /* Jump action. */ struct mlx5_hrxq *tir; /* TIR action. */ + struct mlx5_hw_modify_header_action *mhdr; /* Modify header action. */ /* Encap/Decap action. */ struct mlx5_hw_encap_decap_action *encap_decap; uint16_t encap_decap_pos; /* Encap/Decap action position. */ @@ -2201,6 +2287,16 @@ int flow_dv_action_query(struct rte_eth_dev *dev, size_t flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type); int flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf, size_t *size, struct rte_flow_error *error); +void mlx5_flow_field_id_to_modify_info + (const struct rte_flow_action_modify_data *data, + struct field_modify_info *info, uint32_t *mask, + uint32_t width, struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, struct rte_flow_error *error); +int flow_dv_convert_modify_action(struct rte_flow_item *item, + struct field_modify_info *field, + struct field_modify_info *dcopy, + struct mlx5_flow_dv_modify_hdr_resource *resource, + uint32_t type, struct rte_flow_error *error); #define MLX5_PF_VPORT_ID 0 #define MLX5_ECPF_VPORT_ID 0xFFFE diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index cb034a01f9..7dff2ab44f 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -241,12 +241,6 @@ rte_col_2_mlx5_col(enum rte_color rcol) return MLX5_FLOW_COLOR_UNDEFINED; } -struct field_modify_info { - uint32_t size; /* Size of field in protocol header, in bytes. */ - uint32_t offset; /* Offset of field in protocol header, in bytes. */ - enum mlx5_modification_field id; -}; - struct field_modify_info modify_eth[] = { {4, 0, MLX5_MODI_OUT_DMAC_47_16}, {2, 4, MLX5_MODI_OUT_DMAC_15_0}, @@ -379,45 +373,6 @@ mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action, } } -/** - * Fetch 1, 2, 3 or 4 byte field from the byte array - * and return as unsigned integer in host-endian format. - * - * @param[in] data - * Pointer to data array. - * @param[in] size - * Size of field to extract. - * - * @return - * converted field in host endian format. - */ -static inline uint32_t -flow_dv_fetch_field(const uint8_t *data, uint32_t size) -{ - uint32_t ret; - - switch (size) { - case 1: - ret = *data; - break; - case 2: - ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); - break; - case 3: - ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data); - ret = (ret << 8) | *(data + sizeof(uint16_t)); - break; - case 4: - ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data); - break; - default: - MLX5_ASSERT(false); - ret = 0; - break; - } - return ret; -} - /** * Convert modify-header action to DV specification. * @@ -446,7 +401,7 @@ flow_dv_fetch_field(const uint8_t *data, uint32_t size) * @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ -static int +int flow_dv_convert_modify_action(struct rte_flow_item *item, struct field_modify_info *field, struct field_modify_info *dcopy, @@ -1464,7 +1419,32 @@ mlx5_flow_item_field_width(struct rte_eth_dev *dev, return 0; } -static void +static __rte_always_inline uint8_t +flow_modify_info_mask_8(uint32_t length, uint32_t off) +{ + return (0xffu >> (8 - length)) << off; +} + +static __rte_always_inline uint16_t +flow_modify_info_mask_16(uint32_t length, uint32_t off) +{ + return rte_cpu_to_be_16((0xffffu >> (16 - length)) << off); +} + +static __rte_always_inline uint32_t +flow_modify_info_mask_32(uint32_t length, uint32_t off) +{ + return rte_cpu_to_be_32((0xffffffffu >> (32 - length)) << off); +} + +static __rte_always_inline uint32_t +flow_modify_info_mask_32_masked(uint32_t length, uint32_t off, uint32_t post_mask) +{ + uint32_t mask = (0xffffffffu >> (32 - length)) << off; + return rte_cpu_to_be_32(mask & post_mask); +} + +void mlx5_flow_field_id_to_modify_info (const struct rte_flow_action_modify_data *data, struct field_modify_info *info, uint32_t *mask, @@ -1473,323 +1453,340 @@ mlx5_flow_field_id_to_modify_info { struct mlx5_priv *priv = dev->data->dev_private; uint32_t idx = 0; - uint32_t off = 0; - - switch (data->field) { + uint32_t off_be = 0; + uint32_t length = 0; + switch ((int)data->field) { case RTE_FLOW_FIELD_START: /* not supported yet */ MLX5_ASSERT(false); break; case RTE_FLOW_FIELD_MAC_DST: - off = data->offset > 16 ? data->offset - 16 : 0; - if (mask) { - if (data->offset < 16) { - info[idx] = (struct field_modify_info){2, 4, - MLX5_MODI_OUT_DMAC_15_0}; - if (width < 16) { - mask[1] = rte_cpu_to_be_16(0xffff >> - (16 - width)); - width = 0; - } else { - mask[1] = RTE_BE16(0xffff); - width -= 16; - } - if (!width) - break; - ++idx; - } - info[idx] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_DMAC_47_16}; - mask[0] = rte_cpu_to_be_32((0xffffffff >> - (32 - width)) << off); + MLX5_ASSERT(data->offset + width <= 48); + off_be = 48 - (data->offset + width); + if (off_be < 16) { + info[idx] = (struct field_modify_info){2, 4, + MLX5_MODI_OUT_DMAC_15_0}; + length = off_be + width <= 16 ? width : 16 - off_be; + if (mask) + mask[1] = flow_modify_info_mask_16(length, + off_be); + else + info[idx].offset = off_be; + width -= length; + if (!width) + break; + off_be = 0; + idx++; } else { - if (data->offset < 16) - info[idx++] = (struct field_modify_info){2, 0, - MLX5_MODI_OUT_DMAC_15_0}; - info[idx] = (struct field_modify_info){4, off, - MLX5_MODI_OUT_DMAC_47_16}; + off_be -= 16; } + info[idx] = (struct field_modify_info){4, 0, + MLX5_MODI_OUT_DMAC_47_16}; + if (mask) + mask[0] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_MAC_SRC: - off = data->offset > 16 ? data->offset - 16 : 0; - if (mask) { - if (data->offset < 16) { - info[idx] = (struct field_modify_info){2, 4, - MLX5_MODI_OUT_SMAC_15_0}; - if (width < 16) { - mask[1] = rte_cpu_to_be_16(0xffff >> - (16 - width)); - width = 0; - } else { - mask[1] = RTE_BE16(0xffff); - width -= 16; - } - if (!width) - break; - ++idx; - } - info[idx] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_SMAC_47_16}; - mask[0] = rte_cpu_to_be_32((0xffffffff >> - (32 - width)) << off); + MLX5_ASSERT(data->offset + width <= 48); + off_be = 48 - (data->offset + width); + if (off_be < 16) { + info[idx] = (struct field_modify_info){2, 4, + MLX5_MODI_OUT_SMAC_15_0}; + length = off_be + width <= 16 ? width : 16 - off_be; + if (mask) + mask[1] = flow_modify_info_mask_16(length, + off_be); + else + info[idx].offset = off_be; + width -= length; + if (!width) + break; + off_be = 0; + idx++; } else { - if (data->offset < 16) - info[idx++] = (struct field_modify_info){2, 0, - MLX5_MODI_OUT_SMAC_15_0}; - info[idx] = (struct field_modify_info){4, off, - MLX5_MODI_OUT_SMAC_47_16}; + off_be -= 16; } + info[idx] = (struct field_modify_info){4, 0, + MLX5_MODI_OUT_SMAC_47_16}; + if (mask) + mask[0] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_VLAN_TYPE: /* not supported yet */ break; case RTE_FLOW_FIELD_VLAN_ID: + MLX5_ASSERT(data->offset + width <= 12); + off_be = 12 - (data->offset + width); info[idx] = (struct field_modify_info){2, 0, MLX5_MODI_OUT_FIRST_VID}; if (mask) - mask[idx] = rte_cpu_to_be_16(0x0fff >> (12 - width)); + mask[idx] = flow_modify_info_mask_16(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_MAC_TYPE: + MLX5_ASSERT(data->offset + width <= 16); + off_be = 16 - (data->offset + width); info[idx] = (struct field_modify_info){2, 0, MLX5_MODI_OUT_ETHERTYPE}; if (mask) - mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); + mask[idx] = flow_modify_info_mask_16(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_IPV4_DSCP: + MLX5_ASSERT(data->offset + width <= 6); + off_be = 6 - (data->offset + width); info[idx] = (struct field_modify_info){1, 0, MLX5_MODI_OUT_IP_DSCP}; if (mask) - mask[idx] = 0x3f >> (6 - width); + mask[idx] = flow_modify_info_mask_8(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_IPV4_TTL: + MLX5_ASSERT(data->offset + width <= 8); + off_be = 8 - (data->offset + width); info[idx] = (struct field_modify_info){1, 0, MLX5_MODI_OUT_IPV4_TTL}; if (mask) - mask[idx] = 0xff >> (8 - width); + mask[idx] = flow_modify_info_mask_8(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_IPV4_SRC: + MLX5_ASSERT(data->offset + width <= 32); + off_be = 32 - (data->offset + width); info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_SIPV4}; if (mask) - mask[idx] = rte_cpu_to_be_32(0xffffffff >> - (32 - width)); + mask[idx] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_IPV4_DST: + MLX5_ASSERT(data->offset + width <= 32); + off_be = 32 - (data->offset + width); info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_DIPV4}; if (mask) - mask[idx] = rte_cpu_to_be_32(0xffffffff >> - (32 - width)); + mask[idx] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_IPV6_DSCP: + MLX5_ASSERT(data->offset + width <= 6); + off_be = 6 - (data->offset + width); info[idx] = (struct field_modify_info){1, 0, MLX5_MODI_OUT_IP_DSCP}; if (mask) - mask[idx] = 0x3f >> (6 - width); + mask[idx] = flow_modify_info_mask_8(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_IPV6_HOPLIMIT: + MLX5_ASSERT(data->offset + width <= 8); + off_be = 8 - (data->offset + width); info[idx] = (struct field_modify_info){1, 0, MLX5_MODI_OUT_IPV6_HOPLIMIT}; if (mask) - mask[idx] = 0xff >> (8 - width); + mask[idx] = flow_modify_info_mask_8(width, off_be); + else + info[idx].offset = off_be; break; - case RTE_FLOW_FIELD_IPV6_SRC: - if (mask) { - if (data->offset < 32) { - info[idx] = (struct field_modify_info){4, 12, - MLX5_MODI_OUT_SIPV6_31_0}; - if (width < 32) { - mask[3] = - rte_cpu_to_be_32(0xffffffff >> - (32 - width)); - width = 0; - } else { - mask[3] = RTE_BE32(0xffffffff); - width -= 32; - } - if (!width) - break; - ++idx; - } - if (data->offset < 64) { - info[idx] = (struct field_modify_info){4, 8, - MLX5_MODI_OUT_SIPV6_63_32}; - if (width < 32) { - mask[2] = - rte_cpu_to_be_32(0xffffffff >> - (32 - width)); - width = 0; - } else { - mask[2] = RTE_BE32(0xffffffff); - width -= 32; - } - if (!width) - break; - ++idx; - } - if (data->offset < 96) { - info[idx] = (struct field_modify_info){4, 4, - MLX5_MODI_OUT_SIPV6_95_64}; - if (width < 32) { - mask[1] = - rte_cpu_to_be_32(0xffffffff >> - (32 - width)); - width = 0; - } else { - mask[1] = RTE_BE32(0xffffffff); - width -= 32; - } - if (!width) - break; - ++idx; + case RTE_FLOW_FIELD_IPV6_SRC: { + /* + * Fields corresponding to IPv6 source address bytes + * arranged according to network byte ordering. + */ + struct field_modify_info fields[] = { + { 4, 0, MLX5_MODI_OUT_SIPV6_127_96 }, + { 4, 4, MLX5_MODI_OUT_SIPV6_95_64 }, + { 4, 8, MLX5_MODI_OUT_SIPV6_63_32 }, + { 4, 12, MLX5_MODI_OUT_SIPV6_31_0 }, + }; + /* First mask to be modified is the mask of 4th address byte. */ + uint32_t midx = 3; + + MLX5_ASSERT(data->offset + width <= 128); + off_be = 128 - (data->offset + width); + while (width > 0 && midx > 0) { + if (off_be < 32) { + info[idx] = fields[midx]; + length = off_be + width <= 32 ? + width : 32 - off_be; + if (mask) + mask[midx] = flow_modify_info_mask_32 + (length, off_be); + else + info[idx].offset = off_be; + width -= length; + off_be = 0; + idx++; + } else { + off_be -= 32; } - info[idx] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_SIPV6_127_96}; - mask[0] = rte_cpu_to_be_32(0xffffffff >> (32 - width)); - } else { - if (data->offset < 32) - info[idx++] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_SIPV6_31_0}; - if (data->offset < 64) - info[idx++] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_SIPV6_63_32}; - if (data->offset < 96) - info[idx++] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_SIPV6_95_64}; - if (data->offset < 128) - info[idx++] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_SIPV6_127_96}; + midx--; } + if (!width) + break; + info[idx] = fields[midx]; + if (mask) + mask[midx] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; - case RTE_FLOW_FIELD_IPV6_DST: - if (mask) { - if (data->offset < 32) { - info[idx] = (struct field_modify_info){4, 12, - MLX5_MODI_OUT_DIPV6_31_0}; - if (width < 32) { - mask[3] = - rte_cpu_to_be_32(0xffffffff >> - (32 - width)); - width = 0; - } else { - mask[3] = RTE_BE32(0xffffffff); - width -= 32; - } - if (!width) - break; - ++idx; - } - if (data->offset < 64) { - info[idx] = (struct field_modify_info){4, 8, - MLX5_MODI_OUT_DIPV6_63_32}; - if (width < 32) { - mask[2] = - rte_cpu_to_be_32(0xffffffff >> - (32 - width)); - width = 0; - } else { - mask[2] = RTE_BE32(0xffffffff); - width -= 32; - } - if (!width) - break; - ++idx; - } - if (data->offset < 96) { - info[idx] = (struct field_modify_info){4, 4, - MLX5_MODI_OUT_DIPV6_95_64}; - if (width < 32) { - mask[1] = - rte_cpu_to_be_32(0xffffffff >> - (32 - width)); - width = 0; - } else { - mask[1] = RTE_BE32(0xffffffff); - width -= 32; - } - if (!width) - break; - ++idx; + } + case RTE_FLOW_FIELD_IPV6_DST: { + /* + * Fields corresponding to IPv6 destination address bytes + * arranged according to network byte ordering. + */ + struct field_modify_info fields[] = { + { 4, 0, MLX5_MODI_OUT_DIPV6_127_96 }, + { 4, 4, MLX5_MODI_OUT_DIPV6_95_64 }, + { 4, 8, MLX5_MODI_OUT_DIPV6_63_32 }, + { 4, 12, MLX5_MODI_OUT_DIPV6_31_0 }, + }; + /* First mask to be modified is the mask of 4th address byte. */ + uint32_t midx = 3; + + MLX5_ASSERT(data->offset + width <= 128); + off_be = 128 - (data->offset + width); + while (width > 0 && midx > 0) { + if (off_be < 32) { + info[idx] = fields[midx]; + length = off_be + width <= 32 ? + width : 32 - off_be; + if (mask) + mask[midx] = flow_modify_info_mask_32 + (length, off_be); + else + info[idx].offset = off_be; + width -= length; + off_be = 0; + idx++; + } else { + off_be -= 32; } - info[idx] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_DIPV6_127_96}; - mask[0] = rte_cpu_to_be_32(0xffffffff >> (32 - width)); - } else { - if (data->offset < 32) - info[idx++] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_DIPV6_31_0}; - if (data->offset < 64) - info[idx++] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_DIPV6_63_32}; - if (data->offset < 96) - info[idx++] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_DIPV6_95_64}; - if (data->offset < 128) - info[idx++] = (struct field_modify_info){4, 0, - MLX5_MODI_OUT_DIPV6_127_96}; + midx--; } + if (!width) + break; + info[idx] = fields[midx]; + if (mask) + mask[midx] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; + } case RTE_FLOW_FIELD_TCP_PORT_SRC: + MLX5_ASSERT(data->offset + width <= 16); + off_be = 16 - (data->offset + width); info[idx] = (struct field_modify_info){2, 0, MLX5_MODI_OUT_TCP_SPORT}; if (mask) - mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); + mask[idx] = flow_modify_info_mask_16(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_TCP_PORT_DST: + MLX5_ASSERT(data->offset + width <= 16); + off_be = 16 - (data->offset + width); info[idx] = (struct field_modify_info){2, 0, MLX5_MODI_OUT_TCP_DPORT}; if (mask) - mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); + mask[idx] = flow_modify_info_mask_16(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_TCP_SEQ_NUM: + MLX5_ASSERT(data->offset + width <= 32); + off_be = 32 - (data->offset + width); info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_TCP_SEQ_NUM}; if (mask) - mask[idx] = rte_cpu_to_be_32(0xffffffff >> - (32 - width)); + mask[idx] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_TCP_ACK_NUM: + MLX5_ASSERT(data->offset + width <= 32); + off_be = 32 - (data->offset + width); info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_OUT_TCP_ACK_NUM}; if (mask) - mask[idx] = rte_cpu_to_be_32(0xffffffff >> - (32 - width)); + mask[idx] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_TCP_FLAGS: + MLX5_ASSERT(data->offset + width <= 9); + off_be = 9 - (data->offset + width); info[idx] = (struct field_modify_info){2, 0, MLX5_MODI_OUT_TCP_FLAGS}; if (mask) - mask[idx] = rte_cpu_to_be_16(0x1ff >> (9 - width)); + mask[idx] = flow_modify_info_mask_16(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_UDP_PORT_SRC: + MLX5_ASSERT(data->offset + width <= 16); + off_be = 16 - (data->offset + width); info[idx] = (struct field_modify_info){2, 0, MLX5_MODI_OUT_UDP_SPORT}; if (mask) - mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); + mask[idx] = flow_modify_info_mask_16(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_UDP_PORT_DST: + MLX5_ASSERT(data->offset + width <= 16); + off_be = 16 - (data->offset + width); info[idx] = (struct field_modify_info){2, 0, MLX5_MODI_OUT_UDP_DPORT}; if (mask) - mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width)); + mask[idx] = flow_modify_info_mask_16(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_VXLAN_VNI: - /* not supported yet */ + MLX5_ASSERT(data->offset + width <= 24); + /* VNI is on bits 31-8 of TUNNEL_HDR_DW_1. */ + off_be = 24 - (data->offset + width) + 8; + info[idx] = (struct field_modify_info){4, 0, + MLX5_MODI_TUNNEL_HDR_DW_1}; + if (mask) + mask[idx] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_GENEVE_VNI: /* not supported yet*/ break; case RTE_FLOW_FIELD_GTP_TEID: + MLX5_ASSERT(data->offset + width <= 32); + off_be = 32 - (data->offset + width); info[idx] = (struct field_modify_info){4, 0, MLX5_MODI_GTP_TEID}; if (mask) - mask[idx] = rte_cpu_to_be_32(0xffffffff >> - (32 - width)); + mask[idx] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_TAG: { - int reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, - data->level, error); + MLX5_ASSERT(data->offset + width <= 32); + int reg; + + if (priv->sh->config.dv_flow_en == 2) + reg = REG_C_1; + else + reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, + data->level, error); if (reg < 0) return; MLX5_ASSERT(reg != REG_NON); @@ -1797,15 +1794,18 @@ mlx5_flow_field_id_to_modify_info info[idx] = (struct field_modify_info){4, 0, reg_to_field[reg]}; if (mask) - mask[idx] = - rte_cpu_to_be_32(0xffffffff >> - (32 - width)); + mask[idx] = flow_modify_info_mask_32 + (width, data->offset); + else + info[idx].offset = data->offset; } break; case RTE_FLOW_FIELD_MARK: { uint32_t mark_mask = priv->sh->dv_mark_mask; uint32_t mark_count = __builtin_popcount(mark_mask); + RTE_SET_USED(mark_count); + MLX5_ASSERT(data->offset + width <= mark_count); int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error); if (reg < 0) @@ -1815,14 +1815,18 @@ mlx5_flow_field_id_to_modify_info info[idx] = (struct field_modify_info){4, 0, reg_to_field[reg]}; if (mask) - mask[idx] = rte_cpu_to_be_32((mark_mask >> - (mark_count - width)) & mark_mask); + mask[idx] = flow_modify_info_mask_32_masked + (width, data->offset, mark_mask); + else + info[idx].offset = data->offset; } break; case RTE_FLOW_FIELD_META: { uint32_t meta_mask = priv->sh->dv_meta_mask; uint32_t meta_count = __builtin_popcount(meta_mask); + RTE_SET_USED(meta_count); + MLX5_ASSERT(data->offset + width <= meta_count); int reg = flow_dv_get_metadata_reg(dev, attr, error); if (reg < 0) return; @@ -1831,16 +1835,32 @@ mlx5_flow_field_id_to_modify_info info[idx] = (struct field_modify_info){4, 0, reg_to_field[reg]}; if (mask) - mask[idx] = rte_cpu_to_be_32((meta_mask >> - (meta_count - width)) & meta_mask); + mask[idx] = flow_modify_info_mask_32_masked + (width, data->offset, meta_mask); + else + info[idx].offset = data->offset; } break; case RTE_FLOW_FIELD_IPV4_ECN: case RTE_FLOW_FIELD_IPV6_ECN: + MLX5_ASSERT(data->offset + width <= 2); + off_be = 2 - (data->offset + width); info[idx] = (struct field_modify_info){1, 0, MLX5_MODI_OUT_IP_ECN}; if (mask) - mask[idx] = 0x3 >> (2 - width); + mask[idx] = flow_modify_info_mask_8(width, off_be); + else + info[idx].offset = off_be; + break; + case RTE_FLOW_FIELD_GTP_PSC_QFI: + MLX5_ASSERT(data->offset + width <= 8); + off_be = data->offset + 8; + info[idx] = (struct field_modify_info){4, 0, + MLX5_MODI_GTPU_FIRST_EXT_DW_0}; + if (mask) + mask[idx] = flow_modify_info_mask_32(width, off_be); + else + info[idx].offset = off_be; break; case RTE_FLOW_FIELD_POINTER: case RTE_FLOW_FIELD_VALUE: @@ -1890,7 +1910,8 @@ flow_dv_convert_action_modify_field if (conf->src.field == RTE_FLOW_FIELD_POINTER || conf->src.field == RTE_FLOW_FIELD_VALUE) { - type = MLX5_MODIFICATION_TYPE_SET; + type = conf->operation == RTE_FLOW_MODIFY_SET ? + MLX5_MODIFICATION_TYPE_SET : MLX5_MODIFICATION_TYPE_ADD; /** For SET fill the destination field (field) first. */ mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask, conf->width, dev, diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index b6978bd051..8e0135fdb0 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -319,6 +319,11 @@ __flow_hw_action_template_destroy(struct rte_eth_dev *dev, mlx5_hlist_unregister(priv->sh->flow_tbls, &grp->entry); acts->jump = NULL; } + if (acts->mhdr) { + if (acts->mhdr->action) + mlx5dr_action_destroy(acts->mhdr->action); + mlx5_free(acts->mhdr); + } } /** @@ -425,6 +430,37 @@ __flow_hw_act_data_encap_append(struct mlx5_priv *priv, return 0; } +static __rte_always_inline int +__flow_hw_act_data_hdr_modify_append(struct mlx5_priv *priv, + struct mlx5_hw_actions *acts, + enum rte_flow_action_type type, + uint16_t action_src, + uint16_t action_dst, + uint16_t mhdr_cmds_off, + uint16_t mhdr_cmds_end, + bool shared, + struct field_modify_info *field, + struct field_modify_info *dcopy, + uint32_t *mask) +{ + struct mlx5_action_construct_data *act_data; + + act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst); + if (!act_data) + return -1; + act_data->modify_header.mhdr_cmds_off = mhdr_cmds_off; + act_data->modify_header.mhdr_cmds_end = mhdr_cmds_end; + act_data->modify_header.shared = shared; + rte_memcpy(act_data->modify_header.field, field, + sizeof(*field) * MLX5_ACT_MAX_MOD_FIELDS); + rte_memcpy(act_data->modify_header.dcopy, dcopy, + sizeof(*dcopy) * MLX5_ACT_MAX_MOD_FIELDS); + rte_memcpy(act_data->modify_header.mask, mask, + sizeof(*mask) * MLX5_ACT_MAX_MOD_FIELDS); + LIST_INSERT_HEAD(&acts->act_list, act_data, next); + return 0; +} + /** * Append shared RSS action to the dynamic action list. * @@ -515,6 +551,265 @@ flow_hw_shared_action_translate(struct rte_eth_dev *dev, return 0; } +static __rte_always_inline bool +flow_hw_action_modify_field_is_shared(const struct rte_flow_action *action, + const struct rte_flow_action *mask) +{ + const struct rte_flow_action_modify_field *v = action->conf; + const struct rte_flow_action_modify_field *m = mask->conf; + + if (v->src.field == RTE_FLOW_FIELD_VALUE) { + uint32_t j; + + if (m == NULL) + return false; + for (j = 0; j < RTE_DIM(m->src.value); ++j) { + /* + * Immediate value is considered to be masked + * (and thus shared by all flow rules), if mask + * is non-zero. Partial mask over immediate value + * is not allowed. + */ + if (m->src.value[j]) + return true; + } + return false; + } + if (v->src.field == RTE_FLOW_FIELD_POINTER) + return m->src.pvalue != NULL; + /* + * Source field types other than VALUE and + * POINTER are always shared. + */ + return true; +} + +static __rte_always_inline bool +flow_hw_should_insert_nop(const struct mlx5_hw_modify_header_action *mhdr, + const struct mlx5_modification_cmd *cmd) +{ + struct mlx5_modification_cmd last_cmd = { { 0 } }; + struct mlx5_modification_cmd new_cmd = { { 0 } }; + const uint32_t cmds_num = mhdr->mhdr_cmds_num; + unsigned int last_type; + bool should_insert = false; + + if (cmds_num == 0) + return false; + last_cmd = *(&mhdr->mhdr_cmds[cmds_num - 1]); + last_cmd.data0 = rte_be_to_cpu_32(last_cmd.data0); + last_cmd.data1 = rte_be_to_cpu_32(last_cmd.data1); + last_type = last_cmd.action_type; + new_cmd = *cmd; + new_cmd.data0 = rte_be_to_cpu_32(new_cmd.data0); + new_cmd.data1 = rte_be_to_cpu_32(new_cmd.data1); + switch (new_cmd.action_type) { + case MLX5_MODIFICATION_TYPE_SET: + case MLX5_MODIFICATION_TYPE_ADD: + if (last_type == MLX5_MODIFICATION_TYPE_SET || + last_type == MLX5_MODIFICATION_TYPE_ADD) + should_insert = new_cmd.field == last_cmd.field; + else if (last_type == MLX5_MODIFICATION_TYPE_COPY) + should_insert = new_cmd.field == last_cmd.dst_field; + else if (last_type == MLX5_MODIFICATION_TYPE_NOP) + should_insert = false; + else + MLX5_ASSERT(false); /* Other types are not supported. */ + break; + case MLX5_MODIFICATION_TYPE_COPY: + if (last_type == MLX5_MODIFICATION_TYPE_SET || + last_type == MLX5_MODIFICATION_TYPE_ADD) + should_insert = (new_cmd.field == last_cmd.field || + new_cmd.dst_field == last_cmd.field); + else if (last_type == MLX5_MODIFICATION_TYPE_COPY) + should_insert = (new_cmd.field == last_cmd.dst_field || + new_cmd.dst_field == last_cmd.dst_field); + else if (last_type == MLX5_MODIFICATION_TYPE_NOP) + should_insert = false; + else + MLX5_ASSERT(false); /* Other types are not supported. */ + break; + default: + /* Other action types should be rejected on AT validation. */ + MLX5_ASSERT(false); + break; + } + return should_insert; +} + +static __rte_always_inline int +flow_hw_mhdr_cmd_nop_append(struct mlx5_hw_modify_header_action *mhdr) +{ + struct mlx5_modification_cmd *nop; + uint32_t num = mhdr->mhdr_cmds_num; + + if (num + 1 >= MLX5_MHDR_MAX_CMD) + return -ENOMEM; + nop = mhdr->mhdr_cmds + num; + nop->data0 = 0; + nop->action_type = MLX5_MODIFICATION_TYPE_NOP; + nop->data0 = rte_cpu_to_be_32(nop->data0); + nop->data1 = 0; + mhdr->mhdr_cmds_num = num + 1; + return 0; +} + +static __rte_always_inline int +flow_hw_mhdr_cmd_append(struct mlx5_hw_modify_header_action *mhdr, + struct mlx5_modification_cmd *cmd) +{ + uint32_t num = mhdr->mhdr_cmds_num; + + if (num + 1 >= MLX5_MHDR_MAX_CMD) + return -ENOMEM; + mhdr->mhdr_cmds[num] = *cmd; + mhdr->mhdr_cmds_num = num + 1; + return 0; +} + +static __rte_always_inline int +flow_hw_converted_mhdr_cmds_append(struct mlx5_hw_modify_header_action *mhdr, + struct mlx5_flow_dv_modify_hdr_resource *resource) +{ + uint32_t idx; + int ret; + + for (idx = 0; idx < resource->actions_num; ++idx) { + struct mlx5_modification_cmd *src = &resource->actions[idx]; + + if (flow_hw_should_insert_nop(mhdr, src)) { + ret = flow_hw_mhdr_cmd_nop_append(mhdr); + if (ret) + return ret; + } + ret = flow_hw_mhdr_cmd_append(mhdr, src); + if (ret) + return ret; + } + return 0; +} + +static __rte_always_inline void +flow_hw_modify_field_init(struct mlx5_hw_modify_header_action *mhdr, + struct rte_flow_actions_template *at) +{ + memset(mhdr, 0, sizeof(*mhdr)); + /* Modify header action without any commands is shared by default. */ + mhdr->shared = true; + mhdr->pos = at->mhdr_off; +} + +static __rte_always_inline int +flow_hw_modify_field_compile(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, + const struct rte_flow_action *action_start, /* Start of AT actions. */ + const struct rte_flow_action *action, /* Current action from AT. */ + const struct rte_flow_action *action_mask, /* Current mask from AT. */ + struct mlx5_hw_actions *acts, + struct mlx5_hw_modify_header_action *mhdr, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + const struct rte_flow_action_modify_field *conf = action->conf; + union { + struct mlx5_flow_dv_modify_hdr_resource resource; + uint8_t data[sizeof(struct mlx5_flow_dv_modify_hdr_resource) + + sizeof(struct mlx5_modification_cmd) * MLX5_MHDR_MAX_CMD]; + } dummy; + struct mlx5_flow_dv_modify_hdr_resource *resource; + struct rte_flow_item item = { + .spec = NULL, + .mask = NULL + }; + struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = { + {0, 0, MLX5_MODI_OUT_NONE} }; + struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = { + {0, 0, MLX5_MODI_OUT_NONE} }; + uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = { 0 }; + uint32_t type, value = 0; + uint16_t cmds_start, cmds_end; + bool shared; + int ret; + + /* + * Modify header action is shared if previous modify_field actions + * are shared and currently compiled action is shared. + */ + shared = flow_hw_action_modify_field_is_shared(action, action_mask); + mhdr->shared &= shared; + if (conf->src.field == RTE_FLOW_FIELD_POINTER || + conf->src.field == RTE_FLOW_FIELD_VALUE) { + type = conf->operation == RTE_FLOW_MODIFY_SET ? MLX5_MODIFICATION_TYPE_SET : + MLX5_MODIFICATION_TYPE_ADD; + /* For SET/ADD fill the destination field (field) first. */ + mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask, + conf->width, dev, + attr, error); + item.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ? + (void *)(uintptr_t)conf->src.pvalue : + (void *)(uintptr_t)&conf->src.value; + if (conf->dst.field == RTE_FLOW_FIELD_META || + conf->dst.field == RTE_FLOW_FIELD_TAG) { + value = *(const unaligned_uint32_t *)item.spec; + value = rte_cpu_to_be_32(value); + item.spec = &value; + } else if (conf->dst.field == RTE_FLOW_FIELD_GTP_PSC_QFI) { + /* + * QFI is passed as an uint8_t integer, but it is accessed through + * a 2nd least significant byte of a 32-bit field in modify header command. + */ + value = *(const uint8_t *)item.spec; + value = rte_cpu_to_be_32(value << 8); + item.spec = &value; + } + } else { + type = MLX5_MODIFICATION_TYPE_COPY; + /* For COPY fill the destination field (dcopy) without mask. */ + mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL, + conf->width, dev, + attr, error); + /* Then construct the source field (field) with mask. */ + mlx5_flow_field_id_to_modify_info(&conf->src, field, mask, + conf->width, dev, + attr, error); + } + item.mask = &mask; + memset(&dummy, 0, sizeof(dummy)); + resource = &dummy.resource; + ret = flow_dv_convert_modify_action(&item, field, dcopy, resource, type, error); + if (ret) + return ret; + MLX5_ASSERT(resource->actions_num > 0); + /* + * If previous modify field action collide with this one, then insert NOP command. + * This NOP command will not be a part of action's command range used to update commands + * on rule creation. + */ + if (flow_hw_should_insert_nop(mhdr, &resource->actions[0])) { + ret = flow_hw_mhdr_cmd_nop_append(mhdr); + if (ret) + return rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "too many modify field operations specified"); + } + cmds_start = mhdr->mhdr_cmds_num; + ret = flow_hw_converted_mhdr_cmds_append(mhdr, resource); + if (ret) + return rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "too many modify field operations specified"); + + cmds_end = mhdr->mhdr_cmds_num; + if (shared) + return 0; + ret = __flow_hw_act_data_hdr_modify_append(priv, acts, RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + action - action_start, mhdr->pos, + cmds_start, cmds_end, shared, + field, dcopy, mask); + if (ret) + return rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "not enough memory to store modify field metadata"); + return 0; +} + /** * Translate rte_flow actions to DR action. * @@ -558,10 +853,12 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, uint16_t reformat_pos = MLX5_HW_MAX_ACTS, reformat_src = 0; uint8_t *encap_data = NULL, *encap_data_m = NULL; size_t data_size = 0; + struct mlx5_hw_modify_header_action mhdr = { 0 }; bool actions_end = false; uint32_t type, i; int err; + flow_hw_modify_field_init(&mhdr, at); if (attr->transfer) type = MLX5DR_TABLE_TYPE_FDB; else if (attr->egress) @@ -714,6 +1011,15 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, reformat_pos = i++; refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2; break; + case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: + if (mhdr.pos == UINT16_MAX) + mhdr.pos = i++; + err = flow_hw_modify_field_compile(dev, attr, action_start, + actions, masks, acts, &mhdr, + error); + if (err) + goto err; + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -721,6 +1027,31 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, break; } } + if (mhdr.pos != UINT16_MAX) { + uint32_t flags; + uint32_t bulk_size; + size_t mhdr_len; + + acts->mhdr = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*acts->mhdr), + 0, SOCKET_ID_ANY); + if (!acts->mhdr) + goto err; + rte_memcpy(acts->mhdr, &mhdr, sizeof(*acts->mhdr)); + mhdr_len = sizeof(struct mlx5_modification_cmd) * acts->mhdr->mhdr_cmds_num; + flags = mlx5_hw_act_flag[!!attr->group][type]; + if (acts->mhdr->shared) { + flags |= MLX5DR_ACTION_FLAG_SHARED; + bulk_size = 0; + } else { + bulk_size = rte_log2_u32(table_attr->nb_flows); + } + acts->mhdr->action = mlx5dr_action_create_modify_header + (priv->dr_ctx, mhdr_len, (__be64 *)acts->mhdr->mhdr_cmds, + bulk_size, flags); + if (!acts->mhdr->action) + goto err; + acts->rule_acts[acts->mhdr->pos].action = acts->mhdr->action; + } if (reformat_pos != MLX5_HW_MAX_ACTS) { uint8_t buf[MLX5_ENCAP_MAX_LEN]; bool shared_rfmt = true; @@ -884,6 +1215,110 @@ flow_hw_shared_action_construct(struct rte_eth_dev *dev, return 0; } +static __rte_always_inline int +flow_hw_mhdr_cmd_is_nop(const struct mlx5_modification_cmd *cmd) +{ + struct mlx5_modification_cmd cmd_he = { + .data0 = rte_be_to_cpu_32(cmd->data0), + .data1 = 0, + }; + + return cmd_he.action_type == MLX5_MODIFICATION_TYPE_NOP; +} + +/** + * Construct flow action array. + * + * For action template contains dynamic actions, these actions need to + * be updated according to the rte_flow action during flow creation. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[in] job + * Pointer to job descriptor. + * @param[in] hw_acts + * Pointer to translated actions from template. + * @param[in] it_idx + * Item template index the action template refer to. + * @param[in] actions + * Array of rte_flow action need to be checked. + * @param[in] rule_acts + * Array of DR rule actions to be used during flow creation.. + * @param[in] acts_num + * Pointer to the real acts_num flow has. + * + * @return + * 0 on success, negative value otherwise and rte_errno is set. + */ +static __rte_always_inline int +flow_hw_modify_field_construct(struct mlx5_hw_q_job *job, + struct mlx5_action_construct_data *act_data, + const struct mlx5_hw_actions *hw_acts, + const struct rte_flow_action *action) +{ + const struct rte_flow_action_modify_field *mhdr_action = action->conf; + uint8_t values[16] = { 0 }; + unaligned_uint32_t *value_p; + uint32_t i; + struct field_modify_info *field; + + if (!hw_acts->mhdr) + return -1; + if (hw_acts->mhdr->shared || act_data->modify_header.shared) + return 0; + MLX5_ASSERT(mhdr_action->operation == RTE_FLOW_MODIFY_SET || + mhdr_action->operation == RTE_FLOW_MODIFY_ADD); + if (mhdr_action->src.field != RTE_FLOW_FIELD_VALUE && + mhdr_action->src.field != RTE_FLOW_FIELD_POINTER) + return 0; + if (mhdr_action->src.field == RTE_FLOW_FIELD_VALUE) + rte_memcpy(values, &mhdr_action->src.value, sizeof(values)); + else + rte_memcpy(values, mhdr_action->src.pvalue, sizeof(values)); + if (mhdr_action->dst.field == RTE_FLOW_FIELD_META || + mhdr_action->dst.field == RTE_FLOW_FIELD_TAG) { + value_p = (unaligned_uint32_t *)values; + *value_p = rte_cpu_to_be_32(*value_p); + } else if (mhdr_action->dst.field == RTE_FLOW_FIELD_GTP_PSC_QFI) { + uint32_t tmp; + + /* + * QFI is passed as an uint8_t integer, but it is accessed through + * a 2nd least significant byte of a 32-bit field in modify header command. + */ + tmp = values[0]; + value_p = (unaligned_uint32_t *)values; + *value_p = rte_cpu_to_be_32(tmp << 8); + } + i = act_data->modify_header.mhdr_cmds_off; + field = act_data->modify_header.field; + do { + uint32_t off_b; + uint32_t mask; + uint32_t data; + const uint8_t *mask_src; + + if (i >= act_data->modify_header.mhdr_cmds_end) + return -1; + if (flow_hw_mhdr_cmd_is_nop(&job->mhdr_cmd[i])) { + ++i; + continue; + } + mask_src = (const uint8_t *)act_data->modify_header.mask; + mask = flow_dv_fetch_field(mask_src + field->offset, field->size); + if (!mask) { + ++field; + continue; + } + off_b = rte_bsf32(mask); + data = flow_dv_fetch_field(values + field->offset, field->size); + data = (data & mask) >> off_b; + job->mhdr_cmd[i++].data1 = rte_cpu_to_be_32(data); + ++field; + } while (field->size); + return 0; +} + /** * Construct flow action array. * @@ -928,6 +1363,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, }; uint32_t ft_flag; size_t encap_len = 0; + int ret; memcpy(rule_acts, hw_acts->rule_acts, sizeof(*rule_acts) * hw_acts->acts_num); @@ -945,6 +1381,18 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, } else { attr.ingress = 1; } + if (hw_acts->mhdr && hw_acts->mhdr->mhdr_cmds_num > 0) { + uint16_t pos = hw_acts->mhdr->pos; + + if (!hw_acts->mhdr->shared) { + rule_acts[pos].modify_header.offset = + job->flow->idx - 1; + rule_acts[pos].modify_header.data = + (uint8_t *)job->mhdr_cmd; + rte_memcpy(job->mhdr_cmd, hw_acts->mhdr->mhdr_cmds, + sizeof(*job->mhdr_cmd) * hw_acts->mhdr->mhdr_cmds_num); + } + } LIST_FOREACH(act_data, &hw_acts->act_list, next) { uint32_t jump_group; uint32_t tag; @@ -1020,6 +1468,14 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, MLX5_ASSERT(raw_encap_data->size == act_data->encap.len); break; + case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: + ret = flow_hw_modify_field_construct(job, + act_data, + hw_acts, + action); + if (ret) + return -1; + break; default: break; } @@ -1609,6 +2065,155 @@ flow_hw_table_destroy(struct rte_eth_dev *dev, return 0; } +static bool +flow_hw_modify_field_is_used(const struct rte_flow_action_modify_field *action, + enum rte_flow_field_id field) +{ + return action->src.field == field || action->dst.field == field; +} + +static int +flow_hw_validate_action_modify_field(const struct rte_flow_action *action, + const struct rte_flow_action *mask, + struct rte_flow_error *error) +{ + const struct rte_flow_action_modify_field *action_conf = + action->conf; + const struct rte_flow_action_modify_field *mask_conf = + mask->conf; + + if (action_conf->operation != mask_conf->operation) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "modify_field operation mask and template are not equal"); + if (action_conf->dst.field != mask_conf->dst.field) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "destination field mask and template are not equal"); + if (action_conf->dst.field == RTE_FLOW_FIELD_POINTER || + action_conf->dst.field == RTE_FLOW_FIELD_VALUE) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "immediate value and pointer cannot be used as destination"); + if (mask_conf->dst.level != UINT32_MAX) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "destination encapsulation level must be fully masked"); + if (mask_conf->dst.offset != UINT32_MAX) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "destination offset level must be fully masked"); + if (action_conf->src.field != mask_conf->src.field) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "destination field mask and template are not equal"); + if (action_conf->src.field != RTE_FLOW_FIELD_POINTER && + action_conf->src.field != RTE_FLOW_FIELD_VALUE) { + if (mask_conf->src.level != UINT32_MAX) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "source encapsulation level must be fully masked"); + if (mask_conf->src.offset != UINT32_MAX) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "source offset level must be fully masked"); + } + if (mask_conf->width != UINT32_MAX) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "modify_field width field must be fully masked"); + if (flow_hw_modify_field_is_used(action_conf, RTE_FLOW_FIELD_START)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "modifying arbitrary place in a packet is not supported"); + if (flow_hw_modify_field_is_used(action_conf, RTE_FLOW_FIELD_VLAN_TYPE)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "modifying vlan_type is not supported"); + if (flow_hw_modify_field_is_used(action_conf, RTE_FLOW_FIELD_GENEVE_VNI)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "modifying Geneve VNI is not supported"); + return 0; +} + +static int +flow_hw_action_validate(const struct rte_flow_action actions[], + const struct rte_flow_action masks[], + struct rte_flow_error *error) +{ + int i; + bool actions_end = false; + int ret; + + for (i = 0; !actions_end; ++i) { + const struct rte_flow_action *action = &actions[i]; + const struct rte_flow_action *mask = &masks[i]; + + if (action->type != mask->type) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "mask type does not match action type"); + switch (action->type) { + case RTE_FLOW_ACTION_TYPE_VOID: + break; + case RTE_FLOW_ACTION_TYPE_INDIRECT: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_MARK: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_DROP: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_JUMP: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_QUEUE: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_RSS: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_RAW_DECAP: + /* TODO: Validation logic */ + break; + case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: + ret = flow_hw_validate_action_modify_field(action, + mask, + error); + if (ret < 0) + return ret; + break; + case RTE_FLOW_ACTION_TYPE_END: + actions_end = true; + break; + default: + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "action not supported in template API"); + } + } + return 0; +} + /** * Create flow action template. * @@ -1637,6 +2242,8 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, int len, act_len, mask_len, i; struct rte_flow_actions_template *at; + if (flow_hw_action_validate(actions, masks, error)) + return NULL; act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, NULL, 0, actions, error); if (act_len <= 0) @@ -2093,6 +2700,8 @@ flow_hw_configure(struct rte_eth_dev *dev, } mem_size += (sizeof(struct mlx5_hw_q_job *) + sizeof(uint8_t) * MLX5_ENCAP_MAX_LEN + + sizeof(struct mlx5_modification_cmd) * + MLX5_MHDR_MAX_CMD + sizeof(struct mlx5_hw_q_job)) * queue_attr[0]->size; } @@ -2104,6 +2713,7 @@ flow_hw_configure(struct rte_eth_dev *dev, } for (i = 0; i < nb_queue; i++) { uint8_t *encap = NULL; + struct mlx5_modification_cmd *mhdr_cmd = NULL; priv->hw_q[i].job_idx = queue_attr[i]->size; priv->hw_q[i].size = queue_attr[i]->size; @@ -2115,8 +2725,10 @@ flow_hw_configure(struct rte_eth_dev *dev, &job[queue_attr[i - 1]->size]; job = (struct mlx5_hw_q_job *) &priv->hw_q[i].job[queue_attr[i]->size]; - encap = (uint8_t *)&job[queue_attr[i]->size]; + mhdr_cmd = (struct mlx5_modification_cmd *)&job[queue_attr[i]->size]; + encap = (uint8_t *)&mhdr_cmd[queue_attr[i]->size * MLX5_MHDR_MAX_CMD]; for (j = 0; j < queue_attr[i]->size; j++) { + job[j].mhdr_cmd = &mhdr_cmd[j * MLX5_MHDR_MAX_CMD]; job[j].encap_data = &encap[j * MLX5_ENCAP_MAX_LEN]; priv->hw_q[i].job[j] = &job[j]; } From patchwork Fri Sep 30 12:53:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117215 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 9348AA00C4; Fri, 30 Sep 2022 14:54:12 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4C86542836; Fri, 30 Sep 2022 14:53:57 +0200 (CEST) Received: from NAM02-DM3-obe.outbound.protection.outlook.com (mail-dm3nam02on2075.outbound.protection.outlook.com [40.107.95.75]) by mails.dpdk.org (Postfix) with ESMTP id CF5BB42B6C for ; Fri, 30 Sep 2022 14:53:55 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=RYwMwywFmlG5KJT31AmnyTh2aPmTC4oghz8G3WcR5qal7Uw8tW4CZ1GKNclEo63BCYrH3VjjcQBEPXoj7plfjz5Hvq7dI/f7FVxwSGauCuSdJVOCVVvvpXSF5RzTg8wORextV+Y1ipB9/cOWV7YlKqpDWbN8bI+FW+/zG/QO26hWQgZlNFmck2kOyls16ESJweHupTg1U2kyFUCW1a/1UNctNPYT5+7fEsUfkfaNlNolHNzlotYV4xVhiWBZbWxE2FDNw1eQY2uMARxzNcdN4Ii8lthu5TGS4j05fTLQhHfZH1OobFuNv71V6OpXucQWfGB2DK2luPb7AvSHiBnKyw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=CFwkxj2ib0BoA0L/xze/D5qpyWG97itNBMTM7jUSO8Y=; b=Ux4R2vK1kzgon2MJopuQbvjiRk88bq7ug1asKhnsBTTbDBNNisZ6E5r1zua37LHqHXFgJ4sdcbl2XE4AmC7el3OV6o6x3wBSl5luL4C9ZbTMpufIUvXpa9yTumir/qrZokhysvf5O1/up1lpMEEOA0EU6cmcP7rYXPgJMLFbfeut8tYUYryk1I87DNVPptfPogoma/zVMP5q6V5LekrUFxZt0C2n8WqGIPiw0u+jzOfn4j8OpoWqjXPTHkdejq19386BsEvyAgMVrT61W3DTmU8woacER8nuni0+snU7I0PlQv6+GGnj3/NmdLQ4AJgIJkHNdeIGA7PxWxv5kJ6s9g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=CFwkxj2ib0BoA0L/xze/D5qpyWG97itNBMTM7jUSO8Y=; b=U4EvNY4mqmiIbCEu5epAODdeI0YNpPHdYQk38hXzVob7Pp5gNltZLKXgklr2a6HwOrYrTXWXruWV/mepIg7an4WIH7b32gN9nzK4XVSCpP1UXteAM/GDxcaj1kh/ftd6gFqFt44lc2XhqJRotHzYFy0HNfCsJcO5GbPW/wVBqBYg129lDLVl6+2RJXIxPMC7boIjsqfGVBRZh3BHhXhIzNWBOlwHd2I+HHA0r08lJ6IZUlMbJ4+isFsuQPXvswvVyLjn7D+wLTdFfcYh08+JhKM+sA3D5xeN+g3DYnIWpGr1qU3frpB3fRqYsupuIPwMLWmejlwWiZa2AywMOSkJsA== Received: from DM5PR07CA0097.namprd07.prod.outlook.com (2603:10b6:4:ae::26) by MW4PR12MB6779.namprd12.prod.outlook.com (2603:10b6:303:20f::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23; Fri, 30 Sep 2022 12:53:52 +0000 Received: from DM6NAM11FT089.eop-nam11.prod.protection.outlook.com (2603:10b6:4:ae:cafe::f3) by DM5PR07CA0097.outlook.office365.com (2603:10b6:4:ae::26) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5654.25 via Frontend Transport; Fri, 30 Sep 2022 12:53:51 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT089.mail.protection.outlook.com (10.13.173.82) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:53:51 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:44 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:41 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , "Dariusz Sosnowski" Subject: [PATCH v3 05/17] net/mlx5: add HW steering port action Date: Fri, 30 Sep 2022 15:53:03 +0300 Message-ID: <20220930125315.5079-6-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT089:EE_|MW4PR12MB6779:EE_ X-MS-Office365-Filtering-Correlation-Id: c01c791b-7b75-4160-ecca-08daa2e2d369 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: THN6v3HmFOKytJIl+9b4nMIMqZfju+uTrqyjwRIf2726D7DociLETegGPdHuzyY5Vt0f8yPc4euNXceMm4Sv4ShHvYelzJxlGZ1o8ufakqUzIn2EYvTalNxzUsWff5i2SurfdTyt1uB9MTl+VLngp6lteZ8VH8TjqpSmaaVrPVSBnqiyJeeuFtCU7v/pfuyOS34BivXfW2EBsz/5VUx+JX4HazKLSl+f5/M3TbG4DPN0huenvWEm3NFcYOOlmmQ/vxnIQckOg48i5V343yRXsBQ/W/mUyCsal3rMwg/0ecS3rTVZq5S6rZg5epTVgEkq1EFQhfnJM3pj2CyFqai7ew8jenraP2XIIZ8vcXEFPHKALwNkTl0UovlYbiTJ5DP4QtpPIctyAqF90dxYXp5fbzXmNP0DcmL2qqXbEMAI4OeVg84oybrhAKMVvmQSBohNGOewoLVq+IKaln0IQtbMdblbxXXz3JSz89dSrjn9MtGk6cn4H7nvWbC0LIK9INvPJrZQ2djPEKPF4yuxEc34OPLRJr08lFmrfScUBlS1jIDO3tb7XhfbQ4GCfmNvZApQJ8ulOfP35oeklJG/dtLHWPo3vbzYq8hw2Ork0XVz2xgYdHfckfZyuIvD9z7gtkqASTuN50CwFM93rTWy28eGoBrpmbsu94H0GTUFfxdwFekqnVYceYPpqQXp6X0jHmdUJl7tSb9aCoLV/rs9+H+rvAtOeSuO25/1ts7Bs4YoxNau4NUjV1FKYxXXQA7E/t4QUfPBUwXyqH8rL9eSYccyehUURxcCrQpeoSOO7yt1dk8= X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(136003)(396003)(39860400002)(346002)(376002)(451199015)(40470700004)(46966006)(36840700001)(83380400001)(2906002)(16526019)(1076003)(186003)(2616005)(47076005)(426003)(336012)(82310400005)(356005)(82740400003)(7636003)(86362001)(55016003)(40460700003)(40480700001)(36756003)(36860700001)(70206006)(70586007)(316002)(54906003)(110136005)(478600001)(41300700001)(7696005)(6666004)(107886003)(6286002)(26005)(30864003)(6636002)(8936002)(5660300002)(4326008)(8676002)(559001)(579004)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:53:51.8027 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: c01c791b-7b75-4160-ecca-08daa2e2d369 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT089.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW4PR12MB6779 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Dariusz Sosnowski This patch implements creating and caching of port actions for use with HW Steering FDB flows. Actions are created on flow template API configuration and created only on the port designated as master. Attaching and detaching of ports in the same switching domain causes an update to the port actions cache by, respectively, creating and destroying actions. A new devarg fdb_def_rule_en is being added and it's used to control the default dedicated E-Switch rule is created by PMD implicitly or not, and PMD sets this value to 1 by default. If set to 0, the default E-Switch rule will not be created and user can create the specific E-Switch rule on root table if needed. Signed-off-by: Dariusz Sosnowski --- doc/guides/nics/mlx5.rst | 9 + drivers/net/mlx5/linux/mlx5_os.c | 14 + drivers/net/mlx5/mlx5.c | 14 + drivers/net/mlx5/mlx5.h | 26 +- drivers/net/mlx5/mlx5_flow.c | 96 +- drivers/net/mlx5/mlx5_flow.h | 22 +- drivers/net/mlx5/mlx5_flow_dv.c | 93 +- drivers/net/mlx5/mlx5_flow_hw.c | 1356 +++++++++++++++++++++++++++- drivers/net/mlx5/mlx5_flow_verbs.c | 4 +- drivers/net/mlx5/mlx5_trigger.c | 77 +- 10 files changed, 1594 insertions(+), 117 deletions(-) diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index 631f0840eb..c42ac482d8 100644 --- a/doc/guides/nics/mlx5.rst +++ b/doc/guides/nics/mlx5.rst @@ -1118,6 +1118,15 @@ for an additional list of options shared with other mlx5 drivers. By default, the PMD will set this value to 1. +- ``fdb_def_rule_en`` parameter [int] + + A non-zero value enables the PMD to create a dedicated rule on E-Switch root + table, this dedicated rule forwards all incoming packets into table 1, other + rules will be created in E-Switch table original table level plus one, to + improve the flow insertion rate due to skip root table managed by firmware. + If set to 0, all rules will be created on the original E-Switch table level. + + By default, the PMD will set this value to 1. Supported NICs -------------- diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index b7cc11a2ef..e0586a4d6f 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -1556,6 +1556,13 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, flow_hw_set_port_info(eth_dev); /* Only HWS requires this information. */ flow_hw_init_tags_set(eth_dev); + if (priv->sh->config.dv_esw_en && + flow_hw_create_vport_action(eth_dev)) { + DRV_LOG(ERR, "port %u failed to create vport action", + eth_dev->data->port_id); + err = EINVAL; + goto error; + } return eth_dev; #else DRV_LOG(ERR, "DV support is missing for HWS."); @@ -1620,6 +1627,13 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, return eth_dev; error: if (priv) { +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + if (eth_dev && + priv->sh && + priv->sh->config.dv_flow_en == 2 && + priv->sh->config.dv_esw_en) + flow_hw_destroy_vport_action(eth_dev); +#endif if (priv->mreg_cp_tbl) mlx5_hlist_destroy(priv->mreg_cp_tbl); if (priv->sh) diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index b39ef1ecbe..74adb677f4 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -172,6 +172,9 @@ /* Device parameter to configure the delay drop when creating Rxqs. */ #define MLX5_DELAY_DROP "delay_drop" +/* Device parameter to create the fdb default rule in PMD */ +#define MLX5_FDB_DEFAULT_RULE_EN "fdb_def_rule_en" + /* Shared memory between primary and secondary processes. */ struct mlx5_shared_data *mlx5_shared_data; @@ -1239,6 +1242,8 @@ mlx5_dev_args_check_handler(const char *key, const char *val, void *opaque) config->decap_en = !!tmp; } else if (strcmp(MLX5_ALLOW_DUPLICATE_PATTERN, key) == 0) { config->allow_duplicate_pattern = !!tmp; + } else if (strcmp(MLX5_FDB_DEFAULT_RULE_EN, key) == 0) { + config->fdb_def_rule = !!tmp; } return 0; } @@ -1274,6 +1279,7 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, MLX5_RECLAIM_MEM, MLX5_DECAP_EN, MLX5_ALLOW_DUPLICATE_PATTERN, + MLX5_FDB_DEFAULT_RULE_EN, NULL, }; int ret = 0; @@ -1285,6 +1291,7 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, config->dv_flow_en = 1; config->decap_en = 1; config->allow_duplicate_pattern = 1; + config->fdb_def_rule = 1; if (mkvlist != NULL) { /* Process parameters. */ ret = mlx5_kvargs_process(mkvlist, params, @@ -1360,6 +1367,7 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, DRV_LOG(DEBUG, "\"decap_en\" is %u.", config->decap_en); DRV_LOG(DEBUG, "\"allow_duplicate_pattern\" is %u.", config->allow_duplicate_pattern); + DRV_LOG(DEBUG, "\"fdb_def_rule_en\" is %u.", config->fdb_def_rule); return 0; } @@ -1943,6 +1951,7 @@ mlx5_dev_close(struct rte_eth_dev *dev) mlx5_flex_parser_ecpri_release(dev); mlx5_flex_item_port_cleanup(dev); #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) + flow_hw_destroy_vport_action(dev); flow_hw_resource_release(dev); flow_hw_clear_port_info(dev); if (priv->sh->config.dv_flow_en == 2) @@ -2644,6 +2653,11 @@ mlx5_probe_again_args_validate(struct mlx5_common_device *cdev, sh->ibdev_name); goto error; } + if (sh->config.fdb_def_rule ^ config->fdb_def_rule) { + DRV_LOG(ERR, "\"fdb_def_rule_en\" configuration mismatch for shared %s context.", + sh->ibdev_name); + goto error; + } if (sh->config.l3_vxlan_en ^ config->l3_vxlan_en) { DRV_LOG(ERR, "\"l3_vxlan_en\" " "configuration mismatch for shared %s context.", diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index d07f5b0d8a..0bf21c1efe 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -309,6 +309,7 @@ struct mlx5_sh_config { uint32_t allow_duplicate_pattern:1; uint32_t lro_allowed:1; /* Whether LRO is allowed. */ /* Allow/Prevent the duplicate rules pattern. */ + uint32_t fdb_def_rule:1; /* Create FDB default jump rule */ }; @@ -337,6 +338,8 @@ enum { MLX5_HW_Q_JOB_TYPE_DESTROY, /* Flow destroy job type. */ }; +#define MLX5_HW_MAX_ITEMS (16) + /* HW steering flow management job descriptor. */ struct mlx5_hw_q_job { uint32_t type; /* Job type. */ @@ -344,6 +347,8 @@ struct mlx5_hw_q_job { void *user_data; /* Job user data. */ uint8_t *encap_data; /* Encap data. */ struct mlx5_modification_cmd *mhdr_cmd; + struct rte_flow_item *items; + struct rte_flow_item_ethdev port_spec; }; /* HW steering job descriptor LIFO pool. */ @@ -1202,6 +1207,8 @@ struct mlx5_dev_ctx_shared { uint32_t flow_priority_check_flag:1; /* Check Flag for flow priority. */ uint32_t metadata_regc_check_flag:1; /* Check Flag for metadata REGC. */ uint32_t hws_tags:1; /* Check if tags info for HWS initialized. */ + uint32_t shared_mark_enabled:1; + /* If mark action is enabled on Rxqs (shared E-Switch domain). */ uint32_t max_port; /* Maximal IB device port index. */ struct mlx5_bond_info bond; /* Bonding information. */ struct mlx5_common_device *cdev; /* Backend mlx5 device. */ @@ -1450,6 +1457,12 @@ struct mlx5_obj_ops { #define MLX5_RSS_HASH_FIELDS_LEN RTE_DIM(mlx5_rss_hash_fields) +struct mlx5_hw_ctrl_flow { + LIST_ENTRY(mlx5_hw_ctrl_flow) next; + struct rte_eth_dev *owner_dev; + struct rte_flow *flow; +}; + struct mlx5_priv { struct rte_eth_dev_data *dev_data; /* Pointer to device data. */ struct mlx5_dev_ctx_shared *sh; /* Shared device context. */ @@ -1490,6 +1503,11 @@ struct mlx5_priv { unsigned int reta_idx_n; /* RETA index size. */ struct mlx5_drop drop_queue; /* Flow drop queues. */ void *root_drop_action; /* Pointer to root drop action. */ + rte_spinlock_t hw_ctrl_lock; + LIST_HEAD(hw_ctrl_flow, mlx5_hw_ctrl_flow) hw_ctrl_flows; + struct rte_flow_template_table *hw_esw_sq_miss_root_tbl; + struct rte_flow_template_table *hw_esw_sq_miss_tbl; + struct rte_flow_template_table *hw_esw_zero_tbl; struct mlx5_indexed_pool *flows[MLX5_FLOW_TYPE_MAXI]; /* RTE Flow rules. */ uint32_t ctrl_flows; /* Control flow rules. */ @@ -1550,11 +1568,11 @@ struct mlx5_priv { struct mlx5_hw_q *hw_q; /* HW steering rte flow table list header. */ LIST_HEAD(flow_hw_tbl, rte_flow_template_table) flow_hw_tbl; + struct mlx5dr_action **hw_vport; /* HW steering global drop action. */ - struct mlx5dr_action *hw_drop[MLX5_HW_ACTION_FLAG_MAX] - [MLX5DR_TABLE_TYPE_MAX]; - /* HW steering global drop action. */ - struct mlx5dr_action *hw_tag[MLX5_HW_ACTION_FLAG_MAX]; + struct mlx5dr_action *hw_drop[2]; + /* HW steering global tag action. */ + struct mlx5dr_action *hw_tag[2]; struct mlx5_indexed_pool *acts_ipool; /* Action data indexed pool. */ #endif }; diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 3abb39aa92..9c44b2e99b 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -999,6 +999,7 @@ static const struct rte_flow_ops mlx5_flow_ops = { .flex_item_create = mlx5_flow_flex_item_create, .flex_item_release = mlx5_flow_flex_item_release, .info_get = mlx5_flow_info_get, + .pick_transfer_proxy = mlx5_flow_pick_transfer_proxy, .configure = mlx5_flow_port_configure, .pattern_template_create = mlx5_flow_pattern_template_create, .pattern_template_destroy = mlx5_flow_pattern_template_destroy, @@ -1242,7 +1243,7 @@ mlx5_get_lowest_priority(struct rte_eth_dev *dev, { struct mlx5_priv *priv = dev->data->dev_private; - if (!attr->group && !attr->transfer) + if (!attr->group && !(attr->transfer && priv->fdb_def_rule)) return priv->sh->flow_max_priority - 2; return MLX5_NON_ROOT_FLOW_MAX_PRIO - 1; } @@ -1269,11 +1270,14 @@ mlx5_get_matcher_priority(struct rte_eth_dev *dev, uint16_t priority = (uint16_t)attr->priority; struct mlx5_priv *priv = dev->data->dev_private; + /* NIC root rules */ if (!attr->group && !attr->transfer) { if (attr->priority == MLX5_FLOW_LOWEST_PRIO_INDICATOR) priority = priv->sh->flow_max_priority - 1; return mlx5_os_flow_adjust_priority(dev, priority, subpriority); - } else if (!external && attr->transfer && attr->group == 0 && + /* FDB root rules */ + } else if (attr->transfer && (!external || !priv->fdb_def_rule) && + attr->group == 0 && attr->priority == MLX5_FLOW_LOWEST_PRIO_INDICATOR) { return (priv->sh->flow_max_priority - 1) * 3; } @@ -1481,13 +1485,32 @@ flow_rxq_mark_flag_set(struct rte_eth_dev *dev) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_rxq_ctrl *rxq_ctrl; + uint16_t port_id; - if (priv->mark_enabled) + if (priv->sh->shared_mark_enabled) return; - LIST_FOREACH(rxq_ctrl, &priv->rxqsctrl, next) { - rxq_ctrl->rxq.mark = 1; + if (priv->master || priv->representor) { + MLX5_ETH_FOREACH_DEV(port_id, dev->device) { + struct mlx5_priv *opriv = + rte_eth_devices[port_id].data->dev_private; + + if (!opriv || + opriv->sh != priv->sh || + opriv->domain_id != priv->domain_id || + opriv->mark_enabled) + continue; + LIST_FOREACH(rxq_ctrl, &opriv->rxqsctrl, next) { + rxq_ctrl->rxq.mark = 1; + } + opriv->mark_enabled = 1; + } + } else { + LIST_FOREACH(rxq_ctrl, &priv->rxqsctrl, next) { + rxq_ctrl->rxq.mark = 1; + } + priv->mark_enabled = 1; } - priv->mark_enabled = 1; + priv->sh->shared_mark_enabled = 1; } /** @@ -1623,6 +1646,7 @@ flow_rxq_flags_clear(struct rte_eth_dev *dev) rxq->ctrl->rxq.tunnel = 0; } priv->mark_enabled = 0; + priv->sh->shared_mark_enabled = 0; } /** @@ -2808,8 +2832,8 @@ mlx5_flow_validate_item_tcp(const struct rte_flow_item *item, * Item specification. * @param[in] item_flags * Bit-fields that holds the items detected until now. - * @param[in] attr - * Flow rule attributes. + * @param root + * Whether action is on root table. * @param[out] error * Pointer to error structure. * @@ -2821,7 +2845,7 @@ mlx5_flow_validate_item_vxlan(struct rte_eth_dev *dev, uint16_t udp_dport, const struct rte_flow_item *item, uint64_t item_flags, - const struct rte_flow_attr *attr, + bool root, struct rte_flow_error *error) { const struct rte_flow_item_vxlan *spec = item->spec; @@ -2858,12 +2882,11 @@ mlx5_flow_validate_item_vxlan(struct rte_eth_dev *dev, if (priv->sh->steering_format_version != MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 || !udp_dport || udp_dport == MLX5_UDP_PORT_VXLAN) { - /* FDB domain & NIC domain non-zero group */ - if ((attr->transfer || attr->group) && priv->sh->misc5_cap) + /* non-root table */ + if (!root && priv->sh->misc5_cap) valid_mask = &nic_mask; /* Group zero in NIC domain */ - if (!attr->group && !attr->transfer && - priv->sh->tunnel_header_0_1) + if (!root && priv->sh->tunnel_header_0_1) valid_mask = &nic_mask; } ret = mlx5_flow_item_acceptable @@ -3102,11 +3125,11 @@ mlx5_flow_validate_item_gre_option(struct rte_eth_dev *dev, if (mask->checksum_rsvd.checksum || mask->sequence.sequence) { if (priv->sh->steering_format_version == MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 || - ((attr->group || attr->transfer) && + ((attr->group || (attr->transfer && priv->fdb_def_rule)) && !priv->sh->misc5_cap) || (!(priv->sh->tunnel_header_0_1 && priv->sh->tunnel_header_2_3) && - !attr->group && !attr->transfer)) + !attr->group && (!attr->transfer || !priv->fdb_def_rule))) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, @@ -6163,7 +6186,8 @@ flow_create_split_metadata(struct rte_eth_dev *dev, } if (qrss) { /* Check if it is in meter suffix table. */ - mtr_sfx = attr->group == (attr->transfer ? + mtr_sfx = attr->group == + ((attr->transfer && priv->fdb_def_rule) ? (MLX5_FLOW_TABLE_LEVEL_METER - 1) : MLX5_FLOW_TABLE_LEVEL_METER); /* @@ -11086,3 +11110,43 @@ int mlx5_flow_get_item_vport_id(struct rte_eth_dev *dev, return 0; } + +int +mlx5_flow_pick_transfer_proxy(struct rte_eth_dev *dev, + uint16_t *proxy_port_id, + struct rte_flow_error *error) +{ + const struct mlx5_priv *priv = dev->data->dev_private; + uint16_t port_id; + + if (!priv->sh->config.dv_esw_en) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "unable to provide a proxy port" + " without E-Switch configured"); + if (!priv->master && !priv->representor) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "unable to provide a proxy port" + " for port which is not a master" + " or a representor port"); + if (priv->master) { + *proxy_port_id = dev->data->port_id; + return 0; + } + MLX5_ETH_FOREACH_DEV(port_id, dev->device) { + const struct rte_eth_dev *port_dev = &rte_eth_devices[port_id]; + const struct mlx5_priv *port_priv = port_dev->data->dev_private; + + if (port_priv->master && + port_priv->domain_id == priv->domain_id) { + *proxy_port_id = port_id; + return 0; + } + } + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "unable to find a proxy port"); +} diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 0eab3a3797..93f0e189d4 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -1151,6 +1151,11 @@ struct rte_flow_pattern_template { struct mlx5dr_match_template *mt; /* mlx5 match template. */ uint64_t item_flags; /* Item layer flags. */ uint32_t refcnt; /* Reference counter. */ + /* + * If true, then rule pattern should be prepended with + * represented_port pattern item. + */ + bool implicit_port; }; /* Flow action template struct. */ @@ -1226,6 +1231,7 @@ struct mlx5_hw_action_template { /* mlx5 flow group struct. */ struct mlx5_flow_group { struct mlx5_list_entry entry; + struct rte_eth_dev *dev; /* Reference to corresponding device. */ struct mlx5dr_table *tbl; /* HWS table object. */ struct mlx5_hw_jump_action jump; /* Jump action. */ enum mlx5dr_table_type type; /* Table type. */ @@ -1484,6 +1490,9 @@ void flow_hw_clear_port_info(struct rte_eth_dev *dev); void flow_hw_init_tags_set(struct rte_eth_dev *dev); void flow_hw_clear_tags_set(struct rte_eth_dev *dev); +int flow_hw_create_vport_action(struct rte_eth_dev *dev); +void flow_hw_destroy_vport_action(struct rte_eth_dev *dev); + typedef int (*mlx5_flow_validate_t)(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, const struct rte_flow_item items[], @@ -2056,7 +2065,7 @@ int mlx5_flow_validate_item_vxlan(struct rte_eth_dev *dev, uint16_t udp_dport, const struct rte_flow_item *item, uint64_t item_flags, - const struct rte_flow_attr *attr, + bool root, struct rte_flow_error *error); int mlx5_flow_validate_item_vxlan_gpe(const struct rte_flow_item *item, uint64_t item_flags, @@ -2313,4 +2322,15 @@ int flow_dv_translate_items_hws(const struct rte_flow_item *items, uint32_t key_type, uint64_t *item_flags, uint8_t *match_criteria, struct rte_flow_error *error); + +int mlx5_flow_pick_transfer_proxy(struct rte_eth_dev *dev, + uint16_t *proxy_port_id, + struct rte_flow_error *error); + +int mlx5_flow_hw_flush_ctrl_flows(struct rte_eth_dev *dev); + +int mlx5_flow_hw_esw_create_mgr_sq_miss_flow(struct rte_eth_dev *dev); +int mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, + uint32_t txq); +int mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev); #endif /* RTE_PMD_MLX5_FLOW_H_ */ diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 7dff2ab44f..3fc2453045 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -2471,8 +2471,8 @@ flow_dv_validate_item_gtp(struct rte_eth_dev *dev, * Previous validated item in the pattern items. * @param[in] gtp_item * Previous GTP item specification. - * @param[in] attr - * Pointer to flow attributes. + * @param root + * Whether action is on root table. * @param[out] error * Pointer to error structure. * @@ -2483,7 +2483,7 @@ static int flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item, uint64_t last_item, const struct rte_flow_item *gtp_item, - const struct rte_flow_attr *attr, + bool root, struct rte_flow_error *error) { const struct rte_flow_item_gtp *gtp_spec; @@ -2508,7 +2508,7 @@ flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item, (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, "GTP E flag must be 1 to match GTP PSC"); /* Check the flow is not created in group zero. */ - if (!attr->transfer && !attr->group) + if (root) return rte_flow_error_set (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "GTP PSC is not supported for group 0"); @@ -3373,20 +3373,19 @@ flow_dv_validate_action_set_tag(struct rte_eth_dev *dev, /** * Indicates whether ASO aging is supported. * - * @param[in] sh - * Pointer to shared device context structure. - * @param[in] attr - * Attributes of flow that includes AGE action. + * @param[in] priv + * Pointer to device private context structure. + * @param[in] root + * Whether action is on root table. * * @return * True when ASO aging is supported, false otherwise. */ static inline bool -flow_hit_aso_supported(const struct mlx5_dev_ctx_shared *sh, - const struct rte_flow_attr *attr) +flow_hit_aso_supported(const struct mlx5_priv *priv, bool root) { - MLX5_ASSERT(sh && attr); - return (sh->flow_hit_aso_en && (attr->transfer || attr->group)); + MLX5_ASSERT(priv); + return (priv->sh->flow_hit_aso_en && !root); } /** @@ -3398,8 +3397,8 @@ flow_hit_aso_supported(const struct mlx5_dev_ctx_shared *sh, * Indicator if action is shared. * @param[in] action_flags * Holds the actions detected until now. - * @param[in] attr - * Attributes of flow that includes this action. + * @param[in] root + * Whether action is on root table. * @param[out] error * Pointer to error structure. * @@ -3409,7 +3408,7 @@ flow_hit_aso_supported(const struct mlx5_dev_ctx_shared *sh, static int flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared, uint64_t action_flags, - const struct rte_flow_attr *attr, + bool root, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; @@ -3421,7 +3420,7 @@ flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "duplicate count actions set"); if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) && - !flow_hit_aso_supported(priv->sh, attr)) + !flow_hit_aso_supported(priv, root)) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "old age and indirect count combination is not supported"); @@ -3652,8 +3651,8 @@ flow_dv_validate_action_raw_encap_decap * Holds the actions detected until now. * @param[in] item_flags * The items found in this flow rule. - * @param[in] attr - * Pointer to flow attributes. + * @param root + * Whether action is on root table. * @param[out] error * Pointer to error structure. * @@ -3664,12 +3663,12 @@ static int flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev, uint64_t action_flags, uint64_t item_flags, - const struct rte_flow_attr *attr, + bool root, struct rte_flow_error *error) { RTE_SET_USED(dev); - if (attr->group == 0 && !attr->transfer) + if (root) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -4919,6 +4918,8 @@ flow_dv_validate_action_modify_ttl(const uint64_t action_flags, * Pointer to the modify action. * @param[in] attr * Pointer to the flow attributes. + * @param root + * Whether action is on root table. * @param[out] error * Pointer to error structure. * @@ -4931,6 +4932,7 @@ flow_dv_validate_action_modify_field(struct rte_eth_dev *dev, const uint64_t action_flags, const struct rte_flow_action *action, const struct rte_flow_attr *attr, + bool root, struct rte_flow_error *error) { int ret = 0; @@ -4978,7 +4980,7 @@ flow_dv_validate_action_modify_field(struct rte_eth_dev *dev, } if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE && action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) { - if (!attr->transfer && !attr->group) + if (root) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, action, "modify field action is not" @@ -5068,8 +5070,7 @@ flow_dv_validate_action_modify_field(struct rte_eth_dev *dev, action_modify_field->src.field == RTE_FLOW_FIELD_IPV4_ECN || action_modify_field->dst.field == RTE_FLOW_FIELD_IPV6_ECN || action_modify_field->src.field == RTE_FLOW_FIELD_IPV6_ECN) - if (!hca_attr->modify_outer_ip_ecn && - !attr->transfer && !attr->group) + if (!hca_attr->modify_outer_ip_ecn && root) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, action, "modifications of the ECN for current firmware is not supported"); @@ -5103,11 +5104,12 @@ flow_dv_validate_action_jump(struct rte_eth_dev *dev, bool external, struct rte_flow_error *error) { uint32_t target_group, table = 0; + struct mlx5_priv *priv = dev->data->dev_private; int ret = 0; struct flow_grp_info grp_info = { .external = !!external, .transfer = !!attributes->transfer, - .fdb_def_rule = 1, + .fdb_def_rule = !!priv->fdb_def_rule, .std_tbl_fix = 0 }; if (action_flags & (MLX5_FLOW_FATE_ACTIONS | @@ -5687,6 +5689,8 @@ flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) * Pointer to the COUNT action in sample action list. * @param[out] fdb_mirror_limit * Pointer to the FDB mirror limitation flag. + * @param root + * Whether action is on root table. * @param[out] error * Pointer to error structure. * @@ -5703,6 +5707,7 @@ flow_dv_validate_action_sample(uint64_t *action_flags, const struct rte_flow_action_rss **sample_rss, const struct rte_flow_action_count **count, int *fdb_mirror_limit, + bool root, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; @@ -5804,7 +5809,7 @@ flow_dv_validate_action_sample(uint64_t *action_flags, case RTE_FLOW_ACTION_TYPE_COUNT: ret = flow_dv_validate_action_count (dev, false, *action_flags | sub_action_flags, - attr, error); + root, error); if (ret < 0) return ret; *count = act->conf; @@ -7284,7 +7289,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, case RTE_FLOW_ITEM_TYPE_VXLAN: ret = mlx5_flow_validate_item_vxlan(dev, udp_dport, items, item_flags, - attr, error); + is_root, error); if (ret < 0) return ret; last_item = MLX5_FLOW_LAYER_VXLAN; @@ -7378,7 +7383,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, break; case RTE_FLOW_ITEM_TYPE_GTP_PSC: ret = flow_dv_validate_item_gtp_psc(items, last_item, - gtp_item, attr, + gtp_item, is_root, error); if (ret < 0) return ret; @@ -7595,7 +7600,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, case RTE_FLOW_ACTION_TYPE_COUNT: ret = flow_dv_validate_action_count(dev, shared_count, action_flags, - attr, error); + is_root, error); if (ret < 0) return ret; count = actions->conf; @@ -7889,7 +7894,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, rw_act_num += MLX5_ACT_NUM_SET_TAG; break; case MLX5_RTE_FLOW_ACTION_TYPE_AGE: - if (!attr->transfer && !attr->group) + if (is_root) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -7914,7 +7919,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, * Validate the regular AGE action (using counter) * mutual exclusion with indirect counter actions. */ - if (!flow_hit_aso_supported(priv->sh, attr)) { + if (!flow_hit_aso_supported(priv, is_root)) { if (shared_count) return rte_flow_error_set (error, EINVAL, @@ -7970,6 +7975,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, rss, &sample_rss, &sample_count, &fdb_mirror_limit, + is_root, error); if (ret < 0) return ret; @@ -7986,6 +7992,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, action_flags, actions, attr, + is_root, error); if (ret < 0) return ret; @@ -7999,8 +8006,8 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, break; case RTE_FLOW_ACTION_TYPE_CONNTRACK: ret = flow_dv_validate_action_aso_ct(dev, action_flags, - item_flags, attr, - error); + item_flags, + is_root, error); if (ret < 0) return ret; action_flags |= MLX5_FLOW_ACTION_CT; @@ -9197,15 +9204,18 @@ flow_dv_translate_item_vxlan(struct rte_eth_dev *dev, if (MLX5_ITEM_VALID(item, key_type)) return; MLX5_ITEM_UPDATE(item, key_type, vxlan_v, vxlan_m, &nic_mask); - if (item->mask == &nic_mask && - ((!attr->group && !priv->sh->tunnel_header_0_1) || - (attr->group && !priv->sh->misc5_cap))) + if ((item->mask == &nic_mask) && + ((!attr->group && !(attr->transfer && priv->fdb_def_rule) && + !priv->sh->tunnel_header_0_1) || + ((attr->group || (attr->transfer && priv->fdb_def_rule)) && + !priv->sh->misc5_cap))) vxlan_m = &rte_flow_item_vxlan_mask; if ((priv->sh->steering_format_version == MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 && dport != MLX5_UDP_PORT_VXLAN) || - (!attr->group && !attr->transfer) || - ((attr->group || attr->transfer) && !priv->sh->misc5_cap)) { + (!attr->group && !(attr->transfer && priv->fdb_def_rule)) || + ((attr->group || (attr->transfer && priv->fdb_def_rule)) && + !priv->sh->misc5_cap)) { misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); size = sizeof(vxlan_m->vni); vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni); @@ -14177,7 +14187,7 @@ flow_dv_translate(struct rte_eth_dev *dev, */ if (action_flags & MLX5_FLOW_ACTION_AGE) { if ((non_shared_age && count) || - !flow_hit_aso_supported(priv->sh, attr)) { + !flow_hit_aso_supported(priv, !dev_flow->dv.group)) { /* Creates age by counters. */ cnt_act = flow_dv_prepare_counter (dev, dev_flow, @@ -18326,6 +18336,7 @@ flow_dv_action_validate(struct rte_eth_dev *dev, struct rte_flow_error *err) { struct mlx5_priv *priv = dev->data->dev_private; + /* called from RTE API */ RTE_SET_USED(conf); switch (action->type) { @@ -18353,7 +18364,7 @@ flow_dv_action_validate(struct rte_eth_dev *dev, "Indirect age action not supported"); return flow_dv_validate_action_age(0, action, dev, err); case RTE_FLOW_ACTION_TYPE_COUNT: - return flow_dv_validate_action_count(dev, true, 0, NULL, err); + return flow_dv_validate_action_count(dev, true, 0, false, err); case RTE_FLOW_ACTION_TYPE_CONNTRACK: if (!priv->sh->ct_aso_en) return rte_flow_error_set(err, ENOTSUP, @@ -18530,6 +18541,8 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, bool def_green = false; bool def_yellow = false; const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL}; + /* Called from RTE API */ + bool is_root = !(attr->group || (attr->transfer && priv->fdb_def_rule)); if (!dev_conf->dv_esw_en) def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT; @@ -18731,7 +18744,7 @@ flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev, break; case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: ret = flow_dv_validate_action_modify_field(dev, - action_flags[i], act, attr, &flow_err); + action_flags[i], act, attr, is_root, &flow_err); if (ret < 0) return -rte_mtr_error_set(error, ENOTSUP, diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 8e0135fdb0..b3b37f36a2 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -20,6 +20,14 @@ /* Default queue to flush the flows. */ #define MLX5_DEFAULT_FLUSH_QUEUE 0 +/* Maximum number of rules in control flow tables */ +#define MLX5_HW_CTRL_FLOW_NB_RULES (4096) + +/* Flow group for SQ miss default flows/ */ +#define MLX5_HW_SQ_MISS_GROUP (UINT32_MAX) + +static int flow_hw_flush_all_ctrl_flows(struct rte_eth_dev *dev); + const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops; /* DR action flags with different table. */ @@ -57,6 +65,9 @@ flow_hw_rxq_flag_set(struct rte_eth_dev *dev, bool enable) for (i = 0; i < priv->rxqs_n; ++i) { struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev, i); + /* With RXQ start/stop feature, RXQ might be stopped. */ + if (!rxq_ctrl) + continue; rxq_ctrl->rxq.mark = enable; } priv->mark_enabled = enable; @@ -810,6 +821,77 @@ flow_hw_modify_field_compile(struct rte_eth_dev *dev, return 0; } +static int +flow_hw_represented_port_compile(struct rte_eth_dev *dev, + const struct rte_flow_attr *attr, + const struct rte_flow_action *action_start, + const struct rte_flow_action *action, + const struct rte_flow_action *action_mask, + struct mlx5_hw_actions *acts, + uint16_t action_dst, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + const struct rte_flow_action_ethdev *v = action->conf; + const struct rte_flow_action_ethdev *m = action_mask->conf; + int ret; + + if (!attr->group) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR, NULL, + "represented_port action cannot" + " be used on group 0"); + if (!attr->transfer) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, + NULL, + "represented_port action requires" + " transfer attribute"); + if (attr->ingress || attr->egress) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR, NULL, + "represented_port action cannot" + " be used with direction attributes"); + if (!priv->master) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "represented_port acton must" + " be used on proxy port"); + if (m && !!m->port_id) { + struct mlx5_priv *port_priv; + + port_priv = mlx5_port_to_eswitch_info(v->port_id, false); + if (port_priv == NULL) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "port does not exist or unable to" + " obtain E-Switch info for port"); + MLX5_ASSERT(priv->hw_vport != NULL); + if (priv->hw_vport[v->port_id]) { + acts->rule_acts[action_dst].action = + priv->hw_vport[v->port_id]; + } else { + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "cannot use represented_port action" + " with this port"); + } + } else { + ret = __flow_hw_act_data_general_append + (priv, acts, action->type, + action - action_start, action_dst); + if (ret) + return rte_flow_error_set + (error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "not enough memory to store" + " vport action"); + } + return 0; +} + /** * Translate rte_flow actions to DR action. * @@ -887,7 +969,7 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, break; case RTE_FLOW_ACTION_TYPE_DROP: acts->rule_acts[i++].action = - priv->hw_drop[!!attr->group][type]; + priv->hw_drop[!!attr->group]; break; case RTE_FLOW_ACTION_TYPE_MARK: acts->mark = true; @@ -1020,6 +1102,13 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, if (err) goto err; break; + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: + if (flow_hw_represented_port_compile + (dev, attr, action_start, actions, + masks, acts, i, error)) + goto err; + i++; + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -1352,11 +1441,13 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, struct mlx5dr_rule_action *rule_acts, uint32_t *acts_num) { + struct mlx5_priv *priv = dev->data->dev_private; struct rte_flow_template_table *table = job->flow->table; struct mlx5_action_construct_data *act_data; const struct rte_flow_action *action; const struct rte_flow_action_raw_encap *raw_encap_data; const struct rte_flow_item *enc_item = NULL; + const struct rte_flow_action_ethdev *port_action = NULL; uint8_t *buf = job->encap_data; struct rte_flow_attr attr = { .ingress = 1, @@ -1476,6 +1567,13 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, if (ret) return -1; break; + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: + port_action = action->conf; + if (!priv->hw_vport[port_action->port_id]) + return -1; + rule_acts[act_data->action_dst].action = + priv->hw_vport[port_action->port_id]; + break; default: break; } @@ -1488,6 +1586,52 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, return 0; } +static const struct rte_flow_item * +flow_hw_get_rule_items(struct rte_eth_dev *dev, + struct rte_flow_template_table *table, + const struct rte_flow_item items[], + uint8_t pattern_template_index, + struct mlx5_hw_q_job *job) +{ + if (table->its[pattern_template_index]->implicit_port) { + const struct rte_flow_item *curr_item; + unsigned int nb_items; + bool found_end; + unsigned int i; + + /* Count number of pattern items. */ + nb_items = 0; + found_end = false; + for (curr_item = items; !found_end; ++curr_item) { + ++nb_items; + if (curr_item->type == RTE_FLOW_ITEM_TYPE_END) + found_end = true; + } + /* Prepend represented port item. */ + job->port_spec = (struct rte_flow_item_ethdev){ + .port_id = dev->data->port_id, + }; + job->items[0] = (struct rte_flow_item){ + .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, + .spec = &job->port_spec, + }; + found_end = false; + for (i = 1; i < MLX5_HW_MAX_ITEMS && i - 1 < nb_items; ++i) { + job->items[i] = items[i - 1]; + if (items[i - 1].type == RTE_FLOW_ITEM_TYPE_END) { + found_end = true; + break; + } + } + if (i >= MLX5_HW_MAX_ITEMS && !found_end) { + rte_errno = ENOMEM; + return NULL; + } + return job->items; + } + return items; +} + /** * Enqueue HW steering flow creation. * @@ -1539,6 +1683,7 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev, struct mlx5_hw_actions *hw_acts; struct rte_flow_hw *flow; struct mlx5_hw_q_job *job; + const struct rte_flow_item *rule_items; uint32_t acts_num, flow_idx; int ret; @@ -1565,15 +1710,23 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev, job->user_data = user_data; rule_attr.user_data = job; hw_acts = &table->ats[action_template_index].acts; - /* Construct the flow action array based on the input actions.*/ - flow_hw_actions_construct(dev, job, hw_acts, pattern_template_index, - actions, rule_acts, &acts_num); + /* Construct the flow actions based on the input actions.*/ + if (flow_hw_actions_construct(dev, job, hw_acts, pattern_template_index, + actions, rule_acts, &acts_num)) { + rte_errno = EINVAL; + goto free; + } + rule_items = flow_hw_get_rule_items(dev, table, items, + pattern_template_index, job); + if (!rule_items) + goto free; ret = mlx5dr_rule_create(table->matcher, pattern_template_index, items, action_template_index, rule_acts, &rule_attr, &flow->rule); if (likely(!ret)) return (struct rte_flow *)flow; +free: /* Flow created fail, return the descriptor and flow memory. */ mlx5_ipool_free(table->flow, flow_idx); priv->hw_q[queue].job_idx++; @@ -1754,7 +1907,9 @@ __flow_hw_pull_comp(struct rte_eth_dev *dev, struct rte_flow_op_result comp[BURST_THR]; int ret, i, empty_loop = 0; - flow_hw_push(dev, queue, error); + ret = flow_hw_push(dev, queue, error); + if (ret < 0) + return ret; while (pending_rules) { ret = flow_hw_pull(dev, queue, comp, BURST_THR, error); if (ret < 0) @@ -2039,8 +2194,12 @@ flow_hw_table_destroy(struct rte_eth_dev *dev, { struct mlx5_priv *priv = dev->data->dev_private; int i; + uint32_t fidx = 1; - if (table->refcnt) { + /* Build ipool allocated object bitmap. */ + mlx5_ipool_flush_cache(table->flow); + /* Check if ipool has allocated objects. */ + if (table->refcnt || mlx5_ipool_get_next(table->flow, &fidx)) { DRV_LOG(WARNING, "Table %p is still in using.", (void *)table); return rte_flow_error_set(error, EBUSY, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@ -2052,8 +2211,6 @@ flow_hw_table_destroy(struct rte_eth_dev *dev, __atomic_sub_fetch(&table->its[i]->refcnt, 1, __ATOMIC_RELAXED); for (i = 0; i < table->nb_action_templates; i++) { - if (table->ats[i].acts.mark) - flow_hw_rxq_flag_set(dev, false); __flow_hw_action_template_destroy(dev, &table->ats[i].acts); __atomic_sub_fetch(&table->ats[i].action_template->refcnt, 1, __ATOMIC_RELAXED); @@ -2138,7 +2295,51 @@ flow_hw_validate_action_modify_field(const struct rte_flow_action *action, } static int -flow_hw_action_validate(const struct rte_flow_action actions[], +flow_hw_validate_action_represented_port(struct rte_eth_dev *dev, + const struct rte_flow_action *action, + const struct rte_flow_action *mask, + struct rte_flow_error *error) +{ + const struct rte_flow_action_ethdev *action_conf = action->conf; + const struct rte_flow_action_ethdev *mask_conf = mask->conf; + struct mlx5_priv *priv = dev->data->dev_private; + + if (!priv->sh->config.dv_esw_en) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "cannot use represented_port actions" + " without an E-Switch"); + if (mask_conf->port_id) { + struct mlx5_priv *port_priv; + struct mlx5_priv *dev_priv; + + port_priv = mlx5_port_to_eswitch_info(action_conf->port_id, false); + if (!port_priv) + return rte_flow_error_set(error, rte_errno, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "failed to obtain E-Switch" + " info for port"); + dev_priv = mlx5_dev_to_eswitch_info(dev); + if (!dev_priv) + return rte_flow_error_set(error, rte_errno, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "failed to obtain E-Switch" + " info for transfer proxy"); + if (port_priv->domain_id != dev_priv->domain_id) + return rte_flow_error_set(error, rte_errno, + RTE_FLOW_ERROR_TYPE_ACTION, + action, + "cannot forward to port from" + " a different E-Switch"); + } + return 0; +} + +static int +flow_hw_action_validate(struct rte_eth_dev *dev, + const struct rte_flow_action actions[], const struct rte_flow_action masks[], struct rte_flow_error *error) { @@ -2201,6 +2402,12 @@ flow_hw_action_validate(const struct rte_flow_action actions[], if (ret < 0) return ret; break; + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: + ret = flow_hw_validate_action_represented_port + (dev, action, mask, error); + if (ret < 0) + return ret; + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -2242,7 +2449,7 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, int len, act_len, mask_len, i; struct rte_flow_actions_template *at; - if (flow_hw_action_validate(actions, masks, error)) + if (flow_hw_action_validate(dev, actions, masks, error)) return NULL; act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, NULL, 0, actions, error); @@ -2325,6 +2532,46 @@ flow_hw_actions_template_destroy(struct rte_eth_dev *dev __rte_unused, return 0; } +static struct rte_flow_item * +flow_hw_copy_prepend_port_item(const struct rte_flow_item *items, + struct rte_flow_error *error) +{ + const struct rte_flow_item *curr_item; + struct rte_flow_item *copied_items; + bool found_end; + unsigned int nb_items; + unsigned int i; + size_t size; + + /* Count number of pattern items. */ + nb_items = 0; + found_end = false; + for (curr_item = items; !found_end; ++curr_item) { + ++nb_items; + if (curr_item->type == RTE_FLOW_ITEM_TYPE_END) + found_end = true; + } + /* Allocate new array of items and prepend REPRESENTED_PORT item. */ + size = sizeof(*copied_items) * (nb_items + 1); + copied_items = mlx5_malloc(MLX5_MEM_ZERO, size, 0, rte_socket_id()); + if (!copied_items) { + rte_flow_error_set(error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "cannot allocate item template"); + return NULL; + } + copied_items[0] = (struct rte_flow_item){ + .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, + .spec = NULL, + .last = NULL, + .mask = &rte_flow_item_ethdev_mask, + }; + for (i = 1; i < nb_items + 1; ++i) + copied_items[i] = items[i - 1]; + return copied_items; +} + /** * Create flow item template. * @@ -2348,9 +2595,35 @@ flow_hw_pattern_template_create(struct rte_eth_dev *dev, { struct mlx5_priv *priv = dev->data->dev_private; struct rte_flow_pattern_template *it; + struct rte_flow_item *copied_items = NULL; + const struct rte_flow_item *tmpl_items; + if (priv->sh->config.dv_esw_en && attr->ingress) { + /* + * Disallow pattern template with ingress and egress/transfer + * attributes in order to forbid implicit port matching + * on egress and transfer traffic. + */ + if (attr->egress || attr->transfer) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "item template for ingress traffic" + " cannot be used for egress/transfer" + " traffic when E-Switch is enabled"); + return NULL; + } + copied_items = flow_hw_copy_prepend_port_item(items, error); + if (!copied_items) + return NULL; + tmpl_items = copied_items; + } else { + tmpl_items = items; + } it = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*it), 0, rte_socket_id()); if (!it) { + if (copied_items) + mlx5_free(copied_items); rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -2358,8 +2631,10 @@ flow_hw_pattern_template_create(struct rte_eth_dev *dev, return NULL; } it->attr = *attr; - it->mt = mlx5dr_match_template_create(items, attr->relaxed_matching); + it->mt = mlx5dr_match_template_create(tmpl_items, attr->relaxed_matching); if (!it->mt) { + if (copied_items) + mlx5_free(copied_items); mlx5_free(it); rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@ -2367,9 +2642,12 @@ flow_hw_pattern_template_create(struct rte_eth_dev *dev, "cannot create match template"); return NULL; } - it->item_flags = flow_hw_rss_item_flags_get(items); + it->item_flags = flow_hw_rss_item_flags_get(tmpl_items); + it->implicit_port = !!copied_items; __atomic_fetch_add(&it->refcnt, 1, __ATOMIC_RELAXED); LIST_INSERT_HEAD(&priv->flow_hw_itt, it, next); + if (copied_items) + mlx5_free(copied_items); return it; } @@ -2495,6 +2773,7 @@ flow_hw_grp_create_cb(void *tool_ctx, void *cb_ctx) goto error; grp_data->jump.root_action = jump; } + grp_data->dev = dev; grp_data->idx = idx; grp_data->group_id = attr->group; grp_data->type = dr_tbl_attr.type; @@ -2563,7 +2842,8 @@ flow_hw_grp_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, struct rte_flow_attr *attr = (struct rte_flow_attr *)ctx->data; - return (grp_data->group_id != attr->group) || + return (grp_data->dev != ctx->dev) || + (grp_data->group_id != attr->group) || ((grp_data->type != MLX5DR_TABLE_TYPE_FDB) && attr->transfer) || ((grp_data->type != MLX5DR_TABLE_TYPE_NIC_TX) && @@ -2626,6 +2906,545 @@ flow_hw_grp_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], grp_data->idx); } +/** + * Create and cache a vport action for given @p dev port. vport actions + * cache is used in HWS with FDB flows. + * + * This function does not create any function if proxy port for @p dev port + * was not configured for HW Steering. + * + * This function assumes that E-Switch is enabled and PMD is running with + * HW Steering configured. + * + * @param dev + * Pointer to Ethernet device which will be the action destination. + * + * @return + * 0 on success, positive value otherwise. + */ +int +flow_hw_create_vport_action(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_eth_dev *proxy_dev; + struct mlx5_priv *proxy_priv; + uint16_t port_id = dev->data->port_id; + uint16_t proxy_port_id = port_id; + int ret; + + ret = mlx5_flow_pick_transfer_proxy(dev, &proxy_port_id, NULL); + if (ret) + return ret; + proxy_dev = &rte_eth_devices[proxy_port_id]; + proxy_priv = proxy_dev->data->dev_private; + if (!proxy_priv->hw_vport) + return 0; + if (proxy_priv->hw_vport[port_id]) { + DRV_LOG(ERR, "port %u HWS vport action already created", + port_id); + return -EINVAL; + } + proxy_priv->hw_vport[port_id] = mlx5dr_action_create_dest_vport + (proxy_priv->dr_ctx, priv->dev_port, + MLX5DR_ACTION_FLAG_HWS_FDB); + if (!proxy_priv->hw_vport[port_id]) { + DRV_LOG(ERR, "port %u unable to create HWS vport action", + port_id); + return -EINVAL; + } + return 0; +} + +/** + * Destroys the vport action associated with @p dev device + * from actions' cache. + * + * This function does not destroy any action if there is no action cached + * for @p dev or proxy port was not configured for HW Steering. + * + * This function assumes that E-Switch is enabled and PMD is running with + * HW Steering configured. + * + * @param dev + * Pointer to Ethernet device which will be the action destination. + */ +void +flow_hw_destroy_vport_action(struct rte_eth_dev *dev) +{ + struct rte_eth_dev *proxy_dev; + struct mlx5_priv *proxy_priv; + uint16_t port_id = dev->data->port_id; + uint16_t proxy_port_id = port_id; + + if (mlx5_flow_pick_transfer_proxy(dev, &proxy_port_id, NULL)) + return; + proxy_dev = &rte_eth_devices[proxy_port_id]; + proxy_priv = proxy_dev->data->dev_private; + if (!proxy_priv->hw_vport || !proxy_priv->hw_vport[port_id]) + return; + mlx5dr_action_destroy(proxy_priv->hw_vport[port_id]); + proxy_priv->hw_vport[port_id] = NULL; +} + +static int +flow_hw_create_vport_actions(struct mlx5_priv *priv) +{ + uint16_t port_id; + + MLX5_ASSERT(!priv->hw_vport); + priv->hw_vport = mlx5_malloc(MLX5_MEM_ZERO, + sizeof(*priv->hw_vport) * RTE_MAX_ETHPORTS, + 0, SOCKET_ID_ANY); + if (!priv->hw_vport) + return -ENOMEM; + DRV_LOG(DEBUG, "port %u :: creating vport actions", priv->dev_data->port_id); + DRV_LOG(DEBUG, "port %u :: domain_id=%u", priv->dev_data->port_id, priv->domain_id); + MLX5_ETH_FOREACH_DEV(port_id, NULL) { + struct mlx5_priv *port_priv = rte_eth_devices[port_id].data->dev_private; + + if (!port_priv || + port_priv->domain_id != priv->domain_id) + continue; + DRV_LOG(DEBUG, "port %u :: for port_id=%u, calling mlx5dr_action_create_dest_vport() with ibport=%u", + priv->dev_data->port_id, port_id, port_priv->dev_port); + priv->hw_vport[port_id] = mlx5dr_action_create_dest_vport + (priv->dr_ctx, port_priv->dev_port, + MLX5DR_ACTION_FLAG_HWS_FDB); + DRV_LOG(DEBUG, "port %u :: priv->hw_vport[%u]=%p", + priv->dev_data->port_id, port_id, (void *)priv->hw_vport[port_id]); + if (!priv->hw_vport[port_id]) + return -EINVAL; + } + return 0; +} + +static void +flow_hw_free_vport_actions(struct mlx5_priv *priv) +{ + uint16_t port_id; + + if (!priv->hw_vport) + return; + for (port_id = 0; port_id < RTE_MAX_ETHPORTS; ++port_id) + if (priv->hw_vport[port_id]) + mlx5dr_action_destroy(priv->hw_vport[port_id]); + mlx5_free(priv->hw_vport); + priv->hw_vport = NULL; +} + +/** + * Creates a flow pattern template used to match on E-Switch Manager. + * This template is used to set up a table for SQ miss default flow. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * Pointer to flow pattern template on success, NULL otherwise. + */ +static struct rte_flow_pattern_template * +flow_hw_create_ctrl_esw_mgr_pattern_template(struct rte_eth_dev *dev) +{ + struct rte_flow_pattern_template_attr attr = { + .relaxed_matching = 0, + .transfer = 1, + }; + struct rte_flow_item_ethdev port_spec = { + .port_id = MLX5_REPRESENTED_PORT_ESW_MGR, + }; + struct rte_flow_item_ethdev port_mask = { + .port_id = UINT16_MAX, + }; + struct rte_flow_item items[] = { + { + .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, + .spec = &port_spec, + .mask = &port_mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + + return flow_hw_pattern_template_create(dev, &attr, items, NULL); +} + +/** + * Creates a flow pattern template used to match on a TX queue. + * This template is used to set up a table for SQ miss default flow. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * Pointer to flow pattern template on success, NULL otherwise. + */ +static struct rte_flow_pattern_template * +flow_hw_create_ctrl_sq_pattern_template(struct rte_eth_dev *dev) +{ + struct rte_flow_pattern_template_attr attr = { + .relaxed_matching = 0, + .transfer = 1, + }; + struct mlx5_rte_flow_item_tx_queue queue_mask = { + .queue = UINT32_MAX, + }; + struct rte_flow_item items[] = { + { + .type = (enum rte_flow_item_type) + MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE, + .mask = &queue_mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + + return flow_hw_pattern_template_create(dev, &attr, items, NULL); +} + +/** + * Creates a flow pattern template with unmasked represented port matching. + * This template is used to set up a table for default transfer flows + * directing packets to group 1. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * Pointer to flow pattern template on success, NULL otherwise. + */ +static struct rte_flow_pattern_template * +flow_hw_create_ctrl_port_pattern_template(struct rte_eth_dev *dev) +{ + struct rte_flow_pattern_template_attr attr = { + .relaxed_matching = 0, + .transfer = 1, + }; + struct rte_flow_item_ethdev port_mask = { + .port_id = UINT16_MAX, + }; + struct rte_flow_item items[] = { + { + .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, + .mask = &port_mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + + return flow_hw_pattern_template_create(dev, &attr, items, NULL); +} + +/** + * Creates a flow actions template with an unmasked JUMP action. Flows + * based on this template will perform a jump to some group. This template + * is used to set up tables for control flows. + * + * @param dev + * Pointer to Ethernet device. + * @param group + * Destination group for this action template. + * + * @return + * Pointer to flow actions template on success, NULL otherwise. + */ +static struct rte_flow_actions_template * +flow_hw_create_ctrl_jump_actions_template(struct rte_eth_dev *dev, + uint32_t group) +{ + struct rte_flow_actions_template_attr attr = { + .transfer = 1, + }; + struct rte_flow_action_jump jump_v = { + .group = group, + }; + struct rte_flow_action_jump jump_m = { + .group = UINT32_MAX, + }; + struct rte_flow_action actions_v[] = { + { + .type = RTE_FLOW_ACTION_TYPE_JUMP, + .conf = &jump_v, + }, + { + .type = RTE_FLOW_ACTION_TYPE_END, + } + }; + struct rte_flow_action actions_m[] = { + { + .type = RTE_FLOW_ACTION_TYPE_JUMP, + .conf = &jump_m, + }, + { + .type = RTE_FLOW_ACTION_TYPE_END, + } + }; + + return flow_hw_actions_template_create(dev, &attr, actions_v, actions_m, + NULL); +} + +/** + * Creates a flow action template with a unmasked REPRESENTED_PORT action. + * It is used to create control flow tables. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * Pointer to flow action template on success, NULL otherwise. + */ +static struct rte_flow_actions_template * +flow_hw_create_ctrl_port_actions_template(struct rte_eth_dev *dev) +{ + struct rte_flow_actions_template_attr attr = { + .transfer = 1, + }; + struct rte_flow_action_ethdev port_v = { + .port_id = 0, + }; + struct rte_flow_action actions_v[] = { + { + .type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT, + .conf = &port_v, + }, + { + .type = RTE_FLOW_ACTION_TYPE_END, + } + }; + struct rte_flow_action_ethdev port_m = { + .port_id = 0, + }; + struct rte_flow_action actions_m[] = { + { + .type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT, + .conf = &port_m, + }, + { + .type = RTE_FLOW_ACTION_TYPE_END, + } + }; + + return flow_hw_actions_template_create(dev, &attr, actions_v, actions_m, + NULL); +} + +/** + * Creates a control flow table used to transfer traffic from E-Switch Manager + * and TX queues from group 0 to group 1. + * + * @param dev + * Pointer to Ethernet device. + * @param it + * Pointer to flow pattern template. + * @param at + * Pointer to flow actions template. + * + * @return + * Pointer to flow table on success, NULL otherwise. + */ +static struct rte_flow_template_table* +flow_hw_create_ctrl_sq_miss_root_table(struct rte_eth_dev *dev, + struct rte_flow_pattern_template *it, + struct rte_flow_actions_template *at) +{ + struct rte_flow_template_table_attr attr = { + .flow_attr = { + .group = 0, + .priority = 0, + .ingress = 0, + .egress = 0, + .transfer = 1, + }, + .nb_flows = MLX5_HW_CTRL_FLOW_NB_RULES, + }; + + return flow_hw_table_create(dev, &attr, &it, 1, &at, 1, NULL); +} + + +/** + * Creates a control flow table used to transfer traffic from E-Switch Manager + * and TX queues from group 0 to group 1. + * + * @param dev + * Pointer to Ethernet device. + * @param it + * Pointer to flow pattern template. + * @param at + * Pointer to flow actions template. + * + * @return + * Pointer to flow table on success, NULL otherwise. + */ +static struct rte_flow_template_table* +flow_hw_create_ctrl_sq_miss_table(struct rte_eth_dev *dev, + struct rte_flow_pattern_template *it, + struct rte_flow_actions_template *at) +{ + struct rte_flow_template_table_attr attr = { + .flow_attr = { + .group = MLX5_HW_SQ_MISS_GROUP, + .priority = 0, + .ingress = 0, + .egress = 0, + .transfer = 1, + }, + .nb_flows = MLX5_HW_CTRL_FLOW_NB_RULES, + }; + + return flow_hw_table_create(dev, &attr, &it, 1, &at, 1, NULL); +} + +/** + * Creates a control flow table used to transfer traffic + * from group 0 to group 1. + * + * @param dev + * Pointer to Ethernet device. + * @param it + * Pointer to flow pattern template. + * @param at + * Pointer to flow actions template. + * + * @return + * Pointer to flow table on success, NULL otherwise. + */ +static struct rte_flow_template_table * +flow_hw_create_ctrl_jump_table(struct rte_eth_dev *dev, + struct rte_flow_pattern_template *it, + struct rte_flow_actions_template *at) +{ + struct rte_flow_template_table_attr attr = { + .flow_attr = { + .group = 0, + .priority = 15, /* TODO: Flow priority discovery. */ + .ingress = 0, + .egress = 0, + .transfer = 1, + }, + .nb_flows = MLX5_HW_CTRL_FLOW_NB_RULES, + }; + + return flow_hw_table_create(dev, &attr, &it, 1, &at, 1, NULL); +} + +/** + * Creates a set of flow tables used to create control flows used + * when E-Switch is engaged. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * 0 on success, EINVAL otherwise + */ +static __rte_unused int +flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_flow_pattern_template *esw_mgr_items_tmpl = NULL; + struct rte_flow_pattern_template *sq_items_tmpl = NULL; + struct rte_flow_pattern_template *port_items_tmpl = NULL; + struct rte_flow_actions_template *jump_sq_actions_tmpl = NULL; + struct rte_flow_actions_template *port_actions_tmpl = NULL; + struct rte_flow_actions_template *jump_one_actions_tmpl = NULL; + + /* Item templates */ + esw_mgr_items_tmpl = flow_hw_create_ctrl_esw_mgr_pattern_template(dev); + if (!esw_mgr_items_tmpl) { + DRV_LOG(ERR, "port %u failed to create E-Switch Manager item" + " template for control flows", dev->data->port_id); + goto error; + } + sq_items_tmpl = flow_hw_create_ctrl_sq_pattern_template(dev); + if (!sq_items_tmpl) { + DRV_LOG(ERR, "port %u failed to create SQ item template for" + " control flows", dev->data->port_id); + goto error; + } + port_items_tmpl = flow_hw_create_ctrl_port_pattern_template(dev); + if (!port_items_tmpl) { + DRV_LOG(ERR, "port %u failed to create SQ item template for" + " control flows", dev->data->port_id); + goto error; + } + /* Action templates */ + jump_sq_actions_tmpl = flow_hw_create_ctrl_jump_actions_template(dev, + MLX5_HW_SQ_MISS_GROUP); + if (!jump_sq_actions_tmpl) { + DRV_LOG(ERR, "port %u failed to create jump action template" + " for control flows", dev->data->port_id); + goto error; + } + port_actions_tmpl = flow_hw_create_ctrl_port_actions_template(dev); + if (!port_actions_tmpl) { + DRV_LOG(ERR, "port %u failed to create port action template" + " for control flows", dev->data->port_id); + goto error; + } + jump_one_actions_tmpl = flow_hw_create_ctrl_jump_actions_template(dev, 1); + if (!jump_one_actions_tmpl) { + DRV_LOG(ERR, "port %u failed to create jump action template" + " for control flows", dev->data->port_id); + goto error; + } + /* Tables */ + MLX5_ASSERT(priv->hw_esw_sq_miss_root_tbl == NULL); + priv->hw_esw_sq_miss_root_tbl = flow_hw_create_ctrl_sq_miss_root_table + (dev, esw_mgr_items_tmpl, jump_sq_actions_tmpl); + if (!priv->hw_esw_sq_miss_root_tbl) { + DRV_LOG(ERR, "port %u failed to create table for default sq miss (root table)" + " for control flows", dev->data->port_id); + goto error; + } + MLX5_ASSERT(priv->hw_esw_sq_miss_tbl == NULL); + priv->hw_esw_sq_miss_tbl = flow_hw_create_ctrl_sq_miss_table(dev, sq_items_tmpl, + port_actions_tmpl); + if (!priv->hw_esw_sq_miss_tbl) { + DRV_LOG(ERR, "port %u failed to create table for default sq miss (non-root table)" + " for control flows", dev->data->port_id); + goto error; + } + MLX5_ASSERT(priv->hw_esw_zero_tbl == NULL); + priv->hw_esw_zero_tbl = flow_hw_create_ctrl_jump_table(dev, port_items_tmpl, + jump_one_actions_tmpl); + if (!priv->hw_esw_zero_tbl) { + DRV_LOG(ERR, "port %u failed to create table for default jump to group 1" + " for control flows", dev->data->port_id); + goto error; + } + return 0; +error: + if (priv->hw_esw_zero_tbl) { + flow_hw_table_destroy(dev, priv->hw_esw_zero_tbl, NULL); + priv->hw_esw_zero_tbl = NULL; + } + if (priv->hw_esw_sq_miss_tbl) { + flow_hw_table_destroy(dev, priv->hw_esw_sq_miss_tbl, NULL); + priv->hw_esw_sq_miss_tbl = NULL; + } + if (priv->hw_esw_sq_miss_root_tbl) { + flow_hw_table_destroy(dev, priv->hw_esw_sq_miss_root_tbl, NULL); + priv->hw_esw_sq_miss_root_tbl = NULL; + } + if (jump_one_actions_tmpl) + flow_hw_actions_template_destroy(dev, jump_one_actions_tmpl, NULL); + if (port_actions_tmpl) + flow_hw_actions_template_destroy(dev, port_actions_tmpl, NULL); + if (jump_sq_actions_tmpl) + flow_hw_actions_template_destroy(dev, jump_sq_actions_tmpl, NULL); + if (port_items_tmpl) + flow_hw_pattern_template_destroy(dev, port_items_tmpl, NULL); + if (sq_items_tmpl) + flow_hw_pattern_template_destroy(dev, sq_items_tmpl, NULL); + if (esw_mgr_items_tmpl) + flow_hw_pattern_template_destroy(dev, esw_mgr_items_tmpl, NULL); + return -EINVAL; +} + /** * Configure port HWS resources. * @@ -2643,7 +3462,6 @@ flow_hw_grp_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry) * @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ - static int flow_hw_configure(struct rte_eth_dev *dev, const struct rte_flow_port_attr *port_attr, @@ -2666,6 +3484,14 @@ flow_hw_configure(struct rte_eth_dev *dev, .free = mlx5_free, .type = "mlx5_hw_action_construct_data", }; + /* Adds one queue to be used by PMD. + * The last queue will be used by the PMD. + */ + uint16_t nb_q_updated; + struct rte_flow_queue_attr **_queue_attr = NULL; + struct rte_flow_queue_attr ctrl_queue_attr = {0}; + bool is_proxy = !!(priv->sh->config.dv_esw_en && priv->master); + int ret; if (!port_attr || !nb_queue || !queue_attr) { rte_errno = EINVAL; @@ -2674,7 +3500,7 @@ flow_hw_configure(struct rte_eth_dev *dev, /* In case re-configuring, release existing context at first. */ if (priv->dr_ctx) { /* */ - for (i = 0; i < nb_queue; i++) { + for (i = 0; i < priv->nb_queue; i++) { hw_q = &priv->hw_q[i]; /* Make sure all queues are empty. */ if (hw_q->size != hw_q->job_idx) { @@ -2684,26 +3510,42 @@ flow_hw_configure(struct rte_eth_dev *dev, } flow_hw_resource_release(dev); } + ctrl_queue_attr.size = queue_attr[0]->size; + nb_q_updated = nb_queue + 1; + _queue_attr = mlx5_malloc(MLX5_MEM_ZERO, + nb_q_updated * + sizeof(struct rte_flow_queue_attr *), + 64, SOCKET_ID_ANY); + if (!_queue_attr) { + rte_errno = ENOMEM; + goto err; + } + + memcpy(_queue_attr, queue_attr, + sizeof(void *) * nb_queue); + _queue_attr[nb_queue] = &ctrl_queue_attr; priv->acts_ipool = mlx5_ipool_create(&cfg); if (!priv->acts_ipool) goto err; /* Allocate the queue job descriptor LIFO. */ - mem_size = sizeof(priv->hw_q[0]) * nb_queue; - for (i = 0; i < nb_queue; i++) { + mem_size = sizeof(priv->hw_q[0]) * nb_q_updated; + for (i = 0; i < nb_q_updated; i++) { /* * Check if the queues' size are all the same as the * limitation from HWS layer. */ - if (queue_attr[i]->size != queue_attr[0]->size) { + if (_queue_attr[i]->size != _queue_attr[0]->size) { rte_errno = EINVAL; goto err; } mem_size += (sizeof(struct mlx5_hw_q_job *) + + sizeof(struct mlx5_hw_q_job) + sizeof(uint8_t) * MLX5_ENCAP_MAX_LEN + sizeof(struct mlx5_modification_cmd) * MLX5_MHDR_MAX_CMD + - sizeof(struct mlx5_hw_q_job)) * - queue_attr[0]->size; + sizeof(struct rte_flow_item) * + MLX5_HW_MAX_ITEMS) * + _queue_attr[i]->size; } priv->hw_q = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 64, SOCKET_ID_ANY); @@ -2711,58 +3553,82 @@ flow_hw_configure(struct rte_eth_dev *dev, rte_errno = ENOMEM; goto err; } - for (i = 0; i < nb_queue; i++) { + for (i = 0; i < nb_q_updated; i++) { uint8_t *encap = NULL; struct mlx5_modification_cmd *mhdr_cmd = NULL; + struct rte_flow_item *items = NULL; - priv->hw_q[i].job_idx = queue_attr[i]->size; - priv->hw_q[i].size = queue_attr[i]->size; + priv->hw_q[i].job_idx = _queue_attr[i]->size; + priv->hw_q[i].size = _queue_attr[i]->size; if (i == 0) priv->hw_q[i].job = (struct mlx5_hw_q_job **) - &priv->hw_q[nb_queue]; + &priv->hw_q[nb_q_updated]; else priv->hw_q[i].job = (struct mlx5_hw_q_job **) - &job[queue_attr[i - 1]->size]; + &job[_queue_attr[i - 1]->size - 1].items + [MLX5_HW_MAX_ITEMS]; job = (struct mlx5_hw_q_job *) - &priv->hw_q[i].job[queue_attr[i]->size]; - mhdr_cmd = (struct mlx5_modification_cmd *)&job[queue_attr[i]->size]; - encap = (uint8_t *)&mhdr_cmd[queue_attr[i]->size * MLX5_MHDR_MAX_CMD]; - for (j = 0; j < queue_attr[i]->size; j++) { + &priv->hw_q[i].job[_queue_attr[i]->size]; + mhdr_cmd = (struct mlx5_modification_cmd *) + &job[_queue_attr[i]->size]; + encap = (uint8_t *) + &mhdr_cmd[_queue_attr[i]->size * MLX5_MHDR_MAX_CMD]; + items = (struct rte_flow_item *) + &encap[_queue_attr[i]->size * MLX5_ENCAP_MAX_LEN]; + for (j = 0; j < _queue_attr[i]->size; j++) { job[j].mhdr_cmd = &mhdr_cmd[j * MLX5_MHDR_MAX_CMD]; job[j].encap_data = &encap[j * MLX5_ENCAP_MAX_LEN]; + job[j].items = &items[j * MLX5_HW_MAX_ITEMS]; priv->hw_q[i].job[j] = &job[j]; } } dr_ctx_attr.pd = priv->sh->cdev->pd; - dr_ctx_attr.queues = nb_queue; + dr_ctx_attr.queues = nb_q_updated; /* Queue size should all be the same. Take the first one. */ - dr_ctx_attr.queue_size = queue_attr[0]->size; + dr_ctx_attr.queue_size = _queue_attr[0]->size; dr_ctx = mlx5dr_context_open(priv->sh->cdev->ctx, &dr_ctx_attr); /* rte_errno has been updated by HWS layer. */ if (!dr_ctx) goto err; priv->dr_ctx = dr_ctx; - priv->nb_queue = nb_queue; + priv->nb_queue = nb_q_updated; + rte_spinlock_init(&priv->hw_ctrl_lock); + LIST_INIT(&priv->hw_ctrl_flows); /* Add global actions. */ for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) { - for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) { - priv->hw_drop[i][j] = mlx5dr_action_create_dest_drop - (priv->dr_ctx, mlx5_hw_act_flag[i][j]); - if (!priv->hw_drop[i][j]) - goto err; - } + uint32_t act_flags = 0; + + act_flags = mlx5_hw_act_flag[i][0] | mlx5_hw_act_flag[i][1]; + if (is_proxy) + act_flags |= mlx5_hw_act_flag[i][2]; + priv->hw_drop[i] = mlx5dr_action_create_dest_drop(priv->dr_ctx, act_flags); + if (!priv->hw_drop[i]) + goto err; priv->hw_tag[i] = mlx5dr_action_create_tag (priv->dr_ctx, mlx5_hw_act_flag[i][0]); if (!priv->hw_tag[i]) goto err; } + if (is_proxy) { + ret = flow_hw_create_vport_actions(priv); + if (ret) { + rte_errno = -ret; + goto err; + } + ret = flow_hw_create_ctrl_tables(dev); + if (ret) { + rte_errno = -ret; + goto err; + } + } + if (_queue_attr) + mlx5_free(_queue_attr); return 0; err: + flow_hw_free_vport_actions(priv); for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) { - for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) { - if (priv->hw_drop[i][j]) - mlx5dr_action_destroy(priv->hw_drop[i][j]); - } + if (priv->hw_drop[i]) + mlx5dr_action_destroy(priv->hw_drop[i]); if (priv->hw_tag[i]) mlx5dr_action_destroy(priv->hw_tag[i]); } @@ -2774,6 +3640,8 @@ flow_hw_configure(struct rte_eth_dev *dev, mlx5_ipool_destroy(priv->acts_ipool); priv->acts_ipool = NULL; } + if (_queue_attr) + mlx5_free(_queue_attr); return rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "fail to configure port"); @@ -2792,10 +3660,12 @@ flow_hw_resource_release(struct rte_eth_dev *dev) struct rte_flow_template_table *tbl; struct rte_flow_pattern_template *it; struct rte_flow_actions_template *at; - int i, j; + int i; if (!priv->dr_ctx) return; + flow_hw_rxq_flag_set(dev, false); + flow_hw_flush_all_ctrl_flows(dev); while (!LIST_EMPTY(&priv->flow_hw_tbl)) { tbl = LIST_FIRST(&priv->flow_hw_tbl); flow_hw_table_destroy(dev, tbl, NULL); @@ -2809,13 +3679,12 @@ flow_hw_resource_release(struct rte_eth_dev *dev) flow_hw_actions_template_destroy(dev, at, NULL); } for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) { - for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) { - if (priv->hw_drop[i][j]) - mlx5dr_action_destroy(priv->hw_drop[i][j]); - } + if (priv->hw_drop[i]) + mlx5dr_action_destroy(priv->hw_drop[i]); if (priv->hw_tag[i]) mlx5dr_action_destroy(priv->hw_tag[i]); } + flow_hw_free_vport_actions(priv); if (priv->acts_ipool) { mlx5_ipool_destroy(priv->acts_ipool); priv->acts_ipool = NULL; @@ -3058,4 +3927,397 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .action_query = flow_dv_action_query, }; +static uint32_t +flow_hw_get_ctrl_queue(struct mlx5_priv *priv) +{ + MLX5_ASSERT(priv->nb_queue > 0); + return priv->nb_queue - 1; +} + +/** + * Creates a control flow using flow template API on @p proxy_dev device, + * on behalf of @p owner_dev device. + * + * This function uses locks internally to synchronize access to the + * flow queue. + * + * Created flow is stored in private list associated with @p proxy_dev device. + * + * @param owner_dev + * Pointer to Ethernet device on behalf of which flow is created. + * @param proxy_dev + * Pointer to Ethernet device on which flow is created. + * @param table + * Pointer to flow table. + * @param items + * Pointer to flow rule items. + * @param item_template_idx + * Index of an item template associated with @p table. + * @param actions + * Pointer to flow rule actions. + * @param action_template_idx + * Index of an action template associated with @p table. + * + * @return + * 0 on success, negative errno value otherwise and rte_errno set. + */ +static __rte_unused int +flow_hw_create_ctrl_flow(struct rte_eth_dev *owner_dev, + struct rte_eth_dev *proxy_dev, + struct rte_flow_template_table *table, + struct rte_flow_item items[], + uint8_t item_template_idx, + struct rte_flow_action actions[], + uint8_t action_template_idx) +{ + struct mlx5_priv *priv = proxy_dev->data->dev_private; + uint32_t queue = flow_hw_get_ctrl_queue(priv); + struct rte_flow_op_attr op_attr = { + .postpone = 0, + }; + struct rte_flow *flow = NULL; + struct mlx5_hw_ctrl_flow *entry = NULL; + int ret; + + rte_spinlock_lock(&priv->hw_ctrl_lock); + entry = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_SYS, sizeof(*entry), + 0, SOCKET_ID_ANY); + if (!entry) { + DRV_LOG(ERR, "port %u not enough memory to create control flows", + proxy_dev->data->port_id); + rte_errno = ENOMEM; + ret = -rte_errno; + goto error; + } + flow = flow_hw_async_flow_create(proxy_dev, queue, &op_attr, table, + items, item_template_idx, + actions, action_template_idx, + NULL, NULL); + if (!flow) { + DRV_LOG(ERR, "port %u failed to enqueue create control" + " flow operation", proxy_dev->data->port_id); + ret = -rte_errno; + goto error; + } + ret = flow_hw_push(proxy_dev, queue, NULL); + if (ret) { + DRV_LOG(ERR, "port %u failed to drain control flow queue", + proxy_dev->data->port_id); + goto error; + } + ret = __flow_hw_pull_comp(proxy_dev, queue, 1, NULL); + if (ret) { + DRV_LOG(ERR, "port %u failed to insert control flow", + proxy_dev->data->port_id); + rte_errno = EINVAL; + ret = -rte_errno; + goto error; + } + entry->owner_dev = owner_dev; + entry->flow = flow; + LIST_INSERT_HEAD(&priv->hw_ctrl_flows, entry, next); + rte_spinlock_unlock(&priv->hw_ctrl_lock); + return 0; +error: + if (entry) + mlx5_free(entry); + rte_spinlock_unlock(&priv->hw_ctrl_lock); + return ret; +} + +/** + * Destroys a control flow @p flow using flow template API on @p dev device. + * + * This function uses locks internally to synchronize access to the + * flow queue. + * + * If the @p flow is stored on any private list/pool, then caller must free up + * the relevant resources. + * + * @param dev + * Pointer to Ethernet device. + * @param flow + * Pointer to flow rule. + * + * @return + * 0 on success, non-zero value otherwise. + */ +static int +flow_hw_destroy_ctrl_flow(struct rte_eth_dev *dev, struct rte_flow *flow) +{ + struct mlx5_priv *priv = dev->data->dev_private; + uint32_t queue = flow_hw_get_ctrl_queue(priv); + struct rte_flow_op_attr op_attr = { + .postpone = 0, + }; + int ret; + + rte_spinlock_lock(&priv->hw_ctrl_lock); + ret = flow_hw_async_flow_destroy(dev, queue, &op_attr, flow, NULL, NULL); + if (ret) { + DRV_LOG(ERR, "port %u failed to enqueue destroy control" + " flow operation", dev->data->port_id); + goto exit; + } + ret = flow_hw_push(dev, queue, NULL); + if (ret) { + DRV_LOG(ERR, "port %u failed to drain control flow queue", + dev->data->port_id); + goto exit; + } + ret = __flow_hw_pull_comp(dev, queue, 1, NULL); + if (ret) { + DRV_LOG(ERR, "port %u failed to destroy control flow", + dev->data->port_id); + rte_errno = EINVAL; + ret = -rte_errno; + goto exit; + } +exit: + rte_spinlock_unlock(&priv->hw_ctrl_lock); + return ret; +} + +/** + * Destroys control flows created on behalf of @p owner_dev device. + * + * @param owner_dev + * Pointer to Ethernet device owning control flows. + * + * @return + * 0 on success, otherwise negative error code is returned and + * rte_errno is set. + */ +int +mlx5_flow_hw_flush_ctrl_flows(struct rte_eth_dev *owner_dev) +{ + struct mlx5_priv *owner_priv = owner_dev->data->dev_private; + struct rte_eth_dev *proxy_dev; + struct mlx5_priv *proxy_priv; + struct mlx5_hw_ctrl_flow *cf; + struct mlx5_hw_ctrl_flow *cf_next; + uint16_t owner_port_id = owner_dev->data->port_id; + uint16_t proxy_port_id = owner_dev->data->port_id; + int ret; + + if (owner_priv->sh->config.dv_esw_en) { + if (rte_flow_pick_transfer_proxy(owner_port_id, &proxy_port_id, NULL)) { + DRV_LOG(ERR, "Unable to find proxy port for port %u", + owner_port_id); + rte_errno = EINVAL; + return -rte_errno; + } + proxy_dev = &rte_eth_devices[proxy_port_id]; + proxy_priv = proxy_dev->data->dev_private; + } else { + proxy_dev = owner_dev; + proxy_priv = owner_priv; + } + cf = LIST_FIRST(&proxy_priv->hw_ctrl_flows); + while (cf != NULL) { + cf_next = LIST_NEXT(cf, next); + if (cf->owner_dev == owner_dev) { + ret = flow_hw_destroy_ctrl_flow(proxy_dev, cf->flow); + if (ret) { + rte_errno = ret; + return -ret; + } + LIST_REMOVE(cf, next); + mlx5_free(cf); + } + cf = cf_next; + } + return 0; +} + +/** + * Destroys all control flows created on @p dev device. + * + * @param owner_dev + * Pointer to Ethernet device. + * + * @return + * 0 on success, otherwise negative error code is returned and + * rte_errno is set. + */ +static int +flow_hw_flush_all_ctrl_flows(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_hw_ctrl_flow *cf; + struct mlx5_hw_ctrl_flow *cf_next; + int ret; + + cf = LIST_FIRST(&priv->hw_ctrl_flows); + while (cf != NULL) { + cf_next = LIST_NEXT(cf, next); + ret = flow_hw_destroy_ctrl_flow(dev, cf->flow); + if (ret) { + rte_errno = ret; + return -ret; + } + LIST_REMOVE(cf, next); + mlx5_free(cf); + cf = cf_next; + } + return 0; +} + +int +mlx5_flow_hw_esw_create_mgr_sq_miss_flow(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_flow_item_ethdev port_spec = { + .port_id = MLX5_REPRESENTED_PORT_ESW_MGR, + }; + struct rte_flow_item_ethdev port_mask = { + .port_id = MLX5_REPRESENTED_PORT_ESW_MGR, + }; + struct rte_flow_item items[] = { + { + .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, + .spec = &port_spec, + .mask = &port_mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + struct rte_flow_action_jump jump = { + .group = MLX5_HW_SQ_MISS_GROUP, + }; + struct rte_flow_action actions[] = { + { + .type = RTE_FLOW_ACTION_TYPE_JUMP, + .conf = &jump, + }, + { + .type = RTE_FLOW_ACTION_TYPE_END, + }, + }; + + MLX5_ASSERT(priv->master); + if (!priv->dr_ctx || + !priv->hw_esw_sq_miss_root_tbl) + return 0; + return flow_hw_create_ctrl_flow(dev, dev, + priv->hw_esw_sq_miss_root_tbl, + items, 0, actions, 0); +} + +int +mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq) +{ + uint16_t port_id = dev->data->port_id; + struct mlx5_rte_flow_item_tx_queue queue_spec = { + .queue = txq, + }; + struct mlx5_rte_flow_item_tx_queue queue_mask = { + .queue = UINT32_MAX, + }; + struct rte_flow_item items[] = { + { + .type = (enum rte_flow_item_type) + MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE, + .spec = &queue_spec, + .mask = &queue_mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + struct rte_flow_action_ethdev port = { + .port_id = port_id, + }; + struct rte_flow_action actions[] = { + { + .type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT, + .conf = &port, + }, + { + .type = RTE_FLOW_ACTION_TYPE_END, + }, + }; + struct rte_eth_dev *proxy_dev; + struct mlx5_priv *proxy_priv; + uint16_t proxy_port_id = dev->data->port_id; + int ret; + + RTE_SET_USED(txq); + ret = rte_flow_pick_transfer_proxy(port_id, &proxy_port_id, NULL); + if (ret) { + DRV_LOG(ERR, "Unable to pick proxy port for port %u", port_id); + return ret; + } + proxy_dev = &rte_eth_devices[proxy_port_id]; + proxy_priv = proxy_dev->data->dev_private; + if (!proxy_priv->dr_ctx) + return 0; + if (!proxy_priv->hw_esw_sq_miss_root_tbl || + !proxy_priv->hw_esw_sq_miss_tbl) { + DRV_LOG(ERR, "port %u proxy port %u was configured but default" + " flow tables are not created", + port_id, proxy_port_id); + rte_errno = ENOMEM; + return -rte_errno; + } + return flow_hw_create_ctrl_flow(dev, proxy_dev, + proxy_priv->hw_esw_sq_miss_tbl, + items, 0, actions, 0); +} + +int +mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev) +{ + uint16_t port_id = dev->data->port_id; + struct rte_flow_item_ethdev port_spec = { + .port_id = port_id, + }; + struct rte_flow_item items[] = { + { + .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, + .spec = &port_spec, + }, + { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + struct rte_flow_action_jump jump = { + .group = 1, + }; + struct rte_flow_action actions[] = { + { + .type = RTE_FLOW_ACTION_TYPE_JUMP, + .conf = &jump, + }, + { + .type = RTE_FLOW_ACTION_TYPE_END, + } + }; + struct rte_eth_dev *proxy_dev; + struct mlx5_priv *proxy_priv; + uint16_t proxy_port_id = dev->data->port_id; + int ret; + + ret = rte_flow_pick_transfer_proxy(port_id, &proxy_port_id, NULL); + if (ret) { + DRV_LOG(ERR, "Unable to pick proxy port for port %u", port_id); + return ret; + } + proxy_dev = &rte_eth_devices[proxy_port_id]; + proxy_priv = proxy_dev->data->dev_private; + if (!proxy_priv->dr_ctx) + return 0; + if (!proxy_priv->hw_esw_zero_tbl) { + DRV_LOG(ERR, "port %u proxy port %u was configured but default" + " flow tables are not created", + port_id, proxy_port_id); + rte_errno = EINVAL; + return -rte_errno; + } + return flow_hw_create_ctrl_flow(dev, proxy_dev, + proxy_priv->hw_esw_zero_tbl, + items, 0, actions, 0); +} + #endif diff --git a/drivers/net/mlx5/mlx5_flow_verbs.c b/drivers/net/mlx5/mlx5_flow_verbs.c index fd902078f8..7ffaf4c227 100644 --- a/drivers/net/mlx5/mlx5_flow_verbs.c +++ b/drivers/net/mlx5/mlx5_flow_verbs.c @@ -1245,12 +1245,14 @@ flow_verbs_validate(struct rte_eth_dev *dev, uint16_t ether_type = 0; bool is_empty_vlan = false; uint16_t udp_dport = 0; + bool is_root; if (items == NULL) return -1; ret = mlx5_flow_validate_attributes(dev, attr, error); if (ret < 0) return ret; + is_root = ret; for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) { int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL); int ret = 0; @@ -1380,7 +1382,7 @@ flow_verbs_validate(struct rte_eth_dev *dev, case RTE_FLOW_ITEM_TYPE_VXLAN: ret = mlx5_flow_validate_item_vxlan(dev, udp_dport, items, item_flags, - attr, error); + is_root, error); if (ret < 0) return ret; last_item = MLX5_FLOW_LAYER_VXLAN; diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index c68b32cf14..6313602a66 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -1280,6 +1280,52 @@ mlx5_dev_stop(struct rte_eth_dev *dev) return 0; } +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + +static int +mlx5_traffic_enable_hws(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + unsigned int i; + int ret; + + if (priv->sh->config.dv_esw_en && priv->master) { + if (mlx5_flow_hw_esw_create_mgr_sq_miss_flow(dev)) + goto error; + } + for (i = 0; i < priv->txqs_n; ++i) { + struct mlx5_txq_ctrl *txq = mlx5_txq_get(dev, i); + uint32_t queue; + + if (!txq) + continue; + if (txq->is_hairpin) + queue = txq->obj->sq->id; + else + queue = txq->obj->sq_obj.sq->id; + if ((priv->representor || priv->master) && + priv->sh->config.dv_esw_en) { + if (mlx5_flow_hw_esw_create_sq_miss_flow(dev, queue)) { + mlx5_txq_release(dev, i); + goto error; + } + } + mlx5_txq_release(dev, i); + } + if ((priv->master || priv->representor) && priv->sh->config.dv_esw_en) { + if (mlx5_flow_hw_esw_create_default_jump_flow(dev)) + goto error; + } + return 0; +error: + ret = rte_errno; + mlx5_flow_hw_flush_ctrl_flows(dev); + rte_errno = ret; + return -rte_errno; +} + +#endif + /** * Enable traffic flows configured by control plane * @@ -1316,6 +1362,10 @@ mlx5_traffic_enable(struct rte_eth_dev *dev) unsigned int j; int ret; +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + if (priv->sh->config.dv_flow_en == 2) + return mlx5_traffic_enable_hws(dev); +#endif /* * Hairpin txq default flow should be created no matter if it is * isolation mode. Or else all the packets to be sent will be sent @@ -1346,13 +1396,17 @@ mlx5_traffic_enable(struct rte_eth_dev *dev) } mlx5_txq_release(dev, i); } - if (priv->sh->config.dv_esw_en) { - if (mlx5_flow_create_esw_table_zero_flow(dev)) - priv->fdb_def_rule = 1; - else - DRV_LOG(INFO, "port %u FDB default rule cannot be" - " configured - only Eswitch group 0 flows are" - " supported.", dev->data->port_id); + if (priv->sh->config.fdb_def_rule) { + if (priv->sh->config.dv_esw_en) { + if (mlx5_flow_create_esw_table_zero_flow(dev)) + priv->fdb_def_rule = 1; + else + DRV_LOG(INFO, "port %u FDB default rule cannot be configured - only Eswitch group 0 flows are supported.", + dev->data->port_id); + } + } else { + DRV_LOG(INFO, "port %u FDB default rule is disabled", + dev->data->port_id); } if (!priv->sh->config.lacp_by_user && priv->pf_bond >= 0) { ret = mlx5_flow_lacp_miss(dev); @@ -1470,7 +1524,14 @@ mlx5_traffic_enable(struct rte_eth_dev *dev) void mlx5_traffic_disable(struct rte_eth_dev *dev) { - mlx5_flow_list_flush(dev, MLX5_FLOW_TYPE_CTL, false); +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + struct mlx5_priv *priv = dev->data->dev_private; + + if (priv->sh->config.dv_flow_en == 2) + mlx5_flow_hw_flush_ctrl_flows(dev); + else +#endif + mlx5_flow_list_flush(dev, MLX5_FLOW_TYPE_CTL, false); } /** From patchwork Fri Sep 30 12:53:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117216 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id D6755A00C4; Fri, 30 Sep 2022 14:54:23 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 90BF442B6F; Fri, 30 Sep 2022 14:54:00 +0200 (CEST) Received: from NAM02-SN1-obe.outbound.protection.outlook.com (mail-sn1anam02on2081.outbound.protection.outlook.com [40.107.96.81]) by mails.dpdk.org (Postfix) with ESMTP id 60F7A42905 for ; Fri, 30 Sep 2022 14:53:59 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=khtOAMkuLYcgwYpaZfuB5hsYFGkWRAeIhdSlEWALvzzTpujzMyTpaeorSHQMDKEsbF3lQQjlVdc2KAFiU501KKrHDw9v3CUE03vqSNZQW3UAhWMyV6FAX00jCDJ4PtkkoWKVNLILi/+2HxrczpdSjCYIQTcKfUQ4wQo+zKA50HUWmvdJdT5yeOcgb/7gGQVknAg9yfRdzjWeRli6K8bC+54zOm33BNW85mEycLsJuDqAG+C3CjrI/lwy+szCfCqU6vk3LXKOTO3osn5YjlfNGv+0bn7siKKhazmHDBsvFj1SVbtaLjMM6QwPoF4Jm6ptWVvb6ONuAwamArjNhap8Sw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=pRer6uCC6vY/pTJLDrLPvZETyzt0LsYzlJ7CmgLILSw=; b=W9fenv7fVdkIn2m8nCknZn7h2V0drtu9AWjjGS5wEsQTQYJ2wFhOTHhdm75gdDCdUiplBDiwqfoIEutXUqa8xyqGJKhpuCnRInmV5h5y5xI2E4ytaCohNKsEOCZUPlRWrKmJ6nbS/e2Mb4vUeOHxZZHSgx+cESeZQWvJRpM7aBQgufi4o+HRNHmZhANO0zzW3gTKIZc2iykuKa7KSCsK988veYRqWAbs6rI4JgHQCrkHKiTLFkcSeMUpWWFzIinuSVO6x0bzQnVtxtAk72XMBhjIsS6DEXjLKnqBN16cVMf6YuoUWB8Sj/Bo3cYNq5QCX3VEHK2s6L0rKhdKLLMsjA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=pRer6uCC6vY/pTJLDrLPvZETyzt0LsYzlJ7CmgLILSw=; b=q3NdlUMHV+m+j5Pp0rwEl2TthZ79WhnQAQVH60qDsXuE+sNXtI05iCyLJ+HFUNV7i9Nyi4S1OEyDF2nSBUI2LNVks7vJYEQEx525bVETPPfzAg9JoPXOL8MRb0Dnwx+GjqlUaLSfNBKUuprbdsBh41M61qYj4/+tG8rOjt1i3aI4xJaATINyTIrdOgahppGUFtN99VFSqOgAnKlz9USO0aZVhKpx2iIOcNrplrf8GRMCF/EU8vsYTsiqapvZOa3pGYGRgiG2xdH+EiyTm1y/h8lku3T/lJ5PF4NGE7gVGnfmcC44BMTQXTHS+hftprQqN+BC24qTDwBbzqdzVHS+kw== Received: from DM5PR07CA0112.namprd07.prod.outlook.com (2603:10b6:4:ae::41) by IA1PR12MB6234.namprd12.prod.outlook.com (2603:10b6:208:3e6::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.20; Fri, 30 Sep 2022 12:53:56 +0000 Received: from DM6NAM11FT089.eop-nam11.prod.protection.outlook.com (2603:10b6:4:ae:cafe::52) by DM5PR07CA0112.outlook.office365.com (2603:10b6:4:ae::41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.15 via Frontend Transport; Fri, 30 Sep 2022 12:53:56 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT089.mail.protection.outlook.com (10.13.173.82) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:53:56 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:46 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:44 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , Bing Zhao Subject: [PATCH v3 06/17] net/mlx5: add extended metadata mode for hardware steering Date: Fri, 30 Sep 2022 15:53:04 +0300 Message-ID: <20220930125315.5079-7-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT089:EE_|IA1PR12MB6234:EE_ X-MS-Office365-Filtering-Correlation-Id: ba1844ac-2a85-4f5d-5cf0-08daa2e2d630 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: j8zDnMeCTEYkKi0HSYJz6EHD0+px3t5NVLndhBkevHyo8jBT4kERNs3GT9lMSlDugHbolYgZAZXqEpSBgqXMcJn6h1lCP3dG59kRKTnZgjD+zsHb2/OjzKxxMgMZ1OZp0TB1DWvXqTIeAiwH9ns2dqweI4fSSIPkafRe5ButKBiZerbvO1fNth8zVfOgCAqlb/p2PqfQVfc4dRTj3l31c/nyh+4VaMCjvRysJIOh3bKXtouAQ0OyVOe9f1XvbrmonewN2bR6W9d/6N1CmEdirakXxT/nvJ1P2rLs7tKkNZ9WK9cZYjlziu611KELTGbo4XpAfSibGWSytguW6ZifWoaaIt/MozFSo3dtBHsTYDa0ckNhHBiEj4pjsOhFf27Lmkx55Q017Ji/aX14M/VbEvpmWb9c44fgzKlg6gEGWO2Gxx76xL5kqshEZLOO2Qaahe8Y2fNI/hF8ymnb8QpuwH6SmBLqRrxeutkmWQfTlyhWMadEMD/Q0TRKRcoGh5GZ1Ckx8G3juj4vf3eHf0zS6DWaxl5r+C5WQCXvQir++ScaSWqhtbfmnrhqp/UHKwzzWrU0ATjpRcbzFZ0YMePXVBtno5gr5WfX7PqPkVBkWRQ1pWZL2YKpOINLRbiUo/BNTnDTosBEXPz6PazK2xgi163wjDB8Tj+VsIyVBN650/pIUTdFodKupbm9xCpY3uQSe0+92RqASdNlmQFwOcLvUxGVFjLaoUjmh/qBbsKWY48v5kiHe/GsNP8bVPvqNnceuI/HKqsqUKEFZUyAYetFlb/XliwBGm9yKXaa+AUgHDA= X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(376002)(396003)(136003)(346002)(39860400002)(451199015)(40470700004)(36840700001)(46966006)(86362001)(40480700001)(36860700001)(55016003)(7636003)(36756003)(54906003)(82740400003)(40460700003)(356005)(336012)(4326008)(316002)(110136005)(8676002)(47076005)(5660300002)(6636002)(2906002)(70586007)(70206006)(41300700001)(8936002)(186003)(426003)(16526019)(478600001)(6666004)(82310400005)(107886003)(1076003)(83380400001)(7696005)(2616005)(26005)(30864003)(6286002)(579004)(559001)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:53:56.4586 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ba1844ac-2a85-4f5d-5cf0-08daa2e2d630 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT089.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: IA1PR12MB6234 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Bing Zhao The new mode 4 of devarg "dv_xmeta_en" is added for HWS only. In this mode, the Rx / Tx metadata with 32b width copy between FDB and NIC is supported. The mark is only supported in NIC and there is no copy supported. Signed-off-by: Bing Zhao --- drivers/net/mlx5/linux/mlx5_os.c | 10 +- drivers/net/mlx5/mlx5.c | 7 +- drivers/net/mlx5/mlx5.h | 8 +- drivers/net/mlx5/mlx5_flow.c | 8 +- drivers/net/mlx5/mlx5_flow.h | 14 + drivers/net/mlx5/mlx5_flow_dv.c | 43 +- drivers/net/mlx5/mlx5_flow_hw.c | 864 ++++++++++++++++++++++++++++--- drivers/net/mlx5/mlx5_trigger.c | 3 + 8 files changed, 872 insertions(+), 85 deletions(-) diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index e0586a4d6f..061b825e7b 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -1554,6 +1554,15 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, #ifdef HAVE_IBV_FLOW_DV_SUPPORT if (priv->vport_meta_mask) flow_hw_set_port_info(eth_dev); + if (priv->sh->config.dv_esw_en && + priv->sh->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && + priv->sh->config.dv_xmeta_en != MLX5_XMETA_MODE_META32_HWS) { + DRV_LOG(ERR, + "metadata mode %u is not supported in HWS eswitch mode", + priv->sh->config.dv_xmeta_en); + err = ENOTSUP; + goto error; + } /* Only HWS requires this information. */ flow_hw_init_tags_set(eth_dev); if (priv->sh->config.dv_esw_en && @@ -1569,7 +1578,6 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, goto error; #endif } - /* Port representor shares the same max priority with pf port. */ if (!priv->sh->flow_priority_check_flag) { /* Supported Verbs flow priority number detection. */ err = mlx5_flow_discover_priorities(eth_dev); diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 74adb677f4..cf5146d677 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -1218,7 +1218,8 @@ mlx5_dev_args_check_handler(const char *key, const char *val, void *opaque) if (tmp != MLX5_XMETA_MODE_LEGACY && tmp != MLX5_XMETA_MODE_META16 && tmp != MLX5_XMETA_MODE_META32 && - tmp != MLX5_XMETA_MODE_MISS_INFO) { + tmp != MLX5_XMETA_MODE_MISS_INFO && + tmp != MLX5_XMETA_MODE_META32_HWS) { DRV_LOG(ERR, "Invalid extensive metadata parameter."); rte_errno = EINVAL; return -rte_errno; @@ -2849,6 +2850,10 @@ mlx5_set_metadata_mask(struct rte_eth_dev *dev) meta = UINT32_MAX; mark = (reg_c0 >> rte_bsf32(reg_c0)) & MLX5_FLOW_MARK_MASK; break; + case MLX5_XMETA_MODE_META32_HWS: + meta = UINT32_MAX; + mark = MLX5_FLOW_MARK_MASK; + break; default: meta = 0; mark = 0; diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 0bf21c1efe..fc4bc4e6a3 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -298,8 +298,8 @@ struct mlx5_sh_config { uint32_t reclaim_mode:2; /* Memory reclaim mode. */ uint32_t dv_esw_en:1; /* Enable E-Switch DV flow. */ /* Enable DV flow. 1 means SW steering, 2 means HW steering. */ - unsigned int dv_flow_en:2; - uint32_t dv_xmeta_en:2; /* Enable extensive flow metadata. */ + uint32_t dv_flow_en:2; /* Enable DV flow. */ + uint32_t dv_xmeta_en:3; /* Enable extensive flow metadata. */ uint32_t dv_miss_info:1; /* Restore packet after partial hw miss. */ uint32_t l3_vxlan_en:1; /* Enable L3 VXLAN flow creation. */ uint32_t vf_nl_en:1; /* Enable Netlink requests in VF mode. */ @@ -312,7 +312,6 @@ struct mlx5_sh_config { uint32_t fdb_def_rule:1; /* Create FDB default jump rule */ }; - /* Structure for VF VLAN workaround. */ struct mlx5_vf_vlan { uint32_t tag:12; @@ -1279,12 +1278,12 @@ struct mlx5_dev_ctx_shared { struct mlx5_lb_ctx self_lb; /* QP to enable self loopback for Devx. */ unsigned int flow_max_priority; enum modify_reg flow_mreg_c[MLX5_MREG_C_NUM]; + /* Availability of mreg_c's. */ void *devx_channel_lwm; struct rte_intr_handle *intr_handle_lwm; pthread_mutex_t lwm_config_lock; uint32_t host_shaper_rate:8; uint32_t lwm_triggered:1; - /* Availability of mreg_c's. */ struct mlx5_dev_shared_port port[]; /* per device port data array. */ }; @@ -1508,6 +1507,7 @@ struct mlx5_priv { struct rte_flow_template_table *hw_esw_sq_miss_root_tbl; struct rte_flow_template_table *hw_esw_sq_miss_tbl; struct rte_flow_template_table *hw_esw_zero_tbl; + struct rte_flow_template_table *hw_tx_meta_cpy_tbl; struct mlx5_indexed_pool *flows[MLX5_FLOW_TYPE_MAXI]; /* RTE Flow rules. */ uint32_t ctrl_flows; /* Control flow rules. */ diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 9c44b2e99b..b570ed7f69 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -1107,6 +1107,8 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev, return REG_C_0; case MLX5_XMETA_MODE_META32: return REG_C_1; + case MLX5_XMETA_MODE_META32_HWS: + return REG_C_1; } break; case MLX5_METADATA_TX: @@ -1119,11 +1121,14 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev, return REG_C_0; case MLX5_XMETA_MODE_META32: return REG_C_1; + case MLX5_XMETA_MODE_META32_HWS: + return REG_C_1; } break; case MLX5_FLOW_MARK: switch (config->dv_xmeta_en) { case MLX5_XMETA_MODE_LEGACY: + case MLX5_XMETA_MODE_META32_HWS: return REG_NON; case MLX5_XMETA_MODE_META16: return REG_C_1; @@ -4442,7 +4447,8 @@ static bool flow_check_modify_action_type(struct rte_eth_dev *dev, return true; case RTE_FLOW_ACTION_TYPE_FLAG: case RTE_FLOW_ACTION_TYPE_MARK: - if (priv->sh->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) + if (priv->sh->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY && + priv->sh->config.dv_xmeta_en != MLX5_XMETA_MODE_META32_HWS) return true; else return false; diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 93f0e189d4..a8b27ea494 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -48,6 +48,12 @@ enum mlx5_rte_flow_action_type { MLX5_RTE_FLOW_ACTION_TYPE_RSS, }; +/* Private (internal) Field IDs for MODIFY_FIELD action. */ +enum mlx5_rte_flow_field_id { + MLX5_RTE_FLOW_FIELD_END = INT_MIN, + MLX5_RTE_FLOW_FIELD_META_REG, +}; + #define MLX5_INDIRECT_ACTION_TYPE_OFFSET 30 enum { @@ -1167,6 +1173,7 @@ struct rte_flow_actions_template { struct rte_flow_action *masks; /* Cached action masks.*/ uint16_t mhdr_off; /* Offset of DR modify header action. */ uint32_t refcnt; /* Reference counter. */ + uint16_t rx_cpy_pos; /* Action position of Rx metadata to be copied. */ }; /* Jump action struct. */ @@ -1243,6 +1250,11 @@ struct mlx5_flow_group { #define MLX5_HW_TBL_MAX_ITEM_TEMPLATE 2 #define MLX5_HW_TBL_MAX_ACTION_TEMPLATE 32 +struct mlx5_flow_template_table_cfg { + struct rte_flow_template_table_attr attr; /* Table attributes passed through flow API. */ + bool external; /* True if created by flow API, false if table is internal to PMD. */ +}; + struct rte_flow_template_table { LIST_ENTRY(rte_flow_template_table) next; struct mlx5_flow_group *grp; /* The group rte_flow_template_table uses. */ @@ -1252,6 +1264,7 @@ struct rte_flow_template_table { /* Action templates bind to the table. */ struct mlx5_hw_action_template ats[MLX5_HW_TBL_MAX_ACTION_TEMPLATE]; struct mlx5_indexed_pool *flow; /* The table's flow ipool. */ + struct mlx5_flow_template_table_cfg cfg; uint32_t type; /* Flow table type RX/TX/FDB. */ uint8_t nb_item_templates; /* Item template number. */ uint8_t nb_action_templates; /* Action template number. */ @@ -2333,4 +2346,5 @@ int mlx5_flow_hw_esw_create_mgr_sq_miss_flow(struct rte_eth_dev *dev); int mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq); int mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev); +int mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev); #endif /* RTE_PMD_MLX5_FLOW_H_ */ diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 3fc2453045..5b72cfaa61 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -1783,7 +1783,8 @@ mlx5_flow_field_id_to_modify_info int reg; if (priv->sh->config.dv_flow_en == 2) - reg = REG_C_1; + reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_TAG, + data->level); else reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, data->level, error); @@ -1862,6 +1863,24 @@ mlx5_flow_field_id_to_modify_info else info[idx].offset = off_be; break; + case MLX5_RTE_FLOW_FIELD_META_REG: + { + uint32_t meta_mask = priv->sh->dv_meta_mask; + uint32_t meta_count = __builtin_popcount(meta_mask); + uint32_t reg = data->level; + + RTE_SET_USED(meta_count); + MLX5_ASSERT(data->offset + width <= meta_count); + MLX5_ASSERT(reg != REG_NON); + MLX5_ASSERT(reg < RTE_DIM(reg_to_field)); + info[idx] = (struct field_modify_info){4, 0, reg_to_field[reg]}; + if (mask) + mask[idx] = flow_modify_info_mask_32_masked + (width, data->offset, meta_mask); + else + info[idx].offset = data->offset; + } + break; case RTE_FLOW_FIELD_POINTER: case RTE_FLOW_FIELD_VALUE: default: @@ -9819,7 +9838,19 @@ flow_dv_translate_item_meta(struct rte_eth_dev *dev, mask = meta_m->data; if (key_type == MLX5_SET_MATCHER_HS_M) mask = value; - reg = flow_dv_get_metadata_reg(dev, attr, NULL); + /* + * In the current implementation, REG_B cannot be used to match. + * Force to use REG_C_1 in HWS root table as other tables. + * This map may change. + * NIC: modify - REG_B to be present in SW + * match - REG_C_1 when copied from FDB, different from SWS + * FDB: modify - REG_C_1 in Xmeta mode, REG_NON in legacy mode + * match - REG_C_1 in FDB + */ + if (!!(key_type & MLX5_SET_MATCHER_SW)) + reg = flow_dv_get_metadata_reg(dev, attr, NULL); + else + reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_META, 0); if (reg < 0) return; MLX5_ASSERT(reg != REG_NON); @@ -9919,7 +9950,10 @@ flow_dv_translate_item_tag(struct rte_eth_dev *dev, void *key, /* When set mask, the index should be from spec. */ index = tag_vv ? tag_vv->index : tag_v->index; /* Get the metadata register index for the tag. */ - reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, index, NULL); + if (!!(key_type & MLX5_SET_MATCHER_SW)) + reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, index, NULL); + else + reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_TAG, index); MLX5_ASSERT(reg > 0); flow_dv_match_meta_reg(key, reg, tag_v->data, tag_m->data); } @@ -13437,7 +13471,8 @@ flow_dv_translate_items_sws(struct rte_eth_dev *dev, */ if (!(wks.item_flags & MLX5_FLOW_ITEM_PORT_ID) && !(wks.item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) && priv->sh->esw_mode && - !(attr->egress && !attr->transfer)) { + !(attr->egress && !attr->transfer) && + attr->group != MLX5_FLOW_MREG_CP_TABLE_GROUP) { if (flow_dv_translate_item_port_id_all(dev, match_mask, match_value, NULL, attr)) return -rte_errno; diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index b3b37f36a2..64d06d4fb4 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -20,13 +20,27 @@ /* Default queue to flush the flows. */ #define MLX5_DEFAULT_FLUSH_QUEUE 0 -/* Maximum number of rules in control flow tables */ +/* Maximum number of rules in control flow tables. */ #define MLX5_HW_CTRL_FLOW_NB_RULES (4096) -/* Flow group for SQ miss default flows/ */ -#define MLX5_HW_SQ_MISS_GROUP (UINT32_MAX) +/* Lowest flow group usable by an application. */ +#define MLX5_HW_LOWEST_USABLE_GROUP (1) + +/* Maximum group index usable by user applications for transfer flows. */ +#define MLX5_HW_MAX_TRANSFER_GROUP (UINT32_MAX - 1) + +/* Lowest priority for HW root table. */ +#define MLX5_HW_LOWEST_PRIO_ROOT 15 + +/* Lowest priority for HW non-root table. */ +#define MLX5_HW_LOWEST_PRIO_NON_ROOT (UINT32_MAX) static int flow_hw_flush_all_ctrl_flows(struct rte_eth_dev *dev); +static int flow_hw_translate_group(struct rte_eth_dev *dev, + const struct mlx5_flow_template_table_cfg *cfg, + uint32_t group, + uint32_t *table_group, + struct rte_flow_error *error); const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops; @@ -213,12 +227,12 @@ flow_hw_rss_item_flags_get(const struct rte_flow_item items[]) */ static struct mlx5_hw_jump_action * flow_hw_jump_action_register(struct rte_eth_dev *dev, - const struct rte_flow_attr *attr, + const struct mlx5_flow_template_table_cfg *cfg, uint32_t dest_group, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; - struct rte_flow_attr jattr = *attr; + struct rte_flow_attr jattr = cfg->attr.flow_attr; struct mlx5_flow_group *grp; struct mlx5_flow_cb_ctx ctx = { .dev = dev, @@ -226,9 +240,13 @@ flow_hw_jump_action_register(struct rte_eth_dev *dev, .data = &jattr, }; struct mlx5_list_entry *ge; + uint32_t target_group; - jattr.group = dest_group; - ge = mlx5_hlist_register(priv->sh->flow_tbls, dest_group, &ctx); + target_group = dest_group; + if (flow_hw_translate_group(dev, cfg, dest_group, &target_group, error)) + return NULL; + jattr.group = target_group; + ge = mlx5_hlist_register(priv->sh->flow_tbls, target_group, &ctx); if (!ge) return NULL; grp = container_of(ge, struct mlx5_flow_group, entry); @@ -760,7 +778,8 @@ flow_hw_modify_field_compile(struct rte_eth_dev *dev, (void *)(uintptr_t)conf->src.pvalue : (void *)(uintptr_t)&conf->src.value; if (conf->dst.field == RTE_FLOW_FIELD_META || - conf->dst.field == RTE_FLOW_FIELD_TAG) { + conf->dst.field == RTE_FLOW_FIELD_TAG || + conf->dst.field == (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG) { value = *(const unaligned_uint32_t *)item.spec; value = rte_cpu_to_be_32(value); item.spec = &value; @@ -860,6 +879,9 @@ flow_hw_represented_port_compile(struct rte_eth_dev *dev, if (m && !!m->port_id) { struct mlx5_priv *port_priv; + if (!v) + return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, + action, "port index was not provided"); port_priv = mlx5_port_to_eswitch_info(v->port_id, false); if (port_priv == NULL) return rte_flow_error_set @@ -903,8 +925,8 @@ flow_hw_represented_port_compile(struct rte_eth_dev *dev, * * @param[in] dev * Pointer to the rte_eth_dev structure. - * @param[in] table_attr - * Pointer to the table attributes. + * @param[in] cfg + * Pointer to the table configuration. * @param[in] item_templates * Item template array to be binded to the table. * @param[in/out] acts @@ -919,12 +941,13 @@ flow_hw_represented_port_compile(struct rte_eth_dev *dev, */ static int flow_hw_actions_translate(struct rte_eth_dev *dev, - const struct rte_flow_template_table_attr *table_attr, + const struct mlx5_flow_template_table_cfg *cfg, struct mlx5_hw_actions *acts, struct rte_flow_actions_template *at, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; + const struct rte_flow_template_table_attr *table_attr = &cfg->attr; const struct rte_flow_attr *attr = &table_attr->flow_attr; struct rte_flow_action *actions = at->actions; struct rte_flow_action *action_start = actions; @@ -991,7 +1014,7 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, ((const struct rte_flow_action_jump *) actions->conf)->group; acts->jump = flow_hw_jump_action_register - (dev, attr, jump_group, error); + (dev, cfg, jump_group, error); if (!acts->jump) goto err; acts->rule_acts[i].action = (!!attr->group) ? @@ -1101,6 +1124,16 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, error); if (err) goto err; + /* + * Adjust the action source position for the following. + * ... / MODIFY_FIELD: rx_cpy_pos / (QUEUE|RSS) / ... + * The next action will be Q/RSS, there will not be + * another adjustment and the real source position of + * the following actions will be decreased by 1. + * No change of the total actions in the new template. + */ + if ((actions - action_start) == at->rx_cpy_pos) + action_start += 1; break; case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: if (flow_hw_represented_port_compile @@ -1365,7 +1398,8 @@ flow_hw_modify_field_construct(struct mlx5_hw_q_job *job, else rte_memcpy(values, mhdr_action->src.pvalue, sizeof(values)); if (mhdr_action->dst.field == RTE_FLOW_FIELD_META || - mhdr_action->dst.field == RTE_FLOW_FIELD_TAG) { + mhdr_action->dst.field == RTE_FLOW_FIELD_TAG || + mhdr_action->dst.field == (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG) { value_p = (unaligned_uint32_t *)values; *value_p = rte_cpu_to_be_32(*value_p); } else if (mhdr_action->dst.field == RTE_FLOW_FIELD_GTP_PSC_QFI) { @@ -1513,7 +1547,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, jump_group = ((const struct rte_flow_action_jump *) action->conf)->group; jump = flow_hw_jump_action_register - (dev, &attr, jump_group, NULL); + (dev, &table->cfg, jump_group, NULL); if (!jump) return -1; rule_acts[act_data->action_dst].action = @@ -1710,7 +1744,13 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev, job->user_data = user_data; rule_attr.user_data = job; hw_acts = &table->ats[action_template_index].acts; - /* Construct the flow actions based on the input actions.*/ + /* + * Construct the flow actions based on the input actions. + * The implicitly appended action is always fixed, like metadata + * copy action from FDB to NIC Rx. + * No need to copy and contrust a new "actions" list based on the + * user's input, in order to save the cost. + */ if (flow_hw_actions_construct(dev, job, hw_acts, pattern_template_index, actions, rule_acts, &acts_num)) { rte_errno = EINVAL; @@ -1981,6 +2021,8 @@ flow_hw_q_flow_flush(struct rte_eth_dev *dev, /* Flush flow per-table from MLX5_DEFAULT_FLUSH_QUEUE. */ hw_q = &priv->hw_q[MLX5_DEFAULT_FLUSH_QUEUE]; LIST_FOREACH(tbl, &priv->flow_hw_tbl, next) { + if (!tbl->cfg.external) + continue; MLX5_IPOOL_FOREACH(tbl->flow, fidx, flow) { if (flow_hw_async_flow_destroy(dev, MLX5_DEFAULT_FLUSH_QUEUE, @@ -2018,8 +2060,8 @@ flow_hw_q_flow_flush(struct rte_eth_dev *dev, * * @param[in] dev * Pointer to the rte_eth_dev structure. - * @param[in] attr - * Pointer to the table attributes. + * @param[in] table_cfg + * Pointer to the table configuration. * @param[in] item_templates * Item template array to be binded to the table. * @param[in] nb_item_templates @@ -2036,7 +2078,7 @@ flow_hw_q_flow_flush(struct rte_eth_dev *dev, */ static struct rte_flow_template_table * flow_hw_table_create(struct rte_eth_dev *dev, - const struct rte_flow_template_table_attr *attr, + const struct mlx5_flow_template_table_cfg *table_cfg, struct rte_flow_pattern_template *item_templates[], uint8_t nb_item_templates, struct rte_flow_actions_template *action_templates[], @@ -2048,6 +2090,7 @@ flow_hw_table_create(struct rte_eth_dev *dev, struct rte_flow_template_table *tbl = NULL; struct mlx5_flow_group *grp; struct mlx5dr_match_template *mt[MLX5_HW_TBL_MAX_ITEM_TEMPLATE]; + const struct rte_flow_template_table_attr *attr = &table_cfg->attr; struct rte_flow_attr flow_attr = attr->flow_attr; struct mlx5_flow_cb_ctx ctx = { .dev = dev, @@ -2088,6 +2131,7 @@ flow_hw_table_create(struct rte_eth_dev *dev, tbl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*tbl), 0, rte_socket_id()); if (!tbl) goto error; + tbl->cfg = *table_cfg; /* Allocate flow indexed pool. */ tbl->flow = mlx5_ipool_create(&cfg); if (!tbl->flow) @@ -2131,7 +2175,7 @@ flow_hw_table_create(struct rte_eth_dev *dev, goto at_error; } LIST_INIT(&tbl->ats[i].acts.act_list); - err = flow_hw_actions_translate(dev, attr, + err = flow_hw_actions_translate(dev, &tbl->cfg, &tbl->ats[i].acts, action_templates[i], error); if (err) { @@ -2174,6 +2218,96 @@ flow_hw_table_create(struct rte_eth_dev *dev, return NULL; } +/** + * Translates group index specified by the user in @p attr to internal + * group index. + * + * Translation is done by incrementing group index, so group n becomes n + 1. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] cfg + * Pointer to the template table configuration. + * @param[in] group + * Currently used group index (table group or jump destination). + * @param[out] table_group + * Pointer to output group index. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success. Otherwise, returns negative error code, rte_errno is set + * and error structure is filled. + */ +static int +flow_hw_translate_group(struct rte_eth_dev *dev, + const struct mlx5_flow_template_table_cfg *cfg, + uint32_t group, + uint32_t *table_group, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + const struct rte_flow_attr *flow_attr = &cfg->attr.flow_attr; + + if (priv->sh->config.dv_esw_en && cfg->external && flow_attr->transfer) { + if (group > MLX5_HW_MAX_TRANSFER_GROUP) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR_GROUP, + NULL, + "group index not supported"); + *table_group = group + 1; + } else { + *table_group = group; + } + return 0; +} + +/** + * Create flow table. + * + * This function is a wrapper over @ref flow_hw_table_create(), which translates parameters + * provided by user to proper internal values. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] attr + * Pointer to the table attributes. + * @param[in] item_templates + * Item template array to be binded to the table. + * @param[in] nb_item_templates + * Number of item templates. + * @param[in] action_templates + * Action template array to be binded to the table. + * @param[in] nb_action_templates + * Number of action templates. + * @param[out] error + * Pointer to error structure. + * + * @return + * Table on success, Otherwise, returns negative error code, rte_errno is set + * and error structure is filled. + */ +static struct rte_flow_template_table * +flow_hw_template_table_create(struct rte_eth_dev *dev, + const struct rte_flow_template_table_attr *attr, + struct rte_flow_pattern_template *item_templates[], + uint8_t nb_item_templates, + struct rte_flow_actions_template *action_templates[], + uint8_t nb_action_templates, + struct rte_flow_error *error) +{ + struct mlx5_flow_template_table_cfg cfg = { + .attr = *attr, + .external = true, + }; + uint32_t group = attr->flow_attr.group; + + if (flow_hw_translate_group(dev, &cfg, group, &cfg.attr.flow_attr.group, error)) + return NULL; + return flow_hw_table_create(dev, &cfg, item_templates, nb_item_templates, + action_templates, nb_action_templates, error); +} + /** * Destroy flow table. * @@ -2309,10 +2443,13 @@ flow_hw_validate_action_represented_port(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "cannot use represented_port actions" " without an E-Switch"); - if (mask_conf->port_id) { + if (mask_conf && mask_conf->port_id) { struct mlx5_priv *port_priv; struct mlx5_priv *dev_priv; + if (!action_conf) + return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, + action, "port index was not provided"); port_priv = mlx5_port_to_eswitch_info(action_conf->port_id, false); if (!port_priv) return rte_flow_error_set(error, rte_errno, @@ -2337,20 +2474,77 @@ flow_hw_validate_action_represented_port(struct rte_eth_dev *dev, return 0; } +static inline int +flow_hw_action_meta_copy_insert(const struct rte_flow_action actions[], + const struct rte_flow_action masks[], + const struct rte_flow_action *ins_actions, + const struct rte_flow_action *ins_masks, + struct rte_flow_action *new_actions, + struct rte_flow_action *new_masks, + uint16_t *ins_pos) +{ + uint16_t idx, total = 0; + bool ins = false; + bool act_end = false; + + MLX5_ASSERT(actions && masks); + MLX5_ASSERT(new_actions && new_masks); + MLX5_ASSERT(ins_actions && ins_masks); + for (idx = 0; !act_end; idx++) { + if (idx >= MLX5_HW_MAX_ACTS) + return -1; + if (actions[idx].type == RTE_FLOW_ACTION_TYPE_RSS || + actions[idx].type == RTE_FLOW_ACTION_TYPE_QUEUE) { + ins = true; + *ins_pos = idx; + } + if (actions[idx].type == RTE_FLOW_ACTION_TYPE_END) + act_end = true; + } + if (!ins) + return 0; + else if (idx == MLX5_HW_MAX_ACTS) + return -1; /* No more space. */ + total = idx; + /* Before the position, no change for the actions. */ + for (idx = 0; idx < *ins_pos; idx++) { + new_actions[idx] = actions[idx]; + new_masks[idx] = masks[idx]; + } + /* Insert the new action and mask to the position. */ + new_actions[idx] = *ins_actions; + new_masks[idx] = *ins_masks; + /* Remaining content is right shifted by one position. */ + for (; idx < total; idx++) { + new_actions[idx + 1] = actions[idx]; + new_masks[idx + 1] = masks[idx]; + } + return 0; +} + static int flow_hw_action_validate(struct rte_eth_dev *dev, + const struct rte_flow_actions_template_attr *attr, const struct rte_flow_action actions[], const struct rte_flow_action masks[], struct rte_flow_error *error) { - int i; + struct mlx5_priv *priv = dev->data->dev_private; + uint16_t i; bool actions_end = false; int ret; + /* FDB actions are only valid to proxy port. */ + if (attr->transfer && (!priv->sh->config.dv_esw_en || !priv->master)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "transfer actions are only valid to proxy port"); for (i = 0; !actions_end; ++i) { const struct rte_flow_action *action = &actions[i]; const struct rte_flow_action *mask = &masks[i]; + MLX5_ASSERT(i < MLX5_HW_MAX_ACTS); if (action->type != mask->type) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, @@ -2447,21 +2641,77 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, { struct mlx5_priv *priv = dev->data->dev_private; int len, act_len, mask_len, i; - struct rte_flow_actions_template *at; + struct rte_flow_actions_template *at = NULL; + uint16_t pos = MLX5_HW_MAX_ACTS; + struct rte_flow_action tmp_action[MLX5_HW_MAX_ACTS]; + struct rte_flow_action tmp_mask[MLX5_HW_MAX_ACTS]; + const struct rte_flow_action *ra; + const struct rte_flow_action *rm; + const struct rte_flow_action_modify_field rx_mreg = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_B, + }, + .src = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_C_1, + }, + .width = 32, + }; + const struct rte_flow_action_modify_field rx_mreg_mask = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = UINT32_MAX, + .offset = UINT32_MAX, + }, + .src = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = UINT32_MAX, + .offset = UINT32_MAX, + }, + .width = UINT32_MAX, + }; + const struct rte_flow_action rx_cpy = { + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + .conf = &rx_mreg, + }; + const struct rte_flow_action rx_cpy_mask = { + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + .conf = &rx_mreg_mask, + }; - if (flow_hw_action_validate(dev, actions, masks, error)) + if (flow_hw_action_validate(dev, attr, actions, masks, error)) return NULL; - act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, - NULL, 0, actions, error); + if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS && + priv->sh->config.dv_esw_en) { + if (flow_hw_action_meta_copy_insert(actions, masks, &rx_cpy, &rx_cpy_mask, + tmp_action, tmp_mask, &pos)) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "Failed to concatenate new action/mask"); + return NULL; + } + } + /* Application should make sure only one Q/RSS exist in one rule. */ + if (pos == MLX5_HW_MAX_ACTS) { + ra = actions; + rm = masks; + } else { + ra = tmp_action; + rm = tmp_mask; + } + act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, NULL, 0, ra, error); if (act_len <= 0) return NULL; len = RTE_ALIGN(act_len, 16); - mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, - NULL, 0, masks, error); + mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, NULL, 0, rm, error); if (mask_len <= 0) return NULL; len += RTE_ALIGN(mask_len, 16); - at = mlx5_malloc(MLX5_MEM_ZERO, len + sizeof(*at), 64, rte_socket_id()); + at = mlx5_malloc(MLX5_MEM_ZERO, len + sizeof(*at), + RTE_CACHE_LINE_SIZE, rte_socket_id()); if (!at) { rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@ -2469,18 +2719,20 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, "cannot allocate action template"); return NULL; } + /* Actions part is in the first half. */ at->attr = *attr; at->actions = (struct rte_flow_action *)(at + 1); - act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->actions, len, - actions, error); + act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->actions, + len, ra, error); if (act_len <= 0) goto error; - at->masks = (struct rte_flow_action *) - (((uint8_t *)at->actions) + act_len); + /* Masks part is in the second half. */ + at->masks = (struct rte_flow_action *)(((uint8_t *)at->actions) + act_len); mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->masks, - len - act_len, masks, error); + len - act_len, rm, error); if (mask_len <= 0) goto error; + at->rx_cpy_pos = pos; /* * mlx5 PMD hacks indirect action index directly to the action conf. * The rte_flow_conv() function copies the content from conf pointer. @@ -2497,7 +2749,8 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, LIST_INSERT_HEAD(&priv->flow_hw_at, at, next); return at; error: - mlx5_free(at); + if (at) + mlx5_free(at); return NULL; } @@ -2572,6 +2825,80 @@ flow_hw_copy_prepend_port_item(const struct rte_flow_item *items, return copied_items; } +static int +flow_hw_pattern_validate(struct rte_eth_dev *dev, + const struct rte_flow_pattern_template_attr *attr, + const struct rte_flow_item items[], + struct rte_flow_error *error) +{ + int i; + bool items_end = false; + RTE_SET_USED(dev); + RTE_SET_USED(attr); + + for (i = 0; !items_end; i++) { + int type = items[i].type; + + switch (type) { + case RTE_FLOW_ITEM_TYPE_TAG: + { + int reg; + const struct rte_flow_item_tag *tag = + (const struct rte_flow_item_tag *)items[i].spec; + + reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_TAG, tag->index); + if (reg == REG_NON) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Unsupported tag index"); + break; + } + case MLX5_RTE_FLOW_ITEM_TYPE_TAG: + { + const struct rte_flow_item_tag *tag = + (const struct rte_flow_item_tag *)items[i].spec; + struct mlx5_priv *priv = dev->data->dev_private; + uint8_t regcs = (uint8_t)priv->sh->cdev->config.hca_attr.set_reg_c; + + if (!((1 << (tag->index - REG_C_0)) & regcs)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Unsupported internal tag index"); + } + case RTE_FLOW_ITEM_TYPE_VOID: + case RTE_FLOW_ITEM_TYPE_ETH: + case RTE_FLOW_ITEM_TYPE_VLAN: + case RTE_FLOW_ITEM_TYPE_IPV4: + case RTE_FLOW_ITEM_TYPE_IPV6: + case RTE_FLOW_ITEM_TYPE_UDP: + case RTE_FLOW_ITEM_TYPE_TCP: + case RTE_FLOW_ITEM_TYPE_GTP: + case RTE_FLOW_ITEM_TYPE_GTP_PSC: + case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT: + case RTE_FLOW_ITEM_TYPE_VXLAN: + case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: + case RTE_FLOW_ITEM_TYPE_META: + case RTE_FLOW_ITEM_TYPE_GRE: + case RTE_FLOW_ITEM_TYPE_GRE_KEY: + case RTE_FLOW_ITEM_TYPE_GRE_OPTION: + case RTE_FLOW_ITEM_TYPE_ICMP: + case RTE_FLOW_ITEM_TYPE_ICMP6: + break; + case RTE_FLOW_ITEM_TYPE_END: + items_end = true; + break; + default: + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Unsupported item type"); + } + } + return 0; +} + /** * Create flow item template. * @@ -2598,6 +2925,8 @@ flow_hw_pattern_template_create(struct rte_eth_dev *dev, struct rte_flow_item *copied_items = NULL; const struct rte_flow_item *tmpl_items; + if (flow_hw_pattern_validate(dev, attr, items, error)) + return NULL; if (priv->sh->config.dv_esw_en && attr->ingress) { /* * Disallow pattern template with ingress and egress/transfer @@ -3032,6 +3361,17 @@ flow_hw_free_vport_actions(struct mlx5_priv *priv) priv->hw_vport = NULL; } +static uint32_t +flow_hw_usable_lsb_vport_mask(struct mlx5_priv *priv) +{ + uint32_t usable_mask = ~priv->vport_meta_mask; + + if (usable_mask) + return (1 << rte_bsf32(usable_mask)); + else + return 0; +} + /** * Creates a flow pattern template used to match on E-Switch Manager. * This template is used to set up a table for SQ miss default flow. @@ -3070,7 +3410,10 @@ flow_hw_create_ctrl_esw_mgr_pattern_template(struct rte_eth_dev *dev) } /** - * Creates a flow pattern template used to match on a TX queue. + * Creates a flow pattern template used to match REG_C_0 and a TX queue. + * Matching on REG_C_0 is set up to match on least significant bit usable + * by user-space, which is set when packet was originated from E-Switch Manager. + * * This template is used to set up a table for SQ miss default flow. * * @param dev @@ -3080,16 +3423,30 @@ flow_hw_create_ctrl_esw_mgr_pattern_template(struct rte_eth_dev *dev) * Pointer to flow pattern template on success, NULL otherwise. */ static struct rte_flow_pattern_template * -flow_hw_create_ctrl_sq_pattern_template(struct rte_eth_dev *dev) +flow_hw_create_ctrl_regc_sq_pattern_template(struct rte_eth_dev *dev) { + struct mlx5_priv *priv = dev->data->dev_private; + uint32_t marker_bit = flow_hw_usable_lsb_vport_mask(priv); struct rte_flow_pattern_template_attr attr = { .relaxed_matching = 0, .transfer = 1, }; + struct rte_flow_item_tag reg_c0_spec = { + .index = (uint8_t)REG_C_0, + }; + struct rte_flow_item_tag reg_c0_mask = { + .index = 0xff, + }; struct mlx5_rte_flow_item_tx_queue queue_mask = { .queue = UINT32_MAX, }; struct rte_flow_item items[] = { + { + .type = (enum rte_flow_item_type) + MLX5_RTE_FLOW_ITEM_TYPE_TAG, + .spec = ®_c0_spec, + .mask = ®_c0_mask, + }, { .type = (enum rte_flow_item_type) MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE, @@ -3100,6 +3457,12 @@ flow_hw_create_ctrl_sq_pattern_template(struct rte_eth_dev *dev) }, }; + if (!marker_bit) { + DRV_LOG(ERR, "Unable to set up pattern template for SQ miss table"); + return NULL; + } + reg_c0_spec.data = marker_bit; + reg_c0_mask.data = marker_bit; return flow_hw_pattern_template_create(dev, &attr, items, NULL); } @@ -3137,6 +3500,132 @@ flow_hw_create_ctrl_port_pattern_template(struct rte_eth_dev *dev) return flow_hw_pattern_template_create(dev, &attr, items, NULL); } +/* + * Creating a flow pattern template with all ETH packets matching. + * This template is used to set up a table for default Tx copy (Tx metadata + * to REG_C_1) flow rule usage. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * Pointer to flow pattern template on success, NULL otherwise. + */ +static struct rte_flow_pattern_template * +flow_hw_create_tx_default_mreg_copy_pattern_template(struct rte_eth_dev *dev) +{ + struct rte_flow_pattern_template_attr tx_pa_attr = { + .relaxed_matching = 0, + .egress = 1, + }; + struct rte_flow_item_eth promisc = { + .dst.addr_bytes = "\x00\x00\x00\x00\x00\x00", + .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", + .type = 0, + }; + struct rte_flow_item eth_all[] = { + [0] = { + .type = RTE_FLOW_ITEM_TYPE_ETH, + .spec = &promisc, + .mask = &promisc, + }, + [1] = { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + struct rte_flow_error drop_err; + + RTE_SET_USED(drop_err); + return flow_hw_pattern_template_create(dev, &tx_pa_attr, eth_all, &drop_err); +} + +/** + * Creates a flow actions template with modify field action and masked jump action. + * Modify field action sets the least significant bit of REG_C_0 (usable by user-space) + * to 1, meaning that packet was originated from E-Switch Manager. Jump action + * transfers steering to group 1. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * Pointer to flow actions template on success, NULL otherwise. + */ +static struct rte_flow_actions_template * +flow_hw_create_ctrl_regc_jump_actions_template(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + uint32_t marker_bit = flow_hw_usable_lsb_vport_mask(priv); + uint32_t marker_bit_mask = UINT32_MAX; + struct rte_flow_actions_template_attr attr = { + .transfer = 1, + }; + struct rte_flow_action_modify_field set_reg_v = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_C_0, + }, + .src = { + .field = RTE_FLOW_FIELD_VALUE, + }, + .width = 1, + }; + struct rte_flow_action_modify_field set_reg_m = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = UINT32_MAX, + .offset = UINT32_MAX, + }, + .src = { + .field = RTE_FLOW_FIELD_VALUE, + }, + .width = UINT32_MAX, + }; + struct rte_flow_action_jump jump_v = { + .group = MLX5_HW_LOWEST_USABLE_GROUP, + }; + struct rte_flow_action_jump jump_m = { + .group = UINT32_MAX, + }; + struct rte_flow_action actions_v[] = { + { + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + .conf = &set_reg_v, + }, + { + .type = RTE_FLOW_ACTION_TYPE_JUMP, + .conf = &jump_v, + }, + { + .type = RTE_FLOW_ACTION_TYPE_END, + } + }; + struct rte_flow_action actions_m[] = { + { + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + .conf = &set_reg_m, + }, + { + .type = RTE_FLOW_ACTION_TYPE_JUMP, + .conf = &jump_m, + }, + { + .type = RTE_FLOW_ACTION_TYPE_END, + } + }; + + if (!marker_bit) { + DRV_LOG(ERR, "Unable to set up actions template for SQ miss table"); + return NULL; + } + set_reg_v.dst.offset = rte_bsf32(marker_bit); + rte_memcpy(set_reg_v.src.value, &marker_bit, sizeof(marker_bit)); + rte_memcpy(set_reg_m.src.value, &marker_bit_mask, sizeof(marker_bit_mask)); + return flow_hw_actions_template_create(dev, &attr, actions_v, actions_m, NULL); +} + /** * Creates a flow actions template with an unmasked JUMP action. Flows * based on this template will perform a jump to some group. This template @@ -3231,6 +3720,73 @@ flow_hw_create_ctrl_port_actions_template(struct rte_eth_dev *dev) NULL); } +/* + * Creating an actions template to use header modify action for register + * copying. This template is used to set up a table for copy flow. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * Pointer to flow actions template on success, NULL otherwise. + */ +static struct rte_flow_actions_template * +flow_hw_create_tx_default_mreg_copy_actions_template(struct rte_eth_dev *dev) +{ + struct rte_flow_actions_template_attr tx_act_attr = { + .egress = 1, + }; + const struct rte_flow_action_modify_field mreg_action = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_C_1, + }, + .src = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_A, + }, + .width = 32, + }; + const struct rte_flow_action_modify_field mreg_mask = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = UINT32_MAX, + .offset = UINT32_MAX, + }, + .src = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = UINT32_MAX, + .offset = UINT32_MAX, + }, + .width = UINT32_MAX, + }; + const struct rte_flow_action copy_reg_action[] = { + [0] = { + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + .conf = &mreg_action, + }, + [1] = { + .type = RTE_FLOW_ACTION_TYPE_END, + }, + }; + const struct rte_flow_action copy_reg_mask[] = { + [0] = { + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + .conf = &mreg_mask, + }, + [1] = { + .type = RTE_FLOW_ACTION_TYPE_END, + }, + }; + struct rte_flow_error drop_err; + + RTE_SET_USED(drop_err); + return flow_hw_actions_template_create(dev, &tx_act_attr, copy_reg_action, + copy_reg_mask, &drop_err); +} + /** * Creates a control flow table used to transfer traffic from E-Switch Manager * and TX queues from group 0 to group 1. @@ -3260,8 +3816,12 @@ flow_hw_create_ctrl_sq_miss_root_table(struct rte_eth_dev *dev, }, .nb_flows = MLX5_HW_CTRL_FLOW_NB_RULES, }; + struct mlx5_flow_template_table_cfg cfg = { + .attr = attr, + .external = false, + }; - return flow_hw_table_create(dev, &attr, &it, 1, &at, 1, NULL); + return flow_hw_table_create(dev, &cfg, &it, 1, &at, 1, NULL); } @@ -3286,16 +3846,56 @@ flow_hw_create_ctrl_sq_miss_table(struct rte_eth_dev *dev, { struct rte_flow_template_table_attr attr = { .flow_attr = { - .group = MLX5_HW_SQ_MISS_GROUP, - .priority = 0, + .group = 1, + .priority = MLX5_HW_LOWEST_PRIO_NON_ROOT, .ingress = 0, .egress = 0, .transfer = 1, }, .nb_flows = MLX5_HW_CTRL_FLOW_NB_RULES, }; + struct mlx5_flow_template_table_cfg cfg = { + .attr = attr, + .external = false, + }; + + return flow_hw_table_create(dev, &cfg, &it, 1, &at, 1, NULL); +} + +/* + * Creating the default Tx metadata copy table on NIC Tx group 0. + * + * @param dev + * Pointer to Ethernet device. + * @param pt + * Pointer to flow pattern template. + * @param at + * Pointer to flow actions template. + * + * @return + * Pointer to flow table on success, NULL otherwise. + */ +static struct rte_flow_template_table* +flow_hw_create_tx_default_mreg_copy_table(struct rte_eth_dev *dev, + struct rte_flow_pattern_template *pt, + struct rte_flow_actions_template *at) +{ + struct rte_flow_template_table_attr tx_tbl_attr = { + .flow_attr = { + .group = 0, /* Root */ + .priority = MLX5_HW_LOWEST_PRIO_ROOT, + .egress = 1, + }, + .nb_flows = 1, /* One default flow rule for all. */ + }; + struct mlx5_flow_template_table_cfg tx_tbl_cfg = { + .attr = tx_tbl_attr, + .external = false, + }; + struct rte_flow_error drop_err; - return flow_hw_table_create(dev, &attr, &it, 1, &at, 1, NULL); + RTE_SET_USED(drop_err); + return flow_hw_table_create(dev, &tx_tbl_cfg, &pt, 1, &at, 1, &drop_err); } /** @@ -3320,15 +3920,19 @@ flow_hw_create_ctrl_jump_table(struct rte_eth_dev *dev, struct rte_flow_template_table_attr attr = { .flow_attr = { .group = 0, - .priority = 15, /* TODO: Flow priority discovery. */ + .priority = MLX5_HW_LOWEST_PRIO_ROOT, .ingress = 0, .egress = 0, .transfer = 1, }, .nb_flows = MLX5_HW_CTRL_FLOW_NB_RULES, }; + struct mlx5_flow_template_table_cfg cfg = { + .attr = attr, + .external = false, + }; - return flow_hw_table_create(dev, &attr, &it, 1, &at, 1, NULL); + return flow_hw_table_create(dev, &cfg, &it, 1, &at, 1, NULL); } /** @@ -3346,11 +3950,14 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) { struct mlx5_priv *priv = dev->data->dev_private; struct rte_flow_pattern_template *esw_mgr_items_tmpl = NULL; - struct rte_flow_pattern_template *sq_items_tmpl = NULL; + struct rte_flow_pattern_template *regc_sq_items_tmpl = NULL; struct rte_flow_pattern_template *port_items_tmpl = NULL; - struct rte_flow_actions_template *jump_sq_actions_tmpl = NULL; + struct rte_flow_pattern_template *tx_meta_items_tmpl = NULL; + struct rte_flow_actions_template *regc_jump_actions_tmpl = NULL; struct rte_flow_actions_template *port_actions_tmpl = NULL; struct rte_flow_actions_template *jump_one_actions_tmpl = NULL; + struct rte_flow_actions_template *tx_meta_actions_tmpl = NULL; + uint32_t xmeta = priv->sh->config.dv_xmeta_en; /* Item templates */ esw_mgr_items_tmpl = flow_hw_create_ctrl_esw_mgr_pattern_template(dev); @@ -3359,8 +3966,8 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) " template for control flows", dev->data->port_id); goto error; } - sq_items_tmpl = flow_hw_create_ctrl_sq_pattern_template(dev); - if (!sq_items_tmpl) { + regc_sq_items_tmpl = flow_hw_create_ctrl_regc_sq_pattern_template(dev); + if (!regc_sq_items_tmpl) { DRV_LOG(ERR, "port %u failed to create SQ item template for" " control flows", dev->data->port_id); goto error; @@ -3371,11 +3978,18 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) " control flows", dev->data->port_id); goto error; } + if (xmeta == MLX5_XMETA_MODE_META32_HWS) { + tx_meta_items_tmpl = flow_hw_create_tx_default_mreg_copy_pattern_template(dev); + if (!tx_meta_items_tmpl) { + DRV_LOG(ERR, "port %u failed to Tx metadata copy pattern" + " template for control flows", dev->data->port_id); + goto error; + } + } /* Action templates */ - jump_sq_actions_tmpl = flow_hw_create_ctrl_jump_actions_template(dev, - MLX5_HW_SQ_MISS_GROUP); - if (!jump_sq_actions_tmpl) { - DRV_LOG(ERR, "port %u failed to create jump action template" + regc_jump_actions_tmpl = flow_hw_create_ctrl_regc_jump_actions_template(dev); + if (!regc_jump_actions_tmpl) { + DRV_LOG(ERR, "port %u failed to create REG_C set and jump action template" " for control flows", dev->data->port_id); goto error; } @@ -3385,23 +3999,32 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) " for control flows", dev->data->port_id); goto error; } - jump_one_actions_tmpl = flow_hw_create_ctrl_jump_actions_template(dev, 1); + jump_one_actions_tmpl = flow_hw_create_ctrl_jump_actions_template + (dev, MLX5_HW_LOWEST_USABLE_GROUP); if (!jump_one_actions_tmpl) { DRV_LOG(ERR, "port %u failed to create jump action template" " for control flows", dev->data->port_id); goto error; } + if (xmeta == MLX5_XMETA_MODE_META32_HWS) { + tx_meta_actions_tmpl = flow_hw_create_tx_default_mreg_copy_actions_template(dev); + if (!tx_meta_actions_tmpl) { + DRV_LOG(ERR, "port %u failed to Tx metadata copy actions" + " template for control flows", dev->data->port_id); + goto error; + } + } /* Tables */ MLX5_ASSERT(priv->hw_esw_sq_miss_root_tbl == NULL); priv->hw_esw_sq_miss_root_tbl = flow_hw_create_ctrl_sq_miss_root_table - (dev, esw_mgr_items_tmpl, jump_sq_actions_tmpl); + (dev, esw_mgr_items_tmpl, regc_jump_actions_tmpl); if (!priv->hw_esw_sq_miss_root_tbl) { DRV_LOG(ERR, "port %u failed to create table for default sq miss (root table)" " for control flows", dev->data->port_id); goto error; } MLX5_ASSERT(priv->hw_esw_sq_miss_tbl == NULL); - priv->hw_esw_sq_miss_tbl = flow_hw_create_ctrl_sq_miss_table(dev, sq_items_tmpl, + priv->hw_esw_sq_miss_tbl = flow_hw_create_ctrl_sq_miss_table(dev, regc_sq_items_tmpl, port_actions_tmpl); if (!priv->hw_esw_sq_miss_tbl) { DRV_LOG(ERR, "port %u failed to create table for default sq miss (non-root table)" @@ -3416,6 +4039,16 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) " for control flows", dev->data->port_id); goto error; } + if (xmeta == MLX5_XMETA_MODE_META32_HWS) { + MLX5_ASSERT(priv->hw_tx_meta_cpy_tbl == NULL); + priv->hw_tx_meta_cpy_tbl = flow_hw_create_tx_default_mreg_copy_table(dev, + tx_meta_items_tmpl, tx_meta_actions_tmpl); + if (!priv->hw_tx_meta_cpy_tbl) { + DRV_LOG(ERR, "port %u failed to create table for default" + " Tx metadata copy flow rule", dev->data->port_id); + goto error; + } + } return 0; error: if (priv->hw_esw_zero_tbl) { @@ -3430,16 +4063,20 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) flow_hw_table_destroy(dev, priv->hw_esw_sq_miss_root_tbl, NULL); priv->hw_esw_sq_miss_root_tbl = NULL; } + if (xmeta == MLX5_XMETA_MODE_META32_HWS && tx_meta_actions_tmpl) + flow_hw_actions_template_destroy(dev, tx_meta_actions_tmpl, NULL); if (jump_one_actions_tmpl) flow_hw_actions_template_destroy(dev, jump_one_actions_tmpl, NULL); if (port_actions_tmpl) flow_hw_actions_template_destroy(dev, port_actions_tmpl, NULL); - if (jump_sq_actions_tmpl) - flow_hw_actions_template_destroy(dev, jump_sq_actions_tmpl, NULL); + if (regc_jump_actions_tmpl) + flow_hw_actions_template_destroy(dev, regc_jump_actions_tmpl, NULL); + if (xmeta == MLX5_XMETA_MODE_META32_HWS && tx_meta_items_tmpl) + flow_hw_pattern_template_destroy(dev, tx_meta_items_tmpl, NULL); if (port_items_tmpl) flow_hw_pattern_template_destroy(dev, port_items_tmpl, NULL); - if (sq_items_tmpl) - flow_hw_pattern_template_destroy(dev, sq_items_tmpl, NULL); + if (regc_sq_items_tmpl) + flow_hw_pattern_template_destroy(dev, regc_sq_items_tmpl, NULL); if (esw_mgr_items_tmpl) flow_hw_pattern_template_destroy(dev, esw_mgr_items_tmpl, NULL); return -EINVAL; @@ -3491,7 +4128,7 @@ flow_hw_configure(struct rte_eth_dev *dev, struct rte_flow_queue_attr **_queue_attr = NULL; struct rte_flow_queue_attr ctrl_queue_attr = {0}; bool is_proxy = !!(priv->sh->config.dv_esw_en && priv->master); - int ret; + int ret = 0; if (!port_attr || !nb_queue || !queue_attr) { rte_errno = EINVAL; @@ -3642,6 +4279,9 @@ flow_hw_configure(struct rte_eth_dev *dev, } if (_queue_attr) mlx5_free(_queue_attr); + /* Do not overwrite the internal errno information. */ + if (ret) + return ret; return rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "fail to configure port"); @@ -3751,17 +4391,17 @@ void flow_hw_init_tags_set(struct rte_eth_dev *dev) return; unset |= 1 << (priv->mtr_color_reg - REG_C_0); unset |= 1 << (REG_C_6 - REG_C_0); - if (meta_mode == MLX5_XMETA_MODE_META32_HWS) { - unset |= 1 << (REG_C_1 - REG_C_0); + if (priv->sh->config.dv_esw_en) unset |= 1 << (REG_C_0 - REG_C_0); - } + if (meta_mode == MLX5_XMETA_MODE_META32_HWS) + unset |= 1 << (REG_C_1 - REG_C_0); masks &= ~unset; if (mlx5_flow_hw_avl_tags_init_cnt) { for (i = 0; i < MLX5_FLOW_HW_TAGS_MAX; i++) { if (mlx5_flow_hw_avl_tags[i] != REG_NON && !!((1 << i) & masks)) { copy[mlx5_flow_hw_avl_tags[i] - REG_C_0] = mlx5_flow_hw_avl_tags[i]; - copy_masks |= (1 << i); + copy_masks |= (1 << (mlx5_flow_hw_avl_tags[i] - REG_C_0)); } } if (copy_masks != masks) { @@ -3903,7 +4543,6 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, return flow_dv_action_destroy(dev, handle, error); } - const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .info_get = flow_hw_info_get, .configure = flow_hw_configure, @@ -3911,7 +4550,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .pattern_template_destroy = flow_hw_pattern_template_destroy, .actions_template_create = flow_hw_actions_template_create, .actions_template_destroy = flow_hw_actions_template_destroy, - .template_table_create = flow_hw_table_create, + .template_table_create = flow_hw_template_table_create, .template_table_destroy = flow_hw_table_destroy, .async_flow_create = flow_hw_async_flow_create, .async_flow_destroy = flow_hw_async_flow_destroy, @@ -3927,13 +4566,6 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .action_query = flow_dv_action_query, }; -static uint32_t -flow_hw_get_ctrl_queue(struct mlx5_priv *priv) -{ - MLX5_ASSERT(priv->nb_queue > 0); - return priv->nb_queue - 1; -} - /** * Creates a control flow using flow template API on @p proxy_dev device, * on behalf of @p owner_dev device. @@ -3971,7 +4603,7 @@ flow_hw_create_ctrl_flow(struct rte_eth_dev *owner_dev, uint8_t action_template_idx) { struct mlx5_priv *priv = proxy_dev->data->dev_private; - uint32_t queue = flow_hw_get_ctrl_queue(priv); + uint32_t queue = priv->nb_queue - 1; struct rte_flow_op_attr op_attr = { .postpone = 0, }; @@ -4046,7 +4678,7 @@ static int flow_hw_destroy_ctrl_flow(struct rte_eth_dev *dev, struct rte_flow *flow) { struct mlx5_priv *priv = dev->data->dev_private; - uint32_t queue = flow_hw_get_ctrl_queue(priv); + uint32_t queue = priv->nb_queue - 1; struct rte_flow_op_attr op_attr = { .postpone = 0, }; @@ -4183,10 +4815,24 @@ mlx5_flow_hw_esw_create_mgr_sq_miss_flow(struct rte_eth_dev *dev) .type = RTE_FLOW_ITEM_TYPE_END, }, }; + struct rte_flow_action_modify_field modify_field = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + }, + .src = { + .field = RTE_FLOW_FIELD_VALUE, + }, + .width = 1, + }; struct rte_flow_action_jump jump = { - .group = MLX5_HW_SQ_MISS_GROUP, + .group = 1, }; struct rte_flow_action actions[] = { + { + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + .conf = &modify_field, + }, { .type = RTE_FLOW_ACTION_TYPE_JUMP, .conf = &jump, @@ -4209,6 +4855,12 @@ int mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq) { uint16_t port_id = dev->data->port_id; + struct rte_flow_item_tag reg_c0_spec = { + .index = (uint8_t)REG_C_0, + }; + struct rte_flow_item_tag reg_c0_mask = { + .index = 0xff, + }; struct mlx5_rte_flow_item_tx_queue queue_spec = { .queue = txq, }; @@ -4216,6 +4868,12 @@ mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq) .queue = UINT32_MAX, }; struct rte_flow_item items[] = { + { + .type = (enum rte_flow_item_type) + MLX5_RTE_FLOW_ITEM_TYPE_TAG, + .spec = ®_c0_spec, + .mask = ®_c0_mask, + }, { .type = (enum rte_flow_item_type) MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE, @@ -4241,6 +4899,7 @@ mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq) struct rte_eth_dev *proxy_dev; struct mlx5_priv *proxy_priv; uint16_t proxy_port_id = dev->data->port_id; + uint32_t marker_bit; int ret; RTE_SET_USED(txq); @@ -4261,6 +4920,14 @@ mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq) rte_errno = ENOMEM; return -rte_errno; } + marker_bit = flow_hw_usable_lsb_vport_mask(proxy_priv); + if (!marker_bit) { + DRV_LOG(ERR, "Unable to set up control flow in SQ miss table"); + rte_errno = EINVAL; + return -rte_errno; + } + reg_c0_spec.data = marker_bit; + reg_c0_mask.data = marker_bit; return flow_hw_create_ctrl_flow(dev, proxy_dev, proxy_priv->hw_esw_sq_miss_tbl, items, 0, actions, 0); @@ -4320,4 +4987,53 @@ mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev) items, 0, actions, 0); } +int +mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_flow_item_eth promisc = { + .dst.addr_bytes = "\x00\x00\x00\x00\x00\x00", + .src.addr_bytes = "\x00\x00\x00\x00\x00\x00", + .type = 0, + }; + struct rte_flow_item eth_all[] = { + [0] = { + .type = RTE_FLOW_ITEM_TYPE_ETH, + .spec = &promisc, + .mask = &promisc, + }, + [1] = { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + struct rte_flow_action_modify_field mreg_action = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_C_1, + }, + .src = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_A, + }, + .width = 32, + }; + struct rte_flow_action copy_reg_action[] = { + [0] = { + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + .conf = &mreg_action, + }, + [1] = { + .type = RTE_FLOW_ACTION_TYPE_END, + }, + }; + + MLX5_ASSERT(priv->master); + if (!priv->dr_ctx || !priv->hw_tx_meta_cpy_tbl) + return 0; + return flow_hw_create_ctrl_flow(dev, dev, + priv->hw_tx_meta_cpy_tbl, + eth_all, 0, copy_reg_action, 0); +} + #endif diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index 6313602a66..ccefebefc9 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -1292,6 +1292,9 @@ mlx5_traffic_enable_hws(struct rte_eth_dev *dev) if (priv->sh->config.dv_esw_en && priv->master) { if (mlx5_flow_hw_esw_create_mgr_sq_miss_flow(dev)) goto error; + if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS) + if (mlx5_flow_hw_create_tx_default_mreg_copy_flow(dev)) + goto error; } for (i = 0; i < priv->txqs_n; ++i) { struct mlx5_txq_ctrl *txq = mlx5_txq_get(dev, i); From patchwork Fri Sep 30 12:53:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117219 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id B2E41A00C4; Fri, 30 Sep 2022 14:54:57 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id A408B42B88; Fri, 30 Sep 2022 14:54:08 +0200 (CEST) Received: from NAM12-DM6-obe.outbound.protection.outlook.com (mail-dm6nam12on2082.outbound.protection.outlook.com [40.107.243.82]) by mails.dpdk.org (Postfix) with ESMTP id 270A942B78 for ; Fri, 30 Sep 2022 14:54:04 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=FY/5NaqwJ5jx68ItyKT5b64O/sgt0UPUhCBg5XIG5ibVSF5oZRz8ReUiIuWVwZZ/NkwObKhxZ353MsY9x9bDiJj8evIGnGGONM+OjcZbbMEMDZJsGO/ypR/fyWpq/t0PteylM09BzUW/YVZmflCLJNSa4girn6j/epyVduJgtfgZcKKHGpd6eh9SizErV4UJlHQnH/7itcEtaOgtUjKw0rAvWDOPcjQocP+/aEg1VeNmgdDyGim4c6a5ljPk4F5/BqvxRUMCfId4jzCBNlG7cN6PdWDDTifBeV0haJSbUuwWr6iU8ZKiYZJhSAH/cPCeEW/VS2x2g9oLjEqFJ8DCuw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=F2e+/0gIrioW2vyOvyOqSxYmy6GJC/flyNhTHCdCj1o=; b=TqvCDResZDcS7eE7V6XLnPLuUWa0w99GvyitcfDvtXAzIIgYYK9LgmT0RBO0aCKBO30+2++aNZkI43fVRRtGQ1X0LzFhlYNx0ubmbYh9DC+DxA1FNJglrQaRGJEfDhv4CmSLdVuze5mIpS7VNrk1/eSd/FkKRzcLeud1eQgFgkihWd/hkqjQtbRTjoogUHLAvSaUUyyYVA6lWkB2wFF1jaV4QQ7jBpR1i8U9jc/UcZOZU8rBprELbSMB8Ylj9eE8r4V0oCp0e3NvSED4oKBOMHoWowqncegRy75BNKNhUVPC17IyyPcJGv/UHPRsMi5gCTVmVuS8J+ibRSNJhOfOeg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=F2e+/0gIrioW2vyOvyOqSxYmy6GJC/flyNhTHCdCj1o=; b=W6oM2cGPiaLuS3ZO9rQT6NhNpaModx62mRLJbpO2WqNrQwjKK5TWeZUe4kcGdoK9dP6vUudHrd6IpMpdOrP+T6bNG55gcJo6UDijCw2IV21m+4MeEL/ni4Y7gnJOwD0TXKkKCZZL9o60erhPr6udvAMzMhH182SnFJCQ40mNXYppvayVrFwrUKe/tp3z7uacuTD111UnPnq0PXboxJKdW/3AmN+8MsHwr9/MGiNX2Ixg8e69KCbLZIPIBjwLsfTiAK/o/XJHZM0ddj2AiTOGF7kQq6JGBMlHhUvGY3s05LBVBs8Jbtrmsuz4SFOhMgiDFi7jCT0HYBT5aTAIJKVyxQ== Received: from DM5PR07CA0105.namprd07.prod.outlook.com (2603:10b6:4:ae::34) by BL1PR12MB5318.namprd12.prod.outlook.com (2603:10b6:208:31d::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23; Fri, 30 Sep 2022 12:54:01 +0000 Received: from DM6NAM11FT089.eop-nam11.prod.protection.outlook.com (2603:10b6:4:ae:cafe::11) by DM5PR07CA0105.outlook.office365.com (2603:10b6:4:ae::34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5654.26 via Frontend Transport; Fri, 30 Sep 2022 12:54:00 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT089.mail.protection.outlook.com (10.13.173.82) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:00 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:49 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:46 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , "Alexander Kozyrev" Subject: [PATCH v3 07/17] net/mlx5: add HW steering meter action Date: Fri, 30 Sep 2022 15:53:05 +0300 Message-ID: <20220930125315.5079-8-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT089:EE_|BL1PR12MB5318:EE_ X-MS-Office365-Filtering-Correlation-Id: a0928954-9e46-47ab-831e-08daa2e2d8aa X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: OKbYdyZr5FrFsutldiHdU1NhOd3GHCch77DdhZw2AElSI5bynLcI8QHfwEzqaTG/GtGQnTkfVeyeXEy9D5eJUzaswPQsFI+uuVcHMb6t5fRVD8U+YH334WtQ19FqA0FNBgHPjTTDPhigWm/CKNqsf8ZyRROJ0SW5ST1eiRfsQf73MhVyuLqqCpV73SNxxvqXDFfWsBEtv8eLhtLyJa408Gyfq0+XuSd6xi61t9ali1mj1foyzp+XsM+T+gSFl27CBDBDjr4gCIbhaDM/NUbsFK1r8wBhnHltWletQOCIaA4o6HXlXlW5XHrOEy3w+r0qxAzRmGuGhDQjWtt2kXqBLheI8HpZATZGQh2VqQo6iKAlPzif4UD4qCJtDL6CW36WANOIvqhjPvpD8AO0a7IJLt1AZXnmW6nGd56/mDQGY7emPWwxX0bXAKfGvEEPRfSBGDDXpxfjcPZ/ScVQ6AyY4h4ldNw167Kb4QH3PFe2smnnBcgj+J4JLsA9jZ7LCLL/hVUZklX8zo+ONzk0tKqhw0gOkWNuvpPVm30qkbK6BunrvOlYx+KFwrDcJPOVDhJZiKLzlyZl0ySjXll3B5EvySNnhMi+HWn5LqjHS8kZVcVug+hFqZiRIbP9b/VFmDvEkf6XdE6Q0ggAEYdpEz1ztR3ZLzbGYY0DOuPNS9v00hgJFOf9lvBmN2lteIRIYa8XdHiLvgjVhx13M+YG+lJxg4W8MNzHyHe8k+bhj3VIGlywJ7+m2IjT1g7psXwPZX88q01RY3Ojy9pz4fTuOX6wroi32TKwd8DqMIgjlfRMRP00PlTMCsGEfj8sdrWH0mpNtA/Gr5cVcp2Nbl4a9XKbKfnL2WOgGLzYOJ2F7Ttk/o0= X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(39860400002)(346002)(136003)(376002)(396003)(451199015)(36840700001)(40470700004)(46966006)(82310400005)(36756003)(2906002)(7636003)(8676002)(40480700001)(356005)(82740400003)(4326008)(30864003)(5660300002)(316002)(8936002)(41300700001)(55016003)(6636002)(110136005)(70586007)(70206006)(54906003)(6286002)(40460700003)(186003)(1076003)(426003)(336012)(83380400001)(47076005)(2616005)(16526019)(6666004)(107886003)(36860700001)(86362001)(478600001)(7696005)(26005)(559001)(579004)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:54:00.6146 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: a0928954-9e46-47ab-831e-08daa2e2d8aa X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT089.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL1PR12MB5318 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Alexander Kozyrev This commit adds meter action for HWS steering. HW steering meter is based on ASO. The number of meters will be used by flows should be specified in advanced in the flow configure API. Signed-off-by: Alexander Kozyrev --- drivers/net/mlx5/mlx5.h | 61 ++- drivers/net/mlx5/mlx5_flow.c | 71 +++ drivers/net/mlx5/mlx5_flow.h | 50 ++ drivers/net/mlx5/mlx5_flow_aso.c | 30 +- drivers/net/mlx5/mlx5_flow_dv.c | 25 - drivers/net/mlx5/mlx5_flow_hw.c | 264 ++++++++++- drivers/net/mlx5/mlx5_flow_meter.c | 702 ++++++++++++++++++++++++++++- 7 files changed, 1142 insertions(+), 61 deletions(-) diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index fc4bc4e6a3..686969719a 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -357,6 +357,9 @@ struct mlx5_hw_q { struct mlx5_hw_q_job **job; /* LIFO header. */ } __rte_cache_aligned; + + + #define MLX5_COUNTERS_PER_POOL 512 #define MLX5_MAX_PENDING_QUERIES 4 #define MLX5_CNT_CONTAINER_RESIZE 64 @@ -782,15 +785,29 @@ struct mlx5_flow_meter_policy { /* Is meter action in policy table. */ uint32_t hierarchy_drop_cnt:1; /* Is any meter in hierarchy contains drop_cnt. */ + uint32_t skip_r:1; + /* If red color policy is skipped. */ uint32_t skip_y:1; /* If yellow color policy is skipped. */ uint32_t skip_g:1; /* If green color policy is skipped. */ uint32_t mark:1; /* If policy contains mark action. */ + uint32_t initialized:1; + /* Initialized. */ + uint16_t group; + /* The group. */ rte_spinlock_t sl; uint32_t ref_cnt; /* Use count. */ + struct rte_flow_pattern_template *hws_item_templ; + /* Hardware steering item templates. */ + struct rte_flow_actions_template *hws_act_templ[MLX5_MTR_DOMAIN_MAX]; + /* Hardware steering action templates. */ + struct rte_flow_template_table *hws_flow_table[MLX5_MTR_DOMAIN_MAX]; + /* Hardware steering tables. */ + struct rte_flow *hws_flow_rule[MLX5_MTR_DOMAIN_MAX][RTE_COLORS]; + /* Hardware steering rules. */ struct mlx5_meter_policy_action_container act_cnt[MLX5_MTR_RTE_COLORS]; /* Policy actions container. */ void *dr_drop_action[MLX5_MTR_DOMAIN_MAX]; @@ -865,6 +882,7 @@ struct mlx5_flow_meter_info { */ uint32_t transfer:1; uint32_t def_policy:1; + uint32_t initialized:1; /* Meter points to default policy. */ uint32_t color_aware:1; /* Meter is color aware mode. */ @@ -880,6 +898,10 @@ struct mlx5_flow_meter_info { /**< Flow meter action. */ void *meter_action_y; /**< Flow meter action for yellow init_color. */ + uint32_t meter_offset; + /**< Flow meter offset. */ + uint16_t group; + /**< Flow meter group. */ }; /* PPS(packets per second) map to BPS(Bytes per second). @@ -914,6 +936,7 @@ struct mlx5_flow_meter_profile { uint32_t ref_cnt; /**< Use count. */ uint32_t g_support:1; /**< If G color will be generated. */ uint32_t y_support:1; /**< If Y color will be generated. */ + uint32_t initialized:1; /**< Initialized. */ }; /* 2 meters in each ASO cache line */ @@ -934,13 +957,20 @@ enum mlx5_aso_mtr_state { ASO_METER_READY, /* CQE received. */ }; +/*aso flow meter type*/ +enum mlx5_aso_mtr_type { + ASO_METER_INDIRECT, + ASO_METER_DIRECT, +}; + /* Generic aso_flow_meter information. */ struct mlx5_aso_mtr { LIST_ENTRY(mlx5_aso_mtr) next; + enum mlx5_aso_mtr_type type; struct mlx5_flow_meter_info fm; /**< Pointer to the next aso flow meter structure. */ uint8_t state; /**< ASO flow meter state. */ - uint8_t offset; + uint32_t offset; }; /* Generic aso_flow_meter pool structure. */ @@ -964,6 +994,14 @@ struct mlx5_aso_mtr_pools_mng { struct mlx5_aso_mtr_pool **pools; /* ASO flow meter pool array. */ }; +/* Bulk management structure for ASO flow meter. */ +struct mlx5_mtr_bulk { + uint32_t size; /* Number of ASO objects. */ + struct mlx5dr_action *action; /* HWS action */ + struct mlx5_devx_obj *devx_obj; /* DEVX object. */ + struct mlx5_aso_mtr *aso; /* Array of ASO objects. */ +}; + /* Meter management structure for global flow meter resource. */ struct mlx5_flow_mtr_mng { struct mlx5_aso_mtr_pools_mng pools_mng; @@ -1017,6 +1055,7 @@ struct mlx5_flow_tbl_resource { #define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 3) #define MLX5_FLOW_TABLE_LEVEL_POLICY (MLX5_MAX_TABLES - 4) #define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_POLICY +#define MLX5_FLOW_TABLE_HWS_POLICY (MLX5_MAX_TABLES - 10) #define MLX5_MAX_TABLES_FDB UINT16_MAX #define MLX5_FLOW_TABLE_FACTOR 10 @@ -1303,6 +1342,12 @@ TAILQ_HEAD(mlx5_mtr_profiles, mlx5_flow_meter_profile); /* MTR list. */ TAILQ_HEAD(mlx5_legacy_flow_meters, mlx5_legacy_flow_meter); +struct mlx5_mtr_config { + uint32_t nb_meters; /**< Number of configured meters */ + uint32_t nb_meter_profiles; /**< Number of configured meter profiles */ + uint32_t nb_meter_policies; /**< Number of configured meter policies */ +}; + /* RSS description. */ struct mlx5_flow_rss_desc { uint32_t level; @@ -1538,12 +1583,16 @@ struct mlx5_priv { struct mlx5_nl_vlan_vmwa_context *vmwa_context; /* VLAN WA context. */ struct mlx5_hlist *mreg_cp_tbl; /* Hash table of Rx metadata register copy table. */ + struct mlx5_mtr_config mtr_config; /* Meter configuration */ uint8_t mtr_sfx_reg; /* Meter prefix-suffix flow match REG_C. */ uint8_t mtr_color_reg; /* Meter color match REG_C. */ struct mlx5_legacy_flow_meters flow_meters; /* MTR list. */ struct mlx5_l3t_tbl *mtr_profile_tbl; /* Meter index lookup table. */ + struct mlx5_flow_meter_profile *mtr_profile_arr; /* Profile array. */ struct mlx5_l3t_tbl *policy_idx_tbl; /* Policy index lookup table. */ + struct mlx5_flow_meter_policy *mtr_policy_arr; /* Policy array. */ struct mlx5_l3t_tbl *mtr_idx_tbl; /* Meter index lookup table. */ + struct mlx5_mtr_bulk mtr_bulk; /* Meter index mapping for HWS */ uint8_t skip_default_rss_reta; /* Skip configuration of default reta. */ uint8_t fdb_def_rule; /* Whether fdb jump to table 1 is configured. */ struct mlx5_mp_id mp_id; /* ID of a multi-process process */ @@ -1557,13 +1606,13 @@ struct mlx5_priv { struct mlx5_flex_item flex_item[MLX5_PORT_FLEX_ITEM_NUM]; /* Flex items have been created on the port. */ uint32_t flex_item_map; /* Map of allocated flex item elements. */ + uint32_t nb_queue; /* HW steering queue number. */ #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) /* Item template list. */ LIST_HEAD(flow_hw_itt, rte_flow_pattern_template) flow_hw_itt; /* Action template list. */ LIST_HEAD(flow_hw_at, rte_flow_actions_template) flow_hw_at; struct mlx5dr_context *dr_ctx; /**< HW steering DR context. */ - uint32_t nb_queue; /* HW steering queue number. */ /* HW steering queue polling mechanism job descriptor LIFO. */ struct mlx5_hw_q *hw_q; /* HW steering rte flow table list header. */ @@ -1579,6 +1628,7 @@ struct mlx5_priv { #define PORT_ID(priv) ((priv)->dev_data->port_id) #define ETH_DEV(priv) (&rte_eth_devices[PORT_ID(priv)]) +#define CTRL_QUEUE_ID(priv) ((priv)->nb_queue - 1) struct rte_hairpin_peer_info { uint32_t qp_id; @@ -1890,6 +1940,11 @@ void mlx5_pmd_socket_uninit(void); /* mlx5_flow_meter.c */ +int mlx5_flow_meter_init(struct rte_eth_dev *dev, + uint32_t nb_meters, + uint32_t nb_meter_profiles, + uint32_t nb_meter_policies); +void mlx5_flow_meter_uninit(struct rte_eth_dev *dev); int mlx5_flow_meter_ops_get(struct rte_eth_dev *dev, void *arg); struct mlx5_flow_meter_info *mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id, uint32_t *mtr_idx); @@ -1964,7 +2019,7 @@ int mlx5_aso_flow_hit_queue_poll_stop(struct mlx5_dev_ctx_shared *sh); void mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh, enum mlx5_access_aso_opc_mod aso_opc_mod); int mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, - struct mlx5_aso_mtr *mtr); + struct mlx5_aso_mtr *mtr, struct mlx5_mtr_bulk *bulk); int mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, struct mlx5_aso_mtr *mtr); int mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh, diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index b570ed7f69..fb3be940e5 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -8331,6 +8331,40 @@ mlx5_flow_port_configure(struct rte_eth_dev *dev, return fops->configure(dev, port_attr, nb_queue, queue_attr, error); } +/** + * Validate item template. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[in] attr + * Pointer to the item template attributes. + * @param[in] items + * The template item pattern. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_flow_pattern_validate(struct rte_eth_dev *dev, + const struct rte_flow_pattern_template_attr *attr, + const struct rte_flow_item items[], + struct rte_flow_error *error) +{ + const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr fattr = {0}; + + if (flow_get_drv_type(dev, &fattr) != MLX5_FLOW_TYPE_HW) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "pattern validate with incorrect steering mode"); + return -ENOTSUP; + } + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_HW); + return fops->pattern_validate(dev, attr, items, error); +} + /** * Create flow item template. * @@ -8396,6 +8430,43 @@ mlx5_flow_pattern_template_destroy(struct rte_eth_dev *dev, return fops->pattern_template_destroy(dev, template, error); } +/** + * Validate flow actions template. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[in] attr + * Pointer to the action template attributes. + * @param[in] actions + * Associated actions (list terminated by the END action). + * @param[in] masks + * List of actions that marks which of the action's member is constant. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_flow_actions_validate(struct rte_eth_dev *dev, + const struct rte_flow_actions_template_attr *attr, + const struct rte_flow_action actions[], + const struct rte_flow_action masks[], + struct rte_flow_error *error) +{ + const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr fattr = {0}; + + if (flow_get_drv_type(dev, &fattr) != MLX5_FLOW_TYPE_HW) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "actions validate with incorrect steering mode"); + return -ENOTSUP; + } + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_HW); + return fops->actions_validate(dev, attr, actions, masks, error); +} + /** * Create flow item template. * diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index a8b27ea494..3bde95c927 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -1654,6 +1654,11 @@ typedef int (*mlx5_flow_port_configure_t) uint16_t nb_queue, const struct rte_flow_queue_attr *queue_attr[], struct rte_flow_error *err); +typedef int (*mlx5_flow_pattern_validate_t) + (struct rte_eth_dev *dev, + const struct rte_flow_pattern_template_attr *attr, + const struct rte_flow_item items[], + struct rte_flow_error *error); typedef struct rte_flow_pattern_template *(*mlx5_flow_pattern_template_create_t) (struct rte_eth_dev *dev, const struct rte_flow_pattern_template_attr *attr, @@ -1663,6 +1668,12 @@ typedef int (*mlx5_flow_pattern_template_destroy_t) (struct rte_eth_dev *dev, struct rte_flow_pattern_template *template, struct rte_flow_error *error); +typedef int (*mlx5_flow_actions_validate_t) + (struct rte_eth_dev *dev, + const struct rte_flow_actions_template_attr *attr, + const struct rte_flow_action actions[], + const struct rte_flow_action masks[], + struct rte_flow_error *error); typedef struct rte_flow_actions_template *(*mlx5_flow_actions_template_create_t) (struct rte_eth_dev *dev, const struct rte_flow_actions_template_attr *attr, @@ -1779,8 +1790,10 @@ struct mlx5_flow_driver_ops { mlx5_flow_item_update_t item_update; mlx5_flow_info_get_t info_get; mlx5_flow_port_configure_t configure; + mlx5_flow_pattern_validate_t pattern_validate; mlx5_flow_pattern_template_create_t pattern_template_create; mlx5_flow_pattern_template_destroy_t pattern_template_destroy; + mlx5_flow_actions_validate_t actions_validate; mlx5_flow_actions_template_create_t actions_template_create; mlx5_flow_actions_template_destroy_t actions_template_destroy; mlx5_flow_table_create_t template_table_create; @@ -1862,6 +1875,8 @@ mlx5_aso_meter_by_idx(struct mlx5_priv *priv, uint32_t idx) /* Decrease to original index. */ idx--; + if (priv->mtr_bulk.aso) + return priv->mtr_bulk.aso + idx; MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < pools_mng->n); rte_rwlock_read_lock(&pools_mng->resize_mtrwl); pool = pools_mng->pools[idx / MLX5_ASO_MTRS_PER_POOL]; @@ -1964,6 +1979,32 @@ mlx5_translate_tunnel_etypes(uint64_t pattern_flags) int flow_hw_q_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error); + +/* + * Convert rte_mtr_color to mlx5 color. + * + * @param[in] rcol + * rte_mtr_color. + * + * @return + * mlx5 color. + */ +static inline int +rte_col_2_mlx5_col(enum rte_color rcol) +{ + switch (rcol) { + case RTE_COLOR_GREEN: + return MLX5_FLOW_COLOR_GREEN; + case RTE_COLOR_YELLOW: + return MLX5_FLOW_COLOR_YELLOW; + case RTE_COLOR_RED: + return MLX5_FLOW_COLOR_RED; + default: + break; + } + return MLX5_FLOW_COLOR_UNDEFINED; +} + int mlx5_flow_group_to_table(struct rte_eth_dev *dev, const struct mlx5_flow_tunnel *tunnel, uint32_t group, uint32_t *table, @@ -2347,4 +2388,13 @@ int mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq); int mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev); int mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev); +int mlx5_flow_actions_validate(struct rte_eth_dev *dev, + const struct rte_flow_actions_template_attr *attr, + const struct rte_flow_action actions[], + const struct rte_flow_action masks[], + struct rte_flow_error *error); +int mlx5_flow_pattern_validate(struct rte_eth_dev *dev, + const struct rte_flow_pattern_template_attr *attr, + const struct rte_flow_item items[], + struct rte_flow_error *error); #endif /* RTE_PMD_MLX5_FLOW_H_ */ diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c index 4129e3a9e0..60d0280367 100644 --- a/drivers/net/mlx5/mlx5_flow_aso.c +++ b/drivers/net/mlx5/mlx5_flow_aso.c @@ -642,7 +642,8 @@ mlx5_aso_flow_hit_queue_poll_stop(struct mlx5_dev_ctx_shared *sh) static uint16_t mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, struct mlx5_aso_sq *sq, - struct mlx5_aso_mtr *aso_mtr) + struct mlx5_aso_mtr *aso_mtr, + struct mlx5_mtr_bulk *bulk) { volatile struct mlx5_aso_wqe *wqe = NULL; struct mlx5_flow_meter_info *fm = NULL; @@ -653,6 +654,7 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, uint32_t dseg_idx = 0; struct mlx5_aso_mtr_pool *pool = NULL; uint32_t param_le; + int id; rte_spinlock_lock(&sq->sqsl); res = size - (uint16_t)(sq->head - sq->tail); @@ -666,14 +668,19 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, /* Fill next WQE. */ fm = &aso_mtr->fm; sq->elts[sq->head & mask].mtr = aso_mtr; - pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool, - mtrs[aso_mtr->offset]); - wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id + - (aso_mtr->offset >> 1)); - wqe->general_cseg.opcode = rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO | - (ASO_OPC_MOD_POLICER << - WQE_CSEG_OPC_MOD_OFFSET) | - sq->pi << WQE_CSEG_WQE_INDEX_OFFSET); + if (aso_mtr->type == ASO_METER_INDIRECT) { + pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool, + mtrs[aso_mtr->offset]); + id = pool->devx_obj->id; + } else { + id = bulk->devx_obj->id; + } + wqe->general_cseg.misc = rte_cpu_to_be_32(id + + (aso_mtr->offset >> 1)); + wqe->general_cseg.opcode = + rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO | + (ASO_OPC_MOD_POLICER << WQE_CSEG_OPC_MOD_OFFSET) | + sq->pi << WQE_CSEG_WQE_INDEX_OFFSET); /* There are 2 meters in one ASO cache line. */ dseg_idx = aso_mtr->offset & 0x1; wqe->aso_cseg.data_mask = @@ -811,14 +818,15 @@ mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq) */ int mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, - struct mlx5_aso_mtr *mtr) + struct mlx5_aso_mtr *mtr, + struct mlx5_mtr_bulk *bulk) { struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq; uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES; do { mlx5_aso_mtr_completion_handle(sq); - if (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr)) + if (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk)) return 0; /* Waiting for wqe resource. */ rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY); diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 5b72cfaa61..1eb1ce659f 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -216,31 +216,6 @@ flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr, attr->valid = 1; } -/* - * Convert rte_mtr_color to mlx5 color. - * - * @param[in] rcol - * rte_mtr_color. - * - * @return - * mlx5 color. - */ -static inline int -rte_col_2_mlx5_col(enum rte_color rcol) -{ - switch (rcol) { - case RTE_COLOR_GREEN: - return MLX5_FLOW_COLOR_GREEN; - case RTE_COLOR_YELLOW: - return MLX5_FLOW_COLOR_YELLOW; - case RTE_COLOR_RED: - return MLX5_FLOW_COLOR_RED; - default: - break; - } - return MLX5_FLOW_COLOR_UNDEFINED; -} - struct field_modify_info modify_eth[] = { {4, 0, MLX5_MODI_OUT_DMAC_47_16}, {2, 4, MLX5_MODI_OUT_DMAC_15_0}, diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 64d06d4fb4..c2e16bc56d 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -914,6 +914,38 @@ flow_hw_represented_port_compile(struct rte_eth_dev *dev, return 0; } +static __rte_always_inline int +flow_hw_meter_compile(struct rte_eth_dev *dev, + const struct mlx5_flow_template_table_cfg *cfg, + uint32_t start_pos, const struct rte_flow_action *action, + struct mlx5_hw_actions *acts, uint32_t *end_pos, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr *aso_mtr; + const struct rte_flow_action_meter *meter = action->conf; + uint32_t pos = start_pos; + uint32_t group = cfg->attr.flow_attr.group; + + aso_mtr = mlx5_aso_meter_by_idx(priv, meter->mtr_id); + acts->rule_acts[pos].action = priv->mtr_bulk.action; + acts->rule_acts[pos].aso_meter.offset = aso_mtr->offset; + acts->jump = flow_hw_jump_action_register + (dev, cfg, aso_mtr->fm.group, error); + if (!acts->jump) { + *end_pos = start_pos; + return -ENOMEM; + } + acts->rule_acts[++pos].action = (!!group) ? + acts->jump->hws_action : + acts->jump->root_action; + *end_pos = pos; + if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) { + *end_pos = start_pos; + return -ENOMEM; + } + return 0; +} /** * Translate rte_flow actions to DR action. * @@ -1142,6 +1174,21 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, goto err; i++; break; + case RTE_FLOW_ACTION_TYPE_METER: + if (actions->conf && masks->conf && + ((const struct rte_flow_action_meter *) + masks->conf)->mtr_id) { + err = flow_hw_meter_compile(dev, cfg, + i, actions, acts, &i, error); + if (err) + goto err; + } else if (__flow_hw_act_data_general_append(priv, acts, + actions->type, + actions - action_start, + i)) + goto err; + i++; + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -1482,6 +1529,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, const struct rte_flow_action_raw_encap *raw_encap_data; const struct rte_flow_item *enc_item = NULL; const struct rte_flow_action_ethdev *port_action = NULL; + const struct rte_flow_action_meter *meter = NULL; uint8_t *buf = job->encap_data; struct rte_flow_attr attr = { .ingress = 1, @@ -1489,6 +1537,8 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, uint32_t ft_flag; size_t encap_len = 0; int ret; + struct mlx5_aso_mtr *mtr; + uint32_t mtr_id; memcpy(rule_acts, hw_acts->rule_acts, sizeof(*rule_acts) * hw_acts->acts_num); @@ -1608,6 +1658,29 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, rule_acts[act_data->action_dst].action = priv->hw_vport[port_action->port_id]; break; + case RTE_FLOW_ACTION_TYPE_METER: + meter = action->conf; + mtr_id = meter->mtr_id; + mtr = mlx5_aso_meter_by_idx(priv, mtr_id); + rule_acts[act_data->action_dst].action = + priv->mtr_bulk.action; + rule_acts[act_data->action_dst].aso_meter.offset = + mtr->offset; + jump = flow_hw_jump_action_register + (dev, &table->cfg, mtr->fm.group, NULL); + if (!jump) + return -1; + MLX5_ASSERT + (!rule_acts[act_data->action_dst + 1].action); + rule_acts[act_data->action_dst + 1].action = + (!!attr.group) ? jump->hws_action : + jump->root_action; + job->flow->jump = jump; + job->flow->fate_type = MLX5_FLOW_FATE_JUMP; + (*acts_num)++; + if (mlx5_aso_mtr_wait(priv->sh, mtr)) + return -1; + break; default: break; } @@ -2523,7 +2596,7 @@ flow_hw_action_meta_copy_insert(const struct rte_flow_action actions[], } static int -flow_hw_action_validate(struct rte_eth_dev *dev, +flow_hw_actions_validate(struct rte_eth_dev *dev, const struct rte_flow_actions_template_attr *attr, const struct rte_flow_action actions[], const struct rte_flow_action masks[], @@ -2589,6 +2662,9 @@ flow_hw_action_validate(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_RAW_DECAP: /* TODO: Validation logic */ break; + case RTE_FLOW_ACTION_TYPE_METER: + /* TODO: Validation logic */ + break; case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: ret = flow_hw_validate_action_modify_field(action, mask, @@ -2682,7 +2758,7 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, .conf = &rx_mreg_mask, }; - if (flow_hw_action_validate(dev, attr, actions, masks, error)) + if (flow_hw_actions_validate(dev, attr, actions, masks, error)) return NULL; if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS && priv->sh->config.dv_esw_en) { @@ -3028,15 +3104,27 @@ flow_hw_pattern_template_destroy(struct rte_eth_dev *dev __rte_unused, * 0 on success, a negative errno value otherwise and rte_errno is set. */ static int -flow_hw_info_get(struct rte_eth_dev *dev __rte_unused, - struct rte_flow_port_info *port_info __rte_unused, - struct rte_flow_queue_info *queue_info __rte_unused, +flow_hw_info_get(struct rte_eth_dev *dev, + struct rte_flow_port_info *port_info, + struct rte_flow_queue_info *queue_info, struct rte_flow_error *error __rte_unused) { - /* Nothing to be updated currently. */ + uint16_t port_id = dev->data->port_id; + struct rte_mtr_capabilities mtr_cap; + int ret; + memset(port_info, 0, sizeof(*port_info)); /* Queue size is unlimited from low-level. */ + port_info->max_nb_queues = UINT32_MAX; queue_info->max_size = UINT32_MAX; + + memset(&mtr_cap, 0, sizeof(struct rte_mtr_capabilities)); + ret = rte_mtr_capabilities_get(port_id, &mtr_cap, NULL); + if (!ret) { + port_info->max_nb_meters = mtr_cap.n_max; + port_info->max_nb_meter_profiles = UINT32_MAX; + port_info->max_nb_meter_policies = UINT32_MAX; + } return 0; } @@ -4231,6 +4319,13 @@ flow_hw_configure(struct rte_eth_dev *dev, priv->nb_queue = nb_q_updated; rte_spinlock_init(&priv->hw_ctrl_lock); LIST_INIT(&priv->hw_ctrl_flows); + /* Initialize meter library*/ + if (port_attr->nb_meters) + if (mlx5_flow_meter_init(dev, + port_attr->nb_meters, + port_attr->nb_meter_profiles, + port_attr->nb_meter_policies)) + goto err; /* Add global actions. */ for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) { uint32_t act_flags = 0; @@ -4546,8 +4641,10 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .info_get = flow_hw_info_get, .configure = flow_hw_configure, + .pattern_validate = flow_hw_pattern_validate, .pattern_template_create = flow_hw_pattern_template_create, .pattern_template_destroy = flow_hw_pattern_template_destroy, + .actions_validate = flow_hw_actions_validate, .actions_template_create = flow_hw_actions_template_create, .actions_template_destroy = flow_hw_actions_template_destroy, .template_table_create = flow_hw_template_table_create, @@ -4603,7 +4700,7 @@ flow_hw_create_ctrl_flow(struct rte_eth_dev *owner_dev, uint8_t action_template_idx) { struct mlx5_priv *priv = proxy_dev->data->dev_private; - uint32_t queue = priv->nb_queue - 1; + uint32_t queue = CTRL_QUEUE_ID(priv); struct rte_flow_op_attr op_attr = { .postpone = 0, }; @@ -4678,7 +4775,7 @@ static int flow_hw_destroy_ctrl_flow(struct rte_eth_dev *dev, struct rte_flow *flow) { struct mlx5_priv *priv = dev->data->dev_private; - uint32_t queue = priv->nb_queue - 1; + uint32_t queue = CTRL_QUEUE_ID(priv); struct rte_flow_op_attr op_attr = { .postpone = 0, }; @@ -5036,4 +5133,155 @@ mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev) eth_all, 0, copy_reg_action, 0); } +void +mlx5_flow_meter_uninit(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + if (priv->mtr_policy_arr) { + mlx5_free(priv->mtr_policy_arr); + priv->mtr_policy_arr = NULL; + } + if (priv->mtr_profile_arr) { + mlx5_free(priv->mtr_profile_arr); + priv->mtr_profile_arr = NULL; + } + if (priv->mtr_bulk.aso) { + mlx5_free(priv->mtr_bulk.aso); + priv->mtr_bulk.aso = NULL; + priv->mtr_bulk.size = 0; + mlx5_aso_queue_uninit(priv->sh, ASO_OPC_MOD_POLICER); + } + if (priv->mtr_bulk.action) { + mlx5dr_action_destroy(priv->mtr_bulk.action); + priv->mtr_bulk.action = NULL; + } + if (priv->mtr_bulk.devx_obj) { + claim_zero(mlx5_devx_cmd_destroy(priv->mtr_bulk.devx_obj)); + priv->mtr_bulk.devx_obj = NULL; + } +} + +int +mlx5_flow_meter_init(struct rte_eth_dev *dev, + uint32_t nb_meters, + uint32_t nb_meter_profiles, + uint32_t nb_meter_policies) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_devx_obj *dcs = NULL; + uint32_t log_obj_size; + int ret = 0; + int reg_id; + struct mlx5_aso_mtr *aso; + uint32_t i; + struct rte_flow_error error; + + if (!nb_meters || !nb_meter_profiles || !nb_meter_policies) { + ret = ENOTSUP; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter configuration is invalid."); + goto err; + } + if (!priv->mtr_en || !priv->sh->meter_aso_en) { + ret = ENOTSUP; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter ASO is not supported."); + goto err; + } + priv->mtr_config.nb_meters = nb_meters; + if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) { + ret = ENOMEM; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter ASO queue allocation failed."); + goto err; + } + log_obj_size = rte_log2_u32(nb_meters >> 1); + dcs = mlx5_devx_cmd_create_flow_meter_aso_obj + (priv->sh->cdev->ctx, priv->sh->cdev->pdn, + log_obj_size); + if (!dcs) { + ret = ENOMEM; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter ASO object allocation failed."); + goto err; + } + priv->mtr_bulk.devx_obj = dcs; + reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, NULL); + if (reg_id < 0) { + ret = ENOTSUP; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter register is not available."); + goto err; + } + priv->mtr_bulk.action = mlx5dr_action_create_aso_meter + (priv->dr_ctx, (struct mlx5dr_devx_obj *)dcs, + reg_id - REG_C_0, MLX5DR_ACTION_FLAG_HWS_RX | + MLX5DR_ACTION_FLAG_HWS_TX | + MLX5DR_ACTION_FLAG_HWS_FDB); + if (!priv->mtr_bulk.action) { + ret = ENOMEM; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter action creation failed."); + goto err; + } + priv->mtr_bulk.aso = mlx5_malloc(MLX5_MEM_ZERO, + sizeof(struct mlx5_aso_mtr) * nb_meters, + RTE_CACHE_LINE_SIZE, + SOCKET_ID_ANY); + if (!priv->mtr_bulk.aso) { + ret = ENOMEM; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter bulk ASO allocation failed."); + goto err; + } + priv->mtr_bulk.size = nb_meters; + aso = priv->mtr_bulk.aso; + for (i = 0; i < priv->mtr_bulk.size; i++) { + aso->type = ASO_METER_DIRECT; + aso->state = ASO_METER_WAIT; + aso->offset = i; + aso++; + } + priv->mtr_config.nb_meter_profiles = nb_meter_profiles; + priv->mtr_profile_arr = + mlx5_malloc(MLX5_MEM_ZERO, + sizeof(struct mlx5_flow_meter_profile) * + nb_meter_profiles, + RTE_CACHE_LINE_SIZE, + SOCKET_ID_ANY); + if (!priv->mtr_profile_arr) { + ret = ENOMEM; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter profile allocation failed."); + goto err; + } + priv->mtr_config.nb_meter_policies = nb_meter_policies; + priv->mtr_policy_arr = + mlx5_malloc(MLX5_MEM_ZERO, + sizeof(struct mlx5_flow_meter_policy) * + nb_meter_policies, + RTE_CACHE_LINE_SIZE, + SOCKET_ID_ANY); + if (!priv->mtr_policy_arr) { + ret = ENOMEM; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter policy allocation failed."); + goto err; + } + return 0; +err: + mlx5_flow_meter_uninit(dev); + return ret; +} + #endif diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c index d4aafe4eea..792b945c98 100644 --- a/drivers/net/mlx5/mlx5_flow_meter.c +++ b/drivers/net/mlx5/mlx5_flow_meter.c @@ -98,6 +98,8 @@ mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id) union mlx5_l3t_data data; int32_t ret; + if (priv->mtr_profile_arr) + return &priv->mtr_profile_arr[meter_profile_id]; if (mlx5_l3t_get_entry(priv->mtr_profile_tbl, meter_profile_id, &data) || !data.ptr) return NULL; @@ -145,17 +147,29 @@ mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev, RTE_MTR_ERROR_TYPE_METER_PROFILE, NULL, "Meter profile is null."); /* Meter profile ID must be valid. */ - if (meter_profile_id == UINT32_MAX) - return -rte_mtr_error_set(error, EINVAL, - RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, - NULL, "Meter profile id not valid."); - /* Meter profile must not exist. */ - fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); - if (fmp) - return -rte_mtr_error_set(error, EEXIST, - RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, - NULL, - "Meter profile already exists."); + if (priv->mtr_profile_arr) { + if (meter_profile_id >= priv->mtr_config.nb_meter_profiles) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, "Meter profile id not valid."); + fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); + /* Meter profile must not exist. */ + if (fmp->initialized) + return -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, "Meter profile already exists."); + } else { + if (meter_profile_id == UINT32_MAX) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, "Meter profile id not valid."); + fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); + /* Meter profile must not exist. */ + if (fmp) + return -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, "Meter profile already exists."); + } if (!priv->sh->meter_aso_en) { /* Old version is even not supported. */ if (!priv->sh->cdev->config.hca_attr.qos.flow_meter_old) @@ -574,6 +588,96 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev, return 0; } +/** + * Callback to add MTR profile with HWS. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] meter_profile_id + * Meter profile id. + * @param[in] profile + * Pointer to meter profile detail. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_profile_hws_add(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_meter_profile *profile, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_flow_meter_profile *fmp; + int ret; + + if (!priv->mtr_profile_arr) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter profile array is not allocated"); + /* Check input params. */ + ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id, + profile, error); + if (ret) + return ret; + fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); + /* Fill profile info. */ + fmp->id = meter_profile_id; + fmp->profile = *profile; + fmp->initialized = 1; + /* Fill the flow meter parameters for the PRM. */ + return mlx5_flow_meter_param_fill(fmp, error); +} + +/** + * Callback to delete MTR profile with HWS. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] meter_profile_id + * Meter profile id. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_profile_hws_delete(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_flow_meter_profile *fmp; + + if (!priv->mtr_profile_arr) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter profile array is not allocated"); + /* Meter id must be valid. */ + if (meter_profile_id >= priv->mtr_config.nb_meter_profiles) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + &meter_profile_id, + "Meter profile id not valid."); + /* Meter profile must exist. */ + fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id); + if (!fmp->initialized) + return -rte_mtr_error_set(error, ENOENT, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + &meter_profile_id, + "Meter profile id is invalid."); + /* Check profile is unused. */ + if (fmp->ref_cnt) + return -rte_mtr_error_set(error, EBUSY, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, "Meter profile is in use."); + memset(fmp, 0, sizeof(struct mlx5_flow_meter_profile)); + return 0; +} + /** * Find policy by id. * @@ -594,6 +698,11 @@ mlx5_flow_meter_policy_find(struct rte_eth_dev *dev, struct mlx5_flow_meter_sub_policy *sub_policy = NULL; union mlx5_l3t_data data; + if (priv->mtr_policy_arr) { + if (policy_idx) + *policy_idx = policy_id; + return &priv->mtr_policy_arr[policy_id]; + } if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM || !priv->policy_idx_tbl) return NULL; if (mlx5_l3t_get_entry(priv->policy_idx_tbl, policy_id, &data) || @@ -710,6 +819,43 @@ mlx5_flow_meter_policy_validate(struct rte_eth_dev *dev, return 0; } +/** + * Callback to check MTR policy action validate for HWS + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] actions + * Pointer to meter policy action detail. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_policy_hws_validate(struct rte_eth_dev *dev, + struct rte_mtr_meter_policy_params *policy, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + const struct rte_flow_actions_template_attr attr = { + .transfer = priv->sh->config.dv_esw_en ? 1 : 0 }; + int ret; + int i; + + if (!priv->mtr_en || !priv->sh->meter_aso_en) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY, + NULL, "meter policy unsupported."); + for (i = 0; i < RTE_COLORS; i++) { + ret = mlx5_flow_actions_validate(dev, &attr, policy->actions[i], + policy->actions[i], NULL); + if (ret) + return ret; + } + return 0; +} + static int __mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev, uint32_t policy_id, @@ -1004,6 +1150,338 @@ mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev, return 0; } +/** + * Callback to delete MTR policy for HWS. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] policy_id + * Meter policy id. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_policy_hws_delete(struct rte_eth_dev *dev, + uint32_t policy_id, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_flow_meter_policy *mtr_policy; + uint32_t i, j; + uint32_t nb_flows = 0; + int ret; + struct rte_flow_op_attr op_attr = { .postpone = 1 }; + struct rte_flow_op_result result[RTE_COLORS * MLX5_MTR_DOMAIN_MAX]; + + if (!priv->mtr_policy_arr) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter policy array is not allocated"); + /* Meter id must be valid. */ + if (policy_id >= priv->mtr_config.nb_meter_policies) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + &policy_id, + "Meter policy id not valid."); + /* Meter policy must exist. */ + mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL); + if (!mtr_policy->initialized) + return -rte_mtr_error_set(error, ENOENT, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL, + "Meter policy does not exists."); + /* Check policy is unused. */ + if (mtr_policy->ref_cnt) + return -rte_mtr_error_set(error, EBUSY, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "Meter policy is in use."); + rte_spinlock_lock(&priv->hw_ctrl_lock); + for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { + for (j = 0; j < RTE_COLORS; j++) { + if (mtr_policy->hws_flow_rule[i][j]) { + ret = rte_flow_async_destroy(dev->data->port_id, + CTRL_QUEUE_ID(priv), &op_attr, + mtr_policy->hws_flow_rule[i][j], + NULL, NULL); + if (ret < 0) + continue; + nb_flows++; + } + } + } + ret = rte_flow_push(dev->data->port_id, CTRL_QUEUE_ID(priv), NULL); + while (nb_flows && (ret >= 0)) { + ret = rte_flow_pull(dev->data->port_id, + CTRL_QUEUE_ID(priv), result, + nb_flows, NULL); + nb_flows -= ret; + } + for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { + if (mtr_policy->hws_flow_table[i]) + rte_flow_template_table_destroy(dev->data->port_id, + mtr_policy->hws_flow_table[i], NULL); + } + for (i = 0; i < RTE_COLORS; i++) { + if (mtr_policy->hws_act_templ[i]) + rte_flow_actions_template_destroy(dev->data->port_id, + mtr_policy->hws_act_templ[i], NULL); + } + if (mtr_policy->hws_item_templ) + rte_flow_pattern_template_destroy(dev->data->port_id, + mtr_policy->hws_item_templ, NULL); + rte_spinlock_unlock(&priv->hw_ctrl_lock); + memset(mtr_policy, 0, sizeof(struct mlx5_flow_meter_policy)); + return 0; +} + +/** + * Callback to add MTR policy for HWS. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[out] policy_id + * Pointer to policy id + * @param[in] actions + * Pointer to meter policy action detail. + * @param[out] error + * Pointer to the error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_policy_hws_add(struct rte_eth_dev *dev, + uint32_t policy_id, + struct rte_mtr_meter_policy_params *policy, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_flow_meter_policy *mtr_policy = NULL; + const struct rte_flow_action *act; + const struct rte_flow_action_meter *mtr; + struct mlx5_flow_meter_info *fm; + struct mlx5_flow_meter_policy *plc; + uint8_t domain_color = MLX5_MTR_ALL_DOMAIN_BIT; + bool is_rss = false; + bool is_hierarchy = false; + int i, j; + uint32_t nb_colors = 0; + uint32_t nb_flows = 0; + int color; + int ret; + struct rte_flow_pattern_template_attr pta = {0}; + struct rte_flow_actions_template_attr ata = {0}; + struct rte_flow_template_table_attr ta = { {0}, 0 }; + struct rte_flow_op_attr op_attr = { .postpone = 1 }; + struct rte_flow_op_result result[RTE_COLORS * MLX5_MTR_DOMAIN_MAX]; + const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1; + int color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, + 0, NULL); + struct rte_flow_item_tag tag_spec = { + .data = 0, + .index = color_reg_c_idx + }; + struct rte_flow_item_tag tag_mask = { + .data = color_mask, + .index = 0xff}; + struct rte_flow_item pattern[] = { + [0] = { + .type = (enum rte_flow_item_type) + MLX5_RTE_FLOW_ITEM_TYPE_TAG, + .spec = &tag_spec, + .mask = &tag_mask, + }, + [1] = { .type = RTE_FLOW_ITEM_TYPE_END } + }; + + if (!priv->mtr_policy_arr) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY, + NULL, "Meter policy array is not allocated."); + if (policy_id >= priv->mtr_config.nb_meter_policies) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "Meter policy id not valid."); + mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL); + if (mtr_policy->initialized) + return -rte_mtr_error_set(error, EEXIST, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "Meter policy already exists."); + if (!policy || + !policy->actions[RTE_COLOR_RED] || + !policy->actions[RTE_COLOR_YELLOW] || + !policy->actions[RTE_COLOR_GREEN]) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_METER_POLICY, + NULL, "Meter policy actions are not valid."); + if (policy->actions[RTE_COLOR_RED] == RTE_FLOW_ACTION_TYPE_END) + mtr_policy->skip_r = 1; + if (policy->actions[RTE_COLOR_YELLOW] == RTE_FLOW_ACTION_TYPE_END) + mtr_policy->skip_y = 1; + if (policy->actions[RTE_COLOR_GREEN] == RTE_FLOW_ACTION_TYPE_END) + mtr_policy->skip_g = 1; + if (mtr_policy->skip_r && mtr_policy->skip_y && mtr_policy->skip_g) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "Meter policy actions are empty."); + for (i = 0; i < RTE_COLORS; i++) { + act = policy->actions[i]; + while (act && act->type != RTE_FLOW_ACTION_TYPE_END) { + switch (act->type) { + case RTE_FLOW_ACTION_TYPE_PORT_ID: + /* fall-through. */ + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: + domain_color &= ~(MLX5_MTR_DOMAIN_INGRESS_BIT | + MLX5_MTR_DOMAIN_EGRESS_BIT); + break; + case RTE_FLOW_ACTION_TYPE_RSS: + is_rss = true; + /* fall-through. */ + case RTE_FLOW_ACTION_TYPE_QUEUE: + domain_color &= ~(MLX5_MTR_DOMAIN_EGRESS_BIT | + MLX5_MTR_DOMAIN_TRANSFER_BIT); + break; + case RTE_FLOW_ACTION_TYPE_METER: + is_hierarchy = true; + mtr = act->conf; + fm = mlx5_flow_meter_find(priv, + mtr->mtr_id, NULL); + if (!fm) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_MTR_ID, NULL, + "Meter not found in meter hierarchy."); + plc = mlx5_flow_meter_policy_find(dev, + fm->policy_id, + NULL); + MLX5_ASSERT(plc); + domain_color &= MLX5_MTR_ALL_DOMAIN_BIT & + (plc->ingress << + MLX5_MTR_DOMAIN_INGRESS); + domain_color &= MLX5_MTR_ALL_DOMAIN_BIT & + (plc->egress << + MLX5_MTR_DOMAIN_EGRESS); + domain_color &= MLX5_MTR_ALL_DOMAIN_BIT & + (plc->transfer << + MLX5_MTR_DOMAIN_TRANSFER); + break; + default: + break; + } + act++; + } + } + if (!domain_color) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "Meter policy domains are conflicting."); + mtr_policy->is_rss = is_rss; + mtr_policy->ingress = !!(domain_color & MLX5_MTR_DOMAIN_INGRESS_BIT); + pta.ingress = mtr_policy->ingress; + mtr_policy->egress = !!(domain_color & MLX5_MTR_DOMAIN_EGRESS_BIT); + pta.egress = mtr_policy->egress; + mtr_policy->transfer = !!(domain_color & MLX5_MTR_DOMAIN_TRANSFER_BIT); + pta.transfer = mtr_policy->transfer; + mtr_policy->group = MLX5_FLOW_TABLE_HWS_POLICY - policy_id; + mtr_policy->is_hierarchy = is_hierarchy; + mtr_policy->initialized = 1; + rte_spinlock_lock(&priv->hw_ctrl_lock); + mtr_policy->hws_item_templ = + rte_flow_pattern_template_create(dev->data->port_id, + &pta, pattern, NULL); + if (!mtr_policy->hws_item_templ) + goto policy_add_err; + for (i = 0; i < RTE_COLORS; i++) { + if (mtr_policy->skip_g && i == RTE_COLOR_GREEN) + continue; + if (mtr_policy->skip_y && i == RTE_COLOR_YELLOW) + continue; + if (mtr_policy->skip_r && i == RTE_COLOR_RED) + continue; + mtr_policy->hws_act_templ[nb_colors] = + rte_flow_actions_template_create(dev->data->port_id, + &ata, policy->actions[i], + policy->actions[i], NULL); + if (!mtr_policy->hws_act_templ[nb_colors]) + goto policy_add_err; + nb_colors++; + } + for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) { + memset(&ta, 0, sizeof(ta)); + ta.nb_flows = RTE_COLORS; + ta.flow_attr.group = mtr_policy->group; + if (i == MLX5_MTR_DOMAIN_INGRESS) { + if (!mtr_policy->ingress) + continue; + ta.flow_attr.ingress = 1; + } else if (i == MLX5_MTR_DOMAIN_EGRESS) { + if (!mtr_policy->egress) + continue; + ta.flow_attr.egress = 1; + } else if (i == MLX5_MTR_DOMAIN_TRANSFER) { + if (!mtr_policy->transfer) + continue; + ta.flow_attr.transfer = 1; + } + mtr_policy->hws_flow_table[i] = + rte_flow_template_table_create(dev->data->port_id, + &ta, &mtr_policy->hws_item_templ, 1, + mtr_policy->hws_act_templ, nb_colors, + NULL); + if (!mtr_policy->hws_flow_table[i]) + goto policy_add_err; + nb_colors = 0; + for (j = 0; j < RTE_COLORS; j++) { + if (mtr_policy->skip_g && j == RTE_COLOR_GREEN) + continue; + if (mtr_policy->skip_y && j == RTE_COLOR_YELLOW) + continue; + if (mtr_policy->skip_r && j == RTE_COLOR_RED) + continue; + color = rte_col_2_mlx5_col((enum rte_color)j); + tag_spec.data = color; + mtr_policy->hws_flow_rule[i][j] = + rte_flow_async_create(dev->data->port_id, + CTRL_QUEUE_ID(priv), &op_attr, + mtr_policy->hws_flow_table[i], + pattern, 0, policy->actions[j], + nb_colors, NULL, NULL); + if (!mtr_policy->hws_flow_rule[i][j]) + goto policy_add_err; + nb_colors++; + nb_flows++; + } + ret = rte_flow_push(dev->data->port_id, + CTRL_QUEUE_ID(priv), NULL); + if (ret < 0) + goto policy_add_err; + while (nb_flows) { + ret = rte_flow_pull(dev->data->port_id, + CTRL_QUEUE_ID(priv), result, + nb_flows, NULL); + if (ret < 0) + goto policy_add_err; + for (j = 0; j < ret; j++) { + if (result[j].status == RTE_FLOW_OP_ERROR) + goto policy_add_err; + } + nb_flows -= ret; + } + } + rte_spinlock_unlock(&priv->hw_ctrl_lock); + return 0; +policy_add_err: + rte_spinlock_unlock(&priv->hw_ctrl_lock); + ret = mlx5_flow_meter_policy_hws_delete(dev, policy_id, error); + memset(mtr_policy, 0, sizeof(struct mlx5_flow_meter_policy)); + if (ret) + return ret; + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, "Failed to create meter policy."); +} + /** * Check meter validation. * @@ -1087,7 +1565,8 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv, if (priv->sh->meter_aso_en) { fm->is_enable = !!is_enable; aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); - ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr); + ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr, + &priv->mtr_bulk); if (ret) return ret; ret = mlx5_aso_mtr_wait(priv->sh, aso_mtr); @@ -1336,7 +1815,8 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id, /* If ASO meter supported, update ASO flow meter by wqe. */ if (priv->sh->meter_aso_en) { aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); - ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr); + ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr, + &priv->mtr_bulk); if (ret) goto error; if (!priv->mtr_idx_tbl) { @@ -1369,6 +1849,90 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id, NULL, "Failed to create devx meter."); } +/** + * Create meter rules. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] meter_id + * Meter id. + * @param[in] params + * Pointer to rte meter parameters. + * @param[in] shared + * Meter shared with other flow or not. + * @param[out] error + * Pointer to rte meter error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_hws_create(struct rte_eth_dev *dev, uint32_t meter_id, + struct rte_mtr_params *params, int shared, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_flow_meter_profile *profile; + struct mlx5_flow_meter_info *fm; + struct mlx5_flow_meter_policy *policy = NULL; + struct mlx5_aso_mtr *aso_mtr; + int ret; + + if (!priv->mtr_profile_arr || + !priv->mtr_policy_arr || + !priv->mtr_bulk.aso) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, + "Meter bulk array is not allocated."); + /* Meter profile must exist. */ + profile = mlx5_flow_meter_profile_find(priv, params->meter_profile_id); + if (!profile->initialized) + return -rte_mtr_error_set(error, ENOENT, + RTE_MTR_ERROR_TYPE_METER_PROFILE_ID, + NULL, "Meter profile id not valid."); + /* Meter policy must exist. */ + policy = mlx5_flow_meter_policy_find(dev, + params->meter_policy_id, NULL); + if (!policy->initialized) + return -rte_mtr_error_set(error, ENOENT, + RTE_MTR_ERROR_TYPE_METER_POLICY_ID, + NULL, "Meter policy id not valid."); + /* Meter ID must be valid. */ + if (meter_id >= priv->mtr_config.nb_meters) + return -rte_mtr_error_set(error, EINVAL, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, "Meter id not valid."); + /* Find ASO object. */ + aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id); + fm = &aso_mtr->fm; + if (fm->initialized) + return -rte_mtr_error_set(error, ENOENT, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, "Meter object already exists."); + /* Fill the flow meter parameters. */ + fm->meter_id = meter_id; + fm->policy_id = params->meter_policy_id; + fm->profile = profile; + fm->meter_offset = meter_id; + fm->group = policy->group; + /* Add to the flow meter list. */ + fm->active_state = 1; /* Config meter starts as active. */ + fm->is_enable = params->meter_enable; + fm->shared = !!shared; + fm->initialized = 1; + /* Update ASO flow meter by wqe. */ + ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr, + &priv->mtr_bulk); + if (ret) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, "Failed to create devx meter."); + fm->active_state = params->meter_enable; + __atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED); + __atomic_add_fetch(&policy->ref_cnt, 1, __ATOMIC_RELAXED); + return 0; +} + static int mlx5_flow_meter_params_flush(struct rte_eth_dev *dev, struct mlx5_flow_meter_info *fm, @@ -1475,6 +2039,58 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id, return 0; } +/** + * Destroy meter rules. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] meter_id + * Meter id. + * @param[out] error + * Pointer to rte meter error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_flow_meter_hws_destroy(struct rte_eth_dev *dev, uint32_t meter_id, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr *aso_mtr; + struct mlx5_flow_meter_info *fm; + struct mlx5_flow_meter_policy *policy; + + if (!priv->mtr_profile_arr || + !priv->mtr_policy_arr || + !priv->mtr_bulk.aso) + return -rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_METER_POLICY, NULL, + "Meter bulk array is not allocated."); + /* Find ASO object. */ + aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id); + fm = &aso_mtr->fm; + if (!fm->initialized) + return -rte_mtr_error_set(error, ENOENT, + RTE_MTR_ERROR_TYPE_MTR_ID, + NULL, "Meter object id not valid."); + /* Meter object must not have any owner. */ + if (fm->ref_cnt > 0) + return -rte_mtr_error_set(error, EBUSY, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter object is being used."); + /* Destroy the meter profile. */ + __atomic_sub_fetch(&fm->profile->ref_cnt, + 1, __ATOMIC_RELAXED); + /* Destroy the meter policy. */ + policy = mlx5_flow_meter_policy_find(dev, + fm->policy_id, NULL); + __atomic_sub_fetch(&policy->ref_cnt, + 1, __ATOMIC_RELAXED); + memset(fm, 0, sizeof(struct mlx5_flow_meter_info)); + return 0; +} + /** * Modify meter state. * @@ -1798,6 +2414,23 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = { .stats_read = mlx5_flow_meter_stats_read, }; +static const struct rte_mtr_ops mlx5_flow_mtr_hws_ops = { + .capabilities_get = mlx5_flow_mtr_cap_get, + .meter_profile_add = mlx5_flow_meter_profile_hws_add, + .meter_profile_delete = mlx5_flow_meter_profile_hws_delete, + .meter_policy_validate = mlx5_flow_meter_policy_hws_validate, + .meter_policy_add = mlx5_flow_meter_policy_hws_add, + .meter_policy_delete = mlx5_flow_meter_policy_hws_delete, + .create = mlx5_flow_meter_hws_create, + .destroy = mlx5_flow_meter_hws_destroy, + .meter_enable = mlx5_flow_meter_enable, + .meter_disable = mlx5_flow_meter_disable, + .meter_profile_update = mlx5_flow_meter_profile_update, + .meter_dscp_table_update = NULL, + .stats_update = NULL, + .stats_read = NULL, +}; + /** * Get meter operations. * @@ -1812,7 +2445,12 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = { int mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg) { - *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops; + struct mlx5_priv *priv = dev->data->dev_private; + + if (priv->sh->config.dv_flow_en == 2) + *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_hws_ops; + else + *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops; return 0; } @@ -1841,6 +2479,12 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id, union mlx5_l3t_data data; uint16_t n_valid; + if (priv->mtr_bulk.aso) { + if (mtr_idx) + *mtr_idx = meter_id; + aso_mtr = priv->mtr_bulk.aso + meter_id; + return &aso_mtr->fm; + } if (priv->sh->meter_aso_en) { rte_rwlock_read_lock(&pools_mng->resize_mtrwl); n_valid = pools_mng->n_valid; @@ -2185,6 +2829,7 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error) struct mlx5_flow_meter_profile *fmp; struct mlx5_legacy_flow_meter *legacy_fm; struct mlx5_flow_meter_info *fm; + struct mlx5_flow_meter_policy *policy; struct mlx5_flow_meter_sub_policy *sub_policy; void *tmp; uint32_t i, mtr_idx, policy_idx; @@ -2219,6 +2864,14 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error) NULL, "MTR object meter profile invalid."); } } + if (priv->mtr_bulk.aso) { + for (i = 1; i <= priv->mtr_config.nb_meter_profiles; i++) { + aso_mtr = mlx5_aso_meter_by_idx(priv, i); + fm = &aso_mtr->fm; + if (fm->initialized) + mlx5_flow_meter_hws_destroy(dev, i, error); + } + } if (priv->policy_idx_tbl) { MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) { policy_idx = *(uint32_t *)entry; @@ -2244,6 +2897,15 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error) mlx5_l3t_destroy(priv->policy_idx_tbl); priv->policy_idx_tbl = NULL; } + if (priv->mtr_policy_arr) { + for (i = 0; i < priv->mtr_config.nb_meter_policies; i++) { + policy = mlx5_flow_meter_policy_find(dev, i, + &policy_idx); + if (policy->initialized) + mlx5_flow_meter_policy_hws_delete(dev, i, + error); + } + } if (priv->mtr_profile_tbl) { MLX5_L3T_FOREACH(priv->mtr_profile_tbl, i, entry) { fmp = entry; @@ -2257,9 +2919,21 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error) mlx5_l3t_destroy(priv->mtr_profile_tbl); priv->mtr_profile_tbl = NULL; } + if (priv->mtr_profile_arr) { + for (i = 0; i < priv->mtr_config.nb_meter_profiles; i++) { + fmp = mlx5_flow_meter_profile_find(priv, i); + if (fmp->initialized) + mlx5_flow_meter_profile_hws_delete(dev, i, + error); + } + } /* Delete default policy table. */ mlx5_flow_destroy_def_policy(dev); if (priv->sh->refcnt == 1) mlx5_flow_destroy_mtr_drop_tbls(dev); +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + /* Destroy HWS configuration. */ + mlx5_flow_meter_uninit(dev); +#endif return 0; } From patchwork Fri Sep 30 12:53:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117217 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 1A1DBA00C4; Fri, 30 Sep 2022 14:54:35 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 97FE642B76; Fri, 30 Sep 2022 14:54:02 +0200 (CEST) Received: from NAM10-MW2-obe.outbound.protection.outlook.com (mail-mw2nam10on2076.outbound.protection.outlook.com [40.107.94.76]) by mails.dpdk.org (Postfix) with ESMTP id 08B2142B83 for ; Fri, 30 Sep 2022 14:54:01 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=VR9x9R5m0NyeKtxVoDMq89f35TfiImtiS8JUGJwqKiV4dEw1ugkFaAdo2ufL2qYoEeaOg9DWrBa46UIkSIsTofwuOwEAizrJhjLvifrXj54d36UWU/hEDiMp9FQayIOgJ6Elnif5Eg/+1WECID6IwDE1ZjTcxn2E6tiZB1KoL+VDuNDYuhNMvVudagXCnsQ6hV0QyoZJ4vSyHSHdrqNYPhZBB7fQ5+nmXwovaGg4PhV0sVnVf2+69AklVOLBzq8IQADqwKb5Zpxi4avO95NKaP/90xkC3mcOiUTYLz4ScNzCK4A/v7prus1ydu3RyWC685Yrt5TifYwuT6IqHvJJBw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=r2wmDWH0haKeT+5FY/6qI28oWAqoJrAQCuxxwgmxxG0=; b=dpCT9WdcQG2BpYJe+IQjivJdTqhf4z7pr9LFYsJDBbBXdl85E4d15OxbIoyHxIfTyJQ4haXwd1HU6K5pBTn9ZazjU5WaHwkbP7LK+zhrNdK+Pplfvjz9Mo3AIpx4MliTpgj//IcYxCyAsnrDoqRgXHoeSmRujxYNUEE/ugj5puntC+o0XWcbh4Bb/RVQmdjYy380rszklCEq2SOqrecvyNWHxYA4OW+kh1PcQL7N5SjCRg/GkhfM1/x3iBDXlFDDjAy5hDWZE8YkQVKob97r5wAH2+yFKW/LcT6RI9X8jM2jlZVOShb/NiBmZebFSSrSyunZ5tHhDhEJXKadY8q13A== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.161) smtp.rcpttodomain=ashroe.eu smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=r2wmDWH0haKeT+5FY/6qI28oWAqoJrAQCuxxwgmxxG0=; b=CxkB/M2fhYXID1qEaJoccT5MFgtWi9XCWaED7r/FRLHnrwgSQ3GzEjZTu+54XFDh2IYooQbRhOxIXfzXS0XggsIuIbJAJo/VeW0jE6knMHuu/c4ij7x9RCBnXeAsG+dis22gQIu1GCxO63jWTk1rAXD67gIgy4Qz61J573PbhUablIF7deWOIBxGMUe7VZhCDtP9TR0rfhc9jiq6D0JdFkAIDPmlO4IC9s1+OSzPuQkG98IERX/02Fyb7eiDWvS/0U/2OHjYHp1oNSoijqn1yG7kIVR0n6a7k3HuhzaEHDn9BeMF97ghEHsskkGAZerGQHYutaZL8YTwT1/OtTChOw== Received: from DS7PR03CA0143.namprd03.prod.outlook.com (2603:10b6:5:3b4::28) by CY5PR12MB6180.namprd12.prod.outlook.com (2603:10b6:930:23::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17; Fri, 30 Sep 2022 12:53:56 +0000 Received: from DM6NAM11FT102.eop-nam11.prod.protection.outlook.com (2603:10b6:5:3b4:cafe::bf) by DS7PR03CA0143.outlook.office365.com (2603:10b6:5:3b4::28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23 via Frontend Transport; Fri, 30 Sep 2022 12:53:55 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.161) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.161 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.161; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.161) by DM6NAM11FT102.mail.protection.outlook.com (10.13.173.172) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:53:55 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.67) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:51 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:49 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko , Ray Kinsella CC: , , , Xiaoyu Min Subject: [PATCH v3 08/17] net/mlx5: add HW steering counter action Date: Fri, 30 Sep 2022 15:53:06 +0300 Message-ID: <20220930125315.5079-9-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT102:EE_|CY5PR12MB6180:EE_ X-MS-Office365-Filtering-Correlation-Id: 7d53f3d2-65da-4393-a7d5-08daa2e2d5b5 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: dp1tLRNsRo4wW9QEJABGAWzyk8M0iOkhz3EvpwgmqN+g62e4iaKqUIUPCRQTE2gvp3Bxmb/BVMaofsMfn9Tism+eo2tfTiuT+r7fmAIdXEKTMDbXtlHcq57hDS5p8TAQ2jLyrNcE6qk3/PWvf7lfgZLcGtLYT6BWkexDWhyrMzL8Ae6yAoLP5elEcJ/fN+0eDUnVPUHjSRtyBaJxEK35BwV5os3nvNUKwurEXEQiPIr0LkIDnvuD8lRSGIFUu242XPr2csPiXXTm4+OwSqNBRe/0OGcVbhlFDdpkgBEokpbj9OY1kb96xQevddwY7+Yz6cWXxjbZmsSXaFcxrQsKd/61tJqpHoSDaG4ZzZgtsT/w16lpBBjZB/7xKTNV+uM3wPRuqdoKozyelkX/P5VjAIykpKDPQFN+bglIOngDDsMPyw6UOFRyFMJE0pnzOoKg7r6BUuQW/9zTm96r9trKztAwWCLasXV2hrmz0zPdEyGa2GEhKXJiSnwQu+zYpymlwN5hAYCKjiuBvViR41gGmJcyYSXez6xMsqDLoKZOK8ldHMS7uhW/Ow7hzAYvldTytl4ag7GUTjTf1V/M2ySQM2yzNtfTlTH3/vNZDByY+Rc1s9Zp2Qe8hJSGvtwcbEJtAbHicmdIKsYy0chONobuChLkZPsovz2y++L4WRnwfw5zKVC4cWlN553KrqneyZS1TyhY3h+RJEY0aW6Mnuex7nnZUEWeOIlritrKe1gpyCp+ki6EuHUnN07tuxy9uj3S8A0X79ld2ikeZqYgPCvuEpQyY4L7Z5eTfGLxRr6ztcM= X-Forefront-Antispam-Report: CIP:216.228.117.161; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge2.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(396003)(39860400002)(136003)(376002)(346002)(451199015)(36840700001)(46966006)(40470700004)(36860700001)(86362001)(4326008)(6286002)(7636003)(356005)(40480700001)(83380400001)(70586007)(40460700003)(110136005)(82740400003)(8676002)(36756003)(54906003)(316002)(70206006)(426003)(41300700001)(336012)(55016003)(2906002)(5660300002)(30864003)(16526019)(1076003)(2616005)(47076005)(186003)(8936002)(478600001)(107886003)(6666004)(82310400005)(26005)(7696005)(579004)(559001)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:53:55.6544 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7d53f3d2-65da-4393-a7d5-08daa2e2d5b5 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.161]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT102.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6180 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Xiaoyu Min This commit adds HW steering counter action support. Pool mechanism is the basic data structure for the HW steering counter. The HW steering's counter pool is based on the rte_ring of zero-copy variation. There are two global rte_rings: 1. free_list: Store the counters indexes, which are ready for use. 2. wait_reset_list: Store the counters indexes, which are just freed from the user and need to query the hardware counter to get the reset value before this counter can be reused again. The counter pool also supports cache per HW steering's queues, which are also based on rte_ring of zero-copy variation. The cache can be configured in size, preload, threshold, and fetch size, they are all exposed via device args. The main operations of the counter pool are as follows: - Get one counter from the pool: 1. The user call _get_* API. 2. If the cache is enabled, dequeue one counter index from the local cache: 2.A: if the dequeued one from the local cache is still in reset status (counter's query_gen_when_free is equal to pool's query gen): I. Flush all counters in local cache back to global wait_reset_list. II. Fetch _fetch_sz_ counters into the cache from the global free list. III. Fetch one counter from the cache. 3. If the cache is empty, fetch _fetch_sz_ counters from the global free list into the cache and fetch one counter from the cache. - Free one counter into the pool: 1. The user calls _put_* API. 2. Put the counter into the local cache. 3. If the local cache is full: 3.A: Write back all counters above _threshold_ into the global wait_reset_list. 3.B: Also, write back this counter into the global wait_reset_list. When the local cache is disabled, _get_/_put_ cache directly from/into global list. Signed-off-by: Xiaoyu Min --- drivers/common/mlx5/mlx5_devx_cmds.c | 50 +++ drivers/common/mlx5/mlx5_devx_cmds.h | 27 ++ drivers/common/mlx5/mlx5_prm.h | 62 ++- drivers/common/mlx5/version.map | 1 + drivers/net/mlx5/meson.build | 1 + drivers/net/mlx5/mlx5.c | 14 + drivers/net/mlx5/mlx5.h | 27 ++ drivers/net/mlx5/mlx5_defs.h | 2 + drivers/net/mlx5/mlx5_flow.c | 27 +- drivers/net/mlx5/mlx5_flow.h | 5 + drivers/net/mlx5/mlx5_flow_aso.c | 261 ++++++++++++- drivers/net/mlx5/mlx5_flow_hw.c | 340 +++++++++++++++- drivers/net/mlx5/mlx5_hws_cnt.c | 528 +++++++++++++++++++++++++ drivers/net/mlx5/mlx5_hws_cnt.h | 558 +++++++++++++++++++++++++++ 14 files changed, 1871 insertions(+), 32 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_hws_cnt.c create mode 100644 drivers/net/mlx5/mlx5_hws_cnt.h diff --git a/drivers/common/mlx5/mlx5_devx_cmds.c b/drivers/common/mlx5/mlx5_devx_cmds.c index ac6891145d..eef7a98248 100644 --- a/drivers/common/mlx5/mlx5_devx_cmds.c +++ b/drivers/common/mlx5/mlx5_devx_cmds.c @@ -176,6 +176,41 @@ mlx5_devx_cmd_register_write(void *ctx, uint16_t reg_id, uint32_t arg, return 0; } +struct mlx5_devx_obj * +mlx5_devx_cmd_flow_counter_alloc_general(void *ctx, + struct mlx5_devx_counter_attr *attr) +{ + struct mlx5_devx_obj *dcs = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*dcs), + 0, SOCKET_ID_ANY); + uint32_t in[MLX5_ST_SZ_DW(alloc_flow_counter_in)] = {0}; + uint32_t out[MLX5_ST_SZ_DW(alloc_flow_counter_out)] = {0}; + + if (!dcs) { + rte_errno = ENOMEM; + return NULL; + } + MLX5_SET(alloc_flow_counter_in, in, opcode, + MLX5_CMD_OP_ALLOC_FLOW_COUNTER); + if (attr->bulk_log_max_alloc) + MLX5_SET(alloc_flow_counter_in, in, flow_counter_bulk_log_size, + attr->flow_counter_bulk_log_size); + else + MLX5_SET(alloc_flow_counter_in, in, flow_counter_bulk, + attr->bulk_n_128); + if (attr->pd_valid) + MLX5_SET(alloc_flow_counter_in, in, pd, attr->pd); + dcs->obj = mlx5_glue->devx_obj_create(ctx, in, + sizeof(in), out, sizeof(out)); + if (!dcs->obj) { + DRV_LOG(ERR, "Can't allocate counters - error %d", errno); + rte_errno = errno; + mlx5_free(dcs); + return NULL; + } + dcs->id = MLX5_GET(alloc_flow_counter_out, out, flow_counter_id); + return dcs; +} + /** * Allocate flow counters via devx interface. * @@ -967,6 +1002,16 @@ mlx5_devx_cmd_query_hca_attr(void *ctx, general_obj_types) & MLX5_GENERAL_OBJ_TYPES_CAP_CONN_TRACK_OFFLOAD); attr->rq_delay_drop = MLX5_GET(cmd_hca_cap, hcattr, rq_delay_drop); + attr->max_flow_counter_15_0 = MLX5_GET(cmd_hca_cap, hcattr, + max_flow_counter_15_0); + attr->max_flow_counter_31_16 = MLX5_GET(cmd_hca_cap, hcattr, + max_flow_counter_31_16); + attr->alloc_flow_counter_pd = MLX5_GET(cmd_hca_cap, hcattr, + alloc_flow_counter_pd); + attr->flow_counter_access_aso = MLX5_GET(cmd_hca_cap, hcattr, + flow_counter_access_aso); + attr->flow_access_aso_opc_mod = MLX5_GET(cmd_hca_cap, hcattr, + flow_access_aso_opc_mod); if (attr->crypto) { attr->aes_xts = MLX5_GET(cmd_hca_cap, hcattr, aes_xts); hcattr = mlx5_devx_get_hca_cap(ctx, in, out, &rc, @@ -989,6 +1034,11 @@ mlx5_devx_cmd_query_hca_attr(void *ctx, } attr->log_min_stride_wqe_sz = MLX5_GET(cmd_hca_cap_2, hcattr, log_min_stride_wqe_sz); + attr->flow_counter_bulk_log_max_alloc = MLX5_GET(cmd_hca_cap_2, + hcattr, flow_counter_bulk_log_max_alloc); + attr->flow_counter_bulk_log_granularity = + MLX5_GET(cmd_hca_cap_2, hcattr, + flow_counter_bulk_log_granularity); } if (attr->log_min_stride_wqe_sz == 0) attr->log_min_stride_wqe_sz = MLX5_MPRQ_LOG_MIN_STRIDE_WQE_SIZE; diff --git a/drivers/common/mlx5/mlx5_devx_cmds.h b/drivers/common/mlx5/mlx5_devx_cmds.h index d69dad613e..15b46f2acd 100644 --- a/drivers/common/mlx5/mlx5_devx_cmds.h +++ b/drivers/common/mlx5/mlx5_devx_cmds.h @@ -15,6 +15,16 @@ #define MLX5_DEVX_MAX_KLM_ENTRIES ((UINT16_MAX - \ MLX5_ST_SZ_DW(create_mkey_in) * 4) / (MLX5_ST_SZ_DW(klm) * 4)) +struct mlx5_devx_counter_attr { + uint32_t pd_valid:1; + uint32_t pd:24; + uint32_t bulk_log_max_alloc:1; + union { + uint8_t flow_counter_bulk_log_size; + uint8_t bulk_n_128; + }; +}; + struct mlx5_devx_mkey_attr { uint64_t addr; uint64_t size; @@ -263,6 +273,18 @@ struct mlx5_hca_attr { uint32_t set_reg_c:8; uint32_t nic_flow_table:1; uint32_t modify_outer_ip_ecn:1; + union { + uint32_t max_flow_counter; + struct { + uint16_t max_flow_counter_15_0; + uint16_t max_flow_counter_31_16; + }; + }; + uint32_t flow_counter_bulk_log_max_alloc:5; + uint32_t flow_counter_bulk_log_granularity:5; + uint32_t alloc_flow_counter_pd:1; + uint32_t flow_counter_access_aso:1; + uint32_t flow_access_aso_opc_mod:8; }; /* LAG Context. */ @@ -593,6 +615,11 @@ struct mlx5_devx_crypto_login_attr { /* mlx5_devx_cmds.c */ +__rte_internal +struct mlx5_devx_obj * +mlx5_devx_cmd_flow_counter_alloc_general(void *ctx, + struct mlx5_devx_counter_attr *attr); + __rte_internal struct mlx5_devx_obj *mlx5_devx_cmd_flow_counter_alloc(void *ctx, uint32_t bulk_sz); diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h index c82ec94465..8514ca8fc4 100644 --- a/drivers/common/mlx5/mlx5_prm.h +++ b/drivers/common/mlx5/mlx5_prm.h @@ -1161,8 +1161,10 @@ struct mlx5_ifc_alloc_flow_counter_in_bits { u8 reserved_at_10[0x10]; u8 reserved_at_20[0x10]; u8 op_mod[0x10]; - u8 flow_counter_id[0x20]; - u8 reserved_at_40[0x18]; + u8 reserved_at_40[0x8]; + u8 pd[0x18]; + u8 reserved_at_60[0x13]; + u8 flow_counter_bulk_log_size[0x5]; u8 flow_counter_bulk[0x8]; }; @@ -1382,7 +1384,13 @@ enum { #define MLX5_STEERING_LOGIC_FORMAT_CONNECTX_6DX 0x1 struct mlx5_ifc_cmd_hca_cap_bits { - u8 reserved_at_0[0x20]; + u8 access_other_hca_roce[0x1]; + u8 alloc_flow_counter_pd[0x1]; + u8 flow_counter_access_aso[0x1]; + u8 reserved_at_3[0x5]; + u8 flow_access_aso_opc_mod[0x8]; + u8 reserved_at_10[0xf]; + u8 vhca_resource_manager[0x1]; u8 hca_cap_2[0x1]; u8 reserved_at_21[0xf]; u8 vhca_id[0x10]; @@ -2058,8 +2066,52 @@ struct mlx5_ifc_cmd_hca_cap_2_bits { u8 log_conn_track_max_alloc[0x5]; u8 reserved_at_d8[0x3]; u8 log_max_conn_track_offload[0x5]; - u8 reserved_at_e0[0x20]; /* End of DW7. */ - u8 reserved_at_100[0x700]; + u8 reserved_at_e0[0xc0]; + u8 reserved_at_1a0[0xb]; + u8 format_select_dw_8_6_ext[0x1]; + u8 reserved_at_1ac[0x14]; + u8 general_obj_types_127_64[0x40]; + u8 reserved_at_200[0x53]; + u8 flow_counter_bulk_log_max_alloc[0x5]; + u8 reserved_at_258[0x3]; + u8 flow_counter_bulk_log_granularity[0x5]; + u8 reserved_at_260[0x20]; + u8 format_select_dw_gtpu_dw_0[0x8]; + u8 format_select_dw_gtpu_dw_1[0x8]; + u8 format_select_dw_gtpu_dw_2[0x8]; + u8 format_select_dw_gtpu_first_ext_dw_0[0x8]; + u8 reserved_at_2a0[0x560]; +}; + +struct mlx5_ifc_wqe_based_flow_table_cap_bits { + u8 reserved_at_0[0x3]; + u8 log_max_num_ste[0x5]; + u8 reserved_at_8[0x3]; + u8 log_max_num_stc[0x5]; + u8 reserved_at_10[0x3]; + u8 log_max_num_rtc[0x5]; + u8 reserved_at_18[0x3]; + u8 log_max_num_header_modify_pattern[0x5]; + u8 reserved_at_20[0x3]; + u8 stc_alloc_log_granularity[0x5]; + u8 reserved_at_28[0x3]; + u8 stc_alloc_log_max[0x5]; + u8 reserved_at_30[0x3]; + u8 ste_alloc_log_granularity[0x5]; + u8 reserved_at_38[0x3]; + u8 ste_alloc_log_max[0x5]; + u8 reserved_at_40[0xb]; + u8 rtc_reparse_mode[0x5]; + u8 reserved_at_50[0x3]; + u8 rtc_index_mode[0x5]; + u8 reserved_at_58[0x3]; + u8 rtc_log_depth_max[0x5]; + u8 reserved_at_60[0x10]; + u8 ste_format[0x10]; + u8 stc_action_type[0x80]; + u8 header_insert_type[0x10]; + u8 header_remove_type[0x10]; + u8 trivial_match_definer[0x20]; }; struct mlx5_ifc_esw_cap_bits { diff --git a/drivers/common/mlx5/version.map b/drivers/common/mlx5/version.map index 413dec14ab..4f72900519 100644 --- a/drivers/common/mlx5/version.map +++ b/drivers/common/mlx5/version.map @@ -40,6 +40,7 @@ INTERNAL { mlx5_devx_cmd_create_virtq; mlx5_devx_cmd_destroy; mlx5_devx_cmd_flow_counter_alloc; + mlx5_devx_cmd_flow_counter_alloc_general; mlx5_devx_cmd_flow_counter_query; mlx5_devx_cmd_flow_dump; mlx5_devx_cmd_flow_single_dump; diff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build index 6a84d96380..f2d7bcaff6 100644 --- a/drivers/net/mlx5/meson.build +++ b/drivers/net/mlx5/meson.build @@ -38,6 +38,7 @@ sources = files( 'mlx5_vlan.c', 'mlx5_utils.c', 'mlx5_devx.c', + 'mlx5_hws_cnt.c', ) if is_linux diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index cf5146d677..b6a66f12ee 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -175,6 +175,12 @@ /* Device parameter to create the fdb default rule in PMD */ #define MLX5_FDB_DEFAULT_RULE_EN "fdb_def_rule_en" +/* HW steering counter configuration. */ +#define MLX5_HWS_CNT_SERVICE_CORE "service_core" + +/* HW steering counter's query interval. */ +#define MLX5_HWS_CNT_CYCLE_TIME "svc_cycle_time" + /* Shared memory between primary and secondary processes. */ struct mlx5_shared_data *mlx5_shared_data; @@ -1245,6 +1251,10 @@ mlx5_dev_args_check_handler(const char *key, const char *val, void *opaque) config->allow_duplicate_pattern = !!tmp; } else if (strcmp(MLX5_FDB_DEFAULT_RULE_EN, key) == 0) { config->fdb_def_rule = !!tmp; + } else if (strcmp(MLX5_HWS_CNT_SERVICE_CORE, key) == 0) { + config->cnt_svc.service_core = tmp; + } else if (strcmp(MLX5_HWS_CNT_CYCLE_TIME, key) == 0) { + config->cnt_svc.cycle_time = tmp; } return 0; } @@ -1281,6 +1291,8 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, MLX5_DECAP_EN, MLX5_ALLOW_DUPLICATE_PATTERN, MLX5_FDB_DEFAULT_RULE_EN, + MLX5_HWS_CNT_SERVICE_CORE, + MLX5_HWS_CNT_CYCLE_TIME, NULL, }; int ret = 0; @@ -1293,6 +1305,8 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, config->decap_en = 1; config->allow_duplicate_pattern = 1; config->fdb_def_rule = 1; + config->cnt_svc.cycle_time = MLX5_CNT_SVC_CYCLE_TIME_DEFAULT; + config->cnt_svc.service_core = rte_get_main_lcore(); if (mkvlist != NULL) { /* Process parameters. */ ret = mlx5_kvargs_process(mkvlist, params, diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 686969719a..4859f5a509 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -308,6 +308,10 @@ struct mlx5_sh_config { uint32_t hw_fcs_strip:1; /* FCS stripping is supported. */ uint32_t allow_duplicate_pattern:1; uint32_t lro_allowed:1; /* Whether LRO is allowed. */ + struct { + uint16_t service_core; + uint32_t cycle_time; /* query cycle time in milli-second. */ + } cnt_svc; /* configure for HW steering's counter's service. */ /* Allow/Prevent the duplicate rules pattern. */ uint32_t fdb_def_rule:1; /* Create FDB default jump rule */ }; @@ -1224,6 +1228,22 @@ struct mlx5_flex_item { struct mlx5_flex_pattern_field map[MLX5_FLEX_ITEM_MAPPING_NUM]; }; +#define HWS_CNT_ASO_SQ_NUM 4 + +struct mlx5_hws_aso_mng { + uint16_t sq_num; + struct mlx5_aso_sq sqs[HWS_CNT_ASO_SQ_NUM]; +}; + +struct mlx5_hws_cnt_svc_mng { + uint32_t refcnt; + uint32_t service_core; + uint32_t query_interval; + pthread_t service_thread; + uint8_t svc_running; + struct mlx5_hws_aso_mng aso_mng __rte_cache_aligned; +}; + /* * Shared Infiniband device context for Master/Representors * which belong to same IB device with multiple IB ports. @@ -1323,6 +1343,7 @@ struct mlx5_dev_ctx_shared { pthread_mutex_t lwm_config_lock; uint32_t host_shaper_rate:8; uint32_t lwm_triggered:1; + struct mlx5_hws_cnt_svc_mng *cnt_svc; struct mlx5_dev_shared_port port[]; /* per device port data array. */ }; @@ -1607,6 +1628,7 @@ struct mlx5_priv { /* Flex items have been created on the port. */ uint32_t flex_item_map; /* Map of allocated flex item elements. */ uint32_t nb_queue; /* HW steering queue number. */ + struct mlx5_hws_cnt_pool *hws_cpool; /* HW steering's counter pool. */ #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) /* Item template list. */ LIST_HEAD(flow_hw_itt, rte_flow_pattern_template) flow_hw_itt; @@ -2037,6 +2059,11 @@ mlx5_get_supported_sw_parsing_offloads(const struct mlx5_hca_attr *attr); uint32_t mlx5_get_supported_tunneling_offloads(const struct mlx5_hca_attr *attr); +int mlx5_aso_cnt_queue_init(struct mlx5_dev_ctx_shared *sh); +void mlx5_aso_cnt_queue_uninit(struct mlx5_dev_ctx_shared *sh); +int mlx5_aso_cnt_query(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool); + /* mlx5_flow_flex.c */ struct rte_flow_item_flex_handle * diff --git a/drivers/net/mlx5/mlx5_defs.h b/drivers/net/mlx5/mlx5_defs.h index 585afb0a98..d064abfef3 100644 --- a/drivers/net/mlx5/mlx5_defs.h +++ b/drivers/net/mlx5/mlx5_defs.h @@ -188,4 +188,6 @@ #define static_assert _Static_assert #endif +#define MLX5_CNT_SVC_CYCLE_TIME_DEFAULT 500 + #endif /* RTE_PMD_MLX5_DEFS_H_ */ diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index fb3be940e5..658cc69750 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -7832,24 +7832,33 @@ mlx5_flow_isolate(struct rte_eth_dev *dev, */ static int flow_drv_query(struct rte_eth_dev *dev, - uint32_t flow_idx, + struct rte_flow *eflow, const struct rte_flow_action *actions, void *data, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; const struct mlx5_flow_driver_ops *fops; - struct rte_flow *flow = mlx5_ipool_get(priv->flows[MLX5_FLOW_TYPE_GEN], - flow_idx); - enum mlx5_flow_drv_type ftype; + struct rte_flow *flow = NULL; + enum mlx5_flow_drv_type ftype = MLX5_FLOW_TYPE_MIN; + if (priv->sh->config.dv_flow_en == 2) { +#if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) + flow = eflow; + ftype = MLX5_FLOW_TYPE_HW; +#endif + } else { + flow = (struct rte_flow *)mlx5_ipool_get(priv->flows[MLX5_FLOW_TYPE_GEN], + (uintptr_t)(void *)eflow); + } if (!flow) { return rte_flow_error_set(error, ENOENT, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "invalid flow handle"); } - ftype = flow->drv_type; + if (ftype == MLX5_FLOW_TYPE_MIN) + ftype = flow->drv_type; MLX5_ASSERT(ftype > MLX5_FLOW_TYPE_MIN && ftype < MLX5_FLOW_TYPE_MAX); fops = flow_get_drv_ops(ftype); @@ -7870,14 +7879,8 @@ mlx5_flow_query(struct rte_eth_dev *dev, struct rte_flow_error *error) { int ret; - struct mlx5_priv *priv = dev->data->dev_private; - if (priv->sh->config.dv_flow_en == 2) - return rte_flow_error_set(error, ENOTSUP, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, - "Flow non-Q query not supported"); - ret = flow_drv_query(dev, (uintptr_t)(void *)flow, actions, data, + ret = flow_drv_query(dev, flow, actions, data, error); if (ret < 0) return ret; diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 3bde95c927..8f1b66eaac 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -1103,6 +1103,7 @@ struct rte_flow_hw { }; struct rte_flow_template_table *table; /* The table flow allcated from. */ struct mlx5dr_rule rule; /* HWS layer data struct. */ + uint32_t cnt_id; } __rte_packed; /* rte flow action translate to DR action struct. */ @@ -1146,6 +1147,9 @@ struct mlx5_action_construct_data { uint32_t level; /* RSS level. */ uint32_t idx; /* Shared action index. */ } shared_rss; + struct { + uint32_t id; + } shared_counter; }; }; @@ -1224,6 +1228,7 @@ struct mlx5_hw_actions { uint16_t encap_decap_pos; /* Encap/Decap action position. */ uint32_t acts_num:4; /* Total action number. */ uint32_t mark:1; /* Indicate the mark action. */ + uint32_t cnt_id; /* Counter id. */ /* Translated DR action array from action template. */ struct mlx5dr_rule_action rule_acts[MLX5_HW_MAX_ACTS]; }; diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c index 60d0280367..ed9272e583 100644 --- a/drivers/net/mlx5/mlx5_flow_aso.c +++ b/drivers/net/mlx5/mlx5_flow_aso.c @@ -12,6 +12,9 @@ #include "mlx5.h" #include "mlx5_flow.h" +#include "mlx5_hws_cnt.h" + +#define MLX5_ASO_CNT_QUEUE_LOG_DESC 14 /** * Free MR resources. @@ -79,6 +82,33 @@ mlx5_aso_destroy_sq(struct mlx5_aso_sq *sq) memset(sq, 0, sizeof(*sq)); } +/** + * Initialize Send Queue used for ASO access counter. + * + * @param[in] sq + * ASO SQ to initialize. + */ +static void +mlx5_aso_cnt_init_sq(struct mlx5_aso_sq *sq) +{ + volatile struct mlx5_aso_wqe *restrict wqe; + int i; + int size = 1 << sq->log_desc_n; + + /* All the next fields state should stay constant. */ + for (i = 0, wqe = &sq->sq_obj.aso_wqes[0]; i < size; ++i, ++wqe) { + wqe->general_cseg.sq_ds = rte_cpu_to_be_32((sq->sqn << 8) | + (sizeof(*wqe) >> 4)); + wqe->aso_cseg.operand_masks = rte_cpu_to_be_32 + (0u | + (ASO_OPER_LOGICAL_OR << ASO_CSEG_COND_OPER_OFFSET) | + (ASO_OP_ALWAYS_FALSE << ASO_CSEG_COND_1_OPER_OFFSET) | + (ASO_OP_ALWAYS_FALSE << ASO_CSEG_COND_0_OPER_OFFSET) | + (BYTEWISE_64BYTE << ASO_CSEG_DATA_MASK_MODE_OFFSET)); + wqe->aso_cseg.data_mask = RTE_BE64(UINT64_MAX); + } +} + /** * Initialize Send Queue used for ASO access. * @@ -191,7 +221,7 @@ mlx5_aso_ct_init_sq(struct mlx5_aso_sq *sq) */ static int mlx5_aso_sq_create(struct mlx5_common_device *cdev, struct mlx5_aso_sq *sq, - void *uar) + void *uar, uint16_t log_desc_n) { struct mlx5_devx_cq_attr cq_attr = { .uar_page_id = mlx5_os_get_devx_uar_page_id(uar), @@ -212,12 +242,12 @@ mlx5_aso_sq_create(struct mlx5_common_device *cdev, struct mlx5_aso_sq *sq, int ret; if (mlx5_devx_cq_create(cdev->ctx, &sq->cq.cq_obj, - MLX5_ASO_QUEUE_LOG_DESC, &cq_attr, + log_desc_n, &cq_attr, SOCKET_ID_ANY)) goto error; sq->cq.cq_ci = 0; - sq->cq.log_desc_n = MLX5_ASO_QUEUE_LOG_DESC; - sq->log_desc_n = MLX5_ASO_QUEUE_LOG_DESC; + sq->cq.log_desc_n = log_desc_n; + sq->log_desc_n = log_desc_n; sq_attr.cqn = sq->cq.cq_obj.cq->id; /* for mlx5_aso_wqe that is twice the size of mlx5_wqe */ log_wqbb_n = sq->log_desc_n + 1; @@ -269,7 +299,8 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh, sq_desc_n, &sh->aso_age_mng->aso_sq.mr)) return -1; if (mlx5_aso_sq_create(cdev, &sh->aso_age_mng->aso_sq, - sh->tx_uar.obj)) { + sh->tx_uar.obj, + MLX5_ASO_QUEUE_LOG_DESC)) { mlx5_aso_dereg_mr(cdev, &sh->aso_age_mng->aso_sq.mr); return -1; } @@ -277,7 +308,7 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh, break; case ASO_OPC_MOD_POLICER: if (mlx5_aso_sq_create(cdev, &sh->mtrmng->pools_mng.sq, - sh->tx_uar.obj)) + sh->tx_uar.obj, MLX5_ASO_QUEUE_LOG_DESC)) return -1; mlx5_aso_mtr_init_sq(&sh->mtrmng->pools_mng.sq); break; @@ -287,7 +318,7 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh, &sh->ct_mng->aso_sq.mr)) return -1; if (mlx5_aso_sq_create(cdev, &sh->ct_mng->aso_sq, - sh->tx_uar.obj)) { + sh->tx_uar.obj, MLX5_ASO_QUEUE_LOG_DESC)) { mlx5_aso_dereg_mr(cdev, &sh->ct_mng->aso_sq.mr); return -1; } @@ -1403,3 +1434,219 @@ mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh, rte_errno = EBUSY; return -rte_errno; } + +int +mlx5_aso_cnt_queue_init(struct mlx5_dev_ctx_shared *sh) +{ + struct mlx5_hws_aso_mng *aso_mng = NULL; + uint8_t idx; + struct mlx5_aso_sq *sq; + + MLX5_ASSERT(sh); + MLX5_ASSERT(sh->cnt_svc); + aso_mng = &sh->cnt_svc->aso_mng; + aso_mng->sq_num = HWS_CNT_ASO_SQ_NUM; + for (idx = 0; idx < HWS_CNT_ASO_SQ_NUM; idx++) { + sq = &aso_mng->sqs[idx]; + if (mlx5_aso_sq_create(sh->cdev, sq, sh->tx_uar.obj, + MLX5_ASO_CNT_QUEUE_LOG_DESC)) + goto error; + mlx5_aso_cnt_init_sq(sq); + } + return 0; +error: + mlx5_aso_cnt_queue_uninit(sh); + return -1; +} + +void +mlx5_aso_cnt_queue_uninit(struct mlx5_dev_ctx_shared *sh) +{ + uint16_t idx; + + for (idx = 0; idx < sh->cnt_svc->aso_mng.sq_num; idx++) + mlx5_aso_destroy_sq(&sh->cnt_svc->aso_mng.sqs[idx]); + sh->cnt_svc->aso_mng.sq_num = 0; +} + +static uint16_t +mlx5_aso_cnt_sq_enqueue_burst(struct mlx5_hws_cnt_pool *cpool, + struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_sq *sq, uint32_t n, + uint32_t offset, uint32_t dcs_id_base) +{ + volatile struct mlx5_aso_wqe *wqe; + uint16_t size = 1 << sq->log_desc_n; + uint16_t mask = size - 1; + uint16_t max; + uint32_t upper_offset = offset; + uint64_t addr; + uint32_t ctrl_gen_id = 0; + uint8_t opcmod = sh->cdev->config.hca_attr.flow_access_aso_opc_mod; + rte_be32_t lkey = rte_cpu_to_be_32(cpool->raw_mng->mr.lkey); + uint16_t aso_n = (uint16_t)(RTE_ALIGN_CEIL(n, 4) / 4); + uint32_t ccntid; + + max = RTE_MIN(size - (uint16_t)(sq->head - sq->tail), aso_n); + if (unlikely(!max)) + return 0; + upper_offset += (max * 4); + /* Because only one burst at one time, we can use the same elt. */ + sq->elts[0].burst_size = max; + ctrl_gen_id = dcs_id_base; + ctrl_gen_id /= 4; + do { + ccntid = upper_offset - max * 4; + wqe = &sq->sq_obj.aso_wqes[sq->head & mask]; + rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]); + wqe->general_cseg.misc = rte_cpu_to_be_32(ctrl_gen_id); + wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR << + MLX5_COMP_MODE_OFFSET); + wqe->general_cseg.opcode = rte_cpu_to_be_32 + (MLX5_OPCODE_ACCESS_ASO | + (opcmod << + WQE_CSEG_OPC_MOD_OFFSET) | + (sq->pi << + WQE_CSEG_WQE_INDEX_OFFSET)); + addr = (uint64_t)RTE_PTR_ADD(cpool->raw_mng->raw, + ccntid * sizeof(struct flow_counter_stats)); + wqe->aso_cseg.va_h = rte_cpu_to_be_32((uint32_t)(addr >> 32)); + wqe->aso_cseg.va_l_r = rte_cpu_to_be_32((uint32_t)addr | 1u); + wqe->aso_cseg.lkey = lkey; + sq->pi += 2; /* Each WQE contains 2 WQEBB's. */ + sq->head++; + sq->next++; + ctrl_gen_id++; + max--; + } while (max); + wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS << + MLX5_COMP_MODE_OFFSET); + mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, + sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], + !sh->tx_uar.dbnc); + return sq->elts[0].burst_size; +} + +static uint16_t +mlx5_aso_cnt_completion_handle(struct mlx5_aso_sq *sq) +{ + struct mlx5_aso_cq *cq = &sq->cq; + volatile struct mlx5_cqe *restrict cqe; + const unsigned int cq_size = 1 << cq->log_desc_n; + const unsigned int mask = cq_size - 1; + uint32_t idx; + uint32_t next_idx = cq->cq_ci & mask; + const uint16_t max = (uint16_t)(sq->head - sq->tail); + uint16_t i = 0; + int ret; + if (unlikely(!max)) + return 0; + idx = next_idx; + next_idx = (cq->cq_ci + 1) & mask; + rte_prefetch0(&cq->cq_obj.cqes[next_idx]); + cqe = &cq->cq_obj.cqes[idx]; + ret = check_cqe(cqe, cq_size, cq->cq_ci); + /* + * Be sure owner read is done before any other cookie field or + * opaque field. + */ + rte_io_rmb(); + if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) { + if (likely(ret == MLX5_CQE_STATUS_HW_OWN)) + return 0; /* return immediately. */ + mlx5_aso_cqe_err_handle(sq); + } + i += sq->elts[0].burst_size; + sq->elts[0].burst_size = 0; + cq->cq_ci++; + if (likely(i)) { + sq->tail += i; + rte_io_wmb(); + cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci); + } + return i; +} + +static uint16_t +mlx5_aso_cnt_query_one_dcs(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool, + uint8_t dcs_idx, uint32_t num) +{ + uint32_t dcs_id = cpool->dcs_mng.dcs[dcs_idx].obj->id; + uint64_t cnt_num = cpool->dcs_mng.dcs[dcs_idx].batch_sz; + uint64_t left; + uint32_t iidx = cpool->dcs_mng.dcs[dcs_idx].iidx; + uint32_t offset; + uint16_t mask; + uint16_t sq_idx; + uint64_t burst_sz = (uint64_t)(1 << MLX5_ASO_CNT_QUEUE_LOG_DESC) * 4 * + sh->cnt_svc->aso_mng.sq_num; + uint64_t qburst_sz = burst_sz / sh->cnt_svc->aso_mng.sq_num; + uint64_t n; + struct mlx5_aso_sq *sq; + + cnt_num = RTE_MIN(num, cnt_num); + left = cnt_num; + while (left) { + mask = 0; + for (sq_idx = 0; sq_idx < sh->cnt_svc->aso_mng.sq_num; + sq_idx++) { + if (left == 0) { + mask |= (1 << sq_idx); + continue; + } + n = RTE_MIN(left, qburst_sz); + offset = cnt_num - left; + offset += iidx; + mlx5_aso_cnt_sq_enqueue_burst(cpool, sh, + &sh->cnt_svc->aso_mng.sqs[sq_idx], n, + offset, dcs_id); + left -= n; + } + do { + for (sq_idx = 0; sq_idx < sh->cnt_svc->aso_mng.sq_num; + sq_idx++) { + sq = &sh->cnt_svc->aso_mng.sqs[sq_idx]; + if (mlx5_aso_cnt_completion_handle(sq)) + mask |= (1 << sq_idx); + } + } while (mask < ((1 << sh->cnt_svc->aso_mng.sq_num) - 1)); + } + return cnt_num; +} + +/* + * Query FW counter via ASO WQE. + * + * ASO query counter use _sync_ mode, means: + * 1. each SQ issue one burst with several WQEs + * 2. ask for CQE at last WQE + * 3. busy poll CQ of each SQ's + * 4. If all SQ's CQE are received then goto step 1, issue next burst + * + * @param[in] sh + * Pointer to shared device. + * @param[in] cpool + * Pointer to counter pool. + * + * @return + * 0 on success, -1 on failure. + */ +int +mlx5_aso_cnt_query(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool) +{ + uint32_t idx; + uint32_t num; + uint32_t cnt_num = mlx5_hws_cnt_pool_get_size(cpool) - + rte_ring_count(cpool->free_list); + + for (idx = 0; idx < cpool->dcs_mng.batch_total; idx++) { + num = RTE_MIN(cnt_num, cpool->dcs_mng.dcs[idx].batch_sz); + mlx5_aso_cnt_query_one_dcs(sh, cpool, idx, num); + cnt_num -= num; + if (cnt_num == 0) + break; + } + return 0; +} diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index c2e16bc56d..507abb54e4 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -10,6 +10,7 @@ #include "mlx5_rx.h" #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) +#include "mlx5_hws_cnt.h" /* The maximum actions support in the flow. */ #define MLX5_HW_MAX_ACTS 16 @@ -353,6 +354,10 @@ __flow_hw_action_template_destroy(struct rte_eth_dev *dev, mlx5dr_action_destroy(acts->mhdr->action); mlx5_free(acts->mhdr); } + if (mlx5_hws_cnt_id_valid(acts->cnt_id)) { + mlx5_hws_cnt_shared_put(priv->hws_cpool, &acts->cnt_id); + acts->cnt_id = 0; + } } /** @@ -532,6 +537,44 @@ __flow_hw_act_data_shared_rss_append(struct mlx5_priv *priv, return 0; } +/** + * Append shared counter action to the dynamic action list. + * + * @param[in] priv + * Pointer to the port private data structure. + * @param[in] acts + * Pointer to the template HW steering DR actions. + * @param[in] type + * Action type. + * @param[in] action_src + * Offset of source rte flow action. + * @param[in] action_dst + * Offset of destination DR action. + * @param[in] cnt_id + * Shared counter id. + * + * @return + * 0 on success, negative value otherwise and rte_errno is set. + */ +static __rte_always_inline int +__flow_hw_act_data_shared_cnt_append(struct mlx5_priv *priv, + struct mlx5_hw_actions *acts, + enum rte_flow_action_type type, + uint16_t action_src, + uint16_t action_dst, + cnt_id_t cnt_id) +{ struct mlx5_action_construct_data *act_data; + + act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst); + if (!act_data) + return -1; + act_data->type = type; + act_data->shared_counter.id = cnt_id; + LIST_INSERT_HEAD(&acts->act_list, act_data, next); + return 0; +} + + /** * Translate shared indirect action. * @@ -573,6 +616,13 @@ flow_hw_shared_action_translate(struct rte_eth_dev *dev, action_src, action_dst, idx, shared_rss)) return -1; break; + case MLX5_INDIRECT_ACTION_TYPE_COUNT: + if (__flow_hw_act_data_shared_cnt_append(priv, acts, + (enum rte_flow_action_type) + MLX5_RTE_FLOW_ACTION_TYPE_COUNT, + action_src, action_dst, act_idx)) + return -1; + break; default: DRV_LOG(WARNING, "Unsupported shared action type:%d", type); break; @@ -946,6 +996,30 @@ flow_hw_meter_compile(struct rte_eth_dev *dev, } return 0; } + +static __rte_always_inline int +flow_hw_cnt_compile(struct rte_eth_dev *dev, uint32_t start_pos, + struct mlx5_hw_actions *acts) +{ + struct mlx5_priv *priv = dev->data->dev_private; + uint32_t pos = start_pos; + cnt_id_t cnt_id; + int ret; + + ret = mlx5_hws_cnt_shared_get(priv->hws_cpool, &cnt_id); + if (ret != 0) + return ret; + ret = mlx5_hws_cnt_pool_get_action_offset + (priv->hws_cpool, + cnt_id, + &acts->rule_acts[pos].action, + &acts->rule_acts[pos].counter.offset); + if (ret != 0) + return ret; + acts->cnt_id = cnt_id; + return 0; +} + /** * Translate rte_flow actions to DR action. * @@ -1189,6 +1263,20 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, goto err; i++; break; + case RTE_FLOW_ACTION_TYPE_COUNT: + if (masks->conf && + ((const struct rte_flow_action_count *) + masks->conf)->id) { + err = flow_hw_cnt_compile(dev, i, acts); + if (err) + goto err; + } else if (__flow_hw_act_data_general_append + (priv, acts, actions->type, + actions - action_start, i)) { + goto err; + } + i++; + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -1377,6 +1465,13 @@ flow_hw_shared_action_construct(struct rte_eth_dev *dev, (dev, &act_data, item_flags, rule_act)) return -1; break; + case MLX5_INDIRECT_ACTION_TYPE_COUNT: + if (mlx5_hws_cnt_pool_get_action_offset(priv->hws_cpool, + act_idx, + &rule_act->action, + &rule_act->counter.offset)) + return -1; + break; default: DRV_LOG(WARNING, "Unsupported shared action type:%d", type); break; @@ -1520,7 +1615,8 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, const uint8_t it_idx, const struct rte_flow_action actions[], struct mlx5dr_rule_action *rule_acts, - uint32_t *acts_num) + uint32_t *acts_num, + uint32_t queue) { struct mlx5_priv *priv = dev->data->dev_private; struct rte_flow_template_table *table = job->flow->table; @@ -1574,6 +1670,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, uint64_t item_flags; struct mlx5_hw_jump_action *jump; struct mlx5_hrxq *hrxq; + cnt_id_t cnt_id; action = &actions[act_data->action_src]; MLX5_ASSERT(action->type == RTE_FLOW_ACTION_TYPE_INDIRECT || @@ -1681,6 +1778,32 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, if (mlx5_aso_mtr_wait(priv->sh, mtr)) return -1; break; + case RTE_FLOW_ACTION_TYPE_COUNT: + ret = mlx5_hws_cnt_pool_get(priv->hws_cpool, &queue, + &cnt_id); + if (ret != 0) + return ret; + ret = mlx5_hws_cnt_pool_get_action_offset + (priv->hws_cpool, + cnt_id, + &rule_acts[act_data->action_dst].action, + &rule_acts[act_data->action_dst].counter.offset + ); + if (ret != 0) + return ret; + job->flow->cnt_id = cnt_id; + break; + case MLX5_RTE_FLOW_ACTION_TYPE_COUNT: + ret = mlx5_hws_cnt_pool_get_action_offset + (priv->hws_cpool, + act_data->shared_counter.id, + &rule_acts[act_data->action_dst].action, + &rule_acts[act_data->action_dst].counter.offset + ); + if (ret != 0) + return ret; + job->flow->cnt_id = act_data->shared_counter.id; + break; default: break; } @@ -1690,6 +1813,8 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, job->flow->idx - 1; rule_acts[hw_acts->encap_decap_pos].reformat.data = buf; } + if (mlx5_hws_cnt_id_valid(hw_acts->cnt_id)) + job->flow->cnt_id = hw_acts->cnt_id; return 0; } @@ -1825,7 +1950,7 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev, * user's input, in order to save the cost. */ if (flow_hw_actions_construct(dev, job, hw_acts, pattern_template_index, - actions, rule_acts, &acts_num)) { + actions, rule_acts, &acts_num, queue)) { rte_errno = EINVAL; goto free; } @@ -1955,6 +2080,13 @@ flow_hw_pull(struct rte_eth_dev *dev, flow_hw_jump_release(dev, job->flow->jump); else if (job->flow->fate_type == MLX5_FLOW_FATE_QUEUE) mlx5_hrxq_obj_release(dev, job->flow->hrxq); + if (mlx5_hws_cnt_id_valid(job->flow->cnt_id) && + mlx5_hws_cnt_is_shared + (priv->hws_cpool, job->flow->cnt_id) == false) { + mlx5_hws_cnt_pool_put(priv->hws_cpool, &queue, + &job->flow->cnt_id); + job->flow->cnt_id = 0; + } mlx5_ipool_free(job->flow->table->flow, job->flow->idx); } priv->hw_q[queue].job[priv->hw_q[queue].job_idx++] = job; @@ -2678,6 +2810,9 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, if (ret < 0) return ret; break; + case RTE_FLOW_ACTION_TYPE_COUNT: + /* TODO: Validation logic */ + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -4355,6 +4490,12 @@ flow_hw_configure(struct rte_eth_dev *dev, } if (_queue_attr) mlx5_free(_queue_attr); + if (port_attr->nb_counters) { + priv->hws_cpool = mlx5_hws_cnt_pool_create(dev, port_attr, + nb_queue); + if (priv->hws_cpool == NULL) + goto err; + } return 0; err: flow_hw_free_vport_actions(priv); @@ -4424,6 +4565,8 @@ flow_hw_resource_release(struct rte_eth_dev *dev) mlx5_ipool_destroy(priv->acts_ipool); priv->acts_ipool = NULL; } + if (priv->hws_cpool) + mlx5_hws_cnt_pool_destroy(priv->sh, priv->hws_cpool); mlx5_free(priv->hw_q); priv->hw_q = NULL; claim_zero(mlx5dr_context_close(priv->dr_ctx)); @@ -4565,10 +4708,28 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, void *user_data, struct rte_flow_error *error) { + struct rte_flow_action_handle *handle = NULL; + struct mlx5_priv *priv = dev->data->dev_private; + cnt_id_t cnt_id; + RTE_SET_USED(queue); RTE_SET_USED(attr); RTE_SET_USED(user_data); - return flow_dv_action_create(dev, conf, action, error); + switch (action->type) { + case RTE_FLOW_ACTION_TYPE_COUNT: + if (mlx5_hws_cnt_shared_get(priv->hws_cpool, &cnt_id)) + rte_flow_error_set(error, ENODEV, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "counter are not configured!"); + else + handle = (struct rte_flow_action_handle *) + (uintptr_t)cnt_id; + break; + default: + handle = flow_dv_action_create(dev, conf, action, error); + } + return handle; } /** @@ -4632,10 +4793,172 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, void *user_data, struct rte_flow_error *error) { + uint32_t act_idx = (uint32_t)(uintptr_t)handle; + uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; + struct mlx5_priv *priv = dev->data->dev_private; + RTE_SET_USED(queue); RTE_SET_USED(attr); RTE_SET_USED(user_data); - return flow_dv_action_destroy(dev, handle, error); + switch (type) { + case MLX5_INDIRECT_ACTION_TYPE_COUNT: + return mlx5_hws_cnt_shared_put(priv->hws_cpool, &act_idx); + default: + return flow_dv_action_destroy(dev, handle, error); + } +} + +static int +flow_hw_query_counter(const struct rte_eth_dev *dev, uint32_t counter, + void *data, struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_hws_cnt *cnt; + struct rte_flow_query_count *qc = data; + uint32_t iidx = mlx5_hws_cnt_iidx(priv->hws_cpool, counter); + uint64_t pkts, bytes; + + if (!mlx5_hws_cnt_id_valid(counter)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "counter are not available"); + cnt = &priv->hws_cpool->pool[iidx]; + __hws_cnt_query_raw(priv->hws_cpool, counter, &pkts, &bytes); + qc->hits_set = 1; + qc->bytes_set = 1; + qc->hits = pkts - cnt->reset.hits; + qc->bytes = bytes - cnt->reset.bytes; + if (qc->reset) { + cnt->reset.bytes = bytes; + cnt->reset.hits = pkts; + } + return 0; +} + +static int +flow_hw_query(struct rte_eth_dev *dev, + struct rte_flow *flow __rte_unused, + const struct rte_flow_action *actions __rte_unused, + void *data __rte_unused, + struct rte_flow_error *error __rte_unused) +{ + int ret = -EINVAL; + struct rte_flow_hw *hw_flow = (struct rte_flow_hw *)flow; + + for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { + switch (actions->type) { + case RTE_FLOW_ACTION_TYPE_VOID: + break; + case RTE_FLOW_ACTION_TYPE_COUNT: + ret = flow_hw_query_counter(dev, hw_flow->cnt_id, data, + error); + break; + default: + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + actions, + "action not supported"); + } + } + return ret; +} + +/** + * Create indirect action. + * + * @param[in] dev + * Pointer to the Ethernet device structure. + * @param[in] conf + * Shared action configuration. + * @param[in] action + * Action specification used to create indirect action. + * @param[out] error + * Perform verbose error reporting if not NULL. Initialized in case of + * error only. + * + * @return + * A valid shared action handle in case of success, NULL otherwise and + * rte_errno is set. + */ +static struct rte_flow_action_handle * +flow_hw_action_create(struct rte_eth_dev *dev, + const struct rte_flow_indir_action_conf *conf, + const struct rte_flow_action *action, + struct rte_flow_error *err) +{ + return flow_hw_action_handle_create(dev, UINT32_MAX, NULL, conf, action, + NULL, err); +} + +/** + * Destroy the indirect action. + * Release action related resources on the NIC and the memory. + * Lock free, (mutex should be acquired by caller). + * Dispatcher for action type specific call. + * + * @param[in] dev + * Pointer to the Ethernet device structure. + * @param[in] handle + * The indirect action object handle to be removed. + * @param[out] error + * Perform verbose error reporting if not NULL. Initialized in case of + * error only. + * + * @return + * 0 on success, otherwise negative errno value. + */ +static int +flow_hw_action_destroy(struct rte_eth_dev *dev, + struct rte_flow_action_handle *handle, + struct rte_flow_error *error) +{ + return flow_hw_action_handle_destroy(dev, UINT32_MAX, NULL, handle, + NULL, error); +} + +/** + * Updates in place shared action configuration. + * + * @param[in] dev + * Pointer to the Ethernet device structure. + * @param[in] handle + * The indirect action object handle to be updated. + * @param[in] update + * Action specification used to modify the action pointed by *handle*. + * *update* could be of same type with the action pointed by the *handle* + * handle argument, or some other structures like a wrapper, depending on + * the indirect action type. + * @param[out] error + * Perform verbose error reporting if not NULL. Initialized in case of + * error only. + * + * @return + * 0 on success, otherwise negative errno value. + */ +static int +flow_hw_action_update(struct rte_eth_dev *dev, + struct rte_flow_action_handle *handle, + const void *update, + struct rte_flow_error *err) +{ + return flow_hw_action_handle_update(dev, UINT32_MAX, NULL, handle, + update, NULL, err); +} + +static int +flow_hw_action_query(struct rte_eth_dev *dev, + const struct rte_flow_action_handle *handle, void *data, + struct rte_flow_error *error) +{ + uint32_t act_idx = (uint32_t)(uintptr_t)handle; + uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; + + switch (type) { + case MLX5_INDIRECT_ACTION_TYPE_COUNT: + return flow_hw_query_counter(dev, act_idx, data, error); + default: + return flow_dv_action_query(dev, handle, data, error); + } } const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { @@ -4657,10 +4980,11 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .async_action_destroy = flow_hw_action_handle_destroy, .async_action_update = flow_hw_action_handle_update, .action_validate = flow_dv_action_validate, - .action_create = flow_dv_action_create, - .action_destroy = flow_dv_action_destroy, - .action_update = flow_dv_action_update, - .action_query = flow_dv_action_query, + .action_create = flow_hw_action_create, + .action_destroy = flow_hw_action_destroy, + .action_update = flow_hw_action_update, + .action_query = flow_hw_action_query, + .query = flow_hw_query, }; /** diff --git a/drivers/net/mlx5/mlx5_hws_cnt.c b/drivers/net/mlx5/mlx5_hws_cnt.c new file mode 100644 index 0000000000..e2408ef36d --- /dev/null +++ b/drivers/net/mlx5/mlx5_hws_cnt.c @@ -0,0 +1,528 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2020 Mellanox Technologies, Ltd + */ + +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) + +#include "mlx5_utils.h" +#include "mlx5_hws_cnt.h" + +#define HWS_CNT_CACHE_SZ_DEFAULT 511 +#define HWS_CNT_CACHE_PRELOAD_DEFAULT 254 +#define HWS_CNT_CACHE_FETCH_DEFAULT 254 +#define HWS_CNT_CACHE_THRESHOLD_DEFAULT 254 +#define HWS_CNT_ALLOC_FACTOR_DEFAULT 20 + +static void +__hws_cnt_id_load(struct mlx5_hws_cnt_pool *cpool) +{ + uint32_t preload; + uint32_t q_num = cpool->cache->q_num; + uint32_t cnt_num = mlx5_hws_cnt_pool_get_size(cpool); + cnt_id_t cnt_id, iidx = 0; + uint32_t qidx; + struct rte_ring *qcache = NULL; + + /* + * Counter ID order is important for tracking the max number of in used + * counter for querying, which means counter internal index order must + * be from zero to the number user configured, i.e: 0 - 8000000. + * Need to load counter ID in this order into the cache firstly, + * and then the global free list. + * In the end, user fetch the the counter from minimal to the maximum. + */ + preload = RTE_MIN(cpool->cache->preload_sz, cnt_num / q_num); + for (qidx = 0; qidx < q_num; qidx++) { + for (; iidx < preload * (qidx + 1); iidx++) { + cnt_id = mlx5_hws_cnt_id_gen(cpool, iidx); + qcache = cpool->cache->qcache[qidx]; + if (qcache) + rte_ring_enqueue_elem(qcache, &cnt_id, + sizeof(cnt_id)); + } + } + for (; iidx < cnt_num; iidx++) { + cnt_id = mlx5_hws_cnt_id_gen(cpool, iidx); + rte_ring_enqueue_elem(cpool->free_list, &cnt_id, + sizeof(cnt_id)); + } +} + +static void +__mlx5_hws_cnt_svc(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool) +{ + struct rte_ring *reset_list = cpool->wait_reset_list; + struct rte_ring *reuse_list = cpool->reuse_list; + uint32_t reset_cnt_num; + struct rte_ring_zc_data zcdr = {0}; + struct rte_ring_zc_data zcdu = {0}; + + reset_cnt_num = rte_ring_count(reset_list); + do { + cpool->query_gen++; + mlx5_aso_cnt_query(sh, cpool); + zcdr.n1 = 0; + zcdu.n1 = 0; + rte_ring_enqueue_zc_burst_elem_start(reuse_list, + sizeof(cnt_id_t), reset_cnt_num, &zcdu, + NULL); + rte_ring_dequeue_zc_burst_elem_start(reset_list, + sizeof(cnt_id_t), reset_cnt_num, &zcdr, + NULL); + __hws_cnt_r2rcpy(&zcdu, &zcdr, reset_cnt_num); + rte_ring_dequeue_zc_elem_finish(reset_list, + reset_cnt_num); + rte_ring_enqueue_zc_elem_finish(reuse_list, + reset_cnt_num); + reset_cnt_num = rte_ring_count(reset_list); + } while (reset_cnt_num > 0); +} + +static void +mlx5_hws_cnt_raw_data_free(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_raw_data_mng *mng) +{ + if (mng == NULL) + return; + sh->cdev->mr_scache.dereg_mr_cb(&mng->mr); + mlx5_free(mng->raw); + mlx5_free(mng); +} + +__rte_unused +static struct mlx5_hws_cnt_raw_data_mng * +mlx5_hws_cnt_raw_data_alloc(struct mlx5_dev_ctx_shared *sh, uint32_t n) +{ + struct mlx5_hws_cnt_raw_data_mng *mng = NULL; + int ret; + size_t sz = n * sizeof(struct flow_counter_stats); + + mng = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, sizeof(*mng), 0, + SOCKET_ID_ANY); + if (mng == NULL) + goto error; + mng->raw = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, sz, 0, + SOCKET_ID_ANY); + if (mng->raw == NULL) + goto error; + ret = sh->cdev->mr_scache.reg_mr_cb(sh->cdev->pd, mng->raw, sz, + &mng->mr); + if (ret) { + rte_errno = errno; + goto error; + } + return mng; +error: + mlx5_hws_cnt_raw_data_free(sh, mng); + return NULL; +} + +static void * +mlx5_hws_cnt_svc(void *opaque) +{ + struct mlx5_dev_ctx_shared *sh = + (struct mlx5_dev_ctx_shared *)opaque; + uint64_t interval = + (uint64_t)sh->cnt_svc->query_interval * (US_PER_S / MS_PER_S); + uint16_t port_id; + uint64_t start_cycle, query_cycle = 0; + uint64_t query_us; + uint64_t sleep_us; + + while (sh->cnt_svc->svc_running != 0) { + start_cycle = rte_rdtsc(); + MLX5_ETH_FOREACH_DEV(port_id, sh->cdev->dev) { + struct mlx5_priv *opriv = + rte_eth_devices[port_id].data->dev_private; + if (opriv != NULL && + opriv->sh == sh && + opriv->hws_cpool != NULL) { + __mlx5_hws_cnt_svc(sh, opriv->hws_cpool); + } + } + query_cycle = rte_rdtsc() - start_cycle; + query_us = query_cycle / (rte_get_timer_hz() / US_PER_S); + sleep_us = interval - query_us; + if (interval > query_us) + rte_delay_us_sleep(sleep_us); + } + return NULL; +} + +struct mlx5_hws_cnt_pool * +mlx5_hws_cnt_pool_init(const struct mlx5_hws_cnt_pool_cfg *pcfg, + const struct mlx5_hws_cache_param *ccfg) +{ + char mz_name[RTE_MEMZONE_NAMESIZE]; + struct mlx5_hws_cnt_pool *cntp; + uint64_t cnt_num = 0; + uint32_t qidx; + + MLX5_ASSERT(pcfg); + MLX5_ASSERT(ccfg); + cntp = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, sizeof(*cntp), 0, + SOCKET_ID_ANY); + if (cntp == NULL) + return NULL; + + cntp->cfg = *pcfg; + cntp->cache = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, + sizeof(*cntp->cache) + + sizeof(((struct mlx5_hws_cnt_pool_caches *)0)->qcache[0]) + * ccfg->q_num, 0, SOCKET_ID_ANY); + if (cntp->cache == NULL) + goto error; + /* store the necessary cache parameters. */ + cntp->cache->fetch_sz = ccfg->fetch_sz; + cntp->cache->preload_sz = ccfg->preload_sz; + cntp->cache->threshold = ccfg->threshold; + cntp->cache->q_num = ccfg->q_num; + cnt_num = pcfg->request_num * (100 + pcfg->alloc_factor) / 100; + if (cnt_num > UINT32_MAX) { + DRV_LOG(ERR, "counter number %"PRIu64" is out of 32bit range", + cnt_num); + goto error; + } + cntp->pool = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, + sizeof(struct mlx5_hws_cnt) * + pcfg->request_num * (100 + pcfg->alloc_factor) / 100, + 0, SOCKET_ID_ANY); + if (cntp->pool == NULL) + goto error; + snprintf(mz_name, sizeof(mz_name), "%s_F_RING", pcfg->name); + cntp->free_list = rte_ring_create_elem(mz_name, sizeof(cnt_id_t), + (uint32_t)cnt_num, SOCKET_ID_ANY, + RING_F_SP_ENQ | RING_F_MC_HTS_DEQ | RING_F_EXACT_SZ); + if (cntp->free_list == NULL) { + DRV_LOG(ERR, "failed to create free list ring"); + goto error; + } + snprintf(mz_name, sizeof(mz_name), "%s_R_RING", pcfg->name); + cntp->wait_reset_list = rte_ring_create_elem(mz_name, sizeof(cnt_id_t), + (uint32_t)cnt_num, SOCKET_ID_ANY, + RING_F_MP_HTS_ENQ | RING_F_SC_DEQ | RING_F_EXACT_SZ); + if (cntp->wait_reset_list == NULL) { + DRV_LOG(ERR, "failed to create free list ring"); + goto error; + } + snprintf(mz_name, sizeof(mz_name), "%s_U_RING", pcfg->name); + cntp->reuse_list = rte_ring_create_elem(mz_name, sizeof(cnt_id_t), + (uint32_t)cnt_num, SOCKET_ID_ANY, + RING_F_SP_ENQ | RING_F_MC_HTS_DEQ | RING_F_EXACT_SZ); + if (cntp->reuse_list == NULL) { + DRV_LOG(ERR, "failed to create reuse list ring"); + goto error; + } + for (qidx = 0; qidx < ccfg->q_num; qidx++) { + snprintf(mz_name, sizeof(mz_name), "%s_cache/%u", pcfg->name, + qidx); + cntp->cache->qcache[qidx] = rte_ring_create(mz_name, ccfg->size, + SOCKET_ID_ANY, + RING_F_SP_ENQ | RING_F_SC_DEQ | + RING_F_EXACT_SZ); + if (cntp->cache->qcache[qidx] == NULL) + goto error; + } + return cntp; +error: + mlx5_hws_cnt_pool_deinit(cntp); + return NULL; +} + +void +mlx5_hws_cnt_pool_deinit(struct mlx5_hws_cnt_pool * const cntp) +{ + uint32_t qidx = 0; + if (cntp == NULL) + return; + rte_ring_free(cntp->free_list); + rte_ring_free(cntp->wait_reset_list); + rte_ring_free(cntp->reuse_list); + if (cntp->cache) { + for (qidx = 0; qidx < cntp->cache->q_num; qidx++) + rte_ring_free(cntp->cache->qcache[qidx]); + } + mlx5_free(cntp->cache); + mlx5_free(cntp->raw_mng); + mlx5_free(cntp->pool); + mlx5_free(cntp); +} + +int +mlx5_hws_cnt_service_thread_create(struct mlx5_dev_ctx_shared *sh) +{ +#define CNT_THREAD_NAME_MAX 256 + char name[CNT_THREAD_NAME_MAX]; + rte_cpuset_t cpuset; + int ret; + uint32_t service_core = sh->cnt_svc->service_core; + + CPU_ZERO(&cpuset); + sh->cnt_svc->svc_running = 1; + ret = pthread_create(&sh->cnt_svc->service_thread, NULL, + mlx5_hws_cnt_svc, sh); + if (ret != 0) { + DRV_LOG(ERR, "Failed to create HW steering's counter service thread."); + return -ENOSYS; + } + snprintf(name, CNT_THREAD_NAME_MAX - 1, "%s/svc@%d", + sh->ibdev_name, service_core); + rte_thread_setname(sh->cnt_svc->service_thread, name); + CPU_SET(service_core, &cpuset); + pthread_setaffinity_np(sh->cnt_svc->service_thread, sizeof(cpuset), + &cpuset); + return 0; +} + +void +mlx5_hws_cnt_service_thread_destroy(struct mlx5_dev_ctx_shared *sh) +{ + if (sh->cnt_svc->service_thread == 0) + return; + sh->cnt_svc->svc_running = 0; + pthread_join(sh->cnt_svc->service_thread, NULL); + sh->cnt_svc->service_thread = 0; +} + +int +mlx5_hws_cnt_pool_dcs_alloc(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool) +{ + struct mlx5_hca_attr *hca_attr = &sh->cdev->config.hca_attr; + uint32_t max_log_bulk_sz = 0; + uint32_t log_bulk_sz; + uint32_t idx, alloced = 0; + unsigned int cnt_num = mlx5_hws_cnt_pool_get_size(cpool); + struct mlx5_devx_counter_attr attr = {0}; + struct mlx5_devx_obj *dcs; + + if (hca_attr->flow_counter_bulk_log_max_alloc == 0) { + DRV_LOG(ERR, + "Fw doesn't support bulk log max alloc"); + return -1; + } + max_log_bulk_sz = 23; /* hard code to 8M (1 << 23). */ + cnt_num = RTE_ALIGN_CEIL(cnt_num, 4); /* minimal 4 counter in bulk. */ + log_bulk_sz = RTE_MIN(max_log_bulk_sz, rte_log2_u32(cnt_num)); + attr.pd = sh->cdev->pdn; + attr.pd_valid = 1; + attr.bulk_log_max_alloc = 1; + attr.flow_counter_bulk_log_size = log_bulk_sz; + idx = 0; + dcs = mlx5_devx_cmd_flow_counter_alloc_general(sh->cdev->ctx, &attr); + if (dcs == NULL) + goto error; + cpool->dcs_mng.dcs[idx].obj = dcs; + cpool->dcs_mng.dcs[idx].batch_sz = (1 << log_bulk_sz); + cpool->dcs_mng.batch_total++; + idx++; + cpool->dcs_mng.dcs[0].iidx = 0; + alloced = cpool->dcs_mng.dcs[0].batch_sz; + if (cnt_num > cpool->dcs_mng.dcs[0].batch_sz) { + for (; idx < MLX5_HWS_CNT_DCS_NUM; idx++) { + attr.flow_counter_bulk_log_size = --max_log_bulk_sz; + dcs = mlx5_devx_cmd_flow_counter_alloc_general + (sh->cdev->ctx, &attr); + if (dcs == NULL) + goto error; + cpool->dcs_mng.dcs[idx].obj = dcs; + cpool->dcs_mng.dcs[idx].batch_sz = + (1 << max_log_bulk_sz); + cpool->dcs_mng.dcs[idx].iidx = alloced; + alloced += cpool->dcs_mng.dcs[idx].batch_sz; + cpool->dcs_mng.batch_total++; + } + } + return 0; +error: + DRV_LOG(DEBUG, + "Cannot alloc device counter, allocated[%" PRIu32 "] request[%" PRIu32 "]", + alloced, cnt_num); + for (idx = 0; idx < cpool->dcs_mng.batch_total; idx++) { + mlx5_devx_cmd_destroy(cpool->dcs_mng.dcs[idx].obj); + cpool->dcs_mng.dcs[idx].obj = NULL; + cpool->dcs_mng.dcs[idx].batch_sz = 0; + cpool->dcs_mng.dcs[idx].iidx = 0; + } + cpool->dcs_mng.batch_total = 0; + return -1; +} + +void +mlx5_hws_cnt_pool_dcs_free(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool) +{ + uint32_t idx; + + if (cpool == NULL) + return; + for (idx = 0; idx < MLX5_HWS_CNT_DCS_NUM; idx++) + mlx5_devx_cmd_destroy(cpool->dcs_mng.dcs[idx].obj); + if (cpool->raw_mng) { + mlx5_hws_cnt_raw_data_free(sh, cpool->raw_mng); + cpool->raw_mng = NULL; + } +} + +int +mlx5_hws_cnt_pool_action_create(struct mlx5_priv *priv, + struct mlx5_hws_cnt_pool *cpool) +{ + uint32_t idx; + int ret = 0; + struct mlx5_hws_cnt_dcs *dcs; + uint32_t flags; + + flags = MLX5DR_ACTION_FLAG_HWS_RX | MLX5DR_ACTION_FLAG_HWS_TX; + if (priv->sh->config.dv_esw_en && priv->master) + flags |= MLX5DR_ACTION_FLAG_HWS_FDB; + for (idx = 0; idx < cpool->dcs_mng.batch_total; idx++) { + dcs = &cpool->dcs_mng.dcs[idx]; + dcs->dr_action = mlx5dr_action_create_counter(priv->dr_ctx, + (struct mlx5dr_devx_obj *)dcs->obj, + flags); + if (dcs->dr_action == NULL) { + mlx5_hws_cnt_pool_action_destroy(cpool); + ret = -ENOSYS; + break; + } + } + return ret; +} + +void +mlx5_hws_cnt_pool_action_destroy(struct mlx5_hws_cnt_pool *cpool) +{ + uint32_t idx; + struct mlx5_hws_cnt_dcs *dcs; + + for (idx = 0; idx < cpool->dcs_mng.batch_total; idx++) { + dcs = &cpool->dcs_mng.dcs[idx]; + if (dcs->dr_action != NULL) { + mlx5dr_action_destroy(dcs->dr_action); + dcs->dr_action = NULL; + } + } +} + +struct mlx5_hws_cnt_pool * +mlx5_hws_cnt_pool_create(struct rte_eth_dev *dev, + const struct rte_flow_port_attr *pattr, uint16_t nb_queue) +{ + struct mlx5_hws_cnt_pool *cpool = NULL; + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_hws_cache_param cparam = {0}; + struct mlx5_hws_cnt_pool_cfg pcfg = {0}; + char *mp_name; + int ret = 0; + size_t sz; + + /* init cnt service if not. */ + if (priv->sh->cnt_svc == NULL) { + ret = mlx5_hws_cnt_svc_init(priv->sh); + if (ret != 0) + return NULL; + } + cparam.fetch_sz = HWS_CNT_CACHE_FETCH_DEFAULT; + cparam.preload_sz = HWS_CNT_CACHE_PRELOAD_DEFAULT; + cparam.q_num = nb_queue; + cparam.threshold = HWS_CNT_CACHE_THRESHOLD_DEFAULT; + cparam.size = HWS_CNT_CACHE_SZ_DEFAULT; + pcfg.alloc_factor = HWS_CNT_ALLOC_FACTOR_DEFAULT; + mp_name = mlx5_malloc(MLX5_MEM_ZERO, RTE_MEMZONE_NAMESIZE, 0, + SOCKET_ID_ANY); + if (mp_name == NULL) + goto error; + snprintf(mp_name, RTE_MEMZONE_NAMESIZE, "MLX5_HWS_CNT_POOL_%u", + dev->data->port_id); + pcfg.name = mp_name; + pcfg.request_num = pattr->nb_counters; + cpool = mlx5_hws_cnt_pool_init(&pcfg, &cparam); + if (cpool == NULL) + goto error; + ret = mlx5_hws_cnt_pool_dcs_alloc(priv->sh, cpool); + if (ret != 0) + goto error; + sz = RTE_ALIGN_CEIL(mlx5_hws_cnt_pool_get_size(cpool), 4); + cpool->raw_mng = mlx5_hws_cnt_raw_data_alloc(priv->sh, sz); + if (cpool->raw_mng == NULL) + goto error; + __hws_cnt_id_load(cpool); + /* + * Bump query gen right after pool create so the + * pre-loaded counters can be used directly + * because they already have init value no need + * to wait for query. + */ + cpool->query_gen = 1; + ret = mlx5_hws_cnt_pool_action_create(priv, cpool); + if (ret != 0) + goto error; + priv->sh->cnt_svc->refcnt++; + return cpool; +error: + mlx5_hws_cnt_pool_destroy(priv->sh, cpool); + return NULL; +} + +void +mlx5_hws_cnt_pool_destroy(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool) +{ + if (cpool == NULL) + return; + if (--sh->cnt_svc->refcnt == 0) + mlx5_hws_cnt_svc_deinit(sh); + mlx5_hws_cnt_pool_action_destroy(cpool); + mlx5_hws_cnt_pool_dcs_free(sh, cpool); + mlx5_hws_cnt_raw_data_free(sh, cpool->raw_mng); + mlx5_free((void *)cpool->cfg.name); + mlx5_hws_cnt_pool_deinit(cpool); +} + +int +mlx5_hws_cnt_svc_init(struct mlx5_dev_ctx_shared *sh) +{ + int ret; + + sh->cnt_svc = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, + sizeof(*sh->cnt_svc), 0, SOCKET_ID_ANY); + if (sh->cnt_svc == NULL) + return -1; + sh->cnt_svc->query_interval = sh->config.cnt_svc.cycle_time; + sh->cnt_svc->service_core = sh->config.cnt_svc.service_core; + ret = mlx5_aso_cnt_queue_init(sh); + if (ret != 0) { + mlx5_free(sh->cnt_svc); + sh->cnt_svc = NULL; + return -1; + } + ret = mlx5_hws_cnt_service_thread_create(sh); + if (ret != 0) { + mlx5_aso_cnt_queue_uninit(sh); + mlx5_free(sh->cnt_svc); + sh->cnt_svc = NULL; + } + return 0; +} + +void +mlx5_hws_cnt_svc_deinit(struct mlx5_dev_ctx_shared *sh) +{ + if (sh->cnt_svc == NULL) + return; + mlx5_hws_cnt_service_thread_destroy(sh); + mlx5_aso_cnt_queue_uninit(sh); + mlx5_free(sh->cnt_svc); + sh->cnt_svc = NULL; +} + +#endif diff --git a/drivers/net/mlx5/mlx5_hws_cnt.h b/drivers/net/mlx5/mlx5_hws_cnt.h new file mode 100644 index 0000000000..5fab4ba597 --- /dev/null +++ b/drivers/net/mlx5/mlx5_hws_cnt.h @@ -0,0 +1,558 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2022 Mellanox Technologies, Ltd + */ + +#ifndef _MLX5_HWS_CNT_H_ +#define _MLX5_HWS_CNT_H_ + +#include +#include "mlx5_utils.h" +#include "mlx5_flow.h" + +/* + * COUNTER ID's layout + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T | | D | | + * ~ Y | | C | IDX ~ + * | P | | S | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Bit 31:30 = TYPE = MLX5_INDIRECT_ACTION_TYPE_COUNT = b'10 + * Bit 25:24 = DCS index + * Bit 23:00 = IDX in this counter belonged DCS bulk. + */ +typedef uint32_t cnt_id_t; + +#define MLX5_HWS_CNT_DCS_NUM 4 +#define MLX5_HWS_CNT_DCS_IDX_OFFSET 24 +#define MLX5_HWS_CNT_DCS_IDX_MASK 0x3 +#define MLX5_HWS_CNT_IDX_MASK ((1UL << MLX5_HWS_CNT_DCS_IDX_OFFSET) - 1) + +struct mlx5_hws_cnt_dcs { + void *dr_action; + uint32_t batch_sz; + uint32_t iidx; /* internal index of first counter in this bulk. */ + struct mlx5_devx_obj *obj; +}; + +struct mlx5_hws_cnt_dcs_mng { + uint32_t batch_total; + struct mlx5_hws_cnt_dcs dcs[MLX5_HWS_CNT_DCS_NUM]; +}; + +struct mlx5_hws_cnt { + struct flow_counter_stats reset; + union { + uint32_t share: 1; + /* + * share will be set to 1 when this counter is used as indirect + * action. Only meaningful when user own this counter. + */ + uint32_t query_gen_when_free; + /* + * When PMD own this counter (user put back counter to PMD + * counter pool, i.e), this field recorded value of counter + * pools query generation at time user release the counter. + */ + }; +}; + +struct mlx5_hws_cnt_raw_data_mng { + struct flow_counter_stats *raw; + struct mlx5_pmd_mr mr; +}; + +struct mlx5_hws_cache_param { + uint32_t size; + uint32_t q_num; + uint32_t fetch_sz; + uint32_t threshold; + uint32_t preload_sz; +}; + +struct mlx5_hws_cnt_pool_cfg { + char *name; + uint32_t request_num; + uint32_t alloc_factor; +}; + +struct mlx5_hws_cnt_pool_caches { + uint32_t fetch_sz; + uint32_t threshold; + uint32_t preload_sz; + uint32_t q_num; + struct rte_ring *qcache[]; +}; + +struct mlx5_hws_cnt_pool { + struct mlx5_hws_cnt_pool_cfg cfg __rte_cache_aligned; + struct mlx5_hws_cnt_dcs_mng dcs_mng __rte_cache_aligned; + uint32_t query_gen __rte_cache_aligned; + struct mlx5_hws_cnt *pool; + struct mlx5_hws_cnt_raw_data_mng *raw_mng; + struct rte_ring *reuse_list; + struct rte_ring *free_list; + struct rte_ring *wait_reset_list; + struct mlx5_hws_cnt_pool_caches *cache; +} __rte_cache_aligned; + +/** + * Translate counter id into internal index (start from 0), which can be used + * as index of raw/cnt pool. + * + * @param cnt_id + * The external counter id + * @return + * Internal index + */ +static __rte_always_inline cnt_id_t +mlx5_hws_cnt_iidx(struct mlx5_hws_cnt_pool *cpool, cnt_id_t cnt_id) +{ + uint8_t dcs_idx = cnt_id >> MLX5_HWS_CNT_DCS_IDX_OFFSET; + uint32_t offset = cnt_id & MLX5_HWS_CNT_IDX_MASK; + + dcs_idx &= MLX5_HWS_CNT_DCS_IDX_MASK; + return (cpool->dcs_mng.dcs[dcs_idx].iidx + offset); +} + +/** + * Check if it's valid counter id. + */ +static __rte_always_inline bool +mlx5_hws_cnt_id_valid(cnt_id_t cnt_id) +{ + return (cnt_id >> MLX5_INDIRECT_ACTION_TYPE_OFFSET) == + MLX5_INDIRECT_ACTION_TYPE_COUNT ? true : false; +} + +/** + * Generate Counter id from internal index. + * + * @param cpool + * The pointer to counter pool + * @param index + * The internal counter index. + * + * @return + * Counter id + */ +static __rte_always_inline cnt_id_t +mlx5_hws_cnt_id_gen(struct mlx5_hws_cnt_pool *cpool, cnt_id_t iidx) +{ + struct mlx5_hws_cnt_dcs_mng *dcs_mng = &cpool->dcs_mng; + uint32_t idx; + uint32_t offset; + cnt_id_t cnt_id; + + for (idx = 0, offset = iidx; idx < dcs_mng->batch_total; idx++) { + if (dcs_mng->dcs[idx].batch_sz <= offset) + offset -= dcs_mng->dcs[idx].batch_sz; + else + break; + } + cnt_id = offset; + cnt_id |= (idx << MLX5_HWS_CNT_DCS_IDX_OFFSET); + return (MLX5_INDIRECT_ACTION_TYPE_COUNT << + MLX5_INDIRECT_ACTION_TYPE_OFFSET) | cnt_id; +} + +static __rte_always_inline void +__hws_cnt_query_raw(struct mlx5_hws_cnt_pool *cpool, cnt_id_t cnt_id, + uint64_t *raw_pkts, uint64_t *raw_bytes) +{ + struct mlx5_hws_cnt_raw_data_mng *raw_mng = cpool->raw_mng; + struct flow_counter_stats s[2]; + uint8_t i = 0x1; + size_t stat_sz = sizeof(s[0]); + uint32_t iidx = mlx5_hws_cnt_iidx(cpool, cnt_id); + + memcpy(&s[0], &raw_mng->raw[iidx], stat_sz); + do { + memcpy(&s[i & 1], &raw_mng->raw[iidx], stat_sz); + if (memcmp(&s[0], &s[1], stat_sz) == 0) { + *raw_pkts = rte_be_to_cpu_64(s[0].hits); + *raw_bytes = rte_be_to_cpu_64(s[0].bytes); + break; + } + i = ~i; + } while (1); +} + +/** + * Copy elems from one zero-copy ring to zero-copy ring in place. + * + * The input is a rte ring zero-copy data struct, which has two pointer. + * in case of the wrapper happened, the ptr2 will be meaningful. + * + * So this rountin needs to consider the situation that the address given by + * source and destination could be both wrapped. + * First, calculate the first number of element needs to be copied until wrapped + * address, which could be in source or destination. + * Second, copy left number of element until second wrapped address. If in first + * step the wrapped address is source, then this time it must be in destination. + * and vice-vers. + * Third, copy all left numbe of element. + * + * In worst case, we need copy three pieces of continuous memory. + * + * @param zcdd + * A pointer to zero-copy data of dest ring. + * @param zcds + * A pointer to zero-copy data of source ring. + * @param n + * Number of elems to copy. + */ +static __rte_always_inline void +__hws_cnt_r2rcpy(struct rte_ring_zc_data *zcdd, struct rte_ring_zc_data *zcds, + unsigned int n) +{ + unsigned int n1, n2, n3; + void *s1, *s2, *s3; + void *d1, *d2, *d3; + + s1 = zcds->ptr1; + d1 = zcdd->ptr1; + n1 = RTE_MIN(zcdd->n1, zcds->n1); + if (zcds->n1 > n1) { + n2 = zcds->n1 - n1; + s2 = RTE_PTR_ADD(zcds->ptr1, sizeof(cnt_id_t) * n1); + d2 = zcdd->ptr2; + n3 = n - n1 - n2; + s3 = zcds->ptr2; + d3 = RTE_PTR_ADD(zcdd->ptr2, sizeof(cnt_id_t) * n2); + } else { + n2 = zcdd->n1 - n1; + s2 = zcds->ptr2; + d2 = RTE_PTR_ADD(zcdd->ptr1, sizeof(cnt_id_t) * n1); + n3 = n - n1 - n2; + s3 = RTE_PTR_ADD(zcds->ptr2, sizeof(cnt_id_t) * n2); + d3 = zcdd->ptr2; + } + memcpy(d1, s1, n1 * sizeof(cnt_id_t)); + if (n2 != 0) { + memcpy(d2, s2, n2 * sizeof(cnt_id_t)); + if (n3 != 0) + memcpy(d3, s3, n3 * sizeof(cnt_id_t)); + } +} + +static __rte_always_inline int +mlx5_hws_cnt_pool_cache_flush(struct mlx5_hws_cnt_pool *cpool, + uint32_t queue_id) +{ + unsigned int ret; + struct rte_ring_zc_data zcdr = {0}; + struct rte_ring_zc_data zcdc = {0}; + struct rte_ring *reset_list = NULL; + struct rte_ring *qcache = cpool->cache->qcache[queue_id]; + + ret = rte_ring_dequeue_zc_burst_elem_start(qcache, + sizeof(cnt_id_t), rte_ring_count(qcache), &zcdc, + NULL); + MLX5_ASSERT(ret); + reset_list = cpool->wait_reset_list; + rte_ring_enqueue_zc_burst_elem_start(reset_list, + sizeof(cnt_id_t), ret, &zcdr, NULL); + __hws_cnt_r2rcpy(&zcdr, &zcdc, ret); + rte_ring_enqueue_zc_elem_finish(reset_list, ret); + rte_ring_dequeue_zc_elem_finish(qcache, ret); + return 0; +} + +static __rte_always_inline int +mlx5_hws_cnt_pool_cache_fetch(struct mlx5_hws_cnt_pool *cpool, + uint32_t queue_id) +{ + struct rte_ring *qcache = cpool->cache->qcache[queue_id]; + struct rte_ring *free_list = NULL; + struct rte_ring *reuse_list = NULL; + struct rte_ring *list = NULL; + struct rte_ring_zc_data zcdf = {0}; + struct rte_ring_zc_data zcdc = {0}; + struct rte_ring_zc_data zcdu = {0}; + struct rte_ring_zc_data zcds = {0}; + struct mlx5_hws_cnt_pool_caches *cache = cpool->cache; + unsigned int ret; + + reuse_list = cpool->reuse_list; + ret = rte_ring_dequeue_zc_burst_elem_start(reuse_list, + sizeof(cnt_id_t), cache->fetch_sz, &zcdu, NULL); + zcds = zcdu; + list = reuse_list; + if (unlikely(ret == 0)) { /* no reuse counter. */ + rte_ring_dequeue_zc_elem_finish(reuse_list, 0); + free_list = cpool->free_list; + ret = rte_ring_dequeue_zc_burst_elem_start(free_list, + sizeof(cnt_id_t), cache->fetch_sz, &zcdf, NULL); + zcds = zcdf; + list = free_list; + if (unlikely(ret == 0)) { /* no free counter. */ + rte_ring_dequeue_zc_elem_finish(free_list, 0); + if (rte_ring_count(cpool->wait_reset_list)) + return -EAGAIN; + return -ENOENT; + } + } + rte_ring_enqueue_zc_burst_elem_start(qcache, sizeof(cnt_id_t), + ret, &zcdc, NULL); + __hws_cnt_r2rcpy(&zcdc, &zcds, ret); + rte_ring_dequeue_zc_elem_finish(list, ret); + rte_ring_enqueue_zc_elem_finish(qcache, ret); + return 0; +} + +static __rte_always_inline int +__mlx5_hws_cnt_pool_enqueue_revert(struct rte_ring *r, unsigned int n, + struct rte_ring_zc_data *zcd) +{ + uint32_t current_head = 0; + uint32_t revert2head = 0; + + MLX5_ASSERT(r->prod.sync_type == RTE_RING_SYNC_ST); + MLX5_ASSERT(r->cons.sync_type == RTE_RING_SYNC_ST); + current_head = __atomic_load_n(&r->prod.head, __ATOMIC_RELAXED); + MLX5_ASSERT(n <= r->capacity); + MLX5_ASSERT(n <= rte_ring_count(r)); + revert2head = current_head - n; + r->prod.head = revert2head; /* This ring should be SP. */ + __rte_ring_get_elem_addr(r, revert2head, sizeof(cnt_id_t), n, + &zcd->ptr1, &zcd->n1, &zcd->ptr2); + /* Update tail */ + __atomic_store_n(&r->prod.tail, revert2head, __ATOMIC_RELEASE); + return n; +} + +/** + * Put one counter back in the mempool. + * + * @param cpool + * A pointer to the counter pool structure. + * @param cnt_id + * A counter id to be added. + * @return + * - 0: Success; object taken + * - -ENOENT: not enough entry in pool + */ +static __rte_always_inline int +mlx5_hws_cnt_pool_put(struct mlx5_hws_cnt_pool *cpool, + uint32_t *queue, cnt_id_t *cnt_id) +{ + unsigned int ret = 0; + struct rte_ring_zc_data zcdc = {0}; + struct rte_ring_zc_data zcdr = {0}; + struct rte_ring *qcache = NULL; + unsigned int wb_num = 0; /* cache write-back number. */ + cnt_id_t iidx; + + iidx = mlx5_hws_cnt_iidx(cpool, *cnt_id); + cpool->pool[iidx].query_gen_when_free = + __atomic_load_n(&cpool->query_gen, __ATOMIC_RELAXED); + if (likely(queue != NULL)) + qcache = cpool->cache->qcache[*queue]; + if (unlikely(qcache == NULL)) { + ret = rte_ring_enqueue_elem(cpool->wait_reset_list, cnt_id, + sizeof(cnt_id_t)); + MLX5_ASSERT(ret == 0); + return ret; + } + ret = rte_ring_enqueue_burst_elem(qcache, cnt_id, sizeof(cnt_id_t), 1, + NULL); + if (unlikely(ret == 0)) { /* cache is full. */ + wb_num = rte_ring_count(qcache) - cpool->cache->threshold; + MLX5_ASSERT(wb_num < rte_ring_count(qcache)); + __mlx5_hws_cnt_pool_enqueue_revert(qcache, wb_num, &zcdc); + rte_ring_enqueue_zc_burst_elem_start(cpool->wait_reset_list, + sizeof(cnt_id_t), wb_num, &zcdr, NULL); + __hws_cnt_r2rcpy(&zcdr, &zcdc, wb_num); + rte_ring_enqueue_zc_elem_finish(cpool->wait_reset_list, wb_num); + /* write-back THIS counter too */ + ret = rte_ring_enqueue_burst_elem(cpool->wait_reset_list, + cnt_id, sizeof(cnt_id_t), 1, NULL); + } + return ret == 1 ? 0 : -ENOENT; +} + +/** + * Get one counter from the pool. + * + * If @param queue is not null, objects will be retrieved first from queue's + * cache, subsequently from the common pool. Note that it can return -ENOENT + * when the local cache and common pool are empty, even if cache from other + * queue are full. + * + * @param cntp + * A pointer to the counter pool structure. + * @param queue + * A pointer to HWS queue. If null, it means fetch from common pool. + * @param cnt_id + * A pointer to a cnt_id_t * pointer (counter id) that will be filled. + * @return + * - 0: Success; objects taken. + * - -ENOENT: Not enough entries in the mempool; no object is retrieved. + * - -EAGAIN: counter is not ready; try again. + */ +static __rte_always_inline int +mlx5_hws_cnt_pool_get(struct mlx5_hws_cnt_pool *cpool, + uint32_t *queue, cnt_id_t *cnt_id) +{ + unsigned int ret; + struct rte_ring_zc_data zcdc = {0}; + struct rte_ring *qcache = NULL; + uint32_t query_gen = 0; + cnt_id_t iidx, tmp_cid = 0; + + if (likely(queue != NULL)) + qcache = cpool->cache->qcache[*queue]; + if (unlikely(qcache == NULL)) { + ret = rte_ring_dequeue_elem(cpool->reuse_list, &tmp_cid, + sizeof(cnt_id_t)); + if (unlikely(ret != 0)) { + ret = rte_ring_dequeue_elem(cpool->free_list, &tmp_cid, + sizeof(cnt_id_t)); + if (unlikely(ret != 0)) { + if (rte_ring_count(cpool->wait_reset_list)) + return -EAGAIN; + return -ENOENT; + } + } + *cnt_id = tmp_cid; + iidx = mlx5_hws_cnt_iidx(cpool, *cnt_id); + __hws_cnt_query_raw(cpool, *cnt_id, + &cpool->pool[iidx].reset.hits, + &cpool->pool[iidx].reset.bytes); + return 0; + } + ret = rte_ring_dequeue_zc_burst_elem_start(qcache, sizeof(cnt_id_t), 1, + &zcdc, NULL); + if (unlikely(ret == 0)) { /* local cache is empty. */ + rte_ring_dequeue_zc_elem_finish(qcache, 0); + /* let's fetch from global free list. */ + ret = mlx5_hws_cnt_pool_cache_fetch(cpool, *queue); + if (unlikely(ret != 0)) + return ret; + rte_ring_dequeue_zc_burst_elem_start(qcache, sizeof(cnt_id_t), + 1, &zcdc, NULL); + } + /* get one from local cache. */ + *cnt_id = (*(cnt_id_t *)zcdc.ptr1); + iidx = mlx5_hws_cnt_iidx(cpool, *cnt_id); + query_gen = cpool->pool[iidx].query_gen_when_free; + if (cpool->query_gen == query_gen) { /* counter is waiting to reset. */ + rte_ring_dequeue_zc_elem_finish(qcache, 0); + /* write-back counter to reset list. */ + mlx5_hws_cnt_pool_cache_flush(cpool, *queue); + /* let's fetch from global free list. */ + ret = mlx5_hws_cnt_pool_cache_fetch(cpool, *queue); + if (unlikely(ret != 0)) + return ret; + rte_ring_dequeue_zc_burst_elem_start(qcache, sizeof(cnt_id_t), + 1, &zcdc, NULL); + *cnt_id = *(cnt_id_t *)zcdc.ptr1; + } + __hws_cnt_query_raw(cpool, *cnt_id, &cpool->pool[iidx].reset.hits, + &cpool->pool[iidx].reset.bytes); + rte_ring_dequeue_zc_elem_finish(qcache, 1); + cpool->pool[iidx].share = 0; + return 0; +} + +static __rte_always_inline unsigned int +mlx5_hws_cnt_pool_get_size(struct mlx5_hws_cnt_pool *cpool) +{ + return rte_ring_get_capacity(cpool->free_list); +} + +static __rte_always_inline int +mlx5_hws_cnt_pool_get_action_offset(struct mlx5_hws_cnt_pool *cpool, + cnt_id_t cnt_id, struct mlx5dr_action **action, + uint32_t *offset) +{ + uint8_t idx = cnt_id >> MLX5_HWS_CNT_DCS_IDX_OFFSET; + + idx &= MLX5_HWS_CNT_DCS_IDX_MASK; + *action = cpool->dcs_mng.dcs[idx].dr_action; + *offset = cnt_id & MLX5_HWS_CNT_IDX_MASK; + return 0; +} + +static __rte_always_inline int +mlx5_hws_cnt_shared_get(struct mlx5_hws_cnt_pool *cpool, cnt_id_t *cnt_id) +{ + int ret; + uint32_t iidx; + + ret = mlx5_hws_cnt_pool_get(cpool, NULL, cnt_id); + if (ret != 0) + return ret; + iidx = mlx5_hws_cnt_iidx(cpool, *cnt_id); + MLX5_ASSERT(cpool->pool[iidx].share == 0); + cpool->pool[iidx].share = 1; + return 0; +} + +static __rte_always_inline int +mlx5_hws_cnt_shared_put(struct mlx5_hws_cnt_pool *cpool, cnt_id_t *cnt_id) +{ + int ret; + uint32_t iidx = mlx5_hws_cnt_iidx(cpool, *cnt_id); + + cpool->pool[iidx].share = 0; + ret = mlx5_hws_cnt_pool_put(cpool, NULL, cnt_id); + if (unlikely(ret != 0)) + cpool->pool[iidx].share = 1; /* fail to release, restore. */ + return ret; +} + +static __rte_always_inline bool +mlx5_hws_cnt_is_shared(struct mlx5_hws_cnt_pool *cpool, cnt_id_t cnt_id) +{ + uint32_t iidx = mlx5_hws_cnt_iidx(cpool, cnt_id); + + return cpool->pool[iidx].share ? true : false; +} + +/* init HWS counter pool. */ +struct mlx5_hws_cnt_pool * +mlx5_hws_cnt_pool_init(const struct mlx5_hws_cnt_pool_cfg *pcfg, + const struct mlx5_hws_cache_param *ccfg); + +void +mlx5_hws_cnt_pool_deinit(struct mlx5_hws_cnt_pool *cntp); + +int +mlx5_hws_cnt_service_thread_create(struct mlx5_dev_ctx_shared *sh); + +void +mlx5_hws_cnt_service_thread_destroy(struct mlx5_dev_ctx_shared *sh); + +int +mlx5_hws_cnt_pool_dcs_alloc(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool); +void +mlx5_hws_cnt_pool_dcs_free(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool); + +int +mlx5_hws_cnt_pool_action_create(struct mlx5_priv *priv, + struct mlx5_hws_cnt_pool *cpool); + +void +mlx5_hws_cnt_pool_action_destroy(struct mlx5_hws_cnt_pool *cpool); + +struct mlx5_hws_cnt_pool * +mlx5_hws_cnt_pool_create(struct rte_eth_dev *dev, + const struct rte_flow_port_attr *pattr, uint16_t nb_queue); + +void +mlx5_hws_cnt_pool_destroy(struct mlx5_dev_ctx_shared *sh, + struct mlx5_hws_cnt_pool *cpool); + +int +mlx5_hws_cnt_svc_init(struct mlx5_dev_ctx_shared *sh); + +void +mlx5_hws_cnt_svc_deinit(struct mlx5_dev_ctx_shared *sh); + +#endif /* _MLX5_HWS_CNT_H_ */ From patchwork Fri Sep 30 12:53:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117218 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 404F7A00C4; Fri, 30 Sep 2022 14:54:43 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 7AF0B42B85; Fri, 30 Sep 2022 14:54:03 +0200 (CEST) Received: from NAM04-DM6-obe.outbound.protection.outlook.com (mail-dm6nam04on2063.outbound.protection.outlook.com [40.107.102.63]) by mails.dpdk.org (Postfix) with ESMTP id 2A8C842B85 for ; Fri, 30 Sep 2022 14:54:01 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Vk4WFTtyu0WvFFQ8Fsmt0YrAjiy4IJH+3cbKX76blezg3OmfMfOVCTuLW4VA2cUoDUN9asjLXfKe/pw0ivtczlV+GQSvrKhNVDGaxYsl7h0cJIWCqdCWJKi2q91Z3tY8HTwXwyGiOxZC6nv2F8Zr5HnNsO9rFNqusRlsAccrPrlK607qcAxpmvGIS+cwpXixlyyiuJvL/HEm2buwvl/34YepLLXpVneJET8zxHyHs3COrY4NHBOoyWrdIO7f+2G0nLHTi0AX445AfPu+9ZcDuzhl5iJToB529sWFN4j+yIOH2GXrmOEHgWnqttbKJaWYankwz1W8XqOPFdmeomVgTg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=vqdYZdY7NtaPTC3NXzJ+K4s3k0EinjlgB0rxc9pSKNk=; b=QuRTnj7C30+j+33prds1pZkaKPdTRH3sPOI65UEdRShCrQ6axPhpHDXwvyQtJUo4qznuJNeHa2WRDzeQWesEMCDuXXgSfr29YtGARFm0yJyED0/w5MfmUkY/+LNNLh5kLm/DZ8R5gvXiukX9j09WokR9In80dIFQLMBIYzNXV8T9EgtNKR8FNZF7M5x2aVWUl9q659hH7zqMuv3OZkVjICCZmuJEy5P+TTyv2zcOokKNdWJNJcKEBbhhDKAIwcGNrCdLTu0j/DXRyRRkmv6IJX1RSm7IcpobkKyGYjh+07TD4zDoWknjqx65Lk05h/y9oA2ICbmpYoUIoa+w6j0Qlw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.161) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=vqdYZdY7NtaPTC3NXzJ+K4s3k0EinjlgB0rxc9pSKNk=; b=DLjyjKIKZosTBz09hHvh/EO1DOyzMJ7xlwE/BHJPg/xd6qidSx+Us8Z39965GCqX+Me1FsQzrJMlBqrGJ1i81KQFaVQuBm8KTyk6lg0CPgtmuu6Cu3VW+lOSujHZYpQmchgxm6pbgs8Z+9r/JeoJjUMfoSzUzpUaM65p2t01TjPQdbPzQlzK14FAZco9k3tE6TCCHnasBcUveaMMEXSRdHhSoqCOrIrmKcAeE8OvIxIfW4XauB0bT5n0gWL4zoF5Fgbso+IFIBt2b8p9sXoJILpzWxvl+P+e+gkwweDdoSQbqLTNlU+1Ut/clHkBPrU0L91s4dPdz/eh+UnhY+3Ing== Received: from DS7PR03CA0149.namprd03.prod.outlook.com (2603:10b6:5:3b4::34) by DM4PR12MB5818.namprd12.prod.outlook.com (2603:10b6:8:62::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.20; Fri, 30 Sep 2022 12:53:59 +0000 Received: from DM6NAM11FT102.eop-nam11.prod.protection.outlook.com (2603:10b6:5:3b4:cafe::a6) by DS7PR03CA0149.outlook.office365.com (2603:10b6:5:3b4::34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.20 via Frontend Transport; Fri, 30 Sep 2022 12:53:59 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.161) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.161 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.161; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.161) by DM6NAM11FT102.mail.protection.outlook.com (10.13.173.172) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:53:58 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.67) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:54 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:51 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , "Dariusz Sosnowski" Subject: [PATCH v3 09/17] net/mlx5: support DR action template API Date: Fri, 30 Sep 2022 15:53:07 +0300 Message-ID: <20220930125315.5079-10-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT102:EE_|DM4PR12MB5818:EE_ X-MS-Office365-Filtering-Correlation-Id: 49c437d0-d2cf-4fc7-ae99-08daa2e2d7ac X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: zh59wCTgwk+tS0rAceG1xFLv+o7/zRB81KGezFL0JKt0PZJIrAKAjy4YN0RU421/0f/grNSJgyhn7/IQV3KsoSCnkcNe7IQzGW7odjFg8T0hsLz5BuggpijmNXlqKmVvga08NBVrfSgPp6T3sf+vMWwwNvPqJBdeg5eYjvB/grCC/Wq1Z2f4+mEemCyfGD/44l1DsuwtyDuL/5EU0njkwTILvxwei5ytHFn2xzyaJ+pPCoJcY/6H0NvxLAvI3cW8qkhzQHs+LNSlXqZ5rIL0777AtFYYOF4WBMiEJrZkEY44VkzqcE3ZIotBvJOnWS6gfgQryj7qlFJ6mKGUDsrQHfwdneu/6n7n2MIX73ltQ3LYx/IiEUdVOd4tRi3qpmyzfsmIvxmHNUe0nlBy4xcVipKvXy4WWyj+C7uU0im7Ci1darNbgP9adMKTPGfM1D11141RlJRfNNfKzek7aO3rGfWrDe1kP+BP2fBb+AQL4NxHl9hi4bfrc2DT6d3Hx3acM71x2Nv+R28Nij2tiQeokSD94CNoGzvNgMQs9Gt1Bpuk7pUdHVxaAPNptfp+ityHXb30kdQVxrKWV99Ly8tHc+bv5Q70RP9f0domT+RvaX77kLpE2McC2bs5yTisiuO/RT2U00ri8b6yCUNzGzCyITzxHzkYHlsm5ohuSBuExBOku+2N/yHrMbzF4DNIaY0Fysq8h9G5vHyHgOScnhca5zpUhyNRvjHaU7zDumTYJbl2GVTgAAPfXWfM2QAF9cvNwyA1CqD6y+xiVctr6aELPBM/IlibmVOcnBn5KhIbBdcKIfs2lV30+eFmb7eAiKCt X-Forefront-Antispam-Report: CIP:216.228.117.161; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge2.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(39860400002)(346002)(376002)(396003)(136003)(451199015)(46966006)(36840700001)(40470700004)(2616005)(30864003)(26005)(6286002)(40460700003)(82740400003)(4326008)(356005)(8676002)(110136005)(316002)(36756003)(7636003)(55016003)(36860700001)(54906003)(86362001)(40480700001)(47076005)(1076003)(186003)(336012)(82310400005)(8936002)(83380400001)(478600001)(6666004)(107886003)(426003)(16526019)(7696005)(6636002)(5660300002)(70586007)(2906002)(41300700001)(70206006)(21314003)(579004)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:53:58.9511 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 49c437d0-d2cf-4fc7-ae99-08daa2e2d7ac X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.161]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT102.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM4PR12MB5818 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Dariusz Sosnowski This patch adapts mlx5 PMD to changes in mlx5dr API regarding action templates. It changes the following: 1. Actions template creation: - Flow actions types are translated to mlx5dr action types in order to create mlx5dr_action_template object. - An offset is assigned to each flow action. This offset is used to predetermine action's location in rule_acts array passed on rule creation. 2. Template table creation: - Fixed actions are created and put in rule_acts cache using predetermined offsets - mlx5dr matcher is parametrized by action templates bound to template table. - mlx5dr matcher is configured to optimize rule creation based on passed rule indices. 3. Flow rule creation: - mlx5dr rule is parametrized by action template on which these rule's actions are based. - Rule index hint is provided to mlx5dr. Signed-off-by: Dariusz Sosnowski --- drivers/net/mlx5/linux/mlx5_os.c | 1 + drivers/net/mlx5/mlx5.c | 4 +- drivers/net/mlx5/mlx5.h | 2 + drivers/net/mlx5/mlx5_flow.h | 30 +- drivers/net/mlx5/mlx5_flow_hw.c | 617 +++++++++++++++++++++++++------ drivers/net/mlx5/mlx5_trigger.c | 10 + 6 files changed, 541 insertions(+), 123 deletions(-) diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index 061b825e7b..65795da516 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -1565,6 +1565,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, } /* Only HWS requires this information. */ flow_hw_init_tags_set(eth_dev); + flow_hw_init_flow_metadata_config(eth_dev); if (priv->sh->config.dv_esw_en && flow_hw_create_vport_action(eth_dev)) { DRV_LOG(ERR, "port %u failed to create vport action", diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index b6a66f12ee..cf7b7b7158 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -1969,8 +1969,10 @@ mlx5_dev_close(struct rte_eth_dev *dev) flow_hw_destroy_vport_action(dev); flow_hw_resource_release(dev); flow_hw_clear_port_info(dev); - if (priv->sh->config.dv_flow_en == 2) + if (priv->sh->config.dv_flow_en == 2) { + flow_hw_clear_flow_metadata_config(); flow_hw_clear_tags_set(dev); + } #endif if (priv->rxq_privs != NULL) { /* XXX race condition if mlx5_rx_burst() is still running. */ diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 4859f5a509..c0835e725f 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -1644,6 +1644,8 @@ struct mlx5_priv { struct mlx5dr_action *hw_drop[2]; /* HW steering global tag action. */ struct mlx5dr_action *hw_tag[2]; + /* HW steering create ongoing rte flow table list header. */ + LIST_HEAD(flow_hw_tbl_ongo, rte_flow_template_table) flow_hw_tbl_ongo; struct mlx5_indexed_pool *acts_ipool; /* Action data indexed pool. */ #endif }; diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 8f1b66eaac..ae1417f10e 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -1175,6 +1175,11 @@ struct rte_flow_actions_template { struct rte_flow_actions_template_attr attr; struct rte_flow_action *actions; /* Cached flow actions. */ struct rte_flow_action *masks; /* Cached action masks.*/ + struct mlx5dr_action_template *tmpl; /* mlx5dr action template. */ + uint16_t dr_actions_num; /* Amount of DR rules actions. */ + uint16_t actions_num; /* Amount of flow actions */ + uint16_t *actions_off; /* DR action offset for given rte action offset. */ + uint16_t reformat_off; /* Offset of DR reformat action. */ uint16_t mhdr_off; /* Offset of DR modify header action. */ uint32_t refcnt; /* Reference counter. */ uint16_t rx_cpy_pos; /* Action position of Rx metadata to be copied. */ @@ -1226,7 +1231,6 @@ struct mlx5_hw_actions { /* Encap/Decap action. */ struct mlx5_hw_encap_decap_action *encap_decap; uint16_t encap_decap_pos; /* Encap/Decap action position. */ - uint32_t acts_num:4; /* Total action number. */ uint32_t mark:1; /* Indicate the mark action. */ uint32_t cnt_id; /* Counter id. */ /* Translated DR action array from action template. */ @@ -1482,6 +1486,13 @@ flow_hw_get_wire_port(struct ibv_context *ibctx) } #endif +extern uint32_t mlx5_flow_hw_flow_metadata_config_refcnt; +extern uint8_t mlx5_flow_hw_flow_metadata_esw_en; +extern uint8_t mlx5_flow_hw_flow_metadata_xmeta_en; + +void flow_hw_init_flow_metadata_config(struct rte_eth_dev *dev); +void flow_hw_clear_flow_metadata_config(void); + /* * Convert metadata or tag to the actual register. * META: Can only be used to match in the FDB in this stage, fixed C_1. @@ -1493,7 +1504,20 @@ flow_hw_get_reg_id(enum rte_flow_item_type type, uint32_t id) { switch (type) { case RTE_FLOW_ITEM_TYPE_META: - return REG_C_1; + if (mlx5_flow_hw_flow_metadata_esw_en && + mlx5_flow_hw_flow_metadata_xmeta_en == MLX5_XMETA_MODE_META32_HWS) { + return REG_C_1; + } + /* + * On root table - PMD allows only egress META matching, thus + * REG_A matching is sufficient. + * + * On non-root tables - REG_A corresponds to general_purpose_lookup_field, + * which translates to REG_A in NIC TX and to REG_B in NIC RX. + * However, current FW does not implement REG_B case right now, so + * REG_B case should be rejected on pattern template validation. + */ + return REG_A; case RTE_FLOW_ITEM_TYPE_TAG: MLX5_ASSERT(id < MLX5_FLOW_HW_TAGS_MAX); return mlx5_flow_hw_avl_tags[id]; @@ -2402,4 +2426,6 @@ int mlx5_flow_pattern_validate(struct rte_eth_dev *dev, const struct rte_flow_pattern_template_attr *attr, const struct rte_flow_item items[], struct rte_flow_error *error); +int flow_hw_table_update(struct rte_eth_dev *dev, + struct rte_flow_error *error); #endif /* RTE_PMD_MLX5_FLOW_H_ */ diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 507abb54e4..91835cd024 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -340,6 +340,13 @@ __flow_hw_action_template_destroy(struct rte_eth_dev *dev, struct mlx5_hw_actions *acts) { struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_action_construct_data *data; + + while (!LIST_EMPTY(&acts->act_list)) { + data = LIST_FIRST(&acts->act_list); + LIST_REMOVE(data, next); + mlx5_ipool_free(priv->acts_ipool, data->idx); + } if (acts->jump) { struct mlx5_flow_group *grp; @@ -349,6 +356,16 @@ __flow_hw_action_template_destroy(struct rte_eth_dev *dev, mlx5_hlist_unregister(priv->sh->flow_tbls, &grp->entry); acts->jump = NULL; } + if (acts->tir) { + mlx5_hrxq_release(dev, acts->tir->idx); + acts->tir = NULL; + } + if (acts->encap_decap) { + if (acts->encap_decap->action) + mlx5dr_action_destroy(acts->encap_decap->action); + mlx5_free(acts->encap_decap); + acts->encap_decap = NULL; + } if (acts->mhdr) { if (acts->mhdr->action) mlx5dr_action_destroy(acts->mhdr->action); @@ -967,33 +984,29 @@ flow_hw_represented_port_compile(struct rte_eth_dev *dev, static __rte_always_inline int flow_hw_meter_compile(struct rte_eth_dev *dev, const struct mlx5_flow_template_table_cfg *cfg, - uint32_t start_pos, const struct rte_flow_action *action, - struct mlx5_hw_actions *acts, uint32_t *end_pos, + uint16_t aso_mtr_pos, + uint16_t jump_pos, + const struct rte_flow_action *action, + struct mlx5_hw_actions *acts, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_aso_mtr *aso_mtr; const struct rte_flow_action_meter *meter = action->conf; - uint32_t pos = start_pos; uint32_t group = cfg->attr.flow_attr.group; aso_mtr = mlx5_aso_meter_by_idx(priv, meter->mtr_id); - acts->rule_acts[pos].action = priv->mtr_bulk.action; - acts->rule_acts[pos].aso_meter.offset = aso_mtr->offset; - acts->jump = flow_hw_jump_action_register + acts->rule_acts[aso_mtr_pos].action = priv->mtr_bulk.action; + acts->rule_acts[aso_mtr_pos].aso_meter.offset = aso_mtr->offset; + acts->jump = flow_hw_jump_action_register (dev, cfg, aso_mtr->fm.group, error); - if (!acts->jump) { - *end_pos = start_pos; + if (!acts->jump) return -ENOMEM; - } - acts->rule_acts[++pos].action = (!!group) ? + acts->rule_acts[jump_pos].action = (!!group) ? acts->jump->hws_action : acts->jump->root_action; - *end_pos = pos; - if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) { - *end_pos = start_pos; + if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) return -ENOMEM; - } return 0; } @@ -1046,11 +1059,11 @@ flow_hw_cnt_compile(struct rte_eth_dev *dev, uint32_t start_pos, * Table on success, NULL otherwise and rte_errno is set. */ static int -flow_hw_actions_translate(struct rte_eth_dev *dev, - const struct mlx5_flow_template_table_cfg *cfg, - struct mlx5_hw_actions *acts, - struct rte_flow_actions_template *at, - struct rte_flow_error *error) +__flow_hw_actions_translate(struct rte_eth_dev *dev, + const struct mlx5_flow_template_table_cfg *cfg, + struct mlx5_hw_actions *acts, + struct rte_flow_actions_template *at, + struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; const struct rte_flow_template_table_attr *table_attr = &cfg->attr; @@ -1061,12 +1074,15 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, enum mlx5dr_action_reformat_type refmt_type = 0; const struct rte_flow_action_raw_encap *raw_encap_data; const struct rte_flow_item *enc_item = NULL, *enc_item_m = NULL; - uint16_t reformat_pos = MLX5_HW_MAX_ACTS, reformat_src = 0; + uint16_t reformat_src = 0; uint8_t *encap_data = NULL, *encap_data_m = NULL; size_t data_size = 0; struct mlx5_hw_modify_header_action mhdr = { 0 }; bool actions_end = false; - uint32_t type, i; + uint32_t type; + bool reformat_used = false; + uint16_t action_pos; + uint16_t jump_pos; int err; flow_hw_modify_field_init(&mhdr, at); @@ -1076,46 +1092,53 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, type = MLX5DR_TABLE_TYPE_NIC_TX; else type = MLX5DR_TABLE_TYPE_NIC_RX; - for (i = 0; !actions_end; actions++, masks++) { + for (; !actions_end; actions++, masks++) { switch (actions->type) { case RTE_FLOW_ACTION_TYPE_INDIRECT: + action_pos = at->actions_off[actions - at->actions]; if (!attr->group) { DRV_LOG(ERR, "Indirect action is not supported in root table."); goto err; } if (actions->conf && masks->conf) { if (flow_hw_shared_action_translate - (dev, actions, acts, actions - action_start, i)) + (dev, actions, acts, actions - action_start, action_pos)) goto err; } else if (__flow_hw_act_data_general_append (priv, acts, actions->type, - actions - action_start, i)){ + actions - action_start, action_pos)){ goto err; } - i++; break; case RTE_FLOW_ACTION_TYPE_VOID: break; case RTE_FLOW_ACTION_TYPE_DROP: - acts->rule_acts[i++].action = + action_pos = at->actions_off[actions - at->actions]; + acts->rule_acts[action_pos].action = priv->hw_drop[!!attr->group]; break; case RTE_FLOW_ACTION_TYPE_MARK: + action_pos = at->actions_off[actions - at->actions]; acts->mark = true; - if (masks->conf) - acts->rule_acts[i].tag.value = + if (masks->conf && + ((const struct rte_flow_action_mark *) + masks->conf)->id) + acts->rule_acts[action_pos].tag.value = mlx5_flow_mark_set (((const struct rte_flow_action_mark *) - (masks->conf))->id); + (actions->conf))->id); else if (__flow_hw_act_data_general_append(priv, acts, - actions->type, actions - action_start, i)) + actions->type, actions - action_start, action_pos)) goto err; - acts->rule_acts[i++].action = + acts->rule_acts[action_pos].action = priv->hw_tag[!!attr->group]; flow_hw_rxq_flag_set(dev, true); break; case RTE_FLOW_ACTION_TYPE_JUMP: - if (masks->conf) { + action_pos = at->actions_off[actions - at->actions]; + if (masks->conf && + ((const struct rte_flow_action_jump *) + masks->conf)->group) { uint32_t jump_group = ((const struct rte_flow_action_jump *) actions->conf)->group; @@ -1123,76 +1146,77 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, (dev, cfg, jump_group, error); if (!acts->jump) goto err; - acts->rule_acts[i].action = (!!attr->group) ? + acts->rule_acts[action_pos].action = (!!attr->group) ? acts->jump->hws_action : acts->jump->root_action; } else if (__flow_hw_act_data_general_append (priv, acts, actions->type, - actions - action_start, i)){ + actions - action_start, action_pos)){ goto err; } - i++; break; case RTE_FLOW_ACTION_TYPE_QUEUE: - if (masks->conf) { + action_pos = at->actions_off[actions - at->actions]; + if (masks->conf && + ((const struct rte_flow_action_queue *) + masks->conf)->index) { acts->tir = flow_hw_tir_action_register (dev, mlx5_hw_act_flag[!!attr->group][type], actions); if (!acts->tir) goto err; - acts->rule_acts[i].action = + acts->rule_acts[action_pos].action = acts->tir->action; } else if (__flow_hw_act_data_general_append (priv, acts, actions->type, - actions - action_start, i)) { + actions - action_start, action_pos)) { goto err; } - i++; break; case RTE_FLOW_ACTION_TYPE_RSS: - if (masks->conf) { + action_pos = at->actions_off[actions - at->actions]; + if (actions->conf && masks->conf) { acts->tir = flow_hw_tir_action_register (dev, mlx5_hw_act_flag[!!attr->group][type], actions); if (!acts->tir) goto err; - acts->rule_acts[i].action = + acts->rule_acts[action_pos].action = acts->tir->action; } else if (__flow_hw_act_data_general_append (priv, acts, actions->type, - actions - action_start, i)) { + actions - action_start, action_pos)) { goto err; } - i++; break; case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: - MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS); + MLX5_ASSERT(!reformat_used); enc_item = ((const struct rte_flow_action_vxlan_encap *) actions->conf)->definition; if (masks->conf) enc_item_m = ((const struct rte_flow_action_vxlan_encap *) masks->conf)->definition; - reformat_pos = i++; + reformat_used = true; reformat_src = actions - action_start; refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2; break; case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: - MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS); + MLX5_ASSERT(!reformat_used); enc_item = ((const struct rte_flow_action_nvgre_encap *) actions->conf)->definition; if (masks->conf) enc_item_m = ((const struct rte_flow_action_nvgre_encap *) masks->conf)->definition; - reformat_pos = i++; + reformat_used = true; reformat_src = actions - action_start; refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2; break; case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: - MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS); - reformat_pos = i++; + MLX5_ASSERT(!reformat_used); + reformat_used = true; refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2; break; case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: @@ -1206,25 +1230,23 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, actions->conf; encap_data = raw_encap_data->data; data_size = raw_encap_data->size; - if (reformat_pos != MLX5_HW_MAX_ACTS) { + if (reformat_used) { refmt_type = data_size < MLX5_ENCAPSULATION_DECISION_SIZE ? MLX5DR_ACTION_REFORMAT_TYPE_TNL_L3_TO_L2 : MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L3; } else { - reformat_pos = i++; + reformat_used = true; refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2; } reformat_src = actions - action_start; break; case RTE_FLOW_ACTION_TYPE_RAW_DECAP: - reformat_pos = i++; + reformat_used = true; refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2; break; case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: - if (mhdr.pos == UINT16_MAX) - mhdr.pos = i++; err = flow_hw_modify_field_compile(dev, attr, action_start, actions, masks, acts, &mhdr, error); @@ -1242,40 +1264,46 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, action_start += 1; break; case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: + action_pos = at->actions_off[actions - at->actions]; if (flow_hw_represented_port_compile (dev, attr, action_start, actions, - masks, acts, i, error)) + masks, acts, action_pos, error)) goto err; - i++; break; case RTE_FLOW_ACTION_TYPE_METER: + /* + * METER action is compiled to 2 DR actions - ASO_METER and FT. + * Calculated DR offset is stored only for ASO_METER and FT + * is assumed to be the next action. + */ + action_pos = at->actions_off[actions - at->actions]; + jump_pos = action_pos + 1; if (actions->conf && masks->conf && ((const struct rte_flow_action_meter *) masks->conf)->mtr_id) { err = flow_hw_meter_compile(dev, cfg, - i, actions, acts, &i, error); + action_pos, jump_pos, actions, acts, error); if (err) goto err; } else if (__flow_hw_act_data_general_append(priv, acts, actions->type, actions - action_start, - i)) + action_pos)) goto err; - i++; break; case RTE_FLOW_ACTION_TYPE_COUNT: + action_pos = at->actions_off[actions - action_start]; if (masks->conf && ((const struct rte_flow_action_count *) masks->conf)->id) { - err = flow_hw_cnt_compile(dev, i, acts); + err = flow_hw_cnt_compile(dev, action_pos, acts); if (err) goto err; } else if (__flow_hw_act_data_general_append (priv, acts, actions->type, - actions - action_start, i)) { + actions - action_start, action_pos)) { goto err; } - i++; break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; @@ -1309,10 +1337,11 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, goto err; acts->rule_acts[acts->mhdr->pos].action = acts->mhdr->action; } - if (reformat_pos != MLX5_HW_MAX_ACTS) { + if (reformat_used) { uint8_t buf[MLX5_ENCAP_MAX_LEN]; bool shared_rfmt = true; + MLX5_ASSERT(at->reformat_off != UINT16_MAX); if (enc_item) { MLX5_ASSERT(!encap_data); if (flow_dv_convert_encap_data(enc_item, buf, &data_size, error)) @@ -1340,20 +1369,17 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, (shared_rfmt ? MLX5DR_ACTION_FLAG_SHARED : 0)); if (!acts->encap_decap->action) goto err; - acts->rule_acts[reformat_pos].action = - acts->encap_decap->action; - acts->rule_acts[reformat_pos].reformat.data = - acts->encap_decap->data; + acts->rule_acts[at->reformat_off].action = acts->encap_decap->action; + acts->rule_acts[at->reformat_off].reformat.data = acts->encap_decap->data; if (shared_rfmt) - acts->rule_acts[reformat_pos].reformat.offset = 0; + acts->rule_acts[at->reformat_off].reformat.offset = 0; else if (__flow_hw_act_data_encap_append(priv, acts, (action_start + reformat_src)->type, - reformat_src, reformat_pos, data_size)) + reformat_src, at->reformat_off, data_size)) goto err; acts->encap_decap->shared = shared_rfmt; - acts->encap_decap_pos = reformat_pos; + acts->encap_decap_pos = at->reformat_off; } - acts->acts_num = i; return 0; err: err = rte_errno; @@ -1363,6 +1389,40 @@ flow_hw_actions_translate(struct rte_eth_dev *dev, "fail to create rte table"); } +/** + * Translate rte_flow actions to DR action. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[in] tbl + * Pointer to the flow template table. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, negative value otherwise and rte_errno is set. + */ +static int +flow_hw_actions_translate(struct rte_eth_dev *dev, + struct rte_flow_template_table *tbl, + struct rte_flow_error *error) +{ + uint32_t i; + + for (i = 0; i < tbl->nb_action_templates; i++) { + if (__flow_hw_actions_translate(dev, &tbl->cfg, + &tbl->ats[i].acts, + tbl->ats[i].action_template, + error)) + goto err; + } + return 0; +err: + while (i--) + __flow_hw_action_template_destroy(dev, &tbl->ats[i].acts); + return -1; +} + /** * Get shared indirect action. * @@ -1611,16 +1671,17 @@ flow_hw_modify_field_construct(struct mlx5_hw_q_job *job, static __rte_always_inline int flow_hw_actions_construct(struct rte_eth_dev *dev, struct mlx5_hw_q_job *job, - const struct mlx5_hw_actions *hw_acts, + const struct mlx5_hw_action_template *hw_at, const uint8_t it_idx, const struct rte_flow_action actions[], struct mlx5dr_rule_action *rule_acts, - uint32_t *acts_num, uint32_t queue) { struct mlx5_priv *priv = dev->data->dev_private; struct rte_flow_template_table *table = job->flow->table; struct mlx5_action_construct_data *act_data; + const struct rte_flow_actions_template *at = hw_at->action_template; + const struct mlx5_hw_actions *hw_acts = &hw_at->acts; const struct rte_flow_action *action; const struct rte_flow_action_raw_encap *raw_encap_data; const struct rte_flow_item *enc_item = NULL; @@ -1636,11 +1697,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, struct mlx5_aso_mtr *mtr; uint32_t mtr_id; - memcpy(rule_acts, hw_acts->rule_acts, - sizeof(*rule_acts) * hw_acts->acts_num); - *acts_num = hw_acts->acts_num; - if (LIST_EMPTY(&hw_acts->act_list)) - return 0; + rte_memcpy(rule_acts, hw_acts->rule_acts, sizeof(*rule_acts) * at->dr_actions_num); attr.group = table->grp->group_id; ft_flag = mlx5_hw_act_flag[!!table->grp->group_id][table->type]; if (table->type == MLX5DR_TABLE_TYPE_FDB) { @@ -1774,7 +1831,6 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, jump->root_action; job->flow->jump = jump; job->flow->fate_type = MLX5_FLOW_FATE_JUMP; - (*acts_num)++; if (mlx5_aso_mtr_wait(priv->sh, mtr)) return -1; break; @@ -1912,13 +1968,16 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev, .burst = attr->postpone, }; struct mlx5dr_rule_action rule_acts[MLX5_HW_MAX_ACTS]; - struct mlx5_hw_actions *hw_acts; struct rte_flow_hw *flow; struct mlx5_hw_q_job *job; const struct rte_flow_item *rule_items; - uint32_t acts_num, flow_idx; + uint32_t flow_idx; int ret; + if (unlikely((!dev->data->dev_started))) { + rte_errno = EINVAL; + goto error; + } if (unlikely(!priv->hw_q[queue].job_idx)) { rte_errno = ENOMEM; goto error; @@ -1941,7 +2000,12 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev, job->flow = flow; job->user_data = user_data; rule_attr.user_data = job; - hw_acts = &table->ats[action_template_index].acts; + /* + * Indexed pool returns 1-based indices, but mlx5dr expects 0-based indices for rule + * insertion hints. + */ + MLX5_ASSERT(flow_idx > 0); + rule_attr.rule_idx = flow_idx - 1; /* * Construct the flow actions based on the input actions. * The implicitly appended action is always fixed, like metadata @@ -1949,8 +2013,8 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev, * No need to copy and contrust a new "actions" list based on the * user's input, in order to save the cost. */ - if (flow_hw_actions_construct(dev, job, hw_acts, pattern_template_index, - actions, rule_acts, &acts_num, queue)) { + if (flow_hw_actions_construct(dev, job, &table->ats[action_template_index], + pattern_template_index, actions, rule_acts, queue)) { rte_errno = EINVAL; goto free; } @@ -1959,7 +2023,7 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev, if (!rule_items) goto free; ret = mlx5dr_rule_create(table->matcher, - pattern_template_index, items, + pattern_template_index, rule_items, action_template_index, rule_acts, &rule_attr, &flow->rule); if (likely(!ret)) @@ -2295,6 +2359,7 @@ flow_hw_table_create(struct rte_eth_dev *dev, struct rte_flow_template_table *tbl = NULL; struct mlx5_flow_group *grp; struct mlx5dr_match_template *mt[MLX5_HW_TBL_MAX_ITEM_TEMPLATE]; + struct mlx5dr_action_template *at[MLX5_HW_TBL_MAX_ACTION_TEMPLATE]; const struct rte_flow_template_table_attr *attr = &table_cfg->attr; struct rte_flow_attr flow_attr = attr->flow_attr; struct mlx5_flow_cb_ctx ctx = { @@ -2315,6 +2380,7 @@ flow_hw_table_create(struct rte_eth_dev *dev, struct mlx5_list_entry *ge; uint32_t i, max_tpl = MLX5_HW_TBL_MAX_ITEM_TEMPLATE; uint32_t nb_flows = rte_align32pow2(attr->nb_flows); + bool port_started = !!dev->data->dev_started; int err; /* HWS layer accepts only 1 item template with root table. */ @@ -2349,12 +2415,20 @@ flow_hw_table_create(struct rte_eth_dev *dev, tbl->grp = grp; /* Prepare matcher information. */ matcher_attr.priority = attr->flow_attr.priority; + matcher_attr.optimize_using_rule_idx = true; matcher_attr.mode = MLX5DR_MATCHER_RESOURCE_MODE_RULE; matcher_attr.rule.num_log = rte_log2_u32(nb_flows); /* Build the item template. */ for (i = 0; i < nb_item_templates; i++) { uint32_t ret; + if ((flow_attr.ingress && !item_templates[i]->attr.ingress) || + (flow_attr.egress && !item_templates[i]->attr.egress) || + (flow_attr.transfer && !item_templates[i]->attr.transfer)) { + DRV_LOG(ERR, "pattern template and template table attribute mismatch"); + rte_errno = EINVAL; + goto it_error; + } ret = __atomic_add_fetch(&item_templates[i]->refcnt, 1, __ATOMIC_RELAXED); if (ret <= 1) { @@ -2364,10 +2438,6 @@ flow_hw_table_create(struct rte_eth_dev *dev, mt[i] = item_templates[i]->mt; tbl->its[i] = item_templates[i]; } - tbl->matcher = mlx5dr_matcher_create - (tbl->grp->tbl, mt, nb_item_templates, NULL, 0, &matcher_attr); - if (!tbl->matcher) - goto it_error; tbl->nb_item_templates = nb_item_templates; /* Build the action template. */ for (i = 0; i < nb_action_templates; i++) { @@ -2379,21 +2449,31 @@ flow_hw_table_create(struct rte_eth_dev *dev, rte_errno = EINVAL; goto at_error; } + at[i] = action_templates[i]->tmpl; + tbl->ats[i].action_template = action_templates[i]; LIST_INIT(&tbl->ats[i].acts.act_list); - err = flow_hw_actions_translate(dev, &tbl->cfg, - &tbl->ats[i].acts, - action_templates[i], error); + if (!port_started) + continue; + err = __flow_hw_actions_translate(dev, &tbl->cfg, + &tbl->ats[i].acts, + action_templates[i], error); if (err) { i++; goto at_error; } - tbl->ats[i].action_template = action_templates[i]; } tbl->nb_action_templates = nb_action_templates; + tbl->matcher = mlx5dr_matcher_create + (tbl->grp->tbl, mt, nb_item_templates, at, nb_action_templates, &matcher_attr); + if (!tbl->matcher) + goto at_error; tbl->type = attr->flow_attr.transfer ? MLX5DR_TABLE_TYPE_FDB : (attr->flow_attr.egress ? MLX5DR_TABLE_TYPE_NIC_TX : MLX5DR_TABLE_TYPE_NIC_RX); - LIST_INSERT_HEAD(&priv->flow_hw_tbl, tbl, next); + if (port_started) + LIST_INSERT_HEAD(&priv->flow_hw_tbl, tbl, next); + else + LIST_INSERT_HEAD(&priv->flow_hw_tbl_ongo, tbl, next); return tbl; at_error: while (i--) { @@ -2406,7 +2486,6 @@ flow_hw_table_create(struct rte_eth_dev *dev, while (i--) __atomic_sub_fetch(&item_templates[i]->refcnt, 1, __ATOMIC_RELAXED); - mlx5dr_matcher_destroy(tbl->matcher); error: err = rte_errno; if (tbl) { @@ -2423,6 +2502,33 @@ flow_hw_table_create(struct rte_eth_dev *dev, return NULL; } +/** + * Update flow template table. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, negative value otherwise and rte_errno is set. + */ +int +flow_hw_table_update(struct rte_eth_dev *dev, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_flow_template_table *tbl; + + while ((tbl = LIST_FIRST(&priv->flow_hw_tbl_ongo)) != NULL) { + if (flow_hw_actions_translate(dev, tbl, error)) + return -1; + LIST_REMOVE(tbl, next); + LIST_INSERT_HEAD(&priv->flow_hw_tbl, tbl, next); + } + return 0; +} + /** * Translates group index specified by the user in @p attr to internal * group index. @@ -2501,6 +2607,7 @@ flow_hw_template_table_create(struct rte_eth_dev *dev, uint8_t nb_action_templates, struct rte_flow_error *error) { + struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_flow_template_table_cfg cfg = { .attr = *attr, .external = true, @@ -2509,6 +2616,12 @@ flow_hw_template_table_create(struct rte_eth_dev *dev, if (flow_hw_translate_group(dev, &cfg, group, &cfg.attr.flow_attr.group, error)) return NULL; + if (priv->sh->config.dv_esw_en && cfg.attr.flow_attr.egress) { + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR, NULL, + "egress flows are not supported with HW Steering" + " when E-Switch is enabled"); + return NULL; + } return flow_hw_table_create(dev, &cfg, item_templates, nb_item_templates, action_templates, nb_action_templates, error); } @@ -2750,7 +2863,8 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, const struct rte_flow_action *mask = &masks[i]; MLX5_ASSERT(i < MLX5_HW_MAX_ACTS); - if (action->type != mask->type) + if (action->type != RTE_FLOW_ACTION_TYPE_INDIRECT && + action->type != mask->type) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, action, @@ -2826,6 +2940,157 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, return 0; } +static enum mlx5dr_action_type mlx5_hw_dr_action_types[] = { + [RTE_FLOW_ACTION_TYPE_MARK] = MLX5DR_ACTION_TYP_TAG, + [RTE_FLOW_ACTION_TYPE_DROP] = MLX5DR_ACTION_TYP_DROP, + [RTE_FLOW_ACTION_TYPE_JUMP] = MLX5DR_ACTION_TYP_FT, + [RTE_FLOW_ACTION_TYPE_QUEUE] = MLX5DR_ACTION_TYP_TIR, + [RTE_FLOW_ACTION_TYPE_RSS] = MLX5DR_ACTION_TYP_TIR, + [RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP] = MLX5DR_ACTION_TYP_L2_TO_TNL_L2, + [RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP] = MLX5DR_ACTION_TYP_L2_TO_TNL_L2, + [RTE_FLOW_ACTION_TYPE_VXLAN_DECAP] = MLX5DR_ACTION_TYP_TNL_L2_TO_L2, + [RTE_FLOW_ACTION_TYPE_NVGRE_DECAP] = MLX5DR_ACTION_TYP_TNL_L2_TO_L2, + [RTE_FLOW_ACTION_TYPE_MODIFY_FIELD] = MLX5DR_ACTION_TYP_MODIFY_HDR, + [RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT] = MLX5DR_ACTION_TYP_VPORT, + [RTE_FLOW_ACTION_TYPE_COUNT] = MLX5DR_ACTION_TYP_CTR, +}; + +static int +flow_hw_dr_actions_template_handle_shared(const struct rte_flow_action *mask, + unsigned int action_src, + enum mlx5dr_action_type *action_types, + uint16_t *curr_off, + struct rte_flow_actions_template *at) +{ + uint32_t type; + + if (!mask) { + DRV_LOG(WARNING, "Unable to determine indirect action type " + "without a mask specified"); + return -EINVAL; + } + type = mask->type; + switch (type) { + case RTE_FLOW_ACTION_TYPE_RSS: + at->actions_off[action_src] = *curr_off; + action_types[*curr_off] = MLX5DR_ACTION_TYP_TIR; + *curr_off = *curr_off + 1; + break; + case RTE_FLOW_ACTION_TYPE_COUNT: + at->actions_off[action_src] = *curr_off; + action_types[*curr_off] = MLX5DR_ACTION_TYP_CTR; + *curr_off = *curr_off + 1; + break; + default: + DRV_LOG(WARNING, "Unsupported shared action type: %d", type); + return -EINVAL; + } + return 0; +} + +/** + * Create DR action template based on a provided sequence of flow actions. + * + * @param[in] at + * Pointer to flow actions template to be updated. + * + * @return + * DR action template pointer on success and action offsets in @p at are updated. + * NULL otherwise. + */ +static struct mlx5dr_action_template * +flow_hw_dr_actions_template_create(struct rte_flow_actions_template *at) +{ + struct mlx5dr_action_template *dr_template; + enum mlx5dr_action_type action_types[MLX5_HW_MAX_ACTS] = { MLX5DR_ACTION_TYP_LAST }; + unsigned int i; + uint16_t curr_off; + enum mlx5dr_action_type reformat_act_type = MLX5DR_ACTION_TYP_TNL_L2_TO_L2; + uint16_t reformat_off = UINT16_MAX; + uint16_t mhdr_off = UINT16_MAX; + int ret; + for (i = 0, curr_off = 0; at->actions[i].type != RTE_FLOW_ACTION_TYPE_END; ++i) { + const struct rte_flow_action_raw_encap *raw_encap_data; + size_t data_size; + enum mlx5dr_action_type type; + + if (curr_off >= MLX5_HW_MAX_ACTS) + goto err_actions_num; + switch (at->actions[i].type) { + case RTE_FLOW_ACTION_TYPE_VOID: + break; + case RTE_FLOW_ACTION_TYPE_INDIRECT: + ret = flow_hw_dr_actions_template_handle_shared(&at->masks[i], i, + action_types, + &curr_off, at); + if (ret) + return NULL; + break; + case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: + case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: + case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: + case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: + MLX5_ASSERT(reformat_off == UINT16_MAX); + reformat_off = curr_off++; + reformat_act_type = mlx5_hw_dr_action_types[at->actions[i].type]; + break; + case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: + raw_encap_data = at->actions[i].conf; + data_size = raw_encap_data->size; + if (reformat_off != UINT16_MAX) { + reformat_act_type = data_size < MLX5_ENCAPSULATION_DECISION_SIZE ? + MLX5DR_ACTION_TYP_TNL_L3_TO_L2 : + MLX5DR_ACTION_TYP_L2_TO_TNL_L3; + } else { + reformat_off = curr_off++; + reformat_act_type = MLX5DR_ACTION_TYP_L2_TO_TNL_L2; + } + break; + case RTE_FLOW_ACTION_TYPE_RAW_DECAP: + reformat_off = curr_off++; + reformat_act_type = MLX5DR_ACTION_TYP_TNL_L2_TO_L2; + break; + case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: + if (mhdr_off == UINT16_MAX) { + mhdr_off = curr_off++; + type = mlx5_hw_dr_action_types[at->actions[i].type]; + action_types[mhdr_off] = type; + } + break; + case RTE_FLOW_ACTION_TYPE_METER: + at->actions_off[i] = curr_off; + action_types[curr_off++] = MLX5DR_ACTION_TYP_ASO_METER; + if (curr_off >= MLX5_HW_MAX_ACTS) + goto err_actions_num; + action_types[curr_off++] = MLX5DR_ACTION_TYP_FT; + break; + default: + type = mlx5_hw_dr_action_types[at->actions[i].type]; + at->actions_off[i] = curr_off; + action_types[curr_off++] = type; + break; + } + } + if (curr_off >= MLX5_HW_MAX_ACTS) + goto err_actions_num; + if (mhdr_off != UINT16_MAX) + at->mhdr_off = mhdr_off; + if (reformat_off != UINT16_MAX) { + at->reformat_off = reformat_off; + action_types[reformat_off] = reformat_act_type; + } + dr_template = mlx5dr_action_template_create(action_types); + if (dr_template) + at->dr_actions_num = curr_off; + else + DRV_LOG(ERR, "Failed to create DR action template: %d", rte_errno); + return dr_template; +err_actions_num: + DRV_LOG(ERR, "Number of HW actions (%u) exceeded maximum (%u) allowed in template", + curr_off, MLX5_HW_MAX_ACTS); + return NULL; +} + /** * Create flow action template. * @@ -2851,7 +3116,8 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; - int len, act_len, mask_len, i; + int len, act_num, act_len, mask_len; + unsigned int i; struct rte_flow_actions_template *at = NULL; uint16_t pos = MLX5_HW_MAX_ACTS; struct rte_flow_action tmp_action[MLX5_HW_MAX_ACTS]; @@ -2921,6 +3187,11 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, if (mask_len <= 0) return NULL; len += RTE_ALIGN(mask_len, 16); + /* Count flow actions to allocate required space for storing DR offsets. */ + act_num = 0; + for (i = 0; ra[i].type != RTE_FLOW_ACTION_TYPE_END; ++i) + act_num++; + len += RTE_ALIGN(act_num * sizeof(*at->actions_off), 16); at = mlx5_malloc(MLX5_MEM_ZERO, len + sizeof(*at), RTE_CACHE_LINE_SIZE, rte_socket_id()); if (!at) { @@ -2930,19 +3201,26 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, "cannot allocate action template"); return NULL; } - /* Actions part is in the first half. */ + /* Actions part is in the first part. */ at->attr = *attr; at->actions = (struct rte_flow_action *)(at + 1); act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->actions, len, ra, error); if (act_len <= 0) goto error; - /* Masks part is in the second half. */ + /* Masks part is in the second part. */ at->masks = (struct rte_flow_action *)(((uint8_t *)at->actions) + act_len); mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->masks, len - act_len, rm, error); if (mask_len <= 0) goto error; + /* DR actions offsets in the third part. */ + at->actions_off = (uint16_t *)((uint8_t *)at->masks + mask_len); + at->actions_num = act_num; + for (i = 0; i < at->actions_num; ++i) + at->actions_off[i] = UINT16_MAX; + at->reformat_off = UINT16_MAX; + at->mhdr_off = UINT16_MAX; at->rx_cpy_pos = pos; /* * mlx5 PMD hacks indirect action index directly to the action conf. @@ -2956,12 +3234,18 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, at->masks[i].conf = masks->conf; } } + at->tmpl = flow_hw_dr_actions_template_create(at); + if (!at->tmpl) + goto error; __atomic_fetch_add(&at->refcnt, 1, __ATOMIC_RELAXED); LIST_INSERT_HEAD(&priv->flow_hw_at, at, next); return at; error: - if (at) + if (at) { + if (at->tmpl) + mlx5dr_action_template_destroy(at->tmpl); mlx5_free(at); + } return NULL; } @@ -2992,6 +3276,8 @@ flow_hw_actions_template_destroy(struct rte_eth_dev *dev __rte_unused, "action template in using"); } LIST_REMOVE(template, next); + if (template->tmpl) + mlx5dr_action_template_destroy(template->tmpl); mlx5_free(template); return 0; } @@ -3042,11 +3328,48 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, const struct rte_flow_item items[], struct rte_flow_error *error) { + struct mlx5_priv *priv = dev->data->dev_private; int i; bool items_end = false; - RTE_SET_USED(dev); - RTE_SET_USED(attr); + if (!attr->ingress && !attr->egress && !attr->transfer) + return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR, NULL, + "at least one of the direction attributes" + " must be specified"); + if (priv->sh->config.dv_esw_en) { + MLX5_ASSERT(priv->master || priv->representor); + if (priv->master) { + /* + * It is allowed to specify ingress, egress and transfer attributes + * at the same time, in order to construct flows catching all missed + * FDB traffic and forwarding it to the master port. + */ + if (!(attr->ingress ^ attr->egress ^ attr->transfer)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR, NULL, + "only one or all direction attributes" + " at once can be used on transfer proxy" + " port"); + } else { + if (attr->transfer) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, NULL, + "transfer attribute cannot be used with" + " port representors"); + if (attr->ingress && attr->egress) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR, NULL, + "ingress and egress direction attributes" + " cannot be used at the same time on" + " port representors"); + } + } else { + if (attr->transfer) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER, NULL, + "transfer attribute cannot be used when" + " E-Switch is disabled"); + } for (i = 0; !items_end; i++) { int type = items[i].type; @@ -3069,7 +3392,6 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, { const struct rte_flow_item_tag *tag = (const struct rte_flow_item_tag *)items[i].spec; - struct mlx5_priv *priv = dev->data->dev_private; uint8_t regcs = (uint8_t)priv->sh->cdev->config.hca_attr.set_reg_c; if (!((1 << (tag->index - REG_C_0)) & regcs)) @@ -3077,7 +3399,26 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Unsupported internal tag index"); + break; } + case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT: + if (attr->ingress || attr->egress) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "represented port item cannot be used" + " when transfer attribute is set"); + break; + case RTE_FLOW_ITEM_TYPE_META: + if (!priv->sh->config.dv_esw_en || + priv->sh->config.dv_xmeta_en != MLX5_XMETA_MODE_META32_HWS) { + if (attr->ingress) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "META item is not supported" + " on current FW with ingress" + " attribute"); + } + break; case RTE_FLOW_ITEM_TYPE_VOID: case RTE_FLOW_ITEM_TYPE_ETH: case RTE_FLOW_ITEM_TYPE_VLAN: @@ -3087,10 +3428,8 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, case RTE_FLOW_ITEM_TYPE_TCP: case RTE_FLOW_ITEM_TYPE_GTP: case RTE_FLOW_ITEM_TYPE_GTP_PSC: - case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT: case RTE_FLOW_ITEM_TYPE_VXLAN: case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: - case RTE_FLOW_ITEM_TYPE_META: case RTE_FLOW_ITEM_TYPE_GRE: case RTE_FLOW_ITEM_TYPE_GRE_KEY: case RTE_FLOW_ITEM_TYPE_GRE_OPTION: @@ -3138,21 +3477,7 @@ flow_hw_pattern_template_create(struct rte_eth_dev *dev, if (flow_hw_pattern_validate(dev, attr, items, error)) return NULL; - if (priv->sh->config.dv_esw_en && attr->ingress) { - /* - * Disallow pattern template with ingress and egress/transfer - * attributes in order to forbid implicit port matching - * on egress and transfer traffic. - */ - if (attr->egress || attr->transfer) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, - "item template for ingress traffic" - " cannot be used for egress/transfer" - " traffic when E-Switch is enabled"); - return NULL; - } + if (priv->sh->config.dv_esw_en && attr->ingress && !attr->egress && !attr->transfer) { copied_items = flow_hw_copy_prepend_port_item(items, error); if (!copied_items) return NULL; @@ -4542,6 +4867,10 @@ flow_hw_resource_release(struct rte_eth_dev *dev) return; flow_hw_rxq_flag_set(dev, false); flow_hw_flush_all_ctrl_flows(dev); + while (!LIST_EMPTY(&priv->flow_hw_tbl_ongo)) { + tbl = LIST_FIRST(&priv->flow_hw_tbl_ongo); + flow_hw_table_destroy(dev, tbl, NULL); + } while (!LIST_EMPTY(&priv->flow_hw_tbl)) { tbl = LIST_FIRST(&priv->flow_hw_tbl); flow_hw_table_destroy(dev, tbl, NULL); @@ -4679,6 +5008,54 @@ void flow_hw_clear_tags_set(struct rte_eth_dev *dev) sizeof(enum modify_reg) * MLX5_FLOW_HW_TAGS_MAX); } +uint32_t mlx5_flow_hw_flow_metadata_config_refcnt; +uint8_t mlx5_flow_hw_flow_metadata_esw_en; +uint8_t mlx5_flow_hw_flow_metadata_xmeta_en; + +/** + * Initializes static configuration of META flow items. + * + * As a temporary workaround, META flow item is translated to a register, + * based on statically saved dv_esw_en and dv_xmeta_en device arguments. + * It is a workaround for flow_hw_get_reg_id() where port specific information + * is not available at runtime. + * + * Values of dv_esw_en and dv_xmeta_en device arguments are taken from the first opened port. + * This means that each mlx5 port will use the same configuration for translation + * of META flow items. + * + * @param[in] dev + * Pointer to Ethernet device. + */ +void +flow_hw_init_flow_metadata_config(struct rte_eth_dev *dev) +{ + uint32_t refcnt; + + refcnt = __atomic_fetch_add(&mlx5_flow_hw_flow_metadata_config_refcnt, 1, + __ATOMIC_RELAXED); + if (refcnt > 0) + return; + mlx5_flow_hw_flow_metadata_esw_en = MLX5_SH(dev)->config.dv_esw_en; + mlx5_flow_hw_flow_metadata_xmeta_en = MLX5_SH(dev)->config.dv_xmeta_en; +} + +/** + * Clears statically stored configuration related to META flow items. + */ +void +flow_hw_clear_flow_metadata_config(void) +{ + uint32_t refcnt; + + refcnt = __atomic_sub_fetch(&mlx5_flow_hw_flow_metadata_config_refcnt, 1, + __ATOMIC_RELAXED); + if (refcnt > 0) + return; + mlx5_flow_hw_flow_metadata_esw_en = 0; + mlx5_flow_hw_flow_metadata_xmeta_en = 0; +} + /** * Create shared action. * diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index ccefebefc9..2603196933 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -1170,6 +1170,16 @@ mlx5_dev_start(struct rte_eth_dev *dev) dev->data->port_id, rte_strerror(rte_errno)); goto error; } +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + if (priv->sh->config.dv_flow_en == 2) { + ret = flow_hw_table_update(dev, NULL); + if (ret) { + DRV_LOG(ERR, "port %u failed to update HWS tables", + dev->data->port_id); + goto error; + } + } +#endif ret = mlx5_traffic_enable(dev); if (ret) { DRV_LOG(ERR, "port %u failed to set defaults flows", From patchwork Fri Sep 30 12:53:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117220 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id DBE49A00C4; Fri, 30 Sep 2022 14:55:05 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B3C1D42B99; Fri, 30 Sep 2022 14:54:09 +0200 (CEST) Received: from NAM12-MW2-obe.outbound.protection.outlook.com (mail-mw2nam12on2051.outbound.protection.outlook.com [40.107.244.51]) by mails.dpdk.org (Postfix) with ESMTP id 291AF42B96 for ; Fri, 30 Sep 2022 14:54:05 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=FLKTFXi8t3OsXicv6q57HkB1yPxCWn4Z8uyWvkknX788C8sBXXEoffmACMV7iCq1gXCaca6wat5YfeiqnBbSHtQUCMIdZz/nQxlUxxnEnBA0MiJH0aPAtomJCZ8rMr3ki2ElEbONEiGm/4JEJmI+QI1V+7dhU47Y1iZvGIy1hIBsLELboXdAU74Y1VsyFHQuLCTGtsYVjjK35GMIrPjdWDBXzl8ymP5wgeSbdWvyzaT/UO/ehjKx05Eyo91XCN5faexKpmk4b4pbAc8gK9s1gfItHEU4YdkOeH6fUnUVSJ8KeCuZN24y+erqLtADMwnaWkV/M/XPpu2jSWLtSUvuuQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=dsOrsHy9HWYPPMg3U+os6l+XQ55slRmppe/7Dlf5NFg=; b=DpahlyDERgqhQTEufkz9AQmPN0O4f5IYoeN6yuz7WHumNumCUL31JElm7bdu/P2psHU8kyPXu8BcFM14fy97WqtPsK70wtb1qiMx+S3qGYYsmFLvrKJxo+0JffZWNTRaA2s5RBeen7b2OviGA/hqQoSldpLVGdhRQcWU+P3x2mFiJJORxMJ4GkUT5sewoU3Pno80mI5fXtwraSfHGh5Zq5vIiCFxDwQAdhJjoAFZuupRaW5R/kviiey8/jhUos+RsSkG1wMlOyKHUPVF2xzDkC7tc59/mcwUNZxz1MCC4F1tuqUgeEJp2t9VeQAwPE7DLScw3W6qb4Z4pQKvOFyUWw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.161) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=dsOrsHy9HWYPPMg3U+os6l+XQ55slRmppe/7Dlf5NFg=; b=KUvV5F3w3VUqPTDvSVQ+NV6TVJ0TsmSU8nALRqITay9eXqqmEckmSAaQlyQ/HxM680wWJP1Zh8sQAl4BUUMNEz4cE5uRrZ1ZbvzuOxD+bR0y9nvvhaS7Z6swOMviMAxqrFUcH+NyDk7q/I4D0ujgEaq/Tr4vIZKnWWdXjCnAhw0x2DrSD4EVzTiOukfcrfdHzccdHvOOAymQRIgKS1vGmP0LcyMt/jHwYaUC5TZpXurH3/Gi2pYr+Hl/SvpVahQZCYgOHHCfV5kMxXq7WroLK9HqXvmR3y9Lk/5PxOPpZxHT/TBR3EjqXXQ0+MQhcAD+GITw8D6M10iUCmJtmMzclQ== Received: from DS7PR03CA0121.namprd03.prod.outlook.com (2603:10b6:5:3b4::6) by MW3PR12MB4521.namprd12.prod.outlook.com (2603:10b6:303:53::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23; Fri, 30 Sep 2022 12:54:02 +0000 Received: from DM6NAM11FT102.eop-nam11.prod.protection.outlook.com (2603:10b6:5:3b4:cafe::ad) by DS7PR03CA0121.outlook.office365.com (2603:10b6:5:3b4::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.19 via Frontend Transport; Fri, 30 Sep 2022 12:54:02 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.161) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.161 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.161; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.161) by DM6NAM11FT102.mail.protection.outlook.com (10.13.173.172) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:02 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.67) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:56 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:54 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , Subject: [PATCH v3 10/17] net/mlx5: add HW steering connection tracking support Date: Fri, 30 Sep 2022 15:53:08 +0300 Message-ID: <20220930125315.5079-11-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT102:EE_|MW3PR12MB4521:EE_ X-MS-Office365-Filtering-Correlation-Id: 41d820d4-5670-407d-7a00-08daa2e2d9a8 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: fqOTO3KAqxx8miopdbTUPzKTKUEP1QNsEZuE0yyQM6SmeoaXZIURumHFKVrAIBiYYX3QApklx27haGxfUWwWZCECoTMSpuJoObYU0OTRLF9AWX9GZ2eQJYx1tBJb8qLmmeIH+cnZixGZo7dyPxp8lAYmAESheXBIe93yYfl7rBY+X3Z6RaG6oRyDKsZITnPHrlwgY64+mlt/ljPXvwVRazxXPbeI7yvV8hBeA3kpW1+TglyYWSayyBrjwSePboi8CV2D/MbeQ+yQUJoAo/pG92J9lQFkIbLQAyqdGlhuMAQqGdEvDxRj6UjV0YO5PxPk8H7KB7JkaamKkjhI0PFpusL7WOCvwroImJLTaoOYXEhT2T2fqgM5mfl0s0IxiyBDJQnZcyFL3lyMqtuNWzKzfUZ5TAGi0nSegP7GhpEC+qaL8VV8Fb6ugAMFWd/0fW8eEcqlB7NquWWHz3UYeimAn9cG/Czms/XZ4mUXSs/VgOqJYP/AU3iFrHgWF/wGWWEpgYV/Tfr7UDxrPWomfTBb/KZI1m9PnwDXn7JawS4MDHEoB/HWq4I9D3XAU6qkuwsGae+iK2JkyGRMtFo7a7CVcg5TmZX2rTPNsihxD7NkxFLz9g9kEUsaJRCTocdy98sJO/F09c+NbDzw7QUAnAqw6F8KoXldtMb60J3YG15KmdAaoDky7NYLnH+0mqzHRoC8243VFIFwz6WuIa12sCuRLx8QBKPkUmWnDfeLUPnU0PtoSCqDnyVPWQiopd9LiBHOQ63VjOnIkKT88lNSY65s4enzZxhOhC7Eo38Y0Af6/+s= X-Forefront-Antispam-Report: CIP:216.228.117.161; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge2.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(396003)(39860400002)(136003)(376002)(346002)(451199015)(46966006)(40470700004)(36840700001)(7636003)(40480700001)(66899015)(356005)(83380400001)(478600001)(55016003)(82740400003)(82310400005)(47076005)(36756003)(6286002)(26005)(2616005)(8936002)(2906002)(107886003)(6666004)(5660300002)(1076003)(186003)(41300700001)(30864003)(316002)(16526019)(7696005)(54906003)(8676002)(36860700001)(4326008)(70206006)(70586007)(426003)(86362001)(40460700003)(6636002)(110136005)(336012)(579004)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:54:02.2789 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 41d820d4-5670-407d-7a00-08daa2e2d9a8 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.161]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT102.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW3PR12MB4521 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org This commit adds the support of connection tracking to HW steering as SW steering did before. Different with SW steering implementation, take advantage of HW steering bulk action allocation support, in HW steering only one single CT pool is needed. An indexed pool is introduced to record allocated actions from bulk and CT action state etc. Once one CT action is allocated from bulk, one indexed object will also be allocated from the indexed pool, similar for deallocate. That makes mlx5_aso_ct_action can also be managed by that indexed pool, no need to be reserved from mlx5_aso_ct_pool. The single CT pool is also saved to mlx5_aso_ct_action struct directly. The ASO operation functions are shared with SW steering implementation. Signed-off-by: Suanming Mou --- drivers/net/mlx5/linux/mlx5_os.c | 8 +- drivers/net/mlx5/mlx5.c | 3 +- drivers/net/mlx5/mlx5.h | 54 ++++- drivers/net/mlx5/mlx5_flow.c | 1 + drivers/net/mlx5/mlx5_flow.h | 7 + drivers/net/mlx5/mlx5_flow_aso.c | 212 +++++++++++++---- drivers/net/mlx5/mlx5_flow_dv.c | 28 ++- drivers/net/mlx5/mlx5_flow_hw.c | 381 ++++++++++++++++++++++++++++++- 8 files changed, 617 insertions(+), 77 deletions(-) diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index 65795da516..60a1a391fb 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -1349,9 +1349,11 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, DRV_LOG(DEBUG, "Flow Hit ASO is supported."); } #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */ -#if defined(HAVE_MLX5_DR_CREATE_ACTION_ASO) && \ - defined(HAVE_MLX5_DR_ACTION_ASO_CT) - if (hca_attr->ct_offload && priv->mtr_color_reg == REG_C_3) { +#if defined (HAVE_MLX5_DR_CREATE_ACTION_ASO) && \ + defined (HAVE_MLX5_DR_ACTION_ASO_CT) + /* HWS create CT ASO SQ based on HWS configure queue number. */ + if (sh->config.dv_flow_en != 2 && + hca_attr->ct_offload && priv->mtr_color_reg == REG_C_3) { err = mlx5_flow_aso_ct_mng_init(sh); if (err) { err = -err; diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index cf7b7b7158..925e19bcd5 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -755,7 +755,8 @@ mlx5_flow_aso_ct_mng_init(struct mlx5_dev_ctx_shared *sh) if (sh->ct_mng) return 0; - sh->ct_mng = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*sh->ct_mng), + sh->ct_mng = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*sh->ct_mng) + + sizeof(struct mlx5_aso_sq) * MLX5_ASO_CT_SQ_NUM, RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); if (!sh->ct_mng) { DRV_LOG(ERR, "ASO CT management allocation failed."); diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index c0835e725f..0578a41675 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -39,6 +39,8 @@ #define MLX5_SH(dev) (((struct mlx5_priv *)(dev)->data->dev_private)->sh) +#define MLX5_HW_INV_QUEUE UINT32_MAX + /* * Number of modification commands. * The maximal actions amount in FW is some constant, and it is 16 in the @@ -1159,7 +1161,12 @@ enum mlx5_aso_ct_state { /* Generic ASO connection tracking structure. */ struct mlx5_aso_ct_action { - LIST_ENTRY(mlx5_aso_ct_action) next; /* Pointer to the next ASO CT. */ + union { + LIST_ENTRY(mlx5_aso_ct_action) next; + /* Pointer to the next ASO CT. Used only in SWS. */ + struct mlx5_aso_ct_pool *pool; + /* Pointer to action pool. Used only in HWS. */ + }; void *dr_action_orig; /* General action object for original dir. */ void *dr_action_rply; /* General action object for reply dir. */ uint32_t refcnt; /* Action used count in device flows. */ @@ -1173,28 +1180,48 @@ struct mlx5_aso_ct_action { #define MLX5_ASO_CT_UPDATE_STATE(c, s) \ __atomic_store_n(&((c)->state), (s), __ATOMIC_RELAXED) +#ifdef PEDANTIC +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + /* ASO connection tracking software pool definition. */ struct mlx5_aso_ct_pool { uint16_t index; /* Pool index in pools array. */ + /* Free ASO CT index in the pool. Used by HWS. */ + struct mlx5_indexed_pool *cts; struct mlx5_devx_obj *devx_obj; - /* The first devx object in the bulk, used for freeing (not yet). */ - struct mlx5_aso_ct_action actions[MLX5_ASO_CT_ACTIONS_PER_POOL]; + union { + void *dummy_action; + /* Dummy action to increase the reference count in the driver. */ + struct mlx5dr_action *dr_action; + /* HWS action. */ + }; + struct mlx5_aso_sq *sq; /* Async ASO SQ. */ + struct mlx5_aso_sq *shared_sq; /* Shared ASO SQ. */ + struct mlx5_aso_ct_action actions[0]; /* CT action structures bulk. */ }; LIST_HEAD(aso_ct_list, mlx5_aso_ct_action); +#define MLX5_ASO_CT_SQ_NUM 16 + /* Pools management structure for ASO connection tracking pools. */ struct mlx5_aso_ct_pools_mng { struct mlx5_aso_ct_pool **pools; uint16_t n; /* Total number of pools. */ uint16_t next; /* Number of pools in use, index of next free pool. */ + uint32_t nb_sq; /* Number of ASO SQ. */ rte_spinlock_t ct_sl; /* The ASO CT free list lock. */ rte_rwlock_t resize_rwl; /* The ASO CT pool resize lock. */ struct aso_ct_list free_cts; /* Free ASO CT objects list. */ - struct mlx5_aso_sq aso_sq; /* ASO queue objects. */ + struct mlx5_aso_sq aso_sqs[0]; /* ASO queue objects. */ }; +#ifdef PEDANTIC +#pragma GCC diagnostic error "-Wpedantic" +#endif + /* LAG attr. */ struct mlx5_lag { uint8_t tx_remap_affinity[16]; /* The PF port number of affinity */ @@ -1332,8 +1359,7 @@ struct mlx5_dev_ctx_shared { rte_spinlock_t geneve_tlv_opt_sl; /* Lock for geneve tlv resource */ struct mlx5_flow_mtr_mng *mtrmng; /* Meter management structure. */ - struct mlx5_aso_ct_pools_mng *ct_mng; - /* Management data for ASO connection tracking. */ + struct mlx5_aso_ct_pools_mng *ct_mng; /* Management data for ASO CT in HWS only. */ struct mlx5_lb_ctx self_lb; /* QP to enable self loopback for Devx. */ unsigned int flow_max_priority; enum modify_reg flow_mreg_c[MLX5_MREG_C_NUM]; @@ -1647,6 +1673,9 @@ struct mlx5_priv { /* HW steering create ongoing rte flow table list header. */ LIST_HEAD(flow_hw_tbl_ongo, rte_flow_template_table) flow_hw_tbl_ongo; struct mlx5_indexed_pool *acts_ipool; /* Action data indexed pool. */ + struct mlx5_aso_ct_pools_mng *ct_mng; + /* Management data for ASO connection tracking. */ + struct mlx5_aso_ct_pool *hws_ctpool; /* HW steering's CT pool. */ #endif }; @@ -2046,15 +2075,15 @@ int mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, struct mlx5_aso_mtr *mtr, struct mlx5_mtr_bulk *bulk); int mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, struct mlx5_aso_mtr *mtr); -int mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh, +int mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct, const struct rte_flow_action_conntrack *profile); -int mlx5_aso_ct_wait_ready(struct mlx5_dev_ctx_shared *sh, +int mlx5_aso_ct_wait_ready(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct); -int mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh, +int mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct, struct rte_flow_action_conntrack *profile); -int mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh, +int mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct); uint32_t mlx5_get_supported_sw_parsing_offloads(const struct mlx5_hca_attr *attr); @@ -2065,6 +2094,11 @@ int mlx5_aso_cnt_queue_init(struct mlx5_dev_ctx_shared *sh); void mlx5_aso_cnt_queue_uninit(struct mlx5_dev_ctx_shared *sh); int mlx5_aso_cnt_query(struct mlx5_dev_ctx_shared *sh, struct mlx5_hws_cnt_pool *cpool); +int mlx5_aso_ct_queue_init(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_ct_pools_mng *ct_mng, + uint32_t nb_queues); +int mlx5_aso_ct_queue_uninit(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_ct_pools_mng *ct_mng); /* mlx5_flow_flex.c */ diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 658cc69750..cbf9c31984 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -49,6 +49,7 @@ struct flow_hw_port_info mlx5_flow_hw_port_infos[RTE_MAX_ETHPORTS]; */ uint32_t mlx5_flow_hw_avl_tags_init_cnt; enum modify_reg mlx5_flow_hw_avl_tags[MLX5_FLOW_HW_TAGS_MAX] = {REG_NON}; +enum modify_reg mlx5_flow_hw_aso_tag; struct tunnel_default_miss_ctx { uint16_t *queue; diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index ae1417f10e..f75a56a57b 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -82,6 +82,10 @@ enum { #define MLX5_INDIRECT_ACT_CT_GET_IDX(index) \ ((index) & ((1 << MLX5_INDIRECT_ACT_CT_OWNER_SHIFT) - 1)) +#define MLX5_ACTION_CTX_CT_GET_IDX MLX5_INDIRECT_ACT_CT_GET_IDX +#define MLX5_ACTION_CTX_CT_GET_OWNER MLX5_INDIRECT_ACT_CT_GET_OWNER +#define MLX5_ACTION_CTX_CT_GEN_IDX MLX5_INDIRECT_ACT_CT_GEN_IDX + /* Matches on selected register. */ struct mlx5_rte_flow_item_tag { enum modify_reg id; @@ -1444,6 +1448,7 @@ extern struct flow_hw_port_info mlx5_flow_hw_port_infos[RTE_MAX_ETHPORTS]; #define MLX5_FLOW_HW_TAGS_MAX 8 extern uint32_t mlx5_flow_hw_avl_tags_init_cnt; extern enum modify_reg mlx5_flow_hw_avl_tags[]; +extern enum modify_reg mlx5_flow_hw_aso_tag; /* * Get metadata match tag and mask for given rte_eth_dev port. @@ -1518,6 +1523,8 @@ flow_hw_get_reg_id(enum rte_flow_item_type type, uint32_t id) * REG_B case should be rejected on pattern template validation. */ return REG_A; + case RTE_FLOW_ITEM_TYPE_CONNTRACK: + return mlx5_flow_hw_aso_tag; case RTE_FLOW_ITEM_TYPE_TAG: MLX5_ASSERT(id < MLX5_FLOW_HW_TAGS_MAX); return mlx5_flow_hw_avl_tags[id]; diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c index ed9272e583..c00c07b891 100644 --- a/drivers/net/mlx5/mlx5_flow_aso.c +++ b/drivers/net/mlx5/mlx5_flow_aso.c @@ -313,16 +313,8 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh, mlx5_aso_mtr_init_sq(&sh->mtrmng->pools_mng.sq); break; case ASO_OPC_MOD_CONNECTION_TRACKING: - /* 64B per object for query. */ - if (mlx5_aso_reg_mr(cdev, 64 * sq_desc_n, - &sh->ct_mng->aso_sq.mr)) + if (mlx5_aso_ct_queue_init(sh, sh->ct_mng, MLX5_ASO_CT_SQ_NUM)) return -1; - if (mlx5_aso_sq_create(cdev, &sh->ct_mng->aso_sq, - sh->tx_uar.obj, MLX5_ASO_QUEUE_LOG_DESC)) { - mlx5_aso_dereg_mr(cdev, &sh->ct_mng->aso_sq.mr); - return -1; - } - mlx5_aso_ct_init_sq(&sh->ct_mng->aso_sq); break; default: DRV_LOG(ERR, "Unknown ASO operation mode"); @@ -343,7 +335,7 @@ void mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh, enum mlx5_access_aso_opc_mod aso_opc_mod) { - struct mlx5_aso_sq *sq; + struct mlx5_aso_sq *sq = NULL; switch (aso_opc_mod) { case ASO_OPC_MOD_FLOW_HIT: @@ -354,14 +346,14 @@ mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh, sq = &sh->mtrmng->pools_mng.sq; break; case ASO_OPC_MOD_CONNECTION_TRACKING: - mlx5_aso_dereg_mr(sh->cdev, &sh->ct_mng->aso_sq.mr); - sq = &sh->ct_mng->aso_sq; + mlx5_aso_ct_queue_uninit(sh, sh->ct_mng); break; default: DRV_LOG(ERR, "Unknown ASO operation mode"); return; } - mlx5_aso_destroy_sq(sq); + if (sq) + mlx5_aso_destroy_sq(sq); } /** @@ -903,6 +895,89 @@ mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, return -1; } +static inline struct mlx5_aso_sq* +__mlx5_aso_ct_get_sq_in_hws(uint32_t queue, + struct mlx5_aso_ct_pool *pool) +{ + return (queue == MLX5_HW_INV_QUEUE) ? + pool->shared_sq : &pool->sq[queue]; +} + +static inline struct mlx5_aso_sq* +__mlx5_aso_ct_get_sq_in_sws(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_ct_action *ct) +{ + return &sh->ct_mng->aso_sqs[ct->offset & (MLX5_ASO_CT_SQ_NUM - 1)]; +} + +static inline struct mlx5_aso_ct_pool* +__mlx5_aso_ct_get_pool(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_ct_action *ct) +{ + if (likely(sh->config.dv_flow_en == 2)) + return ct->pool; + return container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); +} + +int +mlx5_aso_ct_queue_uninit(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_ct_pools_mng *ct_mng) +{ + uint32_t i; + + /* 64B per object for query. */ + for (i = 0; i < ct_mng->nb_sq; i++) { + if (ct_mng->aso_sqs[i].mr.addr) + mlx5_aso_dereg_mr(sh->cdev, &ct_mng->aso_sqs[i].mr); + mlx5_aso_destroy_sq(&ct_mng->aso_sqs[i]); + } + return 0; +} + +/** + * API to create and initialize CT Send Queue used for ASO access. + * + * @param[in] sh + * Pointer to shared device context. + * @param[in] ct_mng + * Pointer to the CT management struct. + * *param[in] nb_queues + * Number of queues to be allocated. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_aso_ct_queue_init(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_ct_pools_mng *ct_mng, + uint32_t nb_queues) +{ + uint32_t i; + + /* 64B per object for query. */ + for (i = 0; i < nb_queues; i++) { + if (mlx5_aso_reg_mr(sh->cdev, 64 * (1 << MLX5_ASO_QUEUE_LOG_DESC), + &ct_mng->aso_sqs[i].mr)) + goto error; + if (mlx5_aso_sq_create(sh->cdev, &ct_mng->aso_sqs[i], + sh->tx_uar.obj, + MLX5_ASO_QUEUE_LOG_DESC)) + goto error; + mlx5_aso_ct_init_sq(&ct_mng->aso_sqs[i]); + } + ct_mng->nb_sq = nb_queues; + return 0; +error: + do { + if (ct_mng->aso_sqs[i].mr.addr) + mlx5_aso_dereg_mr(sh->cdev, &ct_mng->aso_sqs[i].mr); + if (&ct_mng->aso_sqs[i]) + mlx5_aso_destroy_sq(&ct_mng->aso_sqs[i]); + } while (i--); + ct_mng->nb_sq = 0; + return -1; +} + /* * Post a WQE to the ASO CT SQ to modify the context. * @@ -918,11 +993,12 @@ mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, */ static uint16_t mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_sq *sq, struct mlx5_aso_ct_action *ct, - const struct rte_flow_action_conntrack *profile) + const struct rte_flow_action_conntrack *profile, + bool need_lock) { volatile struct mlx5_aso_wqe *wqe = NULL; - struct mlx5_aso_sq *sq = &sh->ct_mng->aso_sq; uint16_t size = 1 << sq->log_desc_n; uint16_t mask = size - 1; uint16_t res; @@ -931,11 +1007,13 @@ mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, void *orig_dir; void *reply_dir; - rte_spinlock_lock(&sq->sqsl); + if (need_lock) + rte_spinlock_lock(&sq->sqsl); /* Prevent other threads to update the index. */ res = size - (uint16_t)(sq->head - sq->tail); if (unlikely(!res)) { - rte_spinlock_unlock(&sq->sqsl); + if (need_lock) + rte_spinlock_unlock(&sq->sqsl); DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send"); return 0; } @@ -945,7 +1023,7 @@ mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_WAIT); sq->elts[sq->head & mask].ct = ct; sq->elts[sq->head & mask].query_data = NULL; - pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); + pool = __mlx5_aso_ct_get_pool(sh, ct); /* Each WQE will have a single CT object. */ wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id + ct->offset); @@ -1028,7 +1106,8 @@ mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], !sh->tx_uar.dbnc); - rte_spinlock_unlock(&sq->sqsl); + if (need_lock) + rte_spinlock_unlock(&sq->sqsl); return 1; } @@ -1080,10 +1159,11 @@ mlx5_aso_ct_status_update(struct mlx5_aso_sq *sq, uint16_t num) */ static int mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh, - struct mlx5_aso_ct_action *ct, char *data) + struct mlx5_aso_sq *sq, + struct mlx5_aso_ct_action *ct, char *data, + bool need_lock) { volatile struct mlx5_aso_wqe *wqe = NULL; - struct mlx5_aso_sq *sq = &sh->ct_mng->aso_sq; uint16_t size = 1 << sq->log_desc_n; uint16_t mask = size - 1; uint16_t res; @@ -1098,10 +1178,12 @@ mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh, } else if (state == ASO_CONNTRACK_WAIT) { return 0; } - rte_spinlock_lock(&sq->sqsl); + if (need_lock) + rte_spinlock_lock(&sq->sqsl); res = size - (uint16_t)(sq->head - sq->tail); if (unlikely(!res)) { - rte_spinlock_unlock(&sq->sqsl); + if (need_lock) + rte_spinlock_unlock(&sq->sqsl); DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send"); return 0; } @@ -1113,7 +1195,7 @@ mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh, wqe_idx = sq->head & mask; sq->elts[wqe_idx].ct = ct; sq->elts[wqe_idx].query_data = data; - pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); + pool = __mlx5_aso_ct_get_pool(sh, ct); /* Each WQE will have a single CT object. */ wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id + ct->offset); @@ -1141,7 +1223,8 @@ mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh, mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], !sh->tx_uar.dbnc); - rte_spinlock_unlock(&sq->sqsl); + if (need_lock) + rte_spinlock_unlock(&sq->sqsl); return 1; } @@ -1152,9 +1235,10 @@ mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh, * Pointer to the CT pools management structure. */ static void -mlx5_aso_ct_completion_handle(struct mlx5_aso_ct_pools_mng *mng) +mlx5_aso_ct_completion_handle(struct mlx5_dev_ctx_shared *sh __rte_unused, + struct mlx5_aso_sq *sq, + bool need_lock) { - struct mlx5_aso_sq *sq = &mng->aso_sq; struct mlx5_aso_cq *cq = &sq->cq; volatile struct mlx5_cqe *restrict cqe; const uint32_t cq_size = 1 << cq->log_desc_n; @@ -1165,10 +1249,12 @@ mlx5_aso_ct_completion_handle(struct mlx5_aso_ct_pools_mng *mng) uint16_t n = 0; int ret; - rte_spinlock_lock(&sq->sqsl); + if (need_lock) + rte_spinlock_lock(&sq->sqsl); max = (uint16_t)(sq->head - sq->tail); if (unlikely(!max)) { - rte_spinlock_unlock(&sq->sqsl); + if (need_lock) + rte_spinlock_unlock(&sq->sqsl); return; } next_idx = cq->cq_ci & mask; @@ -1199,7 +1285,8 @@ mlx5_aso_ct_completion_handle(struct mlx5_aso_ct_pools_mng *mng) rte_io_wmb(); cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci); } - rte_spinlock_unlock(&sq->sqsl); + if (need_lock) + rte_spinlock_unlock(&sq->sqsl); } /* @@ -1207,6 +1294,8 @@ mlx5_aso_ct_completion_handle(struct mlx5_aso_ct_pools_mng *mng) * * @param[in] sh * Pointer to mlx5_dev_ctx_shared object. + * @param[in] queue + * The queue index. * @param[in] ct * Pointer to connection tracking offload object. * @param[in] profile @@ -1217,21 +1306,26 @@ mlx5_aso_ct_completion_handle(struct mlx5_aso_ct_pools_mng *mng) */ int mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh, + uint32_t queue, struct mlx5_aso_ct_action *ct, const struct rte_flow_action_conntrack *profile) { uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES; - struct mlx5_aso_ct_pool *pool; + struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct); + struct mlx5_aso_sq *sq; + bool need_lock = !!(queue == MLX5_HW_INV_QUEUE); - MLX5_ASSERT(ct); + if (sh->config.dv_flow_en == 2) + sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool); + else + sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct); do { - mlx5_aso_ct_completion_handle(sh->ct_mng); - if (mlx5_aso_ct_sq_enqueue_single(sh, ct, profile)) + mlx5_aso_ct_completion_handle(sh, sq, need_lock); + if (mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile, need_lock)) return 0; /* Waiting for wqe resource. */ rte_delay_us_sleep(10u); } while (--poll_wqe_times); - pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); DRV_LOG(ERR, "Fail to send WQE for ASO CT %d in pool %d", ct->offset, pool->index); return -1; @@ -1242,6 +1336,8 @@ mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh, * * @param[in] sh * Pointer to mlx5_dev_ctx_shared object. + * @param[in] queue + * The queue which CT works on.. * @param[in] ct * Pointer to connection tracking offload object. * @@ -1249,25 +1345,29 @@ mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh, * 0 on success, -1 on failure. */ int -mlx5_aso_ct_wait_ready(struct mlx5_dev_ctx_shared *sh, +mlx5_aso_ct_wait_ready(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct) { - struct mlx5_aso_ct_pools_mng *mng = sh->ct_mng; uint32_t poll_cqe_times = MLX5_CT_POLL_WQE_CQE_TIMES; - struct mlx5_aso_ct_pool *pool; + struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct); + struct mlx5_aso_sq *sq; + bool need_lock = !!(queue == MLX5_HW_INV_QUEUE); + if (sh->config.dv_flow_en == 2) + sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool); + else + sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct); if (__atomic_load_n(&ct->state, __ATOMIC_RELAXED) == ASO_CONNTRACK_READY) return 0; do { - mlx5_aso_ct_completion_handle(mng); + mlx5_aso_ct_completion_handle(sh, sq, need_lock); if (__atomic_load_n(&ct->state, __ATOMIC_RELAXED) == ASO_CONNTRACK_READY) return 0; /* Waiting for CQE ready, consider should block or sleep. */ rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY); } while (--poll_cqe_times); - pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); DRV_LOG(ERR, "Fail to poll CQE for ASO CT %d in pool %d", ct->offset, pool->index); return -1; @@ -1363,18 +1463,24 @@ mlx5_aso_ct_obj_analyze(struct rte_flow_action_conntrack *profile, */ int mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh, + uint32_t queue, struct mlx5_aso_ct_action *ct, struct rte_flow_action_conntrack *profile) { uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES; - struct mlx5_aso_ct_pool *pool; + struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct); + struct mlx5_aso_sq *sq; + bool need_lock = !!(queue == MLX5_HW_INV_QUEUE); char out_data[64 * 2]; int ret; - MLX5_ASSERT(ct); + if (sh->config.dv_flow_en == 2) + sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool); + else + sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct); do { - mlx5_aso_ct_completion_handle(sh->ct_mng); - ret = mlx5_aso_ct_sq_query_single(sh, ct, out_data); + mlx5_aso_ct_completion_handle(sh, sq, need_lock); + ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data, need_lock); if (ret < 0) return ret; else if (ret > 0) @@ -1383,12 +1489,11 @@ mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh, else rte_delay_us_sleep(10u); } while (--poll_wqe_times); - pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]); DRV_LOG(ERR, "Fail to send WQE for ASO CT %d in pool %d", ct->offset, pool->index); return -1; data_handle: - ret = mlx5_aso_ct_wait_ready(sh, ct); + ret = mlx5_aso_ct_wait_ready(sh, queue, ct); if (!ret) mlx5_aso_ct_obj_analyze(profile, out_data); return ret; @@ -1408,13 +1513,20 @@ mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh, */ int mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh, + uint32_t queue, struct mlx5_aso_ct_action *ct) { - struct mlx5_aso_ct_pools_mng *mng = sh->ct_mng; + struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct); + struct mlx5_aso_sq *sq; + bool need_lock = !!(queue == MLX5_HW_INV_QUEUE); uint32_t poll_cqe_times = MLX5_CT_POLL_WQE_CQE_TIMES; enum mlx5_aso_ct_state state = __atomic_load_n(&ct->state, __ATOMIC_RELAXED); + if (sh->config.dv_flow_en == 2) + sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool); + else + sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct); if (state == ASO_CONNTRACK_FREE) { rte_errno = ENXIO; return -rte_errno; @@ -1423,13 +1535,13 @@ mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh, return 0; } do { - mlx5_aso_ct_completion_handle(mng); + mlx5_aso_ct_completion_handle(sh, sq, need_lock); state = __atomic_load_n(&ct->state, __ATOMIC_RELAXED); if (state == ASO_CONNTRACK_READY || state == ASO_CONNTRACK_QUERY) return 0; - /* Waiting for CQE ready, consider should block or sleep. */ - rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY); + /* Waiting for CQE ready, consider should block or sleep. */ + rte_delay_us_block(MLX5_ASO_WQE_CQE_RESPONSE_DELAY); } while (--poll_cqe_times); rte_errno = EBUSY; return -rte_errno; diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 1eb1ce659f..9bede7c04f 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -12813,6 +12813,7 @@ flow_dv_ct_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *obj = NULL; uint32_t i; uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL); + size_t mem_size; obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->cdev->ctx, priv->sh->cdev->pdn, @@ -12822,7 +12823,10 @@ flow_dv_ct_pool_create(struct rte_eth_dev *dev, DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX."); return NULL; } - pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); + mem_size = sizeof(struct mlx5_aso_ct_action) * + MLX5_ASO_CT_ACTIONS_PER_POOL + + sizeof(*pool); + pool = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY); if (!pool) { rte_errno = ENOMEM; claim_zero(mlx5_devx_cmd_destroy(obj)); @@ -12962,10 +12966,13 @@ flow_dv_translate_create_conntrack(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Failed to allocate CT object"); ct = flow_aso_ct_get_by_dev_idx(dev, idx); - if (mlx5_aso_ct_update_by_wqe(sh, ct, pro)) - return rte_flow_error_set(error, EBUSY, - RTE_FLOW_ERROR_TYPE_ACTION, NULL, - "Failed to update CT"); + if (mlx5_aso_ct_update_by_wqe(sh, MLX5_HW_INV_QUEUE, ct, pro)) { + flow_dv_aso_ct_dev_release(dev, idx); + rte_flow_error_set(error, EBUSY, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "Failed to update CT"); + return 0; + } ct->is_original = !!pro->is_original_dir; ct->peer = pro->peer_port; return idx; @@ -14160,7 +14167,7 @@ flow_dv_translate(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Failed to get CT object."); - if (mlx5_aso_ct_available(priv->sh, ct)) + if (mlx5_aso_ct_available(priv->sh, MLX5_HW_INV_QUEUE, ct)) return rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION, NULL, @@ -15768,14 +15775,15 @@ __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx, ret = mlx5_validate_action_ct(dev, new_prf, error); if (ret) return ret; - ret = mlx5_aso_ct_update_by_wqe(priv->sh, ct, new_prf); + ret = mlx5_aso_ct_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, + ct, new_prf); if (ret) return rte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Failed to send CT context update WQE"); - /* Block until ready or a failure. */ - ret = mlx5_aso_ct_available(priv->sh, ct); + /* Block until ready or a failure, default is asynchronous. */ + ret = mlx5_aso_ct_available(priv->sh, MLX5_HW_INV_QUEUE, ct); if (ret) rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@ -16604,7 +16612,7 @@ flow_dv_action_query(struct rte_eth_dev *dev, ct->peer; ((struct rte_flow_action_conntrack *)data)->is_original_dir = ct->is_original; - if (mlx5_aso_ct_query_by_wqe(priv->sh, ct, data)) + if (mlx5_aso_ct_query_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, ct, data)) return rte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 91835cd024..f4340c475d 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -15,6 +15,14 @@ /* The maximum actions support in the flow. */ #define MLX5_HW_MAX_ACTS 16 +/* + * The default ipool threshold value indicates which per_core_cache + * value to set. + */ +#define MLX5_HW_IPOOL_SIZE_THRESHOLD (1 << 19) +/* The default min local cache size. */ +#define MLX5_HW_IPOOL_CACHE_MIN (1 << 9) + /* Default push burst threshold. */ #define BURST_THR 32u @@ -324,6 +332,25 @@ flow_hw_tir_action_register(struct rte_eth_dev *dev, return hrxq; } +static __rte_always_inline int +flow_hw_ct_compile(struct rte_eth_dev *dev, + uint32_t queue, uint32_t idx, + struct mlx5dr_rule_action *rule_act) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_ct_action *ct; + + ct = mlx5_ipool_get(priv->hws_ctpool->cts, MLX5_ACTION_CTX_CT_GET_IDX(idx)); + if (!ct || mlx5_aso_ct_available(priv->sh, queue, ct)) + return -1; + rule_act->action = priv->hws_ctpool->dr_action; + rule_act->aso_ct.offset = ct->offset; + rule_act->aso_ct.direction = ct->is_original ? + MLX5DR_ACTION_ASO_CT_DIRECTION_INITIATOR : + MLX5DR_ACTION_ASO_CT_DIRECTION_RESPONDER; + return 0; +} + /** * Destroy DR actions created by action template. * @@ -640,6 +667,11 @@ flow_hw_shared_action_translate(struct rte_eth_dev *dev, action_src, action_dst, act_idx)) return -1; break; + case MLX5_INDIRECT_ACTION_TYPE_CT: + if (flow_hw_ct_compile(dev, MLX5_HW_INV_QUEUE, + idx, &acts->rule_acts[action_dst])) + return -1; + break; default: DRV_LOG(WARNING, "Unsupported shared action type:%d", type); break; @@ -1083,6 +1115,7 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev, bool reformat_used = false; uint16_t action_pos; uint16_t jump_pos; + uint32_t ct_idx; int err; flow_hw_modify_field_init(&mhdr, at); @@ -1305,6 +1338,20 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev, goto err; } break; + case RTE_FLOW_ACTION_TYPE_CONNTRACK: + action_pos = at->actions_off[actions - at->actions]; + if (masks->conf) { + ct_idx = MLX5_ACTION_CTX_CT_GET_IDX + ((uint32_t)(uintptr_t)actions->conf); + if (flow_hw_ct_compile(dev, MLX5_HW_INV_QUEUE, ct_idx, + &acts->rule_acts[action_pos])) + goto err; + } else if (__flow_hw_act_data_general_append + (priv, acts, actions->type, + actions - action_start, action_pos)) { + goto err; + } + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -1479,6 +1526,8 @@ flow_hw_shared_action_get(struct rte_eth_dev *dev, * * @param[in] dev * Pointer to the rte_eth_dev data structure. + * @param[in] queue + * The flow creation queue index. * @param[in] action * Pointer to the shared indirect rte_flow action. * @param[in] table @@ -1492,7 +1541,7 @@ flow_hw_shared_action_get(struct rte_eth_dev *dev, * 0 on success, negative value otherwise and rte_errno is set. */ static __rte_always_inline int -flow_hw_shared_action_construct(struct rte_eth_dev *dev, +flow_hw_shared_action_construct(struct rte_eth_dev *dev, uint32_t queue, const struct rte_flow_action *action, struct rte_flow_template_table *table, const uint8_t it_idx, @@ -1532,6 +1581,10 @@ flow_hw_shared_action_construct(struct rte_eth_dev *dev, &rule_act->counter.offset)) return -1; break; + case MLX5_INDIRECT_ACTION_TYPE_CT: + if (flow_hw_ct_compile(dev, queue, idx, rule_act)) + return -1; + break; default: DRV_LOG(WARNING, "Unsupported shared action type:%d", type); break; @@ -1727,6 +1780,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, uint64_t item_flags; struct mlx5_hw_jump_action *jump; struct mlx5_hrxq *hrxq; + uint32_t ct_idx; cnt_id_t cnt_id; action = &actions[act_data->action_src]; @@ -1735,7 +1789,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, switch (act_data->type) { case RTE_FLOW_ACTION_TYPE_INDIRECT: if (flow_hw_shared_action_construct - (dev, action, table, it_idx, + (dev, queue, action, table, it_idx, &rule_acts[act_data->action_dst])) return -1; break; @@ -1860,6 +1914,13 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, return ret; job->flow->cnt_id = act_data->shared_counter.id; break; + case RTE_FLOW_ACTION_TYPE_CONNTRACK: + ct_idx = MLX5_ACTION_CTX_CT_GET_IDX + ((uint32_t)(uintptr_t)action->conf); + if (flow_hw_ct_compile(dev, queue, ct_idx, + &rule_acts[act_data->action_dst])) + return -1; + break; default: break; } @@ -2391,6 +2452,8 @@ flow_hw_table_create(struct rte_eth_dev *dev, if (nb_flows < cfg.trunk_size) { cfg.per_core_cache = 0; cfg.trunk_size = nb_flows; + } else if (nb_flows <= MLX5_HW_IPOOL_SIZE_THRESHOLD) { + cfg.per_core_cache = MLX5_HW_IPOOL_CACHE_MIN; } /* Check if we requires too many templates. */ if (nb_item_templates > max_tpl || @@ -2927,6 +2990,9 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_COUNT: /* TODO: Validation logic */ break; + case RTE_FLOW_ACTION_TYPE_CONNTRACK: + /* TODO: Validation logic */ + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -2953,6 +3019,7 @@ static enum mlx5dr_action_type mlx5_hw_dr_action_types[] = { [RTE_FLOW_ACTION_TYPE_MODIFY_FIELD] = MLX5DR_ACTION_TYP_MODIFY_HDR, [RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT] = MLX5DR_ACTION_TYP_VPORT, [RTE_FLOW_ACTION_TYPE_COUNT] = MLX5DR_ACTION_TYP_CTR, + [RTE_FLOW_ACTION_TYPE_CONNTRACK] = MLX5DR_ACTION_TYP_ASO_CT, }; static int @@ -2981,6 +3048,11 @@ flow_hw_dr_actions_template_handle_shared(const struct rte_flow_action *mask, action_types[*curr_off] = MLX5DR_ACTION_TYP_CTR; *curr_off = *curr_off + 1; break; + case RTE_FLOW_ACTION_TYPE_CONNTRACK: + at->actions_off[action_src] = *curr_off; + action_types[*curr_off] = MLX5DR_ACTION_TYP_ASO_CT; + *curr_off = *curr_off + 1; + break; default: DRV_LOG(WARNING, "Unsupported shared action type: %d", type); return -EINVAL; @@ -3435,6 +3507,7 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, case RTE_FLOW_ITEM_TYPE_GRE_OPTION: case RTE_FLOW_ITEM_TYPE_ICMP: case RTE_FLOW_ITEM_TYPE_ICMP6: + case RTE_FLOW_ITEM_TYPE_CONNTRACK: break; case RTE_FLOW_ITEM_TYPE_END: items_end = true; @@ -4630,6 +4703,97 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) return -EINVAL; } +static void +flow_hw_ct_mng_destroy(struct rte_eth_dev *dev, + struct mlx5_aso_ct_pools_mng *ct_mng) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + mlx5_aso_ct_queue_uninit(priv->sh, ct_mng); + mlx5_free(ct_mng); +} + +static void +flow_hw_ct_pool_destroy(struct rte_eth_dev *dev __rte_unused, + struct mlx5_aso_ct_pool *pool) +{ + if (pool->dr_action) + mlx5dr_action_destroy(pool->dr_action); + if (pool->devx_obj) + claim_zero(mlx5_devx_cmd_destroy(pool->devx_obj)); + if (pool->cts) + mlx5_ipool_destroy(pool->cts); + mlx5_free(pool); +} + +static struct mlx5_aso_ct_pool * +flow_hw_ct_pool_create(struct rte_eth_dev *dev, + const struct rte_flow_port_attr *port_attr) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_ct_pool *pool; + struct mlx5_devx_obj *obj; + uint32_t nb_cts = rte_align32pow2(port_attr->nb_conn_tracks); + uint32_t log_obj_size = rte_log2_u32(nb_cts); + struct mlx5_indexed_pool_config cfg = { + .size = sizeof(struct mlx5_aso_ct_action), + .trunk_size = 1 << 12, + .per_core_cache = 1 << 13, + .need_lock = 1, + .release_mem_en = !!priv->sh->config.reclaim_mode, + .malloc = mlx5_malloc, + .free = mlx5_free, + .type = "mlx5_hw_ct_action", + }; + int reg_id; + uint32_t flags; + + pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY); + if (!pool) { + rte_errno = ENOMEM; + return NULL; + } + obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->cdev->ctx, + priv->sh->cdev->pdn, + log_obj_size); + if (!obj) { + rte_errno = ENODATA; + DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX."); + goto err; + } + pool->devx_obj = obj; + reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, NULL); + flags = MLX5DR_ACTION_FLAG_HWS_RX | MLX5DR_ACTION_FLAG_HWS_TX; + if (priv->sh->config.dv_esw_en && priv->master) + flags |= MLX5DR_ACTION_FLAG_HWS_FDB; + pool->dr_action = mlx5dr_action_create_aso_ct(priv->dr_ctx, + (struct mlx5dr_devx_obj *)obj, + reg_id - REG_C_0, flags); + if (!pool->dr_action) + goto err; + /* + * No need for local cache if CT number is a small number. Since + * flow insertion rate will be very limited in that case. Here let's + * set the number to less than default trunk size 4K. + */ + if (nb_cts <= cfg.trunk_size) { + cfg.per_core_cache = 0; + cfg.trunk_size = nb_cts; + } else if (nb_cts <= MLX5_HW_IPOOL_SIZE_THRESHOLD) { + cfg.per_core_cache = MLX5_HW_IPOOL_CACHE_MIN; + } + pool->cts = mlx5_ipool_create(&cfg); + if (!pool->cts) + goto err; + pool->sq = priv->ct_mng->aso_sqs; + /* Assign the last extra ASO SQ as public SQ. */ + pool->shared_sq = &priv->ct_mng->aso_sqs[priv->nb_queue - 1]; + return pool; +err: + flow_hw_ct_pool_destroy(dev, pool); + return NULL; +} + /** * Configure port HWS resources. * @@ -4815,6 +4979,20 @@ flow_hw_configure(struct rte_eth_dev *dev, } if (_queue_attr) mlx5_free(_queue_attr); + if (port_attr->nb_conn_tracks) { + mem_size = sizeof(struct mlx5_aso_sq) * nb_q_updated + + sizeof(*priv->ct_mng); + priv->ct_mng = mlx5_malloc(MLX5_MEM_ZERO, mem_size, + RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); + if (!priv->ct_mng) + goto err; + if (mlx5_aso_ct_queue_init(priv->sh, priv->ct_mng, nb_q_updated)) + goto err; + priv->hws_ctpool = flow_hw_ct_pool_create(dev, port_attr); + if (!priv->hws_ctpool) + goto err; + priv->sh->ct_aso_en = 1; + } if (port_attr->nb_counters) { priv->hws_cpool = mlx5_hws_cnt_pool_create(dev, port_attr, nb_queue); @@ -4823,6 +5001,14 @@ flow_hw_configure(struct rte_eth_dev *dev, } return 0; err: + if (priv->hws_ctpool) { + flow_hw_ct_pool_destroy(dev, priv->hws_ctpool); + priv->hws_ctpool = NULL; + } + if (priv->ct_mng) { + flow_hw_ct_mng_destroy(dev, priv->ct_mng); + priv->ct_mng = NULL; + } flow_hw_free_vport_actions(priv); for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) { if (priv->hw_drop[i]) @@ -4896,6 +5082,14 @@ flow_hw_resource_release(struct rte_eth_dev *dev) } if (priv->hws_cpool) mlx5_hws_cnt_pool_destroy(priv->sh, priv->hws_cpool); + if (priv->hws_ctpool) { + flow_hw_ct_pool_destroy(dev, priv->hws_ctpool); + priv->hws_ctpool = NULL; + } + if (priv->ct_mng) { + flow_hw_ct_mng_destroy(dev, priv->ct_mng); + priv->ct_mng = NULL; + } mlx5_free(priv->hw_q); priv->hw_q = NULL; claim_zero(mlx5dr_context_close(priv->dr_ctx)); @@ -4964,6 +5158,7 @@ void flow_hw_init_tags_set(struct rte_eth_dev *dev) unset |= 1 << (REG_C_1 - REG_C_0); masks &= ~unset; if (mlx5_flow_hw_avl_tags_init_cnt) { + MLX5_ASSERT(mlx5_flow_hw_aso_tag == priv->mtr_color_reg); for (i = 0; i < MLX5_FLOW_HW_TAGS_MAX; i++) { if (mlx5_flow_hw_avl_tags[i] != REG_NON && !!((1 << i) & masks)) { copy[mlx5_flow_hw_avl_tags[i] - REG_C_0] = @@ -4986,6 +5181,7 @@ void flow_hw_init_tags_set(struct rte_eth_dev *dev) } } priv->sh->hws_tags = 1; + mlx5_flow_hw_aso_tag = (enum modify_reg)priv->mtr_color_reg; mlx5_flow_hw_avl_tags_init_cnt++; } @@ -5056,6 +5252,170 @@ flow_hw_clear_flow_metadata_config(void) mlx5_flow_hw_flow_metadata_xmeta_en = 0; } +static int +flow_hw_conntrack_destroy(struct rte_eth_dev *dev __rte_unused, + uint32_t idx, + struct rte_flow_error *error) +{ + uint16_t owner = (uint16_t)MLX5_ACTION_CTX_CT_GET_OWNER(idx); + uint32_t ct_idx = MLX5_ACTION_CTX_CT_GET_IDX(idx); + struct rte_eth_dev *owndev = &rte_eth_devices[owner]; + struct mlx5_priv *priv = owndev->data->dev_private; + struct mlx5_aso_ct_pool *pool = priv->hws_ctpool; + struct mlx5_aso_ct_action *ct; + + ct = mlx5_ipool_get(pool->cts, ct_idx); + if (!ct) { + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Invalid CT destruction index"); + } + __atomic_store_n(&ct->state, ASO_CONNTRACK_FREE, + __ATOMIC_RELAXED); + mlx5_ipool_free(pool->cts, ct_idx); + return 0; +} + +static int +flow_hw_conntrack_query(struct rte_eth_dev *dev, uint32_t idx, + struct rte_flow_action_conntrack *profile, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_ct_pool *pool = priv->hws_ctpool; + struct mlx5_aso_ct_action *ct; + uint16_t owner = (uint16_t)MLX5_ACTION_CTX_CT_GET_OWNER(idx); + uint32_t ct_idx; + + if (owner != PORT_ID(priv)) + return rte_flow_error_set(error, EACCES, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Can't query CT object owned by another port"); + ct_idx = MLX5_ACTION_CTX_CT_GET_IDX(idx); + ct = mlx5_ipool_get(pool->cts, ct_idx); + if (!ct) { + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Invalid CT query index"); + } + profile->peer_port = ct->peer; + profile->is_original_dir = ct->is_original; + if (mlx5_aso_ct_query_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, ct, profile)) + return rte_flow_error_set(error, EIO, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Failed to query CT context"); + return 0; +} + + +static int +flow_hw_conntrack_update(struct rte_eth_dev *dev, uint32_t queue, + const struct rte_flow_modify_conntrack *action_conf, + uint32_t idx, struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_ct_pool *pool = priv->hws_ctpool; + struct mlx5_aso_ct_action *ct; + const struct rte_flow_action_conntrack *new_prf; + uint16_t owner = (uint16_t)MLX5_ACTION_CTX_CT_GET_OWNER(idx); + uint32_t ct_idx; + int ret = 0; + + if (PORT_ID(priv) != owner) + return rte_flow_error_set(error, EACCES, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Can't update CT object owned by another port"); + ct_idx = MLX5_ACTION_CTX_CT_GET_IDX(idx); + ct = mlx5_ipool_get(pool->cts, ct_idx); + if (!ct) { + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Invalid CT update index"); + } + new_prf = &action_conf->new_ct; + if (action_conf->direction) + ct->is_original = !!new_prf->is_original_dir; + if (action_conf->state) { + /* Only validate the profile when it needs to be updated. */ + ret = mlx5_validate_action_ct(dev, new_prf, error); + if (ret) + return ret; + ret = mlx5_aso_ct_update_by_wqe(priv->sh, queue, ct, new_prf); + if (ret) + return rte_flow_error_set(error, EIO, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Failed to send CT context update WQE"); + if (queue != MLX5_HW_INV_QUEUE) + return 0; + /* Block until ready or a failure in synchronous mode. */ + ret = mlx5_aso_ct_available(priv->sh, queue, ct); + if (ret) + rte_flow_error_set(error, rte_errno, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Timeout to get the CT update"); + } + return ret; +} + +static struct rte_flow_action_handle * +flow_hw_conntrack_create(struct rte_eth_dev *dev, uint32_t queue, + const struct rte_flow_action_conntrack *pro, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_ct_pool *pool = priv->hws_ctpool; + struct mlx5_aso_ct_action *ct; + uint32_t ct_idx = 0; + int ret; + bool async = !!(queue != MLX5_HW_INV_QUEUE); + + if (!pool) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "CT is not enabled"); + return 0; + } + ct = mlx5_ipool_zmalloc(pool->cts, &ct_idx); + if (!ct) { + rte_flow_error_set(error, rte_errno, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "Failed to allocate CT object"); + return 0; + } + ct->offset = ct_idx - 1; + ct->is_original = !!pro->is_original_dir; + ct->peer = pro->peer_port; + ct->pool = pool; + if (mlx5_aso_ct_update_by_wqe(priv->sh, queue, ct, pro)) { + mlx5_ipool_free(pool->cts, ct_idx); + rte_flow_error_set(error, EBUSY, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "Failed to update CT"); + return 0; + } + if (!async) { + ret = mlx5_aso_ct_available(priv->sh, queue, ct); + if (ret) { + mlx5_ipool_free(pool->cts, ct_idx); + rte_flow_error_set(error, rte_errno, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Timeout to get the CT update"); + return 0; + } + } + return (struct rte_flow_action_handle *)(uintptr_t) + MLX5_ACTION_CTX_CT_GEN_IDX(PORT_ID(priv), ct_idx); +} + /** * Create shared action. * @@ -5103,6 +5463,9 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, handle = (struct rte_flow_action_handle *) (uintptr_t)cnt_id; break; + case RTE_FLOW_ACTION_TYPE_CONNTRACK: + handle = flow_hw_conntrack_create(dev, queue, action->conf, error); + break; default: handle = flow_dv_action_create(dev, conf, action, error); } @@ -5138,10 +5501,18 @@ flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue, void *user_data, struct rte_flow_error *error) { + uint32_t act_idx = (uint32_t)(uintptr_t)handle; + uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; + RTE_SET_USED(queue); RTE_SET_USED(attr); RTE_SET_USED(user_data); - return flow_dv_action_update(dev, handle, update, error); + switch (type) { + case MLX5_INDIRECT_ACTION_TYPE_CT: + return flow_hw_conntrack_update(dev, queue, update, act_idx, error); + default: + return flow_dv_action_update(dev, handle, update, error); + } } /** @@ -5180,6 +5551,8 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, switch (type) { case MLX5_INDIRECT_ACTION_TYPE_COUNT: return mlx5_hws_cnt_shared_put(priv->hws_cpool, &act_idx); + case MLX5_INDIRECT_ACTION_TYPE_CT: + return flow_hw_conntrack_destroy(dev, act_idx, error); default: return flow_dv_action_destroy(dev, handle, error); } @@ -5333,6 +5706,8 @@ flow_hw_action_query(struct rte_eth_dev *dev, switch (type) { case MLX5_INDIRECT_ACTION_TYPE_COUNT: return flow_hw_query_counter(dev, act_idx, data, error); + case MLX5_INDIRECT_ACTION_TYPE_CT: + return flow_hw_conntrack_query(dev, act_idx, data, error); default: return flow_dv_action_query(dev, handle, data, error); } From patchwork Fri Sep 30 12:53:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117221 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id E72ADA00C4; Fri, 30 Sep 2022 14:55:14 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 9B46B42BA3; Fri, 30 Sep 2022 14:54:10 +0200 (CEST) Received: from NAM10-BN7-obe.outbound.protection.outlook.com (mail-bn7nam10on2063.outbound.protection.outlook.com [40.107.92.63]) by mails.dpdk.org (Postfix) with ESMTP id 7C01342B83 for ; Fri, 30 Sep 2022 14:54:06 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=fznCtOUYDFgrdkLnxa2IxJOcVV5WbZKIDkKBFe70YD3ZAQlSBiDuVyheiKyyiDuNodOcoxbUmeK/X/ZadflS3nLKsoU8iDGE9DvuoEb73nRRus72Est0AoHAaXLFRzJzzbEvxa7VL6zFQfNTlV+o4vvb62bTc6zdWi+yUxd6yx+OS5+4W5rXxi9se++BOogCShTSqKZiTOqwk6jON0t3A4gZjBsgv5I9g+cxtf+1p0gvPeVb4XezZnXf11/DxwB0DHCE91FtEFCB595sT5kDKEYlODRQbdUzqr9ohXPpnHj+yUsT9JDkMJiBlViLOUSLbxXbBlDauK+ugN5U/UMSOw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=G59syL9dNyinGVGyPdyigrPV9kezJljMVcNYRBqEH24=; b=JE69tu98gh/uwepWyw5qEMoMLSfcHFK55zxWMq3GzFCpvG2CaPb7naxxfEg7tYZOJQ+ONBYhG0i9IZC21/ilJyOiWX/SGaAkrMSw4X2Tsvr81uT4EzVX19F6AbYfptFagff6Wy/JgZD/SsamNPoPFrdowXNj9IBcwqp8Hy3lGwlvyfUuvCYg+m9Aw0u6Z4OyPflD26sTPIGUUeLJjDz0jJUqyEh1h8IO1XsAM2Z1YcuYfH7cseWzMZkXGgnFx7O/knhUoaA4qeTwh1C5JFLEZvgdhLVc/sKBSlTcpmLoGeIay+tKLkaKJulPaVcu/AteoM+xCBK7UpLY85Ra7Ei1Ng== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.161) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=G59syL9dNyinGVGyPdyigrPV9kezJljMVcNYRBqEH24=; b=pjPWKLzU+Z9GRBU0w8734yYbjAnS13O6pnDdhhC6WUqdaMgd6yViMla/wbCL5v2JxGpCjcARgGOtICZ4syeE1Tp37AMLjHuHSmKakSYmiwQwzn7H7KakEOC2uO5OWQRf46ZP2lcZAu5t26azgDEE4nirIfhm52Zs7wFssSfXrydheNIWvU8U2cjNvkOfA2CgoHl21kEdozeD6nM9xjZuGplHAnHDvbxdCnhuBbLnrgbO98KukXJeWDH6tWDcs9dW3P2/L7LPxhSJEyoAYt/YP76AG1LE7Zq1bDUeK2N6XuEV045EH85fcGbEmDASkKONUsiZAy06ROGCLLhBgl5lYg== Received: from DM6PR06CA0017.namprd06.prod.outlook.com (2603:10b6:5:120::30) by DM6PR12MB4532.namprd12.prod.outlook.com (2603:10b6:5:2af::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23; Fri, 30 Sep 2022 12:54:04 +0000 Received: from DM6NAM11FT008.eop-nam11.prod.protection.outlook.com (2603:10b6:5:120:cafe::cc) by DM6PR06CA0017.outlook.office365.com (2603:10b6:5:120::30) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:04 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.161) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.161 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.161; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.161) by DM6NAM11FT008.mail.protection.outlook.com (10.13.172.85) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:04 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.67) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:53:58 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:56 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , Gregory Etelson Subject: [PATCH v3 11/17] net/mlx5: add HW steering VLAN push, pop and VID modify flow actions Date: Fri, 30 Sep 2022 15:53:09 +0300 Message-ID: <20220930125315.5079-12-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT008:EE_|DM6PR12MB4532:EE_ X-MS-Office365-Filtering-Correlation-Id: cf9208f8-dcc8-4626-aaad-08daa2e2dada X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: Otz1nS/h1vvrY8Za2xzj2mXjkuUqkA8MqFKbBxa3pfB/OCgUmxVCr9VrdBRNcy+PY0KL9uZm7364ZEvXcy/0t+d+utsku28F3kWbt0vQB8Vj41vfZWfYibNvpxepnwc88eJQrUGpGSB6DSd4uy9E9OcXRec3NL5YbOsPbJXx72/Y6xdtY1ZmpvLQH1Qw/OpVH4wO4uuEcStA1rUzYo6Jae6Jl78NxULZ3ZnoyFNJ1bgTZeiCBhzCdOxgWRI9VZtieQri4mijd/PuP/EHrTfaGbrvq8pAg/RfvIryIMeh/so5x6ivL4KH9/SLLGk6F/lxhaeDk1EOcIh9Ebt+ihqC2CIeFtFMyIS0Nr7MM6OxrzMyWm4pYKTD2mCzwM1zN68kCFkAcWXfe/BBzo3fl38Lj3jf2vc74k1YXS1oQslO7VJV/TyHC1MGR6YUqUICVxJmAQG1xqs5duZJrfUU4u56Zyux65PtXih2Fk16MtRDgf2AdccTQOSwQdfosqCwp7tsBjCav6Hc5mf3PdOOjzqsM1zRcd7508QTdsD3FAnwyMVMF7DeP/wEr8XBNpKMpkyCmyqiNtXzOsxyop61GWRZdawh0CHsFhXCTAmXAPkEdvIoFXZps1A1VuFRVRfgfaqO3blno+LRHUi6rE7jnQmfWWKXPWvJA3xSP03YqkzQ4yEu20erQwENEh9/Gq7WI5kr8rKX59JFkEpzB+czGeEqvs1R92GyectN+qtI+NgCroliAQtaC6phlsyBnDBXhXqDqea+4/5xjp3ZMX87cFFseg== X-Forefront-Antispam-Report: CIP:216.228.117.161; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge2.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(346002)(39860400002)(136003)(376002)(396003)(451199015)(36840700001)(46966006)(40470700004)(36756003)(110136005)(54906003)(86362001)(356005)(30864003)(7636003)(1076003)(186003)(2616005)(336012)(83380400001)(70586007)(6636002)(82740400003)(16526019)(47076005)(426003)(7696005)(6286002)(36860700001)(26005)(107886003)(6666004)(478600001)(316002)(8676002)(4326008)(70206006)(8936002)(82310400005)(41300700001)(5660300002)(2906002)(40460700003)(40480700001)(55016003); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:54:04.2856 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: cf9208f8-dcc8-4626-aaad-08daa2e2dada X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.161]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT008.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR12MB4532 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Gregory Etelson Add PMD implementation for HW steering VLAN push, pop and modify flow actions. HWS VLAN push flow action is triggered by a sequence of mandatory OF_PUSH_VLAN, OF_SET_VLAN_VID and optional OF_SET_VLAN_PCP flow actions commands. The commands must be arranged in the exact order: OF_PUSH_VLAN / OF_SET_VLAN_VID [ / OF_SET_VLAN_PCP ]. In masked HWS VLAN push flow action template *ALL* the above flow actions must be masked. In non-masked HWS VLAN push flow action template *ALL* the above flow actions must not be masked. Example: flow actions_template create \ actions_template_id \ template \ of_push_vlan / \ of_set_vlan_vid \ [ / of_set_vlan_pcp ] / end \ mask \ of_push_vlan ethertype 0 / \ of_set_vlan_vid vlan_vid 0 \ [ / of_set_vlan_pcp vlan_pcp 0 ] / end\ flow actions_template create \ actions_template_id \ template \ of_push_vlan ethertype / \ of_set_vlan_vid vlan_vid \ [ / of_set_vlan_pcp ] / end \ mask \ of_push_vlan ethertype / \ of_set_vlan_vid vlan_vid \ [ / of_set_vlan_pcp vlan_pcp ] / end\ HWS VLAN pop flow action is triggered by OF_POP_VLAN flow action command. HWS VLAN pop action template is always non-masked. Example: flow actions_template create \ actions_template_id \ template of_pop_vlan / end mask of_pop_vlan / end HWS VLAN VID modify flow action is triggered by a standalone OF_SET_VLAN_VID flow action command. HWS VLAN VID modify action template can be ether masked or non-masked. Example: flow actions_template create \ actions_template_id \ template of_set_vlan_vid / end mask of_set_vlan_vid vlan_vid 0 / end flow actions_template create \ actions_template_id \ template of_set_vlan_vid vlan_vid 0x101 / end \ mask of_set_vlan_vid vlan_vid 0xffff / end Signed-off-by: Gregory Etelson --- drivers/net/mlx5/mlx5.h | 2 + drivers/net/mlx5/mlx5_flow.h | 4 + drivers/net/mlx5/mlx5_flow_dv.c | 2 +- drivers/net/mlx5/mlx5_flow_hw.c | 492 +++++++++++++++++++++++++++++--- 4 files changed, 463 insertions(+), 37 deletions(-) diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 0578a41675..7ec5f6a352 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -1665,6 +1665,8 @@ struct mlx5_priv { struct mlx5_hw_q *hw_q; /* HW steering rte flow table list header. */ LIST_HEAD(flow_hw_tbl, rte_flow_template_table) flow_hw_tbl; + struct mlx5dr_action *hw_push_vlan[MLX5DR_TABLE_TYPE_MAX]; + struct mlx5dr_action *hw_pop_vlan[MLX5DR_TABLE_TYPE_MAX]; struct mlx5dr_action **hw_vport; /* HW steering global drop action. */ struct mlx5dr_action *hw_drop[2]; diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index f75a56a57b..6d928b477e 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -2435,4 +2435,8 @@ int mlx5_flow_pattern_validate(struct rte_eth_dev *dev, struct rte_flow_error *error); int flow_hw_table_update(struct rte_eth_dev *dev, struct rte_flow_error *error); +int mlx5_flow_item_field_width(struct rte_eth_dev *dev, + enum rte_flow_field_id field, int inherit, + const struct rte_flow_attr *attr, + struct rte_flow_error *error); #endif /* RTE_PMD_MLX5_FLOW_H_ */ diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 9bede7c04f..7f81272150 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -1326,7 +1326,7 @@ flow_dv_convert_action_modify_ipv6_dscp MLX5_MODIFICATION_TYPE_SET, error); } -static int +int mlx5_flow_item_field_width(struct rte_eth_dev *dev, enum rte_flow_field_id field, int inherit, const struct rte_flow_attr *attr, diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index f4340c475d..71a134f224 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -44,12 +44,22 @@ /* Lowest priority for HW non-root table. */ #define MLX5_HW_LOWEST_PRIO_NON_ROOT (UINT32_MAX) +#define MLX5_HW_VLAN_PUSH_TYPE_IDX 0 +#define MLX5_HW_VLAN_PUSH_VID_IDX 1 +#define MLX5_HW_VLAN_PUSH_PCP_IDX 2 + static int flow_hw_flush_all_ctrl_flows(struct rte_eth_dev *dev); static int flow_hw_translate_group(struct rte_eth_dev *dev, const struct mlx5_flow_template_table_cfg *cfg, uint32_t group, uint32_t *table_group, struct rte_flow_error *error); +static __rte_always_inline int +flow_hw_set_vlan_vid_construct(struct rte_eth_dev *dev, + struct mlx5_hw_q_job *job, + struct mlx5_action_construct_data *act_data, + const struct mlx5_hw_actions *hw_acts, + const struct rte_flow_action *action); const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops; @@ -1065,6 +1075,52 @@ flow_hw_cnt_compile(struct rte_eth_dev *dev, uint32_t start_pos, return 0; } +static __rte_always_inline bool +is_of_vlan_pcp_present(const struct rte_flow_action *actions) +{ + /* + * Order of RTE VLAN push actions is + * OF_PUSH_VLAN / OF_SET_VLAN_VID [ / OF_SET_VLAN_PCP ] + */ + return actions[MLX5_HW_VLAN_PUSH_PCP_IDX].type == + RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP; +} + +static __rte_always_inline bool +is_template_masked_push_vlan(const struct rte_flow_action_of_push_vlan *mask) +{ + /* + * In masked push VLAN template all RTE push actions are masked. + */ + return mask && mask->ethertype != 0; +} + +static rte_be32_t vlan_hdr_to_be32(const struct rte_flow_action *actions) +{ +/* + * OpenFlow Switch Specification defines 801.1q VID as 12+1 bits. + */ + rte_be32_t type, vid, pcp; +#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN + rte_be32_t vid_lo, vid_hi; +#endif + + type = ((const struct rte_flow_action_of_push_vlan *) + actions[MLX5_HW_VLAN_PUSH_TYPE_IDX].conf)->ethertype; + vid = ((const struct rte_flow_action_of_set_vlan_vid *) + actions[MLX5_HW_VLAN_PUSH_VID_IDX].conf)->vlan_vid; + pcp = is_of_vlan_pcp_present(actions) ? + ((const struct rte_flow_action_of_set_vlan_pcp *) + actions[MLX5_HW_VLAN_PUSH_PCP_IDX].conf)->vlan_pcp : 0; +#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN + vid_hi = vid & 0xff; + vid_lo = vid >> 8; + return (((vid_lo << 8) | (pcp << 5) | vid_hi) << 16) | type; +#else + return (type << 16) | (pcp << 13) | vid; +#endif +} + /** * Translate rte_flow actions to DR action. * @@ -1167,6 +1223,26 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev, priv->hw_tag[!!attr->group]; flow_hw_rxq_flag_set(dev, true); break; + case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: + action_pos = at->actions_off[actions - at->actions]; + acts->rule_acts[action_pos].action = + priv->hw_push_vlan[type]; + if (is_template_masked_push_vlan(masks->conf)) + acts->rule_acts[action_pos].push_vlan.vlan_hdr = + vlan_hdr_to_be32(actions); + else if (__flow_hw_act_data_general_append + (priv, acts, actions->type, + actions - action_start, action_pos)) + goto err; + actions += is_of_vlan_pcp_present(actions) ? + MLX5_HW_VLAN_PUSH_PCP_IDX : + MLX5_HW_VLAN_PUSH_VID_IDX; + break; + case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: + action_pos = at->actions_off[actions - at->actions]; + acts->rule_acts[action_pos].action = + priv->hw_pop_vlan[type]; + break; case RTE_FLOW_ACTION_TYPE_JUMP: action_pos = at->actions_off[actions - at->actions]; if (masks->conf && @@ -1784,8 +1860,17 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, cnt_id_t cnt_id; action = &actions[act_data->action_src]; - MLX5_ASSERT(action->type == RTE_FLOW_ACTION_TYPE_INDIRECT || - (int)action->type == act_data->type); + /* + * action template construction replaces + * OF_SET_VLAN_VID with MODIFY_FIELD + */ + if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) + MLX5_ASSERT(act_data->type == + RTE_FLOW_ACTION_TYPE_MODIFY_FIELD); + else + MLX5_ASSERT(action->type == + RTE_FLOW_ACTION_TYPE_INDIRECT || + (int)action->type == act_data->type); switch (act_data->type) { case RTE_FLOW_ACTION_TYPE_INDIRECT: if (flow_hw_shared_action_construct @@ -1801,6 +1886,10 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, (action->conf))->id); rule_acts[act_data->action_dst].tag.value = tag; break; + case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: + rule_acts[act_data->action_dst].push_vlan.vlan_hdr = + vlan_hdr_to_be32(action); + break; case RTE_FLOW_ACTION_TYPE_JUMP: jump_group = ((const struct rte_flow_action_jump *) action->conf)->group; @@ -1852,10 +1941,16 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, act_data->encap.len); break; case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: - ret = flow_hw_modify_field_construct(job, - act_data, - hw_acts, - action); + if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) + ret = flow_hw_set_vlan_vid_construct(dev, job, + act_data, + hw_acts, + action); + else + ret = flow_hw_modify_field_construct(job, + act_data, + hw_acts, + action); if (ret) return -1; break; @@ -2559,9 +2654,14 @@ flow_hw_table_create(struct rte_eth_dev *dev, mlx5_ipool_destroy(tbl->flow); mlx5_free(tbl); } - rte_flow_error_set(error, err, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, - "fail to create rte table"); + if (error != NULL) { + rte_flow_error_set(error, err, + error->type == RTE_FLOW_ERROR_TYPE_NONE ? + RTE_FLOW_ERROR_TYPE_UNSPECIFIED : error->type, + NULL, + error->message == NULL ? + "fail to create rte table" : error->message); + } return NULL; } @@ -2865,28 +2965,76 @@ flow_hw_action_meta_copy_insert(const struct rte_flow_action actions[], uint16_t *ins_pos) { uint16_t idx, total = 0; - bool ins = false; + uint16_t end_idx = UINT16_MAX; bool act_end = false; + bool modify_field = false; + bool rss_or_queue = false; MLX5_ASSERT(actions && masks); MLX5_ASSERT(new_actions && new_masks); MLX5_ASSERT(ins_actions && ins_masks); for (idx = 0; !act_end; idx++) { - if (idx >= MLX5_HW_MAX_ACTS) - return -1; - if (actions[idx].type == RTE_FLOW_ACTION_TYPE_RSS || - actions[idx].type == RTE_FLOW_ACTION_TYPE_QUEUE) { - ins = true; - *ins_pos = idx; - } - if (actions[idx].type == RTE_FLOW_ACTION_TYPE_END) + switch (actions[idx].type) { + case RTE_FLOW_ACTION_TYPE_RSS: + case RTE_FLOW_ACTION_TYPE_QUEUE: + /* It is assumed that application provided only single RSS/QUEUE action. */ + MLX5_ASSERT(!rss_or_queue); + rss_or_queue = true; + break; + case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: + modify_field = true; + break; + case RTE_FLOW_ACTION_TYPE_END: + end_idx = idx; act_end = true; + break; + default: + break; + } } - if (!ins) + if (!rss_or_queue) return 0; - else if (idx == MLX5_HW_MAX_ACTS) + else if (idx >= MLX5_HW_MAX_ACTS) return -1; /* No more space. */ total = idx; + /* + * If actions template contains MODIFY_FIELD action, then meta copy action can be inserted + * at the template's end. Position of MODIFY_HDR action is based on the position of the + * first MODIFY_FIELD flow action. + */ + if (modify_field) { + *ins_pos = end_idx; + goto insert_meta_copy; + } + /* + * If actions template does not contain MODIFY_FIELD action, then meta copy action must be + * inserted at aplace conforming with action order defined in steering/mlx5dr_action.c. + */ + act_end = false; + for (idx = 0; !act_end; idx++) { + switch (actions[idx].type) { + case RTE_FLOW_ACTION_TYPE_COUNT: + case RTE_FLOW_ACTION_TYPE_METER: + case RTE_FLOW_ACTION_TYPE_METER_MARK: + case RTE_FLOW_ACTION_TYPE_CONNTRACK: + case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: + case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: + case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: + case RTE_FLOW_ACTION_TYPE_RSS: + case RTE_FLOW_ACTION_TYPE_QUEUE: + *ins_pos = idx; + act_end = true; + break; + case RTE_FLOW_ACTION_TYPE_END: + act_end = true; + break; + default: + break; + } + } +insert_meta_copy: + MLX5_ASSERT(*ins_pos != UINT16_MAX); + MLX5_ASSERT(*ins_pos < total); /* Before the position, no change for the actions. */ for (idx = 0; idx < *ins_pos; idx++) { new_actions[idx] = actions[idx]; @@ -2903,6 +3051,73 @@ flow_hw_action_meta_copy_insert(const struct rte_flow_action actions[], return 0; } +static int +flow_hw_validate_action_push_vlan(struct rte_eth_dev *dev, + const + struct rte_flow_actions_template_attr *attr, + const struct rte_flow_action *action, + const struct rte_flow_action *mask, + struct rte_flow_error *error) +{ +#define X_FIELD(ptr, t, f) (((ptr)->conf) && ((t *)((ptr)->conf))->f) + + const bool masked_push = + X_FIELD(mask + MLX5_HW_VLAN_PUSH_TYPE_IDX, + const struct rte_flow_action_of_push_vlan, ethertype); + bool masked_param; + + /* + * Mandatory actions order: + * OF_PUSH_VLAN / OF_SET_VLAN_VID [ / OF_SET_VLAN_PCP ] + */ + RTE_SET_USED(dev); + RTE_SET_USED(attr); + /* Check that mark matches OF_PUSH_VLAN */ + if (mask[MLX5_HW_VLAN_PUSH_TYPE_IDX].type != + RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, "OF_PUSH_VLAN: mask does not match"); + /* Check that the second template and mask items are SET_VLAN_VID */ + if (action[MLX5_HW_VLAN_PUSH_VID_IDX].type != + RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID || + mask[MLX5_HW_VLAN_PUSH_VID_IDX].type != + RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, "OF_PUSH_VLAN: invalid actions order"); + masked_param = X_FIELD(mask + MLX5_HW_VLAN_PUSH_VID_IDX, + const struct rte_flow_action_of_set_vlan_vid, + vlan_vid); + /* + * PMD requires OF_SET_VLAN_VID mask to must match OF_PUSH_VLAN + */ + if (masked_push ^ masked_param) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "OF_SET_VLAN_VID: mask does not match OF_PUSH_VLAN"); + if (is_of_vlan_pcp_present(action)) { + if (mask[MLX5_HW_VLAN_PUSH_PCP_IDX].type != + RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + action, "OF_SET_VLAN_PCP: missing mask configuration"); + masked_param = X_FIELD(mask + MLX5_HW_VLAN_PUSH_PCP_IDX, + const struct + rte_flow_action_of_set_vlan_pcp, + vlan_pcp); + /* + * PMD requires OF_SET_VLAN_PCP mask to must match OF_PUSH_VLAN + */ + if (masked_push ^ masked_param) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "OF_SET_VLAN_PCP: mask does not match OF_PUSH_VLAN"); + } + return 0; +#undef X_FIELD +} + static int flow_hw_actions_validate(struct rte_eth_dev *dev, const struct rte_flow_actions_template_attr *attr, @@ -2993,6 +3208,18 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_CONNTRACK: /* TODO: Validation logic */ break; + case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: + case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: + break; + case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: + ret = flow_hw_validate_action_push_vlan + (dev, attr, action, mask, error); + if (ret != 0) + return ret; + i += is_of_vlan_pcp_present(action) ? + MLX5_HW_VLAN_PUSH_PCP_IDX : + MLX5_HW_VLAN_PUSH_VID_IDX; + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -3020,6 +3247,8 @@ static enum mlx5dr_action_type mlx5_hw_dr_action_types[] = { [RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT] = MLX5DR_ACTION_TYP_VPORT, [RTE_FLOW_ACTION_TYPE_COUNT] = MLX5DR_ACTION_TYP_CTR, [RTE_FLOW_ACTION_TYPE_CONNTRACK] = MLX5DR_ACTION_TYP_ASO_CT, + [RTE_FLOW_ACTION_TYPE_OF_POP_VLAN] = MLX5DR_ACTION_TYP_POP_VLAN, + [RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN] = MLX5DR_ACTION_TYP_PUSH_VLAN, }; static int @@ -3136,6 +3365,14 @@ flow_hw_dr_actions_template_create(struct rte_flow_actions_template *at) goto err_actions_num; action_types[curr_off++] = MLX5DR_ACTION_TYP_FT; break; + case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: + type = mlx5_hw_dr_action_types[at->actions[i].type]; + at->actions_off[i] = curr_off; + action_types[curr_off++] = type; + i += is_of_vlan_pcp_present(at->actions + i) ? + MLX5_HW_VLAN_PUSH_PCP_IDX : + MLX5_HW_VLAN_PUSH_VID_IDX; + break; default: type = mlx5_hw_dr_action_types[at->actions[i].type]; at->actions_off[i] = curr_off; @@ -3163,6 +3400,89 @@ flow_hw_dr_actions_template_create(struct rte_flow_actions_template *at) return NULL; } +static void +flow_hw_set_vlan_vid(struct rte_eth_dev *dev, + struct rte_flow_action *ra, + struct rte_flow_action *rm, + struct rte_flow_action_modify_field *spec, + struct rte_flow_action_modify_field *mask, + int set_vlan_vid_ix) +{ + struct rte_flow_error error; + const bool masked = rm[set_vlan_vid_ix].conf && + (((const struct rte_flow_action_of_set_vlan_vid *) + rm[set_vlan_vid_ix].conf)->vlan_vid != 0); + const struct rte_flow_action_of_set_vlan_vid *conf = + ra[set_vlan_vid_ix].conf; + rte_be16_t vid = masked ? conf->vlan_vid : 0; + int width = mlx5_flow_item_field_width(dev, RTE_FLOW_FIELD_VLAN_ID, 0, + NULL, &error); + *spec = (typeof(*spec)) { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = RTE_FLOW_FIELD_VLAN_ID, + .level = 0, .offset = 0, + }, + .src = { + .field = RTE_FLOW_FIELD_VALUE, + .level = vid, + .offset = 0, + }, + .width = width, + }; + *mask = (typeof(*mask)) { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = RTE_FLOW_FIELD_VLAN_ID, + .level = 0xffffffff, .offset = 0xffffffff, + }, + .src = { + .field = RTE_FLOW_FIELD_VALUE, + .level = masked ? (1U << width) - 1 : 0, + .offset = 0, + }, + .width = 0xffffffff, + }; + ra[set_vlan_vid_ix].type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD; + ra[set_vlan_vid_ix].conf = spec; + rm[set_vlan_vid_ix].type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD; + rm[set_vlan_vid_ix].conf = mask; +} + +static __rte_always_inline int +flow_hw_set_vlan_vid_construct(struct rte_eth_dev *dev, + struct mlx5_hw_q_job *job, + struct mlx5_action_construct_data *act_data, + const struct mlx5_hw_actions *hw_acts, + const struct rte_flow_action *action) +{ + struct rte_flow_error error; + rte_be16_t vid = ((const struct rte_flow_action_of_set_vlan_vid *) + action->conf)->vlan_vid; + int width = mlx5_flow_item_field_width(dev, RTE_FLOW_FIELD_VLAN_ID, 0, + NULL, &error); + struct rte_flow_action_modify_field conf = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = RTE_FLOW_FIELD_VLAN_ID, + .level = 0, .offset = 0, + }, + .src = { + .field = RTE_FLOW_FIELD_VALUE, + .level = vid, + .offset = 0, + }, + .width = width, + }; + struct rte_flow_action modify_action = { + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + .conf = &conf + }; + + return flow_hw_modify_field_construct(job, act_data, hw_acts, + &modify_action); +} + /** * Create flow action template. * @@ -3188,14 +3508,18 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; - int len, act_num, act_len, mask_len; + int len, act_len, mask_len; + unsigned int act_num; unsigned int i; struct rte_flow_actions_template *at = NULL; - uint16_t pos = MLX5_HW_MAX_ACTS; + uint16_t pos = UINT16_MAX; struct rte_flow_action tmp_action[MLX5_HW_MAX_ACTS]; struct rte_flow_action tmp_mask[MLX5_HW_MAX_ACTS]; - const struct rte_flow_action *ra; - const struct rte_flow_action *rm; + struct rte_flow_action *ra = (void *)(uintptr_t)actions; + struct rte_flow_action *rm = (void *)(uintptr_t)masks; + int set_vlan_vid_ix = -1; + struct rte_flow_action_modify_field set_vlan_vid_spec = {0, }; + struct rte_flow_action_modify_field set_vlan_vid_mask = {0, }; const struct rte_flow_action_modify_field rx_mreg = { .operation = RTE_FLOW_MODIFY_SET, .dst = { @@ -3235,21 +3559,58 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, return NULL; if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS && priv->sh->config.dv_esw_en) { + /* Application should make sure only one Q/RSS exist in one rule. */ if (flow_hw_action_meta_copy_insert(actions, masks, &rx_cpy, &rx_cpy_mask, tmp_action, tmp_mask, &pos)) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Failed to concatenate new action/mask"); return NULL; + } else if (pos != UINT16_MAX) { + ra = tmp_action; + rm = tmp_mask; } } - /* Application should make sure only one Q/RSS exist in one rule. */ - if (pos == MLX5_HW_MAX_ACTS) { - ra = actions; - rm = masks; - } else { - ra = tmp_action; - rm = tmp_mask; + for (i = 0; ra[i].type != RTE_FLOW_ACTION_TYPE_END; ++i) { + switch (ra[i].type) { + /* OF_PUSH_VLAN *MUST* come before OF_SET_VLAN_VID */ + case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: + i += is_of_vlan_pcp_present(ra + i) ? + MLX5_HW_VLAN_PUSH_PCP_IDX : + MLX5_HW_VLAN_PUSH_VID_IDX; + break; + case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: + set_vlan_vid_ix = i; + break; + default: + break; + } + } + /* + * Count flow actions to allocate required space for storing DR offsets and to check + * if temporary buffer would not be overrun. + */ + act_num = i + 1; + if (act_num >= MLX5_HW_MAX_ACTS) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Too many actions"); + return NULL; + } + if (set_vlan_vid_ix != -1) { + /* If temporary action buffer was not used, copy template actions to it */ + if (ra == actions && rm == masks) { + for (i = 0; i < act_num; ++i) { + tmp_action[i] = actions[i]; + tmp_mask[i] = masks[i]; + if (actions[i].type == RTE_FLOW_ACTION_TYPE_END) + break; + } + ra = tmp_action; + rm = tmp_mask; + } + flow_hw_set_vlan_vid(dev, ra, rm, + &set_vlan_vid_spec, &set_vlan_vid_mask, + set_vlan_vid_ix); } act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, NULL, 0, ra, error); if (act_len <= 0) @@ -3259,10 +3620,6 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, if (mask_len <= 0) return NULL; len += RTE_ALIGN(mask_len, 16); - /* Count flow actions to allocate required space for storing DR offsets. */ - act_num = 0; - for (i = 0; ra[i].type != RTE_FLOW_ACTION_TYPE_END; ++i) - act_num++; len += RTE_ALIGN(act_num * sizeof(*at->actions_off), 16); at = mlx5_malloc(MLX5_MEM_ZERO, len + sizeof(*at), RTE_CACHE_LINE_SIZE, rte_socket_id()); @@ -4513,7 +4870,11 @@ flow_hw_create_tx_default_mreg_copy_table(struct rte_eth_dev *dev, .attr = tx_tbl_attr, .external = false, }; - struct rte_flow_error drop_err; + struct rte_flow_error drop_err = { + .type = RTE_FLOW_ERROR_TYPE_NONE, + .cause = NULL, + .message = NULL, + }; RTE_SET_USED(drop_err); return flow_hw_table_create(dev, &tx_tbl_cfg, &pt, 1, &at, 1, &drop_err); @@ -4794,6 +5155,60 @@ flow_hw_ct_pool_create(struct rte_eth_dev *dev, return NULL; } +static void +flow_hw_destroy_vlan(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + enum mlx5dr_table_type i; + + for (i = MLX5DR_TABLE_TYPE_NIC_RX; i < MLX5DR_TABLE_TYPE_MAX; i++) { + if (priv->hw_pop_vlan[i]) { + mlx5dr_action_destroy(priv->hw_pop_vlan[i]); + priv->hw_pop_vlan[i] = NULL; + } + if (priv->hw_push_vlan[i]) { + mlx5dr_action_destroy(priv->hw_push_vlan[i]); + priv->hw_push_vlan[i] = NULL; + } + } +} + +static int +flow_hw_create_vlan(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + enum mlx5dr_table_type i; + const enum mlx5dr_action_flags flags[MLX5DR_TABLE_TYPE_MAX] = { + MLX5DR_ACTION_FLAG_HWS_RX, + MLX5DR_ACTION_FLAG_HWS_TX, + MLX5DR_ACTION_FLAG_HWS_FDB + }; + + for (i = MLX5DR_TABLE_TYPE_NIC_RX; i <= MLX5DR_TABLE_TYPE_NIC_TX; i++) { + priv->hw_pop_vlan[i] = + mlx5dr_action_create_pop_vlan(priv->dr_ctx, flags[i]); + if (!priv->hw_pop_vlan[i]) + return -ENOENT; + priv->hw_push_vlan[i] = + mlx5dr_action_create_push_vlan(priv->dr_ctx, flags[i]); + if (!priv->hw_pop_vlan[i]) + return -ENOENT; + } + if (priv->sh->config.dv_esw_en && priv->master) { + priv->hw_pop_vlan[MLX5DR_TABLE_TYPE_FDB] = + mlx5dr_action_create_pop_vlan + (priv->dr_ctx, MLX5DR_ACTION_FLAG_HWS_FDB); + if (!priv->hw_pop_vlan[MLX5DR_TABLE_TYPE_FDB]) + return -ENOENT; + priv->hw_push_vlan[MLX5DR_TABLE_TYPE_FDB] = + mlx5dr_action_create_push_vlan + (priv->dr_ctx, MLX5DR_ACTION_FLAG_HWS_FDB); + if (!priv->hw_pop_vlan[MLX5DR_TABLE_TYPE_FDB]) + return -ENOENT; + } + return 0; +} + /** * Configure port HWS resources. * @@ -4999,6 +5414,9 @@ flow_hw_configure(struct rte_eth_dev *dev, if (priv->hws_cpool == NULL) goto err; } + ret = flow_hw_create_vlan(dev); + if (ret) + goto err; return 0; err: if (priv->hws_ctpool) { @@ -5016,6 +5434,7 @@ flow_hw_configure(struct rte_eth_dev *dev, if (priv->hw_tag[i]) mlx5dr_action_destroy(priv->hw_tag[i]); } + flow_hw_destroy_vlan(dev); if (dr_ctx) claim_zero(mlx5dr_context_close(dr_ctx)); mlx5_free(priv->hw_q); @@ -5075,6 +5494,7 @@ flow_hw_resource_release(struct rte_eth_dev *dev) if (priv->hw_tag[i]) mlx5dr_action_destroy(priv->hw_tag[i]); } + flow_hw_destroy_vlan(dev); flow_hw_free_vport_actions(priv); if (priv->acts_ipool) { mlx5_ipool_destroy(priv->acts_ipool); From patchwork Fri Sep 30 12:53:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117222 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 06C9AA00C4; Fri, 30 Sep 2022 14:55:29 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id C83BE42B6E; Fri, 30 Sep 2022 14:54:17 +0200 (CEST) Received: from NAM12-BN8-obe.outbound.protection.outlook.com (mail-bn8nam12on2050.outbound.protection.outlook.com [40.107.237.50]) by mails.dpdk.org (Postfix) with ESMTP id D255942BB0 for ; Fri, 30 Sep 2022 14:54:11 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=gk2Vj77Z0HHIIF36BSxabNenlfrU+I7uys7uIyQevE//gq8RntkITRy1ONbjwC9YuDEmVQtPH2r5yJh1f++JnpwTIspMfqfRhBMJjPzeOfHq5wHpXAkMk6faR2SqZg//B3PihVV5eA7GPVXJvG9ZGjzJVkwOXz+hTT/T6mSBHB+Xn9kRA+qrvrK71qMGsWJ/ux/D6ArlP25iUy37WO5f2ze54OsS9Ryyu9MYROTP6Lxa19MpjdFihAWirmqgC3ME65OMvxEJDZDM2sjtHS4XlNgvz54rTaRta6YmJ79QEFInqcF/TtuqGk+nQtRHL6OttjcG6Rob8obREOI9XN++Dg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ZeQaD6buAgTwaOqPsm2biRGVHXyC1jA2toKID2l7Mr8=; b=WiJ52Wm2pocee0zUtdHRYI9h6NNbW4lhT68kl8h+u4EXOdWRa/OFs9N4boRVaQV7e5r2Vzy1dqFWKyD4vh/ZP+bb/U7GCuEp5tO4qARqOAHut6QeHnUbFfKbBxLlt/c3W9GOig/sJyCp8LpBNw5Qk4q5rZaxDruGB6JuM8UWqsgtbR91SSRlxtdc/vT/j5Of1TZOlXtP87ZVqA3vYZEDzBqqYn8mXb/Qjk+6OYCd687E6OUlE+tW53vw//GTp9/XoB5kz2wwT96PGCggrJcvSJ1LcmSQvtkgl7kiXB1g0LFHM/6U89ULsCGh35CpTxAXEiNkqW6EgSgidkfIxY3Zew== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ZeQaD6buAgTwaOqPsm2biRGVHXyC1jA2toKID2l7Mr8=; b=Dw3ADdhW32tNIuLZRQKpSw1uNI1IycfV7qUQUJcQ64dUpwC/t/e4Iad1CKYgdmdfk6aTjCUKy9wH2bCGFyqcPKrxNpcaC05P8fqoLsuTKcngK1N75+A+/65B8ySEANUHJbsaSyiv3x/sAJLLhnrPkdla+uFrt3fevbXbWod/9jm/jyfVNTpApuku6XXv+b0U0NKK0PGMhiqxztNK9QThqN3DWMaIH8LFhWJiZ1+iMBwLyydk7WCL3ylhYdDRlcvfKfwHom7OWLZMx7eraG6l2IMNv++AsWLlQnBvOq/EIlol8Y183pybsm7MXsdi45InuPLMJxpEpq+IeFogZSMKgg== Received: from DS7PR05CA0039.namprd05.prod.outlook.com (2603:10b6:8:2f::16) by BL3PR12MB6620.namprd12.prod.outlook.com (2603:10b6:208:38f::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17; Fri, 30 Sep 2022 12:54:09 +0000 Received: from DM6NAM11FT097.eop-nam11.prod.protection.outlook.com (2603:10b6:8:2f:cafe::4d) by DS7PR05CA0039.outlook.office365.com (2603:10b6:8:2f::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.7 via Frontend Transport; Fri, 30 Sep 2022 12:54:09 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT097.mail.protection.outlook.com (10.13.172.72) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:08 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:54:01 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:53:59 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , "Alexander Kozyrev" Subject: [PATCH v3 12/17] net/mlx5: implement METER MARK indirect action for HWS Date: Fri, 30 Sep 2022 15:53:10 +0300 Message-ID: <20220930125315.5079-13-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT097:EE_|BL3PR12MB6620:EE_ X-MS-Office365-Filtering-Correlation-Id: d5105a9a-8c3c-40ec-5673-08daa2e2dd86 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: n9GB0xBVAGJcQlpbkvHmQt0kl4nuaqZwaPbRwoaF1uvjvJ98EgA7lMi59VQPFSEOoQPgqRUBIupTuTvcIaGNCDR51MRU7FR5mje+nQHvkmWgbbtc3W2bHVnVMWPyNPYU4T+/FGrFA+hy9bfx1WgkRLZg0x7pAoUl9vjw4fdpR9ihY2p92qdjI/UwjXnfuJd4TdGXui/rAvshaTIFnGd/gJukGWfWnZqLUjjZChIMTPQ9VcQmQnUH8POS9krHxDhZmRs4VzY99i1OWA+fyTH+OaCrmyChnLXmpZYzyZJFwpx2Kf9BzbSYc7L2GlYX3WXiLm/p54d3aWEDeqWklmE2QS6+z5vkHSNGas8kPLKhDqqQUsulrZHQdmeqTpMT0xA0IC76wozl5W+P5C6slQXwRb8zqxPHMVdKep8Do0wwHloOkiSvzb0QcJV6gSF1yUQyoMPPt9n102KjbAkvlat6IBERtkYVaan/MonQ/axsouItZoaYU6LiLg9AWHDFu3OOeMAejNDM92v8l1KmmooL3RickdBTaTw0vJo64kDSjRjzwV+Rv77Y3o4qY/w7taym1Afy7l9lbYTWjNKR+LFcjpOORyQ2Fs5IR0TewCA6KrN90et99MJNcxZBs4sISEGdjWGukc62j3lIkRptNn+22zRWlcTUBzXSsejEOVZpMzmUVTszMmqyZagOiAtaBPAJEPEh2kfEfNz20kiuYBvU2OjKDmVL/1RbRK/o/mxpe4TJt7jXAAXLsMQjnJJ2rKsA066pVyLYWl95oN56c2F3C+R0EA0TGnORkxW7exixJQs= X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(39860400002)(136003)(396003)(376002)(346002)(451199015)(40470700004)(46966006)(36840700001)(8936002)(5660300002)(83380400001)(36756003)(7696005)(6286002)(6666004)(107886003)(426003)(41300700001)(6636002)(478600001)(54906003)(110136005)(2906002)(40460700003)(186003)(4326008)(70586007)(70206006)(1076003)(30864003)(2616005)(26005)(336012)(55016003)(82310400005)(8676002)(40480700001)(16526019)(47076005)(316002)(86362001)(82740400003)(356005)(36860700001)(7636003)(559001)(579004)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:54:08.7817 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: d5105a9a-8c3c-40ec-5673-08daa2e2dd86 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT097.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL3PR12MB6620 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Alexander Kozyrev Add ability to create an indirect action handle for METER_MARK. It allows to share one Meter between several different actions. Signed-off-by: Alexander Kozyrev --- drivers/net/mlx5/mlx5.c | 4 +- drivers/net/mlx5/mlx5.h | 33 ++- drivers/net/mlx5/mlx5_flow.c | 6 + drivers/net/mlx5/mlx5_flow.h | 19 +- drivers/net/mlx5/mlx5_flow_aso.c | 139 +++++++-- drivers/net/mlx5/mlx5_flow_dv.c | 145 +++++++++- drivers/net/mlx5/mlx5_flow_hw.c | 438 +++++++++++++++++++++++++---- drivers/net/mlx5/mlx5_flow_meter.c | 79 +++++- 8 files changed, 764 insertions(+), 99 deletions(-) diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 925e19bcd5..383a789dfa 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -442,7 +442,7 @@ mlx5_flow_aso_age_mng_init(struct mlx5_dev_ctx_shared *sh) rte_errno = ENOMEM; return -ENOMEM; } - err = mlx5_aso_queue_init(sh, ASO_OPC_MOD_FLOW_HIT); + err = mlx5_aso_queue_init(sh, ASO_OPC_MOD_FLOW_HIT, 1); if (err) { mlx5_free(sh->aso_age_mng); return -1; @@ -763,7 +763,7 @@ mlx5_flow_aso_ct_mng_init(struct mlx5_dev_ctx_shared *sh) rte_errno = ENOMEM; return -rte_errno; } - err = mlx5_aso_queue_init(sh, ASO_OPC_MOD_CONNECTION_TRACKING); + err = mlx5_aso_queue_init(sh, ASO_OPC_MOD_CONNECTION_TRACKING, MLX5_ASO_CT_SQ_NUM); if (err) { mlx5_free(sh->ct_mng); /* rte_errno should be extracted from the failure. */ diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 7ec5f6a352..89dc8441dc 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -971,12 +971,16 @@ enum mlx5_aso_mtr_type { /* Generic aso_flow_meter information. */ struct mlx5_aso_mtr { - LIST_ENTRY(mlx5_aso_mtr) next; + union { + LIST_ENTRY(mlx5_aso_mtr) next; + struct mlx5_aso_mtr_pool *pool; + }; enum mlx5_aso_mtr_type type; struct mlx5_flow_meter_info fm; /**< Pointer to the next aso flow meter structure. */ uint8_t state; /**< ASO flow meter state. */ uint32_t offset; + enum rte_color init_color; }; /* Generic aso_flow_meter pool structure. */ @@ -985,7 +989,11 @@ struct mlx5_aso_mtr_pool { /*Must be the first in pool*/ struct mlx5_devx_obj *devx_obj; /* The devx object of the minimum aso flow meter ID. */ + struct mlx5dr_action *action; /* HWS action. */ + struct mlx5_indexed_pool *idx_pool; /* HWS index pool. */ uint32_t index; /* Pool index in management structure. */ + uint32_t nb_sq; /* Number of ASO SQ. */ + struct mlx5_aso_sq *sq; /* ASO SQs. */ }; LIST_HEAD(aso_meter_list, mlx5_aso_mtr); @@ -1678,6 +1686,7 @@ struct mlx5_priv { struct mlx5_aso_ct_pools_mng *ct_mng; /* Management data for ASO connection tracking. */ struct mlx5_aso_ct_pool *hws_ctpool; /* HW steering's CT pool. */ + struct mlx5_aso_mtr_pool *hws_mpool; /* HW steering's Meter pool. */ #endif }; @@ -1998,7 +2007,8 @@ void mlx5_pmd_socket_uninit(void); int mlx5_flow_meter_init(struct rte_eth_dev *dev, uint32_t nb_meters, uint32_t nb_meter_profiles, - uint32_t nb_meter_policies); + uint32_t nb_meter_policies, + uint32_t nb_queues); void mlx5_flow_meter_uninit(struct rte_eth_dev *dev); int mlx5_flow_meter_ops_get(struct rte_eth_dev *dev, void *arg); struct mlx5_flow_meter_info *mlx5_flow_meter_find(struct mlx5_priv *priv, @@ -2067,15 +2077,24 @@ eth_tx_burst_t mlx5_select_tx_function(struct rte_eth_dev *dev); /* mlx5_flow_aso.c */ +int mlx5_aso_mtr_queue_init(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_mtr_pool *hws_pool, + struct mlx5_aso_mtr_pools_mng *pool_mng, + uint32_t nb_queues); +void mlx5_aso_mtr_queue_uninit(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_mtr_pool *hws_pool, + struct mlx5_aso_mtr_pools_mng *pool_mng); int mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh, - enum mlx5_access_aso_opc_mod aso_opc_mod); + enum mlx5_access_aso_opc_mod aso_opc_mode, + uint32_t nb_queues); int mlx5_aso_flow_hit_queue_poll_start(struct mlx5_dev_ctx_shared *sh); int mlx5_aso_flow_hit_queue_poll_stop(struct mlx5_dev_ctx_shared *sh); void mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh, - enum mlx5_access_aso_opc_mod aso_opc_mod); -int mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, - struct mlx5_aso_mtr *mtr, struct mlx5_mtr_bulk *bulk); -int mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, + enum mlx5_access_aso_opc_mod aso_opc_mod); +int mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, + struct mlx5_aso_mtr *mtr, + struct mlx5_mtr_bulk *bulk); +int mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_mtr *mtr); int mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct, diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index cbf9c31984..9627ffc979 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -4221,6 +4221,12 @@ flow_action_handles_translate(struct rte_eth_dev *dev, MLX5_RTE_FLOW_ACTION_TYPE_COUNT; translated[handle->index].conf = (void *)(uintptr_t)idx; break; + case MLX5_INDIRECT_ACTION_TYPE_METER_MARK: + translated[handle->index].type = + (enum rte_flow_action_type) + MLX5_RTE_FLOW_ACTION_TYPE_METER_MARK; + translated[handle->index].conf = (void *)(uintptr_t)idx; + break; case MLX5_INDIRECT_ACTION_TYPE_AGE: if (priv->sh->flow_hit_aso_en) { translated[handle->index].type = diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 6d928b477e..ffa4f28255 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -46,6 +46,7 @@ enum mlx5_rte_flow_action_type { MLX5_RTE_FLOW_ACTION_TYPE_COUNT, MLX5_RTE_FLOW_ACTION_TYPE_JUMP, MLX5_RTE_FLOW_ACTION_TYPE_RSS, + MLX5_RTE_FLOW_ACTION_TYPE_METER_MARK, }; /* Private (internal) Field IDs for MODIFY_FIELD action. */ @@ -54,22 +55,23 @@ enum mlx5_rte_flow_field_id { MLX5_RTE_FLOW_FIELD_META_REG, }; -#define MLX5_INDIRECT_ACTION_TYPE_OFFSET 30 +#define MLX5_INDIRECT_ACTION_TYPE_OFFSET 29 enum { MLX5_INDIRECT_ACTION_TYPE_RSS, MLX5_INDIRECT_ACTION_TYPE_AGE, MLX5_INDIRECT_ACTION_TYPE_COUNT, MLX5_INDIRECT_ACTION_TYPE_CT, + MLX5_INDIRECT_ACTION_TYPE_METER_MARK, }; -/* Now, the maximal ports will be supported is 256, action number is 4M. */ -#define MLX5_INDIRECT_ACT_CT_MAX_PORT 0x100 +/* Now, the maximal ports will be supported is 16, action number is 32M. */ +#define MLX5_INDIRECT_ACT_CT_MAX_PORT 0x10 #define MLX5_INDIRECT_ACT_CT_OWNER_SHIFT 22 #define MLX5_INDIRECT_ACT_CT_OWNER_MASK (MLX5_INDIRECT_ACT_CT_MAX_PORT - 1) -/* 30-31: type, 22-29: owner port, 0-21: index. */ +/* 29-31: type, 25-28: owner port, 0-24: index */ #define MLX5_INDIRECT_ACT_CT_GEN_IDX(owner, index) \ ((MLX5_INDIRECT_ACTION_TYPE_CT << MLX5_INDIRECT_ACTION_TYPE_OFFSET) | \ (((owner) & MLX5_INDIRECT_ACT_CT_OWNER_MASK) << \ @@ -207,6 +209,9 @@ enum mlx5_feature_name { #define MLX5_FLOW_ITEM_PORT_REPRESENTOR (UINT64_C(1) << 41) #define MLX5_FLOW_ITEM_REPRESENTED_PORT (UINT64_C(1) << 42) +/* Meter color item */ +#define MLX5_FLOW_ITEM_METER_COLOR (UINT64_C(1) << 44) + /* Outer Masks. */ #define MLX5_FLOW_LAYER_OUTER_L3 \ (MLX5_FLOW_LAYER_OUTER_L3_IPV4 | MLX5_FLOW_LAYER_OUTER_L3_IPV6) @@ -1108,6 +1113,7 @@ struct rte_flow_hw { struct rte_flow_template_table *table; /* The table flow allcated from. */ struct mlx5dr_rule rule; /* HWS layer data struct. */ uint32_t cnt_id; + uint32_t mtr_id; } __rte_packed; /* rte flow action translate to DR action struct. */ @@ -1154,6 +1160,9 @@ struct mlx5_action_construct_data { struct { uint32_t id; } shared_counter; + struct { + uint32_t id; + } shared_meter; }; }; @@ -1237,6 +1246,7 @@ struct mlx5_hw_actions { uint16_t encap_decap_pos; /* Encap/Decap action position. */ uint32_t mark:1; /* Indicate the mark action. */ uint32_t cnt_id; /* Counter id. */ + uint32_t mtr_id; /* Meter id. */ /* Translated DR action array from action template. */ struct mlx5dr_rule_action rule_acts[MLX5_HW_MAX_ACTS]; }; @@ -1524,6 +1534,7 @@ flow_hw_get_reg_id(enum rte_flow_item_type type, uint32_t id) */ return REG_A; case RTE_FLOW_ITEM_TYPE_CONNTRACK: + case RTE_FLOW_ITEM_TYPE_METER_COLOR: return mlx5_flow_hw_aso_tag; case RTE_FLOW_ITEM_TYPE_TAG: MLX5_ASSERT(id < MLX5_FLOW_HW_TAGS_MAX); diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c index c00c07b891..f371fff2e2 100644 --- a/drivers/net/mlx5/mlx5_flow_aso.c +++ b/drivers/net/mlx5/mlx5_flow_aso.c @@ -275,6 +275,65 @@ mlx5_aso_sq_create(struct mlx5_common_device *cdev, struct mlx5_aso_sq *sq, return -1; } +void +mlx5_aso_mtr_queue_uninit(struct mlx5_dev_ctx_shared *sh __rte_unused, + struct mlx5_aso_mtr_pool *hws_pool, + struct mlx5_aso_mtr_pools_mng *pool_mng) +{ + uint32_t i; + + if (hws_pool) { + for (i = 0; i < hws_pool->nb_sq; i++) + mlx5_aso_destroy_sq(hws_pool->sq + i); + mlx5_free(hws_pool->sq); + return; + } + if (pool_mng) + mlx5_aso_destroy_sq(&pool_mng->sq); +} + +int +mlx5_aso_mtr_queue_init(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_mtr_pool *hws_pool, + struct mlx5_aso_mtr_pools_mng *pool_mng, + uint32_t nb_queues) +{ + struct mlx5_common_device *cdev = sh->cdev; + struct mlx5_aso_sq *sq; + uint32_t i; + + if (hws_pool) { + sq = mlx5_malloc(MLX5_MEM_ZERO, + sizeof(struct mlx5_aso_sq) * nb_queues, + RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); + if (!sq) + return -1; + hws_pool->sq = sq; + for (i = 0; i < nb_queues; i++) { + if (mlx5_aso_sq_create(cdev, hws_pool->sq + i, + sh->tx_uar.obj, + MLX5_ASO_QUEUE_LOG_DESC)) + goto error; + mlx5_aso_mtr_init_sq(hws_pool->sq + i); + } + hws_pool->nb_sq = nb_queues; + } + if (pool_mng) { + if (mlx5_aso_sq_create(cdev, &pool_mng->sq, + sh->tx_uar.obj, + MLX5_ASO_QUEUE_LOG_DESC)) + return -1; + mlx5_aso_mtr_init_sq(&pool_mng->sq); + } + return 0; +error: + do { + if (&hws_pool->sq[i]) + mlx5_aso_destroy_sq(hws_pool->sq + i); + } while (i--); + return -1; +} + /** * API to create and initialize Send Queue used for ASO access. * @@ -282,13 +341,16 @@ mlx5_aso_sq_create(struct mlx5_common_device *cdev, struct mlx5_aso_sq *sq, * Pointer to shared device context. * @param[in] aso_opc_mod * Mode of ASO feature. + * @param[in] nb_queues + * Number of Send Queues to create. * * @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ int mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh, - enum mlx5_access_aso_opc_mod aso_opc_mod) + enum mlx5_access_aso_opc_mod aso_opc_mod, + uint32_t nb_queues) { uint32_t sq_desc_n = 1 << MLX5_ASO_QUEUE_LOG_DESC; struct mlx5_common_device *cdev = sh->cdev; @@ -307,10 +369,9 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh, mlx5_aso_age_init_sq(&sh->aso_age_mng->aso_sq); break; case ASO_OPC_MOD_POLICER: - if (mlx5_aso_sq_create(cdev, &sh->mtrmng->pools_mng.sq, - sh->tx_uar.obj, MLX5_ASO_QUEUE_LOG_DESC)) + if (mlx5_aso_mtr_queue_init(sh, NULL, + &sh->mtrmng->pools_mng, nb_queues)) return -1; - mlx5_aso_mtr_init_sq(&sh->mtrmng->pools_mng.sq); break; case ASO_OPC_MOD_CONNECTION_TRACKING: if (mlx5_aso_ct_queue_init(sh, sh->ct_mng, MLX5_ASO_CT_SQ_NUM)) @@ -343,7 +404,7 @@ mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh, sq = &sh->aso_age_mng->aso_sq; break; case ASO_OPC_MOD_POLICER: - sq = &sh->mtrmng->pools_mng.sq; + mlx5_aso_mtr_queue_uninit(sh, NULL, &sh->mtrmng->pools_mng); break; case ASO_OPC_MOD_CONNECTION_TRACKING: mlx5_aso_ct_queue_uninit(sh, sh->ct_mng); @@ -666,7 +727,8 @@ static uint16_t mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, struct mlx5_aso_sq *sq, struct mlx5_aso_mtr *aso_mtr, - struct mlx5_mtr_bulk *bulk) + struct mlx5_mtr_bulk *bulk, + bool need_lock) { volatile struct mlx5_aso_wqe *wqe = NULL; struct mlx5_flow_meter_info *fm = NULL; @@ -679,11 +741,13 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, uint32_t param_le; int id; - rte_spinlock_lock(&sq->sqsl); + if (need_lock) + rte_spinlock_lock(&sq->sqsl); res = size - (uint16_t)(sq->head - sq->tail); if (unlikely(!res)) { DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send"); - rte_spinlock_unlock(&sq->sqsl); + if (need_lock) + rte_spinlock_unlock(&sq->sqsl); return 0; } wqe = &sq->sq_obj.aso_wqes[sq->head & mask]; @@ -692,8 +756,11 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, fm = &aso_mtr->fm; sq->elts[sq->head & mask].mtr = aso_mtr; if (aso_mtr->type == ASO_METER_INDIRECT) { - pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool, - mtrs[aso_mtr->offset]); + if (likely(sh->config.dv_flow_en == 2)) + pool = aso_mtr->pool; + else + pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool, + mtrs[aso_mtr->offset]); id = pool->devx_obj->id; } else { id = bulk->devx_obj->id; @@ -756,7 +823,8 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], !sh->tx_uar.dbnc); - rte_spinlock_unlock(&sq->sqsl); + if (need_lock) + rte_spinlock_unlock(&sq->sqsl); return 1; } @@ -779,7 +847,7 @@ mlx5_aso_mtrs_status_update(struct mlx5_aso_sq *sq, uint16_t aso_mtrs_nums) } static void -mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq) +mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq, bool need_lock) { struct mlx5_aso_cq *cq = &sq->cq; volatile struct mlx5_cqe *restrict cqe; @@ -791,7 +859,8 @@ mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq) uint16_t n = 0; int ret; - rte_spinlock_lock(&sq->sqsl); + if (need_lock) + rte_spinlock_lock(&sq->sqsl); max = (uint16_t)(sq->head - sq->tail); if (unlikely(!max)) { rte_spinlock_unlock(&sq->sqsl); @@ -823,7 +892,8 @@ mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq) rte_io_wmb(); cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci); } - rte_spinlock_unlock(&sq->sqsl); + if (need_lock) + rte_spinlock_unlock(&sq->sqsl); } /** @@ -840,16 +910,30 @@ mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq) * 0 on success, a negative errno value otherwise and rte_errno is set. */ int -mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, +mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_mtr *mtr, struct mlx5_mtr_bulk *bulk) { - struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq; + struct mlx5_aso_sq *sq; uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES; + bool need_lock; + if (likely(sh->config.dv_flow_en == 2)) { + if (queue == MLX5_HW_INV_QUEUE) { + sq = &mtr->pool->sq[mtr->pool->nb_sq - 1]; + need_lock = true; + } else { + sq = &mtr->pool->sq[queue]; + need_lock = false; + } + } else { + sq = &sh->mtrmng->pools_mng.sq; + need_lock = true; + } do { - mlx5_aso_mtr_completion_handle(sq); - if (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk)) + mlx5_aso_mtr_completion_handle(sq, need_lock); + if (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, + bulk, need_lock)) return 0; /* Waiting for wqe resource. */ rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY); @@ -873,17 +957,30 @@ mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, * 0 on success, a negative errno value otherwise and rte_errno is set. */ int -mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, +mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_mtr *mtr) { - struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq; + struct mlx5_aso_sq *sq; uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES; + bool need_lock; + if (likely(sh->config.dv_flow_en == 2)) { + if (queue == MLX5_HW_INV_QUEUE) { + sq = &mtr->pool->sq[mtr->pool->nb_sq - 1]; + need_lock = true; + } else { + sq = &mtr->pool->sq[queue]; + need_lock = false; + } + } else { + sq = &sh->mtrmng->pools_mng.sq; + need_lock = true; + } if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) == ASO_METER_READY) return 0; do { - mlx5_aso_mtr_completion_handle(sq); + mlx5_aso_mtr_completion_handle(sq, need_lock); if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) == ASO_METER_READY) return 0; diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 7f81272150..a42eb99154 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -1387,6 +1387,7 @@ mlx5_flow_item_field_width(struct rte_eth_dev *dev, return inherit < 0 ? 0 : inherit; case RTE_FLOW_FIELD_IPV4_ECN: case RTE_FLOW_FIELD_IPV6_ECN: + case RTE_FLOW_FIELD_METER_COLOR: return 2; default: MLX5_ASSERT(false); @@ -1856,6 +1857,31 @@ mlx5_flow_field_id_to_modify_info info[idx].offset = data->offset; } break; + case RTE_FLOW_FIELD_METER_COLOR: + { + const uint32_t color_mask = + (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1; + int reg; + + if (priv->sh->config.dv_flow_en == 2) + reg = flow_hw_get_reg_id + (RTE_FLOW_ITEM_TYPE_METER_COLOR, 0); + else + reg = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, + 0, error); + if (reg < 0) + return; + MLX5_ASSERT(reg != REG_NON); + MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field)); + info[idx] = (struct field_modify_info){4, 0, + reg_to_field[reg]}; + if (mask) + mask[idx] = flow_modify_info_mask_32_masked + (width, data->offset, color_mask); + else + info[idx].offset = data->offset; + } + break; case RTE_FLOW_FIELD_POINTER: case RTE_FLOW_FIELD_VALUE: default: @@ -1913,7 +1939,9 @@ flow_dv_convert_action_modify_field item.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ? (void *)(uintptr_t)conf->src.pvalue : (void *)(uintptr_t)&conf->src.value; - if (conf->dst.field == RTE_FLOW_FIELD_META) { + if (conf->dst.field == RTE_FLOW_FIELD_META || + conf->dst.field == RTE_FLOW_FIELD_TAG || + conf->dst.field == RTE_FLOW_FIELD_METER_COLOR) { meta = *(const unaligned_uint32_t *)item.spec; meta = rte_cpu_to_be_32(meta); item.spec = &meta; @@ -3687,6 +3715,69 @@ flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev, return 0; } +/** + * Validate METER_COLOR item. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[in] item + * Item specification. + * @param[in] attr + * Attributes of flow that includes this item. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +flow_dv_validate_item_meter_color(struct rte_eth_dev *dev, + const struct rte_flow_item *item, + const struct rte_flow_attr *attr __rte_unused, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + const struct rte_flow_item_meter_color *spec = item->spec; + const struct rte_flow_item_meter_color *mask = item->mask; + struct rte_flow_item_meter_color nic_mask = { + .color = RTE_COLORS + }; + int ret; + + if (priv->mtr_color_reg == REG_NON) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, item, + "meter color register" + " isn't available"); + ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error); + if (ret < 0) + return ret; + if (!spec) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM_SPEC, + item->spec, + "data cannot be empty"); + if (spec->color > RTE_COLORS) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, + &spec->color, + "meter color is invalid"); + if (!mask) + mask = &rte_flow_item_meter_color_mask; + if (!mask->color) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL, + "mask cannot be zero"); + + ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask, + (const uint8_t *)&nic_mask, + sizeof(struct rte_flow_item_meter_color), + MLX5_ITEM_RANGE_NOT_ACCEPTED, error); + if (ret < 0) + return ret; + return 0; +} + int flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry, void *cb_ctx) @@ -6519,7 +6610,7 @@ flow_dv_mtr_container_resize(struct rte_eth_dev *dev) return -ENOMEM; } if (!pools_mng->n) - if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) { + if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER, 1)) { mlx5_free(pools); return -ENOMEM; } @@ -7421,6 +7512,13 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, if (ret < 0) return ret; break; + case RTE_FLOW_ITEM_TYPE_METER_COLOR: + ret = flow_dv_validate_item_meter_color(dev, items, + attr, error); + if (ret < 0) + return ret; + last_item = MLX5_FLOW_ITEM_METER_COLOR; + break; default: return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, @@ -10508,6 +10606,45 @@ flow_dv_translate_item_flex(struct rte_eth_dev *dev, void *matcher, void *key, mlx5_flex_flow_translate_item(dev, matcher, key, item, is_inner); } +/** + * Add METER_COLOR item to matcher + * + * @param[in] dev + * The device to configure through. + * @param[in, out] key + * Flow matcher value. + * @param[in] item + * Flow pattern to translate. + * @param[in] key_type + * Set flow matcher mask or value. + */ +static void +flow_dv_translate_item_meter_color(struct rte_eth_dev *dev, void *key, + const struct rte_flow_item *item, + uint32_t key_type) +{ + const struct rte_flow_item_meter_color *color_m = item->mask; + const struct rte_flow_item_meter_color *color_v = item->spec; + uint32_t value, mask; + int reg = REG_NON; + + MLX5_ASSERT(color_v); + if (MLX5_ITEM_VALID(item, key_type)) + return; + MLX5_ITEM_UPDATE(item, key_type, color_v, color_m, + &rte_flow_item_meter_color_mask); + value = rte_col_2_mlx5_col(color_v->color); + mask = color_m ? + color_m->color : (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1; + if (!!(key_type & MLX5_SET_MATCHER_SW)) + reg = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, NULL); + else + reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_METER_COLOR, 0); + if (reg == REG_NON) + return; + flow_dv_match_meta_reg(key, (enum modify_reg)reg, value, mask); +} + static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 }; #define HEADER_IS_ZERO(match_criteria, headers) \ @@ -13260,6 +13397,10 @@ flow_dv_translate_items(struct rte_eth_dev *dev, /* No other protocol should follow eCPRI layer. */ last_item = MLX5_FLOW_LAYER_ECPRI; break; + case RTE_FLOW_ITEM_TYPE_METER_COLOR: + flow_dv_translate_item_meter_color(dev, key, items, key_type); + last_item = MLX5_FLOW_ITEM_METER_COLOR; + break; default: break; } diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 71a134f224..d498d203d5 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -412,6 +412,10 @@ __flow_hw_action_template_destroy(struct rte_eth_dev *dev, mlx5_hws_cnt_shared_put(priv->hws_cpool, &acts->cnt_id); acts->cnt_id = 0; } + if (acts->mtr_id) { + mlx5_ipool_free(priv->hws_mpool->idx_pool, acts->mtr_id); + acts->mtr_id = 0; + } } /** @@ -628,6 +632,42 @@ __flow_hw_act_data_shared_cnt_append(struct mlx5_priv *priv, return 0; } +/** + * Append shared meter_mark action to the dynamic action list. + * + * @param[in] priv + * Pointer to the port private data structure. + * @param[in] acts + * Pointer to the template HW steering DR actions. + * @param[in] type + * Action type. + * @param[in] action_src + * Offset of source rte flow action. + * @param[in] action_dst + * Offset of destination DR action. + * @param[in] mtr_id + * Shared meter id. + * + * @return + * 0 on success, negative value otherwise and rte_errno is set. + */ +static __rte_always_inline int +__flow_hw_act_data_shared_mtr_append(struct mlx5_priv *priv, + struct mlx5_hw_actions *acts, + enum rte_flow_action_type type, + uint16_t action_src, + uint16_t action_dst, + cnt_id_t mtr_id) +{ struct mlx5_action_construct_data *act_data; + + act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst); + if (!act_data) + return -1; + act_data->type = type; + act_data->shared_meter.id = mtr_id; + LIST_INSERT_HEAD(&acts->act_list, act_data, next); + return 0; +} /** * Translate shared indirect action. @@ -682,6 +722,13 @@ flow_hw_shared_action_translate(struct rte_eth_dev *dev, idx, &acts->rule_acts[action_dst])) return -1; break; + case MLX5_INDIRECT_ACTION_TYPE_METER_MARK: + if (__flow_hw_act_data_shared_mtr_append(priv, acts, + (enum rte_flow_action_type) + MLX5_RTE_FLOW_ACTION_TYPE_METER_MARK, + action_src, action_dst, idx)) + return -1; + break; default: DRV_LOG(WARNING, "Unsupported shared action type:%d", type); break; @@ -888,6 +935,7 @@ flow_hw_modify_field_compile(struct rte_eth_dev *dev, (void *)(uintptr_t)&conf->src.value; if (conf->dst.field == RTE_FLOW_FIELD_META || conf->dst.field == RTE_FLOW_FIELD_TAG || + conf->dst.field == RTE_FLOW_FIELD_METER_COLOR || conf->dst.field == (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG) { value = *(const unaligned_uint32_t *)item.spec; value = rte_cpu_to_be_32(value); @@ -1047,7 +1095,7 @@ flow_hw_meter_compile(struct rte_eth_dev *dev, acts->rule_acts[jump_pos].action = (!!group) ? acts->jump->hws_action : acts->jump->root_action; - if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) + if (mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) return -ENOMEM; return 0; } @@ -1121,6 +1169,74 @@ static rte_be32_t vlan_hdr_to_be32(const struct rte_flow_action *actions) #endif } +static __rte_always_inline struct mlx5_aso_mtr * +flow_hw_meter_mark_alloc(struct rte_eth_dev *dev, + const struct rte_flow_action *action, + uint32_t queue) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; + const struct rte_flow_action_meter_mark *meter_mark = action->conf; + struct mlx5_aso_mtr *aso_mtr; + struct mlx5_flow_meter_info *fm; + uint32_t mtr_id; + + aso_mtr = mlx5_ipool_malloc(priv->hws_mpool->idx_pool, &mtr_id); + if (!aso_mtr) + return NULL; + /* Fill the flow meter parameters. */ + aso_mtr->type = ASO_METER_INDIRECT; + fm = &aso_mtr->fm; + fm->meter_id = mtr_id; + fm->profile = (struct mlx5_flow_meter_profile *)(meter_mark->profile); + fm->is_enable = meter_mark->state; + fm->color_aware = meter_mark->color_mode; + aso_mtr->pool = pool; + aso_mtr->state = ASO_METER_WAIT; + aso_mtr->offset = mtr_id - 1; + aso_mtr->init_color = (meter_mark->color_mode) ? + meter_mark->init_color : RTE_COLOR_GREEN; + /* Update ASO flow meter by wqe. */ + if (mlx5_aso_meter_update_by_wqe(priv->sh, queue, aso_mtr, + &priv->mtr_bulk)) { + mlx5_ipool_free(pool->idx_pool, mtr_id); + return NULL; + } + /* Wait for ASO object completion. */ + if (queue == MLX5_HW_INV_QUEUE && + mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) { + mlx5_ipool_free(pool->idx_pool, mtr_id); + return NULL; + } + return aso_mtr; +} + +static __rte_always_inline int +flow_hw_meter_mark_compile(struct rte_eth_dev *dev, + uint16_t aso_mtr_pos, + const struct rte_flow_action *action, + struct mlx5dr_rule_action *acts, + uint32_t *index, + uint32_t queue) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; + struct mlx5_aso_mtr *aso_mtr; + + aso_mtr = flow_hw_meter_mark_alloc(dev, action, queue); + if (!aso_mtr) + return -1; + + /* Compile METER_MARK action */ + acts[aso_mtr_pos].action = pool->action; + acts[aso_mtr_pos].aso_meter.offset = aso_mtr->offset; + acts[aso_mtr_pos].aso_meter.init_color = + (enum mlx5dr_action_aso_meter_color) + rte_col_2_mlx5_col(aso_mtr->init_color); + *index = aso_mtr->fm.meter_id; + return 0; +} + /** * Translate rte_flow actions to DR action. * @@ -1428,6 +1544,24 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev, goto err; } break; + case RTE_FLOW_ACTION_TYPE_METER_MARK: + action_pos = at->actions_off[actions - at->actions]; + if (actions->conf && masks->conf && + ((const struct rte_flow_action_meter_mark *) + masks->conf)->profile) { + err = flow_hw_meter_mark_compile(dev, + action_pos, actions, + acts->rule_acts, + &acts->mtr_id, + MLX5_HW_INV_QUEUE); + if (err) + goto err; + } else if (__flow_hw_act_data_general_append(priv, acts, + actions->type, + actions - action_start, + action_pos)) + goto err; + break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; break; @@ -1624,8 +1758,10 @@ flow_hw_shared_action_construct(struct rte_eth_dev *dev, uint32_t queue, struct mlx5dr_rule_action *rule_act) { struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; struct mlx5_action_construct_data act_data; struct mlx5_shared_action_rss *shared_rss; + struct mlx5_aso_mtr *aso_mtr; uint32_t act_idx = (uint32_t)(uintptr_t)action->conf; uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; uint32_t idx = act_idx & @@ -1661,6 +1797,17 @@ flow_hw_shared_action_construct(struct rte_eth_dev *dev, uint32_t queue, if (flow_hw_ct_compile(dev, queue, idx, rule_act)) return -1; break; + case MLX5_INDIRECT_ACTION_TYPE_METER_MARK: + /* Find ASO object. */ + aso_mtr = mlx5_ipool_get(pool->idx_pool, idx); + if (!aso_mtr) + return -1; + rule_act->action = pool->action; + rule_act->aso_meter.offset = aso_mtr->offset; + rule_act->aso_meter.init_color = + (enum mlx5dr_action_aso_meter_color) + rte_col_2_mlx5_col(aso_mtr->init_color); + break; default: DRV_LOG(WARNING, "Unsupported shared action type:%d", type); break; @@ -1730,6 +1877,7 @@ flow_hw_modify_field_construct(struct mlx5_hw_q_job *job, rte_memcpy(values, mhdr_action->src.pvalue, sizeof(values)); if (mhdr_action->dst.field == RTE_FLOW_FIELD_META || mhdr_action->dst.field == RTE_FLOW_FIELD_TAG || + mhdr_action->dst.field == RTE_FLOW_FIELD_METER_COLOR || mhdr_action->dst.field == (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG) { value_p = (unaligned_uint32_t *)values; *value_p = rte_cpu_to_be_32(*value_p); @@ -1807,6 +1955,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, uint32_t queue) { struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; struct rte_flow_template_table *table = job->flow->table; struct mlx5_action_construct_data *act_data; const struct rte_flow_actions_template *at = hw_at->action_template; @@ -1823,8 +1972,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, uint32_t ft_flag; size_t encap_len = 0; int ret; - struct mlx5_aso_mtr *mtr; - uint32_t mtr_id; + struct mlx5_aso_mtr *aso_mtr; rte_memcpy(rule_acts, hw_acts->rule_acts, sizeof(*rule_acts) * at->dr_actions_num); attr.group = table->grp->group_id; @@ -1858,6 +2006,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, struct mlx5_hrxq *hrxq; uint32_t ct_idx; cnt_id_t cnt_id; + uint32_t mtr_id; action = &actions[act_data->action_src]; /* @@ -1964,13 +2113,13 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_METER: meter = action->conf; mtr_id = meter->mtr_id; - mtr = mlx5_aso_meter_by_idx(priv, mtr_id); + aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_id); rule_acts[act_data->action_dst].action = priv->mtr_bulk.action; rule_acts[act_data->action_dst].aso_meter.offset = - mtr->offset; + aso_mtr->offset; jump = flow_hw_jump_action_register - (dev, &table->cfg, mtr->fm.group, NULL); + (dev, &table->cfg, aso_mtr->fm.group, NULL); if (!jump) return -1; MLX5_ASSERT @@ -1980,7 +2129,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, jump->root_action; job->flow->jump = jump; job->flow->fate_type = MLX5_FLOW_FATE_JUMP; - if (mlx5_aso_mtr_wait(priv->sh, mtr)) + if (mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) return -1; break; case RTE_FLOW_ACTION_TYPE_COUNT: @@ -2016,6 +2165,28 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, &rule_acts[act_data->action_dst])) return -1; break; + case MLX5_RTE_FLOW_ACTION_TYPE_METER_MARK: + mtr_id = act_data->shared_meter.id & + ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); + /* Find ASO object. */ + aso_mtr = mlx5_ipool_get(pool->idx_pool, mtr_id); + if (!aso_mtr) + return -1; + rule_acts[act_data->action_dst].action = + pool->action; + rule_acts[act_data->action_dst].aso_meter.offset = + aso_mtr->offset; + rule_acts[act_data->action_dst].aso_meter.init_color = + (enum mlx5dr_action_aso_meter_color) + rte_col_2_mlx5_col(aso_mtr->init_color); + break; + case RTE_FLOW_ACTION_TYPE_METER_MARK: + ret = flow_hw_meter_mark_compile(dev, + act_data->action_dst, action, + rule_acts, &job->flow->mtr_id, queue); + if (ret != 0) + return ret; + break; default: break; } @@ -2283,6 +2454,7 @@ flow_hw_pull(struct rte_eth_dev *dev, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; struct mlx5_hw_q_job *job; int ret, i; @@ -2307,6 +2479,10 @@ flow_hw_pull(struct rte_eth_dev *dev, &job->flow->cnt_id); job->flow->cnt_id = 0; } + if (job->flow->mtr_id) { + mlx5_ipool_free(pool->idx_pool, job->flow->mtr_id); + job->flow->mtr_id = 0; + } mlx5_ipool_free(job->flow->table->flow, job->flow->idx); } priv->hw_q[queue].job[priv->hw_q[queue].job_idx++] = job; @@ -3189,6 +3365,9 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_METER: /* TODO: Validation logic */ break; + case RTE_FLOW_ACTION_TYPE_METER_MARK: + /* TODO: Validation logic */ + break; case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: ret = flow_hw_validate_action_modify_field(action, mask, @@ -3282,6 +3461,11 @@ flow_hw_dr_actions_template_handle_shared(const struct rte_flow_action *mask, action_types[*curr_off] = MLX5DR_ACTION_TYP_ASO_CT; *curr_off = *curr_off + 1; break; + case RTE_FLOW_ACTION_TYPE_METER_MARK: + at->actions_off[action_src] = *curr_off; + action_types[*curr_off] = MLX5DR_ACTION_TYP_ASO_METER; + *curr_off = *curr_off + 1; + break; default: DRV_LOG(WARNING, "Unsupported shared action type: %d", type); return -EINVAL; @@ -3373,6 +3557,12 @@ flow_hw_dr_actions_template_create(struct rte_flow_actions_template *at) MLX5_HW_VLAN_PUSH_PCP_IDX : MLX5_HW_VLAN_PUSH_VID_IDX; break; + case RTE_FLOW_ACTION_TYPE_METER_MARK: + at->actions_off[i] = curr_off; + action_types[curr_off++] = MLX5DR_ACTION_TYP_ASO_METER; + if (curr_off >= MLX5_HW_MAX_ACTS) + goto err_actions_num; + break; default: type = mlx5_hw_dr_action_types[at->actions[i].type]; at->actions_off[i] = curr_off; @@ -3848,6 +4038,16 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, " attribute"); } break; + case RTE_FLOW_ITEM_TYPE_METER_COLOR: + { + int reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_METER_COLOR, 0); + if (reg == REG_NON) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Unsupported meter color register"); + break; + } case RTE_FLOW_ITEM_TYPE_VOID: case RTE_FLOW_ITEM_TYPE_ETH: case RTE_FLOW_ITEM_TYPE_VLAN: @@ -5363,7 +5563,8 @@ flow_hw_configure(struct rte_eth_dev *dev, if (mlx5_flow_meter_init(dev, port_attr->nb_meters, port_attr->nb_meter_profiles, - port_attr->nb_meter_policies)) + port_attr->nb_meter_policies, + nb_q_updated)) goto err; /* Add global actions. */ for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) { @@ -5867,7 +6068,9 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, { struct rte_flow_action_handle *handle = NULL; struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr *aso_mtr; cnt_id_t cnt_id; + uint32_t mtr_id; RTE_SET_USED(queue); RTE_SET_USED(attr); @@ -5886,6 +6089,14 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, case RTE_FLOW_ACTION_TYPE_CONNTRACK: handle = flow_hw_conntrack_create(dev, queue, action->conf, error); break; + case RTE_FLOW_ACTION_TYPE_METER_MARK: + aso_mtr = flow_hw_meter_mark_alloc(dev, action, queue); + if (!aso_mtr) + break; + mtr_id = (MLX5_INDIRECT_ACTION_TYPE_METER_MARK << + MLX5_INDIRECT_ACTION_TYPE_OFFSET) | (aso_mtr->fm.meter_id); + handle = (struct rte_flow_action_handle *)(uintptr_t)mtr_id; + break; default: handle = flow_dv_action_create(dev, conf, action, error); } @@ -5921,18 +6132,59 @@ flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue, void *user_data, struct rte_flow_error *error) { - uint32_t act_idx = (uint32_t)(uintptr_t)handle; - uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; - RTE_SET_USED(queue); RTE_SET_USED(attr); RTE_SET_USED(user_data); + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; + const struct rte_flow_update_meter_mark *upd_meter_mark = + (const struct rte_flow_update_meter_mark *)update; + const struct rte_flow_action_meter_mark *meter_mark; + struct mlx5_aso_mtr *aso_mtr; + struct mlx5_flow_meter_info *fm; + uint32_t act_idx = (uint32_t)(uintptr_t)handle; + uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; + uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); + switch (type) { case MLX5_INDIRECT_ACTION_TYPE_CT: return flow_hw_conntrack_update(dev, queue, update, act_idx, error); + case MLX5_INDIRECT_ACTION_TYPE_METER_MARK: + meter_mark = &upd_meter_mark->meter_mark; + /* Find ASO object. */ + aso_mtr = mlx5_ipool_get(pool->idx_pool, idx); + if (!aso_mtr) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Invalid meter_mark update index"); + fm = &aso_mtr->fm; + if (upd_meter_mark->profile_valid) + fm->profile = (struct mlx5_flow_meter_profile *) + (meter_mark->profile); + if (upd_meter_mark->color_mode_valid) + fm->color_aware = meter_mark->color_mode; + if (upd_meter_mark->init_color_valid) + aso_mtr->init_color = (meter_mark->color_mode) ? + meter_mark->init_color : RTE_COLOR_GREEN; + if (upd_meter_mark->state_valid) + fm->is_enable = meter_mark->state; + /* Update ASO flow meter by wqe. */ + if (mlx5_aso_meter_update_by_wqe(priv->sh, queue, + aso_mtr, &priv->mtr_bulk)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Unable to update ASO meter WQE"); + /* Wait for ASO object completion. */ + if (queue == MLX5_HW_INV_QUEUE && + mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Unable to wait for ASO meter CQE"); + return 0; default: - return flow_dv_action_update(dev, handle, update, error); + break; } + return flow_dv_action_update(dev, handle, update, error); } /** @@ -5963,7 +6215,11 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, { uint32_t act_idx = (uint32_t)(uintptr_t)handle; uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; + uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; + struct mlx5_aso_mtr *aso_mtr; + struct mlx5_flow_meter_info *fm; RTE_SET_USED(queue); RTE_SET_USED(attr); @@ -5973,6 +6229,28 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, return mlx5_hws_cnt_shared_put(priv->hws_cpool, &act_idx); case MLX5_INDIRECT_ACTION_TYPE_CT: return flow_hw_conntrack_destroy(dev, act_idx, error); + case MLX5_INDIRECT_ACTION_TYPE_METER_MARK: + aso_mtr = mlx5_ipool_get(pool->idx_pool, idx); + if (!aso_mtr) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Invalid meter_mark destroy index"); + fm = &aso_mtr->fm; + fm->is_enable = 0; + /* Update ASO flow meter by wqe. */ + if (mlx5_aso_meter_update_by_wqe(priv->sh, queue, aso_mtr, + &priv->mtr_bulk)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Unable to update ASO meter WQE"); + /* Wait for ASO object completion. */ + if (queue == MLX5_HW_INV_QUEUE && + mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Unable to wait for ASO meter CQE"); + mlx5_ipool_free(pool->idx_pool, idx); + return 0; default: return flow_dv_action_destroy(dev, handle, error); } @@ -6056,8 +6334,8 @@ flow_hw_action_create(struct rte_eth_dev *dev, const struct rte_flow_action *action, struct rte_flow_error *err) { - return flow_hw_action_handle_create(dev, UINT32_MAX, NULL, conf, action, - NULL, err); + return flow_hw_action_handle_create(dev, MLX5_HW_INV_QUEUE, + NULL, conf, action, NULL, err); } /** @@ -6082,8 +6360,8 @@ flow_hw_action_destroy(struct rte_eth_dev *dev, struct rte_flow_action_handle *handle, struct rte_flow_error *error) { - return flow_hw_action_handle_destroy(dev, UINT32_MAX, NULL, handle, - NULL, error); + return flow_hw_action_handle_destroy(dev, MLX5_HW_INV_QUEUE, + NULL, handle, NULL, error); } /** @@ -6111,8 +6389,8 @@ flow_hw_action_update(struct rte_eth_dev *dev, const void *update, struct rte_flow_error *err) { - return flow_hw_action_handle_update(dev, UINT32_MAX, NULL, handle, - update, NULL, err); + return flow_hw_action_handle_update(dev, MLX5_HW_INV_QUEUE, + NULL, handle, update, NULL, err); } static int @@ -6642,6 +6920,12 @@ mlx5_flow_meter_uninit(struct rte_eth_dev *dev) mlx5_free(priv->mtr_profile_arr); priv->mtr_profile_arr = NULL; } + if (priv->hws_mpool) { + mlx5_aso_mtr_queue_uninit(priv->sh, priv->hws_mpool, NULL); + mlx5_ipool_destroy(priv->hws_mpool->idx_pool); + mlx5_free(priv->hws_mpool); + priv->hws_mpool = NULL; + } if (priv->mtr_bulk.aso) { mlx5_free(priv->mtr_bulk.aso); priv->mtr_bulk.aso = NULL; @@ -6662,7 +6946,8 @@ int mlx5_flow_meter_init(struct rte_eth_dev *dev, uint32_t nb_meters, uint32_t nb_meter_profiles, - uint32_t nb_meter_policies) + uint32_t nb_meter_policies, + uint32_t nb_queues) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_devx_obj *dcs = NULL; @@ -6672,29 +6957,35 @@ mlx5_flow_meter_init(struct rte_eth_dev *dev, struct mlx5_aso_mtr *aso; uint32_t i; struct rte_flow_error error; + uint32_t flags; + uint32_t nb_mtrs = rte_align32pow2(nb_meters); + struct mlx5_indexed_pool_config cfg = { + .size = sizeof(struct mlx5_aso_mtr), + .trunk_size = 1 << 12, + .per_core_cache = 1 << 13, + .need_lock = 1, + .release_mem_en = !!priv->sh->config.reclaim_mode, + .malloc = mlx5_malloc, + .max_idx = nb_meters, + .free = mlx5_free, + .type = "mlx5_hw_mtr_mark_action", + }; if (!nb_meters || !nb_meter_profiles || !nb_meter_policies) { ret = ENOTSUP; rte_flow_error_set(&error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "Meter configuration is invalid."); + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter configuration is invalid."); goto err; } if (!priv->mtr_en || !priv->sh->meter_aso_en) { ret = ENOTSUP; rte_flow_error_set(&error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "Meter ASO is not supported."); + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter ASO is not supported."); goto err; } priv->mtr_config.nb_meters = nb_meters; - if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) { - ret = ENOMEM; - rte_flow_error_set(&error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "Meter ASO queue allocation failed."); - goto err; - } log_obj_size = rte_log2_u32(nb_meters >> 1); dcs = mlx5_devx_cmd_create_flow_meter_aso_obj (priv->sh->cdev->ctx, priv->sh->cdev->pdn, @@ -6702,8 +6993,8 @@ mlx5_flow_meter_init(struct rte_eth_dev *dev, if (!dcs) { ret = ENOMEM; rte_flow_error_set(&error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "Meter ASO object allocation failed."); + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter ASO object allocation failed."); goto err; } priv->mtr_bulk.devx_obj = dcs; @@ -6711,31 +7002,33 @@ mlx5_flow_meter_init(struct rte_eth_dev *dev, if (reg_id < 0) { ret = ENOTSUP; rte_flow_error_set(&error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "Meter register is not available."); + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter register is not available."); goto err; } + flags = MLX5DR_ACTION_FLAG_HWS_RX | MLX5DR_ACTION_FLAG_HWS_TX; + if (priv->sh->config.dv_esw_en && priv->master) + flags |= MLX5DR_ACTION_FLAG_HWS_FDB; priv->mtr_bulk.action = mlx5dr_action_create_aso_meter (priv->dr_ctx, (struct mlx5dr_devx_obj *)dcs, - reg_id - REG_C_0, MLX5DR_ACTION_FLAG_HWS_RX | - MLX5DR_ACTION_FLAG_HWS_TX | - MLX5DR_ACTION_FLAG_HWS_FDB); + reg_id - REG_C_0, flags); if (!priv->mtr_bulk.action) { ret = ENOMEM; rte_flow_error_set(&error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "Meter action creation failed."); + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter action creation failed."); goto err; } priv->mtr_bulk.aso = mlx5_malloc(MLX5_MEM_ZERO, - sizeof(struct mlx5_aso_mtr) * nb_meters, - RTE_CACHE_LINE_SIZE, - SOCKET_ID_ANY); + sizeof(struct mlx5_aso_mtr) * + nb_meters, + RTE_CACHE_LINE_SIZE, + SOCKET_ID_ANY); if (!priv->mtr_bulk.aso) { ret = ENOMEM; rte_flow_error_set(&error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "Meter bulk ASO allocation failed."); + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter bulk ASO allocation failed."); goto err; } priv->mtr_bulk.size = nb_meters; @@ -6746,32 +7039,65 @@ mlx5_flow_meter_init(struct rte_eth_dev *dev, aso->offset = i; aso++; } + priv->hws_mpool = mlx5_malloc(MLX5_MEM_ZERO, + sizeof(struct mlx5_aso_mtr_pool), + RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); + if (!priv->hws_mpool) { + ret = ENOMEM; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter ipool allocation failed."); + goto err; + } + priv->hws_mpool->devx_obj = priv->mtr_bulk.devx_obj; + priv->hws_mpool->action = priv->mtr_bulk.action; + priv->hws_mpool->nb_sq = nb_queues; + if (mlx5_aso_mtr_queue_init(priv->sh, priv->hws_mpool, + NULL, nb_queues)) { + ret = ENOMEM; + rte_flow_error_set(&error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter ASO queue allocation failed."); + goto err; + } + /* + * No need for local cache if Meter number is a small number. + * Since flow insertion rate will be very limited in that case. + * Here let's set the number to less than default trunk size 4K. + */ + if (nb_mtrs <= cfg.trunk_size) { + cfg.per_core_cache = 0; + cfg.trunk_size = nb_mtrs; + } else if (nb_mtrs <= MLX5_HW_IPOOL_SIZE_THRESHOLD) { + cfg.per_core_cache = MLX5_HW_IPOOL_CACHE_MIN; + } + priv->hws_mpool->idx_pool = mlx5_ipool_create(&cfg); priv->mtr_config.nb_meter_profiles = nb_meter_profiles; priv->mtr_profile_arr = mlx5_malloc(MLX5_MEM_ZERO, - sizeof(struct mlx5_flow_meter_profile) * - nb_meter_profiles, - RTE_CACHE_LINE_SIZE, - SOCKET_ID_ANY); + sizeof(struct mlx5_flow_meter_profile) * + nb_meter_profiles, + RTE_CACHE_LINE_SIZE, + SOCKET_ID_ANY); if (!priv->mtr_profile_arr) { ret = ENOMEM; rte_flow_error_set(&error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "Meter profile allocation failed."); + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter profile allocation failed."); goto err; } priv->mtr_config.nb_meter_policies = nb_meter_policies; priv->mtr_policy_arr = mlx5_malloc(MLX5_MEM_ZERO, - sizeof(struct mlx5_flow_meter_policy) * - nb_meter_policies, - RTE_CACHE_LINE_SIZE, - SOCKET_ID_ANY); + sizeof(struct mlx5_flow_meter_policy) * + nb_meter_policies, + RTE_CACHE_LINE_SIZE, + SOCKET_ID_ANY); if (!priv->mtr_policy_arr) { ret = ENOMEM; rte_flow_error_set(&error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "Meter policy allocation failed."); + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "Meter policy allocation failed."); goto err; } return 0; diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c index 792b945c98..fd1337ae73 100644 --- a/drivers/net/mlx5/mlx5_flow_meter.c +++ b/drivers/net/mlx5/mlx5_flow_meter.c @@ -588,6 +588,36 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev, return 0; } +/** + * Callback to get MTR profile. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] meter_profile_id + * Meter profile id. + * @param[out] error + * Pointer to the error structure. + * + * @return + * A valid handle in case of success, NULL otherwise. + */ +static struct rte_flow_meter_profile * +mlx5_flow_meter_profile_get(struct rte_eth_dev *dev, + uint32_t meter_profile_id, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + if (!priv->mtr_en) { + rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, + "Meter is not supported"); + return NULL; + } + return (void *)(uintptr_t)mlx5_flow_meter_profile_find(priv, + meter_profile_id); +} + /** * Callback to add MTR profile with HWS. * @@ -1150,6 +1180,37 @@ mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev, return 0; } +/** + * Callback to get MTR policy. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] policy_id + * Meter policy id. + * @param[out] error + * Pointer to the error structure. + * + * @return + * A valid handle in case of success, NULL otherwise. + */ +static struct rte_flow_meter_policy * +mlx5_flow_meter_policy_get(struct rte_eth_dev *dev, + uint32_t policy_id, + struct rte_mtr_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + uint32_t policy_idx; + + if (!priv->mtr_en) { + rte_mtr_error_set(error, ENOTSUP, + RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL, + "Meter is not supported"); + return NULL; + } + return (void *)(uintptr_t)mlx5_flow_meter_policy_find(dev, policy_id, + &policy_idx); +} + /** * Callback to delete MTR policy for HWS. * @@ -1565,11 +1626,11 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv, if (priv->sh->meter_aso_en) { fm->is_enable = !!is_enable; aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); - ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr, - &priv->mtr_bulk); + ret = mlx5_aso_meter_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, + aso_mtr, &priv->mtr_bulk); if (ret) return ret; - ret = mlx5_aso_mtr_wait(priv->sh, aso_mtr); + ret = mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr); if (ret) return ret; } else { @@ -1815,8 +1876,8 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id, /* If ASO meter supported, update ASO flow meter by wqe. */ if (priv->sh->meter_aso_en) { aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); - ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr, - &priv->mtr_bulk); + ret = mlx5_aso_meter_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, + aso_mtr, &priv->mtr_bulk); if (ret) goto error; if (!priv->mtr_idx_tbl) { @@ -1921,7 +1982,7 @@ mlx5_flow_meter_hws_create(struct rte_eth_dev *dev, uint32_t meter_id, fm->shared = !!shared; fm->initialized = 1; /* Update ASO flow meter by wqe. */ - ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr, + ret = mlx5_aso_meter_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr, &priv->mtr_bulk); if (ret) return -rte_mtr_error_set(error, ENOTSUP, @@ -2401,9 +2462,11 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = { .capabilities_get = mlx5_flow_mtr_cap_get, .meter_profile_add = mlx5_flow_meter_profile_add, .meter_profile_delete = mlx5_flow_meter_profile_delete, + .meter_profile_get = mlx5_flow_meter_profile_get, .meter_policy_validate = mlx5_flow_meter_policy_validate, .meter_policy_add = mlx5_flow_meter_policy_add, .meter_policy_delete = mlx5_flow_meter_policy_delete, + .meter_policy_get = mlx5_flow_meter_policy_get, .create = mlx5_flow_meter_create, .destroy = mlx5_flow_meter_destroy, .meter_enable = mlx5_flow_meter_enable, @@ -2418,9 +2481,11 @@ static const struct rte_mtr_ops mlx5_flow_mtr_hws_ops = { .capabilities_get = mlx5_flow_mtr_cap_get, .meter_profile_add = mlx5_flow_meter_profile_hws_add, .meter_profile_delete = mlx5_flow_meter_profile_hws_delete, + .meter_profile_get = mlx5_flow_meter_profile_get, .meter_policy_validate = mlx5_flow_meter_policy_hws_validate, .meter_policy_add = mlx5_flow_meter_policy_hws_add, .meter_policy_delete = mlx5_flow_meter_policy_hws_delete, + .meter_policy_get = mlx5_flow_meter_policy_get, .create = mlx5_flow_meter_hws_create, .destroy = mlx5_flow_meter_hws_destroy, .meter_enable = mlx5_flow_meter_enable, @@ -2566,7 +2631,7 @@ mlx5_flow_meter_attach(struct mlx5_priv *priv, struct mlx5_aso_mtr *aso_mtr; aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); - if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) { + if (mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) { return rte_flow_error_set(error, ENOENT, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, From patchwork Fri Sep 30 12:53:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117223 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2AD62A00C4; Fri, 30 Sep 2022 14:55:35 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id D851642905; Fri, 30 Sep 2022 14:54:18 +0200 (CEST) Received: from NAM04-BN8-obe.outbound.protection.outlook.com (mail-bn8nam04on2052.outbound.protection.outlook.com [40.107.100.52]) by mails.dpdk.org (Postfix) with ESMTP id CDBF142B9D for ; Fri, 30 Sep 2022 14:54:12 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=CFJBj5TRerxnL2y8DlAT1aCtn43/iVSaY+nrLeZ0YS3cmUeyN/C61+eUjqn/kzuOi7Nqi47X3dXXmZeGe26MWfQpKxlRdG3dm+yg8nMnyYETnYHpmYaf18lLJlr0dzZoGP8ryUoykbLOXK4KyI7HHoVNAWBwNIXpdgsV8kOzGnbVmURJUQtJm24b2tEdHeNP4OcoooXRyJg46g0sBwOeXNalbaSIOJCodpcOA6fzREiJobk2O8SroP8VTpeIMKL9dfy2Tsky+hBuEElBo/G1GNezhYfepydPKvMeeme8yujTGF9xHcVqScFBBq/+ZNOsZ1NbQCRg2tYsjiaFDwAQlw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=PorFlQcGZJ4Ghi2Mp66h1nncQTaQPkvJTUl1sipwHDw=; b=OsbSsYjE/fWUtSYS56FN8DrxwwhDkqCA4Ij2qYze3eNFs+JnhqXhQ54XCJ/2RgWVLev+GD6HjJ3Qr6HFaQoDV730rHXH3NvwTZ9Dk7JVdOOcNSv0hFrArD/SHnvMceAlO+/bXh2LMTs384zOgiTtXPHLtqECMTtF7+B0utuOwnzyR4qYSZtrPFqqNDS3kXAIOllmb8bJqhpoZOQIr639pnNr2SHMkfEO3w+W5BUOJp8Vq2KcGe2/D6UPB1uAGmN4vmk7qPzKGdY0DdkLSb4OYAwrVXxrl4uLK0YTM+me6cuvSkZ9axxotpa9nextZngD4JgwRrfz7Dp7Bm1rOwaPpA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.161) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=PorFlQcGZJ4Ghi2Mp66h1nncQTaQPkvJTUl1sipwHDw=; b=YUEpKR1nBWfCQTP1585/387rKw4ZXpkC2K7BkePKRreN6cN4Sr/PC9Se7wUsxZcpW1RK0RJeDKJ+ydXnntuc4QmhKpNkKMlmPg+kQiusk4dnvQFU7KvDpGLmLsUj4NxQMmntddHTRKPXrZ6aUZJgt3GWUVTUqO8B/qfex2L81VY0RighhrQ+09V3lTmzNu7hbvpAeM7RZ2A78sRRxNCgwVEiTXh4IyRB/gW6yl+/tSFP6t5WoO0kqeMv/wkJm1iQOEaE4/EiCLYy0NmsN7tj7aWP/13s0PB9cG/PQy+vAZCZyM9S4A7HenTFpmfI1eEzXKgxH4shJVcE8da43uk40A== Received: from DM6PR06CA0011.namprd06.prod.outlook.com (2603:10b6:5:120::24) by PH7PR12MB6788.namprd12.prod.outlook.com (2603:10b6:510:1ae::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.15; Fri, 30 Sep 2022 12:54:09 +0000 Received: from DM6NAM11FT008.eop-nam11.prod.protection.outlook.com (2603:10b6:5:120:cafe::9) by DM6PR06CA0011.outlook.office365.com (2603:10b6:5:120::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:09 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.161) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.161 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.161; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.161) by DM6NAM11FT008.mail.protection.outlook.com (10.13.172.85) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:09 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.67) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:54:04 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:54:01 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , Michael Baum Subject: [PATCH v3 13/17] net/mlx5: add HWS AGE action support Date: Fri, 30 Sep 2022 15:53:11 +0300 Message-ID: <20220930125315.5079-14-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT008:EE_|PH7PR12MB6788:EE_ X-MS-Office365-Filtering-Correlation-Id: e64cda6c-6da0-4a07-0763-08daa2e2ddad X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: EP5zI3K//+Cw1PU+cc6XN44ColnePkbuSA/z1157Ipxwgv0RYAkIyNeCUazVaaBdhHJ5dSODJxuxhnO777X12OAaAM/7gj4PRpy/SpEQ/DGTyq5MzNr4JrkP6soB8uoqbEVbZxODMsqD2n7trfjSxxP3KRcRINA9ghtEEQaOP6BHq/U+CpLUOyuGbHW2rzQ1/bYkB8gQ4R1Hb90WzxtCUGoKiWlziS5pn2FnjziI45DHzb4AgimH/9csLCXy5fdhmVVcWNFYAzCMJoBBRtQ9rFfaMaYNpqgXxri/Taz21fGci4a6Sh2VDA4pGHx+sQ85sv1kXJNsY6jqbO0HsJML+R4meLzLQju/sCuC+lphkeptWU/GUuMGmezkEE/YnRqwHmkoRBjoi1vSDLkl83Wz3icOb+WBFtpEBW3Q8/BbW+/iP8m31NkvfXLpd6itjXZEl3dIs/1ZrUzOA+TYPI4ULj3t81VBUwfUv1j4t9dfSOj4behZXSjeRG7+api5T1XPln0GGauXLn8WSqn5L2yFaNk6qFWSDEI/weqyu2uZQKKrICFIZtdscr0/tPCfmBYqnn/Vl0Nr08Wd/0t2kp9S909lvqkW2jLon7gwOZIo3Qp5aQixczLjowcF3HnesFAx+kdyv+K8KL6ML9fi8rP53NIKcHPGPrfsfdfiFVweOFgsGUDcut131lo5gA+MzDzEcRfk5pLu4NRbrYk4DdkoxTHrp4mdJ96yWdiQGv+odyCwAxuQwizV1TmecN9dGtzoG+fVPucekd0v0zhxiP9s2XJQwzX7tTHBX5QTkwAxSpA= X-Forefront-Antispam-Report: CIP:216.228.117.161; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge2.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(376002)(346002)(39860400002)(396003)(136003)(451199015)(46966006)(40470700004)(36840700001)(107886003)(16526019)(26005)(6286002)(2616005)(186003)(1076003)(30864003)(2906002)(336012)(8936002)(5660300002)(426003)(83380400001)(70586007)(70206006)(110136005)(36860700001)(82310400005)(7696005)(47076005)(7636003)(6666004)(36756003)(40480700001)(82740400003)(356005)(40460700003)(41300700001)(4326008)(8676002)(54906003)(478600001)(6636002)(86362001)(316002)(55016003)(579004)(559001)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:54:09.0040 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: e64cda6c-6da0-4a07-0763-08daa2e2ddad X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.161]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT008.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH7PR12MB6788 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Michael Baum Add support for AGE action for HW steering. This patch includes: 1. Add new structures to manage the aging. 2. Initialize all them in configure function. 3. Implement per second aging check using CNT background thread. 4. Enable AGE action in flow create/destroy operations. 5. Implement queue-based function to report aged flow rules. Signed-off-by: Michael Baum --- drivers/net/mlx5/mlx5.c | 67 +- drivers/net/mlx5/mlx5.h | 51 +- drivers/net/mlx5/mlx5_defs.h | 3 + drivers/net/mlx5/mlx5_flow.c | 89 ++- drivers/net/mlx5/mlx5_flow.h | 33 +- drivers/net/mlx5/mlx5_flow_dv.c | 30 +- drivers/net/mlx5/mlx5_flow_hw.c | 1104 ++++++++++++++++++++++++---- drivers/net/mlx5/mlx5_flow_verbs.c | 4 +- drivers/net/mlx5/mlx5_hws_cnt.c | 704 +++++++++++++++++- drivers/net/mlx5/mlx5_hws_cnt.h | 193 ++++- 10 files changed, 2013 insertions(+), 265 deletions(-) diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 383a789dfa..742607509b 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -497,6 +497,12 @@ mlx5_flow_aging_init(struct mlx5_dev_ctx_shared *sh) uint32_t i; struct mlx5_age_info *age_info; + /* + * In HW steering, aging information structure is initialized later + * during configure function. + */ + if (sh->config.dv_flow_en == 2) + return; for (i = 0; i < sh->max_port; i++) { age_info = &sh->port[i].age_info; age_info->flags = 0; @@ -540,8 +546,8 @@ mlx5_flow_counter_mode_config(struct rte_eth_dev *dev __rte_unused) hca_attr->flow_counter_bulk_alloc_bitmap); /* Initialize fallback mode only on the port initializes sh. */ if (sh->refcnt == 1) - sh->cmng.counter_fallback = fallback; - else if (fallback != sh->cmng.counter_fallback) + sh->sws_cmng.counter_fallback = fallback; + else if (fallback != sh->sws_cmng.counter_fallback) DRV_LOG(WARNING, "Port %d in sh has different fallback mode " "with others:%d.", PORT_ID(priv), fallback); #endif @@ -556,17 +562,38 @@ mlx5_flow_counter_mode_config(struct rte_eth_dev *dev __rte_unused) static void mlx5_flow_counters_mng_init(struct mlx5_dev_ctx_shared *sh) { - int i; + int i, j; + + if (sh->config.dv_flow_en < 2) { + memset(&sh->sws_cmng, 0, sizeof(sh->sws_cmng)); + TAILQ_INIT(&sh->sws_cmng.flow_counters); + sh->sws_cmng.min_id = MLX5_CNT_BATCH_OFFSET; + sh->sws_cmng.max_id = -1; + sh->sws_cmng.last_pool_idx = POOL_IDX_INVALID; + rte_spinlock_init(&sh->sws_cmng.pool_update_sl); + for (i = 0; i < MLX5_COUNTER_TYPE_MAX; i++) { + TAILQ_INIT(&sh->sws_cmng.counters[i]); + rte_spinlock_init(&sh->sws_cmng.csl[i]); + } + } else { + struct mlx5_hca_attr *attr = &sh->cdev->config.hca_attr; + uint32_t fw_max_nb_cnts = attr->max_flow_counter; + uint8_t log_dcs = log2above(fw_max_nb_cnts) - 1; + uint32_t max_nb_cnts = 0; + + for (i = 0, j = 0; j < MLX5_HWS_CNT_DCS_NUM; ++i) { + int log_dcs_i = log_dcs - i; - memset(&sh->cmng, 0, sizeof(sh->cmng)); - TAILQ_INIT(&sh->cmng.flow_counters); - sh->cmng.min_id = MLX5_CNT_BATCH_OFFSET; - sh->cmng.max_id = -1; - sh->cmng.last_pool_idx = POOL_IDX_INVALID; - rte_spinlock_init(&sh->cmng.pool_update_sl); - for (i = 0; i < MLX5_COUNTER_TYPE_MAX; i++) { - TAILQ_INIT(&sh->cmng.counters[i]); - rte_spinlock_init(&sh->cmng.csl[i]); + if (log_dcs_i < 0) + break; + if ((max_nb_cnts | RTE_BIT32(log_dcs_i)) > + fw_max_nb_cnts) + continue; + max_nb_cnts |= RTE_BIT32(log_dcs_i); + j++; + } + sh->hws_max_log_bulk_sz = log_dcs; + sh->hws_max_nb_counters = max_nb_cnts; } } @@ -607,13 +634,13 @@ mlx5_flow_counters_mng_close(struct mlx5_dev_ctx_shared *sh) rte_pause(); } - if (sh->cmng.pools) { + if (sh->sws_cmng.pools) { struct mlx5_flow_counter_pool *pool; - uint16_t n_valid = sh->cmng.n_valid; - bool fallback = sh->cmng.counter_fallback; + uint16_t n_valid = sh->sws_cmng.n_valid; + bool fallback = sh->sws_cmng.counter_fallback; for (i = 0; i < n_valid; ++i) { - pool = sh->cmng.pools[i]; + pool = sh->sws_cmng.pools[i]; if (!fallback && pool->min_dcs) claim_zero(mlx5_devx_cmd_destroy (pool->min_dcs)); @@ -632,14 +659,14 @@ mlx5_flow_counters_mng_close(struct mlx5_dev_ctx_shared *sh) } mlx5_free(pool); } - mlx5_free(sh->cmng.pools); + mlx5_free(sh->sws_cmng.pools); } - mng = LIST_FIRST(&sh->cmng.mem_mngs); + mng = LIST_FIRST(&sh->sws_cmng.mem_mngs); while (mng) { mlx5_flow_destroy_counter_stat_mem_mng(mng); - mng = LIST_FIRST(&sh->cmng.mem_mngs); + mng = LIST_FIRST(&sh->sws_cmng.mem_mngs); } - memset(&sh->cmng, 0, sizeof(sh->cmng)); + memset(&sh->sws_cmng, 0, sizeof(sh->sws_cmng)); } /** diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 89dc8441dc..c83157d0da 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -639,12 +639,45 @@ struct mlx5_geneve_tlv_option_resource { /* Current time in seconds. */ #define MLX5_CURR_TIME_SEC (rte_rdtsc() / rte_get_tsc_hz()) +/* + * HW steering queue oriented AGE info. + * It contains an array of rings, one for each HWS queue. + */ +struct mlx5_hws_q_age_info { + uint16_t nb_rings; /* Number of aged-out ring lists. */ + struct rte_ring *aged_lists[]; /* Aged-out lists. */ +}; + +/* + * HW steering AGE info. + * It has a ring list containing all aged out flow rules. + */ +struct mlx5_hws_age_info { + struct rte_ring *aged_list; /* Aged out lists. */ +}; + /* Aging information for per port. */ struct mlx5_age_info { uint8_t flags; /* Indicate if is new event or need to be triggered. */ - struct mlx5_counters aged_counters; /* Aged counter list. */ - struct aso_age_list aged_aso; /* Aged ASO actions list. */ - rte_spinlock_t aged_sl; /* Aged flow list lock. */ + union { + /* SW/FW steering AGE info. */ + struct { + struct mlx5_counters aged_counters; + /* Aged counter list. */ + struct aso_age_list aged_aso; + /* Aged ASO actions list. */ + rte_spinlock_t aged_sl; /* Aged flow list lock. */ + }; + struct { + struct mlx5_indexed_pool *ages_ipool; + union { + struct mlx5_hws_age_info hw_age; + /* HW steering AGE info. */ + struct mlx5_hws_q_age_info *hw_q_age; + /* HW steering queue oriented AGE info. */ + }; + }; + }; }; /* Per port data of shared IB device. */ @@ -1302,6 +1335,9 @@ struct mlx5_dev_ctx_shared { uint32_t hws_tags:1; /* Check if tags info for HWS initialized. */ uint32_t shared_mark_enabled:1; /* If mark action is enabled on Rxqs (shared E-Switch domain). */ + uint32_t hws_max_log_bulk_sz:5; + /* Log of minimal HWS counters created hard coded. */ + uint32_t hws_max_nb_counters; /* Maximal number for HWS counters. */ uint32_t max_port; /* Maximal IB device port index. */ struct mlx5_bond_info bond; /* Bonding information. */ struct mlx5_common_device *cdev; /* Backend mlx5 device. */ @@ -1342,7 +1378,8 @@ struct mlx5_dev_ctx_shared { struct mlx5_list *dest_array_list; struct mlx5_list *flex_parsers_dv; /* Flex Item parsers. */ /* List of destination array actions. */ - struct mlx5_flow_counter_mng cmng; /* Counters management structure. */ + struct mlx5_flow_counter_mng sws_cmng; + /* SW steering counters management structure. */ void *default_miss_action; /* Default miss action. */ struct mlx5_indexed_pool *ipool[MLX5_IPOOL_MAX]; struct mlx5_indexed_pool *mdh_ipools[MLX5_MAX_MODIFY_NUM]; @@ -1670,6 +1707,9 @@ struct mlx5_priv { LIST_HEAD(flow_hw_at, rte_flow_actions_template) flow_hw_at; struct mlx5dr_context *dr_ctx; /**< HW steering DR context. */ /* HW steering queue polling mechanism job descriptor LIFO. */ + uint32_t hws_strict_queue:1; + /**< Whether all operations strictly happen on the same HWS queue. */ + uint32_t hws_age_req:1; /**< Whether this port has AGE indexed pool. */ struct mlx5_hw_q *hw_q; /* HW steering rte flow table list header. */ LIST_HEAD(flow_hw_tbl, rte_flow_template_table) flow_hw_tbl; @@ -1985,6 +2025,9 @@ int mlx5_validate_action_ct(struct rte_eth_dev *dev, const struct rte_flow_action_conntrack *conntrack, struct rte_flow_error *error); +int mlx5_flow_get_q_aged_flows(struct rte_eth_dev *dev, uint32_t queue_id, + void **contexts, uint32_t nb_contexts, + struct rte_flow_error *error); /* mlx5_mp_os.c */ diff --git a/drivers/net/mlx5/mlx5_defs.h b/drivers/net/mlx5/mlx5_defs.h index d064abfef3..2af8c731ef 100644 --- a/drivers/net/mlx5/mlx5_defs.h +++ b/drivers/net/mlx5/mlx5_defs.h @@ -43,6 +43,9 @@ #define MLX5_PMD_SOFT_COUNTERS 1 #endif +/* Maximum number of DCS created per port. */ +#define MLX5_HWS_CNT_DCS_NUM 4 + /* Alarm timeout. */ #define MLX5_ALARM_TIMEOUT_US 100000 diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 9627ffc979..4bfa604578 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -987,6 +987,7 @@ static const struct rte_flow_ops mlx5_flow_ops = { .isolate = mlx5_flow_isolate, .query = mlx5_flow_query, .dev_dump = mlx5_flow_dev_dump, + .get_q_aged_flows = mlx5_flow_get_q_aged_flows, .get_aged_flows = mlx5_flow_get_aged_flows, .action_handle_create = mlx5_action_handle_create, .action_handle_destroy = mlx5_action_handle_destroy, @@ -8942,11 +8943,11 @@ mlx5_flow_create_counter_stat_mem_mng(struct mlx5_dev_ctx_shared *sh) mem_mng->raws[i].data = raw_data + i * MLX5_COUNTERS_PER_POOL; } for (i = 0; i < MLX5_MAX_PENDING_QUERIES; ++i) - LIST_INSERT_HEAD(&sh->cmng.free_stat_raws, + LIST_INSERT_HEAD(&sh->sws_cmng.free_stat_raws, mem_mng->raws + MLX5_CNT_CONTAINER_RESIZE + i, next); - LIST_INSERT_HEAD(&sh->cmng.mem_mngs, mem_mng, next); - sh->cmng.mem_mng = mem_mng; + LIST_INSERT_HEAD(&sh->sws_cmng.mem_mngs, mem_mng, next); + sh->sws_cmng.mem_mng = mem_mng; return 0; } @@ -8965,7 +8966,7 @@ static int mlx5_flow_set_counter_stat_mem(struct mlx5_dev_ctx_shared *sh, struct mlx5_flow_counter_pool *pool) { - struct mlx5_flow_counter_mng *cmng = &sh->cmng; + struct mlx5_flow_counter_mng *cmng = &sh->sws_cmng; /* Resize statistic memory once used out. */ if (!(pool->index % MLX5_CNT_CONTAINER_RESIZE) && mlx5_flow_create_counter_stat_mem_mng(sh)) { @@ -8994,14 +8995,14 @@ mlx5_set_query_alarm(struct mlx5_dev_ctx_shared *sh) { uint32_t pools_n, us; - pools_n = __atomic_load_n(&sh->cmng.n_valid, __ATOMIC_RELAXED); + pools_n = __atomic_load_n(&sh->sws_cmng.n_valid, __ATOMIC_RELAXED); us = MLX5_POOL_QUERY_FREQ_US / pools_n; DRV_LOG(DEBUG, "Set alarm for %u pools each %u us", pools_n, us); if (rte_eal_alarm_set(us, mlx5_flow_query_alarm, sh)) { - sh->cmng.query_thread_on = 0; + sh->sws_cmng.query_thread_on = 0; DRV_LOG(ERR, "Cannot reinitialize query alarm"); } else { - sh->cmng.query_thread_on = 1; + sh->sws_cmng.query_thread_on = 1; } } @@ -9017,12 +9018,12 @@ mlx5_flow_query_alarm(void *arg) { struct mlx5_dev_ctx_shared *sh = arg; int ret; - uint16_t pool_index = sh->cmng.pool_index; - struct mlx5_flow_counter_mng *cmng = &sh->cmng; + uint16_t pool_index = sh->sws_cmng.pool_index; + struct mlx5_flow_counter_mng *cmng = &sh->sws_cmng; struct mlx5_flow_counter_pool *pool; uint16_t n_valid; - if (sh->cmng.pending_queries >= MLX5_MAX_PENDING_QUERIES) + if (sh->sws_cmng.pending_queries >= MLX5_MAX_PENDING_QUERIES) goto set_alarm; rte_spinlock_lock(&cmng->pool_update_sl); pool = cmng->pools[pool_index]; @@ -9035,7 +9036,7 @@ mlx5_flow_query_alarm(void *arg) /* There is a pool query in progress. */ goto set_alarm; pool->raw_hw = - LIST_FIRST(&sh->cmng.free_stat_raws); + LIST_FIRST(&sh->sws_cmng.free_stat_raws); if (!pool->raw_hw) /* No free counter statistics raw memory. */ goto set_alarm; @@ -9061,12 +9062,12 @@ mlx5_flow_query_alarm(void *arg) goto set_alarm; } LIST_REMOVE(pool->raw_hw, next); - sh->cmng.pending_queries++; + sh->sws_cmng.pending_queries++; pool_index++; if (pool_index >= n_valid) pool_index = 0; set_alarm: - sh->cmng.pool_index = pool_index; + sh->sws_cmng.pool_index = pool_index; mlx5_set_query_alarm(sh); } @@ -9149,7 +9150,7 @@ mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh, (struct mlx5_flow_counter_pool *)(uintptr_t)async_id; struct mlx5_counter_stats_raw *raw_to_free; uint8_t query_gen = pool->query_gen ^ 1; - struct mlx5_flow_counter_mng *cmng = &sh->cmng; + struct mlx5_flow_counter_mng *cmng = &sh->sws_cmng; enum mlx5_counter_type cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; @@ -9172,9 +9173,9 @@ mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh, rte_spinlock_unlock(&cmng->csl[cnt_type]); } } - LIST_INSERT_HEAD(&sh->cmng.free_stat_raws, raw_to_free, next); + LIST_INSERT_HEAD(&sh->sws_cmng.free_stat_raws, raw_to_free, next); pool->raw_hw = NULL; - sh->cmng.pending_queries--; + sh->sws_cmng.pending_queries--; } static int @@ -9534,7 +9535,7 @@ mlx5_flow_dev_dump_sh_all(struct rte_eth_dev *dev, struct mlx5_list_inconst *l_inconst; struct mlx5_list_entry *e; int lcore_index; - struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; + struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; uint32_t max; void *action; @@ -9705,18 +9706,58 @@ mlx5_flow_get_aged_flows(struct rte_eth_dev *dev, void **contexts, { const struct mlx5_flow_driver_ops *fops; struct rte_flow_attr attr = { .transfer = 0 }; + enum mlx5_flow_drv_type type = flow_get_drv_type(dev, &attr); - if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) { - fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV); - return fops->get_aged_flows(dev, contexts, nb_contexts, - error); + if (type == MLX5_FLOW_TYPE_DV || type == MLX5_FLOW_TYPE_HW) { + fops = flow_get_drv_ops(type); + return fops->get_aged_flows(dev, contexts, nb_contexts, error); } - DRV_LOG(ERR, - "port %u get aged flows is not supported.", - dev->data->port_id); + DRV_LOG(ERR, "port %u get aged flows is not supported.", + dev->data->port_id); return -ENOTSUP; } +/** + * Get aged-out flows per HWS queue. + * + * @param[in] dev + * Pointer to the Ethernet device structure. + * @param[in] queue_id + * Flow queue to query. + * @param[in] context + * The address of an array of pointers to the aged-out flows contexts. + * @param[in] nb_countexts + * The length of context array pointers. + * @param[out] error + * Perform verbose error reporting if not NULL. Initialized in case of + * error only. + * + * @return + * how many contexts get in success, otherwise negative errno value. + * if nb_contexts is 0, return the amount of all aged contexts. + * if nb_contexts is not 0 , return the amount of aged flows reported + * in the context array. + */ +int +mlx5_flow_get_q_aged_flows(struct rte_eth_dev *dev, uint32_t queue_id, + void **contexts, uint32_t nb_contexts, + struct rte_flow_error *error) +{ + const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = { 0 }; + + if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_HW) { + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_HW); + return fops->get_q_aged_flows(dev, queue_id, contexts, + nb_contexts, error); + } + DRV_LOG(ERR, "port %u queue %u get aged flows is not supported.", + dev->data->port_id, queue_id); + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "get Q aged flows with incorrect steering mode"); +} + /* Wrapper for driver action_validate op callback */ static int flow_drv_action_validate(struct rte_eth_dev *dev, diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index ffa4f28255..30a18ea35e 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -293,6 +293,8 @@ enum mlx5_feature_name { #define MLX5_FLOW_ACTION_MODIFY_FIELD (1ull << 39) #define MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY (1ull << 40) #define MLX5_FLOW_ACTION_CT (1ull << 41) +#define MLX5_FLOW_ACTION_INDIRECT_COUNT (1ull << 42) +#define MLX5_FLOW_ACTION_INDIRECT_AGE (1ull << 43) #define MLX5_FLOW_FATE_ACTIONS \ (MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \ @@ -1099,6 +1101,22 @@ struct rte_flow { uint32_t geneve_tlv_option; /**< Holds Geneve TLV option id. > */ } __rte_packed; +/* + * HWS COUNTER ID's layout + * 3 2 1 0 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T | | D | | + * ~ Y | | C | IDX ~ + * | P | | S | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Bit 31:29 = TYPE = MLX5_INDIRECT_ACTION_TYPE_COUNT = b'10 + * Bit 25:24 = DCS index + * Bit 23:00 = IDX in this counter belonged DCS bulk. + */ +typedef uint32_t cnt_id_t; + #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) /* HWS flow struct. */ @@ -1112,7 +1130,8 @@ struct rte_flow_hw { }; struct rte_flow_template_table *table; /* The table flow allcated from. */ struct mlx5dr_rule rule; /* HWS layer data struct. */ - uint32_t cnt_id; + uint32_t age_idx; + cnt_id_t cnt_id; uint32_t mtr_id; } __rte_packed; @@ -1158,7 +1177,7 @@ struct mlx5_action_construct_data { uint32_t idx; /* Shared action index. */ } shared_rss; struct { - uint32_t id; + cnt_id_t id; } shared_counter; struct { uint32_t id; @@ -1189,6 +1208,7 @@ struct rte_flow_actions_template { struct rte_flow_action *actions; /* Cached flow actions. */ struct rte_flow_action *masks; /* Cached action masks.*/ struct mlx5dr_action_template *tmpl; /* mlx5dr action template. */ + uint64_t action_flags; /* Bit-map of all valid action in template. */ uint16_t dr_actions_num; /* Amount of DR rules actions. */ uint16_t actions_num; /* Amount of flow actions */ uint16_t *actions_off; /* DR action offset for given rte action offset. */ @@ -1245,7 +1265,7 @@ struct mlx5_hw_actions { struct mlx5_hw_encap_decap_action *encap_decap; uint16_t encap_decap_pos; /* Encap/Decap action position. */ uint32_t mark:1; /* Indicate the mark action. */ - uint32_t cnt_id; /* Counter id. */ + cnt_id_t cnt_id; /* Counter id. */ uint32_t mtr_id; /* Meter id. */ /* Translated DR action array from action template. */ struct mlx5dr_rule_action rule_acts[MLX5_HW_MAX_ACTS]; @@ -1619,6 +1639,12 @@ typedef int (*mlx5_flow_get_aged_flows_t) void **context, uint32_t nb_contexts, struct rte_flow_error *error); +typedef int (*mlx5_flow_get_q_aged_flows_t) + (struct rte_eth_dev *dev, + uint32_t queue_id, + void **context, + uint32_t nb_contexts, + struct rte_flow_error *error); typedef int (*mlx5_flow_action_validate_t) (struct rte_eth_dev *dev, const struct rte_flow_indir_action_conf *conf, @@ -1825,6 +1851,7 @@ struct mlx5_flow_driver_ops { mlx5_flow_counter_free_t counter_free; mlx5_flow_counter_query_t counter_query; mlx5_flow_get_aged_flows_t get_aged_flows; + mlx5_flow_get_q_aged_flows_t get_q_aged_flows; mlx5_flow_action_validate_t action_validate; mlx5_flow_action_create_t action_create; mlx5_flow_action_destroy_t action_destroy; diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index a42eb99154..1146e13cfa 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -5524,7 +5524,7 @@ flow_dv_validate_action_age(uint64_t action_flags, const struct rte_flow_action_age *age = action->conf; if (!priv->sh->cdev->config.devx || - (priv->sh->cmng.counter_fallback && !priv->sh->aso_age_mng)) + (priv->sh->sws_cmng.counter_fallback && !priv->sh->aso_age_mng)) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -6085,7 +6085,7 @@ flow_dv_counter_get_by_idx(struct rte_eth_dev *dev, struct mlx5_flow_counter_pool **ppool) { struct mlx5_priv *priv = dev->data->dev_private; - struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; + struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; struct mlx5_flow_counter_pool *pool; /* Decrease to original index and clear shared bit. */ @@ -6179,7 +6179,7 @@ static int flow_dv_container_resize(struct rte_eth_dev *dev) { struct mlx5_priv *priv = dev->data->dev_private; - struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; + struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; void *old_pools = cmng->pools; uint32_t resize = cmng->n + MLX5_CNT_CONTAINER_RESIZE; uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize; @@ -6225,7 +6225,7 @@ _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts, cnt = flow_dv_counter_get_by_idx(dev, counter, &pool); MLX5_ASSERT(pool); - if (priv->sh->cmng.counter_fallback) + if (priv->sh->sws_cmng.counter_fallback) return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0, 0, pkts, bytes, 0, NULL, NULL, 0); rte_spinlock_lock(&pool->sl); @@ -6262,8 +6262,8 @@ flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs, { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_flow_counter_pool *pool; - struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; - bool fallback = priv->sh->cmng.counter_fallback; + struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; + bool fallback = priv->sh->sws_cmng.counter_fallback; uint32_t size = sizeof(*pool); size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE; @@ -6324,14 +6324,14 @@ flow_dv_counter_pool_prepare(struct rte_eth_dev *dev, uint32_t age) { struct mlx5_priv *priv = dev->data->dev_private; - struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; + struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; struct mlx5_flow_counter_pool *pool; struct mlx5_counters tmp_tq; struct mlx5_devx_obj *dcs = NULL; struct mlx5_flow_counter *cnt; enum mlx5_counter_type cnt_type = age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; - bool fallback = priv->sh->cmng.counter_fallback; + bool fallback = priv->sh->sws_cmng.counter_fallback; uint32_t i; if (fallback) { @@ -6395,8 +6395,8 @@ flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age) struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_flow_counter_pool *pool = NULL; struct mlx5_flow_counter *cnt_free = NULL; - bool fallback = priv->sh->cmng.counter_fallback; - struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; + bool fallback = priv->sh->sws_cmng.counter_fallback; + struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; enum mlx5_counter_type cnt_type = age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; uint32_t cnt_idx; @@ -6442,7 +6442,7 @@ flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age) if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits, &cnt_free->bytes)) goto err; - if (!fallback && !priv->sh->cmng.query_thread_on) + if (!fallback && !priv->sh->sws_cmng.query_thread_on) /* Start the asynchronous batch query by the host thread. */ mlx5_set_query_alarm(priv->sh); /* @@ -6570,7 +6570,7 @@ flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter) * this case, lock will not be needed as query callback and release * function both operate with the different list. */ - if (!priv->sh->cmng.counter_fallback) { + if (!priv->sh->sws_cmng.counter_fallback) { rte_spinlock_lock(&pool->csl); TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next); rte_spinlock_unlock(&pool->csl); @@ -6578,10 +6578,10 @@ flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter) cnt->dcs_when_free = cnt->dcs_when_active; cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN; - rte_spinlock_lock(&priv->sh->cmng.csl[cnt_type]); - TAILQ_INSERT_TAIL(&priv->sh->cmng.counters[cnt_type], + rte_spinlock_lock(&priv->sh->sws_cmng.csl[cnt_type]); + TAILQ_INSERT_TAIL(&priv->sh->sws_cmng.counters[cnt_type], cnt, next); - rte_spinlock_unlock(&priv->sh->cmng.csl[cnt_type]); + rte_spinlock_unlock(&priv->sh->sws_cmng.csl[cnt_type]); } } diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index d498d203d5..161b96cd87 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -477,7 +477,8 @@ __flow_hw_act_data_general_append(struct mlx5_priv *priv, enum rte_flow_action_type type, uint16_t action_src, uint16_t action_dst) -{ struct mlx5_action_construct_data *act_data; +{ + struct mlx5_action_construct_data *act_data; act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst); if (!act_data) @@ -512,7 +513,8 @@ __flow_hw_act_data_encap_append(struct mlx5_priv *priv, uint16_t action_src, uint16_t action_dst, uint16_t len) -{ struct mlx5_action_construct_data *act_data; +{ + struct mlx5_action_construct_data *act_data; act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst); if (!act_data) @@ -582,7 +584,8 @@ __flow_hw_act_data_shared_rss_append(struct mlx5_priv *priv, uint16_t action_dst, uint32_t idx, struct mlx5_shared_action_rss *rss) -{ struct mlx5_action_construct_data *act_data; +{ + struct mlx5_action_construct_data *act_data; act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst); if (!act_data) @@ -621,7 +624,8 @@ __flow_hw_act_data_shared_cnt_append(struct mlx5_priv *priv, uint16_t action_src, uint16_t action_dst, cnt_id_t cnt_id) -{ struct mlx5_action_construct_data *act_data; +{ + struct mlx5_action_construct_data *act_data; act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst); if (!act_data) @@ -717,6 +721,10 @@ flow_hw_shared_action_translate(struct rte_eth_dev *dev, action_src, action_dst, act_idx)) return -1; break; + case MLX5_INDIRECT_ACTION_TYPE_AGE: + /* Not supported, prevent by validate function. */ + MLX5_ASSERT(0); + break; case MLX5_INDIRECT_ACTION_TYPE_CT: if (flow_hw_ct_compile(dev, MLX5_HW_INV_QUEUE, idx, &acts->rule_acts[action_dst])) @@ -1109,7 +1117,7 @@ flow_hw_cnt_compile(struct rte_eth_dev *dev, uint32_t start_pos, cnt_id_t cnt_id; int ret; - ret = mlx5_hws_cnt_shared_get(priv->hws_cpool, &cnt_id); + ret = mlx5_hws_cnt_shared_get(priv->hws_cpool, &cnt_id, 0); if (ret != 0) return ret; ret = mlx5_hws_cnt_pool_get_action_offset @@ -1250,8 +1258,6 @@ flow_hw_meter_mark_compile(struct rte_eth_dev *dev, * Pointer to the rte_eth_dev structure. * @param[in] cfg * Pointer to the table configuration. - * @param[in] item_templates - * Item template array to be binded to the table. * @param[in/out] acts * Pointer to the template HW steering DR actions. * @param[in] at @@ -1260,7 +1266,7 @@ flow_hw_meter_mark_compile(struct rte_eth_dev *dev, * Pointer to error structure. * * @return - * Table on success, NULL otherwise and rte_errno is set. + * 0 on success, a negative errno otherwise and rte_errno is set. */ static int __flow_hw_actions_translate(struct rte_eth_dev *dev, @@ -1289,6 +1295,7 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev, uint16_t jump_pos; uint32_t ct_idx; int err; + uint32_t target_grp = 0; flow_hw_modify_field_init(&mhdr, at); if (attr->transfer) @@ -1516,8 +1523,42 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev, action_pos)) goto err; break; + case RTE_FLOW_ACTION_TYPE_AGE: + flow_hw_translate_group(dev, cfg, attr->group, + &target_grp, error); + if (target_grp == 0) { + __flow_hw_action_template_destroy(dev, acts); + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "Age action on root table is not supported in HW steering mode"); + } + action_pos = at->actions_off[actions - at->actions]; + if (__flow_hw_act_data_general_append(priv, acts, + actions->type, + actions - action_start, + action_pos)) + goto err; + break; case RTE_FLOW_ACTION_TYPE_COUNT: - action_pos = at->actions_off[actions - action_start]; + flow_hw_translate_group(dev, cfg, attr->group, + &target_grp, error); + if (target_grp == 0) { + __flow_hw_action_template_destroy(dev, acts); + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "Counter action on root table is not supported in HW steering mode"); + } + if ((at->action_flags & MLX5_FLOW_ACTION_AGE) || + (at->action_flags & MLX5_FLOW_ACTION_INDIRECT_AGE)) + /* + * When both COUNT and AGE are requested, it is + * saved as AGE action which creates also the + * counter. + */ + break; + action_pos = at->actions_off[actions - at->actions]; if (masks->conf && ((const struct rte_flow_action_count *) masks->conf)->id) { @@ -1744,6 +1785,10 @@ flow_hw_shared_action_get(struct rte_eth_dev *dev, * Pointer to the flow table. * @param[in] it_idx * Item template index the action template refer to. + * @param[in] action_flags + * Actions bit-map detected in this template. + * @param[in, out] flow + * Pointer to the flow containing the counter. * @param[in] rule_act * Pointer to the shared action's destination rule DR action. * @@ -1754,7 +1799,8 @@ static __rte_always_inline int flow_hw_shared_action_construct(struct rte_eth_dev *dev, uint32_t queue, const struct rte_flow_action *action, struct rte_flow_template_table *table, - const uint8_t it_idx, + const uint8_t it_idx, uint64_t action_flags, + struct rte_flow_hw *flow, struct mlx5dr_rule_action *rule_act) { struct mlx5_priv *priv = dev->data->dev_private; @@ -1762,11 +1808,14 @@ flow_hw_shared_action_construct(struct rte_eth_dev *dev, uint32_t queue, struct mlx5_action_construct_data act_data; struct mlx5_shared_action_rss *shared_rss; struct mlx5_aso_mtr *aso_mtr; + struct mlx5_age_info *age_info; + struct mlx5_hws_age_param *param; uint32_t act_idx = (uint32_t)(uintptr_t)action->conf; uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); uint64_t item_flags; + cnt_id_t age_cnt; memset(&act_data, 0, sizeof(act_data)); switch (type) { @@ -1792,6 +1841,44 @@ flow_hw_shared_action_construct(struct rte_eth_dev *dev, uint32_t queue, &rule_act->action, &rule_act->counter.offset)) return -1; + flow->cnt_id = act_idx; + break; + case MLX5_INDIRECT_ACTION_TYPE_AGE: + /* + * Save the index with the indirect type, to recognize + * it in flow destroy. + */ + flow->age_idx = act_idx; + if (action_flags & MLX5_FLOW_ACTION_INDIRECT_COUNT) + /* + * The mutual update for idirect AGE & COUNT will be + * performed later after we have ID for both of them. + */ + break; + age_info = GET_PORT_AGE_INFO(priv); + param = mlx5_ipool_get(age_info->ages_ipool, idx); + if (param == NULL) + return -1; + if (action_flags & MLX5_FLOW_ACTION_COUNT) { + if (mlx5_hws_cnt_pool_get(priv->hws_cpool, + ¶m->queue_id, &age_cnt, + idx) < 0) + return -1; + flow->cnt_id = age_cnt; + param->nb_cnts++; + } else { + /* + * Get the counter of this indirect AGE or create one + * if doesn't exist. + */ + age_cnt = mlx5_hws_age_cnt_get(priv, param, idx); + if (age_cnt == 0) + return -1; + } + if (mlx5_hws_cnt_pool_get_action_offset(priv->hws_cpool, + age_cnt, &rule_act->action, + &rule_act->counter.offset)) + return -1; break; case MLX5_INDIRECT_ACTION_TYPE_CT: if (flow_hw_ct_compile(dev, queue, idx, rule_act)) @@ -1952,7 +2039,8 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, const uint8_t it_idx, const struct rte_flow_action actions[], struct mlx5dr_rule_action *rule_acts, - uint32_t queue) + uint32_t queue, + struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; @@ -1965,6 +2053,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, const struct rte_flow_item *enc_item = NULL; const struct rte_flow_action_ethdev *port_action = NULL; const struct rte_flow_action_meter *meter = NULL; + const struct rte_flow_action_age *age = NULL; uint8_t *buf = job->encap_data; struct rte_flow_attr attr = { .ingress = 1, @@ -1972,6 +2061,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, uint32_t ft_flag; size_t encap_len = 0; int ret; + uint32_t age_idx = 0; struct mlx5_aso_mtr *aso_mtr; rte_memcpy(rule_acts, hw_acts->rule_acts, sizeof(*rule_acts) * at->dr_actions_num); @@ -2024,6 +2114,7 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_INDIRECT: if (flow_hw_shared_action_construct (dev, queue, action, table, it_idx, + at->action_flags, job->flow, &rule_acts[act_data->action_dst])) return -1; break; @@ -2132,9 +2223,32 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, if (mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) return -1; break; + case RTE_FLOW_ACTION_TYPE_AGE: + age = action->conf; + /* + * First, create the AGE parameter, then create its + * counter later: + * Regular counter - in next case. + * Indirect counter - update it after the loop. + */ + age_idx = mlx5_hws_age_action_create(priv, queue, 0, + age, + job->flow->idx, + error); + if (age_idx == 0) + return -rte_errno; + job->flow->age_idx = age_idx; + if (at->action_flags & MLX5_FLOW_ACTION_INDIRECT_COUNT) + /* + * When AGE uses indirect counter, no need to + * create counter but need to update it with the + * AGE parameter, will be done after the loop. + */ + break; + /* Fall-through. */ case RTE_FLOW_ACTION_TYPE_COUNT: ret = mlx5_hws_cnt_pool_get(priv->hws_cpool, &queue, - &cnt_id); + &cnt_id, age_idx); if (ret != 0) return ret; ret = mlx5_hws_cnt_pool_get_action_offset @@ -2191,6 +2305,25 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, break; } } + if (at->action_flags & MLX5_FLOW_ACTION_INDIRECT_COUNT) { + if (at->action_flags & MLX5_FLOW_ACTION_INDIRECT_AGE) { + age_idx = job->flow->age_idx & MLX5_HWS_AGE_IDX_MASK; + if (mlx5_hws_cnt_age_get(priv->hws_cpool, + job->flow->cnt_id) != age_idx) + /* + * This is first use of this indirect counter + * for this indirect AGE, need to increase the + * number of counters. + */ + mlx5_hws_age_nb_cnt_increase(priv, age_idx); + } + /* + * Update this indirect counter the indirect/direct AGE in which + * using it. + */ + mlx5_hws_cnt_age_set(priv->hws_cpool, job->flow->cnt_id, + age_idx); + } if (hw_acts->encap_decap && !hw_acts->encap_decap->shared) { rule_acts[hw_acts->encap_decap_pos].reformat.offset = job->flow->idx - 1; @@ -2340,8 +2473,10 @@ flow_hw_async_flow_create(struct rte_eth_dev *dev, * No need to copy and contrust a new "actions" list based on the * user's input, in order to save the cost. */ - if (flow_hw_actions_construct(dev, job, &table->ats[action_template_index], - pattern_template_index, actions, rule_acts, queue)) { + if (flow_hw_actions_construct(dev, job, + &table->ats[action_template_index], + pattern_template_index, actions, + rule_acts, queue, error)) { rte_errno = EINVAL; goto free; } @@ -2426,6 +2561,49 @@ flow_hw_async_flow_destroy(struct rte_eth_dev *dev, "fail to create rte flow"); } +/** + * Release the AGE and counter for given flow. + * + * @param[in] priv + * Pointer to the port private data structure. + * @param[in] queue + * The queue to release the counter. + * @param[in, out] flow + * Pointer to the flow containing the counter. + * @param[out] error + * Pointer to error structure. + */ +static void +flow_hw_age_count_release(struct mlx5_priv *priv, uint32_t queue, + struct rte_flow_hw *flow, + struct rte_flow_error *error) +{ + if (mlx5_hws_cnt_is_shared(priv->hws_cpool, flow->cnt_id)) { + if (flow->age_idx && !mlx5_hws_age_is_indirect(flow->age_idx)) { + /* Remove this AGE parameter from indirect counter. */ + mlx5_hws_cnt_age_set(priv->hws_cpool, flow->cnt_id, 0); + /* Release the AGE parameter. */ + mlx5_hws_age_action_destroy(priv, flow->age_idx, error); + flow->age_idx = 0; + } + return; + } + /* Put the counter first to reduce the race risk in BG thread. */ + mlx5_hws_cnt_pool_put(priv->hws_cpool, &queue, &flow->cnt_id); + flow->cnt_id = 0; + if (flow->age_idx) { + if (mlx5_hws_age_is_indirect(flow->age_idx)) { + uint32_t idx = flow->age_idx & MLX5_HWS_AGE_IDX_MASK; + + mlx5_hws_age_nb_cnt_decrease(priv, idx); + } else { + /* Release the AGE parameter. */ + mlx5_hws_age_action_destroy(priv, flow->age_idx, error); + } + flow->age_idx = 0; + } +} + /** * Pull the enqueued flows. * @@ -2472,13 +2650,9 @@ flow_hw_pull(struct rte_eth_dev *dev, flow_hw_jump_release(dev, job->flow->jump); else if (job->flow->fate_type == MLX5_FLOW_FATE_QUEUE) mlx5_hrxq_obj_release(dev, job->flow->hrxq); - if (mlx5_hws_cnt_id_valid(job->flow->cnt_id) && - mlx5_hws_cnt_is_shared - (priv->hws_cpool, job->flow->cnt_id) == false) { - mlx5_hws_cnt_pool_put(priv->hws_cpool, &queue, - &job->flow->cnt_id); - job->flow->cnt_id = 0; - } + if (mlx5_hws_cnt_id_valid(job->flow->cnt_id)) + flow_hw_age_count_release(priv, queue, + job->flow, error); if (job->flow->mtr_id) { mlx5_ipool_free(pool->idx_pool, job->flow->mtr_id); job->flow->mtr_id = 0; @@ -3131,100 +3305,315 @@ flow_hw_validate_action_represented_port(struct rte_eth_dev *dev, return 0; } -static inline int -flow_hw_action_meta_copy_insert(const struct rte_flow_action actions[], - const struct rte_flow_action masks[], - const struct rte_flow_action *ins_actions, - const struct rte_flow_action *ins_masks, - struct rte_flow_action *new_actions, - struct rte_flow_action *new_masks, - uint16_t *ins_pos) +/** + * Validate AGE action. + * + * @param[in] dev + * Pointer to rte_eth_dev structure. + * @param[in] action + * Pointer to the indirect action. + * @param[in] action_flags + * Holds the actions detected until now. + * @param[in] fixed_cnt + * Indicator if this list has a fixed COUNT action. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +flow_hw_validate_action_age(struct rte_eth_dev *dev, + const struct rte_flow_action *action, + uint64_t action_flags, bool fixed_cnt, + struct rte_flow_error *error) { - uint16_t idx, total = 0; - uint16_t end_idx = UINT16_MAX; - bool act_end = false; - bool modify_field = false; - bool rss_or_queue = false; + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); - MLX5_ASSERT(actions && masks); - MLX5_ASSERT(new_actions && new_masks); - MLX5_ASSERT(ins_actions && ins_masks); - for (idx = 0; !act_end; idx++) { - switch (actions[idx].type) { - case RTE_FLOW_ACTION_TYPE_RSS: - case RTE_FLOW_ACTION_TYPE_QUEUE: - /* It is assumed that application provided only single RSS/QUEUE action. */ - MLX5_ASSERT(!rss_or_queue); - rss_or_queue = true; - break; - case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: - modify_field = true; - break; - case RTE_FLOW_ACTION_TYPE_END: - end_idx = idx; - act_end = true; - break; - default: - break; + if (!priv->sh->cdev->config.devx) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "AGE action not supported"); + if (age_info->ages_ipool == NULL) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "aging pool not initialized"); + if ((action_flags & MLX5_FLOW_ACTION_AGE) || + (action_flags & MLX5_FLOW_ACTION_INDIRECT_AGE)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "duplicate AGE actions set"); + if (fixed_cnt) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "AGE and fixed COUNT combination is not supported"); + return 0; +} + +/** + * Validate count action. + * + * @param[in] dev + * Pointer to rte_eth_dev structure. + * @param[in] action + * Pointer to the indirect action. + * @param[in] mask + * Pointer to the indirect action mask. + * @param[in] action_flags + * Holds the actions detected until now. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +flow_hw_validate_action_count(struct rte_eth_dev *dev, + const struct rte_flow_action *action, + const struct rte_flow_action *mask, + uint64_t action_flags, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + const struct rte_flow_action_count *count = mask->conf; + + if (!priv->sh->cdev->config.devx) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "count action not supported"); + if (!priv->hws_cpool) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "counters pool not initialized"); + if ((action_flags & MLX5_FLOW_ACTION_COUNT) || + (action_flags & MLX5_FLOW_ACTION_INDIRECT_COUNT)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "duplicate count actions set"); + if (count && count->id && (action_flags & MLX5_FLOW_ACTION_AGE)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, mask, + "AGE and COUNT action shared by mask combination is not supported"); + return 0; +} + +/** + * Validate meter_mark action. + * + * @param[in] dev + * Pointer to rte_eth_dev structure. + * @param[in] action + * Pointer to the indirect action. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +flow_hw_validate_action_meter_mark(struct rte_eth_dev *dev, + const struct rte_flow_action *action, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + RTE_SET_USED(action); + + if (!priv->sh->cdev->config.devx) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "meter_mark action not supported"); + if (!priv->hws_mpool) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "meter_mark pool not initialized"); + return 0; +} + +/** + * Validate indirect action. + * + * @param[in] dev + * Pointer to rte_eth_dev structure. + * @param[in] action + * Pointer to the indirect action. + * @param[in] mask + * Pointer to the indirect action mask. + * @param[in, out] action_flags + * Holds the actions detected until now. + * @param[in, out] fixed_cnt + * Pointer to indicator if this list has a fixed COUNT action. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +flow_hw_validate_action_indirect(struct rte_eth_dev *dev, + const struct rte_flow_action *action, + const struct rte_flow_action *mask, + uint64_t *action_flags, bool *fixed_cnt, + struct rte_flow_error *error) +{ + uint32_t type; + int ret; + + if (!mask) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Unable to determine indirect action type without a mask specified"); + type = mask->type; + switch (type) { + case RTE_FLOW_ACTION_TYPE_METER_MARK: + ret = flow_hw_validate_action_meter_mark(dev, mask, error); + if (ret < 0) + return ret; + *action_flags |= MLX5_FLOW_ACTION_METER; + break; + case RTE_FLOW_ACTION_TYPE_RSS: + /* TODO: Validation logic (same as flow_hw_actions_validate) */ + *action_flags |= MLX5_FLOW_ACTION_RSS; + break; + case RTE_FLOW_ACTION_TYPE_CONNTRACK: + /* TODO: Validation logic (same as flow_hw_actions_validate) */ + *action_flags |= MLX5_FLOW_ACTION_CT; + break; + case RTE_FLOW_ACTION_TYPE_COUNT: + if (action->conf && mask->conf) { + if ((*action_flags & MLX5_FLOW_ACTION_AGE) || + (*action_flags & MLX5_FLOW_ACTION_INDIRECT_AGE)) + /* + * AGE cannot use indirect counter which is + * shared with enother flow rules. + */ + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, + "AGE and fixed COUNT combination is not supported"); + *fixed_cnt = true; } + ret = flow_hw_validate_action_count(dev, action, mask, + *action_flags, error); + if (ret < 0) + return ret; + *action_flags |= MLX5_FLOW_ACTION_INDIRECT_COUNT; + break; + case RTE_FLOW_ACTION_TYPE_AGE: + ret = flow_hw_validate_action_age(dev, action, *action_flags, + *fixed_cnt, error); + if (ret < 0) + return ret; + *action_flags |= MLX5_FLOW_ACTION_INDIRECT_AGE; + break; + default: + DRV_LOG(WARNING, "Unsupported shared action type: %d", type); + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, mask, + "Unsupported indirect action type"); } - if (!rss_or_queue) - return 0; - else if (idx >= MLX5_HW_MAX_ACTS) - return -1; /* No more space. */ - total = idx; - /* - * If actions template contains MODIFY_FIELD action, then meta copy action can be inserted - * at the template's end. Position of MODIFY_HDR action is based on the position of the - * first MODIFY_FIELD flow action. - */ - if (modify_field) { - *ins_pos = end_idx; - goto insert_meta_copy; - } - /* - * If actions template does not contain MODIFY_FIELD action, then meta copy action must be - * inserted at aplace conforming with action order defined in steering/mlx5dr_action.c. + return 0; +} + +/** + * Validate raw_encap action. + * + * @param[in] dev + * Pointer to rte_eth_dev structure. + * @param[in] action + * Pointer to the indirect action. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +flow_hw_validate_action_raw_encap(struct rte_eth_dev *dev __rte_unused, + const struct rte_flow_action *action, + struct rte_flow_error *error) +{ + const struct rte_flow_action_raw_encap *raw_encap_data = action->conf; + + if (!raw_encap_data || !raw_encap_data->size || !raw_encap_data->data) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION, action, + "invalid raw_encap_data"); + return 0; +} + +static inline uint16_t +flow_hw_template_expand_modify_field(const struct rte_flow_action actions[], + const struct rte_flow_action masks[], + const struct rte_flow_action *mf_action, + const struct rte_flow_action *mf_mask, + struct rte_flow_action *new_actions, + struct rte_flow_action *new_masks, + uint64_t flags, uint32_t act_num) +{ + uint32_t i, tail; + + MLX5_ASSERT(actions && masks); + MLX5_ASSERT(new_actions && new_masks); + MLX5_ASSERT(mf_action && mf_mask); + if (flags & MLX5_FLOW_ACTION_MODIFY_FIELD) { + /* + * Application action template already has Modify Field. + * It's location will be used in DR. + * Expanded MF action can be added before the END. + */ + i = act_num - 1; + goto insert; + } + /** + * Locate the first action positioned BEFORE the new MF. + * + * Search for a place to insert modify header + * from the END action backwards: + * 1. END is always present in actions array + * 2. END location is always at action[act_num - 1] + * 3. END always positioned AFTER modify field location + * + * Relative actions order is the same for RX, TX and FDB. + * + * Current actions order (draft-3) + * @see action_order_arr[] */ - act_end = false; - for (idx = 0; !act_end; idx++) { - switch (actions[idx].type) { - case RTE_FLOW_ACTION_TYPE_COUNT: - case RTE_FLOW_ACTION_TYPE_METER: - case RTE_FLOW_ACTION_TYPE_METER_MARK: - case RTE_FLOW_ACTION_TYPE_CONNTRACK: + for (i = act_num - 2; (int)i >= 0; i--) { + enum rte_flow_action_type type = actions[i].type; + + if (type == RTE_FLOW_ACTION_TYPE_INDIRECT) + type = masks[i].type; + switch (type) { case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: - case RTE_FLOW_ACTION_TYPE_RSS: + case RTE_FLOW_ACTION_TYPE_DROP: + case RTE_FLOW_ACTION_TYPE_JUMP: case RTE_FLOW_ACTION_TYPE_QUEUE: - *ins_pos = idx; - act_end = true; - break; + case RTE_FLOW_ACTION_TYPE_RSS: + case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: + case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: + case RTE_FLOW_ACTION_TYPE_VOID: case RTE_FLOW_ACTION_TYPE_END: - act_end = true; break; default: + i++; /* new MF inserted AFTER actions[i] */ + goto insert; break; } } -insert_meta_copy: - MLX5_ASSERT(*ins_pos != UINT16_MAX); - MLX5_ASSERT(*ins_pos < total); - /* Before the position, no change for the actions. */ - for (idx = 0; idx < *ins_pos; idx++) { - new_actions[idx] = actions[idx]; - new_masks[idx] = masks[idx]; - } - /* Insert the new action and mask to the position. */ - new_actions[idx] = *ins_actions; - new_masks[idx] = *ins_masks; - /* Remaining content is right shifted by one position. */ - for (; idx < total; idx++) { - new_actions[idx + 1] = actions[idx]; - new_masks[idx + 1] = masks[idx]; - } - return 0; + i = 0; +insert: + tail = act_num - i; /* num action to move */ + memcpy(new_actions, actions, sizeof(actions[0]) * i); + new_actions[i] = *mf_action; + memcpy(new_actions + i + 1, actions + i, sizeof(actions[0]) * tail); + memcpy(new_masks, masks, sizeof(masks[0]) * i); + new_masks[i] = *mf_mask; + memcpy(new_masks + i + 1, masks + i, sizeof(masks[0]) * tail); + return i; } static int @@ -3295,13 +3684,17 @@ flow_hw_validate_action_push_vlan(struct rte_eth_dev *dev, } static int -flow_hw_actions_validate(struct rte_eth_dev *dev, - const struct rte_flow_actions_template_attr *attr, - const struct rte_flow_action actions[], - const struct rte_flow_action masks[], - struct rte_flow_error *error) +mlx5_flow_hw_actions_validate(struct rte_eth_dev *dev, + const struct rte_flow_actions_template_attr *attr, + const struct rte_flow_action actions[], + const struct rte_flow_action masks[], + uint64_t *act_flags, + struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; + const struct rte_flow_action_count *count_mask = NULL; + bool fixed_cnt = false; + uint64_t action_flags = 0; uint16_t i; bool actions_end = false; int ret; @@ -3327,46 +3720,70 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, case RTE_FLOW_ACTION_TYPE_VOID: break; case RTE_FLOW_ACTION_TYPE_INDIRECT: - /* TODO: Validation logic */ + ret = flow_hw_validate_action_indirect(dev, action, + mask, + &action_flags, + &fixed_cnt, + error); + if (ret < 0) + return ret; break; case RTE_FLOW_ACTION_TYPE_MARK: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_MARK; break; case RTE_FLOW_ACTION_TYPE_DROP: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_DROP; break; case RTE_FLOW_ACTION_TYPE_JUMP: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_JUMP; break; case RTE_FLOW_ACTION_TYPE_QUEUE: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_QUEUE; break; case RTE_FLOW_ACTION_TYPE_RSS: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_RSS; break; case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_ENCAP; break; case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_ENCAP; break; case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_DECAP; break; case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_DECAP; break; case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: - /* TODO: Validation logic */ + ret = flow_hw_validate_action_raw_encap(dev, action, error); + if (ret < 0) + return ret; + action_flags |= MLX5_FLOW_ACTION_ENCAP; break; case RTE_FLOW_ACTION_TYPE_RAW_DECAP: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_DECAP; break; case RTE_FLOW_ACTION_TYPE_METER: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_METER; break; case RTE_FLOW_ACTION_TYPE_METER_MARK: - /* TODO: Validation logic */ + ret = flow_hw_validate_action_meter_mark(dev, action, + error); + if (ret < 0) + return ret; + action_flags |= MLX5_FLOW_ACTION_METER; break; case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD: ret = flow_hw_validate_action_modify_field(action, @@ -3374,21 +3791,43 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, error); if (ret < 0) return ret; + action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; break; case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: ret = flow_hw_validate_action_represented_port (dev, action, mask, error); if (ret < 0) return ret; + action_flags |= MLX5_FLOW_ACTION_PORT_ID; + break; + case RTE_FLOW_ACTION_TYPE_AGE: + if (count_mask && count_mask->id) + fixed_cnt = true; + ret = flow_hw_validate_action_age(dev, action, + action_flags, + fixed_cnt, error); + if (ret < 0) + return ret; + action_flags |= MLX5_FLOW_ACTION_AGE; break; case RTE_FLOW_ACTION_TYPE_COUNT: - /* TODO: Validation logic */ + ret = flow_hw_validate_action_count(dev, action, mask, + action_flags, + error); + if (ret < 0) + return ret; + count_mask = mask->conf; + action_flags |= MLX5_FLOW_ACTION_COUNT; break; case RTE_FLOW_ACTION_TYPE_CONNTRACK: /* TODO: Validation logic */ + action_flags |= MLX5_FLOW_ACTION_CT; break; case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN: + action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN; + break; case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID: + action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID; break; case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN: ret = flow_hw_validate_action_push_vlan @@ -3398,6 +3837,7 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, i += is_of_vlan_pcp_present(action) ? MLX5_HW_VLAN_PUSH_PCP_IDX : MLX5_HW_VLAN_PUSH_VID_IDX; + action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN; break; case RTE_FLOW_ACTION_TYPE_END: actions_end = true; @@ -3409,9 +3849,23 @@ flow_hw_actions_validate(struct rte_eth_dev *dev, "action not supported in template API"); } } + if (act_flags != NULL) + *act_flags = action_flags; return 0; } +static int +flow_hw_actions_validate(struct rte_eth_dev *dev, + const struct rte_flow_actions_template_attr *attr, + const struct rte_flow_action actions[], + const struct rte_flow_action masks[], + struct rte_flow_error *error) +{ + return mlx5_flow_hw_actions_validate(dev, attr, actions, masks, NULL, + error); +} + + static enum mlx5dr_action_type mlx5_hw_dr_action_types[] = { [RTE_FLOW_ACTION_TYPE_MARK] = MLX5DR_ACTION_TYP_TAG, [RTE_FLOW_ACTION_TYPE_DROP] = MLX5DR_ACTION_TYP_DROP, @@ -3424,7 +3878,6 @@ static enum mlx5dr_action_type mlx5_hw_dr_action_types[] = { [RTE_FLOW_ACTION_TYPE_NVGRE_DECAP] = MLX5DR_ACTION_TYP_TNL_L2_TO_L2, [RTE_FLOW_ACTION_TYPE_MODIFY_FIELD] = MLX5DR_ACTION_TYP_MODIFY_HDR, [RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT] = MLX5DR_ACTION_TYP_VPORT, - [RTE_FLOW_ACTION_TYPE_COUNT] = MLX5DR_ACTION_TYP_CTR, [RTE_FLOW_ACTION_TYPE_CONNTRACK] = MLX5DR_ACTION_TYP_ASO_CT, [RTE_FLOW_ACTION_TYPE_OF_POP_VLAN] = MLX5DR_ACTION_TYP_POP_VLAN, [RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN] = MLX5DR_ACTION_TYP_PUSH_VLAN, @@ -3434,7 +3887,7 @@ static int flow_hw_dr_actions_template_handle_shared(const struct rte_flow_action *mask, unsigned int action_src, enum mlx5dr_action_type *action_types, - uint16_t *curr_off, + uint16_t *curr_off, uint16_t *cnt_off, struct rte_flow_actions_template *at) { uint32_t type; @@ -3451,10 +3904,18 @@ flow_hw_dr_actions_template_handle_shared(const struct rte_flow_action *mask, action_types[*curr_off] = MLX5DR_ACTION_TYP_TIR; *curr_off = *curr_off + 1; break; + case RTE_FLOW_ACTION_TYPE_AGE: case RTE_FLOW_ACTION_TYPE_COUNT: - at->actions_off[action_src] = *curr_off; - action_types[*curr_off] = MLX5DR_ACTION_TYP_CTR; - *curr_off = *curr_off + 1; + /* + * Both AGE and COUNT action need counter, the first one fills + * the action_types array, and the second only saves the offset. + */ + if (*cnt_off == UINT16_MAX) { + *cnt_off = *curr_off; + action_types[*cnt_off] = MLX5DR_ACTION_TYP_CTR; + *curr_off = *curr_off + 1; + } + at->actions_off[action_src] = *cnt_off; break; case RTE_FLOW_ACTION_TYPE_CONNTRACK: at->actions_off[action_src] = *curr_off; @@ -3493,6 +3954,7 @@ flow_hw_dr_actions_template_create(struct rte_flow_actions_template *at) enum mlx5dr_action_type reformat_act_type = MLX5DR_ACTION_TYP_TNL_L2_TO_L2; uint16_t reformat_off = UINT16_MAX; uint16_t mhdr_off = UINT16_MAX; + uint16_t cnt_off = UINT16_MAX; int ret; for (i = 0, curr_off = 0; at->actions[i].type != RTE_FLOW_ACTION_TYPE_END; ++i) { const struct rte_flow_action_raw_encap *raw_encap_data; @@ -3505,9 +3967,12 @@ flow_hw_dr_actions_template_create(struct rte_flow_actions_template *at) case RTE_FLOW_ACTION_TYPE_VOID: break; case RTE_FLOW_ACTION_TYPE_INDIRECT: - ret = flow_hw_dr_actions_template_handle_shared(&at->masks[i], i, - action_types, - &curr_off, at); + ret = flow_hw_dr_actions_template_handle_shared + (&at->masks[i], + i, + action_types, + &curr_off, + &cnt_off, at); if (ret) return NULL; break; @@ -3563,6 +4028,19 @@ flow_hw_dr_actions_template_create(struct rte_flow_actions_template *at) if (curr_off >= MLX5_HW_MAX_ACTS) goto err_actions_num; break; + case RTE_FLOW_ACTION_TYPE_AGE: + case RTE_FLOW_ACTION_TYPE_COUNT: + /* + * Both AGE and COUNT action need counter, the first + * one fills the action_types array, and the second only + * saves the offset. + */ + if (cnt_off == UINT16_MAX) { + cnt_off = curr_off++; + action_types[cnt_off] = MLX5DR_ACTION_TYP_CTR; + } + at->actions_off[i] = cnt_off; + break; default: type = mlx5_hw_dr_action_types[at->actions[i].type]; at->actions_off[i] = curr_off; @@ -3703,6 +4181,7 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, unsigned int i; struct rte_flow_actions_template *at = NULL; uint16_t pos = UINT16_MAX; + uint64_t action_flags = 0; struct rte_flow_action tmp_action[MLX5_HW_MAX_ACTS]; struct rte_flow_action tmp_mask[MLX5_HW_MAX_ACTS]; struct rte_flow_action *ra = (void *)(uintptr_t)actions; @@ -3745,22 +4224,9 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, .conf = &rx_mreg_mask, }; - if (flow_hw_actions_validate(dev, attr, actions, masks, error)) + if (mlx5_flow_hw_actions_validate(dev, attr, actions, masks, + &action_flags, error)) return NULL; - if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS && - priv->sh->config.dv_esw_en) { - /* Application should make sure only one Q/RSS exist in one rule. */ - if (flow_hw_action_meta_copy_insert(actions, masks, &rx_cpy, &rx_cpy_mask, - tmp_action, tmp_mask, &pos)) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, NULL, - "Failed to concatenate new action/mask"); - return NULL; - } else if (pos != UINT16_MAX) { - ra = tmp_action; - rm = tmp_mask; - } - } for (i = 0; ra[i].type != RTE_FLOW_ACTION_TYPE_END; ++i) { switch (ra[i].type) { /* OF_PUSH_VLAN *MUST* come before OF_SET_VLAN_VID */ @@ -3786,6 +4252,29 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Too many actions"); return NULL; } + if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS && + priv->sh->config.dv_esw_en && + (action_flags & + (RTE_FLOW_ACTION_TYPE_QUEUE | RTE_FLOW_ACTION_TYPE_RSS))) { + /* Insert META copy */ + if (act_num + 1 > MLX5_HW_MAX_ACTS) { + rte_flow_error_set(error, E2BIG, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, "cannot expand: too many actions"); + return NULL; + } + /* Application should make sure only one Q/RSS exist in one rule. */ + pos = flow_hw_template_expand_modify_field(actions, masks, + &rx_cpy, + &rx_cpy_mask, + tmp_action, tmp_mask, + action_flags, + act_num); + ra = tmp_action; + rm = tmp_mask; + act_num++; + action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD; + } if (set_vlan_vid_ix != -1) { /* If temporary action buffer was not used, copy template actions to it */ if (ra == actions && rm == masks) { @@ -3856,6 +4345,7 @@ flow_hw_actions_template_create(struct rte_eth_dev *dev, at->tmpl = flow_hw_dr_actions_template_create(at); if (!at->tmpl) goto error; + at->action_flags = action_flags; __atomic_fetch_add(&at->refcnt, 1, __ATOMIC_RELAXED); LIST_INSERT_HEAD(&priv->flow_hw_at, at, next); return at; @@ -4199,6 +4689,7 @@ flow_hw_info_get(struct rte_eth_dev *dev, struct rte_flow_queue_info *queue_info, struct rte_flow_error *error __rte_unused) { + struct mlx5_priv *priv = dev->data->dev_private; uint16_t port_id = dev->data->port_id; struct rte_mtr_capabilities mtr_cap; int ret; @@ -4215,6 +4706,8 @@ flow_hw_info_get(struct rte_eth_dev *dev, port_info->max_nb_meter_profiles = UINT32_MAX; port_info->max_nb_meter_policies = UINT32_MAX; } + port_info->max_nb_counters = priv->sh->hws_max_nb_counters; + port_info->max_nb_aging_objects = port_info->max_nb_counters; return 0; } @@ -5593,8 +6086,6 @@ flow_hw_configure(struct rte_eth_dev *dev, goto err; } } - if (_queue_attr) - mlx5_free(_queue_attr); if (port_attr->nb_conn_tracks) { mem_size = sizeof(struct mlx5_aso_sq) * nb_q_updated + sizeof(*priv->ct_mng); @@ -5611,13 +6102,35 @@ flow_hw_configure(struct rte_eth_dev *dev, } if (port_attr->nb_counters) { priv->hws_cpool = mlx5_hws_cnt_pool_create(dev, port_attr, - nb_queue); + nb_queue); if (priv->hws_cpool == NULL) goto err; } + if (port_attr->nb_aging_objects) { + if (port_attr->nb_counters == 0) { + /* + * Aging management uses counter. Number counters + * requesting should take into account a counter for + * each flow rules containing AGE without counter. + */ + DRV_LOG(ERR, "Port %u AGE objects are requested (%u) " + "without counters requesting.", + dev->data->port_id, + port_attr->nb_aging_objects); + rte_errno = EINVAL; + goto err; + } + ret = mlx5_hws_age_pool_init(dev, port_attr, nb_queue); + if (ret < 0) + goto err; + } ret = flow_hw_create_vlan(dev); if (ret) goto err; + if (_queue_attr) + mlx5_free(_queue_attr); + if (port_attr->flags & RTE_FLOW_PORT_FLAG_STRICT_QUEUE) + priv->hws_strict_queue = 1; return 0; err: if (priv->hws_ctpool) { @@ -5628,6 +6141,10 @@ flow_hw_configure(struct rte_eth_dev *dev, flow_hw_ct_mng_destroy(dev, priv->ct_mng); priv->ct_mng = NULL; } + if (priv->hws_age_req) + mlx5_hws_age_pool_destroy(priv); + if (priv->hws_cpool) + mlx5_hws_cnt_pool_destroy(priv->sh, priv->hws_cpool); flow_hw_free_vport_actions(priv); for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) { if (priv->hw_drop[i]) @@ -5701,6 +6218,8 @@ flow_hw_resource_release(struct rte_eth_dev *dev) mlx5_ipool_destroy(priv->acts_ipool); priv->acts_ipool = NULL; } + if (priv->hws_age_req) + mlx5_hws_age_pool_destroy(priv); if (priv->hws_cpool) mlx5_hws_cnt_pool_destroy(priv->sh, priv->hws_cpool); if (priv->hws_ctpool) { @@ -6037,13 +6556,53 @@ flow_hw_conntrack_create(struct rte_eth_dev *dev, uint32_t queue, MLX5_ACTION_CTX_CT_GEN_IDX(PORT_ID(priv), ct_idx); } +/** + * Validate shared action. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[in] queue + * Which queue to be used. + * @param[in] attr + * Operation attribute. + * @param[in] conf + * Indirect action configuration. + * @param[in] action + * rte_flow action detail. + * @param[in] user_data + * Pointer to the user_data. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, otherwise negative errno value. + */ +static int +flow_hw_action_handle_validate(struct rte_eth_dev *dev, uint32_t queue, + const struct rte_flow_op_attr *attr, + const struct rte_flow_indir_action_conf *conf, + const struct rte_flow_action *action, + void *user_data, + struct rte_flow_error *error) +{ + RTE_SET_USED(attr); + RTE_SET_USED(queue); + RTE_SET_USED(user_data); + switch (action->type) { + case RTE_FLOW_ACTION_TYPE_METER_MARK: + return flow_hw_validate_action_meter_mark(dev, action, error); + default: + return flow_dv_action_validate(dev, conf, action, error); + } +} + /** * Create shared action. * * @param[in] dev * Pointer to the rte_eth_dev structure. * @param[in] queue - * Which queue to be used.. + * Which queue to be used. * @param[in] attr * Operation attribute. * @param[in] conf @@ -6068,16 +6627,32 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, { struct rte_flow_action_handle *handle = NULL; struct mlx5_priv *priv = dev->data->dev_private; + const struct rte_flow_action_age *age; struct mlx5_aso_mtr *aso_mtr; cnt_id_t cnt_id; uint32_t mtr_id; + uint32_t age_idx; - RTE_SET_USED(queue); RTE_SET_USED(attr); RTE_SET_USED(user_data); switch (action->type) { + case RTE_FLOW_ACTION_TYPE_AGE: + age = action->conf; + age_idx = mlx5_hws_age_action_create(priv, queue, true, age, + 0, error); + if (age_idx == 0) { + rte_flow_error_set(error, ENODEV, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "AGE are not configured!"); + } else { + age_idx = (MLX5_INDIRECT_ACTION_TYPE_AGE << + MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx; + handle = + (struct rte_flow_action_handle *)(uintptr_t)age_idx; + } + break; case RTE_FLOW_ACTION_TYPE_COUNT: - if (mlx5_hws_cnt_shared_get(priv->hws_cpool, &cnt_id)) + if (mlx5_hws_cnt_shared_get(priv->hws_cpool, &cnt_id, 0)) rte_flow_error_set(error, ENODEV, RTE_FLOW_ERROR_TYPE_ACTION, NULL, @@ -6097,8 +6672,13 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, MLX5_INDIRECT_ACTION_TYPE_OFFSET) | (aso_mtr->fm.meter_id); handle = (struct rte_flow_action_handle *)(uintptr_t)mtr_id; break; - default: + case RTE_FLOW_ACTION_TYPE_RSS: handle = flow_dv_action_create(dev, conf, action, error); + break; + default: + rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, + NULL, "action type not supported"); + return NULL; } return handle; } @@ -6109,7 +6689,7 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, * @param[in] dev * Pointer to the rte_eth_dev structure. * @param[in] queue - * Which queue to be used.. + * Which queue to be used. * @param[in] attr * Operation attribute. * @param[in] handle @@ -6132,7 +6712,6 @@ flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue, void *user_data, struct rte_flow_error *error) { - RTE_SET_USED(queue); RTE_SET_USED(attr); RTE_SET_USED(user_data); struct mlx5_priv *priv = dev->data->dev_private; @@ -6147,6 +6726,8 @@ flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue, uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); switch (type) { + case MLX5_INDIRECT_ACTION_TYPE_AGE: + return mlx5_hws_age_action_update(priv, idx, update, error); case MLX5_INDIRECT_ACTION_TYPE_CT: return flow_hw_conntrack_update(dev, queue, update, act_idx, error); case MLX5_INDIRECT_ACTION_TYPE_METER_MARK: @@ -6180,11 +6761,15 @@ flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue, return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Unable to wait for ASO meter CQE"); - return 0; - default: break; + case MLX5_INDIRECT_ACTION_TYPE_RSS: + return flow_dv_action_update(dev, handle, update, error); + default: + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "action type not supported"); } - return flow_dv_action_update(dev, handle, update, error); + return 0; } /** @@ -6193,7 +6778,7 @@ flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue, * @param[in] dev * Pointer to the rte_eth_dev structure. * @param[in] queue - * Which queue to be used.. + * Which queue to be used. * @param[in] attr * Operation attribute. * @param[in] handle @@ -6215,6 +6800,7 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, { uint32_t act_idx = (uint32_t)(uintptr_t)handle; uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; + uint32_t age_idx = act_idx & MLX5_HWS_AGE_IDX_MASK; uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; @@ -6225,7 +6811,16 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, RTE_SET_USED(attr); RTE_SET_USED(user_data); switch (type) { + case MLX5_INDIRECT_ACTION_TYPE_AGE: + return mlx5_hws_age_action_destroy(priv, age_idx, error); case MLX5_INDIRECT_ACTION_TYPE_COUNT: + age_idx = mlx5_hws_cnt_age_get(priv->hws_cpool, act_idx); + if (age_idx != 0) + /* + * If this counter belongs to indirect AGE, here is the + * time to update the AGE. + */ + mlx5_hws_age_nb_cnt_decrease(priv, age_idx); return mlx5_hws_cnt_shared_put(priv->hws_cpool, &act_idx); case MLX5_INDIRECT_ACTION_TYPE_CT: return flow_hw_conntrack_destroy(dev, act_idx, error); @@ -6250,10 +6845,15 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Unable to wait for ASO meter CQE"); mlx5_ipool_free(pool->idx_pool, idx); - return 0; - default: + break; + case MLX5_INDIRECT_ACTION_TYPE_RSS: return flow_dv_action_destroy(dev, handle, error); + default: + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "action type not supported"); } + return 0; } static int @@ -6263,13 +6863,14 @@ flow_hw_query_counter(const struct rte_eth_dev *dev, uint32_t counter, struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_hws_cnt *cnt; struct rte_flow_query_count *qc = data; - uint32_t iidx = mlx5_hws_cnt_iidx(priv->hws_cpool, counter); + uint32_t iidx; uint64_t pkts, bytes; if (!mlx5_hws_cnt_id_valid(counter)) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "counter are not available"); + iidx = mlx5_hws_cnt_iidx(priv->hws_cpool, counter); cnt = &priv->hws_cpool->pool[iidx]; __hws_cnt_query_raw(priv->hws_cpool, counter, &pkts, &bytes); qc->hits_set = 1; @@ -6283,12 +6884,64 @@ flow_hw_query_counter(const struct rte_eth_dev *dev, uint32_t counter, return 0; } +/** + * Query a flow rule AGE action for aging information. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] age_idx + * Index of AGE action parameter. + * @param[out] data + * Data retrieved by the query. + * @param[out] error + * Perform verbose error reporting if not NULL. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ static int -flow_hw_query(struct rte_eth_dev *dev, - struct rte_flow *flow __rte_unused, - const struct rte_flow_action *actions __rte_unused, - void *data __rte_unused, - struct rte_flow_error *error __rte_unused) +flow_hw_query_age(const struct rte_eth_dev *dev, uint32_t age_idx, void *data, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct mlx5_indexed_pool *ipool = age_info->ages_ipool; + struct mlx5_hws_age_param *param = mlx5_ipool_get(ipool, age_idx); + struct rte_flow_query_age *resp = data; + + if (!param || !param->timeout) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "age data not available"); + switch (__atomic_load_n(¶m->state, __ATOMIC_RELAXED)) { + case HWS_AGE_AGED_OUT_REPORTED: + case HWS_AGE_AGED_OUT_NOT_REPORTED: + resp->aged = 1; + break; + case HWS_AGE_CANDIDATE: + case HWS_AGE_CANDIDATE_INSIDE_RING: + resp->aged = 0; + break; + case HWS_AGE_FREE: + /* + * When state is FREE the flow itself should be invalid. + * Fall-through. + */ + default: + MLX5_ASSERT(0); + break; + } + resp->sec_since_last_hit_valid = !resp->aged; + if (resp->sec_since_last_hit_valid) + resp->sec_since_last_hit = __atomic_load_n + (¶m->sec_since_last_hit, __ATOMIC_RELAXED); + return 0; +} + +static int +flow_hw_query(struct rte_eth_dev *dev, struct rte_flow *flow, + const struct rte_flow_action *actions, void *data, + struct rte_flow_error *error) { int ret = -EINVAL; struct rte_flow_hw *hw_flow = (struct rte_flow_hw *)flow; @@ -6299,7 +6952,11 @@ flow_hw_query(struct rte_eth_dev *dev, break; case RTE_FLOW_ACTION_TYPE_COUNT: ret = flow_hw_query_counter(dev, hw_flow->cnt_id, data, - error); + error); + break; + case RTE_FLOW_ACTION_TYPE_AGE: + ret = flow_hw_query_age(dev, hw_flow->age_idx, data, + error); break; default: return rte_flow_error_set(error, ENOTSUP, @@ -6311,6 +6968,32 @@ flow_hw_query(struct rte_eth_dev *dev, return ret; } +/** + * Validate indirect action. + * + * @param[in] dev + * Pointer to the Ethernet device structure. + * @param[in] conf + * Shared action configuration. + * @param[in] action + * Action specification used to create indirect action. + * @param[out] error + * Perform verbose error reporting if not NULL. Initialized in case of + * error only. + * + * @return + * 0 on success, otherwise negative errno value. + */ +static int +flow_hw_action_validate(struct rte_eth_dev *dev, + const struct rte_flow_indir_action_conf *conf, + const struct rte_flow_action *action, + struct rte_flow_error *err) +{ + return flow_hw_action_handle_validate(dev, MLX5_HW_INV_QUEUE, NULL, + conf, action, NULL, err); +} + /** * Create indirect action. * @@ -6334,6 +7017,12 @@ flow_hw_action_create(struct rte_eth_dev *dev, const struct rte_flow_action *action, struct rte_flow_error *err) { + struct mlx5_priv *priv = dev->data->dev_private; + + if (priv->hws_strict_queue) + DRV_LOG(WARNING, + "port %u create indirect action called in strict queue mode.", + dev->data->port_id); return flow_hw_action_handle_create(dev, MLX5_HW_INV_QUEUE, NULL, conf, action, NULL, err); } @@ -6400,17 +7089,118 @@ flow_hw_action_query(struct rte_eth_dev *dev, { uint32_t act_idx = (uint32_t)(uintptr_t)handle; uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; + uint32_t age_idx = act_idx & MLX5_HWS_AGE_IDX_MASK; switch (type) { + case MLX5_INDIRECT_ACTION_TYPE_AGE: + return flow_hw_query_age(dev, age_idx, data, error); case MLX5_INDIRECT_ACTION_TYPE_COUNT: return flow_hw_query_counter(dev, act_idx, data, error); case MLX5_INDIRECT_ACTION_TYPE_CT: return flow_hw_conntrack_query(dev, act_idx, data, error); - default: + case MLX5_INDIRECT_ACTION_TYPE_RSS: return flow_dv_action_query(dev, handle, data, error); + default: + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ACTION, NULL, + "action type not supported"); } } +/** + * Get aged-out flows of a given port on the given HWS flow queue. + * + * @param[in] dev + * Pointer to the Ethernet device structure. + * @param[in] queue_id + * Flow queue to query. Ignored when RTE_FLOW_PORT_FLAG_STRICT_QUEUE not set. + * @param[in, out] contexts + * The address of an array of pointers to the aged-out flows contexts. + * @param[in] nb_contexts + * The length of context array pointers. + * @param[out] error + * Perform verbose error reporting if not NULL. Initialized in case of + * error only. + * + * @return + * if nb_contexts is 0, return the amount of all aged contexts. + * if nb_contexts is not 0 , return the amount of aged flows reported + * in the context array, otherwise negative errno value. + */ +static int +flow_hw_get_q_aged_flows(struct rte_eth_dev *dev, uint32_t queue_id, + void **contexts, uint32_t nb_contexts, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct rte_ring *r; + int nb_flows = 0; + + if (nb_contexts && !contexts) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "empty context"); + if (priv->hws_strict_queue) { + if (queue_id >= age_info->hw_q_age->nb_rings) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "invalid queue id"); + r = age_info->hw_q_age->aged_lists[queue_id]; + } else { + r = age_info->hw_age.aged_list; + MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER); + } + if (nb_contexts == 0) + return rte_ring_count(r); + while ((uint32_t)nb_flows < nb_contexts) { + uint32_t age_idx; + + if (rte_ring_dequeue_elem(r, &age_idx, sizeof(uint32_t)) < 0) + break; + /* get the AGE context if the aged-out index is still valid. */ + contexts[nb_flows] = mlx5_hws_age_context_get(priv, age_idx); + if (!contexts[nb_flows]) + continue; + nb_flows++; + } + return nb_flows; +} + +/** + * Get aged-out flows. + * + * This function is relevant only if RTE_FLOW_PORT_FLAG_STRICT_QUEUE isn't set. + * + * @param[in] dev + * Pointer to the Ethernet device structure. + * @param[in] contexts + * The address of an array of pointers to the aged-out flows contexts. + * @param[in] nb_contexts + * The length of context array pointers. + * @param[out] error + * Perform verbose error reporting if not NULL. Initialized in case of + * error only. + * + * @return + * how many contexts get in success, otherwise negative errno value. + * if nb_contexts is 0, return the amount of all aged contexts. + * if nb_contexts is not 0 , return the amount of aged flows reported + * in the context array. + */ +static int +flow_hw_get_aged_flows(struct rte_eth_dev *dev, void **contexts, + uint32_t nb_contexts, struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + if (priv->hws_strict_queue) + DRV_LOG(WARNING, + "port %u get aged flows called in strict queue mode.", + dev->data->port_id); + return flow_hw_get_q_aged_flows(dev, 0, contexts, nb_contexts, error); +} + const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .info_get = flow_hw_info_get, .configure = flow_hw_configure, @@ -6429,12 +7219,14 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .async_action_create = flow_hw_action_handle_create, .async_action_destroy = flow_hw_action_handle_destroy, .async_action_update = flow_hw_action_handle_update, - .action_validate = flow_dv_action_validate, + .action_validate = flow_hw_action_validate, .action_create = flow_hw_action_create, .action_destroy = flow_hw_action_destroy, .action_update = flow_hw_action_update, .action_query = flow_hw_action_query, .query = flow_hw_query, + .get_aged_flows = flow_hw_get_aged_flows, + .get_q_aged_flows = flow_hw_get_q_aged_flows, }; /** diff --git a/drivers/net/mlx5/mlx5_flow_verbs.c b/drivers/net/mlx5/mlx5_flow_verbs.c index 7ffaf4c227..81a33ddf09 100644 --- a/drivers/net/mlx5/mlx5_flow_verbs.c +++ b/drivers/net/mlx5/mlx5_flow_verbs.c @@ -122,7 +122,7 @@ flow_verbs_counter_get_by_idx(struct rte_eth_dev *dev, struct mlx5_flow_counter_pool **ppool) { struct mlx5_priv *priv = dev->data->dev_private; - struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; + struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; struct mlx5_flow_counter_pool *pool; idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1); @@ -215,7 +215,7 @@ static uint32_t flow_verbs_counter_new(struct rte_eth_dev *dev, uint32_t id __rte_unused) { struct mlx5_priv *priv = dev->data->dev_private; - struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng; + struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng; struct mlx5_flow_counter_pool *pool = NULL; struct mlx5_flow_counter *cnt = NULL; uint32_t n_valid = cmng->n_valid; diff --git a/drivers/net/mlx5/mlx5_hws_cnt.c b/drivers/net/mlx5/mlx5_hws_cnt.c index e2408ef36d..6eab58aa9c 100644 --- a/drivers/net/mlx5/mlx5_hws_cnt.c +++ b/drivers/net/mlx5/mlx5_hws_cnt.c @@ -8,6 +8,7 @@ #include #include #include +#include #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) @@ -26,8 +27,8 @@ __hws_cnt_id_load(struct mlx5_hws_cnt_pool *cpool) uint32_t preload; uint32_t q_num = cpool->cache->q_num; uint32_t cnt_num = mlx5_hws_cnt_pool_get_size(cpool); - cnt_id_t cnt_id, iidx = 0; - uint32_t qidx; + cnt_id_t cnt_id; + uint32_t qidx, iidx = 0; struct rte_ring *qcache = NULL; /* @@ -86,6 +87,174 @@ __mlx5_hws_cnt_svc(struct mlx5_dev_ctx_shared *sh, } while (reset_cnt_num > 0); } +/** + * Release AGE parameter. + * + * @param priv + * Pointer to the port private data structure. + * @param own_cnt_index + * Counter ID to created only for this AGE to release. + * Zero means there is no such counter. + * @param age_ipool + * Pointer to AGE parameter indexed pool. + * @param idx + * Index of AGE parameter in the indexed pool. + */ +static void +mlx5_hws_age_param_free(struct mlx5_priv *priv, cnt_id_t own_cnt_index, + struct mlx5_indexed_pool *age_ipool, uint32_t idx) +{ + if (own_cnt_index) { + struct mlx5_hws_cnt_pool *cpool = priv->hws_cpool; + + MLX5_ASSERT(mlx5_hws_cnt_is_shared(cpool, own_cnt_index)); + mlx5_hws_cnt_shared_put(cpool, &own_cnt_index); + } + mlx5_ipool_free(age_ipool, idx); +} + +/** + * Check and callback event for new aged flow in the HWS counter pool. + * + * @param[in] priv + * Pointer to port private object. + * @param[in] cpool + * Pointer to current counter pool. + */ +static void +mlx5_hws_aging_check(struct mlx5_priv *priv, struct mlx5_hws_cnt_pool *cpool) +{ + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct flow_counter_stats *stats = cpool->raw_mng->raw; + struct mlx5_hws_age_param *param; + struct rte_ring *r; + const uint64_t curr_time = MLX5_CURR_TIME_SEC; + const uint32_t time_delta = curr_time - cpool->time_of_last_age_check; + uint32_t nb_alloc_cnts = mlx5_hws_cnt_pool_get_size(cpool); + uint16_t expected1 = HWS_AGE_CANDIDATE; + uint16_t expected2 = HWS_AGE_CANDIDATE_INSIDE_RING; + uint32_t i; + + cpool->time_of_last_age_check = curr_time; + for (i = 0; i < nb_alloc_cnts; ++i) { + uint32_t age_idx = cpool->pool[i].age_idx; + uint64_t hits; + + if (!cpool->pool[i].in_used || age_idx == 0) + continue; + param = mlx5_ipool_get(age_info->ages_ipool, age_idx); + if (unlikely(param == NULL)) { + /* + * When AGE which used indirect counter it is user + * responsibility not using this indirect counter + * without this AGE. + * If this counter is used after the AGE was freed, the + * AGE index is invalid and using it here will cause a + * segmentation fault. + */ + DRV_LOG(WARNING, + "Counter %u is lost his AGE, it is unused.", i); + continue; + } + if (param->timeout == 0) + continue; + switch (__atomic_load_n(¶m->state, __ATOMIC_RELAXED)) { + case HWS_AGE_AGED_OUT_NOT_REPORTED: + case HWS_AGE_AGED_OUT_REPORTED: + /* Already aged-out, no action is needed. */ + continue; + case HWS_AGE_CANDIDATE: + case HWS_AGE_CANDIDATE_INSIDE_RING: + /* This AGE candidate to be aged-out, go to checking. */ + break; + case HWS_AGE_FREE: + /* + * AGE parameter with state "FREE" couldn't be pointed + * by any counter since counter is destroyed first. + * Fall-through. + */ + default: + MLX5_ASSERT(0); + continue; + } + hits = rte_be_to_cpu_64(stats[i].hits); + if (param->nb_cnts == 1) { + if (hits != param->accumulator_last_hits) { + __atomic_store_n(¶m->sec_since_last_hit, 0, + __ATOMIC_RELAXED); + param->accumulator_last_hits = hits; + continue; + } + } else { + param->accumulator_hits += hits; + param->accumulator_cnt++; + if (param->accumulator_cnt < param->nb_cnts) + continue; + param->accumulator_cnt = 0; + if (param->accumulator_last_hits != + param->accumulator_hits) { + __atomic_store_n(¶m->sec_since_last_hit, + 0, __ATOMIC_RELAXED); + param->accumulator_last_hits = + param->accumulator_hits; + param->accumulator_hits = 0; + continue; + } + param->accumulator_hits = 0; + } + if (__atomic_add_fetch(¶m->sec_since_last_hit, time_delta, + __ATOMIC_RELAXED) <= + __atomic_load_n(¶m->timeout, __ATOMIC_RELAXED)) + continue; + /* Prepare the relevant ring for this AGE parameter */ + if (priv->hws_strict_queue) + r = age_info->hw_q_age->aged_lists[param->queue_id]; + else + r = age_info->hw_age.aged_list; + /* Changing the state atomically and insert it into the ring. */ + if (__atomic_compare_exchange_n(¶m->state, &expected1, + HWS_AGE_AGED_OUT_NOT_REPORTED, + false, __ATOMIC_RELAXED, + __ATOMIC_RELAXED)) { + int ret = rte_ring_enqueue_burst_elem(r, &age_idx, + sizeof(uint32_t), + 1, NULL); + + /* + * The ring doesn't have enough room for this entry, + * it replace back the state for the next second. + * + * FIXME: if until next sec it get traffic, we are going + * to lose this "aged out", will be fixed later + * when optimise it to fill ring in bulks. + */ + expected2 = HWS_AGE_AGED_OUT_NOT_REPORTED; + if (ret < 0 && + !__atomic_compare_exchange_n(¶m->state, + &expected2, expected1, + false, + __ATOMIC_RELAXED, + __ATOMIC_RELAXED) && + expected2 == HWS_AGE_FREE) + mlx5_hws_age_param_free(priv, + param->own_cnt_index, + age_info->ages_ipool, + age_idx); + /* The event is irrelevant in strict queue mode. */ + if (!priv->hws_strict_queue) + MLX5_AGE_SET(age_info, MLX5_AGE_EVENT_NEW); + } else { + __atomic_compare_exchange_n(¶m->state, &expected2, + HWS_AGE_AGED_OUT_NOT_REPORTED, + false, __ATOMIC_RELAXED, + __ATOMIC_RELAXED); + } + } + /* The event is irrelevant in strict queue mode. */ + if (!priv->hws_strict_queue) + mlx5_age_event_prepare(priv->sh); +} + static void mlx5_hws_cnt_raw_data_free(struct mlx5_dev_ctx_shared *sh, struct mlx5_hws_cnt_raw_data_mng *mng) @@ -104,12 +273,14 @@ mlx5_hws_cnt_raw_data_alloc(struct mlx5_dev_ctx_shared *sh, uint32_t n) struct mlx5_hws_cnt_raw_data_mng *mng = NULL; int ret; size_t sz = n * sizeof(struct flow_counter_stats); + size_t pgsz = rte_mem_page_size(); + MLX5_ASSERT(pgsz > 0); mng = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, sizeof(*mng), 0, SOCKET_ID_ANY); if (mng == NULL) goto error; - mng->raw = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, sz, 0, + mng->raw = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, sz, pgsz, SOCKET_ID_ANY); if (mng->raw == NULL) goto error; @@ -146,6 +317,9 @@ mlx5_hws_cnt_svc(void *opaque) opriv->sh == sh && opriv->hws_cpool != NULL) { __mlx5_hws_cnt_svc(sh, opriv->hws_cpool); + if (opriv->hws_age_req) + mlx5_hws_aging_check(opriv, + opriv->hws_cpool); } } query_cycle = rte_rdtsc() - start_cycle; @@ -158,8 +332,9 @@ mlx5_hws_cnt_svc(void *opaque) } struct mlx5_hws_cnt_pool * -mlx5_hws_cnt_pool_init(const struct mlx5_hws_cnt_pool_cfg *pcfg, - const struct mlx5_hws_cache_param *ccfg) +mlx5_hws_cnt_pool_init(struct mlx5_dev_ctx_shared *sh, + const struct mlx5_hws_cnt_pool_cfg *pcfg, + const struct mlx5_hws_cache_param *ccfg) { char mz_name[RTE_MEMZONE_NAMESIZE]; struct mlx5_hws_cnt_pool *cntp; @@ -185,16 +360,26 @@ mlx5_hws_cnt_pool_init(const struct mlx5_hws_cnt_pool_cfg *pcfg, cntp->cache->preload_sz = ccfg->preload_sz; cntp->cache->threshold = ccfg->threshold; cntp->cache->q_num = ccfg->q_num; + if (pcfg->request_num > sh->hws_max_nb_counters) { + DRV_LOG(ERR, "Counter number %u " + "is greater than the maximum supported (%u).", + pcfg->request_num, sh->hws_max_nb_counters); + goto error; + } cnt_num = pcfg->request_num * (100 + pcfg->alloc_factor) / 100; if (cnt_num > UINT32_MAX) { DRV_LOG(ERR, "counter number %"PRIu64" is out of 32bit range", cnt_num); goto error; } + /* + * When counter request number is supported, but the factor takes it + * out of size, the factor is reduced. + */ + cnt_num = RTE_MIN((uint32_t)cnt_num, sh->hws_max_nb_counters); cntp->pool = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, - sizeof(struct mlx5_hws_cnt) * - pcfg->request_num * (100 + pcfg->alloc_factor) / 100, - 0, SOCKET_ID_ANY); + sizeof(struct mlx5_hws_cnt) * cnt_num, + 0, SOCKET_ID_ANY); if (cntp->pool == NULL) goto error; snprintf(mz_name, sizeof(mz_name), "%s_F_RING", pcfg->name); @@ -231,6 +416,8 @@ mlx5_hws_cnt_pool_init(const struct mlx5_hws_cnt_pool_cfg *pcfg, if (cntp->cache->qcache[qidx] == NULL) goto error; } + /* Initialize the time for aging-out calculation. */ + cntp->time_of_last_age_check = MLX5_CURR_TIME_SEC; return cntp; error: mlx5_hws_cnt_pool_deinit(cntp); @@ -297,19 +484,17 @@ mlx5_hws_cnt_pool_dcs_alloc(struct mlx5_dev_ctx_shared *sh, struct mlx5_hws_cnt_pool *cpool) { struct mlx5_hca_attr *hca_attr = &sh->cdev->config.hca_attr; - uint32_t max_log_bulk_sz = 0; + uint32_t max_log_bulk_sz = sh->hws_max_log_bulk_sz; uint32_t log_bulk_sz; - uint32_t idx, alloced = 0; + uint32_t idx, alloc_candidate, alloced = 0; unsigned int cnt_num = mlx5_hws_cnt_pool_get_size(cpool); struct mlx5_devx_counter_attr attr = {0}; struct mlx5_devx_obj *dcs; if (hca_attr->flow_counter_bulk_log_max_alloc == 0) { - DRV_LOG(ERR, - "Fw doesn't support bulk log max alloc"); + DRV_LOG(ERR, "Fw doesn't support bulk log max alloc"); return -1; } - max_log_bulk_sz = 23; /* hard code to 8M (1 << 23). */ cnt_num = RTE_ALIGN_CEIL(cnt_num, 4); /* minimal 4 counter in bulk. */ log_bulk_sz = RTE_MIN(max_log_bulk_sz, rte_log2_u32(cnt_num)); attr.pd = sh->cdev->pdn; @@ -327,18 +512,23 @@ mlx5_hws_cnt_pool_dcs_alloc(struct mlx5_dev_ctx_shared *sh, cpool->dcs_mng.dcs[0].iidx = 0; alloced = cpool->dcs_mng.dcs[0].batch_sz; if (cnt_num > cpool->dcs_mng.dcs[0].batch_sz) { - for (; idx < MLX5_HWS_CNT_DCS_NUM; idx++) { + while (idx < MLX5_HWS_CNT_DCS_NUM) { attr.flow_counter_bulk_log_size = --max_log_bulk_sz; + alloc_candidate = RTE_BIT32(max_log_bulk_sz); + if (alloced + alloc_candidate > sh->hws_max_nb_counters) + continue; dcs = mlx5_devx_cmd_flow_counter_alloc_general (sh->cdev->ctx, &attr); if (dcs == NULL) goto error; cpool->dcs_mng.dcs[idx].obj = dcs; - cpool->dcs_mng.dcs[idx].batch_sz = - (1 << max_log_bulk_sz); + cpool->dcs_mng.dcs[idx].batch_sz = alloc_candidate; cpool->dcs_mng.dcs[idx].iidx = alloced; alloced += cpool->dcs_mng.dcs[idx].batch_sz; cpool->dcs_mng.batch_total++; + if (alloced >= cnt_num) + break; + idx++; } } return 0; @@ -445,7 +635,7 @@ mlx5_hws_cnt_pool_create(struct rte_eth_dev *dev, dev->data->port_id); pcfg.name = mp_name; pcfg.request_num = pattr->nb_counters; - cpool = mlx5_hws_cnt_pool_init(&pcfg, &cparam); + cpool = mlx5_hws_cnt_pool_init(priv->sh, &pcfg, &cparam); if (cpool == NULL) goto error; ret = mlx5_hws_cnt_pool_dcs_alloc(priv->sh, cpool); @@ -525,4 +715,484 @@ mlx5_hws_cnt_svc_deinit(struct mlx5_dev_ctx_shared *sh) sh->cnt_svc = NULL; } +/** + * Destroy AGE action. + * + * @param priv + * Pointer to the port private data structure. + * @param idx + * Index of AGE parameter. + * @param error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_hws_age_action_destroy(struct mlx5_priv *priv, uint32_t idx, + struct rte_flow_error *error) +{ + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct mlx5_indexed_pool *ipool = age_info->ages_ipool; + struct mlx5_hws_age_param *param = mlx5_ipool_get(ipool, idx); + + if (param == NULL) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "invalid AGE parameter index"); + switch (__atomic_exchange_n(¶m->state, HWS_AGE_FREE, + __ATOMIC_RELAXED)) { + case HWS_AGE_CANDIDATE: + case HWS_AGE_AGED_OUT_REPORTED: + mlx5_hws_age_param_free(priv, param->own_cnt_index, ipool, idx); + break; + case HWS_AGE_AGED_OUT_NOT_REPORTED: + case HWS_AGE_CANDIDATE_INSIDE_RING: + /* + * In both cases AGE is inside the ring. Change the state here + * and destroy it later when it is taken out of ring. + */ + break; + case HWS_AGE_FREE: + /* + * If index is valid and state is FREE, it says this AGE has + * been freed for the user but not for the PMD since it is + * inside the ring. + */ + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "this AGE has already been released"); + default: + MLX5_ASSERT(0); + break; + } + return 0; +} + +/** + * Create AGE action parameter. + * + * @param[in] priv + * Pointer to the port private data structure. + * @param[in] queue_id + * Which HWS queue to be used. + * @param[in] shared + * Whether it indirect AGE action. + * @param[in] flow_idx + * Flow index from indexed pool. + * For indirect AGE action it doesn't affect. + * @param[in] age + * Pointer to the aging action configuration. + * @param[out] error + * Pointer to error structure. + * + * @return + * Index to AGE action parameter on success, 0 otherwise. + */ +uint32_t +mlx5_hws_age_action_create(struct mlx5_priv *priv, uint32_t queue_id, + bool shared, const struct rte_flow_action_age *age, + uint32_t flow_idx, struct rte_flow_error *error) +{ + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct mlx5_indexed_pool *ipool = age_info->ages_ipool; + struct mlx5_hws_age_param *param; + uint32_t age_idx; + + param = mlx5_ipool_malloc(ipool, &age_idx); + if (param == NULL) { + rte_flow_error_set(error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "cannot allocate AGE parameter"); + return 0; + } + MLX5_ASSERT(__atomic_load_n(¶m->state, + __ATOMIC_RELAXED) == HWS_AGE_FREE); + if (shared) { + param->nb_cnts = 0; + param->accumulator_hits = 0; + param->accumulator_cnt = 0; + flow_idx = age_idx; + } else { + param->nb_cnts = 1; + } + param->context = age->context ? age->context : + (void *)(uintptr_t)flow_idx; + param->timeout = age->timeout; + param->queue_id = queue_id; + param->accumulator_last_hits = 0; + param->own_cnt_index = 0; + param->sec_since_last_hit = 0; + param->state = HWS_AGE_CANDIDATE; + return age_idx; +} + +/** + * Update indirect AGE action parameter. + * + * @param[in] priv + * Pointer to the port private data structure. + * @param[in] idx + * Index of AGE parameter. + * @param[in] update + * Update value. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_hws_age_action_update(struct mlx5_priv *priv, uint32_t idx, + const void *update, struct rte_flow_error *error) +{ + const struct rte_flow_update_age *update_ade = update; + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct mlx5_indexed_pool *ipool = age_info->ages_ipool; + struct mlx5_hws_age_param *param = mlx5_ipool_get(ipool, idx); + bool sec_since_last_hit_reset = false; + bool state_update = false; + + if (param == NULL) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "invalid AGE parameter index"); + if (update_ade->timeout_valid) { + uint32_t old_timeout = __atomic_exchange_n(¶m->timeout, + update_ade->timeout, + __ATOMIC_RELAXED); + + if (old_timeout == 0) + sec_since_last_hit_reset = true; + else if (old_timeout < update_ade->timeout || + update_ade->timeout == 0) + /* + * When timeout is increased, aged-out flows might be + * active again and state should be updated accordingly. + * When new timeout is 0, we update the state for not + * reporting aged-out stopped. + */ + state_update = true; + } + if (update_ade->touch) { + sec_since_last_hit_reset = true; + state_update = true; + } + if (sec_since_last_hit_reset) + __atomic_store_n(¶m->sec_since_last_hit, 0, + __ATOMIC_RELAXED); + if (state_update) { + uint16_t expected = HWS_AGE_AGED_OUT_NOT_REPORTED; + + /* + * Change states of aged-out flows to active: + * - AGED_OUT_NOT_REPORTED -> CANDIDATE_INSIDE_RING + * - AGED_OUT_REPORTED -> CANDIDATE + */ + if (!__atomic_compare_exchange_n(¶m->state, &expected, + HWS_AGE_CANDIDATE_INSIDE_RING, + false, __ATOMIC_RELAXED, + __ATOMIC_RELAXED) && + expected == HWS_AGE_AGED_OUT_REPORTED) + __atomic_store_n(¶m->state, HWS_AGE_CANDIDATE, + __ATOMIC_RELAXED); + } + return 0; +} + +/** + * Get the AGE context if the aged-out index is still valid. + * + * @param priv + * Pointer to the port private data structure. + * @param idx + * Index of AGE parameter. + * + * @return + * AGE context if the index is still aged-out, NULL otherwise. + */ +void * +mlx5_hws_age_context_get(struct mlx5_priv *priv, uint32_t idx) +{ + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct mlx5_indexed_pool *ipool = age_info->ages_ipool; + struct mlx5_hws_age_param *param = mlx5_ipool_get(ipool, idx); + uint16_t expected = HWS_AGE_AGED_OUT_NOT_REPORTED; + + MLX5_ASSERT(param != NULL); + if (__atomic_compare_exchange_n(¶m->state, &expected, + HWS_AGE_AGED_OUT_REPORTED, false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED)) + return param->context; + switch (expected) { + case HWS_AGE_FREE: + /* + * This AGE couldn't have been destroyed since it was inside + * the ring. Its state has updated, and now it is actually + * destroyed. + */ + mlx5_hws_age_param_free(priv, param->own_cnt_index, ipool, idx); + break; + case HWS_AGE_CANDIDATE_INSIDE_RING: + __atomic_store_n(¶m->state, HWS_AGE_CANDIDATE, + __ATOMIC_RELAXED); + break; + case HWS_AGE_CANDIDATE: + /* + * Only BG thread pushes to ring and it never pushes this state. + * When AGE inside the ring becomes candidate, it has a special + * state called HWS_AGE_CANDIDATE_INSIDE_RING. + * Fall-through. + */ + case HWS_AGE_AGED_OUT_REPORTED: + /* + * Only this thread (doing query) may write this state, and it + * happens only after the query thread takes it out of the ring. + * Fall-through. + */ + case HWS_AGE_AGED_OUT_NOT_REPORTED: + /* + * In this case the compare return true and function return + * the context immediately. + * Fall-through. + */ + default: + MLX5_ASSERT(0); + break; + } + return NULL; +} + +#ifdef RTE_ARCH_64 +#define MLX5_HWS_AGED_OUT_RING_SIZE_MAX UINT32_MAX +#else +#define MLX5_HWS_AGED_OUT_RING_SIZE_MAX RTE_BIT32(8) +#endif + +/** + * Get the size of aged out ring list for each queue. + * + * The size is one percent of nb_counters divided by nb_queues. + * The ring size must be power of 2, so it align up to power of 2. + * In 32 bit systems, the size is limited by 256. + * + * This function is called when RTE_FLOW_PORT_FLAG_STRICT_QUEUE is on. + * + * @param nb_counters + * Final number of allocated counter in the pool. + * @param nb_queues + * Number of HWS queues in this port. + * + * @return + * Size of aged out ring per queue. + */ +static __rte_always_inline uint32_t +mlx5_hws_aged_out_q_ring_size_get(uint32_t nb_counters, uint32_t nb_queues) +{ + uint32_t size = rte_align32pow2((nb_counters / 100) / nb_queues); + uint32_t max_size = MLX5_HWS_AGED_OUT_RING_SIZE_MAX; + + return RTE_MIN(size, max_size); +} + +/** + * Get the size of the aged out ring list. + * + * The size is one percent of nb_counters. + * The ring size must be power of 2, so it align up to power of 2. + * In 32 bit systems, the size is limited by 256. + * + * This function is called when RTE_FLOW_PORT_FLAG_STRICT_QUEUE is off. + * + * @param nb_counters + * Final number of allocated counter in the pool. + * + * @return + * Size of the aged out ring list. + */ +static __rte_always_inline uint32_t +mlx5_hws_aged_out_ring_size_get(uint32_t nb_counters) +{ + uint32_t size = rte_align32pow2(nb_counters / 100); + uint32_t max_size = MLX5_HWS_AGED_OUT_RING_SIZE_MAX; + + return RTE_MIN(size, max_size); +} + +/** + * Initialize the shared aging list information per port. + * + * @param dev + * Pointer to the rte_eth_dev structure. + * @param nb_queues + * Number of HWS queues. + * @param strict_queue + * Indicator whether is strict_queue mode. + * @param ring_size + * Size of aged-out ring for creation. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +static int +mlx5_hws_age_info_init(struct rte_eth_dev *dev, uint16_t nb_queues, + bool strict_queue, uint32_t ring_size) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + uint32_t flags = RING_F_SP_ENQ | RING_F_SC_DEQ | RING_F_EXACT_SZ; + char mz_name[RTE_MEMZONE_NAMESIZE]; + struct rte_ring *r = NULL; + uint32_t qidx; + + age_info->flags = 0; + if (strict_queue) { + size_t size = sizeof(*age_info->hw_q_age) + + sizeof(struct rte_ring *) * nb_queues; + + age_info->hw_q_age = mlx5_malloc(MLX5_MEM_ANY | MLX5_MEM_ZERO, + size, 0, SOCKET_ID_ANY); + if (age_info->hw_q_age == NULL) + return -ENOMEM; + for (qidx = 0; qidx < nb_queues; ++qidx) { + snprintf(mz_name, sizeof(mz_name), + "port_%u_queue_%u_aged_out_ring", + dev->data->port_id, qidx); + r = rte_ring_create(mz_name, ring_size, SOCKET_ID_ANY, + flags); + if (r == NULL) { + DRV_LOG(ERR, "\"%s\" creation failed: %s", + mz_name, rte_strerror(rte_errno)); + goto error; + } + age_info->hw_q_age->aged_lists[qidx] = r; + DRV_LOG(DEBUG, + "\"%s\" is successfully created (size=%u).", + mz_name, ring_size); + } + age_info->hw_q_age->nb_rings = nb_queues; + } else { + snprintf(mz_name, sizeof(mz_name), "port_%u_aged_out_ring", + dev->data->port_id); + r = rte_ring_create(mz_name, ring_size, SOCKET_ID_ANY, flags); + if (r == NULL) { + DRV_LOG(ERR, "\"%s\" creation failed: %s", mz_name, + rte_strerror(rte_errno)); + return -rte_errno; + } + age_info->hw_age.aged_list = r; + DRV_LOG(DEBUG, "\"%s\" is successfully created (size=%u).", + mz_name, ring_size); + /* In non "strict_queue" mode, initialize the event. */ + MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER); + } + return 0; +error: + MLX5_ASSERT(strict_queue); + while (qidx--) + rte_ring_free(age_info->hw_q_age->aged_lists[qidx]); + rte_free(age_info->hw_q_age); + return -1; +} + +/** + * Destroy the shared aging list information per port. + * + * @param priv + * Pointer to port private object. + */ +static void +mlx5_hws_age_info_destroy(struct mlx5_priv *priv) +{ + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + uint16_t nb_queues = age_info->hw_q_age->nb_rings; + + if (priv->hws_strict_queue) { + uint32_t qidx; + + for (qidx = 0; qidx < nb_queues; ++qidx) + rte_ring_free(age_info->hw_q_age->aged_lists[qidx]); + rte_free(age_info->hw_q_age); + } else { + rte_ring_free(age_info->hw_age.aged_list); + } +} + +/** + * Initialize the aging mechanism per port. + * + * @param dev + * Pointer to the rte_eth_dev structure. + * @param attr + * Port configuration attributes. + * @param nb_queues + * Number of HWS queues. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + */ +int +mlx5_hws_age_pool_init(struct rte_eth_dev *dev, + const struct rte_flow_port_attr *attr, + uint16_t nb_queues) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct mlx5_indexed_pool_config cfg = { + .size = + RTE_CACHE_LINE_ROUNDUP(sizeof(struct mlx5_hws_age_param)), + .need_lock = 1, + .release_mem_en = !!priv->sh->config.reclaim_mode, + .malloc = mlx5_malloc, + .free = mlx5_free, + .type = "mlx5_hws_age_pool", + }; + bool strict_queue = !!(attr->flags & RTE_FLOW_PORT_FLAG_STRICT_QUEUE); + uint32_t nb_alloc_cnts; + uint32_t rsize; + uint32_t nb_ages_updated; + int ret; + + MLX5_ASSERT(priv->hws_cpool); + nb_alloc_cnts = mlx5_hws_cnt_pool_get_size(priv->hws_cpool); + if (strict_queue) { + rsize = mlx5_hws_aged_out_q_ring_size_get(nb_alloc_cnts, + nb_queues); + nb_ages_updated = rsize * nb_queues + attr->nb_aging_objects; + } else { + rsize = mlx5_hws_aged_out_ring_size_get(nb_alloc_cnts); + nb_ages_updated = rsize + attr->nb_aging_objects; + } + ret = mlx5_hws_age_info_init(dev, nb_queues, strict_queue, rsize); + if (ret < 0) + return ret; + cfg.trunk_size = rte_align32pow2(nb_ages_updated); + age_info->ages_ipool = mlx5_ipool_create(&cfg); + if (age_info->ages_ipool == NULL) { + mlx5_hws_age_info_destroy(priv); + rte_errno = ENOMEM; + return -rte_errno; + } + priv->hws_age_req = 1; + return 0; +} + +/** + * Cleanup all aging resources per port. + * + * @param priv + * Pointer to port private object. + */ +void +mlx5_hws_age_pool_destroy(struct mlx5_priv *priv) +{ + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + + MLX5_ASSERT(priv->hws_age_req); + mlx5_ipool_destroy(age_info->ages_ipool); + age_info->ages_ipool = NULL; + mlx5_hws_age_info_destroy(priv); + priv->hws_age_req = 0; +} + #endif diff --git a/drivers/net/mlx5/mlx5_hws_cnt.h b/drivers/net/mlx5/mlx5_hws_cnt.h index 5fab4ba597..e311923f71 100644 --- a/drivers/net/mlx5/mlx5_hws_cnt.h +++ b/drivers/net/mlx5/mlx5_hws_cnt.h @@ -10,26 +10,26 @@ #include "mlx5_flow.h" /* - * COUNTER ID's layout + * HWS COUNTER ID's layout * 3 2 1 0 * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | T | | D | | - * ~ Y | | C | IDX ~ - * | P | | S | | + * | T | | D | | + * ~ Y | | C | IDX ~ + * | P | | S | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * - * Bit 31:30 = TYPE = MLX5_INDIRECT_ACTION_TYPE_COUNT = b'10 + * Bit 31:29 = TYPE = MLX5_INDIRECT_ACTION_TYPE_COUNT = b'10 * Bit 25:24 = DCS index * Bit 23:00 = IDX in this counter belonged DCS bulk. */ -typedef uint32_t cnt_id_t; -#define MLX5_HWS_CNT_DCS_NUM 4 #define MLX5_HWS_CNT_DCS_IDX_OFFSET 24 #define MLX5_HWS_CNT_DCS_IDX_MASK 0x3 #define MLX5_HWS_CNT_IDX_MASK ((1UL << MLX5_HWS_CNT_DCS_IDX_OFFSET) - 1) +#define MLX5_HWS_AGE_IDX_MASK (RTE_BIT32(MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1) + struct mlx5_hws_cnt_dcs { void *dr_action; uint32_t batch_sz; @@ -44,12 +44,22 @@ struct mlx5_hws_cnt_dcs_mng { struct mlx5_hws_cnt { struct flow_counter_stats reset; + bool in_used; /* Indicator whether this counter in used or in pool. */ union { - uint32_t share: 1; - /* - * share will be set to 1 when this counter is used as indirect - * action. Only meaningful when user own this counter. - */ + struct { + uint32_t share:1; + /* + * share will be set to 1 when this counter is used as + * indirect action. + */ + uint32_t age_idx:24; + /* + * When this counter uses for aging, it save the index + * of AGE parameter. For pure counter (without aging) + * this index is zero. + */ + }; + /* This struct is only meaningful when user own this counter. */ uint32_t query_gen_when_free; /* * When PMD own this counter (user put back counter to PMD @@ -96,8 +106,48 @@ struct mlx5_hws_cnt_pool { struct rte_ring *free_list; struct rte_ring *wait_reset_list; struct mlx5_hws_cnt_pool_caches *cache; + uint64_t time_of_last_age_check; } __rte_cache_aligned; +/* HWS AGE status. */ +enum { + HWS_AGE_FREE, /* Initialized state. */ + HWS_AGE_CANDIDATE, /* AGE assigned to flows. */ + HWS_AGE_CANDIDATE_INSIDE_RING, + /* + * AGE assigned to flows but it still in ring. It was aged-out but the + * timeout was changed, so it in ring but stiil candidate. + */ + HWS_AGE_AGED_OUT_REPORTED, + /* + * Aged-out, reported by rte_flow_get_q_aged_flows and wait for destroy. + */ + HWS_AGE_AGED_OUT_NOT_REPORTED, + /* + * Aged-out, inside the aged-out ring. + * wait for rte_flow_get_q_aged_flows and destroy. + */ +}; + +/* HWS counter age parameter. */ +struct mlx5_hws_age_param { + uint32_t timeout; /* Aging timeout in seconds (atomically accessed). */ + uint32_t sec_since_last_hit; + /* Time in seconds since last hit (atomically accessed). */ + uint16_t state; /* AGE state (atomically accessed). */ + uint64_t accumulator_last_hits; + /* Last total value of hits for comparing. */ + uint64_t accumulator_hits; + /* Accumulator for hits coming from several counters. */ + uint32_t accumulator_cnt; + /* Number counters which already updated the accumulator in this sec. */ + uint32_t nb_cnts; /* Number counters used by this AGE. */ + uint32_t queue_id; /* Queue id of the counter. */ + cnt_id_t own_cnt_index; + /* Counter action created specifically for this AGE action. */ + void *context; /* Flow AGE context. */ +} __rte_packed __rte_cache_aligned; + /** * Translate counter id into internal index (start from 0), which can be used * as index of raw/cnt pool. @@ -107,7 +157,7 @@ struct mlx5_hws_cnt_pool { * @return * Internal index */ -static __rte_always_inline cnt_id_t +static __rte_always_inline uint32_t mlx5_hws_cnt_iidx(struct mlx5_hws_cnt_pool *cpool, cnt_id_t cnt_id) { uint8_t dcs_idx = cnt_id >> MLX5_HWS_CNT_DCS_IDX_OFFSET; @@ -139,7 +189,7 @@ mlx5_hws_cnt_id_valid(cnt_id_t cnt_id) * Counter id */ static __rte_always_inline cnt_id_t -mlx5_hws_cnt_id_gen(struct mlx5_hws_cnt_pool *cpool, cnt_id_t iidx) +mlx5_hws_cnt_id_gen(struct mlx5_hws_cnt_pool *cpool, uint32_t iidx) { struct mlx5_hws_cnt_dcs_mng *dcs_mng = &cpool->dcs_mng; uint32_t idx; @@ -344,9 +394,10 @@ mlx5_hws_cnt_pool_put(struct mlx5_hws_cnt_pool *cpool, struct rte_ring_zc_data zcdr = {0}; struct rte_ring *qcache = NULL; unsigned int wb_num = 0; /* cache write-back number. */ - cnt_id_t iidx; + uint32_t iidx; iidx = mlx5_hws_cnt_iidx(cpool, *cnt_id); + cpool->pool[iidx].in_used = false; cpool->pool[iidx].query_gen_when_free = __atomic_load_n(&cpool->query_gen, __ATOMIC_RELAXED); if (likely(queue != NULL)) @@ -388,20 +439,23 @@ mlx5_hws_cnt_pool_put(struct mlx5_hws_cnt_pool *cpool, * A pointer to HWS queue. If null, it means fetch from common pool. * @param cnt_id * A pointer to a cnt_id_t * pointer (counter id) that will be filled. + * @param age_idx + * Index of AGE parameter using this counter, zero means there is no such AGE. + * * @return * - 0: Success; objects taken. * - -ENOENT: Not enough entries in the mempool; no object is retrieved. * - -EAGAIN: counter is not ready; try again. */ static __rte_always_inline int -mlx5_hws_cnt_pool_get(struct mlx5_hws_cnt_pool *cpool, - uint32_t *queue, cnt_id_t *cnt_id) +mlx5_hws_cnt_pool_get(struct mlx5_hws_cnt_pool *cpool, uint32_t *queue, + cnt_id_t *cnt_id, uint32_t age_idx) { unsigned int ret; struct rte_ring_zc_data zcdc = {0}; struct rte_ring *qcache = NULL; - uint32_t query_gen = 0; - cnt_id_t iidx, tmp_cid = 0; + uint32_t iidx, query_gen = 0; + cnt_id_t tmp_cid = 0; if (likely(queue != NULL)) qcache = cpool->cache->qcache[*queue]; @@ -422,6 +476,8 @@ mlx5_hws_cnt_pool_get(struct mlx5_hws_cnt_pool *cpool, __hws_cnt_query_raw(cpool, *cnt_id, &cpool->pool[iidx].reset.hits, &cpool->pool[iidx].reset.bytes); + cpool->pool[iidx].in_used = true; + cpool->pool[iidx].age_idx = age_idx; return 0; } ret = rte_ring_dequeue_zc_burst_elem_start(qcache, sizeof(cnt_id_t), 1, @@ -455,6 +511,8 @@ mlx5_hws_cnt_pool_get(struct mlx5_hws_cnt_pool *cpool, &cpool->pool[iidx].reset.bytes); rte_ring_dequeue_zc_elem_finish(qcache, 1); cpool->pool[iidx].share = 0; + cpool->pool[iidx].in_used = true; + cpool->pool[iidx].age_idx = age_idx; return 0; } @@ -478,16 +536,16 @@ mlx5_hws_cnt_pool_get_action_offset(struct mlx5_hws_cnt_pool *cpool, } static __rte_always_inline int -mlx5_hws_cnt_shared_get(struct mlx5_hws_cnt_pool *cpool, cnt_id_t *cnt_id) +mlx5_hws_cnt_shared_get(struct mlx5_hws_cnt_pool *cpool, cnt_id_t *cnt_id, + uint32_t age_idx) { int ret; uint32_t iidx; - ret = mlx5_hws_cnt_pool_get(cpool, NULL, cnt_id); + ret = mlx5_hws_cnt_pool_get(cpool, NULL, cnt_id, age_idx); if (ret != 0) return ret; iidx = mlx5_hws_cnt_iidx(cpool, *cnt_id); - MLX5_ASSERT(cpool->pool[iidx].share == 0); cpool->pool[iidx].share = 1; return 0; } @@ -513,10 +571,73 @@ mlx5_hws_cnt_is_shared(struct mlx5_hws_cnt_pool *cpool, cnt_id_t cnt_id) return cpool->pool[iidx].share ? true : false; } +static __rte_always_inline void +mlx5_hws_cnt_age_set(struct mlx5_hws_cnt_pool *cpool, cnt_id_t cnt_id, + uint32_t age_idx) +{ + uint32_t iidx = mlx5_hws_cnt_iidx(cpool, cnt_id); + + MLX5_ASSERT(cpool->pool[iidx].share); + cpool->pool[iidx].age_idx = age_idx; +} + +static __rte_always_inline uint32_t +mlx5_hws_cnt_age_get(struct mlx5_hws_cnt_pool *cpool, cnt_id_t cnt_id) +{ + uint32_t iidx = mlx5_hws_cnt_iidx(cpool, cnt_id); + + MLX5_ASSERT(cpool->pool[iidx].share); + return cpool->pool[iidx].age_idx; +} + +static __rte_always_inline cnt_id_t +mlx5_hws_age_cnt_get(struct mlx5_priv *priv, struct mlx5_hws_age_param *param, + uint32_t age_idx) +{ + if (!param->own_cnt_index) { + /* Create indirect counter one for internal usage. */ + if (mlx5_hws_cnt_shared_get(priv->hws_cpool, + ¶m->own_cnt_index, age_idx) < 0) + return 0; + param->nb_cnts++; + } + return param->own_cnt_index; +} + +static __rte_always_inline void +mlx5_hws_age_nb_cnt_increase(struct mlx5_priv *priv, uint32_t age_idx) +{ + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct mlx5_indexed_pool *ipool = age_info->ages_ipool; + struct mlx5_hws_age_param *param = mlx5_ipool_get(ipool, age_idx); + + MLX5_ASSERT(param != NULL); + param->nb_cnts++; +} + +static __rte_always_inline void +mlx5_hws_age_nb_cnt_decrease(struct mlx5_priv *priv, uint32_t age_idx) +{ + struct mlx5_age_info *age_info = GET_PORT_AGE_INFO(priv); + struct mlx5_indexed_pool *ipool = age_info->ages_ipool; + struct mlx5_hws_age_param *param = mlx5_ipool_get(ipool, age_idx); + + if (param != NULL) + param->nb_cnts--; +} + +static __rte_always_inline bool +mlx5_hws_age_is_indirect(uint32_t age_idx) +{ + return (age_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET) == + MLX5_INDIRECT_ACTION_TYPE_AGE ? true : false; +} + /* init HWS counter pool. */ struct mlx5_hws_cnt_pool * -mlx5_hws_cnt_pool_init(const struct mlx5_hws_cnt_pool_cfg *pcfg, - const struct mlx5_hws_cache_param *ccfg); +mlx5_hws_cnt_pool_init(struct mlx5_dev_ctx_shared *sh, + const struct mlx5_hws_cnt_pool_cfg *pcfg, + const struct mlx5_hws_cache_param *ccfg); void mlx5_hws_cnt_pool_deinit(struct mlx5_hws_cnt_pool *cntp); @@ -555,4 +676,28 @@ mlx5_hws_cnt_svc_init(struct mlx5_dev_ctx_shared *sh); void mlx5_hws_cnt_svc_deinit(struct mlx5_dev_ctx_shared *sh); +int +mlx5_hws_age_action_destroy(struct mlx5_priv *priv, uint32_t idx, + struct rte_flow_error *error); + +uint32_t +mlx5_hws_age_action_create(struct mlx5_priv *priv, uint32_t queue_id, + bool shared, const struct rte_flow_action_age *age, + uint32_t flow_idx, struct rte_flow_error *error); + +int +mlx5_hws_age_action_update(struct mlx5_priv *priv, uint32_t idx, + const void *update, struct rte_flow_error *error); + +void * +mlx5_hws_age_context_get(struct mlx5_priv *priv, uint32_t idx); + +int +mlx5_hws_age_pool_init(struct rte_eth_dev *dev, + const struct rte_flow_port_attr *attr, + uint16_t nb_queues); + +void +mlx5_hws_age_pool_destroy(struct mlx5_priv *priv); + #endif /* _MLX5_HWS_CNT_H_ */ From patchwork Fri Sep 30 12:53:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117224 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 89DC5A00C4; Fri, 30 Sep 2022 14:55:47 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 18D2642BC1; Fri, 30 Sep 2022 14:54:24 +0200 (CEST) Received: from NAM12-DM6-obe.outbound.protection.outlook.com (mail-dm6nam12on2057.outbound.protection.outlook.com [40.107.243.57]) by mails.dpdk.org (Postfix) with ESMTP id 7B35C40684 for ; Fri, 30 Sep 2022 14:54:17 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=EymsDMKMrwsqQgFr6zVvpxE+iXFPcu/NzINPeav8R1QvMNtKEy/CkzuSVw9GfVSb7+7pQRbgkaXKo7UYpgHt7CAKAXq8Fmi3fqb55pq8JPzh4zev4Nq8LhcKWXaNXXPMbAV90OaWpeAi8rWBDElHGrJmwZWU0uGQJ1iJeGbbTGWt6j5uV22BkDlrx5aQRFDsfH6p3sOa4y/ABTqdf2opmHnIm6t5Ps2QKK8jx5gLAc6wZpoyyikr1/4HG2YNMEGy4dNUGhdBRI/hQVpaJ2xxsvqIY4JgxvyAJHI5vMRI9rNvpeOFWEg5tGt0mDy3s/9fEvSCCmg6o6FCmIXDl5r+4g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=ZJF/XfaNgHd6DR9bNgT6SgkHsqIsDtRdtOR38a7xEi0=; b=jvRCH08K9DQiJ0RwnpLl3r351TrkxGNrDN1c2KphWqqj3mVxNCc9MEVFTjA5v21QHi4ZupEqViH0apI9eQptst2GmgEbNTx0ZTfxX6p657UbPdDH/NcQUc7k/yOMNkV2UMeb4o0/XF02Jrx+8X/Zn6tm4sKxjD2Kot5omfOwGA7sCYioJKR0HNO73SSNOj2PrxvAt30VgbZ7LBnRgtgE/dGKZyM2FNjou8oH1d8tiY5ighw59AiD7mvydGye6kxAdVs/AXxTbyJJqM7ZL0kGM/iZDcgekjEhnINMUOIH6Sz1WpVbeSCaxRqjW441pwirF7zAbPwYovrtauO6jA+sNg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ZJF/XfaNgHd6DR9bNgT6SgkHsqIsDtRdtOR38a7xEi0=; b=LREUMTdSfpHoNZ2DB/svAgdKzeT3cSsSvKelXfCUoQCwLruyZGwO/RWzQmE6dofpoGTlaTVp9VUAGXovoMMMp0OyVHpY55j17G0c60rbXP4+nAWVXUtsJTZfTVijghoVAc6INAMmKvB+mXqI1nbX3SwngWsrNZWzlnRD1kmmBi5ylE251JL+Ae4KCWrVRVOR+1Tg8pJSdNnOA4TmCXYR4z3zfrn3Bh3xvgzxdBKSahM5tE8+b91hP+sqaJaFUdNWA5IIpOa9aimTlicSqTRm6g4jiLvL4+BgsUaCa8k9jRzJ7RnkQNaXblmt/7petbk5f74Q6PIZF8xir3PkSXRRbw== Received: from DM6PR08CA0047.namprd08.prod.outlook.com (2603:10b6:5:1e0::21) by MW4PR12MB7029.namprd12.prod.outlook.com (2603:10b6:303:1ef::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.19; Fri, 30 Sep 2022 12:54:15 +0000 Received: from DM6NAM11FT081.eop-nam11.prod.protection.outlook.com (2603:10b6:5:1e0:cafe::a1) by DM6PR08CA0047.outlook.office365.com (2603:10b6:5:1e0::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.20 via Frontend Transport; Fri, 30 Sep 2022 12:54:14 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT081.mail.protection.outlook.com (10.13.172.136) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:14 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:54:06 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:54:04 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , Subject: [PATCH v3 14/17] net/mlx5: add async action push and pull support Date: Fri, 30 Sep 2022 15:53:12 +0300 Message-ID: <20220930125315.5079-15-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT081:EE_|MW4PR12MB7029:EE_ X-MS-Office365-Filtering-Correlation-Id: e59340e2-f173-46dd-01f6-08daa2e2e111 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: M7Vfc1vnV+/i91HtwPD6MlASGVs7O9EoMT2WsyrDe/94ZwaOYR5mBZqEXp2otFeAkb3bBZvTZknn1nvnbnXtYaktjSf5UIxImlcpsZIVGMCKgZEH8KmnTbu1fERu0oTw7nm+hm5g8frvZMNSP31IAq1OYmVMdlsnBeEuc2IEzYI7XQ0WKvJEA0Dfe6e5r794SKTYyeurlSqCVzXoB98iPisYZ7mgGUDIxnNwuJ6Mc05WtF7BgfZrDh65SlA/CKZ0ErWh7xZCeveK33Qj+/QSMi5GHBpLS8GIQjrryFmWubCXDRGrZsvTL+TPp2ZerZs6dmgh8IbWVH9f3wDjhaqc2NQB0jJjQHGYUdAJcl3BK6yVKZtg/4Lvqs9lUCfcBlyJ7xTApmqjTOmj4TQd2jgqvoOy5cS24akZ+5tLYEju6HbJv/cwDoww1Y0yIYtjkjaATuiQOdCidoVdpWHp7bRl8oeUk4RcusjRCIXOLZbj41NMfIr9TwYLcr13QyqgQALJqXqShgYu5/cLvAnwOuWWs9LZ2+ImVr4S00M7cqjU6OejHwv+7KL1GOc3/tlc7lB3rEnDu+6nbYIDwGTte1ZE5Qr8yXTTQsySAchW328i2kuGjSFpWHxJa+FPOjCyBdk9qXgR+j2iNdB3eLMdREsSOiKxkQjt7zNOAY5pTeCXE3aQSFtLf8nnZexBWc/TKLSri5+7IY7Dl3CR4pYOtkIq3aCZGjAfBxcaZfXKgXdljuIasFtsYzTCxd2nALyZcLQpV1kJUVbWe5Li4pb2cU1RX2P9Cn21BtGeXQpvbtRqE+E= X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(376002)(136003)(39860400002)(396003)(346002)(451199015)(36840700001)(40470700004)(46966006)(107886003)(8936002)(7696005)(6666004)(30864003)(82310400005)(6286002)(2906002)(7636003)(356005)(26005)(36756003)(41300700001)(47076005)(426003)(5660300002)(4326008)(70586007)(70206006)(82740400003)(336012)(8676002)(83380400001)(186003)(1076003)(16526019)(2616005)(40460700003)(55016003)(86362001)(40480700001)(6636002)(36860700001)(110136005)(54906003)(478600001)(316002)(559001)(579004)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:54:14.7237 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: e59340e2-f173-46dd-01f6-08daa2e2e111 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT081.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW4PR12MB7029 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org The queue based rte_flow_async_action_* functions work same as queue based async flow functions. The operations can be pushed asynchronously, so is the pull. This commit adds the async action missing push and pull support. Signed-off-by: Suanming Mou --- drivers/net/mlx5/mlx5.h | 62 ++++- drivers/net/mlx5/mlx5_flow.c | 45 ++++ drivers/net/mlx5/mlx5_flow.h | 17 ++ drivers/net/mlx5/mlx5_flow_aso.c | 181 +++++++++++-- drivers/net/mlx5/mlx5_flow_dv.c | 7 +- drivers/net/mlx5/mlx5_flow_hw.c | 412 +++++++++++++++++++++++++---- drivers/net/mlx5/mlx5_flow_meter.c | 6 +- 7 files changed, 626 insertions(+), 104 deletions(-) diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index c83157d0da..f6033710aa 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -341,6 +341,8 @@ struct mlx5_lb_ctx { enum { MLX5_HW_Q_JOB_TYPE_CREATE, /* Flow create job type. */ MLX5_HW_Q_JOB_TYPE_DESTROY, /* Flow destroy job type. */ + MLX5_HW_Q_JOB_TYPE_UPDATE, + MLX5_HW_Q_JOB_TYPE_QUERY, }; #define MLX5_HW_MAX_ITEMS (16) @@ -348,12 +350,23 @@ enum { /* HW steering flow management job descriptor. */ struct mlx5_hw_q_job { uint32_t type; /* Job type. */ - struct rte_flow_hw *flow; /* Flow attached to the job. */ + union { + struct rte_flow_hw *flow; /* Flow attached to the job. */ + const void *action; /* Indirect action attached to the job. */ + }; void *user_data; /* Job user data. */ uint8_t *encap_data; /* Encap data. */ struct mlx5_modification_cmd *mhdr_cmd; struct rte_flow_item *items; - struct rte_flow_item_ethdev port_spec; + union { + struct { + /* Pointer to ct query user memory. */ + struct rte_flow_action_conntrack *profile; + /* Pointer to ct ASO query out memory. */ + void *out_data; + } __rte_packed; + struct rte_flow_item_ethdev port_spec; + } __rte_packed; }; /* HW steering job descriptor LIFO pool. */ @@ -361,6 +374,8 @@ struct mlx5_hw_q { uint32_t job_idx; /* Free job index. */ uint32_t size; /* LIFO size. */ struct mlx5_hw_q_job **job; /* LIFO header. */ + struct rte_ring *indir_cq; /* Indirect action SW completion queue. */ + struct rte_ring *indir_iq; /* Indirect action SW in progress queue. */ } __rte_cache_aligned; @@ -569,6 +584,7 @@ struct mlx5_aso_sq_elem { struct mlx5_aso_ct_action *ct; char *query_data; }; + void *user_data; }; }; @@ -578,7 +594,9 @@ struct mlx5_aso_sq { struct mlx5_aso_cq cq; struct mlx5_devx_sq sq_obj; struct mlx5_pmd_mr mr; + volatile struct mlx5_aso_wqe *db; uint16_t pi; + uint16_t db_pi; uint32_t head; uint32_t tail; uint32_t sqn; @@ -993,6 +1011,7 @@ struct mlx5_flow_meter_profile { enum mlx5_aso_mtr_state { ASO_METER_FREE, /* In free list. */ ASO_METER_WAIT, /* ACCESS_ASO WQE in progress. */ + ASO_METER_WAIT_ASYNC, /* CQE will be handled by async pull. */ ASO_METER_READY, /* CQE received. */ }; @@ -1195,6 +1214,7 @@ struct mlx5_bond_info { enum mlx5_aso_ct_state { ASO_CONNTRACK_FREE, /* Inactive, in the free list. */ ASO_CONNTRACK_WAIT, /* WQE sent in the SQ. */ + ASO_CONNTRACK_WAIT_ASYNC, /* CQE will be handled by async pull. */ ASO_CONNTRACK_READY, /* CQE received w/o error. */ ASO_CONNTRACK_QUERY, /* WQE for query sent. */ ASO_CONNTRACK_MAX, /* Guard. */ @@ -1203,13 +1223,21 @@ enum mlx5_aso_ct_state { /* Generic ASO connection tracking structure. */ struct mlx5_aso_ct_action { union { - LIST_ENTRY(mlx5_aso_ct_action) next; - /* Pointer to the next ASO CT. Used only in SWS. */ - struct mlx5_aso_ct_pool *pool; - /* Pointer to action pool. Used only in HWS. */ + /* SWS mode struct. */ + struct { + /* Pointer to the next ASO CT. Used only in SWS. */ + LIST_ENTRY(mlx5_aso_ct_action) next; + }; + /* HWS mode struct. */ + struct { + /* Pointer to action pool. Used only in HWS. */ + struct mlx5_aso_ct_pool *pool; + }; }; - void *dr_action_orig; /* General action object for original dir. */ - void *dr_action_rply; /* General action object for reply dir. */ + /* General action object for original dir. */ + void *dr_action_orig; + /* General action object for reply dir. */ + void *dr_action_rply; uint32_t refcnt; /* Action used count in device flows. */ uint16_t offset; /* Offset of ASO CT in DevX objects bulk. */ uint16_t peer; /* The only peer port index could also use this CT. */ @@ -2135,18 +2163,21 @@ int mlx5_aso_flow_hit_queue_poll_stop(struct mlx5_dev_ctx_shared *sh); void mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh, enum mlx5_access_aso_opc_mod aso_opc_mod); int mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, - struct mlx5_aso_mtr *mtr, - struct mlx5_mtr_bulk *bulk); + struct mlx5_aso_mtr *mtr, struct mlx5_mtr_bulk *bulk, + void *user_data, bool push); int mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_mtr *mtr); int mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct, - const struct rte_flow_action_conntrack *profile); + const struct rte_flow_action_conntrack *profile, + void *user_data, + bool push); int mlx5_aso_ct_wait_ready(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct); int mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct, - struct rte_flow_action_conntrack *profile); + struct rte_flow_action_conntrack *profile, + void *user_data, bool push); int mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct); uint32_t @@ -2154,6 +2185,13 @@ mlx5_get_supported_sw_parsing_offloads(const struct mlx5_hca_attr *attr); uint32_t mlx5_get_supported_tunneling_offloads(const struct mlx5_hca_attr *attr); +void mlx5_aso_ct_obj_analyze(struct rte_flow_action_conntrack *profile, + char *wdata); +void mlx5_aso_push_wqe(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_sq *sq); +int mlx5_aso_pull_completion(struct mlx5_aso_sq *sq, + struct rte_flow_op_result res[], + uint16_t n_res); int mlx5_aso_cnt_queue_init(struct mlx5_dev_ctx_shared *sh); void mlx5_aso_cnt_queue_uninit(struct mlx5_dev_ctx_shared *sh); int mlx5_aso_cnt_query(struct mlx5_dev_ctx_shared *sh, diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 4bfa604578..bc2ccb4d3c 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -979,6 +979,14 @@ mlx5_flow_async_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, void *user_data, struct rte_flow_error *error); +static int +mlx5_flow_async_action_handle_query(struct rte_eth_dev *dev, uint32_t queue, + const struct rte_flow_op_attr *attr, + const struct rte_flow_action_handle *handle, + void *data, + void *user_data, + struct rte_flow_error *error); + static const struct rte_flow_ops mlx5_flow_ops = { .validate = mlx5_flow_validate, .create = mlx5_flow_create, @@ -1015,6 +1023,7 @@ static const struct rte_flow_ops mlx5_flow_ops = { .push = mlx5_flow_push, .async_action_handle_create = mlx5_flow_async_action_handle_create, .async_action_handle_update = mlx5_flow_async_action_handle_update, + .async_action_handle_query = mlx5_flow_async_action_handle_query, .async_action_handle_destroy = mlx5_flow_async_action_handle_destroy, }; @@ -8858,6 +8867,42 @@ mlx5_flow_async_action_handle_update(struct rte_eth_dev *dev, uint32_t queue, update, user_data, error); } +/** + * Query shared action. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[in] queue + * Which queue to be used.. + * @param[in] attr + * Operation attribute. + * @param[in] handle + * Action handle to be updated. + * @param[in] data + * Pointer query result data. + * @param[in] user_data + * Pointer to the user_data. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 on success, negative value otherwise and rte_errno is set. + */ +static int +mlx5_flow_async_action_handle_query(struct rte_eth_dev *dev, uint32_t queue, + const struct rte_flow_op_attr *attr, + const struct rte_flow_action_handle *handle, + void *data, + void *user_data, + struct rte_flow_error *error) +{ + const struct mlx5_flow_driver_ops *fops = + flow_get_drv_ops(MLX5_FLOW_TYPE_HW); + + return fops->async_action_query(dev, queue, attr, handle, + data, user_data, error); +} + /** * Destroy shared action. * diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 30a18ea35e..e45869a890 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -57,6 +57,13 @@ enum mlx5_rte_flow_field_id { #define MLX5_INDIRECT_ACTION_TYPE_OFFSET 29 +#define MLX5_INDIRECT_ACTION_TYPE_GET(handle) \ + (((uint32_t)(uintptr_t)(handle)) >> MLX5_INDIRECT_ACTION_TYPE_OFFSET) + +#define MLX5_INDIRECT_ACTION_IDX_GET(handle) \ + (((uint32_t)(uintptr_t)(handle)) & \ + ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1)) + enum { MLX5_INDIRECT_ACTION_TYPE_RSS, MLX5_INDIRECT_ACTION_TYPE_AGE, @@ -1816,6 +1823,15 @@ typedef int (*mlx5_flow_async_action_handle_update_t) void *user_data, struct rte_flow_error *error); +typedef int (*mlx5_flow_async_action_handle_query_t) + (struct rte_eth_dev *dev, + uint32_t queue, + const struct rte_flow_op_attr *attr, + const struct rte_flow_action_handle *handle, + void *data, + void *user_data, + struct rte_flow_error *error); + typedef int (*mlx5_flow_async_action_handle_destroy_t) (struct rte_eth_dev *dev, uint32_t queue, @@ -1878,6 +1894,7 @@ struct mlx5_flow_driver_ops { mlx5_flow_push_t push; mlx5_flow_async_action_handle_create_t async_action_create; mlx5_flow_async_action_handle_update_t async_action_update; + mlx5_flow_async_action_handle_query_t async_action_query; mlx5_flow_async_action_handle_destroy_t async_action_destroy; }; diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c index f371fff2e2..43ef893e9d 100644 --- a/drivers/net/mlx5/mlx5_flow_aso.c +++ b/drivers/net/mlx5/mlx5_flow_aso.c @@ -519,6 +519,70 @@ mlx5_aso_cqe_err_handle(struct mlx5_aso_sq *sq) (volatile uint32_t *)&sq->sq_obj.aso_wqes[idx]); } +int +mlx5_aso_pull_completion(struct mlx5_aso_sq *sq, + struct rte_flow_op_result res[], + uint16_t n_res) +{ + struct mlx5_aso_cq *cq = &sq->cq; + volatile struct mlx5_cqe *restrict cqe; + const uint32_t cq_size = 1 << cq->log_desc_n; + const uint32_t mask = cq_size - 1; + uint32_t idx; + uint32_t next_idx; + uint16_t max; + uint16_t n = 0; + int ret; + + max = (uint16_t)(sq->head - sq->tail); + if (unlikely(!max || !n_res)) + return 0; + next_idx = cq->cq_ci & mask; + do { + idx = next_idx; + next_idx = (cq->cq_ci + 1) & mask; + /* Need to confirm the position of the prefetch. */ + rte_prefetch0(&cq->cq_obj.cqes[next_idx]); + cqe = &cq->cq_obj.cqes[idx]; + ret = check_cqe(cqe, cq_size, cq->cq_ci); + /* + * Be sure owner read is done before any other cookie field or + * opaque field. + */ + rte_io_rmb(); + if (ret == MLX5_CQE_STATUS_HW_OWN) + break; + res[n].user_data = sq->elts[(uint16_t)((sq->tail + n) & mask)].user_data; + if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) { + mlx5_aso_cqe_err_handle(sq); + res[n].status = RTE_FLOW_OP_ERROR; + } else { + res[n].status = RTE_FLOW_OP_SUCCESS; + } + cq->cq_ci++; + if (++n == n_res) + break; + } while (1); + if (likely(n)) { + sq->tail += n; + rte_io_wmb(); + cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci); + } + return n; +} + +void +mlx5_aso_push_wqe(struct mlx5_dev_ctx_shared *sh, + struct mlx5_aso_sq *sq) +{ + if (sq->db_pi == sq->pi) + return; + mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)sq->db, + sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], + !sh->tx_uar.dbnc); + sq->db_pi = sq->pi; +} + /** * Update ASO objects upon completion. * @@ -728,7 +792,9 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, struct mlx5_aso_sq *sq, struct mlx5_aso_mtr *aso_mtr, struct mlx5_mtr_bulk *bulk, - bool need_lock) + bool need_lock, + void *user_data, + bool push) { volatile struct mlx5_aso_wqe *wqe = NULL; struct mlx5_flow_meter_info *fm = NULL; @@ -754,7 +820,7 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]); /* Fill next WQE. */ fm = &aso_mtr->fm; - sq->elts[sq->head & mask].mtr = aso_mtr; + sq->elts[sq->head & mask].mtr = user_data ? user_data : aso_mtr; if (aso_mtr->type == ASO_METER_INDIRECT) { if (likely(sh->config.dv_flow_en == 2)) pool = aso_mtr->pool; @@ -820,9 +886,13 @@ mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, */ sq->head++; sq->pi += 2;/* Each WQE contains 2 WQEBB's. */ - mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, + if (push) { + mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], !sh->tx_uar.dbnc); + sq->db_pi = sq->pi; + } + sq->db = wqe; if (need_lock) rte_spinlock_unlock(&sq->sqsl); return 1; @@ -912,11 +982,14 @@ mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq, bool need_lock) int mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_mtr *mtr, - struct mlx5_mtr_bulk *bulk) + struct mlx5_mtr_bulk *bulk, + void *user_data, + bool push) { struct mlx5_aso_sq *sq; uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES; bool need_lock; + int ret; if (likely(sh->config.dv_flow_en == 2)) { if (queue == MLX5_HW_INV_QUEUE) { @@ -930,10 +1003,15 @@ mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, sq = &sh->mtrmng->pools_mng.sq; need_lock = true; } + if (queue != MLX5_HW_INV_QUEUE) { + ret = mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk, + need_lock, user_data, push); + return ret > 0 ? 0 : -1; + } do { mlx5_aso_mtr_completion_handle(sq, need_lock); - if (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, - bulk, need_lock)) + if (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk, + need_lock, NULL, true)) return 0; /* Waiting for wqe resource. */ rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY); @@ -962,6 +1040,7 @@ mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, uint32_t queue, { struct mlx5_aso_sq *sq; uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES; + uint8_t state; bool need_lock; if (likely(sh->config.dv_flow_en == 2)) { @@ -976,8 +1055,8 @@ mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, uint32_t queue, sq = &sh->mtrmng->pools_mng.sq; need_lock = true; } - if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) == - ASO_METER_READY) + state = __atomic_load_n(&mtr->state, __ATOMIC_RELAXED); + if (state == ASO_METER_READY || state == ASO_METER_WAIT_ASYNC) return 0; do { mlx5_aso_mtr_completion_handle(sq, need_lock); @@ -1093,7 +1172,9 @@ mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, struct mlx5_aso_sq *sq, struct mlx5_aso_ct_action *ct, const struct rte_flow_action_conntrack *profile, - bool need_lock) + bool need_lock, + void *user_data, + bool push) { volatile struct mlx5_aso_wqe *wqe = NULL; uint16_t size = 1 << sq->log_desc_n; @@ -1117,10 +1198,16 @@ mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, wqe = &sq->sq_obj.aso_wqes[sq->head & mask]; rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]); /* Fill next WQE. */ - MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_WAIT); - sq->elts[sq->head & mask].ct = ct; - sq->elts[sq->head & mask].query_data = NULL; + MLX5_ASO_CT_UPDATE_STATE(ct, + user_data ? ASO_CONNTRACK_WAIT_ASYNC : ASO_CONNTRACK_WAIT); + if (user_data) { + sq->elts[sq->head & mask].user_data = user_data; + } else { + sq->elts[sq->head & mask].ct = ct; + sq->elts[sq->head & mask].query_data = NULL; + } pool = __mlx5_aso_ct_get_pool(sh, ct); + /* Each WQE will have a single CT object. */ wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id + ct->offset); @@ -1200,9 +1287,13 @@ mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh, profile->reply_dir.max_ack); sq->head++; sq->pi += 2; /* Each WQE contains 2 WQEBB's. */ - mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, - sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], - !sh->tx_uar.dbnc); + if (push) { + mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, + sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], + !sh->tx_uar.dbnc); + sq->db_pi = sq->pi; + } + sq->db = wqe; if (need_lock) rte_spinlock_unlock(&sq->sqsl); return 1; @@ -1258,7 +1349,9 @@ static int mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh, struct mlx5_aso_sq *sq, struct mlx5_aso_ct_action *ct, char *data, - bool need_lock) + bool need_lock, + void *user_data, + bool push) { volatile struct mlx5_aso_wqe *wqe = NULL; uint16_t size = 1 << sq->log_desc_n; @@ -1284,14 +1377,23 @@ mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh, DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send"); return 0; } - MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_QUERY); + MLX5_ASO_CT_UPDATE_STATE(ct, + user_data ? ASO_CONNTRACK_WAIT_ASYNC : ASO_CONNTRACK_QUERY); wqe = &sq->sq_obj.aso_wqes[sq->head & mask]; /* Confirm the location and address of the prefetch instruction. */ rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]); /* Fill next WQE. */ wqe_idx = sq->head & mask; - sq->elts[wqe_idx].ct = ct; - sq->elts[wqe_idx].query_data = data; + /* Check if this is async mode. */ + if (user_data) { + struct mlx5_hw_q_job *job = (struct mlx5_hw_q_job *)user_data; + + sq->elts[wqe_idx].ct = user_data; + job->out_data = (char *)((uintptr_t)sq->mr.addr + wqe_idx * 64); + } else { + sq->elts[wqe_idx].query_data = data; + sq->elts[wqe_idx].ct = ct; + } pool = __mlx5_aso_ct_get_pool(sh, ct); /* Each WQE will have a single CT object. */ wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id + @@ -1317,9 +1419,13 @@ mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh, * data segment is not used in this case. */ sq->pi += 2; - mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, - sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], - !sh->tx_uar.dbnc); + if (push) { + mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, + sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], + !sh->tx_uar.dbnc); + sq->db_pi = sq->pi; + } + sq->db = wqe; if (need_lock) rte_spinlock_unlock(&sq->sqsl); return 1; @@ -1405,20 +1511,29 @@ int mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct, - const struct rte_flow_action_conntrack *profile) + const struct rte_flow_action_conntrack *profile, + void *user_data, + bool push) { uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES; struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct); struct mlx5_aso_sq *sq; bool need_lock = !!(queue == MLX5_HW_INV_QUEUE); + int ret; if (sh->config.dv_flow_en == 2) sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool); else sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct); + if (queue != MLX5_HW_INV_QUEUE) { + ret = mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile, + need_lock, user_data, push); + return ret > 0 ? 0 : -1; + } do { - mlx5_aso_ct_completion_handle(sh, sq, need_lock); - if (mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile, need_lock)) + mlx5_aso_ct_completion_handle(sh, sq, need_lock); + if (mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile, + need_lock, NULL, true)) return 0; /* Waiting for wqe resource. */ rte_delay_us_sleep(10u); @@ -1478,7 +1593,7 @@ mlx5_aso_ct_wait_ready(struct mlx5_dev_ctx_shared *sh, uint32_t queue, * @param[in] wdata * Pointer to data fetched from hardware. */ -static inline void +void mlx5_aso_ct_obj_analyze(struct rte_flow_action_conntrack *profile, char *wdata) { @@ -1562,7 +1677,8 @@ int mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue, struct mlx5_aso_ct_action *ct, - struct rte_flow_action_conntrack *profile) + struct rte_flow_action_conntrack *profile, + void *user_data, bool push) { uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES; struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct); @@ -1575,9 +1691,15 @@ mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh, sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool); else sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct); + if (queue != MLX5_HW_INV_QUEUE) { + ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data, + need_lock, user_data, push); + return ret > 0 ? 0 : -1; + } do { mlx5_aso_ct_completion_handle(sh, sq, need_lock); - ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data, need_lock); + ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data, + need_lock, NULL, true); if (ret < 0) return ret; else if (ret > 0) @@ -1628,7 +1750,8 @@ mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh, rte_errno = ENXIO; return -rte_errno; } else if (state == ASO_CONNTRACK_READY || - state == ASO_CONNTRACK_QUERY) { + state == ASO_CONNTRACK_QUERY || + state == ASO_CONNTRACK_WAIT_ASYNC) { return 0; } do { diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 1146e13cfa..d31838e26e 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -13103,7 +13103,7 @@ flow_dv_translate_create_conntrack(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "Failed to allocate CT object"); ct = flow_aso_ct_get_by_dev_idx(dev, idx); - if (mlx5_aso_ct_update_by_wqe(sh, MLX5_HW_INV_QUEUE, ct, pro)) { + if (mlx5_aso_ct_update_by_wqe(sh, MLX5_HW_INV_QUEUE, ct, pro, NULL, true)) { flow_dv_aso_ct_dev_release(dev, idx); rte_flow_error_set(error, EBUSY, RTE_FLOW_ERROR_TYPE_ACTION, NULL, @@ -15917,7 +15917,7 @@ __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx, if (ret) return ret; ret = mlx5_aso_ct_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, - ct, new_prf); + ct, new_prf, NULL, true); if (ret) return rte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@ -16753,7 +16753,8 @@ flow_dv_action_query(struct rte_eth_dev *dev, ct->peer; ((struct rte_flow_action_conntrack *)data)->is_original_dir = ct->is_original; - if (mlx5_aso_ct_query_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, ct, data)) + if (mlx5_aso_ct_query_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, ct, + data, NULL, true)) return rte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 161b96cd87..9f70637fcf 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -1178,9 +1178,9 @@ static rte_be32_t vlan_hdr_to_be32(const struct rte_flow_action *actions) } static __rte_always_inline struct mlx5_aso_mtr * -flow_hw_meter_mark_alloc(struct rte_eth_dev *dev, - const struct rte_flow_action *action, - uint32_t queue) +flow_hw_meter_mark_alloc(struct rte_eth_dev *dev, uint32_t queue, + const struct rte_flow_action *action, + void *user_data, bool push) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; @@ -1200,13 +1200,14 @@ flow_hw_meter_mark_alloc(struct rte_eth_dev *dev, fm->is_enable = meter_mark->state; fm->color_aware = meter_mark->color_mode; aso_mtr->pool = pool; - aso_mtr->state = ASO_METER_WAIT; + aso_mtr->state = (queue == MLX5_HW_INV_QUEUE) ? + ASO_METER_WAIT : ASO_METER_WAIT_ASYNC; aso_mtr->offset = mtr_id - 1; aso_mtr->init_color = (meter_mark->color_mode) ? meter_mark->init_color : RTE_COLOR_GREEN; /* Update ASO flow meter by wqe. */ if (mlx5_aso_meter_update_by_wqe(priv->sh, queue, aso_mtr, - &priv->mtr_bulk)) { + &priv->mtr_bulk, user_data, push)) { mlx5_ipool_free(pool->idx_pool, mtr_id); return NULL; } @@ -1231,7 +1232,7 @@ flow_hw_meter_mark_compile(struct rte_eth_dev *dev, struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; struct mlx5_aso_mtr *aso_mtr; - aso_mtr = flow_hw_meter_mark_alloc(dev, action, queue); + aso_mtr = flow_hw_meter_mark_alloc(dev, queue, action, NULL, true); if (!aso_mtr) return -1; @@ -2295,9 +2296,13 @@ flow_hw_actions_construct(struct rte_eth_dev *dev, rte_col_2_mlx5_col(aso_mtr->init_color); break; case RTE_FLOW_ACTION_TYPE_METER_MARK: + /* + * Allocate meter directly will slow down flow + * insertion rate. + */ ret = flow_hw_meter_mark_compile(dev, act_data->action_dst, action, - rule_acts, &job->flow->mtr_id, queue); + rule_acts, &job->flow->mtr_id, MLX5_HW_INV_QUEUE); if (ret != 0) return ret; break; @@ -2604,6 +2609,74 @@ flow_hw_age_count_release(struct mlx5_priv *priv, uint32_t queue, } } +static inline int +__flow_hw_pull_indir_action_comp(struct rte_eth_dev *dev, + uint32_t queue, + struct rte_flow_op_result res[], + uint16_t n_res) + +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_ring *r = priv->hw_q[queue].indir_cq; + struct mlx5_hw_q_job *job; + void *user_data = NULL; + uint32_t type, idx; + struct mlx5_aso_mtr *aso_mtr; + struct mlx5_aso_ct_action *aso_ct; + int ret_comp, i; + + ret_comp = (int)rte_ring_count(r); + if (ret_comp > n_res) + ret_comp = n_res; + for (i = 0; i < ret_comp; i++) { + rte_ring_dequeue(r, &user_data); + res[i].user_data = user_data; + res[i].status = RTE_FLOW_OP_SUCCESS; + } + if (ret_comp < n_res && priv->hws_mpool) + ret_comp += mlx5_aso_pull_completion(&priv->hws_mpool->sq[queue], + &res[ret_comp], n_res - ret_comp); + if (ret_comp < n_res && priv->hws_ctpool) + ret_comp += mlx5_aso_pull_completion(&priv->ct_mng->aso_sqs[queue], + &res[ret_comp], n_res - ret_comp); + for (i = 0; i < ret_comp; i++) { + job = (struct mlx5_hw_q_job *)res[i].user_data; + /* Restore user data. */ + res[i].user_data = job->user_data; + if (job->type == MLX5_HW_Q_JOB_TYPE_DESTROY) { + type = MLX5_INDIRECT_ACTION_TYPE_GET(job->action); + if (type == MLX5_INDIRECT_ACTION_TYPE_METER_MARK) { + idx = MLX5_INDIRECT_ACTION_IDX_GET(job->action); + mlx5_ipool_free(priv->hws_mpool->idx_pool, idx); + } + } else if (job->type == MLX5_HW_Q_JOB_TYPE_CREATE) { + type = MLX5_INDIRECT_ACTION_TYPE_GET(job->action); + if (type == MLX5_INDIRECT_ACTION_TYPE_METER_MARK) { + idx = MLX5_INDIRECT_ACTION_IDX_GET(job->action); + aso_mtr = mlx5_ipool_get(priv->hws_mpool->idx_pool, idx); + aso_mtr->state = ASO_METER_READY; + } else if (type == MLX5_INDIRECT_ACTION_TYPE_CT) { + idx = MLX5_ACTION_CTX_CT_GET_IDX + ((uint32_t)(uintptr_t)job->action); + aso_ct = mlx5_ipool_get(priv->hws_ctpool->cts, idx); + aso_ct->state = ASO_CONNTRACK_READY; + } + } else if (job->type == MLX5_HW_Q_JOB_TYPE_QUERY) { + type = MLX5_INDIRECT_ACTION_TYPE_GET(job->action); + if (type == MLX5_INDIRECT_ACTION_TYPE_CT) { + idx = MLX5_ACTION_CTX_CT_GET_IDX + ((uint32_t)(uintptr_t)job->action); + aso_ct = mlx5_ipool_get(priv->hws_ctpool->cts, idx); + mlx5_aso_ct_obj_analyze(job->profile, + job->out_data); + aso_ct->state = ASO_CONNTRACK_READY; + } + } + priv->hw_q[queue].job[priv->hw_q[queue].job_idx++] = job; + } + return ret_comp; +} + /** * Pull the enqueued flows. * @@ -2636,6 +2709,7 @@ flow_hw_pull(struct rte_eth_dev *dev, struct mlx5_hw_q_job *job; int ret, i; + /* 1. Pull the flow completion. */ ret = mlx5dr_send_queue_poll(priv->dr_ctx, queue, res, n_res); if (ret < 0) return rte_flow_error_set(error, rte_errno, @@ -2661,9 +2735,34 @@ flow_hw_pull(struct rte_eth_dev *dev, } priv->hw_q[queue].job[priv->hw_q[queue].job_idx++] = job; } + /* 2. Pull indirect action comp. */ + if (ret < n_res) + ret += __flow_hw_pull_indir_action_comp(dev, queue, &res[ret], + n_res - ret); return ret; } +static inline void +__flow_hw_push_action(struct rte_eth_dev *dev, + uint32_t queue) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_ring *iq = priv->hw_q[queue].indir_iq; + struct rte_ring *cq = priv->hw_q[queue].indir_cq; + void *job = NULL; + uint32_t ret, i; + + ret = rte_ring_count(iq); + for (i = 0; i < ret; i++) { + rte_ring_dequeue(iq, &job); + rte_ring_enqueue(cq, job); + } + if (priv->hws_ctpool) + mlx5_aso_push_wqe(priv->sh, &priv->ct_mng->aso_sqs[queue]); + if (priv->hws_mpool) + mlx5_aso_push_wqe(priv->sh, &priv->hws_mpool->sq[queue]); +} + /** * Push the enqueued flows to HW. * @@ -2687,6 +2786,7 @@ flow_hw_push(struct rte_eth_dev *dev, struct mlx5_priv *priv = dev->data->dev_private; int ret; + __flow_hw_push_action(dev, queue); ret = mlx5dr_send_queue_action(priv->dr_ctx, queue, MLX5DR_SEND_QUEUE_ACTION_DRAIN); if (ret) { @@ -5944,7 +6044,7 @@ flow_hw_configure(struct rte_eth_dev *dev, /* Adds one queue to be used by PMD. * The last queue will be used by the PMD. */ - uint16_t nb_q_updated; + uint16_t nb_q_updated = 0; struct rte_flow_queue_attr **_queue_attr = NULL; struct rte_flow_queue_attr ctrl_queue_attr = {0}; bool is_proxy = !!(priv->sh->config.dv_esw_en && priv->master); @@ -6011,6 +6111,7 @@ flow_hw_configure(struct rte_eth_dev *dev, goto err; } for (i = 0; i < nb_q_updated; i++) { + char mz_name[RTE_MEMZONE_NAMESIZE]; uint8_t *encap = NULL; struct mlx5_modification_cmd *mhdr_cmd = NULL; struct rte_flow_item *items = NULL; @@ -6038,6 +6139,22 @@ flow_hw_configure(struct rte_eth_dev *dev, job[j].items = &items[j * MLX5_HW_MAX_ITEMS]; priv->hw_q[i].job[j] = &job[j]; } + snprintf(mz_name, sizeof(mz_name), "port_%u_indir_act_cq_%u", + dev->data->port_id, i); + priv->hw_q[i].indir_cq = rte_ring_create(mz_name, + _queue_attr[i]->size, SOCKET_ID_ANY, + RING_F_SP_ENQ | RING_F_SC_DEQ | + RING_F_EXACT_SZ); + if (!priv->hw_q[i].indir_cq) + goto err; + snprintf(mz_name, sizeof(mz_name), "port_%u_indir_act_iq_%u", + dev->data->port_id, i); + priv->hw_q[i].indir_iq = rte_ring_create(mz_name, + _queue_attr[i]->size, SOCKET_ID_ANY, + RING_F_SP_ENQ | RING_F_SC_DEQ | + RING_F_EXACT_SZ); + if (!priv->hw_q[i].indir_iq) + goto err; } dr_ctx_attr.pd = priv->sh->cdev->pd; dr_ctx_attr.queues = nb_q_updated; @@ -6155,6 +6272,12 @@ flow_hw_configure(struct rte_eth_dev *dev, flow_hw_destroy_vlan(dev); if (dr_ctx) claim_zero(mlx5dr_context_close(dr_ctx)); + for (i = 0; i < nb_q_updated; i++) { + if (priv->hw_q[i].indir_iq) + rte_ring_free(priv->hw_q[i].indir_iq); + if (priv->hw_q[i].indir_cq) + rte_ring_free(priv->hw_q[i].indir_cq); + } mlx5_free(priv->hw_q); priv->hw_q = NULL; if (priv->acts_ipool) { @@ -6184,7 +6307,7 @@ flow_hw_resource_release(struct rte_eth_dev *dev) struct rte_flow_template_table *tbl; struct rte_flow_pattern_template *it; struct rte_flow_actions_template *at; - int i; + uint32_t i; if (!priv->dr_ctx) return; @@ -6230,6 +6353,10 @@ flow_hw_resource_release(struct rte_eth_dev *dev) flow_hw_ct_mng_destroy(dev, priv->ct_mng); priv->ct_mng = NULL; } + for (i = 0; i < priv->nb_queue; i++) { + rte_ring_free(priv->hw_q[i].indir_iq); + rte_ring_free(priv->hw_q[i].indir_cq); + } mlx5_free(priv->hw_q); priv->hw_q = NULL; claim_zero(mlx5dr_context_close(priv->dr_ctx)); @@ -6418,8 +6545,9 @@ flow_hw_conntrack_destroy(struct rte_eth_dev *dev __rte_unused, } static int -flow_hw_conntrack_query(struct rte_eth_dev *dev, uint32_t idx, +flow_hw_conntrack_query(struct rte_eth_dev *dev, uint32_t queue, uint32_t idx, struct rte_flow_action_conntrack *profile, + void *user_data, bool push, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; @@ -6443,7 +6571,7 @@ flow_hw_conntrack_query(struct rte_eth_dev *dev, uint32_t idx, } profile->peer_port = ct->peer; profile->is_original_dir = ct->is_original; - if (mlx5_aso_ct_query_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, ct, profile)) + if (mlx5_aso_ct_query_by_wqe(priv->sh, queue, ct, profile, user_data, push)) return rte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, @@ -6455,7 +6583,8 @@ flow_hw_conntrack_query(struct rte_eth_dev *dev, uint32_t idx, static int flow_hw_conntrack_update(struct rte_eth_dev *dev, uint32_t queue, const struct rte_flow_modify_conntrack *action_conf, - uint32_t idx, struct rte_flow_error *error) + uint32_t idx, void *user_data, bool push, + struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_aso_ct_pool *pool = priv->hws_ctpool; @@ -6486,7 +6615,8 @@ flow_hw_conntrack_update(struct rte_eth_dev *dev, uint32_t queue, ret = mlx5_validate_action_ct(dev, new_prf, error); if (ret) return ret; - ret = mlx5_aso_ct_update_by_wqe(priv->sh, queue, ct, new_prf); + ret = mlx5_aso_ct_update_by_wqe(priv->sh, queue, ct, new_prf, + user_data, push); if (ret) return rte_flow_error_set(error, EIO, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@ -6508,6 +6638,7 @@ flow_hw_conntrack_update(struct rte_eth_dev *dev, uint32_t queue, static struct rte_flow_action_handle * flow_hw_conntrack_create(struct rte_eth_dev *dev, uint32_t queue, const struct rte_flow_action_conntrack *pro, + void *user_data, bool push, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; @@ -6534,7 +6665,7 @@ flow_hw_conntrack_create(struct rte_eth_dev *dev, uint32_t queue, ct->is_original = !!pro->is_original_dir; ct->peer = pro->peer_port; ct->pool = pool; - if (mlx5_aso_ct_update_by_wqe(priv->sh, queue, ct, pro)) { + if (mlx5_aso_ct_update_by_wqe(priv->sh, queue, ct, pro, user_data, push)) { mlx5_ipool_free(pool->cts, ct_idx); rte_flow_error_set(error, EBUSY, RTE_FLOW_ERROR_TYPE_ACTION, NULL, @@ -6626,15 +6757,29 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, struct rte_flow_error *error) { struct rte_flow_action_handle *handle = NULL; + struct mlx5_hw_q_job *job = NULL; struct mlx5_priv *priv = dev->data->dev_private; const struct rte_flow_action_age *age; struct mlx5_aso_mtr *aso_mtr; cnt_id_t cnt_id; uint32_t mtr_id; uint32_t age_idx; + bool push = true; + bool aso = false; - RTE_SET_USED(attr); - RTE_SET_USED(user_data); + if (attr) { + MLX5_ASSERT(queue != MLX5_HW_INV_QUEUE); + if (unlikely(!priv->hw_q[queue].job_idx)) { + rte_flow_error_set(error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Flow queue full."); + return NULL; + } + job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx]; + job->type = MLX5_HW_Q_JOB_TYPE_CREATE; + job->user_data = user_data; + push = !attr->postpone; + } switch (action->type) { case RTE_FLOW_ACTION_TYPE_AGE: age = action->conf; @@ -6662,10 +6807,13 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, (uintptr_t)cnt_id; break; case RTE_FLOW_ACTION_TYPE_CONNTRACK: - handle = flow_hw_conntrack_create(dev, queue, action->conf, error); + aso = true; + handle = flow_hw_conntrack_create(dev, queue, action->conf, job, + push, error); break; case RTE_FLOW_ACTION_TYPE_METER_MARK: - aso_mtr = flow_hw_meter_mark_alloc(dev, action, queue); + aso = true; + aso_mtr = flow_hw_meter_mark_alloc(dev, queue, action, job, push); if (!aso_mtr) break; mtr_id = (MLX5_INDIRECT_ACTION_TYPE_METER_MARK << @@ -6678,7 +6826,20 @@ flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue, default: rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "action type not supported"); - return NULL; + break; + } + if (job) { + if (!handle) { + priv->hw_q[queue].job_idx++; + return NULL; + } + job->action = handle; + if (push) + __flow_hw_push_action(dev, queue); + if (aso) + return handle; + rte_ring_enqueue(push ? priv->hw_q[queue].indir_cq : + priv->hw_q[queue].indir_iq, job); } return handle; } @@ -6712,32 +6873,56 @@ flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue, void *user_data, struct rte_flow_error *error) { - RTE_SET_USED(attr); - RTE_SET_USED(user_data); struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; + const struct rte_flow_modify_conntrack *ct_conf = + (const struct rte_flow_modify_conntrack *)update; const struct rte_flow_update_meter_mark *upd_meter_mark = (const struct rte_flow_update_meter_mark *)update; const struct rte_flow_action_meter_mark *meter_mark; + struct mlx5_hw_q_job *job = NULL; struct mlx5_aso_mtr *aso_mtr; struct mlx5_flow_meter_info *fm; uint32_t act_idx = (uint32_t)(uintptr_t)handle; uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); + int ret = 0; + bool push = true; + bool aso = false; + if (attr) { + MLX5_ASSERT(queue != MLX5_HW_INV_QUEUE); + if (unlikely(!priv->hw_q[queue].job_idx)) + return rte_flow_error_set(error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Action update failed due to queue full."); + job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx]; + job->type = MLX5_HW_Q_JOB_TYPE_UPDATE; + job->user_data = user_data; + push = !attr->postpone; + } switch (type) { case MLX5_INDIRECT_ACTION_TYPE_AGE: - return mlx5_hws_age_action_update(priv, idx, update, error); + ret = mlx5_hws_age_action_update(priv, idx, update, error); + break; case MLX5_INDIRECT_ACTION_TYPE_CT: - return flow_hw_conntrack_update(dev, queue, update, act_idx, error); + if (ct_conf->state) + aso = true; + ret = flow_hw_conntrack_update(dev, queue, update, act_idx, + job, push, error); + break; case MLX5_INDIRECT_ACTION_TYPE_METER_MARK: + aso = true; meter_mark = &upd_meter_mark->meter_mark; /* Find ASO object. */ aso_mtr = mlx5_ipool_get(pool->idx_pool, idx); - if (!aso_mtr) - return rte_flow_error_set(error, EINVAL, + if (!aso_mtr) { + ret = -EINVAL; + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Invalid meter_mark update index"); + break; + } fm = &aso_mtr->fm; if (upd_meter_mark->profile_valid) fm->profile = (struct mlx5_flow_meter_profile *) @@ -6751,25 +6936,46 @@ flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue, fm->is_enable = meter_mark->state; /* Update ASO flow meter by wqe. */ if (mlx5_aso_meter_update_by_wqe(priv->sh, queue, - aso_mtr, &priv->mtr_bulk)) - return rte_flow_error_set(error, EINVAL, + aso_mtr, &priv->mtr_bulk, job, push)) { + ret = -EINVAL; + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Unable to update ASO meter WQE"); + break; + } /* Wait for ASO object completion. */ if (queue == MLX5_HW_INV_QUEUE && - mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) - return rte_flow_error_set(error, EINVAL, + mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) { + ret = -EINVAL; + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Unable to wait for ASO meter CQE"); + } break; case MLX5_INDIRECT_ACTION_TYPE_RSS: - return flow_dv_action_update(dev, handle, update, error); + ret = flow_dv_action_update(dev, handle, update, error); + break; default: - return rte_flow_error_set(error, ENOTSUP, + ret = -ENOTSUP; + rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "action type not supported"); + break; } - return 0; + if (job) { + if (ret) { + priv->hw_q[queue].job_idx++; + return ret; + } + job->action = handle; + if (push) + __flow_hw_push_action(dev, queue); + if (aso) + return 0; + rte_ring_enqueue(push ? priv->hw_q[queue].indir_cq : + priv->hw_q[queue].indir_iq, job); + } + return ret; } /** @@ -6804,15 +7010,28 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1); struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; + struct mlx5_hw_q_job *job = NULL; struct mlx5_aso_mtr *aso_mtr; struct mlx5_flow_meter_info *fm; + bool push = true; + bool aso = false; + int ret = 0; - RTE_SET_USED(queue); - RTE_SET_USED(attr); - RTE_SET_USED(user_data); + if (attr) { + MLX5_ASSERT(queue != MLX5_HW_INV_QUEUE); + if (unlikely(!priv->hw_q[queue].job_idx)) + return rte_flow_error_set(error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Action destroy failed due to queue full."); + job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx]; + job->type = MLX5_HW_Q_JOB_TYPE_DESTROY; + job->user_data = user_data; + push = !attr->postpone; + } switch (type) { case MLX5_INDIRECT_ACTION_TYPE_AGE: - return mlx5_hws_age_action_destroy(priv, age_idx, error); + ret = mlx5_hws_age_action_destroy(priv, age_idx, error); + break; case MLX5_INDIRECT_ACTION_TYPE_COUNT: age_idx = mlx5_hws_cnt_age_get(priv->hws_cpool, act_idx); if (age_idx != 0) @@ -6821,39 +7040,69 @@ flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue, * time to update the AGE. */ mlx5_hws_age_nb_cnt_decrease(priv, age_idx); - return mlx5_hws_cnt_shared_put(priv->hws_cpool, &act_idx); + ret = mlx5_hws_cnt_shared_put(priv->hws_cpool, &act_idx); + break; case MLX5_INDIRECT_ACTION_TYPE_CT: - return flow_hw_conntrack_destroy(dev, act_idx, error); + ret = flow_hw_conntrack_destroy(dev, act_idx, error); + break; case MLX5_INDIRECT_ACTION_TYPE_METER_MARK: aso_mtr = mlx5_ipool_get(pool->idx_pool, idx); - if (!aso_mtr) - return rte_flow_error_set(error, EINVAL, + if (!aso_mtr) { + ret = -EINVAL; + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Invalid meter_mark destroy index"); + break; + } fm = &aso_mtr->fm; fm->is_enable = 0; /* Update ASO flow meter by wqe. */ if (mlx5_aso_meter_update_by_wqe(priv->sh, queue, aso_mtr, - &priv->mtr_bulk)) - return rte_flow_error_set(error, EINVAL, + &priv->mtr_bulk, job, push)) { + ret = -EINVAL; + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Unable to update ASO meter WQE"); + break; + } /* Wait for ASO object completion. */ if (queue == MLX5_HW_INV_QUEUE && - mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) - return rte_flow_error_set(error, EINVAL, + mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr)) { + ret = -EINVAL; + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "Unable to wait for ASO meter CQE"); - mlx5_ipool_free(pool->idx_pool, idx); + break; + } + if (!job) + mlx5_ipool_free(pool->idx_pool, idx); + else + aso = true; break; case MLX5_INDIRECT_ACTION_TYPE_RSS: - return flow_dv_action_destroy(dev, handle, error); + ret = flow_dv_action_destroy(dev, handle, error); + break; default: - return rte_flow_error_set(error, ENOTSUP, + ret = -ENOTSUP; + rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "action type not supported"); + break; } - return 0; + if (job) { + if (ret) { + priv->hw_q[queue].job_idx++; + return ret; + } + job->action = handle; + if (push) + __flow_hw_push_action(dev, queue); + if (aso) + return ret; + rte_ring_enqueue(push ? priv->hw_q[queue].indir_cq : + priv->hw_q[queue].indir_iq, job); + } + return ret; } static int @@ -7083,28 +7332,76 @@ flow_hw_action_update(struct rte_eth_dev *dev, } static int -flow_hw_action_query(struct rte_eth_dev *dev, - const struct rte_flow_action_handle *handle, void *data, - struct rte_flow_error *error) +flow_hw_action_handle_query(struct rte_eth_dev *dev, uint32_t queue, + const struct rte_flow_op_attr *attr, + const struct rte_flow_action_handle *handle, + void *data, void *user_data, + struct rte_flow_error *error) { + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_hw_q_job *job = NULL; uint32_t act_idx = (uint32_t)(uintptr_t)handle; uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET; uint32_t age_idx = act_idx & MLX5_HWS_AGE_IDX_MASK; + int ret; + bool push = true; + bool aso = false; + if (attr) { + MLX5_ASSERT(queue != MLX5_HW_INV_QUEUE); + if (unlikely(!priv->hw_q[queue].job_idx)) + return rte_flow_error_set(error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Action destroy failed due to queue full."); + job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx]; + job->type = MLX5_HW_Q_JOB_TYPE_QUERY; + job->user_data = user_data; + push = !attr->postpone; + } switch (type) { case MLX5_INDIRECT_ACTION_TYPE_AGE: - return flow_hw_query_age(dev, age_idx, data, error); + ret = flow_hw_query_age(dev, age_idx, data, error); + break; case MLX5_INDIRECT_ACTION_TYPE_COUNT: - return flow_hw_query_counter(dev, act_idx, data, error); + ret = flow_hw_query_counter(dev, act_idx, data, error); + break; case MLX5_INDIRECT_ACTION_TYPE_CT: - return flow_hw_conntrack_query(dev, act_idx, data, error); - case MLX5_INDIRECT_ACTION_TYPE_RSS: - return flow_dv_action_query(dev, handle, data, error); + aso = true; + if (job) + job->profile = (struct rte_flow_action_conntrack *)data; + ret = flow_hw_conntrack_query(dev, queue, act_idx, data, + job, push, error); + break; default: - return rte_flow_error_set(error, ENOTSUP, + ret = -ENOTSUP; + rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "action type not supported"); + break; + } + if (job) { + if (ret) { + priv->hw_q[queue].job_idx++; + return ret; + } + job->action = handle; + if (push) + __flow_hw_push_action(dev, queue); + if (aso) + return ret; + rte_ring_enqueue(push ? priv->hw_q[queue].indir_cq : + priv->hw_q[queue].indir_iq, job); } + return 0; +} + +static int +flow_hw_action_query(struct rte_eth_dev *dev, + const struct rte_flow_action_handle *handle, void *data, + struct rte_flow_error *error) +{ + return flow_hw_action_handle_query(dev, MLX5_HW_INV_QUEUE, NULL, + handle, data, NULL, error); } /** @@ -7219,6 +7516,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .async_action_create = flow_hw_action_handle_create, .async_action_destroy = flow_hw_action_handle_destroy, .async_action_update = flow_hw_action_handle_update, + .async_action_query = flow_hw_action_handle_query, .action_validate = flow_hw_action_validate, .action_create = flow_hw_action_create, .action_destroy = flow_hw_action_destroy, diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c index fd1337ae73..480ac6c8ec 100644 --- a/drivers/net/mlx5/mlx5_flow_meter.c +++ b/drivers/net/mlx5/mlx5_flow_meter.c @@ -1627,7 +1627,7 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv, fm->is_enable = !!is_enable; aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); ret = mlx5_aso_meter_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, - aso_mtr, &priv->mtr_bulk); + aso_mtr, &priv->mtr_bulk, NULL, true); if (ret) return ret; ret = mlx5_aso_mtr_wait(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr); @@ -1877,7 +1877,7 @@ mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id, if (priv->sh->meter_aso_en) { aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm); ret = mlx5_aso_meter_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, - aso_mtr, &priv->mtr_bulk); + aso_mtr, &priv->mtr_bulk, NULL, true); if (ret) goto error; if (!priv->mtr_idx_tbl) { @@ -1983,7 +1983,7 @@ mlx5_flow_meter_hws_create(struct rte_eth_dev *dev, uint32_t meter_id, fm->initialized = 1; /* Update ASO flow meter by wqe. */ ret = mlx5_aso_meter_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, aso_mtr, - &priv->mtr_bulk); + &priv->mtr_bulk, NULL, true); if (ret) return -rte_mtr_error_set(error, ENOTSUP, RTE_MTR_ERROR_TYPE_UNSPECIFIED, From patchwork Fri Sep 30 12:53:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117225 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 67248A00C4; Fri, 30 Sep 2022 14:55:54 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id E864342BC4; Fri, 30 Sep 2022 14:54:24 +0200 (CEST) Received: from NAM02-SN1-obe.outbound.protection.outlook.com (mail-sn1anam02on2056.outbound.protection.outlook.com [40.107.96.56]) by mails.dpdk.org (Postfix) with ESMTP id 85A8F42B9D for ; Fri, 30 Sep 2022 14:54:18 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=nRiJyPqLPmO78/ECHIwuxVqapfkgdOOWzPG9grroXnPH9xjYi6RDFdpS5blIgGYacs63+JxfcvXJTBoyBFXgqbL4qEW5FMLiKASbZUlQw+CFuyOZ8bw+uPqOS7Lqk0+wLIXSRmmRZUCUJPyjsRjvERuI9LR58Akq0V+RIgWTprxhWdsfAXk9Qhc3T0MwDIud5u0F8BSsAWdxxCHJcijv0eehZB8bIkuEIZPI9MD0lnLbNguSCEWvGxUxGNxqQFuoMWwTpyE0X5SIDWDJ8YKDbV2qpOPFRbOyyMD5YegzClyg8ksjRcriaqQwfAomZkvckTlVn2XHvuCZoHgNWuLQJg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=Z+TJnbLt0KaxppOmng/uo9+kRaEVyuT+rSlm6d1Xkz0=; b=h2BiHj9b//52nW5KitaSdtDdZ1ndEa99ELH8ijz5fUing6FuRpSj/yktiliffALwzJlNT/S5tVUyseA6NmDJu6J5rvmrbAVZp0xEPQKjb0TEYdShg7bn+OB5rmaFHWOxaWAs0ARyIuhgtX/bU0XmL0yCBAAMcShPviOZqp4OSDAb1UCxZGbgYiOXU6sOkVaGl2tyxVi0ITM/sxcu3J8Fm+WeXEVYBuxIemmsHgWAdBFRis05kGSE3s1b1IDnvPqCIjmSETncq8X6Bkk3QF1DjPOZubNIpDqg3485E/IejOGFZwLCCbVJrdERa74tlnMMkqqlTqvYSAq6pNp4uExTuQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.161) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=Z+TJnbLt0KaxppOmng/uo9+kRaEVyuT+rSlm6d1Xkz0=; b=LlotXvNf151C/ml/EFuGYAJiv4ITlJl586N/qLQ7hWKOS+wE85GoW6bPvvs0xGJjvITyaBloQkOo0iy/4aynl5fUyjD4pkZI4QaarMrkKD7hetylzvPKjK2+l/ryFglYUh0zlKy9DoTRx5Y2niwyJCsOYC/OdVEWkr3qp4CrdSAT/a1h02n4Z20BC0Wm1O/GjijeFQ9TcdO4VSkJ+rVXNDq2dGUhipY3Az+Herwb8cftC8FizHOmHQ0p+esN9OGrYjb6ns+6Wm/Yjki8Rg46TI43QcLy83MSaQBSX6uLoXXapqRg/SHGka4xJnG9DMa/jndQD42IZotrilB9iYcb3w== Received: from DS7PR05CA0063.namprd05.prod.outlook.com (2603:10b6:8:57::19) by MN0PR12MB6056.namprd12.prod.outlook.com (2603:10b6:208:3cc::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.20; Fri, 30 Sep 2022 12:54:16 +0000 Received: from DM6NAM11FT018.eop-nam11.prod.protection.outlook.com (2603:10b6:8:57:cafe::4f) by DS7PR05CA0063.outlook.office365.com (2603:10b6:8:57::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.14 via Frontend Transport; Fri, 30 Sep 2022 12:54:16 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.161) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.161 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.161; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.161) by DM6NAM11FT018.mail.protection.outlook.com (10.13.172.110) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:16 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.67) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:54:08 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:54:06 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , Gregory Etelson Subject: [PATCH v3 15/17] net/mlx5: support flow integrity in HWS group 0 Date: Fri, 30 Sep 2022 15:53:13 +0300 Message-ID: <20220930125315.5079-16-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT018:EE_|MN0PR12MB6056:EE_ X-MS-Office365-Filtering-Correlation-Id: ee85d648-e39e-4b7e-77a9-08daa2e2e201 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: TwFO6ITCBKGJE/xDfPnZJsMmrvblcmOMYSGKtxfg6OPJ2DYDzrojfqA6Q8ScW5k0QnLFvBj06+l/zpGPVZ7XWNKvrV5Oqfh+NM0fHfEoLxBHqCPqWKTdkXSuIMB0gamkk3YRuBK5D7eRNTeHUYBsJHIIuR9OPZxUTVuSmmwirJmY4JZ2A4RhJZdcDtw8zt/C0FJJY1zQm5vGnuwkcvXX+fnTey14koW0nhEQDb2VI9Ebb0lL4ml99VSKO30/2/UWbvQ+tsDObxsg9rSUyiiN/y2kCm8iB8a3FVkKqrTrikfpZPrtS0N3nclU+x31cxBq4WJI5e/9sPyitI4AjdafzlM41opNHxbxyJAfFykLKtnE1Os2V7XB+TFMcVNWUwxdNKMV1gFSqmlcDu2+Dff+zVOSUEPYZ1L2Qv6jbpPrY3b2K9MZtu9u43ATAU/YnDwvZzadFZjlR7qHxyL+9gnfCX/1XyjDZGATWHDx/j8K98IH0qQPvnELo/Ia6lqJmvUuqSelN4iGfsQ15unce03YtOUCa1NCI+E1rCLwZygGbZBhpwcIcolzcClXtFtH/7+LzF3Z43jyt3Rd8jA4+XjNefKgbIQffgmT0LSKmQKBy5yH3bqnkKb+CwG1fs8eLo5fAwtJ6T4tvize95MpuNnpShQSCTMYQ+1XMppilVvG2FW4PswpM794YJp28GN5DsVSaa64ZxusXuGArl6B13PaxlxezjdBvEOznDOwstzIfdciasTRjYlLyNe2fobVA7mGXSt0Qegpy19UDHZI8mg8z9JJ6fsIRUpTBLb8KR5uP8s= X-Forefront-Antispam-Report: CIP:216.228.117.161; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge2.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(39860400002)(346002)(376002)(396003)(136003)(451199015)(46966006)(36840700001)(40470700004)(2616005)(30864003)(26005)(6286002)(40460700003)(82740400003)(4326008)(356005)(8676002)(110136005)(316002)(36756003)(7636003)(55016003)(36860700001)(54906003)(86362001)(40480700001)(47076005)(1076003)(186003)(336012)(82310400005)(8936002)(83380400001)(478600001)(6666004)(107886003)(426003)(16526019)(7696005)(6636002)(5660300002)(70586007)(2906002)(41300700001)(70206006)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:54:16.2839 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ee85d648-e39e-4b7e-77a9-08daa2e2e201 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.161]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT018.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN0PR12MB6056 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Gregory Etelson - Reformat flow integrity item translation for HWS code. - Support flow integrity bits in HWS group 0. - Update integrity item translation to match positive semantics only. Positive flow semantics was described in patch [ae37c0f60c]. Signed-off-by: Gregory Etelson --- drivers/net/mlx5/mlx5_flow.h | 1 + drivers/net/mlx5/mlx5_flow_dv.c | 163 ++++++++++++++++---------------- drivers/net/mlx5/mlx5_flow_hw.c | 8 ++ 3 files changed, 90 insertions(+), 82 deletions(-) diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index e45869a890..3f4aa080bb 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -1462,6 +1462,7 @@ struct mlx5_dv_matcher_workspace { struct mlx5_flow_rss_desc *rss_desc; /* RSS descriptor. */ const struct rte_flow_item *tunnel_item; /* Flow tunnel item. */ const struct rte_flow_item *gre_item; /* Flow GRE item. */ + const struct rte_flow_item *integrity_items[2]; }; struct mlx5_flow_split_info { diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index d31838e26e..e86a06eae6 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -12648,132 +12648,121 @@ flow_dv_aso_age_params_init(struct rte_eth_dev *dev, static void flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask, - const struct rte_flow_item_integrity *value, - void *headers_m, void *headers_v) + void *headers) { + /* + * In HWS mode MLX5_ITEM_UPDATE() macro assigns the same pointer to + * both mask and value, therefore ether can be used. + * In SWS SW_V mode mask points to item mask and value points to item + * spec. Integrity item value is used only if matching mask is set. + * Use mask reference here to keep SWS functionality. + */ if (mask->l4_ok) { /* RTE l4_ok filter aggregates hardware l4_ok and * l4_checksum_ok filters. * Positive RTE l4_ok match requires hardware match on both L4 * hardware integrity bits. - * For negative match, check hardware l4_checksum_ok bit only, - * because hardware sets that bit to 0 for all packets - * with bad L4. + * PMD supports positive integrity item semantics only. */ - if (value->l4_ok) { - MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_ok, 1); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_ok, 1); - } - MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 1); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok, - !!value->l4_ok); - } - if (mask->l4_csum_ok) { - MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 1); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok, - value->l4_csum_ok); + MLX5_SET(fte_match_set_lyr_2_4, headers, l4_ok, 1); + MLX5_SET(fte_match_set_lyr_2_4, headers, l4_checksum_ok, 1); + } else if (mask->l4_csum_ok) { + MLX5_SET(fte_match_set_lyr_2_4, headers, l4_checksum_ok, 1); } } static void flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask, - const struct rte_flow_item_integrity *value, - void *headers_m, void *headers_v, bool is_ipv4) + void *headers, bool is_ipv4) { + /* + * In HWS mode MLX5_ITEM_UPDATE() macro assigns the same pointer to + * both mask and value, therefore ether can be used. + * In SWS SW_V mode mask points to item mask and value points to item + * spec. Integrity item value used only if matching mask is set. + * Use mask reference here to keep SWS functionality. + */ if (mask->l3_ok) { /* RTE l3_ok filter aggregates for IPv4 hardware l3_ok and * ipv4_csum_ok filters. * Positive RTE l3_ok match requires hardware match on both L3 * hardware integrity bits. - * For negative match, check hardware l3_csum_ok bit only, - * because hardware sets that bit to 0 for all packets - * with bad L3. + * PMD supports positive integrity item semantics only. */ + MLX5_SET(fte_match_set_lyr_2_4, headers, l3_ok, 1); if (is_ipv4) { - if (value->l3_ok) { - MLX5_SET(fte_match_set_lyr_2_4, headers_m, - l3_ok, 1); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, - l3_ok, 1); - } - MLX5_SET(fte_match_set_lyr_2_4, headers_m, + MLX5_SET(fte_match_set_lyr_2_4, headers, ipv4_checksum_ok, 1); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, - ipv4_checksum_ok, !!value->l3_ok); - } else { - MLX5_SET(fte_match_set_lyr_2_4, headers_m, l3_ok, 1); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, l3_ok, - value->l3_ok); } - } - if (mask->ipv4_csum_ok) { - MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok, 1); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_checksum_ok, - value->ipv4_csum_ok); + } else if (is_ipv4 && mask->ipv4_csum_ok) { + MLX5_SET(fte_match_set_lyr_2_4, headers, ipv4_checksum_ok, 1); } } static void -set_integrity_bits(void *headers_m, void *headers_v, - const struct rte_flow_item *integrity_item, bool is_l3_ip4) +set_integrity_bits(void *headers, const struct rte_flow_item *integrity_item, + bool is_l3_ip4, uint32_t key_type) { - const struct rte_flow_item_integrity *spec = integrity_item->spec; - const struct rte_flow_item_integrity *mask = integrity_item->mask; + const struct rte_flow_item_integrity *spec; + const struct rte_flow_item_integrity *mask; /* Integrity bits validation cleared spec pointer */ - MLX5_ASSERT(spec != NULL); - if (!mask) - mask = &rte_flow_item_integrity_mask; - flow_dv_translate_integrity_l3(mask, spec, headers_m, headers_v, - is_l3_ip4); - flow_dv_translate_integrity_l4(mask, spec, headers_m, headers_v); + if (MLX5_ITEM_VALID(integrity_item, key_type)) + return; + MLX5_ITEM_UPDATE(integrity_item, key_type, spec, mask, + &rte_flow_item_integrity_mask); + flow_dv_translate_integrity_l3(mask, headers, is_l3_ip4); + flow_dv_translate_integrity_l4(mask, headers); } static void -flow_dv_translate_item_integrity_post(void *matcher, void *key, +flow_dv_translate_item_integrity_post(void *key, const struct rte_flow_item *integrity_items[2], - uint64_t pattern_flags) + uint64_t pattern_flags, uint32_t key_type) { - void *headers_m, *headers_v; + void *headers; bool is_l3_ip4; if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) { - headers_m = MLX5_ADDR_OF(fte_match_param, matcher, - inner_headers); - headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers); + headers = MLX5_ADDR_OF(fte_match_param, key, inner_headers); is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4) != 0; - set_integrity_bits(headers_m, headers_v, - integrity_items[1], is_l3_ip4); + set_integrity_bits(headers, integrity_items[1], is_l3_ip4, + key_type); } if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) { - headers_m = MLX5_ADDR_OF(fte_match_param, matcher, - outer_headers); - headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers); + headers = MLX5_ADDR_OF(fte_match_param, key, outer_headers); is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4) != 0; - set_integrity_bits(headers_m, headers_v, - integrity_items[0], is_l3_ip4); + set_integrity_bits(headers, integrity_items[0], is_l3_ip4, + key_type); } } -static void +static uint64_t flow_dv_translate_item_integrity(const struct rte_flow_item *item, - const struct rte_flow_item *integrity_items[2], - uint64_t *last_item) + struct mlx5_dv_matcher_workspace *wks, + uint64_t key_type) { - const struct rte_flow_item_integrity *spec = (typeof(spec))item->spec; + if ((key_type & MLX5_SET_MATCHER_SW) != 0) { + const struct rte_flow_item_integrity + *spec = (typeof(spec))item->spec; - /* integrity bits validation cleared spec pointer */ - MLX5_ASSERT(spec != NULL); - if (spec->level > 1) { - integrity_items[1] = item; - *last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY; + /* SWS integrity bits validation cleared spec pointer */ + if (spec->level > 1) { + wks->integrity_items[1] = item; + wks->last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY; + } else { + wks->integrity_items[0] = item; + wks->last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY; + } } else { - integrity_items[0] = item; - *last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY; + /* HWS supports outer integrity only */ + wks->integrity_items[0] = item; + wks->last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY; } + return wks->last_item; } /** @@ -13401,6 +13390,10 @@ flow_dv_translate_items(struct rte_eth_dev *dev, flow_dv_translate_item_meter_color(dev, key, items, key_type); last_item = MLX5_FLOW_ITEM_METER_COLOR; break; + case RTE_FLOW_ITEM_TYPE_INTEGRITY: + last_item = flow_dv_translate_item_integrity(items, + wks, key_type); + break; default: break; } @@ -13464,6 +13457,12 @@ flow_dv_translate_items_hws(const struct rte_flow_item *items, if (ret) return ret; } + if (wks.item_flags & MLX5_FLOW_ITEM_INTEGRITY) { + flow_dv_translate_item_integrity_post(key, + wks.integrity_items, + wks.item_flags, + key_type); + } if (wks.item_flags & MLX5_FLOW_LAYER_VXLAN_GPE) { flow_dv_translate_item_vxlan_gpe(key, wks.tunnel_item, @@ -13544,7 +13543,6 @@ flow_dv_translate_items_sws(struct rte_eth_dev *dev, mlx5_flow_get_thread_workspace())->rss_desc, }; struct mlx5_dv_matcher_workspace wks_m = wks; - const struct rte_flow_item *integrity_items[2] = {NULL, NULL}; int ret = 0; int tunnel; @@ -13555,10 +13553,6 @@ flow_dv_translate_items_sws(struct rte_eth_dev *dev, NULL, "item not supported"); tunnel = !!(wks.item_flags & MLX5_FLOW_LAYER_TUNNEL); switch (items->type) { - case RTE_FLOW_ITEM_TYPE_INTEGRITY: - flow_dv_translate_item_integrity(items, integrity_items, - &wks.last_item); - break; case RTE_FLOW_ITEM_TYPE_CONNTRACK: flow_dv_translate_item_aso_ct(dev, match_mask, match_value, items); @@ -13601,9 +13595,14 @@ flow_dv_translate_items_sws(struct rte_eth_dev *dev, return -rte_errno; } if (wks.item_flags & MLX5_FLOW_ITEM_INTEGRITY) { - flow_dv_translate_item_integrity_post(match_mask, match_value, - integrity_items, - wks.item_flags); + flow_dv_translate_item_integrity_post(match_mask, + wks_m.integrity_items, + wks_m.item_flags, + MLX5_SET_MATCHER_SW_M); + flow_dv_translate_item_integrity_post(match_value, + wks.integrity_items, + wks.item_flags, + MLX5_SET_MATCHER_SW_V); } if (wks.item_flags & MLX5_FLOW_LAYER_VXLAN_GPE) { flow_dv_translate_item_vxlan_gpe(match_mask, diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 9f70637fcf..2b5eab6659 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -4656,6 +4656,14 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, case RTE_FLOW_ITEM_TYPE_ICMP6: case RTE_FLOW_ITEM_TYPE_CONNTRACK: break; + case RTE_FLOW_ITEM_TYPE_INTEGRITY: + /* + * Integrity flow item validation require access to + * both item mask and spec. + * Current HWS model allows item mask in pattern + * template and item spec in flow rule. + */ + break; case RTE_FLOW_ITEM_TYPE_END: items_end = true; break; From patchwork Fri Sep 30 12:53:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117226 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 05522A00C4; Fri, 30 Sep 2022 14:56:01 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id C110642BC7; Fri, 30 Sep 2022 14:54:25 +0200 (CEST) Received: from NAM10-BN7-obe.outbound.protection.outlook.com (mail-bn7nam10on2060.outbound.protection.outlook.com [40.107.92.60]) by mails.dpdk.org (Postfix) with ESMTP id 0141141109 for ; Fri, 30 Sep 2022 14:54:22 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=TDLYcMz5ATlMNPvhYv2W47slg9NkVIAnHeExFn8lwERrFi7PxwtM3Uxk8pizFCrXPXjUhVqaSOB7En++qw+zGammqzEW34ONhNxB2CoPxqIf25f9OxPHgjfZpFRYY9Ox/ix3D0iSS+jrPohC3Li7ENieZzcBAyCXV+fKR0KoCaD4F4CgypSQziGPYwYysre5W53XueySfkrpCzXLLWuPIfR6MASMbHkVP2aAJmTJmABhiL9fAjtl3k+/BuPSiUdPKfjDhSTakZDDb0GMV+0t3O8XsJZgObT8USTIq1u0MBlbm13Ih+zdwqOwHWiMpy3t7eH1lR9MEKXX+7kBG/tbww== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=v36ljghLrNMYblQNTT0nvGiQac2omdnznjCdqAZemug=; b=O4z2iP8Sh1592nYWtCy7vns8fq3OiXwY0uBjArGVzui/yRcdaSUcZcswhEHYJeMz4FpO3jd5oL1/eoKbPZLWh954Da5kxKWmluTuqWC76GQIoyGim0tW2RX2qTRmAmya90Iq48OBBLqNJ1PZvgaLYxgKrbJ2g44Zszk0tirik2gYd/ug4v/c2HNhu1HbutXc07qXZ/UDxznI7HuuQjX7RidtPHfW3f0r5BrZXwt9PefVckAX1I2db1scyvjmIepEHYmzMXHbjyNJdMX2H4nc6U/51RVowZth+GOW1pBh4NLoyhEedO0ONUthm+4yP4iSVldU6b2pcTOZm19+4Z2ETQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=ashroe.eu smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=v36ljghLrNMYblQNTT0nvGiQac2omdnznjCdqAZemug=; b=H1DlHlgDg33toICgt6NuYgftaEVQQKOnXYWgIV8b+g3ySzsN67zA8LoPpruTQ+OTSfip9IM+LL8dnyLGmBrqx1Wn/BP5AYrZ+jFCK8tF92imPFp1ONbNIrDfTYA9PtMo30ErNngExqZHAwJ9EYgvn2PHaFjfnvQy+n8eIJ2unMRA/oKXXvFmP73bAxl0qEQ0fUqiP6ASRNTe5stpEVG3XwNUytlSUMKeRUxw4NbhvniiDvvazLyIEg7bEv9XRi+zzfuJrLKs3dG9+4aa69xUerNMeRcM6GRWo2H1vv5WrBbprouIONlD2zvx0r3dYY0Xpgt6jZQW9A3H1K/AL5o69g== Received: from DM6PR07CA0070.namprd07.prod.outlook.com (2603:10b6:5:74::47) by CH2PR12MB4102.namprd12.prod.outlook.com (2603:10b6:610:a9::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.23; Fri, 30 Sep 2022 12:54:19 +0000 Received: from DM6NAM11FT081.eop-nam11.prod.protection.outlook.com (2603:10b6:5:74:cafe::77) by DM6PR07CA0070.outlook.office365.com (2603:10b6:5:74::47) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:19 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT081.mail.protection.outlook.com (10.13.172.136) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:19 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:54:11 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:54:09 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko , Ray Kinsella CC: , , , "Dariusz Sosnowski" , Xueming Li Subject: [PATCH v3 16/17] net/mlx5: support device control for E-Switch default rule Date: Fri, 30 Sep 2022 15:53:14 +0300 Message-ID: <20220930125315.5079-17-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT081:EE_|CH2PR12MB4102:EE_ X-MS-Office365-Filtering-Correlation-Id: 28604d66-0263-49c3-6f6f-08daa2e2e3f6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: Th/EVjdKV3NsWvr/rMOWtmcLiwK+HAxP+kUZvod6zBqsiX1RBVO0BYM9RfF0YUYpDpxV75ODById4s6iE8bB3c0iWtLLu9luPAFolByCqgT2kQIBM9h1tx+cIqT7fEoJbJn4sk1RCe7D8bwKn+xBSYEqKc9Uv4lJgMkOVKB8RXqma2vfjYuLf5vv20guM4rD3LuIZA2dxtaq6fUketV4jpqyZU0s26HmMDhSrOJDvzqqHHqZMKDnyNP5wVEamvgUeHkO/IjaI0EIDgy55kH9Ri6jPmxawmZjkuHXjmViuDqWdnl9sGdcFk2hcF8kD4nwNYnvnkJIBqJOefrYdFE2P41Qhv31+sAraw3sJ68D25JDWrltgXCyHFSZfofYRXma9Ma+BpLdclsR8j5eIktxspqr8sKhvM1xv77MrAMe92Czu32szSdmZGkqWJJvrFi751nK/JXoFsWdP+vMsycvCghxUimkZm5HXs8T5YvkcFGMS5p3Nc2usuylDO185/o+nSQGOSeg//BckrBeVN0sdbraOj6FxcJtp5FKycCNPlDqtEJGE9lHGYL1ZlGD8MC7jByMsDZ5UiV+A34UN1zeTCJG/p518roNQE2Hqt2YQwOmQokjnpHFDsR1KMDWtujK2iocJdXCb5EAENWtUHY5jrn0DO4mGoS9qidHodJV+fOxVvtHmDixNk8fqopRcz3/oKAwWL17PlHsH0kHjl4+hoQayV3fqyvE44ZJ8ST/fId5XUq7tJXkxWsv5A0cKpvRXUQ70ycV4VSZ9gsNhGaiWQ== X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(376002)(136003)(346002)(39860400002)(396003)(451199015)(40470700004)(36840700001)(46966006)(40480700001)(41300700001)(36756003)(36860700001)(7696005)(30864003)(55016003)(40460700003)(8936002)(1076003)(16526019)(478600001)(82310400005)(2616005)(70206006)(336012)(107886003)(5660300002)(26005)(186003)(6666004)(6286002)(86362001)(70586007)(8676002)(4326008)(110136005)(83380400001)(426003)(47076005)(316002)(54906003)(82740400003)(7636003)(2906002)(356005); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:54:19.5671 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 28604d66-0263-49c3-6f6f-08daa2e2e3f6 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT081.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR12MB4102 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Dariusz Sosnowski This patch introduces This patch adds support for fdb_def_rule_en device argument to HW Steering, which controls: - creation of default FDB jump flow rule, - ability of the user to create transfer flow rules in root table. A new PMD API to allow user application to enable traffic with port ID and SQ number is also added to direct packet to wire. Signed-off-by: Dariusz Sosnowski Signed-off-by: Xueming Li --- drivers/net/mlx5/linux/mlx5_os.c | 14 ++ drivers/net/mlx5/mlx5.h | 4 +- drivers/net/mlx5/mlx5_flow.c | 28 ++-- drivers/net/mlx5/mlx5_flow.h | 11 +- drivers/net/mlx5/mlx5_flow_dv.c | 78 +++++---- drivers/net/mlx5/mlx5_flow_hw.c | 279 +++++++++++++++---------------- drivers/net/mlx5/mlx5_trigger.c | 31 ++-- drivers/net/mlx5/mlx5_tx.h | 1 + drivers/net/mlx5/mlx5_txq.c | 47 ++++++ drivers/net/mlx5/rte_pmd_mlx5.h | 17 ++ drivers/net/mlx5/version.map | 1 + 11 files changed, 305 insertions(+), 206 deletions(-) diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index 60a1a391fb..de8c003d02 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -1554,6 +1554,20 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, rte_rwlock_init(&priv->ind_tbls_lock); if (priv->sh->config.dv_flow_en == 2) { #ifdef HAVE_IBV_FLOW_DV_SUPPORT + if (priv->sh->config.dv_esw_en) { + if (priv->sh->dv_regc0_mask == UINT32_MAX) { + DRV_LOG(ERR, "E-Switch port metadata is required when using HWS " + "but it is disabled (configure it through devlink)"); + err = ENOTSUP; + goto error; + } + if (priv->sh->dv_regc0_mask == 0) { + DRV_LOG(ERR, "E-Switch with HWS is not supported " + "(no available bits in reg_c[0])"); + err = ENOTSUP; + goto error; + } + } if (priv->vport_meta_mask) flow_hw_set_port_info(eth_dev); if (priv->sh->config.dv_esw_en && diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index f6033710aa..419b5a18ca 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -2015,7 +2015,7 @@ int mlx5_flow_ops_get(struct rte_eth_dev *dev, const struct rte_flow_ops **ops); int mlx5_flow_start_default(struct rte_eth_dev *dev); void mlx5_flow_stop_default(struct rte_eth_dev *dev); int mlx5_flow_verify(struct rte_eth_dev *dev); -int mlx5_ctrl_flow_source_queue(struct rte_eth_dev *dev, uint32_t queue); +int mlx5_ctrl_flow_source_queue(struct rte_eth_dev *dev, uint32_t sq_num); int mlx5_ctrl_flow_vlan(struct rte_eth_dev *dev, struct rte_flow_item_eth *eth_spec, struct rte_flow_item_eth *eth_mask, @@ -2027,7 +2027,7 @@ int mlx5_ctrl_flow(struct rte_eth_dev *dev, int mlx5_flow_lacp_miss(struct rte_eth_dev *dev); struct rte_flow *mlx5_flow_create_esw_table_zero_flow(struct rte_eth_dev *dev); uint32_t mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev, - uint32_t txq); + uint32_t sq_num); void mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh, uint64_t async_id, int status); void mlx5_set_query_alarm(struct mlx5_dev_ctx_shared *sh); diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index bc2ccb4d3c..2142cd828a 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -7155,14 +7155,14 @@ mlx5_flow_create_esw_table_zero_flow(struct rte_eth_dev *dev) * * @param dev * Pointer to Ethernet device. - * @param txq - * Txq index. + * @param sq_num + * SQ number. * * @return * Flow ID on success, 0 otherwise and rte_errno is set. */ uint32_t -mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq) +mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev, uint32_t sq_num) { struct rte_flow_attr attr = { .group = 0, @@ -7174,8 +7174,8 @@ mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq) struct rte_flow_item_port_id port_spec = { .id = MLX5_PORT_ESW_MGR, }; - struct mlx5_rte_flow_item_tx_queue txq_spec = { - .queue = txq, + struct mlx5_rte_flow_item_sq sq_spec = { + .queue = sq_num, }; struct rte_flow_item pattern[] = { { @@ -7184,8 +7184,8 @@ mlx5_flow_create_devx_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq) }, { .type = (enum rte_flow_item_type) - MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE, - .spec = &txq_spec, + MLX5_RTE_FLOW_ITEM_TYPE_SQ, + .spec = &sq_spec, }, { .type = RTE_FLOW_ITEM_TYPE_END, @@ -7556,30 +7556,30 @@ mlx5_flow_verify(struct rte_eth_dev *dev __rte_unused) * * @param dev * Pointer to Ethernet device. - * @param queue - * The queue index. + * @param sq_num + * The SQ hw number. * * @return * 0 on success, a negative errno value otherwise and rte_errno is set. */ int mlx5_ctrl_flow_source_queue(struct rte_eth_dev *dev, - uint32_t queue) + uint32_t sq_num) { const struct rte_flow_attr attr = { .egress = 1, .priority = 0, }; - struct mlx5_rte_flow_item_tx_queue queue_spec = { - .queue = queue, + struct mlx5_rte_flow_item_sq queue_spec = { + .queue = sq_num, }; - struct mlx5_rte_flow_item_tx_queue queue_mask = { + struct mlx5_rte_flow_item_sq queue_mask = { .queue = UINT32_MAX, }; struct rte_flow_item items[] = { { .type = (enum rte_flow_item_type) - MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE, + MLX5_RTE_FLOW_ITEM_TYPE_SQ, .spec = &queue_spec, .last = NULL, .mask = &queue_mask, diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 3f4aa080bb..63f946473d 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -29,7 +29,7 @@ enum mlx5_rte_flow_item_type { MLX5_RTE_FLOW_ITEM_TYPE_END = INT_MIN, MLX5_RTE_FLOW_ITEM_TYPE_TAG, - MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE, + MLX5_RTE_FLOW_ITEM_TYPE_SQ, MLX5_RTE_FLOW_ITEM_TYPE_VLAN, MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL, }; @@ -115,8 +115,8 @@ struct mlx5_flow_action_copy_mreg { }; /* Matches on source queue. */ -struct mlx5_rte_flow_item_tx_queue { - uint32_t queue; +struct mlx5_rte_flow_item_sq { + uint32_t queue; /* DevX SQ number */ }; /* Feature name to allocate metadata register. */ @@ -179,7 +179,7 @@ enum mlx5_feature_name { #define MLX5_FLOW_LAYER_GENEVE (1u << 26) /* Queue items. */ -#define MLX5_FLOW_ITEM_TX_QUEUE (1u << 27) +#define MLX5_FLOW_ITEM_SQ (1u << 27) /* Pattern tunnel Layer bits (continued). */ #define MLX5_FLOW_LAYER_GTP (1u << 28) @@ -2475,9 +2475,8 @@ int mlx5_flow_pick_transfer_proxy(struct rte_eth_dev *dev, int mlx5_flow_hw_flush_ctrl_flows(struct rte_eth_dev *dev); -int mlx5_flow_hw_esw_create_mgr_sq_miss_flow(struct rte_eth_dev *dev); int mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, - uint32_t txq); + uint32_t sqn); int mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev); int mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev); int mlx5_flow_actions_validate(struct rte_eth_dev *dev, diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index e86a06eae6..0f6fd34a8b 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -7453,8 +7453,8 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, return ret; last_item = MLX5_FLOW_ITEM_TAG; break; - case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: - last_item = MLX5_FLOW_ITEM_TX_QUEUE; + case MLX5_RTE_FLOW_ITEM_TYPE_SQ: + last_item = MLX5_FLOW_ITEM_SQ; break; case MLX5_RTE_FLOW_ITEM_TYPE_TAG: break; @@ -8343,7 +8343,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, * work due to metadata regC0 mismatch. */ if ((!attr->transfer && attr->egress) && priv->representor && - !(item_flags & MLX5_FLOW_ITEM_TX_QUEUE)) + !(item_flags & MLX5_FLOW_ITEM_SQ)) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, @@ -10123,6 +10123,29 @@ flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *key, return 0; } +/** + * Translate port representor item to eswitch match on port id. + * + * @param[in] dev + * The devich to configure through. + * @param[in, out] key + * Flow matcher value. + * @param[in] key_type + * Set flow matcher mask or value. + * + * @return + * 0 on success, a negative errno value otherwise. + */ +static int +flow_dv_translate_item_port_representor(struct rte_eth_dev *dev, void *key, + uint32_t key_type) +{ + flow_dv_translate_item_source_vport(key, + key_type & MLX5_SET_MATCHER_V ? + mlx5_flow_get_esw_manager_vport_id(dev) : 0xffff); + return 0; +} + /** * Translate represented port item to eswitch match on port id. * @@ -11402,10 +11425,10 @@ flow_dv_translate_create_counter(struct rte_eth_dev *dev, } /** - * Add Tx queue matcher + * Add SQ matcher * - * @param[in] dev - * Pointer to the dev struct. + * @param[in, out] matcher + * Flow matcher. * @param[in, out] key * Flow matcher value. * @param[in] item @@ -11414,40 +11437,29 @@ flow_dv_translate_create_counter(struct rte_eth_dev *dev, * Set flow matcher mask or value. */ static void -flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev, - void *key, - const struct rte_flow_item *item, - uint32_t key_type) +flow_dv_translate_item_sq(void *key, + const struct rte_flow_item *item, + uint32_t key_type) { - const struct mlx5_rte_flow_item_tx_queue *queue_m; - const struct mlx5_rte_flow_item_tx_queue *queue_v; - const struct mlx5_rte_flow_item_tx_queue queue_mask = { + const struct mlx5_rte_flow_item_sq *queue_m; + const struct mlx5_rte_flow_item_sq *queue_v; + const struct mlx5_rte_flow_item_sq queue_mask = { .queue = UINT32_MAX, }; - void *misc_v = - MLX5_ADDR_OF(fte_match_param, key, misc_parameters); - struct mlx5_txq_ctrl *txq = NULL; + void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters); uint32_t queue; MLX5_ITEM_UPDATE(item, key_type, queue_v, queue_m, &queue_mask); if (!queue_m || !queue_v) return; if (key_type & MLX5_SET_MATCHER_V) { - txq = mlx5_txq_get(dev, queue_v->queue); - if (!txq) - return; - if (txq->is_hairpin) - queue = txq->obj->sq->id; - else - queue = txq->obj->sq_obj.sq->id; + queue = queue_v->queue; if (key_type == MLX5_SET_MATCHER_SW_V) queue &= queue_m->queue; } else { queue = queue_m->queue; } MLX5_SET(fte_match_set_misc, misc_v, source_sqn, queue); - if (txq) - mlx5_txq_release(dev, queue_v->queue); } /** @@ -13148,6 +13160,11 @@ flow_dv_translate_items(struct rte_eth_dev *dev, (dev, key, items, wks->attr, key_type); last_item = MLX5_FLOW_ITEM_PORT_ID; break; + case RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR: + flow_dv_translate_item_port_representor + (dev, key, key_type); + last_item = MLX5_FLOW_ITEM_PORT_REPRESENTOR; + break; case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT: flow_dv_translate_item_represented_port (dev, key, items, wks->attr, key_type); @@ -13353,9 +13370,9 @@ flow_dv_translate_items(struct rte_eth_dev *dev, flow_dv_translate_mlx5_item_tag(dev, key, items, key_type); last_item = MLX5_FLOW_ITEM_TAG; break; - case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: - flow_dv_translate_item_tx_queue(dev, key, items, key_type); - last_item = MLX5_FLOW_ITEM_TX_QUEUE; + case MLX5_RTE_FLOW_ITEM_TYPE_SQ: + flow_dv_translate_item_sq(key, items, key_type); + last_item = MLX5_FLOW_ITEM_SQ; break; case RTE_FLOW_ITEM_TYPE_GTP: flow_dv_translate_item_gtp(key, items, tunnel, key_type); @@ -13564,7 +13581,6 @@ flow_dv_translate_items_sws(struct rte_eth_dev *dev, wks.last_item = tunnel ? MLX5_FLOW_ITEM_INNER_FLEX : MLX5_FLOW_ITEM_OUTER_FLEX; break; - default: ret = flow_dv_translate_items(dev, items, &wks_m, match_mask, MLX5_SET_MATCHER_SW_M, error); @@ -13587,7 +13603,9 @@ flow_dv_translate_items_sws(struct rte_eth_dev *dev, * in use. */ if (!(wks.item_flags & MLX5_FLOW_ITEM_PORT_ID) && - !(wks.item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) && priv->sh->esw_mode && + !(wks.item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) && + !(wks.item_flags & MLX5_FLOW_ITEM_PORT_REPRESENTOR) && + priv->sh->esw_mode && !(attr->egress && !attr->transfer) && attr->group != MLX5_FLOW_MREG_CP_TABLE_GROUP) { if (flow_dv_translate_item_port_id_all(dev, match_mask, diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index 2b5eab6659..b2824ad8fe 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -3173,7 +3173,10 @@ flow_hw_translate_group(struct rte_eth_dev *dev, struct mlx5_priv *priv = dev->data->dev_private; const struct rte_flow_attr *flow_attr = &cfg->attr.flow_attr; - if (priv->sh->config.dv_esw_en && cfg->external && flow_attr->transfer) { + if (priv->sh->config.dv_esw_en && + priv->fdb_def_rule && + cfg->external && + flow_attr->transfer) { if (group > MLX5_HW_MAX_TRANSFER_GROUP) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR_GROUP, @@ -4648,7 +4651,7 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, case RTE_FLOW_ITEM_TYPE_GTP: case RTE_FLOW_ITEM_TYPE_GTP_PSC: case RTE_FLOW_ITEM_TYPE_VXLAN: - case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE: + case MLX5_RTE_FLOW_ITEM_TYPE_SQ: case RTE_FLOW_ITEM_TYPE_GRE: case RTE_FLOW_ITEM_TYPE_GRE_KEY: case RTE_FLOW_ITEM_TYPE_GRE_OPTION: @@ -5141,14 +5144,23 @@ flow_hw_free_vport_actions(struct mlx5_priv *priv) } static uint32_t -flow_hw_usable_lsb_vport_mask(struct mlx5_priv *priv) +flow_hw_esw_mgr_regc_marker_mask(struct rte_eth_dev *dev) { - uint32_t usable_mask = ~priv->vport_meta_mask; + uint32_t mask = MLX5_SH(dev)->dv_regc0_mask; - if (usable_mask) - return (1 << rte_bsf32(usable_mask)); - else - return 0; + /* Mask is verified during device initialization. */ + MLX5_ASSERT(mask != 0); + return mask; +} + +static uint32_t +flow_hw_esw_mgr_regc_marker(struct rte_eth_dev *dev) +{ + uint32_t mask = MLX5_SH(dev)->dv_regc0_mask; + + /* Mask is verified during device initialization. */ + MLX5_ASSERT(mask != 0); + return RTE_BIT32(rte_bsf32(mask)); } /** @@ -5174,12 +5186,19 @@ flow_hw_create_ctrl_esw_mgr_pattern_template(struct rte_eth_dev *dev) struct rte_flow_item_ethdev port_mask = { .port_id = UINT16_MAX, }; + struct mlx5_rte_flow_item_sq sq_mask = { + .queue = UINT32_MAX, + }; struct rte_flow_item items[] = { { .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, .spec = &port_spec, .mask = &port_mask, }, + { + .type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_SQ, + .mask = &sq_mask, + }, { .type = RTE_FLOW_ITEM_TYPE_END, }, @@ -5189,9 +5208,10 @@ flow_hw_create_ctrl_esw_mgr_pattern_template(struct rte_eth_dev *dev) } /** - * Creates a flow pattern template used to match REG_C_0 and a TX queue. - * Matching on REG_C_0 is set up to match on least significant bit usable - * by user-space, which is set when packet was originated from E-Switch Manager. + * Creates a flow pattern template used to match REG_C_0 and a SQ. + * Matching on REG_C_0 is set up to match on all bits usable by user-space. + * If traffic was sent from E-Switch Manager, then all usable bits will be set to 0, + * except the least significant bit, which will be set to 1. * * This template is used to set up a table for SQ miss default flow. * @@ -5204,8 +5224,6 @@ flow_hw_create_ctrl_esw_mgr_pattern_template(struct rte_eth_dev *dev) static struct rte_flow_pattern_template * flow_hw_create_ctrl_regc_sq_pattern_template(struct rte_eth_dev *dev) { - struct mlx5_priv *priv = dev->data->dev_private; - uint32_t marker_bit = flow_hw_usable_lsb_vport_mask(priv); struct rte_flow_pattern_template_attr attr = { .relaxed_matching = 0, .transfer = 1, @@ -5215,8 +5233,9 @@ flow_hw_create_ctrl_regc_sq_pattern_template(struct rte_eth_dev *dev) }; struct rte_flow_item_tag reg_c0_mask = { .index = 0xff, + .data = flow_hw_esw_mgr_regc_marker_mask(dev), }; - struct mlx5_rte_flow_item_tx_queue queue_mask = { + struct mlx5_rte_flow_item_sq queue_mask = { .queue = UINT32_MAX, }; struct rte_flow_item items[] = { @@ -5228,7 +5247,7 @@ flow_hw_create_ctrl_regc_sq_pattern_template(struct rte_eth_dev *dev) }, { .type = (enum rte_flow_item_type) - MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE, + MLX5_RTE_FLOW_ITEM_TYPE_SQ, .mask = &queue_mask, }, { @@ -5236,12 +5255,6 @@ flow_hw_create_ctrl_regc_sq_pattern_template(struct rte_eth_dev *dev) }, }; - if (!marker_bit) { - DRV_LOG(ERR, "Unable to set up pattern template for SQ miss table"); - return NULL; - } - reg_c0_spec.data = marker_bit; - reg_c0_mask.data = marker_bit; return flow_hw_pattern_template_create(dev, &attr, items, NULL); } @@ -5333,9 +5346,8 @@ flow_hw_create_tx_default_mreg_copy_pattern_template(struct rte_eth_dev *dev) static struct rte_flow_actions_template * flow_hw_create_ctrl_regc_jump_actions_template(struct rte_eth_dev *dev) { - struct mlx5_priv *priv = dev->data->dev_private; - uint32_t marker_bit = flow_hw_usable_lsb_vport_mask(priv); - uint32_t marker_bit_mask = UINT32_MAX; + uint32_t marker_mask = flow_hw_esw_mgr_regc_marker_mask(dev); + uint32_t marker_bits = flow_hw_esw_mgr_regc_marker(dev); struct rte_flow_actions_template_attr attr = { .transfer = 1, }; @@ -5348,7 +5360,7 @@ flow_hw_create_ctrl_regc_jump_actions_template(struct rte_eth_dev *dev) .src = { .field = RTE_FLOW_FIELD_VALUE, }, - .width = 1, + .width = __builtin_popcount(marker_mask), }; struct rte_flow_action_modify_field set_reg_m = { .operation = RTE_FLOW_MODIFY_SET, @@ -5395,13 +5407,9 @@ flow_hw_create_ctrl_regc_jump_actions_template(struct rte_eth_dev *dev) } }; - if (!marker_bit) { - DRV_LOG(ERR, "Unable to set up actions template for SQ miss table"); - return NULL; - } - set_reg_v.dst.offset = rte_bsf32(marker_bit); - rte_memcpy(set_reg_v.src.value, &marker_bit, sizeof(marker_bit)); - rte_memcpy(set_reg_m.src.value, &marker_bit_mask, sizeof(marker_bit_mask)); + set_reg_v.dst.offset = rte_bsf32(marker_mask); + rte_memcpy(set_reg_v.src.value, &marker_bits, sizeof(marker_bits)); + rte_memcpy(set_reg_m.src.value, &marker_mask, sizeof(marker_mask)); return flow_hw_actions_template_create(dev, &attr, actions_v, actions_m, NULL); } @@ -5588,7 +5596,7 @@ flow_hw_create_ctrl_sq_miss_root_table(struct rte_eth_dev *dev, struct rte_flow_template_table_attr attr = { .flow_attr = { .group = 0, - .priority = 0, + .priority = MLX5_HW_LOWEST_PRIO_ROOT, .ingress = 0, .egress = 0, .transfer = 1, @@ -5703,7 +5711,7 @@ flow_hw_create_ctrl_jump_table(struct rte_eth_dev *dev, struct rte_flow_template_table_attr attr = { .flow_attr = { .group = 0, - .priority = MLX5_HW_LOWEST_PRIO_ROOT, + .priority = 0, .ingress = 0, .egress = 0, .transfer = 1, @@ -7765,141 +7773,123 @@ flow_hw_flush_all_ctrl_flows(struct rte_eth_dev *dev) } int -mlx5_flow_hw_esw_create_mgr_sq_miss_flow(struct rte_eth_dev *dev) +mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t sqn) { - struct mlx5_priv *priv = dev->data->dev_private; - struct rte_flow_item_ethdev port_spec = { + uint16_t port_id = dev->data->port_id; + struct rte_flow_item_ethdev esw_mgr_spec = { .port_id = MLX5_REPRESENTED_PORT_ESW_MGR, }; - struct rte_flow_item_ethdev port_mask = { + struct rte_flow_item_ethdev esw_mgr_mask = { .port_id = MLX5_REPRESENTED_PORT_ESW_MGR, }; - struct rte_flow_item items[] = { - { - .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, - .spec = &port_spec, - .mask = &port_mask, - }, - { - .type = RTE_FLOW_ITEM_TYPE_END, - }, - }; - struct rte_flow_action_modify_field modify_field = { - .operation = RTE_FLOW_MODIFY_SET, - .dst = { - .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, - }, - .src = { - .field = RTE_FLOW_FIELD_VALUE, - }, - .width = 1, - }; - struct rte_flow_action_jump jump = { - .group = 1, - }; - struct rte_flow_action actions[] = { - { - .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, - .conf = &modify_field, - }, - { - .type = RTE_FLOW_ACTION_TYPE_JUMP, - .conf = &jump, - }, - { - .type = RTE_FLOW_ACTION_TYPE_END, - }, - }; - - MLX5_ASSERT(priv->master); - if (!priv->dr_ctx || - !priv->hw_esw_sq_miss_root_tbl) - return 0; - return flow_hw_create_ctrl_flow(dev, dev, - priv->hw_esw_sq_miss_root_tbl, - items, 0, actions, 0); -} - -int -mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t txq) -{ - uint16_t port_id = dev->data->port_id; struct rte_flow_item_tag reg_c0_spec = { .index = (uint8_t)REG_C_0, + .data = flow_hw_esw_mgr_regc_marker(dev), }; struct rte_flow_item_tag reg_c0_mask = { .index = 0xff, + .data = flow_hw_esw_mgr_regc_marker_mask(dev), }; - struct mlx5_rte_flow_item_tx_queue queue_spec = { - .queue = txq, - }; - struct mlx5_rte_flow_item_tx_queue queue_mask = { - .queue = UINT32_MAX, - }; - struct rte_flow_item items[] = { - { - .type = (enum rte_flow_item_type) - MLX5_RTE_FLOW_ITEM_TYPE_TAG, - .spec = ®_c0_spec, - .mask = ®_c0_mask, - }, - { - .type = (enum rte_flow_item_type) - MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE, - .spec = &queue_spec, - .mask = &queue_mask, - }, - { - .type = RTE_FLOW_ITEM_TYPE_END, - }, + struct mlx5_rte_flow_item_sq sq_spec = { + .queue = sqn, }; struct rte_flow_action_ethdev port = { .port_id = port_id, }; - struct rte_flow_action actions[] = { - { - .type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT, - .conf = &port, - }, - { - .type = RTE_FLOW_ACTION_TYPE_END, - }, - }; + struct rte_flow_item items[3] = { { 0 } }; + struct rte_flow_action actions[3] = { { 0 } }; struct rte_eth_dev *proxy_dev; struct mlx5_priv *proxy_priv; uint16_t proxy_port_id = dev->data->port_id; - uint32_t marker_bit; int ret; - RTE_SET_USED(txq); ret = rte_flow_pick_transfer_proxy(port_id, &proxy_port_id, NULL); if (ret) { - DRV_LOG(ERR, "Unable to pick proxy port for port %u", port_id); + DRV_LOG(ERR, "Unable to pick transfer proxy port for port %u. Transfer proxy " + "port must be present to create default SQ miss flows.", + port_id); return ret; } proxy_dev = &rte_eth_devices[proxy_port_id]; proxy_priv = proxy_dev->data->dev_private; - if (!proxy_priv->dr_ctx) + if (!proxy_priv->dr_ctx) { + DRV_LOG(DEBUG, "Transfer proxy port (port %u) of port %u must be configured " + "for HWS to create default SQ miss flows. Default flows will " + "not be created.", + proxy_port_id, port_id); return 0; + } if (!proxy_priv->hw_esw_sq_miss_root_tbl || !proxy_priv->hw_esw_sq_miss_tbl) { - DRV_LOG(ERR, "port %u proxy port %u was configured but default" - " flow tables are not created", - port_id, proxy_port_id); + DRV_LOG(ERR, "Transfer proxy port (port %u) of port %u was configured, but " + "default flow tables were not created.", + proxy_port_id, port_id); rte_errno = ENOMEM; return -rte_errno; } - marker_bit = flow_hw_usable_lsb_vport_mask(proxy_priv); - if (!marker_bit) { - DRV_LOG(ERR, "Unable to set up control flow in SQ miss table"); - rte_errno = EINVAL; - return -rte_errno; + /* + * Create a root SQ miss flow rule - match E-Switch Manager and SQ, + * and jump to group 1. + */ + items[0] = (struct rte_flow_item){ + .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, + .spec = &esw_mgr_spec, + .mask = &esw_mgr_mask, + }; + items[1] = (struct rte_flow_item){ + .type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_SQ, + .spec = &sq_spec, + }; + items[2] = (struct rte_flow_item){ + .type = RTE_FLOW_ITEM_TYPE_END, + }; + actions[0] = (struct rte_flow_action){ + .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + }; + actions[1] = (struct rte_flow_action){ + .type = RTE_FLOW_ACTION_TYPE_JUMP, + }; + actions[2] = (struct rte_flow_action) { + .type = RTE_FLOW_ACTION_TYPE_END, + }; + ret = flow_hw_create_ctrl_flow(dev, proxy_dev, proxy_priv->hw_esw_sq_miss_root_tbl, + items, 0, actions, 0); + if (ret) { + DRV_LOG(ERR, "Port %u failed to create root SQ miss flow rule for SQ %u, ret %d", + port_id, sqn, ret); + return ret; } - reg_c0_spec.data = marker_bit; - reg_c0_mask.data = marker_bit; - return flow_hw_create_ctrl_flow(dev, proxy_dev, - proxy_priv->hw_esw_sq_miss_tbl, - items, 0, actions, 0); + /* + * Create a non-root SQ miss flow rule - match REG_C_0 marker and SQ, + * and forward to port. + */ + items[0] = (struct rte_flow_item){ + .type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_TAG, + .spec = ®_c0_spec, + .mask = ®_c0_mask, + }; + items[1] = (struct rte_flow_item){ + .type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_SQ, + .spec = &sq_spec, + }; + items[2] = (struct rte_flow_item){ + .type = RTE_FLOW_ITEM_TYPE_END, + }; + actions[0] = (struct rte_flow_action){ + .type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT, + .conf = &port, + }; + actions[1] = (struct rte_flow_action){ + .type = RTE_FLOW_ACTION_TYPE_END, + }; + ret = flow_hw_create_ctrl_flow(dev, proxy_dev, proxy_priv->hw_esw_sq_miss_tbl, + items, 0, actions, 0); + if (ret) { + DRV_LOG(ERR, "Port %u failed to create HWS SQ miss flow rule for SQ %u, ret %d", + port_id, sqn, ret); + return ret; + } + return 0; } int @@ -7937,17 +7927,24 @@ mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev) ret = rte_flow_pick_transfer_proxy(port_id, &proxy_port_id, NULL); if (ret) { - DRV_LOG(ERR, "Unable to pick proxy port for port %u", port_id); + DRV_LOG(ERR, "Unable to pick transfer proxy port for port %u. Transfer proxy " + "port must be present to create default FDB jump rule.", + port_id); return ret; } proxy_dev = &rte_eth_devices[proxy_port_id]; proxy_priv = proxy_dev->data->dev_private; - if (!proxy_priv->dr_ctx) + if (!proxy_priv->dr_ctx) { + DRV_LOG(DEBUG, "Transfer proxy port (port %u) of port %u must be configured " + "for HWS to create default FDB jump rule. Default rule will " + "not be created.", + proxy_port_id, port_id); return 0; + } if (!proxy_priv->hw_esw_zero_tbl) { - DRV_LOG(ERR, "port %u proxy port %u was configured but default" - " flow tables are not created", - port_id, proxy_port_id); + DRV_LOG(ERR, "Transfer proxy port (port %u) of port %u was configured, but " + "default flow tables were not created.", + proxy_port_id, port_id); rte_errno = EINVAL; return -rte_errno; } diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index 2603196933..a973cbc5e3 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -426,7 +426,7 @@ mlx5_hairpin_queue_peer_update(struct rte_eth_dev *dev, uint16_t peer_queue, mlx5_txq_release(dev, peer_queue); return -rte_errno; } - peer_info->qp_id = txq_ctrl->obj->sq->id; + peer_info->qp_id = mlx5_txq_get_sqn(txq_ctrl); peer_info->vhca_id = priv->sh->cdev->config.hca_attr.vhca_id; /* 1-to-1 mapping, only the first one is used. */ peer_info->peer_q = txq_ctrl->hairpin_conf.peers[0].queue; @@ -818,7 +818,7 @@ mlx5_hairpin_bind_single_port(struct rte_eth_dev *dev, uint16_t rx_port) } /* Pass TxQ's information to peer RxQ and try binding. */ cur.peer_q = rx_queue; - cur.qp_id = txq_ctrl->obj->sq->id; + cur.qp_id = mlx5_txq_get_sqn(txq_ctrl); cur.vhca_id = priv->sh->cdev->config.hca_attr.vhca_id; cur.tx_explicit = txq_ctrl->hairpin_conf.tx_explicit; cur.manual_bind = txq_ctrl->hairpin_conf.manual_bind; @@ -1300,8 +1300,6 @@ mlx5_traffic_enable_hws(struct rte_eth_dev *dev) int ret; if (priv->sh->config.dv_esw_en && priv->master) { - if (mlx5_flow_hw_esw_create_mgr_sq_miss_flow(dev)) - goto error; if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS) if (mlx5_flow_hw_create_tx_default_mreg_copy_flow(dev)) goto error; @@ -1312,10 +1310,7 @@ mlx5_traffic_enable_hws(struct rte_eth_dev *dev) if (!txq) continue; - if (txq->is_hairpin) - queue = txq->obj->sq->id; - else - queue = txq->obj->sq_obj.sq->id; + queue = mlx5_txq_get_sqn(txq); if ((priv->representor || priv->master) && priv->sh->config.dv_esw_en) { if (mlx5_flow_hw_esw_create_sq_miss_flow(dev, queue)) { @@ -1325,9 +1320,15 @@ mlx5_traffic_enable_hws(struct rte_eth_dev *dev) } mlx5_txq_release(dev, i); } - if ((priv->master || priv->representor) && priv->sh->config.dv_esw_en) { - if (mlx5_flow_hw_esw_create_default_jump_flow(dev)) - goto error; + if (priv->sh->config.fdb_def_rule) { + if ((priv->master || priv->representor) && priv->sh->config.dv_esw_en) { + if (!mlx5_flow_hw_esw_create_default_jump_flow(dev)) + priv->fdb_def_rule = 1; + else + goto error; + } + } else { + DRV_LOG(INFO, "port %u FDB default rule is disabled", dev->data->port_id); } return 0; error: @@ -1393,14 +1394,18 @@ mlx5_traffic_enable(struct rte_eth_dev *dev) txq_ctrl->hairpin_conf.tx_explicit == 0 && txq_ctrl->hairpin_conf.peers[0].port == priv->dev_data->port_id) { - ret = mlx5_ctrl_flow_source_queue(dev, i); + ret = mlx5_ctrl_flow_source_queue(dev, + mlx5_txq_get_sqn(txq_ctrl)); if (ret) { mlx5_txq_release(dev, i); goto error; } } if (priv->sh->config.dv_esw_en) { - if (mlx5_flow_create_devx_sq_miss_flow(dev, i) == 0) { + uint32_t q = mlx5_txq_get_sqn(txq_ctrl); + + if (mlx5_flow_create_devx_sq_miss_flow(dev, q) == 0) { + mlx5_txq_release(dev, i); DRV_LOG(ERR, "Port %u Tx queue %u SQ create representor devx default miss rule failed.", dev->data->port_id, i); diff --git a/drivers/net/mlx5/mlx5_tx.h b/drivers/net/mlx5/mlx5_tx.h index e0fc1872fe..6471ebf59f 100644 --- a/drivers/net/mlx5/mlx5_tx.h +++ b/drivers/net/mlx5/mlx5_tx.h @@ -213,6 +213,7 @@ struct mlx5_txq_ctrl *mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx); int mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx); int mlx5_txq_releasable(struct rte_eth_dev *dev, uint16_t idx); int mlx5_txq_verify(struct rte_eth_dev *dev); +int mlx5_txq_get_sqn(struct mlx5_txq_ctrl *txq); void txq_alloc_elts(struct mlx5_txq_ctrl *txq_ctrl); void txq_free_elts(struct mlx5_txq_ctrl *txq_ctrl); uint64_t mlx5_get_tx_port_offloads(struct rte_eth_dev *dev); diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c index 9150ced72d..7a0f1d61a5 100644 --- a/drivers/net/mlx5/mlx5_txq.c +++ b/drivers/net/mlx5/mlx5_txq.c @@ -27,6 +27,8 @@ #include "mlx5_tx.h" #include "mlx5_rxtx.h" #include "mlx5_autoconf.h" +#include "rte_pmd_mlx5.h" +#include "mlx5_flow.h" /** * Allocate TX queue elements. @@ -1274,6 +1276,51 @@ mlx5_txq_verify(struct rte_eth_dev *dev) return ret; } +int +mlx5_txq_get_sqn(struct mlx5_txq_ctrl *txq) +{ + return txq->is_hairpin ? txq->obj->sq->id : txq->obj->sq_obj.sq->id; +} + +int +rte_pmd_mlx5_external_sq_enable(uint16_t port_id, uint32_t sq_num) +{ + struct rte_eth_dev *dev; + struct mlx5_priv *priv; + uint32_t flow; + + if (rte_eth_dev_is_valid_port(port_id) < 0) { + DRV_LOG(ERR, "There is no Ethernet device for port %u.", + port_id); + rte_errno = ENODEV; + return -rte_errno; + } + dev = &rte_eth_devices[port_id]; + priv = dev->data->dev_private; + if ((!priv->representor && !priv->master) || + !priv->sh->config.dv_esw_en) { + DRV_LOG(ERR, "Port %u must be represetnor or master port in E-Switch mode.", + port_id); + rte_errno = EINVAL; + return -rte_errno; + } + if (sq_num == 0) { + DRV_LOG(ERR, "Invalid SQ number."); + rte_errno = EINVAL; + return -rte_errno; + } +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + if (priv->sh->config.dv_flow_en == 2) + return mlx5_flow_hw_esw_create_sq_miss_flow(dev, sq_num); +#endif + flow = mlx5_flow_create_devx_sq_miss_flow(dev, sq_num); + if (flow > 0) + return 0; + DRV_LOG(ERR, "Port %u failed to create default miss flow for SQ %u.", + port_id, sq_num); + return -rte_errno; +} + /** * Set the Tx queue dynamic timestamp (mask and offset) * diff --git a/drivers/net/mlx5/rte_pmd_mlx5.h b/drivers/net/mlx5/rte_pmd_mlx5.h index fbfdd9737b..d4caea5b20 100644 --- a/drivers/net/mlx5/rte_pmd_mlx5.h +++ b/drivers/net/mlx5/rte_pmd_mlx5.h @@ -139,6 +139,23 @@ int rte_pmd_mlx5_external_rx_queue_id_unmap(uint16_t port_id, __rte_experimental int rte_pmd_mlx5_host_shaper_config(int port_id, uint8_t rate, uint32_t flags); +/** + * Enable traffic for external SQ. + * + * @param[in] port_id + * The port identifier of the Ethernet device. + * @param[in] sq_num + * SQ HW number. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + * Possible values for rte_errno: + * - EINVAL - invalid sq_number or port type. + * - ENODEV - there is no Ethernet device for this port id. + */ +__rte_experimental +int rte_pmd_mlx5_external_sq_enable(uint16_t port_id, uint32_t sq_num); + #ifdef __cplusplus } #endif diff --git a/drivers/net/mlx5/version.map b/drivers/net/mlx5/version.map index 9942de5079..848270da13 100644 --- a/drivers/net/mlx5/version.map +++ b/drivers/net/mlx5/version.map @@ -14,4 +14,5 @@ EXPERIMENTAL { rte_pmd_mlx5_external_rx_queue_id_unmap; # added in 22.07 rte_pmd_mlx5_host_shaper_config; + rte_pmd_mlx5_external_sq_enable; }; From patchwork Fri Sep 30 12:53:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suanming Mou X-Patchwork-Id: 117227 X-Patchwork-Delegate: rasland@nvidia.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5C838A00C4; Fri, 30 Sep 2022 14:56:11 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id AF2A242BD3; Fri, 30 Sep 2022 14:54:29 +0200 (CEST) Received: from NAM11-BN8-obe.outbound.protection.outlook.com (mail-bn8nam11on2040.outbound.protection.outlook.com [40.107.236.40]) by mails.dpdk.org (Postfix) with ESMTP id D6FF442BC9 for ; Fri, 30 Sep 2022 14:54:25 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=HGHIASqoyN67eIWpLBUSctfevzpklOEE1XqpeyiBfPnKJ7LIg0lOVPtfWpKCtTX7qJXo8uo8XZkspkKskeGAvjTvT1bVYSKLXFcF28z0sUR6uHWPI2ZWLqD/3zq5uiiBkwZVYPDnO33KCUVQlXRoKSVzTinIjFbYlfbC1mEvdmKkF0CZtfhMzJ5vUwp5Y7PMZkNBEwSjiRVhvwJj2c/ftx2Sch4zftxlYzIqyDuoBTIq5yfNfAvO+i2gj+/LpKiv6P4ITNOT3UVBUz5ktG1+bVDKGIqJVFRLo9xkGML6I+bAz3IwYIOVny1MSUub4lTAQXc11feYq96peidWVo8Qbg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=8iylnYThu5ufnhL5oYP4orRGo3Zxmai7KDRxPqmrQIE=; b=mML8gSER47pfEOOeu2g1+c3J+JOU+RqC+T10TAJcxvwv0dgJOs3TZqB4j8hhOWXLs9h4hn3tyV2xyQS8DKEIjn3lLOkhtol3c8hZoOia4sJYMRUMs1P5Xh8xHs//ZehpVWTUVuwgd2bAOaY4PQRWtn9TpT2B1DEmN7FIByJ0l5sjJp272IRCuBcRV/X2p3C7bc4eXH+jyLBTIV/1Jq5vjYpVBy6OgNKs6QyKYV20zSkbca+fZ+aqsrCujhkC+XODoWnJtkIOPmTVZZIa2ExtCSy3jshbmJhy0lD00tXhut6WvsXAt7yaPB3/yBt+EUqFlX4XMsIvHhQHmJoyIu1kOg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.117.160) smtp.rcpttodomain=dpdk.org smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=8iylnYThu5ufnhL5oYP4orRGo3Zxmai7KDRxPqmrQIE=; b=qD8U/3c9GiaTcBhOaGkktjzKRthRxFqRHrR+H6L+rNz29mK11m7sKmsGTJwjL9RmlRBscwLZEga95Y6lsgXLUTl6CLJYA+CiL2LpGbPutr7/svuII/ElHObxX4rI0m0EJh8wPbf2+kLJJHFa1cU/WkBhOoavWFhHHG4XtsBzhp0h3s4S0rfrCQVGsTKaWIwHmsl4NIoaepIDQBQmbjTJG+UTvhty42twM9LueDpixf88GE406MrhoFrpcXKOLoX2S+OfoJnnJ+eRsEZY23TgDYKRS8aNbFov8dzODkAtOURL+p5349GGjmy/tXBHbXfSUtKdcYseY7MStETrEV0SZQ== Received: from DM6PR07CA0043.namprd07.prod.outlook.com (2603:10b6:5:74::20) by CY5PR12MB6347.namprd12.prod.outlook.com (2603:10b6:930:20::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.20; Fri, 30 Sep 2022 12:54:23 +0000 Received: from DM6NAM11FT081.eop-nam11.prod.protection.outlook.com (2603:10b6:5:74:cafe::c4) by DM6PR07CA0043.outlook.office365.com (2603:10b6:5:74::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.20 via Frontend Transport; Fri, 30 Sep 2022 12:54:23 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.117.160) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.117.160 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.117.160; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.117.160) by DM6NAM11FT081.mail.protection.outlook.com (10.13.172.136) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5676.17 via Frontend Transport; Fri, 30 Sep 2022 12:54:23 +0000 Received: from rnnvmail201.nvidia.com (10.129.68.8) by mail.nvidia.com (10.129.200.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.26; Fri, 30 Sep 2022 05:54:14 -0700 Received: from nvidia.com (10.126.230.35) by rnnvmail201.nvidia.com (10.129.68.8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.29; Fri, 30 Sep 2022 05:54:11 -0700 From: Suanming Mou To: Matan Azrad , Viacheslav Ovsiienko CC: , , , "Dariusz Sosnowski" Subject: [PATCH v3 17/17] net/mlx5: support device control of representor matching Date: Fri, 30 Sep 2022 15:53:15 +0300 Message-ID: <20220930125315.5079-18-suanmingm@nvidia.com> X-Mailer: git-send-email 2.18.1 In-Reply-To: <20220930125315.5079-1-suanmingm@nvidia.com> References: <20220923144334.27736-1-suanmingm@nvidia.com> <20220930125315.5079-1-suanmingm@nvidia.com> MIME-Version: 1.0 X-Originating-IP: [10.126.230.35] X-ClientProxiedBy: rnnvmail201.nvidia.com (10.129.68.8) To rnnvmail201.nvidia.com (10.129.68.8) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DM6NAM11FT081:EE_|CY5PR12MB6347:EE_ X-MS-Office365-Filtering-Correlation-Id: 726aaff4-c497-4b04-4d47-08daa2e2e605 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 80um1MHEI21knOpdRZqZaKkILDLB2hbpt6mCPiBVc2rkFBkS3zKnEnQ8Jt1HoWP+2Urxl8jqr3RDrr4RkSdsGLNDqYS0rPY2UuQItBosk92xzYFVUTqv42surM4Jnqa2fKOVd+yVXDXbelkdDpidmNSb0yVeZ0XTNa6dmkQ98PfYVRaYLhO468ADQAySoqLPDjlLRYKAMmccpOTCQ+2K0mxgr/3MgqB9vbzlXF1y864MwuUaixqVH81noiy05MCbxkaiqjaG5jsXIdxLRmCyh1oWyv/pPT3EGBuk1LU6U9PalBtJruCo1v2JR1ifejAzmgT8fuVg9qYgdSWm9LWV0arDmQZN28ugKFtqLnaoiBakpDnzo/Y2oKzcP9+171Id5BYZ6wAOmNak3dH08R80ouLjh8h3NNIaPeUY3xcwet3v5d34RHsR2xyXErL+V6v45gyTiErU8N3M7h4xpN17C3uIltBwNE9w0kZPPHUOQMZDsRtLNh8ikaX2azca1dwme2J7SSGxhguhba7sZ1jKQPdFUC6YpkANB7eP4qtvvIjqbuqiu63WcvQmTpPQf+/s8GfNXUCNK4X7LROaSB+l6bYjB5qdGlZN4/XPkST+6WoW6GS4ztjINxGoPcsW/NRsT1ZeiW1XTl1S9IgifmJNGHMUCgiDprU2lwOvxlMdAT30S/IuujCBGcZGzLrmYge8qL6WR337ZMZTC/p8rXMuDrPaTSkGpmwqgATd7lsL4hhv9RLtlz2DXhcSAUhQZev8JHsulCS5PDUzKoEHBMBVGymeB8+fk4qk8ZBomhFBM7I= X-Forefront-Antispam-Report: CIP:216.228.117.160; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc6edge1.nvidia.com; CAT:NONE; SFS:(13230022)(4636009)(346002)(376002)(396003)(39860400002)(136003)(451199015)(46966006)(36840700001)(40470700004)(55016003)(110136005)(54906003)(316002)(6636002)(86362001)(40460700003)(40480700001)(478600001)(70586007)(70206006)(4326008)(8676002)(5660300002)(8936002)(356005)(30864003)(82740400003)(41300700001)(82310400005)(36860700001)(107886003)(2906002)(2616005)(336012)(7636003)(186003)(1076003)(426003)(36756003)(16526019)(83380400001)(26005)(47076005)(6286002)(7696005)(579004)(559001)(309714004); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Sep 2022 12:54:23.0199 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 726aaff4-c497-4b04-4d47-08daa2e2e605 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.117.160]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: DM6NAM11FT081.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY5PR12MB6347 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Dariusz Sosnowski In some E-Switch use cases applications want to receive all traffic on a single port. Since currently flow API does not provide a way to match traffic forwarded to any port representor, this patch adds support for controlling representor matching on ingress flow rules. Representor matching is controlled through new device argument repr_matching_en. - If representor matching is enabled (default setting), then each ingress pattern template has an implicit REPRESENTED_PORT item added. Flow rules based on this pattern template will match the vport associated with port on which rule is created. - If representor matching is disabled, then there will be no implicit item added. As a result ingress flow rules will match traffic coming to any port, not only the port on which flow rule is created. Representor matching is enabled by default, to provide an expected default behavior. This patch enables egress flow rules on representors when E-Switch is enabled in the following configurations: - repr_matching_en=1 and dv_xmeta_en=4 - repr_matching_en=1 and dv_xmeta_en=0 - repr_matching_en=0 and dv_xmeta_en=0 When representor matching is enabled, the following logic is implemented: 1. Creating an egress template table in group 0 for each port. These tables will hold default flow rules defined as follows: pattern SQ actions MODIFY_FIELD (set available bits in REG_C_0 to vport_meta_tag) MODIFY_FIELD (copy REG_A to REG_C_1, only when dv_xmeta_en == 4) JUMP (group 1) 2. Egress pattern templates created by an application have an implicit MLX5_RTE_FLOW_ITEM_TYPE_TAG item prepended to pattern, which matches available bits of REG_C_0. 3. Egress flow rules created by an application have an implicit MLX5_RTE_FLOW_ITEM_TYPE_TAG item prepended to pattern, which matches vport_meta_tag placed in available bits of REG_C_0. 4. Egress template tables created by an application, which are in group n, are placed in group n + 1. 5. Items and actions related to META are operating on REG_A when dv_xmeta_en == 0 or REG_C_1 when dv_xmeta_en == 4. When representor matching is disabled and extended metadata is disabled, no changes to current logic are required. Signed-off-by: Dariusz Sosnowski --- drivers/net/mlx5/linux/mlx5_os.c | 11 + drivers/net/mlx5/mlx5.c | 13 + drivers/net/mlx5/mlx5.h | 5 + drivers/net/mlx5/mlx5_flow.c | 8 +- drivers/net/mlx5/mlx5_flow.h | 7 + drivers/net/mlx5/mlx5_flow_hw.c | 738 ++++++++++++++++++++++++------- drivers/net/mlx5/mlx5_trigger.c | 167 ++++++- 7 files changed, 783 insertions(+), 166 deletions(-) diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c index de8c003d02..50d34b152a 100644 --- a/drivers/net/mlx5/linux/mlx5_os.c +++ b/drivers/net/mlx5/linux/mlx5_os.c @@ -1555,6 +1555,9 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, if (priv->sh->config.dv_flow_en == 2) { #ifdef HAVE_IBV_FLOW_DV_SUPPORT if (priv->sh->config.dv_esw_en) { + uint32_t usable_bits; + uint32_t required_bits; + if (priv->sh->dv_regc0_mask == UINT32_MAX) { DRV_LOG(ERR, "E-Switch port metadata is required when using HWS " "but it is disabled (configure it through devlink)"); @@ -1567,6 +1570,14 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev, err = ENOTSUP; goto error; } + usable_bits = __builtin_popcount(priv->sh->dv_regc0_mask); + required_bits = __builtin_popcount(priv->vport_meta_mask); + if (usable_bits < required_bits) { + DRV_LOG(ERR, "Not enough bits available in reg_c[0] to provide " + "representor matching."); + err = ENOTSUP; + goto error; + } } if (priv->vport_meta_mask) flow_hw_set_port_info(eth_dev); diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 742607509b..c249619a60 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -181,6 +181,9 @@ /* HW steering counter's query interval. */ #define MLX5_HWS_CNT_CYCLE_TIME "svc_cycle_time" +/* Device parameter to control representor matching in ingress/egress flows with HWS. */ +#define MLX5_REPR_MATCHING_EN "repr_matching_en" + /* Shared memory between primary and secondary processes. */ struct mlx5_shared_data *mlx5_shared_data; @@ -1283,6 +1286,8 @@ mlx5_dev_args_check_handler(const char *key, const char *val, void *opaque) config->cnt_svc.service_core = tmp; } else if (strcmp(MLX5_HWS_CNT_CYCLE_TIME, key) == 0) { config->cnt_svc.cycle_time = tmp; + } else if (strcmp(MLX5_REPR_MATCHING_EN, key) == 0) { + config->repr_matching = !!tmp; } return 0; } @@ -1321,6 +1326,7 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, MLX5_FDB_DEFAULT_RULE_EN, MLX5_HWS_CNT_SERVICE_CORE, MLX5_HWS_CNT_CYCLE_TIME, + MLX5_REPR_MATCHING_EN, NULL, }; int ret = 0; @@ -1335,6 +1341,7 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, config->fdb_def_rule = 1; config->cnt_svc.cycle_time = MLX5_CNT_SVC_CYCLE_TIME_DEFAULT; config->cnt_svc.service_core = rte_get_main_lcore(); + config->repr_matching = 1; if (mkvlist != NULL) { /* Process parameters. */ ret = mlx5_kvargs_process(mkvlist, params, @@ -1368,6 +1375,11 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, config->dv_xmeta_en); config->dv_xmeta_en = MLX5_XMETA_MODE_LEGACY; } + if (config->dv_flow_en != 2 && !config->repr_matching) { + DRV_LOG(DEBUG, "Disabling representor matching is valid only " + "when HW Steering is enabled."); + config->repr_matching = 1; + } if (config->tx_pp && !sh->dev_cap.txpp_en) { DRV_LOG(ERR, "Packet pacing is not supported."); rte_errno = ENODEV; @@ -1411,6 +1423,7 @@ mlx5_shared_dev_ctx_args_config(struct mlx5_dev_ctx_shared *sh, DRV_LOG(DEBUG, "\"allow_duplicate_pattern\" is %u.", config->allow_duplicate_pattern); DRV_LOG(DEBUG, "\"fdb_def_rule_en\" is %u.", config->fdb_def_rule); + DRV_LOG(DEBUG, "\"repr_matching_en\" is %u.", config->repr_matching); return 0; } diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 419b5a18ca..a0fb6d04d8 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -316,6 +316,7 @@ struct mlx5_sh_config { } cnt_svc; /* configure for HW steering's counter's service. */ /* Allow/Prevent the duplicate rules pattern. */ uint32_t fdb_def_rule:1; /* Create FDB default jump rule */ + uint32_t repr_matching:1; /* Enable implicit vport matching in HWS FDB. */ }; /* Structure for VF VLAN workaround. */ @@ -366,6 +367,7 @@ struct mlx5_hw_q_job { void *out_data; } __rte_packed; struct rte_flow_item_ethdev port_spec; + struct rte_flow_item_tag tag_spec; } __rte_packed; }; @@ -1673,6 +1675,9 @@ struct mlx5_priv { struct rte_flow_template_table *hw_esw_sq_miss_tbl; struct rte_flow_template_table *hw_esw_zero_tbl; struct rte_flow_template_table *hw_tx_meta_cpy_tbl; + struct rte_flow_pattern_template *hw_tx_repr_tagging_pt; + struct rte_flow_actions_template *hw_tx_repr_tagging_at; + struct rte_flow_template_table *hw_tx_repr_tagging_tbl; struct mlx5_indexed_pool *flows[MLX5_FLOW_TYPE_MAXI]; /* RTE Flow rules. */ uint32_t ctrl_flows; /* Control flow rules. */ diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 2142cd828a..026d4eb9c0 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -1123,7 +1123,11 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev, } break; case MLX5_METADATA_TX: - return REG_A; + if (config->dv_flow_en == 2 && config->dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS) { + return REG_C_1; + } else { + return REG_A; + } case MLX5_METADATA_FDB: switch (config->dv_xmeta_en) { case MLX5_XMETA_MODE_LEGACY: @@ -11319,7 +11323,7 @@ mlx5_flow_pick_transfer_proxy(struct rte_eth_dev *dev, return 0; } } - return rte_flow_error_set(error, EINVAL, + return rte_flow_error_set(error, ENODEV, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, "unable to find a proxy port"); } diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 63f946473d..a497dac474 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -1199,12 +1199,18 @@ struct rte_flow_pattern_template { struct rte_flow_pattern_template_attr attr; struct mlx5dr_match_template *mt; /* mlx5 match template. */ uint64_t item_flags; /* Item layer flags. */ + uint64_t orig_item_nb; /* Number of pattern items provided by the user (with END item). */ uint32_t refcnt; /* Reference counter. */ /* * If true, then rule pattern should be prepended with * represented_port pattern item. */ bool implicit_port; + /* + * If true, then rule pattern should be prepended with + * tag pattern item for representor matching. + */ + bool implicit_tag; }; /* Flow action template struct. */ @@ -2479,6 +2485,7 @@ int mlx5_flow_hw_esw_create_sq_miss_flow(struct rte_eth_dev *dev, uint32_t sqn); int mlx5_flow_hw_esw_create_default_jump_flow(struct rte_eth_dev *dev); int mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev); +int mlx5_flow_hw_tx_repr_matching_flow(struct rte_eth_dev *dev, uint32_t sqn); int mlx5_flow_actions_validate(struct rte_eth_dev *dev, const struct rte_flow_actions_template_attr *attr, const struct rte_flow_action actions[], diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c index b2824ad8fe..461d344700 100644 --- a/drivers/net/mlx5/mlx5_flow_hw.c +++ b/drivers/net/mlx5/mlx5_flow_hw.c @@ -32,12 +32,15 @@ /* Maximum number of rules in control flow tables. */ #define MLX5_HW_CTRL_FLOW_NB_RULES (4096) -/* Lowest flow group usable by an application. */ +/* Lowest flow group usable by an application if group translation is done. */ #define MLX5_HW_LOWEST_USABLE_GROUP (1) /* Maximum group index usable by user applications for transfer flows. */ #define MLX5_HW_MAX_TRANSFER_GROUP (UINT32_MAX - 1) +/* Maximum group index usable by user applications for egress flows. */ +#define MLX5_HW_MAX_EGRESS_GROUP (UINT32_MAX - 1) + /* Lowest priority for HW root table. */ #define MLX5_HW_LOWEST_PRIO_ROOT 15 @@ -61,6 +64,9 @@ flow_hw_set_vlan_vid_construct(struct rte_eth_dev *dev, const struct mlx5_hw_actions *hw_acts, const struct rte_flow_action *action); +static __rte_always_inline uint32_t flow_hw_tx_tag_regc_mask(struct rte_eth_dev *dev); +static __rte_always_inline uint32_t flow_hw_tx_tag_regc_value(struct rte_eth_dev *dev); + const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops; /* DR action flags with different table. */ @@ -2346,21 +2352,18 @@ flow_hw_get_rule_items(struct rte_eth_dev *dev, uint8_t pattern_template_index, struct mlx5_hw_q_job *job) { - if (table->its[pattern_template_index]->implicit_port) { - const struct rte_flow_item *curr_item; - unsigned int nb_items; - bool found_end; - unsigned int i; - - /* Count number of pattern items. */ - nb_items = 0; - found_end = false; - for (curr_item = items; !found_end; ++curr_item) { - ++nb_items; - if (curr_item->type == RTE_FLOW_ITEM_TYPE_END) - found_end = true; + struct rte_flow_pattern_template *pt = table->its[pattern_template_index]; + + /* Only one implicit item can be added to flow rule pattern. */ + MLX5_ASSERT(!pt->implicit_port || !pt->implicit_tag); + /* At least one item was allocated in job descriptor for items. */ + MLX5_ASSERT(MLX5_HW_MAX_ITEMS >= 1); + if (pt->implicit_port) { + if (pt->orig_item_nb + 1 > MLX5_HW_MAX_ITEMS) { + rte_errno = ENOMEM; + return NULL; } - /* Prepend represented port item. */ + /* Set up represented port item in job descriptor. */ job->port_spec = (struct rte_flow_item_ethdev){ .port_id = dev->data->port_id, }; @@ -2368,21 +2371,26 @@ flow_hw_get_rule_items(struct rte_eth_dev *dev, .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, .spec = &job->port_spec, }; - found_end = false; - for (i = 1; i < MLX5_HW_MAX_ITEMS && i - 1 < nb_items; ++i) { - job->items[i] = items[i - 1]; - if (items[i - 1].type == RTE_FLOW_ITEM_TYPE_END) { - found_end = true; - break; - } - } - if (i >= MLX5_HW_MAX_ITEMS && !found_end) { + rte_memcpy(&job->items[1], items, sizeof(*items) * pt->orig_item_nb); + return job->items; + } else if (pt->implicit_tag) { + if (pt->orig_item_nb + 1 > MLX5_HW_MAX_ITEMS) { rte_errno = ENOMEM; return NULL; } + /* Set up tag item in job descriptor. */ + job->tag_spec = (struct rte_flow_item_tag){ + .data = flow_hw_tx_tag_regc_value(dev), + }; + job->items[0] = (struct rte_flow_item){ + .type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_TAG, + .spec = &job->tag_spec, + }; + rte_memcpy(&job->items[1], items, sizeof(*items) * pt->orig_item_nb); return job->items; + } else { + return items; } - return items; } /** @@ -2960,6 +2968,11 @@ flow_hw_table_create(struct rte_eth_dev *dev, uint8_t nb_action_templates, struct rte_flow_error *error) { + struct rte_flow_error sub_error = { + .type = RTE_FLOW_ERROR_TYPE_NONE, + .cause = NULL, + .message = NULL, + }; struct mlx5_priv *priv = dev->data->dev_private; struct mlx5dr_matcher_attr matcher_attr = {0}; struct rte_flow_template_table *tbl = NULL; @@ -2970,7 +2983,7 @@ flow_hw_table_create(struct rte_eth_dev *dev, struct rte_flow_attr flow_attr = attr->flow_attr; struct mlx5_flow_cb_ctx ctx = { .dev = dev, - .error = error, + .error = &sub_error, .data = &flow_attr, }; struct mlx5_indexed_pool_config cfg = { @@ -3064,7 +3077,7 @@ flow_hw_table_create(struct rte_eth_dev *dev, continue; err = __flow_hw_actions_translate(dev, &tbl->cfg, &tbl->ats[i].acts, - action_templates[i], error); + action_templates[i], &sub_error); if (err) { i++; goto at_error; @@ -3105,12 +3118,11 @@ flow_hw_table_create(struct rte_eth_dev *dev, mlx5_free(tbl); } if (error != NULL) { - rte_flow_error_set(error, err, - error->type == RTE_FLOW_ERROR_TYPE_NONE ? - RTE_FLOW_ERROR_TYPE_UNSPECIFIED : error->type, - NULL, - error->message == NULL ? - "fail to create rte table" : error->message); + if (sub_error.type == RTE_FLOW_ERROR_TYPE_NONE) + rte_flow_error_set(error, err, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Failed to create template table"); + else + rte_memcpy(error, &sub_error, sizeof(sub_error)); } return NULL; } @@ -3171,9 +3183,10 @@ flow_hw_translate_group(struct rte_eth_dev *dev, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_sh_config *config = &priv->sh->config; const struct rte_flow_attr *flow_attr = &cfg->attr.flow_attr; - if (priv->sh->config.dv_esw_en && + if (config->dv_esw_en && priv->fdb_def_rule && cfg->external && flow_attr->transfer) { @@ -3183,6 +3196,22 @@ flow_hw_translate_group(struct rte_eth_dev *dev, NULL, "group index not supported"); *table_group = group + 1; + } else if (config->dv_esw_en && + !(config->repr_matching && config->dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS) && + cfg->external && + flow_attr->egress) { + /* + * On E-Switch setups, egress group translation is not done if and only if + * representor matching is disabled and legacy metadata mode is selected. + * In all other cases, egree group 0 is reserved for representor tagging flows + * and metadata copy flows. + */ + if (group > MLX5_HW_MAX_EGRESS_GROUP) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ATTR_GROUP, + NULL, + "group index not supported"); + *table_group = group + 1; } else { *table_group = group; } @@ -3223,7 +3252,6 @@ flow_hw_template_table_create(struct rte_eth_dev *dev, uint8_t nb_action_templates, struct rte_flow_error *error) { - struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_flow_template_table_cfg cfg = { .attr = *attr, .external = true, @@ -3232,12 +3260,6 @@ flow_hw_template_table_create(struct rte_eth_dev *dev, if (flow_hw_translate_group(dev, &cfg, group, &cfg.attr.flow_attr.group, error)) return NULL; - if (priv->sh->config.dv_esw_en && cfg.attr.flow_attr.egress) { - rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR, NULL, - "egress flows are not supported with HW Steering" - " when E-Switch is enabled"); - return NULL; - } return flow_hw_table_create(dev, &cfg, item_templates, nb_item_templates, action_templates, nb_action_templates, error); } @@ -4494,26 +4516,28 @@ flow_hw_actions_template_destroy(struct rte_eth_dev *dev __rte_unused, return 0; } -static struct rte_flow_item * -flow_hw_copy_prepend_port_item(const struct rte_flow_item *items, - struct rte_flow_error *error) +static uint32_t +flow_hw_count_items(const struct rte_flow_item *items) { const struct rte_flow_item *curr_item; - struct rte_flow_item *copied_items; - bool found_end; - unsigned int nb_items; - unsigned int i; - size_t size; + uint32_t nb_items; - /* Count number of pattern items. */ nb_items = 0; - found_end = false; - for (curr_item = items; !found_end; ++curr_item) { + for (curr_item = items; curr_item->type != RTE_FLOW_ITEM_TYPE_END; ++curr_item) ++nb_items; - if (curr_item->type == RTE_FLOW_ITEM_TYPE_END) - found_end = true; - } - /* Allocate new array of items and prepend REPRESENTED_PORT item. */ + return ++nb_items; +} + +static struct rte_flow_item * +flow_hw_prepend_item(const struct rte_flow_item *items, + const uint32_t nb_items, + const struct rte_flow_item *new_item, + struct rte_flow_error *error) +{ + struct rte_flow_item *copied_items; + size_t size; + + /* Allocate new array of items. */ size = sizeof(*copied_items) * (nb_items + 1); copied_items = mlx5_malloc(MLX5_MEM_ZERO, size, 0, rte_socket_id()); if (!copied_items) { @@ -4523,14 +4547,9 @@ flow_hw_copy_prepend_port_item(const struct rte_flow_item *items, "cannot allocate item template"); return NULL; } - copied_items[0] = (struct rte_flow_item){ - .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, - .spec = NULL, - .last = NULL, - .mask = &rte_flow_item_ethdev_mask, - }; - for (i = 1; i < nb_items + 1; ++i) - copied_items[i] = items[i - 1]; + /* Put new item at the beginning and copy the rest. */ + copied_items[0] = *new_item; + rte_memcpy(&copied_items[1], items, sizeof(*items) * nb_items); return copied_items; } @@ -4551,17 +4570,13 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, if (priv->sh->config.dv_esw_en) { MLX5_ASSERT(priv->master || priv->representor); if (priv->master) { - /* - * It is allowed to specify ingress, egress and transfer attributes - * at the same time, in order to construct flows catching all missed - * FDB traffic and forwarding it to the master port. - */ - if (!(attr->ingress ^ attr->egress ^ attr->transfer)) + if ((attr->ingress && attr->egress) || + (attr->ingress && attr->transfer) || + (attr->egress && attr->transfer)) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ATTR, NULL, - "only one or all direction attributes" - " at once can be used on transfer proxy" - " port"); + "only one direction attribute at once" + " can be used on transfer proxy port"); } else { if (attr->transfer) return rte_flow_error_set(error, EINVAL, @@ -4614,11 +4629,16 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, break; } case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT: - if (attr->ingress || attr->egress) + if (attr->ingress && priv->sh->config.repr_matching) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, NULL, + "represented port item cannot be used" + " when ingress attribute is set"); + if (attr->egress) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, "represented port item cannot be used" - " when transfer attribute is set"); + " when egress attribute is set"); break; case RTE_FLOW_ITEM_TYPE_META: if (!priv->sh->config.dv_esw_en || @@ -4680,6 +4700,17 @@ flow_hw_pattern_validate(struct rte_eth_dev *dev, return 0; } +static bool +flow_hw_pattern_has_sq_match(const struct rte_flow_item *items) +{ + unsigned int i; + + for (i = 0; items[i].type != RTE_FLOW_ITEM_TYPE_END; ++i) + if (items[i].type == (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_SQ) + return true; + return false; +} + /** * Create flow item template. * @@ -4705,17 +4736,53 @@ flow_hw_pattern_template_create(struct rte_eth_dev *dev, struct rte_flow_pattern_template *it; struct rte_flow_item *copied_items = NULL; const struct rte_flow_item *tmpl_items; + uint64_t orig_item_nb; + struct rte_flow_item port = { + .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, + .mask = &rte_flow_item_ethdev_mask, + }; + struct rte_flow_item_tag tag_v = { + .data = 0, + .index = REG_C_0, + }; + struct rte_flow_item_tag tag_m = { + .data = flow_hw_tx_tag_regc_mask(dev), + .index = 0xff, + }; + struct rte_flow_item tag = { + .type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_TAG, + .spec = &tag_v, + .mask = &tag_m, + .last = NULL + }; if (flow_hw_pattern_validate(dev, attr, items, error)) return NULL; - if (priv->sh->config.dv_esw_en && attr->ingress && !attr->egress && !attr->transfer) { - copied_items = flow_hw_copy_prepend_port_item(items, error); + orig_item_nb = flow_hw_count_items(items); + if (priv->sh->config.dv_esw_en && + priv->sh->config.repr_matching && + attr->ingress && !attr->egress && !attr->transfer) { + copied_items = flow_hw_prepend_item(items, orig_item_nb, &port, error); + if (!copied_items) + return NULL; + tmpl_items = copied_items; + } else if (priv->sh->config.dv_esw_en && + priv->sh->config.repr_matching && + !attr->ingress && attr->egress && !attr->transfer) { + if (flow_hw_pattern_has_sq_match(items)) { + DRV_LOG(DEBUG, "Port %u omitting implicit REG_C_0 match for egress " + "pattern template", dev->data->port_id); + tmpl_items = items; + goto setup_pattern_template; + } + copied_items = flow_hw_prepend_item(items, orig_item_nb, &tag, error); if (!copied_items) return NULL; tmpl_items = copied_items; } else { tmpl_items = items; } +setup_pattern_template: it = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*it), 0, rte_socket_id()); if (!it) { if (copied_items) @@ -4727,6 +4794,7 @@ flow_hw_pattern_template_create(struct rte_eth_dev *dev, return NULL; } it->attr = *attr; + it->orig_item_nb = orig_item_nb; it->mt = mlx5dr_match_template_create(tmpl_items, attr->relaxed_matching); if (!it->mt) { if (copied_items) @@ -4739,11 +4807,15 @@ flow_hw_pattern_template_create(struct rte_eth_dev *dev, return NULL; } it->item_flags = flow_hw_rss_item_flags_get(tmpl_items); - it->implicit_port = !!copied_items; + if (copied_items) { + if (attr->ingress) + it->implicit_port = true; + else if (attr->egress) + it->implicit_tag = true; + mlx5_free(copied_items); + } __atomic_fetch_add(&it->refcnt, 1, __ATOMIC_RELAXED); LIST_INSERT_HEAD(&priv->flow_hw_itt, it, next); - if (copied_items) - mlx5_free(copied_items); return it; } @@ -5143,6 +5215,254 @@ flow_hw_free_vport_actions(struct mlx5_priv *priv) priv->hw_vport = NULL; } +/** + * Create an egress pattern template matching on source SQ. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * Pointer to pattern template on success. NULL otherwise, and rte_errno is set. + */ +static struct rte_flow_pattern_template * +flow_hw_create_tx_repr_sq_pattern_tmpl(struct rte_eth_dev *dev) +{ + struct rte_flow_pattern_template_attr attr = { + .relaxed_matching = 0, + .egress = 1, + }; + struct mlx5_rte_flow_item_sq sq_mask = { + .queue = UINT32_MAX, + }; + struct rte_flow_item items[] = { + { + .type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_SQ, + .mask = &sq_mask, + }, + { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + + return flow_hw_pattern_template_create(dev, &attr, items, NULL); +} + +static __rte_always_inline uint32_t +flow_hw_tx_tag_regc_mask(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + uint32_t mask = priv->sh->dv_regc0_mask; + + /* Mask is verified during device initialization. Sanity checking here. */ + MLX5_ASSERT(mask != 0); + /* + * Availability of sufficient number of bits in REG_C_0 is verified on initialization. + * Sanity checking here. + */ + MLX5_ASSERT(__builtin_popcount(mask) >= __builtin_popcount(priv->vport_meta_mask)); + return mask; +} + +static __rte_always_inline uint32_t +flow_hw_tx_tag_regc_value(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + uint32_t tag; + + /* Mask is verified during device initialization. Sanity checking here. */ + MLX5_ASSERT(priv->vport_meta_mask != 0); + tag = priv->vport_meta_tag >> (rte_bsf32(priv->vport_meta_mask)); + /* + * Availability of sufficient number of bits in REG_C_0 is verified on initialization. + * Sanity checking here. + */ + MLX5_ASSERT((tag & priv->sh->dv_regc0_mask) == tag); + return tag; +} + +static void +flow_hw_update_action_mask(struct rte_flow_action *action, + struct rte_flow_action *mask, + enum rte_flow_action_type type, + void *conf_v, + void *conf_m) +{ + action->type = type; + action->conf = conf_v; + mask->type = type; + mask->conf = conf_m; +} + +/** + * Create an egress actions template with MODIFY_FIELD action for setting unused REG_C_0 bits + * to vport tag and JUMP action to group 1. + * + * If extended metadata mode is enabled, then MODIFY_FIELD action for copying software metadata + * to REG_C_1 is added as well. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * Pointer to actions template on success. NULL otherwise, and rte_errno is set. + */ +static struct rte_flow_actions_template * +flow_hw_create_tx_repr_tag_jump_acts_tmpl(struct rte_eth_dev *dev) +{ + uint32_t tag_mask = flow_hw_tx_tag_regc_mask(dev); + uint32_t tag_value = flow_hw_tx_tag_regc_value(dev); + struct rte_flow_actions_template_attr attr = { + .egress = 1, + }; + struct rte_flow_action_modify_field set_tag_v = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_C_0, + .offset = rte_bsf32(tag_mask), + }, + .src = { + .field = RTE_FLOW_FIELD_VALUE, + }, + .width = __builtin_popcount(tag_mask), + }; + struct rte_flow_action_modify_field set_tag_m = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = UINT32_MAX, + .offset = UINT32_MAX, + }, + .src = { + .field = RTE_FLOW_FIELD_VALUE, + }, + .width = UINT32_MAX, + }; + struct rte_flow_action_modify_field copy_metadata_v = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_C_1, + }, + .src = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = REG_A, + }, + .width = 32, + }; + struct rte_flow_action_modify_field copy_metadata_m = { + .operation = RTE_FLOW_MODIFY_SET, + .dst = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = UINT32_MAX, + .offset = UINT32_MAX, + }, + .src = { + .field = (enum rte_flow_field_id)MLX5_RTE_FLOW_FIELD_META_REG, + .level = UINT32_MAX, + .offset = UINT32_MAX, + }, + .width = UINT32_MAX, + }; + struct rte_flow_action_jump jump_v = { + .group = MLX5_HW_LOWEST_USABLE_GROUP, + }; + struct rte_flow_action_jump jump_m = { + .group = UINT32_MAX, + }; + struct rte_flow_action actions_v[4] = { { 0 } }; + struct rte_flow_action actions_m[4] = { { 0 } }; + unsigned int idx = 0; + + rte_memcpy(set_tag_v.src.value, &tag_value, sizeof(tag_value)); + rte_memcpy(set_tag_m.src.value, &tag_mask, sizeof(tag_mask)); + flow_hw_update_action_mask(&actions_v[idx], &actions_m[idx], + RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + &set_tag_v, &set_tag_m); + idx++; + if (MLX5_SH(dev)->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS) { + flow_hw_update_action_mask(&actions_v[idx], &actions_m[idx], + RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, + ©_metadata_v, ©_metadata_m); + idx++; + } + flow_hw_update_action_mask(&actions_v[idx], &actions_m[idx], RTE_FLOW_ACTION_TYPE_JUMP, + &jump_v, &jump_m); + idx++; + flow_hw_update_action_mask(&actions_v[idx], &actions_m[idx], RTE_FLOW_ACTION_TYPE_END, + NULL, NULL); + idx++; + MLX5_ASSERT(idx <= RTE_DIM(actions_v)); + return flow_hw_actions_template_create(dev, &attr, actions_v, actions_m, NULL); +} + +static void +flow_hw_cleanup_tx_repr_tagging(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + if (priv->hw_tx_repr_tagging_tbl) { + flow_hw_table_destroy(dev, priv->hw_tx_repr_tagging_tbl, NULL); + priv->hw_tx_repr_tagging_tbl = NULL; + } + if (priv->hw_tx_repr_tagging_at) { + flow_hw_actions_template_destroy(dev, priv->hw_tx_repr_tagging_at, NULL); + priv->hw_tx_repr_tagging_at = NULL; + } + if (priv->hw_tx_repr_tagging_pt) { + flow_hw_pattern_template_destroy(dev, priv->hw_tx_repr_tagging_pt, NULL); + priv->hw_tx_repr_tagging_pt = NULL; + } +} + +/** + * Setup templates and table used to create default Tx flow rules. These default rules + * allow for matching Tx representor traffic using a vport tag placed in unused bits of + * REG_C_0 register. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * 0 on success, negative errno value otherwise. + */ +static int +flow_hw_setup_tx_repr_tagging(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_flow_template_table_attr attr = { + .flow_attr = { + .group = 0, + .priority = MLX5_HW_LOWEST_PRIO_ROOT, + .egress = 1, + }, + .nb_flows = MLX5_HW_CTRL_FLOW_NB_RULES, + }; + struct mlx5_flow_template_table_cfg cfg = { + .attr = attr, + .external = false, + }; + + MLX5_ASSERT(priv->sh->config.dv_esw_en); + MLX5_ASSERT(priv->sh->config.repr_matching); + priv->hw_tx_repr_tagging_pt = flow_hw_create_tx_repr_sq_pattern_tmpl(dev); + if (!priv->hw_tx_repr_tagging_pt) + goto error; + priv->hw_tx_repr_tagging_at = flow_hw_create_tx_repr_tag_jump_acts_tmpl(dev); + if (!priv->hw_tx_repr_tagging_at) + goto error; + priv->hw_tx_repr_tagging_tbl = flow_hw_table_create(dev, &cfg, + &priv->hw_tx_repr_tagging_pt, 1, + &priv->hw_tx_repr_tagging_at, 1, + NULL); + if (!priv->hw_tx_repr_tagging_tbl) + goto error; + return 0; +error: + flow_hw_cleanup_tx_repr_tagging(dev); + return -rte_errno; +} + static uint32_t flow_hw_esw_mgr_regc_marker_mask(struct rte_eth_dev *dev) { @@ -5549,29 +5869,43 @@ flow_hw_create_tx_default_mreg_copy_actions_template(struct rte_eth_dev *dev) }, .width = UINT32_MAX, }; - const struct rte_flow_action copy_reg_action[] = { + const struct rte_flow_action_jump jump_action = { + .group = 1, + }; + const struct rte_flow_action_jump jump_mask = { + .group = UINT32_MAX, + }; + const struct rte_flow_action actions[] = { [0] = { .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, .conf = &mreg_action, }, [1] = { + .type = RTE_FLOW_ACTION_TYPE_JUMP, + .conf = &jump_action, + }, + [2] = { .type = RTE_FLOW_ACTION_TYPE_END, }, }; - const struct rte_flow_action copy_reg_mask[] = { + const struct rte_flow_action masks[] = { [0] = { .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, .conf = &mreg_mask, }, [1] = { + .type = RTE_FLOW_ACTION_TYPE_JUMP, + .conf = &jump_mask, + }, + [2] = { .type = RTE_FLOW_ACTION_TYPE_END, }, }; struct rte_flow_error drop_err; RTE_SET_USED(drop_err); - return flow_hw_actions_template_create(dev, &tx_act_attr, copy_reg_action, - copy_reg_mask, &drop_err); + return flow_hw_actions_template_create(dev, &tx_act_attr, actions, + masks, &drop_err); } /** @@ -5749,63 +6083,21 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) struct rte_flow_actions_template *jump_one_actions_tmpl = NULL; struct rte_flow_actions_template *tx_meta_actions_tmpl = NULL; uint32_t xmeta = priv->sh->config.dv_xmeta_en; + uint32_t repr_matching = priv->sh->config.repr_matching; - /* Item templates */ + /* Create templates and table for default SQ miss flow rules - root table. */ esw_mgr_items_tmpl = flow_hw_create_ctrl_esw_mgr_pattern_template(dev); if (!esw_mgr_items_tmpl) { DRV_LOG(ERR, "port %u failed to create E-Switch Manager item" " template for control flows", dev->data->port_id); goto error; } - regc_sq_items_tmpl = flow_hw_create_ctrl_regc_sq_pattern_template(dev); - if (!regc_sq_items_tmpl) { - DRV_LOG(ERR, "port %u failed to create SQ item template for" - " control flows", dev->data->port_id); - goto error; - } - port_items_tmpl = flow_hw_create_ctrl_port_pattern_template(dev); - if (!port_items_tmpl) { - DRV_LOG(ERR, "port %u failed to create SQ item template for" - " control flows", dev->data->port_id); - goto error; - } - if (xmeta == MLX5_XMETA_MODE_META32_HWS) { - tx_meta_items_tmpl = flow_hw_create_tx_default_mreg_copy_pattern_template(dev); - if (!tx_meta_items_tmpl) { - DRV_LOG(ERR, "port %u failed to Tx metadata copy pattern" - " template for control flows", dev->data->port_id); - goto error; - } - } - /* Action templates */ regc_jump_actions_tmpl = flow_hw_create_ctrl_regc_jump_actions_template(dev); if (!regc_jump_actions_tmpl) { DRV_LOG(ERR, "port %u failed to create REG_C set and jump action template" " for control flows", dev->data->port_id); goto error; } - port_actions_tmpl = flow_hw_create_ctrl_port_actions_template(dev); - if (!port_actions_tmpl) { - DRV_LOG(ERR, "port %u failed to create port action template" - " for control flows", dev->data->port_id); - goto error; - } - jump_one_actions_tmpl = flow_hw_create_ctrl_jump_actions_template - (dev, MLX5_HW_LOWEST_USABLE_GROUP); - if (!jump_one_actions_tmpl) { - DRV_LOG(ERR, "port %u failed to create jump action template" - " for control flows", dev->data->port_id); - goto error; - } - if (xmeta == MLX5_XMETA_MODE_META32_HWS) { - tx_meta_actions_tmpl = flow_hw_create_tx_default_mreg_copy_actions_template(dev); - if (!tx_meta_actions_tmpl) { - DRV_LOG(ERR, "port %u failed to Tx metadata copy actions" - " template for control flows", dev->data->port_id); - goto error; - } - } - /* Tables */ MLX5_ASSERT(priv->hw_esw_sq_miss_root_tbl == NULL); priv->hw_esw_sq_miss_root_tbl = flow_hw_create_ctrl_sq_miss_root_table (dev, esw_mgr_items_tmpl, regc_jump_actions_tmpl); @@ -5814,6 +6106,19 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) " for control flows", dev->data->port_id); goto error; } + /* Create templates and table for default SQ miss flow rules - non-root table. */ + regc_sq_items_tmpl = flow_hw_create_ctrl_regc_sq_pattern_template(dev); + if (!regc_sq_items_tmpl) { + DRV_LOG(ERR, "port %u failed to create SQ item template for" + " control flows", dev->data->port_id); + goto error; + } + port_actions_tmpl = flow_hw_create_ctrl_port_actions_template(dev); + if (!port_actions_tmpl) { + DRV_LOG(ERR, "port %u failed to create port action template" + " for control flows", dev->data->port_id); + goto error; + } MLX5_ASSERT(priv->hw_esw_sq_miss_tbl == NULL); priv->hw_esw_sq_miss_tbl = flow_hw_create_ctrl_sq_miss_table(dev, regc_sq_items_tmpl, port_actions_tmpl); @@ -5822,6 +6127,20 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) " for control flows", dev->data->port_id); goto error; } + /* Create templates and table for default FDB jump flow rules. */ + port_items_tmpl = flow_hw_create_ctrl_port_pattern_template(dev); + if (!port_items_tmpl) { + DRV_LOG(ERR, "port %u failed to create SQ item template for" + " control flows", dev->data->port_id); + goto error; + } + jump_one_actions_tmpl = flow_hw_create_ctrl_jump_actions_template + (dev, MLX5_HW_LOWEST_USABLE_GROUP); + if (!jump_one_actions_tmpl) { + DRV_LOG(ERR, "port %u failed to create jump action template" + " for control flows", dev->data->port_id); + goto error; + } MLX5_ASSERT(priv->hw_esw_zero_tbl == NULL); priv->hw_esw_zero_tbl = flow_hw_create_ctrl_jump_table(dev, port_items_tmpl, jump_one_actions_tmpl); @@ -5830,7 +6149,20 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) " for control flows", dev->data->port_id); goto error; } - if (xmeta == MLX5_XMETA_MODE_META32_HWS) { + /* Create templates and table for default Tx metadata copy flow rule. */ + if (!repr_matching && xmeta == MLX5_XMETA_MODE_META32_HWS) { + tx_meta_items_tmpl = flow_hw_create_tx_default_mreg_copy_pattern_template(dev); + if (!tx_meta_items_tmpl) { + DRV_LOG(ERR, "port %u failed to Tx metadata copy pattern" + " template for control flows", dev->data->port_id); + goto error; + } + tx_meta_actions_tmpl = flow_hw_create_tx_default_mreg_copy_actions_template(dev); + if (!tx_meta_actions_tmpl) { + DRV_LOG(ERR, "port %u failed to Tx metadata copy actions" + " template for control flows", dev->data->port_id); + goto error; + } MLX5_ASSERT(priv->hw_tx_meta_cpy_tbl == NULL); priv->hw_tx_meta_cpy_tbl = flow_hw_create_tx_default_mreg_copy_table(dev, tx_meta_items_tmpl, tx_meta_actions_tmpl); @@ -5854,7 +6186,7 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) flow_hw_table_destroy(dev, priv->hw_esw_sq_miss_root_tbl, NULL); priv->hw_esw_sq_miss_root_tbl = NULL; } - if (xmeta == MLX5_XMETA_MODE_META32_HWS && tx_meta_actions_tmpl) + if (tx_meta_actions_tmpl) flow_hw_actions_template_destroy(dev, tx_meta_actions_tmpl, NULL); if (jump_one_actions_tmpl) flow_hw_actions_template_destroy(dev, jump_one_actions_tmpl, NULL); @@ -5862,7 +6194,7 @@ flow_hw_create_ctrl_tables(struct rte_eth_dev *dev) flow_hw_actions_template_destroy(dev, port_actions_tmpl, NULL); if (regc_jump_actions_tmpl) flow_hw_actions_template_destroy(dev, regc_jump_actions_tmpl, NULL); - if (xmeta == MLX5_XMETA_MODE_META32_HWS && tx_meta_items_tmpl) + if (tx_meta_items_tmpl) flow_hw_pattern_template_destroy(dev, tx_meta_items_tmpl, NULL); if (port_items_tmpl) flow_hw_pattern_template_destroy(dev, port_items_tmpl, NULL); @@ -6207,6 +6539,13 @@ flow_hw_configure(struct rte_eth_dev *dev, if (!priv->hw_tag[i]) goto err; } + if (priv->sh->config.dv_esw_en && priv->sh->config.repr_matching) { + ret = flow_hw_setup_tx_repr_tagging(dev); + if (ret) { + rte_errno = -ret; + goto err; + } + } if (is_proxy) { ret = flow_hw_create_vport_actions(priv); if (ret) { @@ -6329,6 +6668,7 @@ flow_hw_resource_release(struct rte_eth_dev *dev) return; flow_hw_rxq_flag_set(dev, false); flow_hw_flush_all_ctrl_flows(dev); + flow_hw_cleanup_tx_repr_tagging(dev); while (!LIST_EMPTY(&priv->flow_hw_tbl_ongo)) { tbl = LIST_FIRST(&priv->flow_hw_tbl_ongo); flow_hw_table_destroy(dev, tbl, NULL); @@ -7688,45 +8028,30 @@ flow_hw_destroy_ctrl_flow(struct rte_eth_dev *dev, struct rte_flow *flow) } /** - * Destroys control flows created on behalf of @p owner_dev device. + * Destroys control flows created on behalf of @p owner device on @p dev device. * - * @param owner_dev + * @param dev + * Pointer to Ethernet device on which control flows were created. + * @param owner * Pointer to Ethernet device owning control flows. * * @return * 0 on success, otherwise negative error code is returned and * rte_errno is set. */ -int -mlx5_flow_hw_flush_ctrl_flows(struct rte_eth_dev *owner_dev) +static int +flow_hw_flush_ctrl_flows_owned_by(struct rte_eth_dev *dev, struct rte_eth_dev *owner) { - struct mlx5_priv *owner_priv = owner_dev->data->dev_private; - struct rte_eth_dev *proxy_dev; - struct mlx5_priv *proxy_priv; + struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_hw_ctrl_flow *cf; struct mlx5_hw_ctrl_flow *cf_next; - uint16_t owner_port_id = owner_dev->data->port_id; - uint16_t proxy_port_id = owner_dev->data->port_id; int ret; - if (owner_priv->sh->config.dv_esw_en) { - if (rte_flow_pick_transfer_proxy(owner_port_id, &proxy_port_id, NULL)) { - DRV_LOG(ERR, "Unable to find proxy port for port %u", - owner_port_id); - rte_errno = EINVAL; - return -rte_errno; - } - proxy_dev = &rte_eth_devices[proxy_port_id]; - proxy_priv = proxy_dev->data->dev_private; - } else { - proxy_dev = owner_dev; - proxy_priv = owner_priv; - } - cf = LIST_FIRST(&proxy_priv->hw_ctrl_flows); + cf = LIST_FIRST(&priv->hw_ctrl_flows); while (cf != NULL) { cf_next = LIST_NEXT(cf, next); - if (cf->owner_dev == owner_dev) { - ret = flow_hw_destroy_ctrl_flow(proxy_dev, cf->flow); + if (cf->owner_dev == owner) { + ret = flow_hw_destroy_ctrl_flow(dev, cf->flow); if (ret) { rte_errno = ret; return -ret; @@ -7739,6 +8064,50 @@ mlx5_flow_hw_flush_ctrl_flows(struct rte_eth_dev *owner_dev) return 0; } +/** + * Destroys control flows created for @p owner_dev device. + * + * @param owner_dev + * Pointer to Ethernet device owning control flows. + * + * @return + * 0 on success, otherwise negative error code is returned and + * rte_errno is set. + */ +int +mlx5_flow_hw_flush_ctrl_flows(struct rte_eth_dev *owner_dev) +{ + struct mlx5_priv *owner_priv = owner_dev->data->dev_private; + struct rte_eth_dev *proxy_dev; + uint16_t owner_port_id = owner_dev->data->port_id; + uint16_t proxy_port_id = owner_dev->data->port_id; + int ret; + + /* Flush all flows created by this port for itself. */ + ret = flow_hw_flush_ctrl_flows_owned_by(owner_dev, owner_dev); + if (ret) + return ret; + /* Flush all flows created for this port on proxy port. */ + if (owner_priv->sh->config.dv_esw_en) { + ret = rte_flow_pick_transfer_proxy(owner_port_id, &proxy_port_id, NULL); + if (ret == -ENODEV) { + DRV_LOG(DEBUG, "Unable to find transfer proxy port for port %u. It was " + "probably closed. Control flows were cleared.", + owner_port_id); + rte_errno = 0; + return 0; + } else if (ret) { + DRV_LOG(ERR, "Unable to find proxy port for port %u (ret = %d)", + owner_port_id, ret); + return ret; + } + proxy_dev = &rte_eth_devices[proxy_port_id]; + } else { + proxy_dev = owner_dev; + } + return flow_hw_flush_ctrl_flows_owned_by(proxy_dev, owner_dev); +} + /** * Destroys all control flows created on @p dev device. * @@ -7990,6 +8359,9 @@ mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev) .conf = &mreg_action, }, [1] = { + .type = RTE_FLOW_ACTION_TYPE_JUMP, + }, + [2] = { .type = RTE_FLOW_ACTION_TYPE_END, }, }; @@ -8002,6 +8374,60 @@ mlx5_flow_hw_create_tx_default_mreg_copy_flow(struct rte_eth_dev *dev) eth_all, 0, copy_reg_action, 0); } +int +mlx5_flow_hw_tx_repr_matching_flow(struct rte_eth_dev *dev, uint32_t sqn) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_rte_flow_item_sq sq_spec = { + .queue = sqn, + }; + struct rte_flow_item items[] = { + { + .type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_SQ, + .spec = &sq_spec, + }, + { + .type = RTE_FLOW_ITEM_TYPE_END, + }, + }; + /* + * Allocate actions array suitable for all cases - extended metadata enabled or not. + * With extended metadata there will be an additional MODIFY_FIELD action before JUMP. + */ + struct rte_flow_action actions[] = { + { .type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD }, + { .type = RTE_FLOW_ACTION_TYPE_JUMP }, + { .type = RTE_FLOW_ACTION_TYPE_END }, + { .type = RTE_FLOW_ACTION_TYPE_END }, + }; + + /* It is assumed that caller checked for representor matching. */ + MLX5_ASSERT(priv->sh->config.repr_matching); + if (!priv->dr_ctx) { + DRV_LOG(DEBUG, "Port %u must be configured for HWS, before creating " + "default egress flow rules. Omitting creation.", + dev->data->port_id); + return 0; + } + if (!priv->hw_tx_repr_tagging_tbl) { + DRV_LOG(ERR, "Port %u is configured for HWS, but table for default " + "egress flow rules does not exist.", + dev->data->port_id); + rte_errno = EINVAL; + return -rte_errno; + } + /* + * If extended metadata mode is enabled, then an additional MODIFY_FIELD action must be + * placed before terminating JUMP action. + */ + if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS) { + actions[1].type = RTE_FLOW_ACTION_TYPE_MODIFY_FIELD; + actions[2].type = RTE_FLOW_ACTION_TYPE_JUMP; + } + return flow_hw_create_ctrl_flow(dev, dev, priv->hw_tx_repr_tagging_tbl, + items, 0, actions, 0); +} + void mlx5_flow_meter_uninit(struct rte_eth_dev *dev) { diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index a973cbc5e3..dcb02f2a7f 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -1065,6 +1065,69 @@ mlx5_hairpin_get_peer_ports(struct rte_eth_dev *dev, uint16_t *peer_ports, return ret; } +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + +/** + * Check if starting representor port is allowed. + * + * If transfer proxy port is configured for HWS, then starting representor port + * is allowed if and only if transfer proxy port is started as well. + * + * @param dev + * Pointer to Ethernet device structure. + * + * @return + * If stopping representor port is allowed, then 0 is returned. + * Otherwise rte_errno is set, and negative errno value is returned. + */ +static int +mlx5_hw_representor_port_allowed_start(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_eth_dev *proxy_dev; + struct mlx5_priv *proxy_priv; + uint16_t proxy_port_id = UINT16_MAX; + int ret; + + MLX5_ASSERT(priv->sh->config.dv_flow_en == 2); + MLX5_ASSERT(priv->sh->config.dv_esw_en); + MLX5_ASSERT(priv->representor); + ret = rte_flow_pick_transfer_proxy(dev->data->port_id, &proxy_port_id, NULL); + if (ret) { + if (ret == -ENODEV) + DRV_LOG(ERR, "Starting representor port %u is not allowed. Transfer " + "proxy port is not available.", dev->data->port_id); + else + DRV_LOG(ERR, "Failed to pick transfer proxy for port %u (ret = %d)", + dev->data->port_id, ret); + return ret; + } + proxy_dev = &rte_eth_devices[proxy_port_id]; + proxy_priv = proxy_dev->data->dev_private; + if (proxy_priv->dr_ctx == NULL) { + DRV_LOG(DEBUG, "Starting representor port %u is allowed, but default traffic flows" + " will not be created. Transfer proxy port must be configured" + " for HWS and started.", + dev->data->port_id); + return 0; + } + if (!proxy_dev->data->dev_started) { + DRV_LOG(ERR, "Failed to start port %u: transfer proxy (port %u) must be started", + dev->data->port_id, proxy_port_id); + rte_errno = EAGAIN; + return -rte_errno; + } + if (priv->sh->config.repr_matching && !priv->dr_ctx) { + DRV_LOG(ERR, "Failed to start port %u: with representor matching enabled, port " + "must be configured for HWS", dev->data->port_id); + rte_errno = EINVAL; + return -rte_errno; + } + return 0; +} + +#endif + /** * DPDK callback to start the device. * @@ -1084,6 +1147,19 @@ mlx5_dev_start(struct rte_eth_dev *dev) int fine_inline; DRV_LOG(DEBUG, "port %u starting device", dev->data->port_id); +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + if (priv->sh->config.dv_flow_en == 2) { + /* If there is no E-Switch, then there are no start/stop order limitations. */ + if (!priv->sh->config.dv_esw_en) + goto continue_dev_start; + /* If master is being started, then it is always allowed. */ + if (priv->master) + goto continue_dev_start; + if (mlx5_hw_representor_port_allowed_start(dev)) + return -rte_errno; + } +continue_dev_start: +#endif fine_inline = rte_mbuf_dynflag_lookup (RTE_PMD_MLX5_FINE_GRANULARITY_INLINE, NULL); if (fine_inline >= 0) @@ -1248,6 +1324,53 @@ mlx5_dev_start(struct rte_eth_dev *dev) return -rte_errno; } +#ifdef HAVE_IBV_FLOW_DV_SUPPORT +/** + * Check if stopping transfer proxy port is allowed. + * + * If transfer proxy port is configured for HWS, then it is allowed to stop it + * if and only if all other representor ports are stopped. + * + * @param dev + * Pointer to Ethernet device structure. + * + * @return + * If stopping transfer proxy port is allowed, then 0 is returned. + * Otherwise rte_errno is set, and negative errno value is returned. + */ +static int +mlx5_hw_proxy_port_allowed_stop(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + bool representor_started = false; + uint16_t port_id; + + MLX5_ASSERT(priv->sh->config.dv_flow_en == 2); + MLX5_ASSERT(priv->sh->config.dv_esw_en); + MLX5_ASSERT(priv->master); + /* If transfer proxy port was not configured for HWS, then stopping it is allowed. */ + if (!priv->dr_ctx) + return 0; + MLX5_ETH_FOREACH_DEV(port_id, dev->device) { + const struct rte_eth_dev *port_dev = &rte_eth_devices[port_id]; + const struct mlx5_priv *port_priv = port_dev->data->dev_private; + + if (port_id != dev->data->port_id && + port_priv->domain_id == priv->domain_id && + port_dev->data->dev_started) + representor_started = true; + } + if (representor_started) { + DRV_LOG(INFO, "Failed to stop port %u: attached representor ports" + " must be stopped before stopping transfer proxy port", + dev->data->port_id); + rte_errno = EBUSY; + return -rte_errno; + } + return 0; +} +#endif + /** * DPDK callback to stop the device. * @@ -1261,6 +1384,21 @@ mlx5_dev_stop(struct rte_eth_dev *dev) { struct mlx5_priv *priv = dev->data->dev_private; +#ifdef HAVE_IBV_FLOW_DV_SUPPORT + if (priv->sh->config.dv_flow_en == 2) { + /* If there is no E-Switch, then there are no start/stop order limitations. */ + if (!priv->sh->config.dv_esw_en) + goto continue_dev_stop; + /* If representor is being stopped, then it is always allowed. */ + if (priv->representor) + goto continue_dev_stop; + if (mlx5_hw_proxy_port_allowed_stop(dev)) { + dev->data->dev_started = 1; + return -rte_errno; + } + } +continue_dev_stop: +#endif dev->data->dev_started = 0; /* Prevent crashes when queues are still in use. */ dev->rx_pkt_burst = rte_eth_pkt_burst_dummy; @@ -1296,13 +1434,21 @@ static int mlx5_traffic_enable_hws(struct rte_eth_dev *dev) { struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_sh_config *config = &priv->sh->config; unsigned int i; int ret; - if (priv->sh->config.dv_esw_en && priv->master) { - if (priv->sh->config.dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS) - if (mlx5_flow_hw_create_tx_default_mreg_copy_flow(dev)) - goto error; + /* + * With extended metadata enabled, the Tx metadata copy is handled by default + * Tx tagging flow rules, so default Tx flow rule is not needed. It is only + * required when representor matching is disabled. + */ + if (config->dv_esw_en && + !config->repr_matching && + config->dv_xmeta_en == MLX5_XMETA_MODE_META32_HWS && + priv->master) { + if (mlx5_flow_hw_create_tx_default_mreg_copy_flow(dev)) + goto error; } for (i = 0; i < priv->txqs_n; ++i) { struct mlx5_txq_ctrl *txq = mlx5_txq_get(dev, i); @@ -1311,17 +1457,22 @@ mlx5_traffic_enable_hws(struct rte_eth_dev *dev) if (!txq) continue; queue = mlx5_txq_get_sqn(txq); - if ((priv->representor || priv->master) && - priv->sh->config.dv_esw_en) { + if ((priv->representor || priv->master) && config->dv_esw_en) { if (mlx5_flow_hw_esw_create_sq_miss_flow(dev, queue)) { mlx5_txq_release(dev, i); goto error; } } + if (config->dv_esw_en && config->repr_matching) { + if (mlx5_flow_hw_tx_repr_matching_flow(dev, queue)) { + mlx5_txq_release(dev, i); + goto error; + } + } mlx5_txq_release(dev, i); } - if (priv->sh->config.fdb_def_rule) { - if ((priv->master || priv->representor) && priv->sh->config.dv_esw_en) { + if (config->fdb_def_rule) { + if ((priv->master || priv->representor) && config->dv_esw_en) { if (!mlx5_flow_hw_esw_create_default_jump_flow(dev)) priv->fdb_def_rule = 1; else