From patchwork Thu Jan 25 13:30:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Baum X-Patchwork-Id: 136159 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 3051F439C1; Thu, 25 Jan 2024 14:33:18 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id F0AA742E78; Thu, 25 Jan 2024 14:31:41 +0100 (CET) Received: from NAM02-DM3-obe.outbound.protection.outlook.com (mail-dm3nam02on2041.outbound.protection.outlook.com [40.107.95.41]) by mails.dpdk.org (Postfix) with ESMTP id 091F642E6A for ; Thu, 25 Jan 2024 14:31:40 +0100 (CET) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=B8TZ4BQivZxXudN3XIs4cSfTG5ors/EsIXUQTgkezRfw15dYBSa6EHUtqPG9XVAmvYVBfIYIJuyUS25UPwnMgzpn80NAoE+qWgWodqcGCayDFw3RR6tw9uAZ7pAhzb5Z1aakuKVy2omT/QPsPlz/lNaTzsp90CX7B+0/8dDMfQxPbNs0hau7pQEsd5QIuSE8cAZusojulePA+RkNfhP6iY1XER0MrL0A9uaZMsrCwVzNZUrtyzbwDkfAAg4SB166NV8RXMTiHyWFs1oqdslKjdOE+CeLabrDexIOBZ6mvzuvNa06bm9ADf45E4Ou+ahT4AyvT31ShYbBV5Kgzm13nA== 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=g6tAIlXyFC7G7uBDx/1OCtvqlJUJo+k66H+eKz6r0uA=; b=E6RVRPr2yeiyJifDogxUQt8/Sy22rqMlR7uBmksNMoLluP+1TbALNJUlIFotwYQC7XaMgm0qwBzaN8KrEgctEyCiR8DJNM7AT0mLQ/LU6vY1Nq/SBVnn58WC5urdzjv8t8uBZjRixW6iEQOtC2tsaolOvcmyYwjHHZ+IlsBaUuSGYERs09arpKZ526FxQjSGb4P22sn+r3GVFn83DMIWRnvjmiQwLktwnMusgJDBZmJnJ0Tk6bfGvV4SJEMUeG1iGr36+gNw/4bCPveHbfVLD71H3fS0oATByyHeYgrrAjy72b1SGmTvegwDUCMQ0QIXIyjGNa4QBqDyBZq+jSSitw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.118.232) 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 (0) 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=g6tAIlXyFC7G7uBDx/1OCtvqlJUJo+k66H+eKz6r0uA=; b=dewPcaMi44CZcoGYzzYQLv/RCKVtNRi4vElBgho17FnY/eFAIuRjCMN2paP6GRWHDt16G+WdxUV9wlbao7fBDU2zZS6IrL8iAOcu8/EayZXGzTuWBcJCF400oaAkJe2CCZ9Z7SbMa1H3lD6cjsdYG1eiuh1Kn6BBjZzyNXsy67fIVzCDAZBy4PBDjXZw+hfU7AjltS1Sb2VufUXNxCLySgQXKl9sZF15sc8sDi6srACPOY4M3rVunCzgnXy32QEj5361D0/KuZi0gel033MF3B5Hkr+yPJriyyikcT7oHMpySNl1icvFMYtXGOxYjJDCJxeOtd44kHHHQlafo8t9pA== Received: from CYZPR02CA0012.namprd02.prod.outlook.com (2603:10b6:930:a1::7) by PH7PR12MB6936.namprd12.prod.outlook.com (2603:10b6:510:1ba::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7228.22; Thu, 25 Jan 2024 13:31:30 +0000 Received: from CY4PEPF0000EE3D.namprd03.prod.outlook.com (2603:10b6:930:a1:cafe::54) by CYZPR02CA0012.outlook.office365.com (2603:10b6:930:a1::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7228.27 via Frontend Transport; Thu, 25 Jan 2024 13:31:30 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.118.232) 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.118.232 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.118.232; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.118.232) by CY4PEPF0000EE3D.mail.protection.outlook.com (10.167.242.17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7181.13 via Frontend Transport; Thu, 25 Jan 2024 13:31:30 +0000 Received: from drhqmail201.nvidia.com (10.126.190.180) by mail.nvidia.com (10.127.129.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.41; Thu, 25 Jan 2024 05:31:22 -0800 Received: from drhqmail202.nvidia.com (10.126.190.181) by drhqmail201.nvidia.com (10.126.190.180) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.41; Thu, 25 Jan 2024 05:31:22 -0800 Received: from nvidia.com (10.127.8.13) by mail.nvidia.com (10.126.190.181) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.41 via Frontend Transport; Thu, 25 Jan 2024 05:31:20 -0800 From: Michael Baum To: CC: Matan Azrad , Raslan Darawsheh , Dariusz Sosnowski , Viacheslav Ovsiienko , Ori Kam , Suanming Mou Subject: [PATCH v2 13/23] net/mlx5: add GENEVE TLV options parser API Date: Thu, 25 Jan 2024 15:30:33 +0200 Message-ID: <20240125133043.575860-14-michaelba@nvidia.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20240125133043.575860-1-michaelba@nvidia.com> References: <20231203112543.844014-1-michaelba@nvidia.com> <20240125133043.575860-1-michaelba@nvidia.com> MIME-Version: 1.0 X-NV-OnPremToCloud: ExternallySecured X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: CY4PEPF0000EE3D:EE_|PH7PR12MB6936:EE_ X-MS-Office365-Filtering-Correlation-Id: 08844e24-c636-4797-1883-08dc1da9f0b6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: bq29RtoN90SrbGxUxyNitZdMpueBXQLTwfUpHKF/bfAeKqzTf93MLQqppYSQGHEzGwTao87+362Ihqq12Gvb2AMOPNwY5BPKPVGNMhB8utTIK/8ZxM9WuKR2e15ADTHyuZ8kF4uqVELtRXkVg1K75XwloNXdYdIbGmRargj8WJyV3aXrHIkUfAN/B5iv1tAaJPCX573NP72kvRl0srZsgPmhClMGDYQ6D3tslD29nBf5bMzpViUf/cGp45MEutPLiW+/w8CZUx9Z/EACZD7a+BDWvGSlwQppORhUUpEaAXtW1ZsURW6EfDwzuLckdZb5S1UqaVoASgh/wW2prX6wugUt38r6Tb9bBDmFZluSb0UY0vUQZlsBEfRnRFGcl6lH8K4tHNLmKTvBX2BviiBGjgYeRsyYToZAkyQhm6VLrSlGWdUXuuuK4clgEVvLO24dPzbNKqOkHd0EjuDeGU/9a2A67sa+6wHdbE9v6fULyZUeDXNjVM2Iq60yLBkua7gMSEMnkLt2a2UjjofX4w6eRboAVpg/e4quOZEUbygJiNfrS+WDa0tfXOzy4717xgBTWq7FntMT3cWpwUM/ym+IklmL5qAgiU2f9yNYQwUleKMGuyidK+j8/CoHmehSjQLF+OuiyKTGlm448Lm9l6W9E2PBVbxLU1RwDHg48xYz/ceSetOk4TqKuGNGytwYvM1i3Tgi+MruYZjX+ZR0+dzRQolYBrPeKVnkW+gMmmKxh9GkhTqiFl1hQ+6TchwGvXWS6EaecDAj9LL+sIe82VqkvRJfXFmJp1fNFbkEG+Plog7rI1Vedq5Tk2tA6gJNkU6l25Os5FHD2uJhBKfoBsJcQv7ODFKYybXC25D7PSu3P0Q= X-Forefront-Antispam-Report: CIP:216.228.118.232; CTRY:US; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:mail.nvidia.com; PTR:dc7edge1.nvidia.com; CAT:NONE; SFS:(13230031)(4636009)(39860400002)(136003)(346002)(396003)(376002)(230273577357003)(230173577357003)(230922051799003)(451199024)(1800799012)(186009)(82310400011)(64100799003)(46966006)(36840700001)(40470700004)(7636003)(70206006)(6916009)(54906003)(70586007)(86362001)(336012)(316002)(107886003)(426003)(1076003)(26005)(6286002)(83380400001)(7696005)(6666004)(2616005)(36860700001)(40460700003)(82740400003)(40480700001)(41300700001)(36756003)(356005)(30864003)(2906002)(55016003)(5660300002)(478600001)(47076005)(8676002)(4326008)(8936002)(21314003); DIR:OUT; SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 25 Jan 2024 13:31:30.3818 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 08844e24-c636-4797-1883-08dc1da9f0b6 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a; Ip=[216.228.118.232]; Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: CY4PEPF0000EE3D.namprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH7PR12MB6936 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 Add a new private API to create/destroy parser for GENEVE TLV options. Signed-off-by: Michael Baum Signed-off-by: Viacheslav Ovsiienko Acked-by: Suanming Mou --- doc/guides/nics/mlx5.rst | 122 ++++++ doc/guides/platform/mlx5.rst | 6 +- drivers/net/mlx5/meson.build | 1 + drivers/net/mlx5/mlx5.c | 30 +- drivers/net/mlx5/mlx5.h | 8 + drivers/net/mlx5/mlx5_flow.c | 30 ++ drivers/net/mlx5/mlx5_flow.h | 18 + drivers/net/mlx5/mlx5_flow_geneve.c | 627 ++++++++++++++++++++++++++++ drivers/net/mlx5/rte_pmd_mlx5.h | 102 +++++ drivers/net/mlx5/version.map | 3 + 10 files changed, 945 insertions(+), 2 deletions(-) create mode 100644 drivers/net/mlx5/mlx5_flow_geneve.c diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index f8930cb902..e82f7034aa 100644 --- a/doc/guides/nics/mlx5.rst +++ b/doc/guides/nics/mlx5.rst @@ -2314,6 +2314,128 @@ and disables ``avail_thresh_triggered``. testpmd> mlx5 set port 1 host_shaper avail_thresh_triggered 0 rate 50 +.. _geneve_parser_api: + +GENEVE TLV options parser +------------------------- + +NVIDIA ConnectX and BlueField devices support configure flex parser for +`GENEVE TLV options `_. + +Each physical device has 7 DWs for GENEVE TLV options. +Partial option configuration is supported, mask for data is provided in parser +creation indicating which DWs configuration is requested. Only masked data DWs +can be matched later as item field using flow API. + +Matching of ``type`` field is supported for each configured option. +However, for matching ``class` field, the option should be configured with +``match_on_class_mode=2``. Matching on ``length`` field is not supported. +When ``match_on_class_mode=2`` is requested, one extra DW is consumed for it. + +Parser API +~~~~~~~~~~ + +An API to create/destroy GENEVE TLV parser is added. +Although the parser is created per physical device, this API is port oriented. +Each port should call this API before using GENEVE OPT item, +but its configuration must use the same options list with same internal order +configured by first port. + +Calling this API for different ports under same physical device doesn't consume +more DWs, the first one creates the parser and the rest use same configuration. + +``struct rte_pmd_mlx5_geneve_tlv`` is used for single option configuration: + +.. _table_rte_pmd_mlx5_geneve_tlv: + +.. table:: GENEVE TLV + + +-------------------------+-------------------------------------------------+ + | Field | Value | + +=========================+=================================================+ + | ``option_class`` | class | + +-------------------------+-------------------------------------------------+ + | ``option_type`` | type | + +-------------------------+-------------------------------------------------+ + | ``option_len`` | data length in DW granularity | + +-------------------------+-------------------------------------------------+ + | ``match_on_class_mode`` | indicator about class field role in this option | + +-------------------------+-------------------------------------------------+ + | ``offset`` | offset of the first sample in DW granularity | + +-------------------------+-------------------------------------------------+ + | ``sample_len`` | number of DW to sample | + +-------------------------+-------------------------------------------------+ + | ``match_data_mask`` | array of DWs which each bit marks if this bit | + | | should be sampled | + +-------------------------+-------------------------------------------------+ + +Creation +^^^^^^^^ + +Creates GENEVE TLV parser for the selected port. +This function must be called before first use of GENEVE option. + +.. code-block:: c + + void * + rte_pmd_mlx5_create_geneve_tlv_parser(uint16_t port_id, + const struct rte_pmd_mlx5_geneve_tlv tlv_list[], + uint8_t nb_options); + +The parser creation is done once for all GENEVE TLV options. +For adding a new option, the exist parser should be destroyed first. + +Arguments: + +- ``port_id``: port identifier of Ethernet device. +- ``tlv_list``: list of GENEVE TLV options to create parser for them. +- ``nb_options``: number of options in TLV list. + +Return values: + +- A valid handle in case of success, NULL otherwise (``rte_errno`` is also set), + the following errors are defined. +- ``ENODEV``: there is no Ethernet device for this port id. +- ``EINVAL``: invalid GENEVE TLV option requested. +- ``ENOTSUP``: the port doesn't support GENEVE TLV parsing. +- ``EEXIST``: this port already has GENEVE TLV parser or another port under same + physical device has already prepared a different parser. +- ``ENOMEM``: not enough memory to execute the function, or resource limitation + on the device. + + +Destruction +^^^^^^^^^^^ + +Destroy GENEVE TLV parser created by ``rte_pmd_mlx5_create_geneve_tlv_parser()``. +This function must be called after last use of GENEVE option and before port +closing. + +.. code-block:: c + + int + rte_pmd_mlx5_destroy_geneve_tlv_parser(void *handle); + +Failure to destroy a parser handle may occur when one of the options is used by +valid template table. + +Arguments: + +- ``handle``: handle for the GENEVE TLV parser object to be destroyed. + +Return values: + +- 0 on success, a negative errno value otherwise and ``rte_errno`` is set. + + +Limitations +~~~~~~~~~~~ + +* Supported only in HW steering (``dv_flow_en`` = 2). +* Supported only when ``FLEX_PARSER_PROFILE_ENABLE`` = 8. +* Supported for FW version **xx.37.0142** and above. + + Testpmd driver specific commands -------------------------------- diff --git a/doc/guides/platform/mlx5.rst b/doc/guides/platform/mlx5.rst index 400000e284..d16508d0da 100644 --- a/doc/guides/platform/mlx5.rst +++ b/doc/guides/platform/mlx5.rst @@ -536,10 +536,14 @@ Below are some firmware configurations listed. or FLEX_PARSER_PROFILE_ENABLE=1 -- enable Geneve TLV option flow matching:: +- enable Geneve TLV option flow matching in SW steering:: FLEX_PARSER_PROFILE_ENABLE=0 +- enable Geneve TLV option flow matching in HW steering:: + + FLEX_PARSER_PROFILE_ENABLE=8 + - enable GTP flow matching:: FLEX_PARSER_PROFILE_ENABLE=3 diff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build index 69771c63ab..d705fe21bb 100644 --- a/drivers/net/mlx5/meson.build +++ b/drivers/net/mlx5/meson.build @@ -46,6 +46,7 @@ sources = files( if is_linux sources += files( + 'mlx5_flow_geneve.c', 'mlx5_flow_hw.c', 'mlx5_hws_cnt.c', 'mlx5_flow_quota.c', diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index f9fc652136..5f8af31aea 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -1722,6 +1722,19 @@ mlx5_get_physical_device(struct mlx5_common_device *cdev) return phdev; } +struct mlx5_physical_device * +mlx5_get_locked_physical_device(struct mlx5_priv *priv) +{ + pthread_mutex_lock(&mlx5_dev_ctx_list_mutex); + return priv->sh->phdev; +} + +void +mlx5_unlock_physical_device(void) +{ + pthread_mutex_unlock(&mlx5_dev_ctx_list_mutex); +} + static void mlx5_physical_device_destroy(struct mlx5_physical_device *phdev) { @@ -2278,6 +2291,7 @@ int mlx5_dev_close(struct rte_eth_dev *dev) { struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_dev_ctx_shared *sh = priv->sh; unsigned int i; int ret; @@ -2290,7 +2304,7 @@ mlx5_dev_close(struct rte_eth_dev *dev) rte_eth_dev_release_port(dev); return 0; } - if (!priv->sh) + if (!sh) return 0; if (priv->shared_refcnt) { DRV_LOG(ERR, "port %u is shared host in use (%u)", @@ -2298,6 +2312,15 @@ mlx5_dev_close(struct rte_eth_dev *dev) rte_errno = EBUSY; return -EBUSY; } +#ifdef HAVE_MLX5_HWS_SUPPORT + /* Check if shared GENEVE options created on context being closed. */ + ret = mlx5_geneve_tlv_options_check_busy(priv); + if (ret) { + DRV_LOG(ERR, "port %u maintains shared GENEVE TLV options", + dev->data->port_id); + return ret; + } +#endif DRV_LOG(DEBUG, "port %u closing device \"%s\"", dev->data->port_id, ((priv->sh->cdev->ctx != NULL) ? @@ -2330,6 +2353,11 @@ 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->tlv_options != NULL) { + /* Free the GENEVE TLV parser resource. */ + claim_zero(mlx5_geneve_tlv_options_destroy(priv->tlv_options, sh->phdev)); + priv->tlv_options = NULL; + } #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 8bf7f86416..683029023e 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -1419,6 +1419,8 @@ struct mlx5_dev_registers { #define HAVE_MLX5_DR_CREATE_ACTION_ASO_EXT #endif +struct mlx5_geneve_tlv_options; + /** * Physical device structure. * This device is created once per NIC to manage recourses shared by all ports @@ -1428,6 +1430,7 @@ struct mlx5_physical_device { LIST_ENTRY(mlx5_physical_device) next; struct mlx5_dev_ctx_shared *sh; /* Created on sherd context. */ uint64_t guid; /* System image guid, the uniq ID of physical device. */ + struct mlx5_geneve_tlv_options *tlv_options; uint32_t refcnt; }; @@ -1950,6 +1953,8 @@ struct mlx5_priv { /* Action template list. */ LIST_HEAD(flow_hw_at, rte_flow_actions_template) flow_hw_at; struct mlx5dr_context *dr_ctx; /**< HW steering DR context. */ + /* Pointer to the GENEVE TLV options. */ + struct mlx5_geneve_tlv_options *tlv_options; /* HW steering queue polling mechanism job descriptor LIFO. */ uint32_t hws_strict_queue:1; /**< Whether all operations strictly happen on the same HWS queue. */ @@ -2088,6 +2093,9 @@ void mlx5_flow_counter_mode_config(struct rte_eth_dev *dev); int mlx5_flow_aso_age_mng_init(struct mlx5_dev_ctx_shared *sh); int mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh); int mlx5_flow_aso_ct_mng_init(struct mlx5_dev_ctx_shared *sh); +struct mlx5_physical_device * +mlx5_get_locked_physical_device(struct mlx5_priv *priv); +void mlx5_unlock_physical_device(void); /* mlx5_ethdev.c */ diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index acaf34ce52..5159e8e773 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -12524,3 +12524,33 @@ mlx5_flow_discover_ipv6_tc_support(struct rte_eth_dev *dev) flow_list_destroy(dev, MLX5_FLOW_TYPE_GEN, flow_idx); return 0; } + +void * +rte_pmd_mlx5_create_geneve_tlv_parser(uint16_t port_id, + const struct rte_pmd_mlx5_geneve_tlv tlv_list[], + uint8_t nb_options) +{ +#ifdef HAVE_MLX5_HWS_SUPPORT + return mlx5_geneve_tlv_parser_create(port_id, tlv_list, nb_options); +#else + (void)port_id; + (void)tlv_list; + (void)nb_options; + DRV_LOG(ERR, "%s is not supported.", __func__); + rte_errno = ENOTSUP; + return NULL; +#endif +} + +int +rte_pmd_mlx5_destroy_geneve_tlv_parser(void *handle) +{ +#ifdef HAVE_MLX5_HWS_SUPPORT + return mlx5_geneve_tlv_parser_destroy(handle); +#else + (void)handle; + DRV_LOG(ERR, "%s is not supported.", __func__); + rte_errno = ENOTSUP; + return -rte_errno; +#endif +} diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h index 6f720de14d..4bf9ed7e4d 100644 --- a/drivers/net/mlx5/mlx5_flow.h +++ b/drivers/net/mlx5/mlx5_flow.h @@ -1336,6 +1336,8 @@ struct mlx5_action_construct_data { }; }; +#define MAX_GENEVE_OPTIONS_RESOURCES 7 + /* Flow item template struct. */ struct rte_flow_pattern_template { LIST_ENTRY(rte_flow_pattern_template) next; @@ -1650,6 +1652,11 @@ struct mlx5_flow_split_info { uint64_t prefix_layers; /**< Prefix subflow layers. */ }; +struct mlx5_hl_data { + uint8_t dw_offset; + uint32_t dw_mask; +}; + struct flow_hw_port_info { uint32_t regc_mask; uint32_t regc_value; @@ -1765,6 +1772,12 @@ flow_hw_get_reg_id_from_ctx(void *dr_ctx, return REG_NON; } +void * +mlx5_geneve_tlv_parser_create(uint16_t port_id, + const struct rte_pmd_mlx5_geneve_tlv tlv_list[], + uint8_t nb_options); +int mlx5_geneve_tlv_parser_destroy(void *handle); + void flow_hw_set_port_info(struct rte_eth_dev *dev); void flow_hw_clear_port_info(struct rte_eth_dev *dev); int flow_hw_create_vport_action(struct rte_eth_dev *dev); @@ -2810,6 +2823,11 @@ mlx5_get_tof(const struct rte_flow_item *items, enum mlx5_tof_rule_type *rule_type); void flow_hw_resource_release(struct rte_eth_dev *dev); +int +mlx5_geneve_tlv_options_destroy(struct mlx5_geneve_tlv_options *options, + struct mlx5_physical_device *phdev); +int +mlx5_geneve_tlv_options_check_busy(struct mlx5_priv *priv); void flow_hw_rxq_flag_set(struct rte_eth_dev *dev, bool enable); int flow_dv_action_validate(struct rte_eth_dev *dev, diff --git a/drivers/net/mlx5/mlx5_flow_geneve.c b/drivers/net/mlx5/mlx5_flow_geneve.c new file mode 100644 index 0000000000..f23fb31aa0 --- /dev/null +++ b/drivers/net/mlx5/mlx5_flow_geneve.c @@ -0,0 +1,627 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2022 NVIDIA Corporation & Affiliates + */ + +#include + +#include +#include + +#include "generic/rte_byteorder.h" +#include "mlx5.h" +#include "mlx5_flow.h" +#include "rte_pmd_mlx5.h" + +#if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) + +#define MAX_GENEVE_OPTION_DATA_SIZE 32 +#define MAX_GENEVE_OPTION_TOTAL_DATA_SIZE \ + (MAX_GENEVE_OPTION_DATA_SIZE * MAX_GENEVE_OPTIONS_RESOURCES) + +/** + * Single DW inside GENEVE TLV option. + */ +struct mlx5_geneve_tlv_resource { + struct mlx5_devx_obj *obj; /* FW object returned in parser creation. */ + uint32_t modify_field; /* Modify field ID for this DW. */ + uint8_t offset; /* Offset used in obj creation, from option start. */ +}; + +/** + * Single GENEVE TLV option context. + * May include some FW objects for different DWs in same option. + */ +struct mlx5_geneve_tlv_option { + uint8_t type; + uint16_t class; + uint8_t class_mode; + struct mlx5_hl_data match_data[MAX_GENEVE_OPTION_DATA_SIZE]; + uint32_t match_data_size; + struct mlx5_hl_data hl_ok_bit; + struct mlx5_geneve_tlv_resource resources[MAX_GENEVE_OPTIONS_RESOURCES]; + RTE_ATOMIC(uint32_t) refcnt; +}; + +/** + * List of GENEVE TLV options. + */ +struct mlx5_geneve_tlv_options { + /* List of configured GENEVE TLV options. */ + struct mlx5_geneve_tlv_option options[MAX_GENEVE_OPTIONS_RESOURCES]; + /* + * Copy of list given in parser creation, use to compare with new + * configuration. + */ + struct rte_pmd_mlx5_geneve_tlv spec[MAX_GENEVE_OPTIONS_RESOURCES]; + rte_be32_t buffer[MAX_GENEVE_OPTION_TOTAL_DATA_SIZE]; + uint8_t nb_options; /* Number entries in above lists. */ + RTE_ATOMIC(uint32_t) refcnt; +}; + +/** + * Create single GENEVE TLV option sample. + * + * @param ctx + * Context returned from mlx5 open_device() glue function. + * @param attr + * Pointer to GENEVE TLV option attributes structure. + * @param query_attr + * Pointer to match sample info attributes structure. + * @param match_data + * Pointer to header layout structure to update. + * @param resource + * Pointer to single sample context to fill. + * + * @return + * 0 on success, a negative errno otherwise and rte_errno is set. + */ +static int +mlx5_geneve_tlv_option_create_sample(void *ctx, + struct mlx5_devx_geneve_tlv_option_attr *attr, + struct mlx5_devx_match_sample_info_query_attr *query_attr, + struct mlx5_hl_data *match_data, + struct mlx5_geneve_tlv_resource *resource) +{ + struct mlx5_devx_obj *obj; + int ret; + + obj = mlx5_devx_cmd_create_geneve_tlv_option(ctx, attr); + if (obj == NULL) + return -rte_errno; + ret = mlx5_devx_cmd_query_geneve_tlv_option(ctx, obj, query_attr); + if (ret) { + claim_zero(mlx5_devx_cmd_destroy(obj)); + return ret; + } + resource->obj = obj; + resource->offset = attr->sample_offset; + resource->modify_field = query_attr->modify_field_id; + match_data->dw_offset = query_attr->sample_dw_data; + match_data->dw_mask = 0xffffffff; + return 0; +} + +/** + * Destroy single GENEVE TLV option sample. + * + * @param resource + * Pointer to single sample context to clean. + */ +static void +mlx5_geneve_tlv_option_destroy_sample(struct mlx5_geneve_tlv_resource *resource) +{ + claim_zero(mlx5_devx_cmd_destroy(resource->obj)); + resource->obj = NULL; +} + +/** + * Create single GENEVE TLV option. + * + * @param ctx + * Context returned from mlx5 open_device() glue function. + * @param spec + * Pointer to user configuration. + * @param option + * Pointer to single GENEVE TLV option to fill. + * + * @return + * 0 on success, a negative errno otherwise and rte_errno is set. + */ +static int +mlx5_geneve_tlv_option_create(void *ctx, const struct rte_pmd_mlx5_geneve_tlv *spec, + struct mlx5_geneve_tlv_option *option) +{ + struct mlx5_devx_geneve_tlv_option_attr attr = { + .option_class = spec->option_class, + .option_type = spec->option_type, + .option_data_len = spec->option_len, + .option_class_ignore = spec->match_on_class_mode == 1 ? 0 : 1, + .offset_valid = 1, + }; + struct mlx5_devx_match_sample_info_query_attr query_attr = {0}; + struct mlx5_geneve_tlv_resource *resource; + uint8_t i, resource_id = 0; + int ret; + + if (spec->match_on_class_mode == 2) { + /* Header is matchable, create sample for DW0. */ + attr.sample_offset = 0; + resource = &option->resources[resource_id]; + ret = mlx5_geneve_tlv_option_create_sample(ctx, &attr, + &query_attr, + &option->match_data[0], + resource); + if (ret) + return ret; + resource_id++; + } + /* + * Create FW object for each DW request by user. + * Starting from 1 since FW offset starts from header. + */ + for (i = 1; i <= spec->sample_len; ++i) { + if (spec->match_data_mask[i - 1] == 0) + continue; + /* offset of data + offset inside data = specific DW offset. */ + attr.sample_offset = spec->offset + i; + resource = &option->resources[resource_id]; + ret = mlx5_geneve_tlv_option_create_sample(ctx, &attr, + &query_attr, + &option->match_data[i], + resource); + if (ret) + goto error; + resource_id++; + } + /* + * Update the OK bit information according to last query. + * It should be same for each query under same option. + */ + option->hl_ok_bit.dw_offset = query_attr.sample_dw_ok_bit; + option->hl_ok_bit.dw_mask = 1 << query_attr.sample_dw_ok_bit_offset; + option->match_data_size = spec->sample_len + 1; + option->type = spec->option_type; + option->class = spec->option_class; + option->class_mode = spec->match_on_class_mode; + rte_atomic_store_explicit(&option->refcnt, 0, rte_memory_order_relaxed); + return 0; +error: + for (i = 0; i < resource_id; ++i) { + resource = &option->resources[i]; + mlx5_geneve_tlv_option_destroy_sample(resource); + } + return ret; +} + +/** + * Destroy single GENEVE TLV option. + * + * @param option + * Pointer to single GENEVE TLV option to destroy. + * + * @return + * 0 on success, a negative errno otherwise and rte_errno is set. + */ +static int +mlx5_geneve_tlv_option_destroy(struct mlx5_geneve_tlv_option *option) +{ + uint8_t i; + + if (rte_atomic_load_explicit(&option->refcnt, rte_memory_order_relaxed)) { + DRV_LOG(ERR, + "Option type %u class %u is still in used by %u tables.", + option->type, option->class, option->refcnt); + rte_errno = EBUSY; + return -rte_errno; + } + for (i = 0; option->resources[i].obj != NULL; ++i) + mlx5_geneve_tlv_option_destroy_sample(&option->resources[i]); + return 0; +} + +/** + * Copy the GENEVE TLV option user configuration for future comparing. + * + * @param dst + * Pointer to internal user configuration copy. + * @param src + * Pointer to user configuration. + * @param match_data_mask + * Pointer to allocated data array. + */ +static void +mlx5_geneve_tlv_option_copy(struct rte_pmd_mlx5_geneve_tlv *dst, + const struct rte_pmd_mlx5_geneve_tlv *src, + rte_be32_t *match_data_mask) +{ + uint8_t i; + + dst->option_type = src->option_type; + dst->option_class = src->option_class; + dst->option_len = src->option_len; + dst->offset = src->offset; + dst->match_on_class_mode = src->match_on_class_mode; + dst->sample_len = src->sample_len; + for (i = 0; i < dst->sample_len; ++i) + match_data_mask[i] = src->match_data_mask[i]; + dst->match_data_mask = match_data_mask; +} + +/** + * Create list of GENEVE TLV options according to user configuration list. + * + * @param sh + * Shared context the options are being created on. + * @param tlv_list + * A list of GENEVE TLV options to create parser for them. + * @param nb_options + * The number of options in TLV list. + * + * @return + * A pointer to GENEVE TLV options parser structure on success, + * NULL otherwise and rte_errno is set. + */ +static struct mlx5_geneve_tlv_options * +mlx5_geneve_tlv_options_create(struct mlx5_dev_ctx_shared *sh, + const struct rte_pmd_mlx5_geneve_tlv tlv_list[], + uint8_t nb_options) +{ + struct mlx5_geneve_tlv_options *options; + const struct rte_pmd_mlx5_geneve_tlv *spec; + rte_be32_t *data_mask; + uint8_t i, j; + int ret; + + options = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE, + sizeof(struct mlx5_geneve_tlv_options), + RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY); + if (options == NULL) { + DRV_LOG(ERR, + "Failed to allocate memory for GENEVE TLV options."); + rte_errno = ENOMEM; + return NULL; + } + for (i = 0; i < nb_options; ++i) { + spec = &tlv_list[i]; + ret = mlx5_geneve_tlv_option_create(sh->cdev->ctx, spec, + &options->options[i]); + if (ret < 0) + goto error; + /* Copy the user list for comparing future configuration. */ + data_mask = options->buffer + i * MAX_GENEVE_OPTION_DATA_SIZE; + mlx5_geneve_tlv_option_copy(&options->spec[i], spec, data_mask); + } + MLX5_ASSERT(sh->phdev->sh == NULL); + sh->phdev->sh = sh; + options->nb_options = nb_options; + options->refcnt = 1; + return options; +error: + for (j = 0; j < i; ++j) + mlx5_geneve_tlv_option_destroy(&options->options[j]); + mlx5_free(options); + return NULL; +} + +/** + * Destroy GENEVE TLV options structure. + * + * @param options + * Pointer to GENEVE TLV options structure to destroy. + * @param phdev + * Pointer physical device options were created on. + * + * @return + * 0 on success, a negative errno otherwise and rte_errno is set. + */ +int +mlx5_geneve_tlv_options_destroy(struct mlx5_geneve_tlv_options *options, + struct mlx5_physical_device *phdev) +{ + uint8_t i; + int ret; + + if (--options->refcnt) + return 0; + for (i = 0; i < options->nb_options; ++i) { + ret = mlx5_geneve_tlv_option_destroy(&options->options[i]); + if (ret < 0) { + DRV_LOG(ERR, + "Failed to destroy option %u, %u/%u is already destroyed.", + i, i, options->nb_options); + return ret; + } + } + mlx5_free(options); + phdev->tlv_options = NULL; + phdev->sh = NULL; + return 0; +} + +/** + * Check if GENEVE TLV options are hosted on the current port + * and the port can be closed + * + * @param priv + * Device private data. + * + * @return + * 0 on success, a negative EBUSY and rte_errno is set. + */ +int +mlx5_geneve_tlv_options_check_busy(struct mlx5_priv *priv) +{ + struct mlx5_physical_device *phdev = mlx5_get_locked_physical_device(priv); + struct mlx5_dev_ctx_shared *sh = priv->sh; + + if (!phdev || phdev->sh != sh) { + mlx5_unlock_physical_device(); + return 0; + } + if (!sh->phdev->tlv_options || sh->phdev->tlv_options->refcnt == 1) { + /* Mark port as being closed one */ + sh->phdev->sh = NULL; + mlx5_unlock_physical_device(); + return 0; + } + mlx5_unlock_physical_device(); + rte_errno = EBUSY; + return -EBUSY; +} + +/** + * Validate GENEVE TLV option user request structure. + * + * @param attr + * Pointer to HCA attribute structure. + * @param option + * Pointer to user configuration. + * + * @return + * 0 on success, a negative errno otherwise and rte_errno is set. + */ +static int +mlx5_geneve_tlv_option_validate(struct mlx5_hca_attr *attr, + const struct rte_pmd_mlx5_geneve_tlv *option) +{ + if (option->option_len > attr->max_geneve_tlv_option_data_len) { + DRV_LOG(ERR, + "GENEVE TLV option length (%u) exceeds the limit (%u).", + option->option_len, + attr->max_geneve_tlv_option_data_len); + rte_errno = ENOTSUP; + return -rte_errno; + } + if (option->option_len < option->offset + option->sample_len) { + DRV_LOG(ERR, + "GENEVE TLV option length is smaller than (offset + sample_len)."); + rte_errno = EINVAL; + return -rte_errno; + } + if (option->match_on_class_mode > 2) { + DRV_LOG(ERR, + "GENEVE TLV option match_on_class_mode is invalid."); + rte_errno = EINVAL; + return -rte_errno; + } + return 0; +} + +/** + * Get the number of requested DWs in given GENEVE TLV option. + * + * @param option + * Pointer to user configuration. + * + * @return + * Number of requested DWs for given GENEVE TLV option. + */ +static uint8_t +mlx5_geneve_tlv_option_get_nb_dws(const struct rte_pmd_mlx5_geneve_tlv *option) +{ + uint8_t nb_dws = 0; + uint8_t i; + + if (option->match_on_class_mode == 2) + nb_dws++; + for (i = 0; i < option->sample_len; ++i) { + if (option->match_data_mask[i] == 0xffffffff) + nb_dws++; + } + return nb_dws; +} + +/** + * Compare GENEVE TLV option user request structure. + * + * @param option1 + * Pointer to first user configuration. + * @param option2 + * Pointer to second user configuration. + * + * @return + * True if the options are equal, false otherwise. + */ +static bool +mlx5_geneve_tlv_option_compare(const struct rte_pmd_mlx5_geneve_tlv *option1, + const struct rte_pmd_mlx5_geneve_tlv *option2) +{ + uint8_t i; + + if (option1->option_type != option2->option_type || + option1->option_class != option2->option_class || + option1->option_len != option2->option_len || + option1->offset != option2->offset || + option1->match_on_class_mode != option2->match_on_class_mode || + option1->sample_len != option2->sample_len) + return false; + for (i = 0; i < option1->sample_len; ++i) { + if (option1->match_data_mask[i] != option2->match_data_mask[i]) + return false; + } + return true; +} + +/** + * Check whether the given GENEVE TLV option list is equal to internal list. + * The lists are equal when they have same size and same options in the same + * order inside the list. + * + * @param options + * Pointer to GENEVE TLV options structure. + * @param tlv_list + * A list of GENEVE TLV options to compare. + * @param nb_options + * The number of options in TLV list. + * + * @return + * True if the lists are equal, false otherwise. + */ +static bool +mlx5_is_same_geneve_tlv_options(const struct mlx5_geneve_tlv_options *options, + const struct rte_pmd_mlx5_geneve_tlv tlv_list[], + uint8_t nb_options) +{ + const struct rte_pmd_mlx5_geneve_tlv *spec = options->spec; + uint8_t i; + + if (options->nb_options != nb_options) + return false; + for (i = 0; i < nb_options; ++i) { + if (!mlx5_geneve_tlv_option_compare(&spec[i], &tlv_list[i])) + return false; + } + return true; +} + +void * +mlx5_geneve_tlv_parser_create(uint16_t port_id, + const struct rte_pmd_mlx5_geneve_tlv tlv_list[], + uint8_t nb_options) +{ + struct mlx5_geneve_tlv_options *options = NULL; + struct mlx5_physical_device *phdev; + struct rte_eth_dev *dev; + struct mlx5_priv *priv; + struct mlx5_hca_attr *attr; + uint8_t total_dws = 0; + uint8_t i; + + /* + * Validate the input before taking a lock and before any memory + * allocation. + */ + 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 NULL; + } + dev = &rte_eth_devices[port_id]; + priv = dev->data->dev_private; + if (priv->tlv_options) { + DRV_LOG(ERR, "Port %u already has GENEVE TLV parser.", port_id); + rte_errno = EEXIST; + return NULL; + } + if (priv->sh->config.dv_flow_en < 2) { + DRV_LOG(ERR, + "GENEVE TLV parser is only supported for HW steering."); + rte_errno = ENOTSUP; + return NULL; + } + attr = &priv->sh->cdev->config.hca_attr; + MLX5_ASSERT(MAX_GENEVE_OPTIONS_RESOURCES <= + attr->max_geneve_tlv_options); + if (!attr->geneve_tlv_option_offset || !attr->geneve_tlv_sample || + !attr->query_match_sample_info || !attr->geneve_tlv_opt) { + DRV_LOG(ERR, "Not enough capabilities to support GENEVE TLV parser, maybe old FW version"); + rte_errno = ENOTSUP; + return NULL; + } + if (nb_options > MAX_GENEVE_OPTIONS_RESOURCES) { + DRV_LOG(ERR, + "GENEVE TLV option number (%u) exceeds the limit (%u).", + nb_options, MAX_GENEVE_OPTIONS_RESOURCES); + rte_errno = EINVAL; + return NULL; + } + for (i = 0; i < nb_options; ++i) { + if (mlx5_geneve_tlv_option_validate(attr, &tlv_list[i]) < 0) { + DRV_LOG(ERR, "GENEVE TLV option %u is invalid.", i); + return NULL; + } + total_dws += mlx5_geneve_tlv_option_get_nb_dws(&tlv_list[i]); + } + if (total_dws > MAX_GENEVE_OPTIONS_RESOURCES) { + DRV_LOG(ERR, + "Total requested DWs (%u) exceeds the limit (%u).", + total_dws, MAX_GENEVE_OPTIONS_RESOURCES); + rte_errno = EINVAL; + return NULL; + } + /* Take lock for this physical device and manage the options. */ + phdev = mlx5_get_locked_physical_device(priv); + options = priv->sh->phdev->tlv_options; + if (options) { + if (!mlx5_is_same_geneve_tlv_options(options, tlv_list, + nb_options)) { + mlx5_unlock_physical_device(); + DRV_LOG(ERR, "Another port has already prepared different GENEVE TLV parser."); + rte_errno = EEXIST; + return NULL; + } + if (phdev->sh == NULL) { + mlx5_unlock_physical_device(); + DRV_LOG(ERR, "GENEVE TLV options are hosted on port being closed."); + rte_errno = EBUSY; + return NULL; + } + /* Use existing options. */ + options->refcnt++; + goto exit; + } + /* Create GENEVE TLV options for this physical device. */ + options = mlx5_geneve_tlv_options_create(priv->sh, tlv_list, nb_options); + if (!options) { + mlx5_unlock_physical_device(); + return NULL; + } + phdev->tlv_options = options; +exit: + mlx5_unlock_physical_device(); + priv->tlv_options = options; + return priv; +} + +int +mlx5_geneve_tlv_parser_destroy(void *handle) +{ + struct mlx5_priv *priv = (struct mlx5_priv *)handle; + struct mlx5_physical_device *phdev; + int ret; + + if (priv == NULL) { + DRV_LOG(ERR, "Handle input is invalid (NULL)."); + rte_errno = EINVAL; + return -rte_errno; + } + if (priv->tlv_options == NULL) { + DRV_LOG(ERR, "This parser has been already released."); + rte_errno = ENOENT; + return -rte_errno; + } + /* Take lock for this physical device and manage the options. */ + phdev = mlx5_get_locked_physical_device(priv); + /* Destroy the options */ + ret = mlx5_geneve_tlv_options_destroy(phdev->tlv_options, phdev); + if (ret < 0) { + mlx5_unlock_physical_device(); + return ret; + } + priv->tlv_options = NULL; + mlx5_unlock_physical_device(); + return 0; +} + +#endif /* defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) */ diff --git a/drivers/net/mlx5/rte_pmd_mlx5.h b/drivers/net/mlx5/rte_pmd_mlx5.h index 654dd3cff3..004be0eea1 100644 --- a/drivers/net/mlx5/rte_pmd_mlx5.h +++ b/drivers/net/mlx5/rte_pmd_mlx5.h @@ -229,6 +229,108 @@ enum rte_pmd_mlx5_flow_engine_mode { __rte_experimental int rte_pmd_mlx5_flow_engine_set_mode(enum rte_pmd_mlx5_flow_engine_mode mode, uint32_t flags); +/** + * User configuration structure using to create parser for single GENEVE TLV option. + */ +struct rte_pmd_mlx5_geneve_tlv { + /** + * The class of the GENEVE TLV option. + * Relevant only when 'match_on_class_mode' is 1. + */ + rte_be16_t option_class; + /** + * The type of the GENEVE TLV option. + * This field is the identifier of the option. + */ + uint8_t option_type; + /** + * The length of the GENEVE TLV option data excluding the option header + * in DW granularity. + */ + uint8_t option_len; + /** + * Indicator about class field role in this option: + * 0 - class is ignored. + * 1 - class is fixed (the class defines the option along with the type). + * 2 - class matching per flow. + */ + uint8_t match_on_class_mode; + /** + * The offset of the first sample in DW granularity. + * This offset is relative to first of option data. + * The 'match_data_mask' corresponds to option data since this offset. + */ + uint8_t offset; + /** + * The number of DW to sample. + * This field describes the length of 'match_data_mask' in DW + * granularity. + */ + uint8_t sample_len; + /** + * Array of DWs which each bit marks if this bit should be sampled. + * Each nonzero DW consumes one DW from maximum 7 DW in total. + */ + rte_be32_t *match_data_mask; +}; + +/** + * Creates GENEVE TLV parser for the selected port. + * This function must be called before first use of GENEVE option. + * + * This API is port oriented, but the configuration is done once for all ports + * under the same physical device. Each port should call this API before using + * GENEVE OPT item, but it must use the same options in the same order inside + * the list. + * + * Each physical device has 7 DWs for GENEVE TLV options. Each nonzero element + * in 'match_data_mask' array consumes one DW, and choosing matchable mode for + * class consumes additional one. + * Calling this API for second port under same physical device doesn't consume + * more DW, it uses same configuration. + * + * @param[in] port_id + * The port identifier of the Ethernet device. + * @param[in] tlv_list + * A list of GENEVE TLV options to create parser for them. + * @param[in] nb_options + * The number of options in TLV list. + * + * @return + * A pointer to TLV handle on success, NULL otherwise and rte_errno is set. + * Possible values for rte_errno: + * - ENOMEM - not enough memory to create GENEVE TLV parser. + * - EEXIST - this port already has GENEVE TLV parser or another port under + * same physical device has already prepared a different parser. + * - EINVAL - invalid GENEVE TLV requested. + * - ENODEV - there is no Ethernet device for this port id. + * - ENOTSUP - the port doesn't support GENEVE TLV parsing. + */ +__rte_experimental +void * +rte_pmd_mlx5_create_geneve_tlv_parser(uint16_t port_id, + const struct rte_pmd_mlx5_geneve_tlv tlv_list[], + uint8_t nb_options); + +/** + * Destroy GENEVE TLV parser for the selected port. + * This function must be called after last use of GENEVE option and before port + * closing. + * + * @param[in] handle + * Handle for the GENEVE TLV parser object to be destroyed. + * + * @return + * 0 on success, a negative errno value otherwise and rte_errno is set. + * Possible values for rte_errno: + * - EINVAL - invalid handle. + * - ENOENT - there is no valid GENEVE TLV parser in this handle. + * - EBUSY - one of options is in used by template table. + */ +__rte_experimental +int +rte_pmd_mlx5_destroy_geneve_tlv_parser(void *handle); + #ifdef __cplusplus } #endif diff --git a/drivers/net/mlx5/version.map b/drivers/net/mlx5/version.map index 99f5ab754a..8fb0e07303 100644 --- a/drivers/net/mlx5/version.map +++ b/drivers/net/mlx5/version.map @@ -17,4 +17,7 @@ EXPERIMENTAL { rte_pmd_mlx5_external_sq_enable; # added in 23.03 rte_pmd_mlx5_flow_engine_set_mode; + # added in 24.03 + rte_pmd_mlx5_create_geneve_tlv_parser; + rte_pmd_mlx5_destroy_geneve_tlv_parser; };