All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michael Baum <michaelba@nvidia.com>
To: <dev@dpdk.org>
Cc: Matan Azrad <matan@nvidia.com>,
	Raslan Darawsheh <rasland@nvidia.com>,
	Viacheslav Ovsiienko <viacheslavo@nvidia.com>,
	Ori Kam <orika@nvidia.com>, Suanming Mou <suanmingm@nvidia.com>
Subject: [PATCH v1 13/23] net/mlx5: add GENEVE TLV options parser API
Date: Sun, 3 Dec 2023 13:25:33 +0200	[thread overview]
Message-ID: <20231203112543.844014-14-michaelba@nvidia.com> (raw)
In-Reply-To: <20231203112543.844014-1-michaelba@nvidia.com>

Add a new private API to create/destroy parser for GENEVE TLV options.

Signed-off-by: Michael Baum <michaelba@nvidia.com>
Signed-off-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
 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 6b52fb93c5..80446d8d82 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -2298,6 +2298,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 <https://www.rfc-editor.org/rfc/rfc8926.html#name-tunnel-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 6a82c38cf4..2e0d71a12c 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;
 };
 
@@ -1949,6 +1952,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. */
@@ -2087,6 +2092,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 85e8c77c81..ae53cc8e74 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -12476,3 +12476,33 @@ mlx5_flow_pick_transfer_proxy(struct rte_eth_dev *dev,
 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
 				  NULL, "unable to find a proxy port");
 }
+
+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 6dde9de688..4bfc218175 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1330,6 +1330,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;
@@ -1644,6 +1646,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;
@@ -1759,6 +1766,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);
@@ -2803,6 +2816,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 <rte_flow.h>
+
+#include <mlx5_malloc.h>
+#include <stdint.h>
+
+#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;
 };
-- 
2.25.1


  parent reply	other threads:[~2023-12-03 11:28 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-03 11:25 [PATCH v1 00/23] net/mlx5: support Geneve and options for HWS Michael Baum
2023-12-03 11:25 ` [PATCH v1 01/23] common/mlx5: fix duplicate read of general capabilities Michael Baum
2023-12-03 11:25 ` [PATCH v1 02/23] common/mlx5: fix query sample info capability Michael Baum
2023-12-03 11:25 ` [PATCH v1 03/23] net/mlx5/hws: fix tunnel protocol checks Michael Baum
2023-12-03 11:25 ` [PATCH v1 04/23] net/mlx5: remove GENEVE options length limitation Michael Baum
2023-12-03 11:25 ` [PATCH v1 05/23] net/mlx5: fix GENEVE option item translation Michael Baum
2023-12-03 11:25 ` [PATCH v1 06/23] common/mlx5: add system image GUID attribute Michael Baum
2023-12-03 11:25 ` [PATCH v1 07/23] common/mlx5: add GENEVE TLV option attribute structure Michael Baum
2023-12-03 11:25 ` [PATCH v1 08/23] common/mlx5: add PRM attribute for TLV sample Michael Baum
2023-12-03 11:25 ` [PATCH v1 09/23] common/mlx5: add sample info query syndrome into error log Michael Baum
2023-12-03 11:25 ` [PATCH v1 10/23] common/mlx5: query GENEVE option sample ID from HCA attr Michael Baum
2023-12-03 11:25 ` [PATCH v1 11/23] common/mlx5: add function to query GENEVE TLV option Michael Baum
2023-12-03 11:25 ` [PATCH v1 12/23] net/mlx5: add physical device handle Michael Baum
2023-12-03 11:25 ` Michael Baum [this message]
2023-12-03 11:25 ` [PATCH v1 14/23] net/mlx5: add API to expose GENEVE option FW information Michael Baum
2023-12-03 11:25 ` [PATCH v1 15/23] net/mlx5: add testpmd support for GENEVE TLV parser Michael Baum
2023-12-03 11:25 ` [PATCH v1 16/23] net/mlx5/hws: increase hl size for future compatibility Michael Baum
2023-12-03 11:25 ` [PATCH v1 17/23] net/mlx5/hws: support GENEVE matching Michael Baum
2023-12-03 11:25 ` [PATCH v1 18/23] net/mlx5/hws: support GENEVE options header Michael Baum
2023-12-03 11:25 ` [PATCH v1 19/23] net/mlx5: add support for GENEVE and option item in HWS Michael Baum
2023-12-03 11:25 ` [PATCH v1 20/23] net/mlx5: add GENEVE option support for profile 0 Michael Baum
2023-12-03 11:25 ` [PATCH v1 21/23] net/mlx5: add GENEVE option support for group 0 Michael Baum
2023-12-03 11:25 ` [PATCH v1 22/23] net/mlx5: add support for GENEVE VNI modify field Michael Baum
2023-12-03 11:25 ` [PATCH v1 23/23] net/mlx5: add support for modify GENEVE option header Michael Baum
2024-01-25  9:42 ` [PATCH v1 00/23] net/mlx5: support Geneve and options for HWS Suanming Mou
2024-01-25 13:30 ` [PATCH v2 " Michael Baum
2024-01-25 13:30   ` [PATCH v2 01/23] common/mlx5: fix duplicate read of general capabilities Michael Baum
2024-01-25 13:30   ` [PATCH v2 02/23] common/mlx5: fix query sample info capability Michael Baum
2024-01-25 13:30   ` [PATCH v2 03/23] net/mlx5/hws: fix tunnel protocol checks Michael Baum
2024-01-25 13:30   ` [PATCH v2 04/23] net/mlx5: remove GENEVE options length limitation Michael Baum
2024-01-25 13:30   ` [PATCH v2 05/23] net/mlx5: fix GENEVE option item translation Michael Baum
2024-01-25 13:30   ` [PATCH v2 06/23] common/mlx5: add system image GUID attribute Michael Baum
2024-01-25 13:30   ` [PATCH v2 07/23] common/mlx5: add GENEVE TLV option attribute structure Michael Baum
2024-01-25 13:30   ` [PATCH v2 08/23] common/mlx5: add PRM attribute for TLV sample Michael Baum
2024-01-25 13:30   ` [PATCH v2 09/23] common/mlx5: add sample info query syndrome into error log Michael Baum
2024-01-25 13:30   ` [PATCH v2 10/23] common/mlx5: query GENEVE option sample ID from HCA attr Michael Baum
2024-01-25 13:30   ` [PATCH v2 11/23] common/mlx5: add function to query GENEVE TLV option Michael Baum
2024-01-25 13:30   ` [PATCH v2 12/23] net/mlx5: add physical device handle Michael Baum
2024-01-25 13:30   ` [PATCH v2 13/23] net/mlx5: add GENEVE TLV options parser API Michael Baum
2024-01-25 13:30   ` [PATCH v2 14/23] net/mlx5: add API to expose GENEVE option FW information Michael Baum
2024-01-25 13:30   ` [PATCH v2 15/23] net/mlx5: add testpmd support for GENEVE TLV parser Michael Baum
2024-01-25 13:30   ` [PATCH v2 16/23] net/mlx5/hws: increase hl size for future compatibility Michael Baum
2024-01-25 13:30   ` [PATCH v2 17/23] net/mlx5/hws: support GENEVE matching Michael Baum
2024-01-25 13:30   ` [PATCH v2 18/23] net/mlx5/hws: support GENEVE options header Michael Baum
2024-01-25 13:30   ` [PATCH v2 19/23] net/mlx5: add support for GENEVE and option item in HWS Michael Baum
2024-01-25 13:30   ` [PATCH v2 20/23] net/mlx5: add GENEVE option support for profile 0 Michael Baum
2024-01-25 13:30   ` [PATCH v2 21/23] net/mlx5: add GENEVE option support for group 0 Michael Baum
2024-01-25 13:30   ` [PATCH v2 22/23] net/mlx5: add support for GENEVE VNI modify field Michael Baum
2024-01-25 13:30   ` [PATCH v2 23/23] net/mlx5: add support for modify GENEVE option header Michael Baum
2024-01-29 12:21   ` [PATCH v2 00/23] net/mlx5: support Geneve and options for HWS Raslan Darawsheh

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231203112543.844014-14-michaelba@nvidia.com \
    --to=michaelba@nvidia.com \
    --cc=dev@dpdk.org \
    --cc=matan@nvidia.com \
    --cc=orika@nvidia.com \
    --cc=rasland@nvidia.com \
    --cc=suanmingm@nvidia.com \
    --cc=viacheslavo@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.