* [PATCH 1/4] ethdev: introduce encap hash calculation
2024-01-28 9:39 [PATCH 0/4] introduce encap hash calculation Ori Kam
@ 2024-01-28 9:39 ` Ori Kam
2024-02-01 8:40 ` Ori Kam
2024-02-06 22:39 ` Thomas Monjalon
2024-01-28 9:39 ` [PATCH 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
` (6 subsequent siblings)
7 siblings, 2 replies; 31+ messages in thread
From: Ori Kam @ 2024-01-28 9:39 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Thomas Monjalon
Cc: dev, orika, rasland
During the encapsulation of a packet, it is expected to calculate the
hash value which is based on the original packet (the outer values,
which will become the inner values).
The tunnel protocol defines which tunnel field should hold this hash,
but it doesn't define the hash calculation algorithm.
An application that uses flow offloads gets the first few packets
and then decides to offload the flow. As a result, there are two
different paths that a packet from a given flow may take.
SW for the first few packets or HW for the rest.
When the packet goes through the SW, the SW encapsulates the packet
and must use the same hash calculation as the HW will do for
the rest of the packets in this flow.
This patch gives the SW a way to query the hash value
for a given packet as if the packet was passed through the HW.
Signed-off-by: Ori Kam <orika@nvidia.com>
---
doc/guides/prog_guide/rte_flow.rst | 22 ++++++++++++
doc/guides/rel_notes/release_24_03.rst | 4 +++
lib/ethdev/rte_flow.c | 25 +++++++++++++
lib/ethdev/rte_flow.h | 50 ++++++++++++++++++++++++++
lib/ethdev/rte_flow_driver.h | 5 +++
lib/ethdev/version.map | 1 +
6 files changed, 107 insertions(+)
diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 900fdaefb6..0435dda3c7 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -4211,6 +4211,28 @@ as it would be calculated in the HW.
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+Calculate encap hash
+~~~~~~~~~~~~~~~~~~~~
+
+Calculating hash of a packet in SW as it would be calculated in HW for the encap action
+
+When the HW execute an encapsulation action, it may calculate an hash value which is based
+on the original packet. This hash is stored depending on the encapsulation protocol, in one
+of the outer fields.
+
+This function allows the application to calculate the hash for a given packet as if the
+encapsulation was done in HW.
+
+.. code-block:: c
+
+ int
+ rte_flow_calc_encap_hash(uint16_t port_id,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t hash_len,
+ uint8_t *hash,
+ struct rte_flow_error *error);
+
.. _flow_isolated_mode:
Flow isolated mode
diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst
index 5e545da867..80af380172 100644
--- a/doc/guides/rel_notes/release_24_03.rst
+++ b/doc/guides/rel_notes/release_24_03.rst
@@ -75,6 +75,10 @@ New Features
* Added support for VXLAN-GPE matching in HW Steering flow engine
(``dv_flow_en`` = 2).
+* **Added ability to calculate the encap hash as done by HW.**
+
+ * Added function that calculates the encap hash, as the HW calculates it:
+ ``rte_flow_calc_encap_hash()``
Removed Items
-------------
diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
index 3f58d792f9..7fce754be1 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -2482,3 +2482,28 @@ rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
hash, error);
return flow_err(port_id, ret, error);
}
+
+int
+rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
+ uint8_t *hash, struct rte_flow_error *error)
+{
+ int ret;
+ struct rte_eth_dev *dev;
+ const struct rte_flow_ops *ops;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ ops = rte_flow_ops_get(port_id, error);
+ if (!ops || !ops->flow_calc_encap_hash)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "calc encap hash is not supported");
+ if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT && hash_len != 2) ||
+ (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID && hash_len != 1))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "hash len doesn't match the requested field len");
+ dev = &rte_eth_devices[port_id];
+ ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash, error);
+ return flow_err(port_id, ret, error);
+}
diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
index 1267c146e5..ffbde58245 100644
--- a/lib/ethdev/rte_flow.h
+++ b/lib/ethdev/rte_flow.h
@@ -6783,6 +6783,56 @@ rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
const struct rte_flow_item pattern[], uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Destination field type for the hash calculation, when encap action is used.
+ *
+ * @see function rte_flow_calc_encap_hash
+ */
+enum rte_flow_encap_hash_field {
+ /* Calculate hash placed in UDP source port field. */
+ RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
+ /* Calculate hash placed in NVGRE flow ID field. */
+ RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Simulates HW hash calculation that is done when encap action is being used.
+ *
+ * @param[in] port_id
+ * Port identifier of Ethernet device.
+ * @param[in] pattern
+ * The values to be used in the hash calculation.
+ * @param[in] dest_field
+ * Type of destination field for hash calculation.
+ * @param[in] hash_len
+ * The length of the hash pointer in bytes. Should be according to encap_hash_field.
+ * @param[out] hash
+ * Used to return the calculated hash. It will be written in network order,
+ * so hash[0] is the MSB.
+ * The number of bytes is based on the destination field type.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ * PMDs initialize this structure in case of error only.
+ *
+ * @return
+ * - (0) if success.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-ENOTSUP) if underlying device does not support this functionality.
+ * - (-EINVAL) if *pattern* doesn't hold enough information to calculate the hash
+ * or the dest is not supported.
+ */
+__rte_experimental
+int
+rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
+ uint8_t *hash, struct rte_flow_error *error);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/ethdev/rte_flow_driver.h b/lib/ethdev/rte_flow_driver.h
index f35f659503..447163655a 100644
--- a/lib/ethdev/rte_flow_driver.h
+++ b/lib/ethdev/rte_flow_driver.h
@@ -370,6 +370,11 @@ struct rte_flow_ops {
(struct rte_eth_dev *dev, const struct rte_flow_template_table *table,
const struct rte_flow_item pattern[], uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+ /** @see rte_flow_calc_encap_hash() */
+ int (*flow_calc_encap_hash)
+ (struct rte_eth_dev *dev, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t *hash,
+ struct rte_flow_error *error);
};
/**
diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
index a050baab0f..360898d067 100644
--- a/lib/ethdev/version.map
+++ b/lib/ethdev/version.map
@@ -319,6 +319,7 @@ EXPERIMENTAL {
# added in 24.03
rte_eth_find_rss_algo;
+ rte_flow_calc_encap_hash;
};
INTERNAL {
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: [PATCH 1/4] ethdev: introduce encap hash calculation
2024-01-28 9:39 ` [PATCH 1/4] ethdev: " Ori Kam
@ 2024-02-01 8:40 ` Ori Kam
2024-02-06 22:39 ` Thomas Monjalon
1 sibling, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-01 8:40 UTC (permalink / raw)
To: ferruh.yigit; +Cc: dev, Raslan Darawsheh
Hi Ferruh,
Can you please review my patch?
Thanks,
Ori
> -----Original Message-----
> From: Ori Kam <orika@nvidia.com>
> Sent: Sunday, January 28, 2024 11:40 AM
> To: Dariusz Sosnowski <dsosnowski@nvidia.com>; ferruh.yigit@amd.com;
>
> During the encapsulation of a packet, it is expected to calculate the
> hash value which is based on the original packet (the outer values,
> which will become the inner values).
>
> The tunnel protocol defines which tunnel field should hold this hash,
> but it doesn't define the hash calculation algorithm.
>
> An application that uses flow offloads gets the first few packets
> and then decides to offload the flow. As a result, there are two
> different paths that a packet from a given flow may take.
> SW for the first few packets or HW for the rest.
> When the packet goes through the SW, the SW encapsulates the packet
> and must use the same hash calculation as the HW will do for
> the rest of the packets in this flow.
>
> This patch gives the SW a way to query the hash value
> for a given packet as if the packet was passed through the HW.
>
> Signed-off-by: Ori Kam <orika@nvidia.com>
> ---
> doc/guides/prog_guide/rte_flow.rst | 22 ++++++++++++
> doc/guides/rel_notes/release_24_03.rst | 4 +++
> lib/ethdev/rte_flow.c | 25 +++++++++++++
> lib/ethdev/rte_flow.h | 50 ++++++++++++++++++++++++++
> lib/ethdev/rte_flow_driver.h | 5 +++
> lib/ethdev/version.map | 1 +
> 6 files changed, 107 insertions(+)
>
> diff --git a/doc/guides/prog_guide/rte_flow.rst
> b/doc/guides/prog_guide/rte_flow.rst
> index 900fdaefb6..0435dda3c7 100644
> --- a/doc/guides/prog_guide/rte_flow.rst
> +++ b/doc/guides/prog_guide/rte_flow.rst
> @@ -4211,6 +4211,28 @@ as it would be calculated in the HW.
> uint8_t pattern_template_index,
> uint32_t *hash, struct rte_flow_error
> *error);
>
> +Calculate encap hash
> +~~~~~~~~~~~~~~~~~~~~
> +
> +Calculating hash of a packet in SW as it would be calculated in HW for the
> encap action
> +
> +When the HW execute an encapsulation action, it may calculate an hash
> value which is based
> +on the original packet. This hash is stored depending on the encapsulation
> protocol, in one
> +of the outer fields.
> +
> +This function allows the application to calculate the hash for a given packet
> as if the
> +encapsulation was done in HW.
> +
> +.. code-block:: c
> +
> + int
> + rte_flow_calc_encap_hash(uint16_t port_id,
> + const struct rte_flow_item pattern[],
> + enum rte_flow_encap_hash_field
> dest_field,
> + uint8_t hash_len,
> + uint8_t *hash,
> + struct rte_flow_error *error);
> +
> .. _flow_isolated_mode:
>
> Flow isolated mode
> diff --git a/doc/guides/rel_notes/release_24_03.rst
> b/doc/guides/rel_notes/release_24_03.rst
> index 5e545da867..80af380172 100644
> --- a/doc/guides/rel_notes/release_24_03.rst
> +++ b/doc/guides/rel_notes/release_24_03.rst
> @@ -75,6 +75,10 @@ New Features
> * Added support for VXLAN-GPE matching in HW Steering flow engine
> (``dv_flow_en`` = 2).
>
> +* **Added ability to calculate the encap hash as done by HW.**
> +
> + * Added function that calculates the encap hash, as the HW calculates it:
> + ``rte_flow_calc_encap_hash()``
>
> Removed Items
> -------------
> diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
> index 3f58d792f9..7fce754be1 100644
> --- a/lib/ethdev/rte_flow.c
> +++ b/lib/ethdev/rte_flow.c
> @@ -2482,3 +2482,28 @@ rte_flow_calc_table_hash(uint16_t port_id, const
> struct rte_flow_template_table
> hash, error);
> return flow_err(port_id, ret, error);
> }
> +
> +int
> +rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item
> pattern[],
> + enum rte_flow_encap_hash_field dest_field, uint8_t
> hash_len,
> + uint8_t *hash, struct rte_flow_error *error)
> +{
> + int ret;
> + struct rte_eth_dev *dev;
> + const struct rte_flow_ops *ops;
> +
> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
> + ops = rte_flow_ops_get(port_id, error);
> + if (!ops || !ops->flow_calc_encap_hash)
> + return rte_flow_error_set(error, ENOTSUP,
> +
> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> + "calc encap hash is not supported");
> + if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT &&
> hash_len != 2) ||
> + (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID
> && hash_len != 1))
> + return rte_flow_error_set(error, EINVAL,
> +
> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> + "hash len doesn't match the
> requested field len");
> + dev = &rte_eth_devices[port_id];
> + ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash,
> error);
> + return flow_err(port_id, ret, error);
> +}
> diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
> index 1267c146e5..ffbde58245 100644
> --- a/lib/ethdev/rte_flow.h
> +++ b/lib/ethdev/rte_flow.h
> @@ -6783,6 +6783,56 @@ rte_flow_calc_table_hash(uint16_t port_id, const
> struct rte_flow_template_table
> const struct rte_flow_item pattern[], uint8_t
> pattern_template_index,
> uint32_t *hash, struct rte_flow_error *error);
>
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Destination field type for the hash calculation, when encap action is used.
> + *
> + * @see function rte_flow_calc_encap_hash
> + */
> +enum rte_flow_encap_hash_field {
> + /* Calculate hash placed in UDP source port field. */
> + RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
> + /* Calculate hash placed in NVGRE flow ID field. */
> + RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
> +};
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Simulates HW hash calculation that is done when encap action is being
> used.
> + *
> + * @param[in] port_id
> + * Port identifier of Ethernet device.
> + * @param[in] pattern
> + * The values to be used in the hash calculation.
> + * @param[in] dest_field
> + * Type of destination field for hash calculation.
> + * @param[in] hash_len
> + * The length of the hash pointer in bytes. Should be according to
> encap_hash_field.
> + * @param[out] hash
> + * Used to return the calculated hash. It will be written in network order,
> + * so hash[0] is the MSB.
> + * The number of bytes is based on the destination field type.
> + * @param[out] error
> + * Perform verbose error reporting if not NULL.
> + * PMDs initialize this structure in case of error only.
> + *
> + * @return
> + * - (0) if success.
> + * - (-ENODEV) if *port_id* invalid.
> + * - (-ENOTSUP) if underlying device does not support this functionality.
> + * - (-EINVAL) if *pattern* doesn't hold enough information to calculate the
> hash
> + * or the dest is not supported.
> + */
> +__rte_experimental
> +int
> +rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item
> pattern[],
> + enum rte_flow_encap_hash_field dest_field, uint8_t
> hash_len,
> + uint8_t *hash, struct rte_flow_error *error);
> +
> #ifdef __cplusplus
> }
> #endif
> diff --git a/lib/ethdev/rte_flow_driver.h b/lib/ethdev/rte_flow_driver.h
> index f35f659503..447163655a 100644
> --- a/lib/ethdev/rte_flow_driver.h
> +++ b/lib/ethdev/rte_flow_driver.h
> @@ -370,6 +370,11 @@ struct rte_flow_ops {
> (struct rte_eth_dev *dev, const struct
> rte_flow_template_table *table,
> const struct rte_flow_item pattern[], uint8_t
> pattern_template_index,
> uint32_t *hash, struct rte_flow_error *error);
> + /** @see rte_flow_calc_encap_hash() */
> + int (*flow_calc_encap_hash)
> + (struct rte_eth_dev *dev, const struct rte_flow_item
> pattern[],
> + enum rte_flow_encap_hash_field dest_field, uint8_t *hash,
> + struct rte_flow_error *error);
> };
>
> /**
> diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
> index a050baab0f..360898d067 100644
> --- a/lib/ethdev/version.map
> +++ b/lib/ethdev/version.map
> @@ -319,6 +319,7 @@ EXPERIMENTAL {
>
> # added in 24.03
> rte_eth_find_rss_algo;
> + rte_flow_calc_encap_hash;
> };
>
> INTERNAL {
> --
> 2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/4] ethdev: introduce encap hash calculation
2024-01-28 9:39 ` [PATCH 1/4] ethdev: " Ori Kam
2024-02-01 8:40 ` Ori Kam
@ 2024-02-06 22:39 ` Thomas Monjalon
2024-02-07 6:56 ` Ori Kam
1 sibling, 1 reply; 31+ messages in thread
From: Thomas Monjalon @ 2024-02-06 22:39 UTC (permalink / raw)
To: Ori Kam
Cc: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, dev, rasland
28/01/2024 10:39, Ori Kam:
> During the encapsulation of a packet, it is expected to calculate the
> hash value which is based on the original packet (the outer values,
> which will become the inner values).
It is not clear what the hash is for.
> The tunnel protocol defines which tunnel field should hold this hash,
> but it doesn't define the hash calculation algorithm.
If the hash is stored in the packet header,
I expect it to be reproducible when being checked.
How the algorithm may be undefined?
> An application that uses flow offloads gets the first few packets
> and then decides to offload the flow. As a result, there are two
> different paths that a packet from a given flow may take.
> SW for the first few packets or HW for the rest.
> When the packet goes through the SW, the SW encapsulates the packet
> and must use the same hash calculation as the HW will do for
> the rest of the packets in this flow.
>
> This patch gives the SW a way to query the hash value
> for a given packet as if the packet was passed through the HW.
>
> Signed-off-by: Ori Kam <orika@nvidia.com>
> ---
> +Calculate encap hash
> +~~~~~~~~~~~~~~~~~~~~
> +
> +Calculating hash of a packet in SW as it would be calculated in HW for the encap action
We should give the real full name of the flow action.
> +
> +When the HW execute an encapsulation action, it may calculate an hash value which is based
> +on the original packet. This hash is stored depending on the encapsulation protocol, in one
> +of the outer fields.
Give an example of such encapsulation protocol?
> +This function allows the application to calculate the hash for a given packet as if the
> +encapsulation was done in HW.
> +
> +.. code-block:: c
> +
> + int
> + rte_flow_calc_encap_hash(uint16_t port_id,
> + const struct rte_flow_item pattern[],
> + enum rte_flow_encap_hash_field dest_field,
> + uint8_t hash_len,
> + uint8_t *hash,
> + struct rte_flow_error *error);
I don't think we should add the complete prototype in this guide.
[...]
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Simulates HW hash calculation that is done when encap action is being used.
s/Simulates/Simulate/
> + *
> + * @param[in] port_id
> + * Port identifier of Ethernet device.
> + * @param[in] pattern
> + * The values to be used in the hash calculation.
> + * @param[in] dest_field
> + * Type of destination field for hash calculation.
> + * @param[in] hash_len
> + * The length of the hash pointer in bytes. Should be according to encap_hash_field.
> + * @param[out] hash
> + * Used to return the calculated hash. It will be written in network order,
> + * so hash[0] is the MSB.
> + * The number of bytes is based on the destination field type.
> + * @param[out] error
> + * Perform verbose error reporting if not NULL.
> + * PMDs initialize this structure in case of error only.
> + *
> + * @return
> + * - (0) if success.
> + * - (-ENODEV) if *port_id* invalid.
> + * - (-ENOTSUP) if underlying device does not support this functionality.
> + * - (-EINVAL) if *pattern* doesn't hold enough information to calculate the hash
> + * or the dest is not supported.
> + */
> +__rte_experimental
> +int
> +rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
> + enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
> + uint8_t *hash, struct rte_flow_error *error);
^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: [PATCH 1/4] ethdev: introduce encap hash calculation
2024-02-06 22:39 ` Thomas Monjalon
@ 2024-02-07 6:56 ` Ori Kam
2024-02-07 9:25 ` Thomas Monjalon
0 siblings, 1 reply; 31+ messages in thread
From: Ori Kam @ 2024-02-07 6:56 UTC (permalink / raw)
To: NBU-Contact-Thomas Monjalon (EXTERNAL)
Cc: Dariusz Sosnowski, ferruh.yigit, cristian.dumitrescu,
andrew.rybchenko, stephen, dev, Raslan Darawsheh
Hi Thomas,
> -----Original Message-----
> From: Thomas Monjalon <thomas@monjalon.net>
> Sent: Wednesday, February 7, 2024 12:40 AM
>
> 28/01/2024 10:39, Ori Kam:
> > During the encapsulation of a packet, it is expected to calculate the
> > hash value which is based on the original packet (the outer values,
> > which will become the inner values).
>
> It is not clear what the hash is for.
Will add explanation.
>
> > The tunnel protocol defines which tunnel field should hold this hash,
> > but it doesn't define the hash calculation algorithm.
>
> If the hash is stored in the packet header,
> I expect it to be reproducible when being checked.
> How the algorithm may be undefined?
>
The hash is not being checked it is used for hash the packets to different queues.
the actual value is not important. It is critical that all packets that belongs to the same
flow will have the same hash value.
> > An application that uses flow offloads gets the first few packets
> > and then decides to offload the flow. As a result, there are two
> > different paths that a packet from a given flow may take.
> > SW for the first few packets or HW for the rest.
> > When the packet goes through the SW, the SW encapsulates the packet
> > and must use the same hash calculation as the HW will do for
> > the rest of the packets in this flow.
> >
> > This patch gives the SW a way to query the hash value
> > for a given packet as if the packet was passed through the HW.
> >
> > Signed-off-by: Ori Kam <orika@nvidia.com>
> > ---
> > +Calculate encap hash
> > +~~~~~~~~~~~~~~~~~~~~
> > +
> > +Calculating hash of a packet in SW as it would be calculated in HW for the
> encap action
>
> We should give the real full name of the flow action.
>
> > +
> > +When the HW execute an encapsulation action, it may calculate an hash
> value which is based
> > +on the original packet. This hash is stored depending on the encapsulation
> protocol, in one
> > +of the outer fields.
>
> Give an example of such encapsulation protocol?
Sure,
Just to be clear something like this?
When the HW execute an encapsulation action for example for VXLAN tunnel,, it may ...
>
> > +This function allows the application to calculate the hash for a given
> packet as if the
> > +encapsulation was done in HW.
> > +
> > +.. code-block:: c
> > +
> > + int
> > + rte_flow_calc_encap_hash(uint16_t port_id,
> > + const struct rte_flow_item pattern[],
> > + enum rte_flow_encap_hash_field
> dest_field,
> > + uint8_t hash_len,
> > + uint8_t *hash,
> > + struct rte_flow_error *error);
>
> I don't think we should add the complete prototype in this guide.
Agree, will remove.
>
> [...]
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change without prior notice.
> > + *
> > + * Simulates HW hash calculation that is done when encap action is being
> used.
>
> s/Simulates/Simulate/
Will fix.
>
> > + *
> > + * @param[in] port_id
> > + * Port identifier of Ethernet device.
> > + * @param[in] pattern
> > + * The values to be used in the hash calculation.
> > + * @param[in] dest_field
> > + * Type of destination field for hash calculation.
> > + * @param[in] hash_len
> > + * The length of the hash pointer in bytes. Should be according to
> encap_hash_field.
> > + * @param[out] hash
> > + * Used to return the calculated hash. It will be written in network order,
> > + * so hash[0] is the MSB.
> > + * The number of bytes is based on the destination field type.
> > + * @param[out] error
> > + * Perform verbose error reporting if not NULL.
> > + * PMDs initialize this structure in case of error only.
> > + *
> > + * @return
> > + * - (0) if success.
> > + * - (-ENODEV) if *port_id* invalid.
> > + * - (-ENOTSUP) if underlying device does not support this functionality.
> > + * - (-EINVAL) if *pattern* doesn't hold enough information to calculate
> the hash
> > + * or the dest is not supported.
> > + */
> > +__rte_experimental
> > +int
> > +rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item
> pattern[],
> > + enum rte_flow_encap_hash_field dest_field, uint8_t
> hash_len,
> > + uint8_t *hash, struct rte_flow_error *error);
>
>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH 1/4] ethdev: introduce encap hash calculation
2024-02-07 6:56 ` Ori Kam
@ 2024-02-07 9:25 ` Thomas Monjalon
0 siblings, 0 replies; 31+ messages in thread
From: Thomas Monjalon @ 2024-02-07 9:25 UTC (permalink / raw)
To: Ori Kam
Cc: Dariusz Sosnowski, ferruh.yigit, cristian.dumitrescu,
andrew.rybchenko, stephen, dev, Raslan Darawsheh
07/02/2024 07:56, Ori Kam:
> Hi Thomas,
>
> > -----Original Message-----
> > From: Thomas Monjalon <thomas@monjalon.net>
> > Sent: Wednesday, February 7, 2024 12:40 AM
> >
> > 28/01/2024 10:39, Ori Kam:
> > > During the encapsulation of a packet, it is expected to calculate the
> > > hash value which is based on the original packet (the outer values,
> > > which will become the inner values).
> >
> > It is not clear what the hash is for.
>
> Will add explanation.
>
> >
> > > The tunnel protocol defines which tunnel field should hold this hash,
> > > but it doesn't define the hash calculation algorithm.
> >
> > If the hash is stored in the packet header,
> > I expect it to be reproducible when being checked.
> > How the algorithm may be undefined?
> >
> The hash is not being checked it is used for hash the packets to different queues.
> the actual value is not important. It is critical that all packets that belongs to the same
> flow will have the same hash value.
That's the missing explanation.
Please describe you are talking about an internal hash
used for distributing packet in queues.
You should also explain how it differs from RSS.
> > > An application that uses flow offloads gets the first few packets
> > > and then decides to offload the flow. As a result, there are two
> > > different paths that a packet from a given flow may take.
> > > SW for the first few packets or HW for the rest.
> > > When the packet goes through the SW, the SW encapsulates the packet
> > > and must use the same hash calculation as the HW will do for
> > > the rest of the packets in this flow.
> > >
> > > This patch gives the SW a way to query the hash value
> > > for a given packet as if the packet was passed through the HW.
> > >
> > > Signed-off-by: Ori Kam <orika@nvidia.com>
> > > ---
> > > +Calculate encap hash
> > > +~~~~~~~~~~~~~~~~~~~~
> > > +
> > > +Calculating hash of a packet in SW as it would be calculated in HW for the
> > encap action
> >
> > We should give the real full name of the flow action.
> >
> > > +
> > > +When the HW execute an encapsulation action, it may calculate an hash
> > value which is based
> > > +on the original packet. This hash is stored depending on the encapsulation
> > protocol, in one
> > > +of the outer fields.
> >
> > Give an example of such encapsulation protocol?
>
> Sure,
> Just to be clear something like this?
> When the HW execute an encapsulation action for example for VXLAN tunnel,, it may ...
I was more thinking about saying which fields are hashed in VXLAN,
and more importantly how/when the hash is used.
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 2/4] net/mlx5/hws: introduce encap entropy hash calculation API
2024-01-28 9:39 [PATCH 0/4] introduce encap hash calculation Ori Kam
2024-01-28 9:39 ` [PATCH 1/4] ethdev: " Ori Kam
@ 2024-01-28 9:39 ` Ori Kam
2024-01-28 9:39 ` [PATCH 3/4] net/mlx5: add calc encap hash support Ori Kam
` (5 subsequent siblings)
7 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-01-28 9:39 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Viacheslav Ovsiienko, Suanming Mou, Matan Azrad
Cc: dev, orika, rasland, Hamdan Igbaria
From: Hamdan Igbaria <hamdani@nvidia.com>
Add new function for encap entropy hash calculation, the function
will check the device capability for the entropy hash type used
by the device, and will calculate the entropy hash value of the
user passed fields according this type.
Signed-off-by: Hamdan Igbaria <hamdani@nvidia.com>
---
drivers/common/mlx5/mlx5_prm.h | 8 ++-
drivers/net/mlx5/hws/mlx5dr.h | 38 ++++++++++++++
drivers/net/mlx5/hws/mlx5dr_cmd.c | 23 +++++++++
drivers/net/mlx5/hws/mlx5dr_cmd.h | 4 ++
drivers/net/mlx5/hws/mlx5dr_crc32.c | 78 +++++++++++++++++++++++++++++
drivers/net/mlx5/hws/mlx5dr_crc32.h | 5 ++
6 files changed, 154 insertions(+), 2 deletions(-)
diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h
index 69404b5ed8..82923d5f3f 100644
--- a/drivers/common/mlx5/mlx5_prm.h
+++ b/drivers/common/mlx5/mlx5_prm.h
@@ -2130,7 +2130,10 @@ struct mlx5_ifc_flow_table_prop_layout_bits {
struct mlx5_ifc_roce_caps_bits {
u8 reserved_0[0x1e];
u8 qp_ts_format[0x2];
- u8 reserved_at_20[0x7e0];
+ u8 reserved_at_20[0xa0];
+ u8 r_roce_max_src_udp_port[0x10];
+ u8 r_roce_min_src_udp_port[0x10];
+ u8 reserved_at_e0[0x720];
};
struct mlx5_ifc_ft_fields_support_bits {
@@ -2368,7 +2371,8 @@ struct mlx5_ifc_cmd_hca_cap_2_bits {
u8 format_select_dw_gtpu_first_ext_dw_0[0x8];
u8 generate_wqe_type[0x20];
u8 reserved_at_2c0[0x160];
- u8 reserved_at_420[0x1c];
+ u8 reserved_at_420[0x18];
+ u8 encap_entropy_hash_type[0x4];
u8 flow_table_hash_type[0x4];
u8 reserved_at_440[0x3c0];
};
diff --git a/drivers/net/mlx5/hws/mlx5dr.h b/drivers/net/mlx5/hws/mlx5dr.h
index d88f73ab57..321b649f8c 100644
--- a/drivers/net/mlx5/hws/mlx5dr.h
+++ b/drivers/net/mlx5/hws/mlx5dr.h
@@ -279,6 +279,27 @@ struct mlx5dr_action_dest_attr {
} reformat;
};
+union mlx5dr_crc_encap_entropy_hash_ip_field {
+ uint8_t ipv6_addr[16];
+ struct {
+ uint8_t reserved[12];
+ rte_be32_t ipv4_addr;
+ };
+};
+
+struct mlx5dr_crc_encap_entropy_hash_fields {
+ union mlx5dr_crc_encap_entropy_hash_ip_field dst;
+ union mlx5dr_crc_encap_entropy_hash_ip_field src;
+ uint8_t next_protocol;
+ rte_be16_t dst_port;
+ rte_be16_t src_port;
+}__rte_packed;
+
+enum mlx5dr_crc_encap_entropy_hash_size {
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8,
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16,
+};
+
/* Open a context used for direct rule insertion using hardware steering.
* Each context can contain multiple tables of different types.
*
@@ -845,4 +866,21 @@ int mlx5dr_send_queue_action(struct mlx5dr_context *ctx,
*/
int mlx5dr_debug_dump(struct mlx5dr_context *ctx, FILE *f);
+/* Calculate encap entropy hash value
+ *
+ * @param[in] ctx
+ * The context to get from it's capabilities the entropy hash type.
+ * @param[in] data
+ * The fields for the hash calculation.
+ * @param[in] entropy_res
+ * An array to store the hash value to it.
+ * @param[in] res_size
+ * The result size.
+ * @return zero on success non zero otherwise.
+ */
+int mlx5dr_crc_encap_entropy_hash_calc(struct mlx5dr_context *ctx,
+ struct mlx5dr_crc_encap_entropy_hash_fields *data,
+ uint8_t entropy_res[],
+ enum mlx5dr_crc_encap_entropy_hash_size res_size);
+
#endif
diff --git a/drivers/net/mlx5/hws/mlx5dr_cmd.c b/drivers/net/mlx5/hws/mlx5dr_cmd.c
index 876a47147d..f77b194708 100644
--- a/drivers/net/mlx5/hws/mlx5dr_cmd.c
+++ b/drivers/net/mlx5/hws/mlx5dr_cmd.c
@@ -1103,6 +1103,8 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
caps->ipsec_offload = MLX5_GET(query_hca_cap_out, out,
capability.cmd_hca_cap.ipsec_offload);
+ caps->roce = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.roce);
+
MLX5_SET(query_hca_cap_in, in, op_mod,
MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE_2 |
MLX5_HCA_CAP_OPMOD_GET_CUR);
@@ -1158,6 +1160,9 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
caps->flow_table_hash_type = MLX5_GET(query_hca_cap_out, out,
capability.cmd_hca_cap_2.flow_table_hash_type);
+ caps->encap_entropy_hash_type = MLX5_GET(query_hca_cap_out, out,
+ capability.cmd_hca_cap_2.encap_entropy_hash_type);
+
MLX5_SET(query_hca_cap_in, in, op_mod,
MLX5_GET_HCA_CAP_OP_MOD_NIC_FLOW_TABLE |
MLX5_HCA_CAP_OPMOD_GET_CUR);
@@ -1306,6 +1311,24 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
capability.esw_cap.merged_eswitch);
}
+ if (caps->roce) {
+ MLX5_SET(query_hca_cap_in, in, op_mod,
+ MLX5_GET_HCA_CAP_OP_MOD_ROCE |
+ MLX5_HCA_CAP_OPMOD_GET_CUR);
+
+ ret = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in), out, sizeof(out));
+ if (ret) {
+ DR_LOG(ERR, "Failed to query roce caps");
+ rte_errno = errno;
+ return rte_errno;
+ }
+
+ caps->roce_max_src_udp_port = MLX5_GET(query_hca_cap_out, out,
+ capability.roce_caps.r_roce_max_src_udp_port);
+ caps->roce_min_src_udp_port = MLX5_GET(query_hca_cap_out, out,
+ capability.roce_caps.r_roce_min_src_udp_port);
+ }
+
ret = mlx5_glue->query_device_ex(ctx, NULL, &attr_ex);
if (ret) {
DR_LOG(ERR, "Failed to query device attributes");
diff --git a/drivers/net/mlx5/hws/mlx5dr_cmd.h b/drivers/net/mlx5/hws/mlx5dr_cmd.h
index 18c2b07fc8..694231e08f 100644
--- a/drivers/net/mlx5/hws/mlx5dr_cmd.h
+++ b/drivers/net/mlx5/hws/mlx5dr_cmd.h
@@ -246,6 +246,10 @@ struct mlx5dr_cmd_query_caps {
uint32_t shared_vhca_id;
char fw_ver[64];
bool ipsec_offload;
+ uint8_t encap_entropy_hash_type;
+ bool roce;
+ uint16_t roce_max_src_udp_port;
+ uint16_t roce_min_src_udp_port;
};
int mlx5dr_cmd_destroy_obj(struct mlx5dr_devx_obj *devx_obj);
diff --git a/drivers/net/mlx5/hws/mlx5dr_crc32.c b/drivers/net/mlx5/hws/mlx5dr_crc32.c
index 9c454eda0c..7431462e14 100644
--- a/drivers/net/mlx5/hws/mlx5dr_crc32.c
+++ b/drivers/net/mlx5/hws/mlx5dr_crc32.c
@@ -50,6 +50,42 @@ uint32_t dr_ste_crc_tab32[] = {
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
+/* CRC table for the CRC-16, the polynome is 0x100b */
+uint16_t dr_crc_inner_crc_tab16[] = {
+ 0x0000, 0x100B, 0x2016, 0x301D, 0x402C, 0x5027, 0x603A, 0x7031,
+ 0x8058, 0x9053, 0xA04E, 0xB045, 0xC074, 0xD07F, 0xE062, 0xF069,
+ 0x10BB, 0x00B0, 0x30AD, 0x20A6, 0x5097, 0x409C, 0x7081, 0x608A,
+ 0x90E3, 0x80E8, 0xB0F5, 0xA0FE, 0xD0CF, 0xC0C4, 0xF0D9, 0xE0D2,
+ 0x2176, 0x317D, 0x0160, 0x116B, 0x615A, 0x7151, 0x414C, 0x5147,
+ 0xA12E, 0xB125, 0x8138, 0x9133, 0xE102, 0xF109, 0xC114, 0xD11F,
+ 0x31CD, 0x21C6, 0x11DB, 0x01D0, 0x71E1, 0x61EA, 0x51F7, 0x41FC,
+ 0xB195, 0xA19E, 0x9183, 0x8188, 0xF1B9, 0xE1B2, 0xD1AF, 0xC1A4,
+ 0x42EC, 0x52E7, 0x62FA, 0x72F1, 0x02C0, 0x12CB, 0x22D6, 0x32DD,
+ 0xC2B4, 0xD2BF, 0xE2A2, 0xF2A9, 0x8298, 0x9293, 0xA28E, 0xB285,
+ 0x5257, 0x425C, 0x7241, 0x624A, 0x127B, 0x0270, 0x326D, 0x2266,
+ 0xD20F, 0xC204, 0xF219, 0xE212, 0x9223, 0x8228, 0xB235, 0xA23E,
+ 0x639A, 0x7391, 0x438C, 0x5387, 0x23B6, 0x33BD, 0x03A0, 0x13AB,
+ 0xE3C2, 0xF3C9, 0xC3D4, 0xD3DF, 0xA3EE, 0xB3E5, 0x83F8, 0x93F3,
+ 0x7321, 0x632A, 0x5337, 0x433C, 0x330D, 0x2306, 0x131B, 0x0310,
+ 0xF379, 0xE372, 0xD36F, 0xC364, 0xB355, 0xA35E, 0x9343, 0x8348,
+ 0x85D8, 0x95D3, 0xA5CE, 0xB5C5, 0xC5F4, 0xD5FF, 0xE5E2, 0xF5E9,
+ 0x0580, 0x158B, 0x2596, 0x359D, 0x45AC, 0x55A7, 0x65BA, 0x75B1,
+ 0x9563, 0x8568, 0xB575, 0xA57E, 0xD54F, 0xC544, 0xF559, 0xE552,
+ 0x153B, 0x0530, 0x352D, 0x2526, 0x5517, 0x451C, 0x7501, 0x650A,
+ 0xA4AE, 0xB4A5, 0x84B8, 0x94B3, 0xE482, 0xF489, 0xC494, 0xD49F,
+ 0x24F6, 0x34FD, 0x04E0, 0x14EB, 0x64DA, 0x74D1, 0x44CC, 0x54C7,
+ 0xB415, 0xA41E, 0x9403, 0x8408, 0xF439, 0xE432, 0xD42F, 0xC424,
+ 0x344D, 0x2446, 0x145B, 0x0450, 0x7461, 0x646A, 0x5477, 0x447C,
+ 0xC734, 0xD73F, 0xE722, 0xF729, 0x8718, 0x9713, 0xA70E, 0xB705,
+ 0x476C, 0x5767, 0x677A, 0x7771, 0x0740, 0x174B, 0x2756, 0x375D,
+ 0xD78F, 0xC784, 0xF799, 0xE792, 0x97A3, 0x87A8, 0xB7B5, 0xA7BE,
+ 0x57D7, 0x47DC, 0x77C1, 0x67CA, 0x17FB, 0x07F0, 0x37ED, 0x27E6,
+ 0xE642, 0xF649, 0xC654, 0xD65F, 0xA66E, 0xB665, 0x8678, 0x9673,
+ 0x661A, 0x7611, 0x460C, 0x5607, 0x2636, 0x363D, 0x0620, 0x162B,
+ 0xF6F9, 0xE6F2, 0xD6EF, 0xC6E4, 0xB6D5, 0xA6DE, 0x96C3, 0x86C8,
+ 0x76A1, 0x66AA, 0x56B7, 0x46BC, 0x368D, 0x2686, 0x169B, 0x0690
+};
+
uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len)
{
uint32_t crc = 0;
@@ -59,3 +95,45 @@ uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len)
return rte_be_to_cpu_32(crc);
}
+
+uint16_t mlx5dr_crc16_calc(uint8_t *p, size_t len, uint16_t crc_tab16[])
+{
+ uint16_t crc = 0;
+
+ while (len--)
+ crc = (crc << 8) ^ crc_tab16[((crc >> 8) ^ *p++) & 0xff];
+
+ return crc;
+}
+
+int mlx5dr_crc_encap_entropy_hash_calc(struct mlx5dr_context *ctx,
+ struct mlx5dr_crc_encap_entropy_hash_fields *data,
+ uint8_t entropy_res[],
+ enum mlx5dr_crc_encap_entropy_hash_size res_size)
+{
+ struct mlx5dr_cmd_query_caps *caps = ctx->caps;
+ uint16_t max_hash, min_hash, res;
+
+ if (caps->encap_entropy_hash_type) {
+ DR_LOG(ERR, "calculation of encap_entropy_hash_type 0x%x not supported",
+ caps->encap_entropy_hash_type);
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ max_hash = caps->roce_max_src_udp_port;
+ min_hash = caps->roce_min_src_udp_port;
+
+ res = mlx5dr_crc16_calc((uint8_t *)data, sizeof(*data), dr_crc_inner_crc_tab16);
+
+ if (res_size == MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16) {
+ *(uint16_t *)entropy_res = rte_cpu_to_be_16((min_hash | res) & max_hash);
+ } else if (res_size == MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8) {
+ *entropy_res = (uint8_t)(res & 0xff);
+ } else {
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/mlx5/hws/mlx5dr_crc32.h b/drivers/net/mlx5/hws/mlx5dr_crc32.h
index 9aab9e06ca..75b6009a15 100644
--- a/drivers/net/mlx5/hws/mlx5dr_crc32.h
+++ b/drivers/net/mlx5/hws/mlx5dr_crc32.h
@@ -10,4 +10,9 @@
*/
uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len);
+/* Standard CRC16 calculation using the crc_tab16 param to indicate
+ * the pre-calculated polynome hash values.
+ */
+uint16_t mlx5dr_crc16_calc(uint8_t *p, size_t len, uint16_t crc_tab16[]);
+
#endif /* MLX5DR_CRC32_C_ */
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 3/4] net/mlx5: add calc encap hash support
2024-01-28 9:39 [PATCH 0/4] introduce encap hash calculation Ori Kam
2024-01-28 9:39 ` [PATCH 1/4] ethdev: " Ori Kam
2024-01-28 9:39 ` [PATCH 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
@ 2024-01-28 9:39 ` Ori Kam
2024-01-28 9:39 ` [PATCH 4/4] app/testpmd: add encap hash calculation Ori Kam
` (4 subsequent siblings)
7 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-01-28 9:39 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Viacheslav Ovsiienko, Suanming Mou, Matan Azrad
Cc: dev, orika, rasland
This commit adds support for encap hash calculation.
Signed-off-by: Ori Kam <orika@nvidia.com>
---
drivers/net/mlx5/mlx5_flow.c | 29 +++++++++++++++
drivers/net/mlx5/mlx5_flow.h | 8 ++++
drivers/net/mlx5/mlx5_flow_hw.c | 66 +++++++++++++++++++++++++++++++++
3 files changed, 103 insertions(+)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index acaf34ce52..d1a7ad9234 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1197,6 +1197,12 @@ mlx5_flow_calc_table_hash(struct rte_eth_dev *dev,
const struct rte_flow_item pattern[],
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+static int
+mlx5_flow_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error);
static const struct rte_flow_ops mlx5_flow_ops = {
.validate = mlx5_flow_validate,
@@ -1253,6 +1259,7 @@ static const struct rte_flow_ops mlx5_flow_ops = {
.async_action_list_handle_query_update =
mlx5_flow_async_action_list_handle_query_update,
.flow_calc_table_hash = mlx5_flow_calc_table_hash,
+ .flow_calc_encap_hash = mlx5_flow_calc_encap_hash,
};
/* Tunnel information. */
@@ -11121,6 +11128,28 @@ mlx5_flow_calc_table_hash(struct rte_eth_dev *dev,
hash, error);
}
+static int
+mlx5_flow_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error)
+{
+ enum mlx5_flow_drv_type drv_type = flow_get_drv_type(dev, NULL);
+ const struct mlx5_flow_driver_ops *fops;
+
+ if (drv_type == MLX5_FLOW_TYPE_MIN || drv_type == MLX5_FLOW_TYPE_MAX)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "invalid driver type");
+ fops = flow_get_drv_ops(drv_type);
+ if (!fops || !fops->flow_calc_encap_hash)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "no calc encap hash handler");
+ return fops->flow_calc_encap_hash(dev, pattern, dest_field, hash, error);
+}
+
/**
* Destroy all indirect actions (shared RSS).
*
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index fe4f46724b..a04dde9e93 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -2109,6 +2109,13 @@ typedef int
const struct rte_flow_item pattern[],
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+typedef int
+(*mlx5_flow_calc_encap_hash_t)
+ (struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error);
struct mlx5_flow_driver_ops {
mlx5_flow_validate_t validate;
@@ -2182,6 +2189,7 @@ struct mlx5_flow_driver_ops {
mlx5_flow_async_action_list_handle_query_update_t
async_action_list_handle_query_update;
mlx5_flow_calc_table_hash_t flow_calc_table_hash;
+ mlx5_flow_calc_encap_hash_t flow_calc_encap_hash;
};
/* mlx5_flow.c */
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index 48b70c0c29..0e4e7bd3f5 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -11556,6 +11556,71 @@ flow_hw_calc_table_hash(struct rte_eth_dev *dev,
return 0;
}
+static int
+flow_hw_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5dr_crc_encap_entropy_hash_fields data;
+ enum mlx5dr_crc_encap_entropy_hash_size res_size =
+ dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT ?
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16 :
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8;
+ int res;
+
+ memset(&data, 0, sizeof(struct mlx5dr_crc_encap_entropy_hash_fields));
+
+ for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+ switch (pattern->type) {
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ data.dst.ipv4_addr =
+ ((const struct rte_flow_item_ipv4 *)(pattern->spec))->hdr.dst_addr;
+ data.src.ipv4_addr =
+ ((const struct rte_flow_item_ipv4 *)(pattern->spec))->hdr.src_addr;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ memcpy(data.dst.ipv6_addr,
+ ((const struct rte_flow_item_ipv6 *)(pattern->spec))->hdr.dst_addr,
+ sizeof(data.dst.ipv6_addr));
+ memcpy(data.src.ipv6_addr,
+ ((const struct rte_flow_item_ipv6 *)(pattern->spec))->hdr.src_addr,
+ sizeof(data.src.ipv6_addr));
+ break;
+ case RTE_FLOW_ITEM_TYPE_UDP:
+ data.next_protocol = IPPROTO_UDP;
+ data.dst_port =
+ ((const struct rte_flow_item_udp *)(pattern->spec))->hdr.dst_port;
+ data.src_port =
+ ((const struct rte_flow_item_udp *)(pattern->spec))->hdr.src_port;
+ break;
+ case RTE_FLOW_ITEM_TYPE_TCP:
+ data.next_protocol = IPPROTO_TCP;
+ data.dst_port =
+ ((const struct rte_flow_item_tcp *)(pattern->spec))->hdr.dst_port;
+ data.src_port =
+ ((const struct rte_flow_item_tcp *)(pattern->spec))->hdr.src_port;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ICMP:
+ data.next_protocol = IPPROTO_ICMP;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ICMP6:
+ data.next_protocol = IPPROTO_ICMPV6;
+ break;
+ default:
+ break;
+ }
+ }
+ res = mlx5dr_crc_encap_entropy_hash_calc(priv->dr_ctx, &data, hash, res_size);
+ if (res)
+ return rte_flow_error_set(error, res,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "error while calculating encap hash");
+ return 0;
+}
+
const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
.info_get = flow_hw_info_get,
.configure = flow_hw_configure,
@@ -11601,6 +11666,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
.item_create = flow_dv_item_create,
.item_release = flow_dv_item_release,
.flow_calc_table_hash = flow_hw_calc_table_hash,
+ .flow_calc_encap_hash = flow_hw_calc_encap_hash,
};
/**
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH 4/4] app/testpmd: add encap hash calculation
2024-01-28 9:39 [PATCH 0/4] introduce encap hash calculation Ori Kam
` (2 preceding siblings ...)
2024-01-28 9:39 ` [PATCH 3/4] net/mlx5: add calc encap hash support Ori Kam
@ 2024-01-28 9:39 ` Ori Kam
2024-01-31 18:30 ` [PATCH 0/4] introduce " Dariusz Sosnowski
` (3 subsequent siblings)
7 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-01-28 9:39 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Aman Singh, Yuying Zhang
Cc: dev, orika, rasland
This commits add support for calculating the encap hash.
Command structure:
flow hash {port} encap {target field} pattern {item} [/ {item} [...] ] / end
Example:
calculate hash to be used by VXLAN encapsulation.
flow hash 0 encap hash_field_sport pattern ipv4 dst is 7.7.7.7 src is 8.8.8.8 / udp dst is 5678 src is 1234 / end
Signed-off-by: Ori Kam <orika@nvidia.com>
---
app/test-pmd/cmdline_flow.c | 57 +++++++++++++++++++--
app/test-pmd/config.c | 30 +++++++++++
app/test-pmd/testpmd.h | 3 ++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 21 +++++++-
4 files changed, 106 insertions(+), 5 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 4062879552..a42f07276d 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -219,6 +219,10 @@ enum index {
HASH_CALC_TABLE,
HASH_CALC_PATTERN_INDEX,
HASH_CALC_PATTERN,
+ HASH_CALC_ENCAP,
+ HASH_CALC_DEST,
+ ENCAP_HASH_FIELD_SRC_PORT,
+ ENCAP_HASH_FIELD_GRE_FLOW_ID,
/* Tunnel arguments. */
TUNNEL_CREATE,
@@ -1192,6 +1196,8 @@ struct buffer {
uint32_t pattern_n;
uint32_t actions_n;
uint8_t *data;
+ enum rte_flow_encap_hash_field field;
+ uint8_t encap_hash;
} vc; /**< Validate/create arguments. */
struct {
uint64_t *rule;
@@ -2550,6 +2556,18 @@ static const enum index action_represented_port[] = {
ZERO,
};
+static const enum index next_hash_subcmd[] = {
+ HASH_CALC_TABLE,
+ HASH_CALC_ENCAP,
+ ZERO,
+};
+
+static const enum index next_hash_encap_dest_subcmd[] = {
+ ENCAP_HASH_FIELD_SRC_PORT,
+ ENCAP_HASH_FIELD_GRE_FLOW_ID,
+ ZERO,
+};
+
static int parse_set_raw_encap_decap(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
@@ -3789,7 +3807,7 @@ static const struct token token_list[] = {
[HASH] = {
.name = "hash",
.help = "calculate hash for a given pattern in a given template table",
- .next = NEXT(NEXT_ENTRY(HASH_CALC_TABLE), NEXT_ENTRY(COMMON_PORT_ID)),
+ .next = NEXT(next_hash_subcmd, NEXT_ENTRY(COMMON_PORT_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_hash,
},
@@ -3803,6 +3821,12 @@ static const struct token token_list[] = {
args.vc.table_id)),
.call = parse_hash,
},
+ [HASH_CALC_ENCAP] = {
+ .name = "encap",
+ .help = "calculates encap hash",
+ .next = NEXT(next_hash_encap_dest_subcmd),
+ .call = parse_hash,
+ },
[HASH_CALC_PATTERN_INDEX] = {
.name = "pattern_template",
.help = "specify pattern template id",
@@ -3812,6 +3836,18 @@ static const struct token token_list[] = {
args.vc.pat_templ_id)),
.call = parse_hash,
},
+ [ENCAP_HASH_FIELD_SRC_PORT] = {
+ .name = "hash_field_sport",
+ .help = "the encap hash field is src port",
+ .next = NEXT(NEXT_ENTRY(ITEM_PATTERN)),
+ .call = parse_hash,
+ },
+ [ENCAP_HASH_FIELD_GRE_FLOW_ID] = {
+ .name = "hash_field_flow_id",
+ .help = "the encap hash field is NVGRE flow id",
+ .next = NEXT(NEXT_ENTRY(ITEM_PATTERN)),
+ .call = parse_hash,
+ },
/* Top-level command. */
[INDIRECT_ACTION] = {
.name = "indirect_action",
@@ -10691,6 +10727,15 @@ parse_hash(struct context *ctx, const struct token *token,
ctx->object = out->args.vc.pattern;
ctx->objmask = NULL;
return len;
+ case HASH_CALC_ENCAP:
+ out->args.vc.encap_hash = 1;
+ return len;
+ case ENCAP_HASH_FIELD_SRC_PORT:
+ out->args.vc.field = RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT;
+ return len;
+ case ENCAP_HASH_FIELD_GRE_FLOW_ID:
+ out->args.vc.field = RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID;
+ return len;
default:
return -1;
}
@@ -12651,9 +12696,13 @@ cmd_flow_parsed(const struct buffer *in)
port_queue_flow_pull(in->port, in->queue);
break;
case HASH:
- port_flow_hash_calc(in->port, in->args.vc.table_id,
- in->args.vc.pat_templ_id,
- in->args.vc.pattern);
+ if (!in->args.vc.encap_hash)
+ port_flow_hash_calc(in->port, in->args.vc.table_id,
+ in->args.vc.pat_templ_id,
+ in->args.vc.pattern);
+ else
+ port_flow_hash_calc_encap(in->port, in->args.vc.field,
+ in->args.vc.pattern);
break;
case QUEUE_AGED:
port_queue_flow_aged(in->port, in->queue,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index cad7537bc6..e26b5bd18d 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -3339,6 +3339,36 @@ port_flow_hash_calc(portid_t port_id, uint32_t table_id,
return 0;
}
+/** Calculate the encap hash result for a given pattern. */
+int
+port_flow_hash_calc_encap(portid_t port_id,
+ enum rte_flow_encap_hash_field encap_hash_field,
+ const struct rte_flow_item pattern[])
+{
+ struct rte_flow_error error;
+ int ret = 0;
+ uint16_t hash = 0;
+ uint8_t len = encap_hash_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT ? 2 : 1;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL) {
+ printf("Failed to calculate encap hash - not a valid port");
+ return -EINVAL;
+ }
+
+ ret = rte_flow_calc_encap_hash(port_id, pattern, encap_hash_field, len,
+ (uint8_t *)&hash, &error);
+ if (ret < 0) {
+ printf("Failed to calculate encap hash");
+ return ret;
+ }
+ if (encap_hash_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT)
+ printf("encap hash result %#x\n", hash);
+ else
+ printf("encap hash result %#x\n", *(uint8_t *)&hash);
+ return 0;
+}
+
/** Pull queue operation results from the queue. */
static int
port_queue_aged_flow_destroy(portid_t port_id, queueid_t queue_id,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 9b10a9ea1c..e18546c46e 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -1016,6 +1016,9 @@ int port_queue_flow_push(portid_t port_id, queueid_t queue_id);
int port_queue_flow_pull(portid_t port_id, queueid_t queue_id);
int port_flow_hash_calc(portid_t port_id, uint32_t table_id,
uint8_t pattern_template_index, const struct rte_flow_item pattern[]);
+int port_flow_hash_calc_encap(portid_t port_id,
+ enum rte_flow_encap_hash_field encap_hash_field,
+ const struct rte_flow_item pattern[]);
void port_queue_flow_aged(portid_t port_id, uint32_t queue_id, uint8_t destroy);
int port_flow_validate(portid_t port_id,
const struct rte_flow_attr *attr,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 38ab421547..37a508c967 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -3297,7 +3297,7 @@ The usual error message is shown when operations results cannot be pulled::
Calculating hash
~~~~~~~~~~~~~~~~
-``flow hash`` calculates the hash for a given pattern.
+``flow hash {port_id} template_table`` calculates the hash for a given pattern.
It is bound to ``rte_flow_calc_table_hash()``::
flow hash {port_id} template_table {table_id}
@@ -3316,6 +3316,25 @@ Otherwise, it will show an error message of the form::
This command uses the same pattern items as ``flow create``,
their format is described in `Creating flow rules`_.
+
+Simulate encap hash calculation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``flow hash {port_id} encap`` adds hash query, that returns the hash value
+that the HW will calculate when encapsulating a packet.
+
+ flow hash {port_id} encap {target field} pattern {item} [/ {item} [...]] / end
+
+If successful, it will show::
+
+ encap hash result #[...]
+
+The value will be shown as uint16_t without endian conversion.
+
+Otherwise it will show an error message of the form::
+
+ Failed to calculate encap hash - [...]
+
Creating a tunnel stub for offload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: [PATCH 0/4] introduce encap hash calculation
2024-01-28 9:39 [PATCH 0/4] introduce encap hash calculation Ori Kam
` (3 preceding siblings ...)
2024-01-28 9:39 ` [PATCH 4/4] app/testpmd: add encap hash calculation Ori Kam
@ 2024-01-31 18:30 ` Dariusz Sosnowski
2024-02-08 9:09 ` [PATCH v2 1/4] ethdev: " Ori Kam
` (2 subsequent siblings)
7 siblings, 0 replies; 31+ messages in thread
From: Dariusz Sosnowski @ 2024-01-31 18:30 UTC (permalink / raw)
To: Ori Kam, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko, stephen
Cc: dev, Raslan Darawsheh
> -----Original Message-----
> From: Ori Kam <orika@nvidia.com>
> Sent: Sunday, January 28, 2024 10:40
> To: Dariusz Sosnowski <dsosnowski@nvidia.com>; ferruh.yigit@amd.com;
> cristian.dumitrescu@intel.com; andrew.rybchenko@oktetlabs.ru;
> stephen@networkplumber.org
> Cc: dev@dpdk.org; Ori Kam <orika@nvidia.com>; Raslan Darawsheh
> <rasland@nvidia.com>
> Subject: [PATCH 0/4] introduce encap hash calculation
>
> This patch set adds the support for encap hash calculation.
>
> It is based on RFC:
> https://patchwork.dpdk.org/project/dpdk/patch/20231210083100.7893-
> 1-orika@nvidia.com/
>
> Hamdan Igbaria (1):
> net/mlx5/hws: introduce encap entropy hash calculation API
>
> Ori Kam (3):
> ethdev: introduce encap hash calculation
> net/mlx5: add calc encap hash support
> app/testpmd: add encap hash calculation
>
> app/test-pmd/cmdline_flow.c | 57 +++++++++++++--
> app/test-pmd/config.c | 30 ++++++++
> app/test-pmd/testpmd.h | 3 +
> doc/guides/prog_guide/rte_flow.rst | 22 ++++++
> doc/guides/rel_notes/release_24_03.rst | 4 ++
> doc/guides/testpmd_app_ug/testpmd_funcs.rst | 21 +++++-
> drivers/common/mlx5/mlx5_prm.h | 8 ++-
> drivers/net/mlx5/hws/mlx5dr.h | 38 ++++++++++
> drivers/net/mlx5/hws/mlx5dr_cmd.c | 23 ++++++
> drivers/net/mlx5/hws/mlx5dr_cmd.h | 4 ++
> drivers/net/mlx5/hws/mlx5dr_crc32.c | 78 +++++++++++++++++++++
> drivers/net/mlx5/hws/mlx5dr_crc32.h | 5 ++
> drivers/net/mlx5/mlx5_flow.c | 29 ++++++++
> drivers/net/mlx5/mlx5_flow.h | 8 +++
> drivers/net/mlx5/mlx5_flow_hw.c | 66 +++++++++++++++++
> lib/ethdev/rte_flow.c | 25 +++++++
> lib/ethdev/rte_flow.h | 50 +++++++++++++
> lib/ethdev/rte_flow_driver.h | 5 ++
> lib/ethdev/version.map | 1 +
> 19 files changed, 470 insertions(+), 7 deletions(-)
>
> --
> 2.34.1
Series-Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
Best regards,
Dariusz Sosnowski
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 1/4] ethdev: introduce encap hash calculation
2024-01-28 9:39 [PATCH 0/4] introduce encap hash calculation Ori Kam
` (4 preceding siblings ...)
2024-01-31 18:30 ` [PATCH 0/4] introduce " Dariusz Sosnowski
@ 2024-02-08 9:09 ` Ori Kam
2024-02-08 9:09 ` [PATCH v2 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
` (3 more replies)
2024-02-13 13:48 ` [PATCH v3 " Ori Kam
2024-02-13 14:16 ` [PATCH v4 1/4] ethdev: introduce " Ori Kam
7 siblings, 4 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-08 9:09 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Thomas Monjalon
Cc: dev, orika, rasland
During encapsulation of a packet, it is possible to change some
outer headers to improve flow destribution.
For example, from VXLAN RFC:
"It is recommended that the UDP source port number
be calculated using a hash of fields from the inner packet --
one example being a hash of the inner Ethernet frame's headers.
This is to enable a level of entropy for the ECMP/load-balancing"
The tunnel protocol defines which outer field should hold this hash,
but it doesn't define the hash calculation algorithm.
An application that uses flow offloads gets the first few packets
(exception path) and then decides to offload the flow.
As a result, there are two
different paths that a packet from a given flow may take.
SW for the first few packets or HW for the rest.
When the packet goes through the SW, the SW encapsulates the packet
and must use the same hash calculation as the HW will do for
the rest of the packets in this flow.
the new function rte_flow_calc_encap_hash can query the hash value
fromm the driver for a given packet as if the packet was passed
through the HW.
Signed-off-by: Ori Kam <orika@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
doc/guides/prog_guide/rte_flow.rst | 14 +++++++
doc/guides/rel_notes/release_24_03.rst | 6 ++-
lib/ethdev/rte_flow.c | 25 +++++++++++++
lib/ethdev/rte_flow.h | 51 ++++++++++++++++++++++++++
lib/ethdev/rte_flow_driver.h | 5 +++
lib/ethdev/version.map | 1 +
6 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 900fdaefb6..d3491a3ac5 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -4211,6 +4211,20 @@ as it would be calculated in the HW.
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+Calculate encapsulation hash
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Calculating hash of a packet as it would be calculated by the HW, when encapsulating
+a packet.
+
+When the HW execute an encapsulation action, for example VXLAN tunnel,
+it may calculate an hash of the packet to be encapsulated.
+This hash is stored in the outer header of the tunnel.
+This allow better spreading of traffic.
+
+This function can be used for packets of a flow that are not offloaded and
+pass through the SW instead of the HW, for example, SYN/FIN packets.
+
.. _flow_isolated_mode:
Flow isolated mode
diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst
index 2b91217943..9508dda362 100644
--- a/doc/guides/rel_notes/release_24_03.rst
+++ b/doc/guides/rel_notes/release_24_03.rst
@@ -60,6 +60,11 @@ New Features
* Added new function ``rte_eth_find_rss_algo`` to get RSS hash
algorithm by its name.
+* **Added hash calculation of an encapsulated packet as done by the HW.**
+
+ Added function to calculate hash when doing tunnel encapsulation:
+ ``rte_flow_calc_encap_hash()``
+
* **Added flow matching of random value.**
* Added ``RTE_FLOW_ITEM_TYPE_RANDOM`` to match random value.
@@ -91,7 +96,6 @@ New Features
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_OPT_CLASS`` flow action.
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_OPT_DATA`` flow action.
-
Removed Items
-------------
diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
index 3f58d792f9..7fce754be1 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -2482,3 +2482,28 @@ rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
hash, error);
return flow_err(port_id, ret, error);
}
+
+int
+rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
+ uint8_t *hash, struct rte_flow_error *error)
+{
+ int ret;
+ struct rte_eth_dev *dev;
+ const struct rte_flow_ops *ops;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ ops = rte_flow_ops_get(port_id, error);
+ if (!ops || !ops->flow_calc_encap_hash)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "calc encap hash is not supported");
+ if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT && hash_len != 2) ||
+ (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID && hash_len != 1))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "hash len doesn't match the requested field len");
+ dev = &rte_eth_devices[port_id];
+ ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash, error);
+ return flow_err(port_id, ret, error);
+}
diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
index 1267c146e5..2bdf3a4a17 100644
--- a/lib/ethdev/rte_flow.h
+++ b/lib/ethdev/rte_flow.h
@@ -6783,6 +6783,57 @@ rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
const struct rte_flow_item pattern[], uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Destination field type for the hash calculation, when encap action is used.
+ *
+ * @see function rte_flow_calc_encap_hash
+ */
+enum rte_flow_encap_hash_field {
+ /* Calculate hash placed in UDP source port field. */
+ RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
+ /* Calculate hash placed in NVGRE flow ID field. */
+ RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Simulate HW hash calculation that is done when an encap action is being used.
+ * This hash can be stored in tunnel outer header to improve packet distribution.
+ *
+ * @param[in] port_id
+ * Port identifier of Ethernet device.
+ * @param[in] pattern
+ * The values to be used in the hash calculation.
+ * @param[in] dest_field
+ * Type of destination field for hash calculation.
+ * @param[in] hash_len
+ * The length of the hash pointer in bytes. Should be according to encap_hash_field.
+ * @param[out] hash
+ * Used to return the calculated hash. It will be written in network order,
+ * so hash[0] is the MSB.
+ * The number of bytes is based on the destination field type.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ * PMDs initialize this structure in case of error only.
+ *
+ * @return
+ * - (0) if success.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-ENOTSUP) if underlying device does not support this functionality.
+ * - (-EINVAL) if *pattern* doesn't hold enough information to calculate the hash
+ * or the dest is not supported.
+ */
+__rte_experimental
+int
+rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
+ uint8_t *hash, struct rte_flow_error *error);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/ethdev/rte_flow_driver.h b/lib/ethdev/rte_flow_driver.h
index f35f659503..447163655a 100644
--- a/lib/ethdev/rte_flow_driver.h
+++ b/lib/ethdev/rte_flow_driver.h
@@ -370,6 +370,11 @@ struct rte_flow_ops {
(struct rte_eth_dev *dev, const struct rte_flow_template_table *table,
const struct rte_flow_item pattern[], uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+ /** @see rte_flow_calc_encap_hash() */
+ int (*flow_calc_encap_hash)
+ (struct rte_eth_dev *dev, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t *hash,
+ struct rte_flow_error *error);
};
/**
diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
index a050baab0f..360898d067 100644
--- a/lib/ethdev/version.map
+++ b/lib/ethdev/version.map
@@ -319,6 +319,7 @@ EXPERIMENTAL {
# added in 24.03
rte_eth_find_rss_algo;
+ rte_flow_calc_encap_hash;
};
INTERNAL {
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 2/4] net/mlx5/hws: introduce encap entropy hash calculation API
2024-02-08 9:09 ` [PATCH v2 1/4] ethdev: " Ori Kam
@ 2024-02-08 9:09 ` Ori Kam
2024-02-08 9:09 ` [PATCH v2 3/4] net/mlx5: add calc encap hash support Ori Kam
` (2 subsequent siblings)
3 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-08 9:09 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Viacheslav Ovsiienko, Suanming Mou, Matan Azrad
Cc: dev, orika, rasland, Hamdan Igbaria
From: Hamdan Igbaria <hamdani@nvidia.com>
Add new function for encap entropy hash calculation, the function
will check the device capability for the entropy hash type used
by the device, and will calculate the entropy hash value of the
user passed fields according this type.
Signed-off-by: Hamdan Igbaria <hamdani@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
drivers/common/mlx5/mlx5_prm.h | 8 ++-
drivers/net/mlx5/hws/mlx5dr.h | 38 ++++++++++++++
drivers/net/mlx5/hws/mlx5dr_cmd.c | 23 +++++++++
drivers/net/mlx5/hws/mlx5dr_cmd.h | 4 ++
drivers/net/mlx5/hws/mlx5dr_crc32.c | 78 +++++++++++++++++++++++++++++
drivers/net/mlx5/hws/mlx5dr_crc32.h | 5 ++
6 files changed, 154 insertions(+), 2 deletions(-)
diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h
index f64f25dbb7..ea765c1ea7 100644
--- a/drivers/common/mlx5/mlx5_prm.h
+++ b/drivers/common/mlx5/mlx5_prm.h
@@ -2132,7 +2132,10 @@ struct mlx5_ifc_flow_table_prop_layout_bits {
struct mlx5_ifc_roce_caps_bits {
u8 reserved_0[0x1e];
u8 qp_ts_format[0x2];
- u8 reserved_at_20[0x7e0];
+ u8 reserved_at_20[0xa0];
+ u8 r_roce_max_src_udp_port[0x10];
+ u8 r_roce_min_src_udp_port[0x10];
+ u8 reserved_at_e0[0x720];
};
struct mlx5_ifc_ft_fields_support_bits {
@@ -2370,7 +2373,8 @@ struct mlx5_ifc_cmd_hca_cap_2_bits {
u8 format_select_dw_gtpu_first_ext_dw_0[0x8];
u8 generate_wqe_type[0x20];
u8 reserved_at_2c0[0x160];
- u8 reserved_at_420[0x1c];
+ u8 reserved_at_420[0x18];
+ u8 encap_entropy_hash_type[0x4];
u8 flow_table_hash_type[0x4];
u8 reserved_at_440[0x3c0];
};
diff --git a/drivers/net/mlx5/hws/mlx5dr.h b/drivers/net/mlx5/hws/mlx5dr.h
index d88f73ab57..321b649f8c 100644
--- a/drivers/net/mlx5/hws/mlx5dr.h
+++ b/drivers/net/mlx5/hws/mlx5dr.h
@@ -279,6 +279,27 @@ struct mlx5dr_action_dest_attr {
} reformat;
};
+union mlx5dr_crc_encap_entropy_hash_ip_field {
+ uint8_t ipv6_addr[16];
+ struct {
+ uint8_t reserved[12];
+ rte_be32_t ipv4_addr;
+ };
+};
+
+struct mlx5dr_crc_encap_entropy_hash_fields {
+ union mlx5dr_crc_encap_entropy_hash_ip_field dst;
+ union mlx5dr_crc_encap_entropy_hash_ip_field src;
+ uint8_t next_protocol;
+ rte_be16_t dst_port;
+ rte_be16_t src_port;
+}__rte_packed;
+
+enum mlx5dr_crc_encap_entropy_hash_size {
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8,
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16,
+};
+
/* Open a context used for direct rule insertion using hardware steering.
* Each context can contain multiple tables of different types.
*
@@ -845,4 +866,21 @@ int mlx5dr_send_queue_action(struct mlx5dr_context *ctx,
*/
int mlx5dr_debug_dump(struct mlx5dr_context *ctx, FILE *f);
+/* Calculate encap entropy hash value
+ *
+ * @param[in] ctx
+ * The context to get from it's capabilities the entropy hash type.
+ * @param[in] data
+ * The fields for the hash calculation.
+ * @param[in] entropy_res
+ * An array to store the hash value to it.
+ * @param[in] res_size
+ * The result size.
+ * @return zero on success non zero otherwise.
+ */
+int mlx5dr_crc_encap_entropy_hash_calc(struct mlx5dr_context *ctx,
+ struct mlx5dr_crc_encap_entropy_hash_fields *data,
+ uint8_t entropy_res[],
+ enum mlx5dr_crc_encap_entropy_hash_size res_size);
+
#endif
diff --git a/drivers/net/mlx5/hws/mlx5dr_cmd.c b/drivers/net/mlx5/hws/mlx5dr_cmd.c
index 876a47147d..f77b194708 100644
--- a/drivers/net/mlx5/hws/mlx5dr_cmd.c
+++ b/drivers/net/mlx5/hws/mlx5dr_cmd.c
@@ -1103,6 +1103,8 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
caps->ipsec_offload = MLX5_GET(query_hca_cap_out, out,
capability.cmd_hca_cap.ipsec_offload);
+ caps->roce = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.roce);
+
MLX5_SET(query_hca_cap_in, in, op_mod,
MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE_2 |
MLX5_HCA_CAP_OPMOD_GET_CUR);
@@ -1158,6 +1160,9 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
caps->flow_table_hash_type = MLX5_GET(query_hca_cap_out, out,
capability.cmd_hca_cap_2.flow_table_hash_type);
+ caps->encap_entropy_hash_type = MLX5_GET(query_hca_cap_out, out,
+ capability.cmd_hca_cap_2.encap_entropy_hash_type);
+
MLX5_SET(query_hca_cap_in, in, op_mod,
MLX5_GET_HCA_CAP_OP_MOD_NIC_FLOW_TABLE |
MLX5_HCA_CAP_OPMOD_GET_CUR);
@@ -1306,6 +1311,24 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
capability.esw_cap.merged_eswitch);
}
+ if (caps->roce) {
+ MLX5_SET(query_hca_cap_in, in, op_mod,
+ MLX5_GET_HCA_CAP_OP_MOD_ROCE |
+ MLX5_HCA_CAP_OPMOD_GET_CUR);
+
+ ret = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in), out, sizeof(out));
+ if (ret) {
+ DR_LOG(ERR, "Failed to query roce caps");
+ rte_errno = errno;
+ return rte_errno;
+ }
+
+ caps->roce_max_src_udp_port = MLX5_GET(query_hca_cap_out, out,
+ capability.roce_caps.r_roce_max_src_udp_port);
+ caps->roce_min_src_udp_port = MLX5_GET(query_hca_cap_out, out,
+ capability.roce_caps.r_roce_min_src_udp_port);
+ }
+
ret = mlx5_glue->query_device_ex(ctx, NULL, &attr_ex);
if (ret) {
DR_LOG(ERR, "Failed to query device attributes");
diff --git a/drivers/net/mlx5/hws/mlx5dr_cmd.h b/drivers/net/mlx5/hws/mlx5dr_cmd.h
index 18c2b07fc8..694231e08f 100644
--- a/drivers/net/mlx5/hws/mlx5dr_cmd.h
+++ b/drivers/net/mlx5/hws/mlx5dr_cmd.h
@@ -246,6 +246,10 @@ struct mlx5dr_cmd_query_caps {
uint32_t shared_vhca_id;
char fw_ver[64];
bool ipsec_offload;
+ uint8_t encap_entropy_hash_type;
+ bool roce;
+ uint16_t roce_max_src_udp_port;
+ uint16_t roce_min_src_udp_port;
};
int mlx5dr_cmd_destroy_obj(struct mlx5dr_devx_obj *devx_obj);
diff --git a/drivers/net/mlx5/hws/mlx5dr_crc32.c b/drivers/net/mlx5/hws/mlx5dr_crc32.c
index 9c454eda0c..7431462e14 100644
--- a/drivers/net/mlx5/hws/mlx5dr_crc32.c
+++ b/drivers/net/mlx5/hws/mlx5dr_crc32.c
@@ -50,6 +50,42 @@ uint32_t dr_ste_crc_tab32[] = {
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
+/* CRC table for the CRC-16, the polynome is 0x100b */
+uint16_t dr_crc_inner_crc_tab16[] = {
+ 0x0000, 0x100B, 0x2016, 0x301D, 0x402C, 0x5027, 0x603A, 0x7031,
+ 0x8058, 0x9053, 0xA04E, 0xB045, 0xC074, 0xD07F, 0xE062, 0xF069,
+ 0x10BB, 0x00B0, 0x30AD, 0x20A6, 0x5097, 0x409C, 0x7081, 0x608A,
+ 0x90E3, 0x80E8, 0xB0F5, 0xA0FE, 0xD0CF, 0xC0C4, 0xF0D9, 0xE0D2,
+ 0x2176, 0x317D, 0x0160, 0x116B, 0x615A, 0x7151, 0x414C, 0x5147,
+ 0xA12E, 0xB125, 0x8138, 0x9133, 0xE102, 0xF109, 0xC114, 0xD11F,
+ 0x31CD, 0x21C6, 0x11DB, 0x01D0, 0x71E1, 0x61EA, 0x51F7, 0x41FC,
+ 0xB195, 0xA19E, 0x9183, 0x8188, 0xF1B9, 0xE1B2, 0xD1AF, 0xC1A4,
+ 0x42EC, 0x52E7, 0x62FA, 0x72F1, 0x02C0, 0x12CB, 0x22D6, 0x32DD,
+ 0xC2B4, 0xD2BF, 0xE2A2, 0xF2A9, 0x8298, 0x9293, 0xA28E, 0xB285,
+ 0x5257, 0x425C, 0x7241, 0x624A, 0x127B, 0x0270, 0x326D, 0x2266,
+ 0xD20F, 0xC204, 0xF219, 0xE212, 0x9223, 0x8228, 0xB235, 0xA23E,
+ 0x639A, 0x7391, 0x438C, 0x5387, 0x23B6, 0x33BD, 0x03A0, 0x13AB,
+ 0xE3C2, 0xF3C9, 0xC3D4, 0xD3DF, 0xA3EE, 0xB3E5, 0x83F8, 0x93F3,
+ 0x7321, 0x632A, 0x5337, 0x433C, 0x330D, 0x2306, 0x131B, 0x0310,
+ 0xF379, 0xE372, 0xD36F, 0xC364, 0xB355, 0xA35E, 0x9343, 0x8348,
+ 0x85D8, 0x95D3, 0xA5CE, 0xB5C5, 0xC5F4, 0xD5FF, 0xE5E2, 0xF5E9,
+ 0x0580, 0x158B, 0x2596, 0x359D, 0x45AC, 0x55A7, 0x65BA, 0x75B1,
+ 0x9563, 0x8568, 0xB575, 0xA57E, 0xD54F, 0xC544, 0xF559, 0xE552,
+ 0x153B, 0x0530, 0x352D, 0x2526, 0x5517, 0x451C, 0x7501, 0x650A,
+ 0xA4AE, 0xB4A5, 0x84B8, 0x94B3, 0xE482, 0xF489, 0xC494, 0xD49F,
+ 0x24F6, 0x34FD, 0x04E0, 0x14EB, 0x64DA, 0x74D1, 0x44CC, 0x54C7,
+ 0xB415, 0xA41E, 0x9403, 0x8408, 0xF439, 0xE432, 0xD42F, 0xC424,
+ 0x344D, 0x2446, 0x145B, 0x0450, 0x7461, 0x646A, 0x5477, 0x447C,
+ 0xC734, 0xD73F, 0xE722, 0xF729, 0x8718, 0x9713, 0xA70E, 0xB705,
+ 0x476C, 0x5767, 0x677A, 0x7771, 0x0740, 0x174B, 0x2756, 0x375D,
+ 0xD78F, 0xC784, 0xF799, 0xE792, 0x97A3, 0x87A8, 0xB7B5, 0xA7BE,
+ 0x57D7, 0x47DC, 0x77C1, 0x67CA, 0x17FB, 0x07F0, 0x37ED, 0x27E6,
+ 0xE642, 0xF649, 0xC654, 0xD65F, 0xA66E, 0xB665, 0x8678, 0x9673,
+ 0x661A, 0x7611, 0x460C, 0x5607, 0x2636, 0x363D, 0x0620, 0x162B,
+ 0xF6F9, 0xE6F2, 0xD6EF, 0xC6E4, 0xB6D5, 0xA6DE, 0x96C3, 0x86C8,
+ 0x76A1, 0x66AA, 0x56B7, 0x46BC, 0x368D, 0x2686, 0x169B, 0x0690
+};
+
uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len)
{
uint32_t crc = 0;
@@ -59,3 +95,45 @@ uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len)
return rte_be_to_cpu_32(crc);
}
+
+uint16_t mlx5dr_crc16_calc(uint8_t *p, size_t len, uint16_t crc_tab16[])
+{
+ uint16_t crc = 0;
+
+ while (len--)
+ crc = (crc << 8) ^ crc_tab16[((crc >> 8) ^ *p++) & 0xff];
+
+ return crc;
+}
+
+int mlx5dr_crc_encap_entropy_hash_calc(struct mlx5dr_context *ctx,
+ struct mlx5dr_crc_encap_entropy_hash_fields *data,
+ uint8_t entropy_res[],
+ enum mlx5dr_crc_encap_entropy_hash_size res_size)
+{
+ struct mlx5dr_cmd_query_caps *caps = ctx->caps;
+ uint16_t max_hash, min_hash, res;
+
+ if (caps->encap_entropy_hash_type) {
+ DR_LOG(ERR, "calculation of encap_entropy_hash_type 0x%x not supported",
+ caps->encap_entropy_hash_type);
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ max_hash = caps->roce_max_src_udp_port;
+ min_hash = caps->roce_min_src_udp_port;
+
+ res = mlx5dr_crc16_calc((uint8_t *)data, sizeof(*data), dr_crc_inner_crc_tab16);
+
+ if (res_size == MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16) {
+ *(uint16_t *)entropy_res = rte_cpu_to_be_16((min_hash | res) & max_hash);
+ } else if (res_size == MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8) {
+ *entropy_res = (uint8_t)(res & 0xff);
+ } else {
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/mlx5/hws/mlx5dr_crc32.h b/drivers/net/mlx5/hws/mlx5dr_crc32.h
index 9aab9e06ca..75b6009a15 100644
--- a/drivers/net/mlx5/hws/mlx5dr_crc32.h
+++ b/drivers/net/mlx5/hws/mlx5dr_crc32.h
@@ -10,4 +10,9 @@
*/
uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len);
+/* Standard CRC16 calculation using the crc_tab16 param to indicate
+ * the pre-calculated polynome hash values.
+ */
+uint16_t mlx5dr_crc16_calc(uint8_t *p, size_t len, uint16_t crc_tab16[]);
+
#endif /* MLX5DR_CRC32_C_ */
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 3/4] net/mlx5: add calc encap hash support
2024-02-08 9:09 ` [PATCH v2 1/4] ethdev: " Ori Kam
2024-02-08 9:09 ` [PATCH v2 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
@ 2024-02-08 9:09 ` Ori Kam
2024-02-08 9:09 ` [PATCH v2 4/4] app/testpmd: add encap hash calculation Ori Kam
2024-02-08 17:13 ` [PATCH v2 1/4] ethdev: introduce " Ferruh Yigit
3 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-08 9:09 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Viacheslav Ovsiienko, Suanming Mou, Matan Azrad
Cc: dev, orika, rasland
This commit adds support for encap hash calculation.
Signed-off-by: Ori Kam <orika@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
drivers/net/mlx5/mlx5_flow.c | 29 +++++++++++++++
drivers/net/mlx5/mlx5_flow.h | 8 ++++
drivers/net/mlx5/mlx5_flow_hw.c | 66 +++++++++++++++++++++++++++++++++
3 files changed, 103 insertions(+)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 5159e8e773..0fb6b3b374 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1197,6 +1197,12 @@ mlx5_flow_calc_table_hash(struct rte_eth_dev *dev,
const struct rte_flow_item pattern[],
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+static int
+mlx5_flow_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error);
static const struct rte_flow_ops mlx5_flow_ops = {
.validate = mlx5_flow_validate,
@@ -1253,6 +1259,7 @@ static const struct rte_flow_ops mlx5_flow_ops = {
.async_action_list_handle_query_update =
mlx5_flow_async_action_list_handle_query_update,
.flow_calc_table_hash = mlx5_flow_calc_table_hash,
+ .flow_calc_encap_hash = mlx5_flow_calc_encap_hash,
};
/* Tunnel information. */
@@ -11121,6 +11128,28 @@ mlx5_flow_calc_table_hash(struct rte_eth_dev *dev,
hash, error);
}
+static int
+mlx5_flow_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error)
+{
+ enum mlx5_flow_drv_type drv_type = flow_get_drv_type(dev, NULL);
+ const struct mlx5_flow_driver_ops *fops;
+
+ if (drv_type == MLX5_FLOW_TYPE_MIN || drv_type == MLX5_FLOW_TYPE_MAX)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "invalid driver type");
+ fops = flow_get_drv_ops(drv_type);
+ if (!fops || !fops->flow_calc_encap_hash)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "no calc encap hash handler");
+ return fops->flow_calc_encap_hash(dev, pattern, dest_field, hash, error);
+}
+
/**
* Destroy all indirect actions (shared RSS).
*
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index c9cc942d80..5a8404b9b3 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -2195,6 +2195,13 @@ typedef int
const struct rte_flow_item pattern[],
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+typedef int
+(*mlx5_flow_calc_encap_hash_t)
+ (struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error);
struct mlx5_flow_driver_ops {
mlx5_flow_validate_t validate;
@@ -2268,6 +2275,7 @@ struct mlx5_flow_driver_ops {
mlx5_flow_async_action_list_handle_query_update_t
async_action_list_handle_query_update;
mlx5_flow_calc_table_hash_t flow_calc_table_hash;
+ mlx5_flow_calc_encap_hash_t flow_calc_encap_hash;
};
/* mlx5_flow.c */
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index 7510715189..d81ca96b7b 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -11628,6 +11628,71 @@ flow_hw_calc_table_hash(struct rte_eth_dev *dev,
return 0;
}
+static int
+flow_hw_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5dr_crc_encap_entropy_hash_fields data;
+ enum mlx5dr_crc_encap_entropy_hash_size res_size =
+ dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT ?
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16 :
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8;
+ int res;
+
+ memset(&data, 0, sizeof(struct mlx5dr_crc_encap_entropy_hash_fields));
+
+ for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+ switch (pattern->type) {
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ data.dst.ipv4_addr =
+ ((const struct rte_flow_item_ipv4 *)(pattern->spec))->hdr.dst_addr;
+ data.src.ipv4_addr =
+ ((const struct rte_flow_item_ipv4 *)(pattern->spec))->hdr.src_addr;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ memcpy(data.dst.ipv6_addr,
+ ((const struct rte_flow_item_ipv6 *)(pattern->spec))->hdr.dst_addr,
+ sizeof(data.dst.ipv6_addr));
+ memcpy(data.src.ipv6_addr,
+ ((const struct rte_flow_item_ipv6 *)(pattern->spec))->hdr.src_addr,
+ sizeof(data.src.ipv6_addr));
+ break;
+ case RTE_FLOW_ITEM_TYPE_UDP:
+ data.next_protocol = IPPROTO_UDP;
+ data.dst_port =
+ ((const struct rte_flow_item_udp *)(pattern->spec))->hdr.dst_port;
+ data.src_port =
+ ((const struct rte_flow_item_udp *)(pattern->spec))->hdr.src_port;
+ break;
+ case RTE_FLOW_ITEM_TYPE_TCP:
+ data.next_protocol = IPPROTO_TCP;
+ data.dst_port =
+ ((const struct rte_flow_item_tcp *)(pattern->spec))->hdr.dst_port;
+ data.src_port =
+ ((const struct rte_flow_item_tcp *)(pattern->spec))->hdr.src_port;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ICMP:
+ data.next_protocol = IPPROTO_ICMP;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ICMP6:
+ data.next_protocol = IPPROTO_ICMPV6;
+ break;
+ default:
+ break;
+ }
+ }
+ res = mlx5dr_crc_encap_entropy_hash_calc(priv->dr_ctx, &data, hash, res_size);
+ if (res)
+ return rte_flow_error_set(error, res,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "error while calculating encap hash");
+ return 0;
+}
+
const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
.info_get = flow_hw_info_get,
.configure = flow_hw_configure,
@@ -11673,6 +11738,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
.item_create = flow_dv_item_create,
.item_release = flow_dv_item_release,
.flow_calc_table_hash = flow_hw_calc_table_hash,
+ .flow_calc_encap_hash = flow_hw_calc_encap_hash,
};
/**
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v2 4/4] app/testpmd: add encap hash calculation
2024-02-08 9:09 ` [PATCH v2 1/4] ethdev: " Ori Kam
2024-02-08 9:09 ` [PATCH v2 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
2024-02-08 9:09 ` [PATCH v2 3/4] net/mlx5: add calc encap hash support Ori Kam
@ 2024-02-08 9:09 ` Ori Kam
2024-02-08 17:13 ` [PATCH v2 1/4] ethdev: introduce " Ferruh Yigit
3 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-08 9:09 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Aman Singh, Yuying Zhang
Cc: dev, orika, rasland
This commits add support for calculating the encap hash.
Command structure:
flow hash {port} encap {target field} pattern {item} [/ {item} [...] ] / end
Example:
calculate hash to be used by VXLAN encapsulation.
flow hash 0 encap hash_field_sport pattern ipv4 dst is 7.7.7.7 src is 8.8.8.8 / udp dst is 5678 src is 1234 / end
Signed-off-by: Ori Kam <orika@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
app/test-pmd/cmdline_flow.c | 57 +++++++++++++++++++--
app/test-pmd/config.c | 30 +++++++++++
app/test-pmd/testpmd.h | 3 ++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 21 +++++++-
4 files changed, 106 insertions(+), 5 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 4062879552..a42f07276d 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -219,6 +219,10 @@ enum index {
HASH_CALC_TABLE,
HASH_CALC_PATTERN_INDEX,
HASH_CALC_PATTERN,
+ HASH_CALC_ENCAP,
+ HASH_CALC_DEST,
+ ENCAP_HASH_FIELD_SRC_PORT,
+ ENCAP_HASH_FIELD_GRE_FLOW_ID,
/* Tunnel arguments. */
TUNNEL_CREATE,
@@ -1192,6 +1196,8 @@ struct buffer {
uint32_t pattern_n;
uint32_t actions_n;
uint8_t *data;
+ enum rte_flow_encap_hash_field field;
+ uint8_t encap_hash;
} vc; /**< Validate/create arguments. */
struct {
uint64_t *rule;
@@ -2550,6 +2556,18 @@ static const enum index action_represented_port[] = {
ZERO,
};
+static const enum index next_hash_subcmd[] = {
+ HASH_CALC_TABLE,
+ HASH_CALC_ENCAP,
+ ZERO,
+};
+
+static const enum index next_hash_encap_dest_subcmd[] = {
+ ENCAP_HASH_FIELD_SRC_PORT,
+ ENCAP_HASH_FIELD_GRE_FLOW_ID,
+ ZERO,
+};
+
static int parse_set_raw_encap_decap(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
@@ -3789,7 +3807,7 @@ static const struct token token_list[] = {
[HASH] = {
.name = "hash",
.help = "calculate hash for a given pattern in a given template table",
- .next = NEXT(NEXT_ENTRY(HASH_CALC_TABLE), NEXT_ENTRY(COMMON_PORT_ID)),
+ .next = NEXT(next_hash_subcmd, NEXT_ENTRY(COMMON_PORT_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_hash,
},
@@ -3803,6 +3821,12 @@ static const struct token token_list[] = {
args.vc.table_id)),
.call = parse_hash,
},
+ [HASH_CALC_ENCAP] = {
+ .name = "encap",
+ .help = "calculates encap hash",
+ .next = NEXT(next_hash_encap_dest_subcmd),
+ .call = parse_hash,
+ },
[HASH_CALC_PATTERN_INDEX] = {
.name = "pattern_template",
.help = "specify pattern template id",
@@ -3812,6 +3836,18 @@ static const struct token token_list[] = {
args.vc.pat_templ_id)),
.call = parse_hash,
},
+ [ENCAP_HASH_FIELD_SRC_PORT] = {
+ .name = "hash_field_sport",
+ .help = "the encap hash field is src port",
+ .next = NEXT(NEXT_ENTRY(ITEM_PATTERN)),
+ .call = parse_hash,
+ },
+ [ENCAP_HASH_FIELD_GRE_FLOW_ID] = {
+ .name = "hash_field_flow_id",
+ .help = "the encap hash field is NVGRE flow id",
+ .next = NEXT(NEXT_ENTRY(ITEM_PATTERN)),
+ .call = parse_hash,
+ },
/* Top-level command. */
[INDIRECT_ACTION] = {
.name = "indirect_action",
@@ -10691,6 +10727,15 @@ parse_hash(struct context *ctx, const struct token *token,
ctx->object = out->args.vc.pattern;
ctx->objmask = NULL;
return len;
+ case HASH_CALC_ENCAP:
+ out->args.vc.encap_hash = 1;
+ return len;
+ case ENCAP_HASH_FIELD_SRC_PORT:
+ out->args.vc.field = RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT;
+ return len;
+ case ENCAP_HASH_FIELD_GRE_FLOW_ID:
+ out->args.vc.field = RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID;
+ return len;
default:
return -1;
}
@@ -12651,9 +12696,13 @@ cmd_flow_parsed(const struct buffer *in)
port_queue_flow_pull(in->port, in->queue);
break;
case HASH:
- port_flow_hash_calc(in->port, in->args.vc.table_id,
- in->args.vc.pat_templ_id,
- in->args.vc.pattern);
+ if (!in->args.vc.encap_hash)
+ port_flow_hash_calc(in->port, in->args.vc.table_id,
+ in->args.vc.pat_templ_id,
+ in->args.vc.pattern);
+ else
+ port_flow_hash_calc_encap(in->port, in->args.vc.field,
+ in->args.vc.pattern);
break;
case QUEUE_AGED:
port_queue_flow_aged(in->port, in->queue,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index cad7537bc6..e26b5bd18d 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -3339,6 +3339,36 @@ port_flow_hash_calc(portid_t port_id, uint32_t table_id,
return 0;
}
+/** Calculate the encap hash result for a given pattern. */
+int
+port_flow_hash_calc_encap(portid_t port_id,
+ enum rte_flow_encap_hash_field encap_hash_field,
+ const struct rte_flow_item pattern[])
+{
+ struct rte_flow_error error;
+ int ret = 0;
+ uint16_t hash = 0;
+ uint8_t len = encap_hash_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT ? 2 : 1;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL) {
+ printf("Failed to calculate encap hash - not a valid port");
+ return -EINVAL;
+ }
+
+ ret = rte_flow_calc_encap_hash(port_id, pattern, encap_hash_field, len,
+ (uint8_t *)&hash, &error);
+ if (ret < 0) {
+ printf("Failed to calculate encap hash");
+ return ret;
+ }
+ if (encap_hash_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT)
+ printf("encap hash result %#x\n", hash);
+ else
+ printf("encap hash result %#x\n", *(uint8_t *)&hash);
+ return 0;
+}
+
/** Pull queue operation results from the queue. */
static int
port_queue_aged_flow_destroy(portid_t port_id, queueid_t queue_id,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 9b10a9ea1c..e18546c46e 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -1016,6 +1016,9 @@ int port_queue_flow_push(portid_t port_id, queueid_t queue_id);
int port_queue_flow_pull(portid_t port_id, queueid_t queue_id);
int port_flow_hash_calc(portid_t port_id, uint32_t table_id,
uint8_t pattern_template_index, const struct rte_flow_item pattern[]);
+int port_flow_hash_calc_encap(portid_t port_id,
+ enum rte_flow_encap_hash_field encap_hash_field,
+ const struct rte_flow_item pattern[]);
void port_queue_flow_aged(portid_t port_id, uint32_t queue_id, uint8_t destroy);
int port_flow_validate(portid_t port_id,
const struct rte_flow_attr *attr,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 38ab421547..37a508c967 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -3297,7 +3297,7 @@ The usual error message is shown when operations results cannot be pulled::
Calculating hash
~~~~~~~~~~~~~~~~
-``flow hash`` calculates the hash for a given pattern.
+``flow hash {port_id} template_table`` calculates the hash for a given pattern.
It is bound to ``rte_flow_calc_table_hash()``::
flow hash {port_id} template_table {table_id}
@@ -3316,6 +3316,25 @@ Otherwise, it will show an error message of the form::
This command uses the same pattern items as ``flow create``,
their format is described in `Creating flow rules`_.
+
+Simulate encap hash calculation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``flow hash {port_id} encap`` adds hash query, that returns the hash value
+that the HW will calculate when encapsulating a packet.
+
+ flow hash {port_id} encap {target field} pattern {item} [/ {item} [...]] / end
+
+If successful, it will show::
+
+ encap hash result #[...]
+
+The value will be shown as uint16_t without endian conversion.
+
+Otherwise it will show an error message of the form::
+
+ Failed to calculate encap hash - [...]
+
Creating a tunnel stub for offload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 1/4] ethdev: introduce encap hash calculation
2024-02-08 9:09 ` [PATCH v2 1/4] ethdev: " Ori Kam
` (2 preceding siblings ...)
2024-02-08 9:09 ` [PATCH v2 4/4] app/testpmd: add encap hash calculation Ori Kam
@ 2024-02-08 17:13 ` Ferruh Yigit
2024-02-11 7:29 ` Ori Kam
3 siblings, 1 reply; 31+ messages in thread
From: Ferruh Yigit @ 2024-02-08 17:13 UTC (permalink / raw)
To: Ori Kam, dsosnowski, cristian.dumitrescu, andrew.rybchenko,
stephen, Thomas Monjalon
Cc: dev, rasland
On 2/8/2024 9:09 AM, Ori Kam wrote:
> During encapsulation of a packet, it is possible to change some
> outer headers to improve flow destribution.
> For example, from VXLAN RFC:
> "It is recommended that the UDP source port number
> be calculated using a hash of fields from the inner packet --
> one example being a hash of the inner Ethernet frame's headers.
> This is to enable a level of entropy for the ECMP/load-balancing"
>
> The tunnel protocol defines which outer field should hold this hash,
> but it doesn't define the hash calculation algorithm.
>
> An application that uses flow offloads gets the first few packets
> (exception path) and then decides to offload the flow.
> As a result, there are two
> different paths that a packet from a given flow may take.
> SW for the first few packets or HW for the rest.
> When the packet goes through the SW, the SW encapsulates the packet
> and must use the same hash calculation as the HW will do for
> the rest of the packets in this flow.
>
> the new function rte_flow_calc_encap_hash can query the hash value
> fromm the driver for a given packet as if the packet was passed
> through the HW.
>
> Signed-off-by: Ori Kam <orika@nvidia.com>
> Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
>
<...>
> +int
> +rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
> + enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
> + uint8_t *hash, struct rte_flow_error *error)
> +{
> + int ret;
> + struct rte_eth_dev *dev;
> + const struct rte_flow_ops *ops;
> +
> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
> + ops = rte_flow_ops_get(port_id, error);
> + if (!ops || !ops->flow_calc_encap_hash)
> + return rte_flow_error_set(error, ENOTSUP,
> + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> + "calc encap hash is not supported");
> + if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT && hash_len != 2) ||
> + (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID && hash_len != 1))
>
If there is a fixed mapping with the dest_field and the size, instead of
putting this information into check code, what do you think to put it
into the data structure?
I mean instead of using enum for dest_filed, it can be a struct that is
holding enum and its expected size, this clarifies what the expected
size for that field.
> + return rte_flow_error_set(error, EINVAL,
> + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> + "hash len doesn't match the requested field len");
> + dev = &rte_eth_devices[port_id];
> + ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash, error);
>
'hash_len' is get by API, but it is not passed to dev_ops, does this
mean this information hardcoded in the driver as well, if so why
duplicate this information in driver instead off passing hash_len to driver?
> + return flow_err(port_id, ret, error);
> +}
> diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
> index 1267c146e5..2bdf3a4a17 100644
> --- a/lib/ethdev/rte_flow.h
> +++ b/lib/ethdev/rte_flow.h
> @@ -6783,6 +6783,57 @@ rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
> const struct rte_flow_item pattern[], uint8_t pattern_template_index,
> uint32_t *hash, struct rte_flow_error *error);
>
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Destination field type for the hash calculation, when encap action is used.
> + *
> + * @see function rte_flow_calc_encap_hash
> + */
> +enum rte_flow_encap_hash_field {
> + /* Calculate hash placed in UDP source port field. */
> + RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
> + /* Calculate hash placed in NVGRE flow ID field. */
> + RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
> +};
>
Indeed above enum represents a field in a network protocol, right?
Instead of having a 'RTE_FLOW_ENCAP_HASH_' specific one, can re-using
'enum rte_flow_field_id' work?
^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: [PATCH v2 1/4] ethdev: introduce encap hash calculation
2024-02-08 17:13 ` [PATCH v2 1/4] ethdev: introduce " Ferruh Yigit
@ 2024-02-11 7:29 ` Ori Kam
2024-02-12 17:05 ` Ferruh Yigit
0 siblings, 1 reply; 31+ messages in thread
From: Ori Kam @ 2024-02-11 7:29 UTC (permalink / raw)
To: Ferruh Yigit, Dariusz Sosnowski, cristian.dumitrescu,
andrew.rybchenko, stephen, NBU-Contact-Thomas Monjalon (EXTERNAL)
Cc: dev, Raslan Darawsheh
Hi Ferruh,
> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@amd.com>
> Sent: Thursday, February 8, 2024 7:13 PM
> To: Ori Kam <orika@nvidia.com>; Dariusz Sosnowski
>
> On 2/8/2024 9:09 AM, Ori Kam wrote:
> > During encapsulation of a packet, it is possible to change some
> > outer headers to improve flow destribution.
> > For example, from VXLAN RFC:
> > "It is recommended that the UDP source port number
> > be calculated using a hash of fields from the inner packet --
> > one example being a hash of the inner Ethernet frame's headers.
> > This is to enable a level of entropy for the ECMP/load-balancing"
> >
> > The tunnel protocol defines which outer field should hold this hash,
> > but it doesn't define the hash calculation algorithm.
> >
> > An application that uses flow offloads gets the first few packets
> > (exception path) and then decides to offload the flow.
> > As a result, there are two
> > different paths that a packet from a given flow may take.
> > SW for the first few packets or HW for the rest.
> > When the packet goes through the SW, the SW encapsulates the packet
> > and must use the same hash calculation as the HW will do for
> > the rest of the packets in this flow.
> >
> > the new function rte_flow_calc_encap_hash can query the hash value
> > fromm the driver for a given packet as if the packet was passed
> > through the HW.
> >
> > Signed-off-by: Ori Kam <orika@nvidia.com>
> > Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
> >
>
> <...>
>
> > +int
> > +rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item
> pattern[],
> > + enum rte_flow_encap_hash_field dest_field, uint8_t
> hash_len,
> > + uint8_t *hash, struct rte_flow_error *error)
> > +{
> > + int ret;
> > + struct rte_eth_dev *dev;
> > + const struct rte_flow_ops *ops;
> > +
> > + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
> > + ops = rte_flow_ops_get(port_id, error);
> > + if (!ops || !ops->flow_calc_encap_hash)
> > + return rte_flow_error_set(error, ENOTSUP,
> > +
> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> > + "calc encap hash is not supported");
> > + if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT &&
> hash_len != 2) ||
> > + (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID
> && hash_len != 1))
> >
>
> If there is a fixed mapping with the dest_field and the size, instead of
> putting this information into check code, what do you think to put it
> into the data structure?
>
> I mean instead of using enum for dest_filed, it can be a struct that is
> holding enum and its expected size, this clarifies what the expected
> size for that field.
>
From my original email I think we only need the type, we don't need the size.
On the RFC thread there was an objection. So I added the size,
If you think it is not needed lets remove it.
> > + return rte_flow_error_set(error, EINVAL,
> > +
> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> > + "hash len doesn't match the
> requested field len");
> > + dev = &rte_eth_devices[port_id];
> > + ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash,
> error);
> >
>
> 'hash_len' is get by API, but it is not passed to dev_ops, does this
> mean this information hardcoded in the driver as well, if so why
> duplicate this information in driver instead off passing hash_len to driver?
Not sure I understand, like I wrote above this is pure verification from my point of view.
The driver knows the size based on the dest.
>
>
> > + return flow_err(port_id, ret, error);
> > +}
> > diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
> > index 1267c146e5..2bdf3a4a17 100644
> > --- a/lib/ethdev/rte_flow.h
> > +++ b/lib/ethdev/rte_flow.h
> > @@ -6783,6 +6783,57 @@ rte_flow_calc_table_hash(uint16_t port_id,
> const struct rte_flow_template_table
> > const struct rte_flow_item pattern[], uint8_t
> pattern_template_index,
> > uint32_t *hash, struct rte_flow_error *error);
> >
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change without prior notice.
> > + *
> > + * Destination field type for the hash calculation, when encap action is
> used.
> > + *
> > + * @see function rte_flow_calc_encap_hash
> > + */
> > +enum rte_flow_encap_hash_field {
> > + /* Calculate hash placed in UDP source port field. */
> > + RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
> > + /* Calculate hash placed in NVGRE flow ID field. */
> > + RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
> > +};
> >
>
> Indeed above enum represents a field in a network protocol, right?
> Instead of having a 'RTE_FLOW_ENCAP_HASH_' specific one, can re-using
> 'enum rte_flow_field_id' work?
Since the option are really limited and defined by standard, I prefer to have dedicated options.
Best,
Ori
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 1/4] ethdev: introduce encap hash calculation
2024-02-11 7:29 ` Ori Kam
@ 2024-02-12 17:05 ` Ferruh Yigit
2024-02-12 18:44 ` Ori Kam
0 siblings, 1 reply; 31+ messages in thread
From: Ferruh Yigit @ 2024-02-12 17:05 UTC (permalink / raw)
To: Ori Kam, Dariusz Sosnowski, cristian.dumitrescu,
andrew.rybchenko, stephen, NBU-Contact-Thomas Monjalon (EXTERNAL)
Cc: dev, Raslan Darawsheh
On 2/11/2024 7:29 AM, Ori Kam wrote:
> Hi Ferruh,
>
>> -----Original Message-----
>> From: Ferruh Yigit <ferruh.yigit@amd.com>
>> Sent: Thursday, February 8, 2024 7:13 PM
>> To: Ori Kam <orika@nvidia.com>; Dariusz Sosnowski
>>
>> On 2/8/2024 9:09 AM, Ori Kam wrote:
>>> During encapsulation of a packet, it is possible to change some
>>> outer headers to improve flow destribution.
>>> For example, from VXLAN RFC:
>>> "It is recommended that the UDP source port number
>>> be calculated using a hash of fields from the inner packet --
>>> one example being a hash of the inner Ethernet frame's headers.
>>> This is to enable a level of entropy for the ECMP/load-balancing"
>>>
>>> The tunnel protocol defines which outer field should hold this hash,
>>> but it doesn't define the hash calculation algorithm.
>>>
>>> An application that uses flow offloads gets the first few packets
>>> (exception path) and then decides to offload the flow.
>>> As a result, there are two
>>> different paths that a packet from a given flow may take.
>>> SW for the first few packets or HW for the rest.
>>> When the packet goes through the SW, the SW encapsulates the packet
>>> and must use the same hash calculation as the HW will do for
>>> the rest of the packets in this flow.
>>>
>>> the new function rte_flow_calc_encap_hash can query the hash value
>>> fromm the driver for a given packet as if the packet was passed
>>> through the HW.
>>>
>>> Signed-off-by: Ori Kam <orika@nvidia.com>
>>> Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
>>>
>>
>> <...>
>>
>>> +int
>>> +rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item
>> pattern[],
>>> + enum rte_flow_encap_hash_field dest_field, uint8_t
>> hash_len,
>>> + uint8_t *hash, struct rte_flow_error *error)
>>> +{
>>> + int ret;
>>> + struct rte_eth_dev *dev;
>>> + const struct rte_flow_ops *ops;
>>> +
>>> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
>>> + ops = rte_flow_ops_get(port_id, error);
>>> + if (!ops || !ops->flow_calc_encap_hash)
>>> + return rte_flow_error_set(error, ENOTSUP,
>>> +
>> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
>>> + "calc encap hash is not supported");
>>> + if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT &&
>> hash_len != 2) ||
>>> + (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID
>> && hash_len != 1))
>>>
>>
>> If there is a fixed mapping with the dest_field and the size, instead of
>> putting this information into check code, what do you think to put it
>> into the data structure?
>>
>> I mean instead of using enum for dest_filed, it can be a struct that is
>> holding enum and its expected size, this clarifies what the expected
>> size for that field.
>>
>
> From my original email I think we only need the type, we don't need the size.
> On the RFC thread there was an objection. So I added the size,
> If you think it is not needed lets remove it.
>
I am not saying length is not needed, but
API gets 'dest_field' & 'hash_len', and according checks in the API for
each 'dest_field' there is an exact 'hash_len' requirement, this
requirement is something impacts user but this information is embedded
in the API, my suggestion is make it more visible to user.
My initial suggestion was put this into an object, like:
```
struct x {
enum rte_flow_encap_hash_field dest_field;
size_t expected size;
} y[] = {
{ RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT, 2 },
{ RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID, 1 }
};
```
But as you mentioned this is a limited set, perhaps it is sufficient to
document size requirement in the "enum rte_flow_encap_hash_field" API
doxygen comment.
>>> + return rte_flow_error_set(error, EINVAL,
>>> +
>> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
>>> + "hash len doesn't match the
>> requested field len");
>>> + dev = &rte_eth_devices[port_id];
>>> + ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash,
>> error);
>>>
>>
>> 'hash_len' is get by API, but it is not passed to dev_ops, does this
>> mean this information hardcoded in the driver as well, if so why
>> duplicate this information in driver instead off passing hash_len to driver?
>
> Not sure I understand, like I wrote above this is pure verification from my point of view.
> The driver knows the size based on the dest.
>
My intention was similar to above comment, like dest_field type
RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT implies that required size should be
2 bytes, and it seems driver already knows about this requirement.
Instead, it can be possible to verify 'hash_len' in the API level, pass
this information to the driver and driver use 'hash_len' directly for
its size parameter, so driver will rely on API provided 'hash_len' value
instead of storing this information within driver.
Lets assume 10 drivers are implementing this feature, should all of them
define MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16 equivalent enum/define
withing the driver?
>>
>>
>>> + return flow_err(port_id, ret, error);
>>> +}
>>> diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
>>> index 1267c146e5..2bdf3a4a17 100644
>>> --- a/lib/ethdev/rte_flow.h
>>> +++ b/lib/ethdev/rte_flow.h
>>> @@ -6783,6 +6783,57 @@ rte_flow_calc_table_hash(uint16_t port_id,
>> const struct rte_flow_template_table
>>> const struct rte_flow_item pattern[], uint8_t
>> pattern_template_index,
>>> uint32_t *hash, struct rte_flow_error *error);
>>>
>>> +/**
>>> + * @warning
>>> + * @b EXPERIMENTAL: this API may change without prior notice.
>>> + *
>>> + * Destination field type for the hash calculation, when encap action is
>> used.
>>> + *
>>> + * @see function rte_flow_calc_encap_hash
>>> + */
>>> +enum rte_flow_encap_hash_field {
>>> + /* Calculate hash placed in UDP source port field. */
>>>
Just recognized that comments are not doxygen comments.
>>> + RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
>>> + /* Calculate hash placed in NVGRE flow ID field. */
>>> + RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
>>> +};
>>>
>>
>> Indeed above enum represents a field in a network protocol, right?
>> Instead of having a 'RTE_FLOW_ENCAP_HASH_' specific one, can re-using
>> 'enum rte_flow_field_id' work?
>
> Since the option are really limited and defined by standard, I prefer to have dedicated options.
>
OK, my intention is to reduce the duplication. Just for brainstorm, what
is the benefit of having 'RTE_FLOW_ENCAP_HASH_' specific enums, if we
can present them as generic protocol fiels, like
'RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT' vs 'RTE_FLOW_FIELD_UDP_PORT_SRC,'?
^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: [PATCH v2 1/4] ethdev: introduce encap hash calculation
2024-02-12 17:05 ` Ferruh Yigit
@ 2024-02-12 18:44 ` Ori Kam
2024-02-12 20:09 ` Ferruh Yigit
0 siblings, 1 reply; 31+ messages in thread
From: Ori Kam @ 2024-02-12 18:44 UTC (permalink / raw)
To: Ferruh Yigit, Dariusz Sosnowski, cristian.dumitrescu,
andrew.rybchenko, stephen, NBU-Contact-Thomas Monjalon (EXTERNAL)
Cc: dev, Raslan Darawsheh
Hi Ferruh
> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@amd.com>
> Sent: Monday, February 12, 2024 7:05 PM
>
> On 2/11/2024 7:29 AM, Ori Kam wrote:
> > Hi Ferruh,
> >
> >> -----Original Message-----
> >> From: Ferruh Yigit <ferruh.yigit@amd.com>
> >> Sent: Thursday, February 8, 2024 7:13 PM
> >> To: Ori Kam <orika@nvidia.com>; Dariusz Sosnowski
> >>
> >> On 2/8/2024 9:09 AM, Ori Kam wrote:
> >>> During encapsulation of a packet, it is possible to change some
> >>> outer headers to improve flow destribution.
> >>> For example, from VXLAN RFC:
> >>> "It is recommended that the UDP source port number
> >>> be calculated using a hash of fields from the inner packet --
> >>> one example being a hash of the inner Ethernet frame's headers.
> >>> This is to enable a level of entropy for the ECMP/load-balancing"
> >>>
> >>> The tunnel protocol defines which outer field should hold this hash,
> >>> but it doesn't define the hash calculation algorithm.
> >>>
> >>> An application that uses flow offloads gets the first few packets
> >>> (exception path) and then decides to offload the flow.
> >>> As a result, there are two
> >>> different paths that a packet from a given flow may take.
> >>> SW for the first few packets or HW for the rest.
> >>> When the packet goes through the SW, the SW encapsulates the packet
> >>> and must use the same hash calculation as the HW will do for
> >>> the rest of the packets in this flow.
> >>>
> >>> the new function rte_flow_calc_encap_hash can query the hash value
> >>> fromm the driver for a given packet as if the packet was passed
> >>> through the HW.
> >>>
> >>> Signed-off-by: Ori Kam <orika@nvidia.com>
> >>> Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
> >>>
> >>
> >> <...>
> >>
> >>> +int
> >>> +rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item
> >> pattern[],
> >>> + enum rte_flow_encap_hash_field dest_field, uint8_t
> >> hash_len,
> >>> + uint8_t *hash, struct rte_flow_error *error)
> >>> +{
> >>> + int ret;
> >>> + struct rte_eth_dev *dev;
> >>> + const struct rte_flow_ops *ops;
> >>> +
> >>> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
> >>> + ops = rte_flow_ops_get(port_id, error);
> >>> + if (!ops || !ops->flow_calc_encap_hash)
> >>> + return rte_flow_error_set(error, ENOTSUP,
> >>> +
> >> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> >>> + "calc encap hash is not supported");
> >>> + if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT &&
> >> hash_len != 2) ||
> >>> + (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID
> >> && hash_len != 1))
> >>>
> >>
> >> If there is a fixed mapping with the dest_field and the size, instead of
> >> putting this information into check code, what do you think to put it
> >> into the data structure?
> >>
> >> I mean instead of using enum for dest_filed, it can be a struct that is
> >> holding enum and its expected size, this clarifies what the expected
> >> size for that field.
> >>
> >
> > From my original email I think we only need the type, we don't need the
> size.
> > On the RFC thread there was an objection. So I added the size,
> > If you think it is not needed lets remove it.
> >
>
> I am not saying length is not needed, but
> API gets 'dest_field' & 'hash_len', and according checks in the API for
> each 'dest_field' there is an exact 'hash_len' requirement, this
> requirement is something impacts user but this information is embedded
> in the API, my suggestion is make it more visible to user.
>
> My initial suggestion was put this into an object, like:
> ```
> struct x {
> enum rte_flow_encap_hash_field dest_field;
> size_t expected size;
> } y[] = {
> { RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT, 2 },
> { RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID, 1 }
> };
> ```
>
> But as you mentioned this is a limited set, perhaps it is sufficient to
> document size requirement in the "enum rte_flow_encap_hash_field" API
> doxygen comment.
Will add it to the doxygen.
>
>
>
> >>> + return rte_flow_error_set(error, EINVAL,
> >>> +
> >> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> >>> + "hash len doesn't match the
> >> requested field len");
> >>> + dev = &rte_eth_devices[port_id];
> >>> + ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash,
> >> error);
> >>>
> >>
> >> 'hash_len' is get by API, but it is not passed to dev_ops, does this
> >> mean this information hardcoded in the driver as well, if so why
> >> duplicate this information in driver instead off passing hash_len to driver?
> >
> > Not sure I understand, like I wrote above this is pure verification from my
> point of view.
> > The driver knows the size based on the dest.
> >
>
> My intention was similar to above comment, like dest_field type
> RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT implies that required size should
> be
> 2 bytes, and it seems driver already knows about this requirement.
That is correct, that is why I don't think we need the size, add added it
only for validation due to community request.
>
> Instead, it can be possible to verify 'hash_len' in the API level, pass
> this information to the driver and driver use 'hash_len' directly for
> its size parameter, so driver will rely on API provided 'hash_len' value
> instead of storing this information within driver.
>
> Lets assume 10 drivers are implementing this feature, should all of them
> define MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16 equivalent
> enum/define
> withing the driver?
No, the driver implements hard-coded logic, which means that it just needs to know
the dest field, in order to know what hash to calculate
It is possible that for each field the HW will calculate the hash using different algorithm.
Also it is possible that the HW doesn't support writing to the expected field, in which case we
want the driver call to fail.
Field implies size.
Size doesn't implies field.
>
> >>
> >>
> >>> + return flow_err(port_id, ret, error);
> >>> +}
> >>> diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
> >>> index 1267c146e5..2bdf3a4a17 100644
> >>> --- a/lib/ethdev/rte_flow.h
> >>> +++ b/lib/ethdev/rte_flow.h
> >>> @@ -6783,6 +6783,57 @@ rte_flow_calc_table_hash(uint16_t port_id,
> >> const struct rte_flow_template_table
> >>> const struct rte_flow_item pattern[], uint8_t
> >> pattern_template_index,
> >>> uint32_t *hash, struct rte_flow_error *error);
> >>>
> >>> +/**
> >>> + * @warning
> >>> + * @b EXPERIMENTAL: this API may change without prior notice.
> >>> + *
> >>> + * Destination field type for the hash calculation, when encap action is
> >> used.
> >>> + *
> >>> + * @see function rte_flow_calc_encap_hash
> >>> + */
> >>> +enum rte_flow_encap_hash_field {
> >>> + /* Calculate hash placed in UDP source port field. */
> >>>
>
> Just recognized that comments are not doxygen comments.
Thanks,
Will fix.
>
> >>> + RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
> >>> + /* Calculate hash placed in NVGRE flow ID field. */
> >>> + RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
> >>> +};
> >>>
> >>
> >> Indeed above enum represents a field in a network protocol, right?
> >> Instead of having a 'RTE_FLOW_ENCAP_HASH_' specific one, can re-using
> >> 'enum rte_flow_field_id' work?
> >
> > Since the option are really limited and defined by standard, I prefer to have
> dedicated options.
> >
>
> OK, my intention is to reduce the duplication. Just for brainstorm, what
> is the benefit of having 'RTE_FLOW_ENCAP_HASH_' specific enums, if we
> can present them as generic protocol fiels, like
> 'RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT' vs
> 'RTE_FLOW_FIELD_UDP_PORT_SRC,'?
I guess you want to go with 'RTE_FLOW_FIELD_UDP_PORT_SRC
right?
The main issue is since the options are really limited and used for a very dedicated function.
When app developers / DPDK developers will look at it, it will be very unclear what is the use of this enum.
We already have an enum for fields. Like you suggested we could have used it,
but this will show much more option than there are really.
Best,
Ori
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v2 1/4] ethdev: introduce encap hash calculation
2024-02-12 18:44 ` Ori Kam
@ 2024-02-12 20:09 ` Ferruh Yigit
2024-02-13 7:05 ` Ori Kam
0 siblings, 1 reply; 31+ messages in thread
From: Ferruh Yigit @ 2024-02-12 20:09 UTC (permalink / raw)
To: Ori Kam, Dariusz Sosnowski, cristian.dumitrescu,
andrew.rybchenko, stephen, NBU-Contact-Thomas Monjalon (EXTERNAL)
Cc: dev, Raslan Darawsheh
On 2/12/2024 6:44 PM, Ori Kam wrote:
> Hi Ferruh
>
>> -----Original Message-----
>> From: Ferruh Yigit <ferruh.yigit@amd.com>
>> Sent: Monday, February 12, 2024 7:05 PM
>>
>> On 2/11/2024 7:29 AM, Ori Kam wrote:
>>> Hi Ferruh,
>>>
>>>> -----Original Message-----
>>>> From: Ferruh Yigit <ferruh.yigit@amd.com>
>>>> Sent: Thursday, February 8, 2024 7:13 PM
>>>> To: Ori Kam <orika@nvidia.com>; Dariusz Sosnowski
>>>>
>>>> On 2/8/2024 9:09 AM, Ori Kam wrote:
>>>>> During encapsulation of a packet, it is possible to change some
>>>>> outer headers to improve flow destribution.
>>>>> For example, from VXLAN RFC:
>>>>> "It is recommended that the UDP source port number
>>>>> be calculated using a hash of fields from the inner packet --
>>>>> one example being a hash of the inner Ethernet frame's headers.
>>>>> This is to enable a level of entropy for the ECMP/load-balancing"
>>>>>
>>>>> The tunnel protocol defines which outer field should hold this hash,
>>>>> but it doesn't define the hash calculation algorithm.
>>>>>
>>>>> An application that uses flow offloads gets the first few packets
>>>>> (exception path) and then decides to offload the flow.
>>>>> As a result, there are two
>>>>> different paths that a packet from a given flow may take.
>>>>> SW for the first few packets or HW for the rest.
>>>>> When the packet goes through the SW, the SW encapsulates the packet
>>>>> and must use the same hash calculation as the HW will do for
>>>>> the rest of the packets in this flow.
>>>>>
>>>>> the new function rte_flow_calc_encap_hash can query the hash value
>>>>> fromm the driver for a given packet as if the packet was passed
>>>>> through the HW.
>>>>>
>>>>> Signed-off-by: Ori Kam <orika@nvidia.com>
>>>>> Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
>>>>>
>>>>
>>>> <...>
>>>>
>>>>> +int
>>>>> +rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item
>>>> pattern[],
>>>>> + enum rte_flow_encap_hash_field dest_field, uint8_t
>>>> hash_len,
>>>>> + uint8_t *hash, struct rte_flow_error *error)
>>>>> +{
>>>>> + int ret;
>>>>> + struct rte_eth_dev *dev;
>>>>> + const struct rte_flow_ops *ops;
>>>>> +
>>>>> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
>>>>> + ops = rte_flow_ops_get(port_id, error);
>>>>> + if (!ops || !ops->flow_calc_encap_hash)
>>>>> + return rte_flow_error_set(error, ENOTSUP,
>>>>> +
>>>> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
>>>>> + "calc encap hash is not supported");
>>>>> + if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT &&
>>>> hash_len != 2) ||
>>>>> + (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID
>>>> && hash_len != 1))
>>>>>
>>>>
>>>> If there is a fixed mapping with the dest_field and the size, instead of
>>>> putting this information into check code, what do you think to put it
>>>> into the data structure?
>>>>
>>>> I mean instead of using enum for dest_filed, it can be a struct that is
>>>> holding enum and its expected size, this clarifies what the expected
>>>> size for that field.
>>>>
>>>
>>> From my original email I think we only need the type, we don't need the
>> size.
>>> On the RFC thread there was an objection. So I added the size,
>>> If you think it is not needed lets remove it.
>>>
>>
>> I am not saying length is not needed, but
>> API gets 'dest_field' & 'hash_len', and according checks in the API for
>> each 'dest_field' there is an exact 'hash_len' requirement, this
>> requirement is something impacts user but this information is embedded
>> in the API, my suggestion is make it more visible to user.
>>
>> My initial suggestion was put this into an object, like:
>> ```
>> struct x {
>> enum rte_flow_encap_hash_field dest_field;
>> size_t expected size;
>> } y[] = {
>> { RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT, 2 },
>> { RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID, 1 }
>> };
>> ```
>>
>> But as you mentioned this is a limited set, perhaps it is sufficient to
>> document size requirement in the "enum rte_flow_encap_hash_field" API
>> doxygen comment.
>
> Will add it to the doxygen.
>
>>
>>
>>
>>>>> + return rte_flow_error_set(error, EINVAL,
>>>>> +
>>>> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
>>>>> + "hash len doesn't match the
>>>> requested field len");
>>>>> + dev = &rte_eth_devices[port_id];
>>>>> + ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash,
>>>> error);
>>>>>
>>>>
>>>> 'hash_len' is get by API, but it is not passed to dev_ops, does this
>>>> mean this information hardcoded in the driver as well, if so why
>>>> duplicate this information in driver instead off passing hash_len to driver?
>>>
>>> Not sure I understand, like I wrote above this is pure verification from my
>> point of view.
>>> The driver knows the size based on the dest.
>>>
>>
>> My intention was similar to above comment, like dest_field type
>> RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT implies that required size should
>> be
>> 2 bytes, and it seems driver already knows about this requirement.
>
> That is correct, that is why I don't think we need the size, add added it
> only for validation due to community request.
>
>>
>> Instead, it can be possible to verify 'hash_len' in the API level, pass
>> this information to the driver and driver use 'hash_len' directly for
>> its size parameter, so driver will rely on API provided 'hash_len' value
>> instead of storing this information within driver.
>>
>> Lets assume 10 drivers are implementing this feature, should all of them
>> define MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16 equivalent
>> enum/define
>> withing the driver?
>
> No, the driver implements hard-coded logic, which means that it just needs to know
> the dest field, in order to know what hash to calculate
> It is possible that for each field the HW will calculate the hash using different algorithm.
>
OK if HW already needs to know the size in advance, lets go with enum
doxygen update only.
> Also it is possible that the HW doesn't support writing to the expected field, in which case we
> want the driver call to fail.
>
> Field implies size.
> Size doesn't implies field.
>
>>
>>>>
>>>>
>>>>> + return flow_err(port_id, ret, error);
>>>>> +}
>>>>> diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
>>>>> index 1267c146e5..2bdf3a4a17 100644
>>>>> --- a/lib/ethdev/rte_flow.h
>>>>> +++ b/lib/ethdev/rte_flow.h
>>>>> @@ -6783,6 +6783,57 @@ rte_flow_calc_table_hash(uint16_t port_id,
>>>> const struct rte_flow_template_table
>>>>> const struct rte_flow_item pattern[], uint8_t
>>>> pattern_template_index,
>>>>> uint32_t *hash, struct rte_flow_error *error);
>>>>>
>>>>> +/**
>>>>> + * @warning
>>>>> + * @b EXPERIMENTAL: this API may change without prior notice.
>>>>> + *
>>>>> + * Destination field type for the hash calculation, when encap action is
>>>> used.
>>>>> + *
>>>>> + * @see function rte_flow_calc_encap_hash
>>>>> + */
>>>>> +enum rte_flow_encap_hash_field {
>>>>> + /* Calculate hash placed in UDP source port field. */
>>>>>
>>
>> Just recognized that comments are not doxygen comments.
>
> Thanks,
> Will fix.
>>
>>>>> + RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
>>>>> + /* Calculate hash placed in NVGRE flow ID field. */
>>>>> + RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
>>>>> +};
>>>>>
>>>>
>>>> Indeed above enum represents a field in a network protocol, right?
>>>> Instead of having a 'RTE_FLOW_ENCAP_HASH_' specific one, can re-using
>>>> 'enum rte_flow_field_id' work?
>>>
>>> Since the option are really limited and defined by standard, I prefer to have
>> dedicated options.
>>>
>>
>> OK, my intention is to reduce the duplication. Just for brainstorm, what
>> is the benefit of having 'RTE_FLOW_ENCAP_HASH_' specific enums, if we
>> can present them as generic protocol fiels, like
>> 'RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT' vs
>> 'RTE_FLOW_FIELD_UDP_PORT_SRC,'?
>
> I guess you want to go with 'RTE_FLOW_FIELD_UDP_PORT_SRC
> right?
>
I just want to discuss if redundancy can be eliminated.
> The main issue is since the options are really limited and used for a very dedicated function.
> When app developers / DPDK developers will look at it, it will be very unclear what is the use of this enum.
> We already have an enum for fields. Like you suggested we could have used it,
> but this will show much more option than there are really.
>
OK, lets use dedicated enums to clarify to the users the specific fields
available for this set of APIs.
Btw, is boundary check like following required for the APIs:
```
if (dest_field > RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID)
return -EINVAL;
```
In case user pass an invalid value as 'dest_filed'
(Note: I intentionally not used MAX enum something like
'RTE_FLOW_ENCAP_HASH_FIELD_MAX' to not need to deal with ABI issues in
the future.)
^ permalink raw reply [flat|nested] 31+ messages in thread
* RE: [PATCH v2 1/4] ethdev: introduce encap hash calculation
2024-02-12 20:09 ` Ferruh Yigit
@ 2024-02-13 7:05 ` Ori Kam
0 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-13 7:05 UTC (permalink / raw)
To: Ferruh Yigit, Dariusz Sosnowski, cristian.dumitrescu,
andrew.rybchenko, stephen, NBU-Contact-Thomas Monjalon (EXTERNAL)
Cc: dev, Raslan Darawsheh
> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@amd.com>
> Sent: Monday, February 12, 2024 10:10 PM
>
> On 2/12/2024 6:44 PM, Ori Kam wrote:
> > Hi Ferruh
> >
> >> -----Original Message-----
> >> From: Ferruh Yigit <ferruh.yigit@amd.com>
> >> Sent: Monday, February 12, 2024 7:05 PM
> >>
> >> On 2/11/2024 7:29 AM, Ori Kam wrote:
> >>> Hi Ferruh,
> >>>
> >>>> -----Original Message-----
> >>>> From: Ferruh Yigit <ferruh.yigit@amd.com>
> >>>> Sent: Thursday, February 8, 2024 7:13 PM
> >>>> To: Ori Kam <orika@nvidia.com>; Dariusz Sosnowski
> >>>>
> >>>> On 2/8/2024 9:09 AM, Ori Kam wrote:
> >>>>> During encapsulation of a packet, it is possible to change some
> >>>>> outer headers to improve flow destribution.
> >>>>> For example, from VXLAN RFC:
> >>>>> "It is recommended that the UDP source port number
> >>>>> be calculated using a hash of fields from the inner packet --
> >>>>> one example being a hash of the inner Ethernet frame's headers.
> >>>>> This is to enable a level of entropy for the ECMP/load-balancing"
> >>>>>
> >>>>> The tunnel protocol defines which outer field should hold this hash,
> >>>>> but it doesn't define the hash calculation algorithm.
> >>>>>
> >>>>> An application that uses flow offloads gets the first few packets
> >>>>> (exception path) and then decides to offload the flow.
> >>>>> As a result, there are two
> >>>>> different paths that a packet from a given flow may take.
> >>>>> SW for the first few packets or HW for the rest.
> >>>>> When the packet goes through the SW, the SW encapsulates the
> packet
> >>>>> and must use the same hash calculation as the HW will do for
> >>>>> the rest of the packets in this flow.
> >>>>>
> >>>>> the new function rte_flow_calc_encap_hash can query the hash value
> >>>>> fromm the driver for a given packet as if the packet was passed
> >>>>> through the HW.
> >>>>>
> >>>>> Signed-off-by: Ori Kam <orika@nvidia.com>
> >>>>> Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
> >>>>>
> >>>>
> >>>> <...>
> >>>>
> >>>>> +int
> >>>>> +rte_flow_calc_encap_hash(uint16_t port_id, const struct
> rte_flow_item
> >>>> pattern[],
> >>>>> + enum rte_flow_encap_hash_field dest_field,
> uint8_t
> >>>> hash_len,
> >>>>> + uint8_t *hash, struct rte_flow_error *error)
> >>>>> +{
> >>>>> + int ret;
> >>>>> + struct rte_eth_dev *dev;
> >>>>> + const struct rte_flow_ops *ops;
> >>>>> +
> >>>>> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
> >>>>> + ops = rte_flow_ops_get(port_id, error);
> >>>>> + if (!ops || !ops->flow_calc_encap_hash)
> >>>>> + return rte_flow_error_set(error, ENOTSUP,
> >>>>> +
> >>>> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> >>>>> + "calc encap hash is not
> supported");
> >>>>> + if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT
> &&
> >>>> hash_len != 2) ||
> >>>>> + (dest_field ==
> RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID
> >>>> && hash_len != 1))
> >>>>>
> >>>>
> >>>> If there is a fixed mapping with the dest_field and the size, instead of
> >>>> putting this information into check code, what do you think to put it
> >>>> into the data structure?
> >>>>
> >>>> I mean instead of using enum for dest_filed, it can be a struct that is
> >>>> holding enum and its expected size, this clarifies what the expected
> >>>> size for that field.
> >>>>
> >>>
> >>> From my original email I think we only need the type, we don't need the
> >> size.
> >>> On the RFC thread there was an objection. So I added the size,
> >>> If you think it is not needed lets remove it.
> >>>
> >>
> >> I am not saying length is not needed, but
> >> API gets 'dest_field' & 'hash_len', and according checks in the API for
> >> each 'dest_field' there is an exact 'hash_len' requirement, this
> >> requirement is something impacts user but this information is embedded
> >> in the API, my suggestion is make it more visible to user.
> >>
> >> My initial suggestion was put this into an object, like:
> >> ```
> >> struct x {
> >> enum rte_flow_encap_hash_field dest_field;
> >> size_t expected size;
> >> } y[] = {
> >> { RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT, 2 },
> >> { RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID, 1 }
> >> };
> >> ```
> >>
> >> But as you mentioned this is a limited set, perhaps it is sufficient to
> >> document size requirement in the "enum rte_flow_encap_hash_field" API
> >> doxygen comment.
> >
> > Will add it to the doxygen.
> >
> >>
> >>
> >>
> >>>>> + return rte_flow_error_set(error, EINVAL,
> >>>>> +
> >>>> RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
> >>>>> + "hash len doesn't match the
> >>>> requested field len");
> >>>>> + dev = &rte_eth_devices[port_id];
> >>>>> + ret = ops->flow_calc_encap_hash(dev, pattern, dest_field,
> hash,
> >>>> error);
> >>>>>
> >>>>
> >>>> 'hash_len' is get by API, but it is not passed to dev_ops, does this
> >>>> mean this information hardcoded in the driver as well, if so why
> >>>> duplicate this information in driver instead off passing hash_len to
> driver?
> >>>
> >>> Not sure I understand, like I wrote above this is pure verification from my
> >> point of view.
> >>> The driver knows the size based on the dest.
> >>>
> >>
> >> My intention was similar to above comment, like dest_field type
> >> RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT implies that required size
> should
> >> be
> >> 2 bytes, and it seems driver already knows about this requirement.
> >
> > That is correct, that is why I don't think we need the size, add added it
> > only for validation due to community request.
> >
> >>
> >> Instead, it can be possible to verify 'hash_len' in the API level, pass
> >> this information to the driver and driver use 'hash_len' directly for
> >> its size parameter, so driver will rely on API provided 'hash_len' value
> >> instead of storing this information within driver.
> >>
> >> Lets assume 10 drivers are implementing this feature, should all of them
> >> define MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16 equivalent
> >> enum/define
> >> withing the driver?
> >
> > No, the driver implements hard-coded logic, which means that it just needs
> to know
> > the dest field, in order to know what hash to calculate
> > It is possible that for each field the HW will calculate the hash using
> different algorithm.
> >
>
> OK if HW already needs to know the size in advance, lets go with enum
> doxygen update only.
>
> > Also it is possible that the HW doesn't support writing to the expected field,
> in which case we
> > want the driver call to fail.
> >
> > Field implies size.
> > Size doesn't implies field.
> >
> >>
> >>>>
> >>>>
> >>>>> + return flow_err(port_id, ret, error);
> >>>>> +}
> >>>>> diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
> >>>>> index 1267c146e5..2bdf3a4a17 100644
> >>>>> --- a/lib/ethdev/rte_flow.h
> >>>>> +++ b/lib/ethdev/rte_flow.h
> >>>>> @@ -6783,6 +6783,57 @@ rte_flow_calc_table_hash(uint16_t
> port_id,
> >>>> const struct rte_flow_template_table
> >>>>> const struct rte_flow_item pattern[], uint8_t
> >>>> pattern_template_index,
> >>>>> uint32_t *hash, struct rte_flow_error *error);
> >>>>>
> >>>>> +/**
> >>>>> + * @warning
> >>>>> + * @b EXPERIMENTAL: this API may change without prior notice.
> >>>>> + *
> >>>>> + * Destination field type for the hash calculation, when encap action
> is
> >>>> used.
> >>>>> + *
> >>>>> + * @see function rte_flow_calc_encap_hash
> >>>>> + */
> >>>>> +enum rte_flow_encap_hash_field {
> >>>>> + /* Calculate hash placed in UDP source port field. */
> >>>>>
> >>
> >> Just recognized that comments are not doxygen comments.
> >
> > Thanks,
> > Will fix.
> >>
> >>>>> + RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
> >>>>> + /* Calculate hash placed in NVGRE flow ID field. */
> >>>>> + RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
> >>>>> +};
> >>>>>
> >>>>
> >>>> Indeed above enum represents a field in a network protocol, right?
> >>>> Instead of having a 'RTE_FLOW_ENCAP_HASH_' specific one, can re-
> using
> >>>> 'enum rte_flow_field_id' work?
> >>>
> >>> Since the option are really limited and defined by standard, I prefer to
> have
> >> dedicated options.
> >>>
> >>
> >> OK, my intention is to reduce the duplication. Just for brainstorm, what
> >> is the benefit of having 'RTE_FLOW_ENCAP_HASH_' specific enums, if we
> >> can present them as generic protocol fiels, like
> >> 'RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT' vs
> >> 'RTE_FLOW_FIELD_UDP_PORT_SRC,'?
> >
> > I guess you want to go with 'RTE_FLOW_FIELD_UDP_PORT_SRC
> > right?
> >
>
> I just want to discuss if redundancy can be eliminated.
>
> > The main issue is since the options are really limited and used for a very
> dedicated function.
> > When app developers / DPDK developers will look at it, it will be very
> unclear what is the use of this enum.
> > We already have an enum for fields. Like you suggested we could have
> used it,
> > but this will show much more option than there are really.
> >
>
> OK, lets use dedicated enums to clarify to the users the specific fields
> available for this set of APIs.
>
> Btw, is boundary check like following required for the APIs:
> ```
> if (dest_field > RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID)
> return -EINVAL;
> ```
> In case user pass an invalid value as 'dest_filed'
>
> (Note: I intentionally not used MAX enum something like
> 'RTE_FLOW_ENCAP_HASH_FIELD_MAX' to not need to deal with ABI issues in
> the future.)
Good idea will add
Best,
Ori
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 1/4] ethdev: introduce encap hash calculation
2024-01-28 9:39 [PATCH 0/4] introduce encap hash calculation Ori Kam
` (5 preceding siblings ...)
2024-02-08 9:09 ` [PATCH v2 1/4] ethdev: " Ori Kam
@ 2024-02-13 13:48 ` Ori Kam
2024-02-13 13:48 ` [PATCH v3 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
` (2 more replies)
2024-02-13 14:16 ` [PATCH v4 1/4] ethdev: introduce " Ori Kam
7 siblings, 3 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-13 13:48 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Thomas Monjalon
Cc: dev, orika, rasland
During encapsulation of a packet, it is possible to change some
outer headers to improve flow destribution.
For example, from VXLAN RFC:
"It is recommended that the UDP source port number
be calculated using a hash of fields from the inner packet --
one example being a hash of the inner Ethernet frame's headers.
This is to enable a level of entropy for the ECMP/load-balancing"
The tunnel protocol defines which outer field should hold this hash,
but it doesn't define the hash calculation algorithm.
An application that uses flow offloads gets the first few packets
(exception path) and then decides to offload the flow.
As a result, there are two
different paths that a packet from a given flow may take.
SW for the first few packets or HW for the rest.
When the packet goes through the SW, the SW encapsulates the packet
and must use the same hash calculation as the HW will do for
the rest of the packets in this flow.
the new function rte_flow_calc_encap_hash can query the hash value
fromm the driver for a given packet as if the packet was passed
through the HW.
Signed-off-by: Ori Kam <orika@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
doc/guides/prog_guide/rte_flow.rst | 14 +++++++
doc/guides/rel_notes/release_24_03.rst | 6 ++-
lib/ethdev/rte_flow.c | 29 ++++++++++++++
lib/ethdev/rte_flow.h | 53 ++++++++++++++++++++++++++
lib/ethdev/rte_flow_driver.h | 5 +++
lib/ethdev/version.map | 1 +
6 files changed, 107 insertions(+), 1 deletion(-)
diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 34dc06ec66..294862d502 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -4226,6 +4226,20 @@ as it would be calculated in the HW.
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+Calculate encapsulation hash
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Calculating hash of a packet as it would be calculated by the HW, when encapsulating
+a packet.
+
+When the HW execute an encapsulation action, for example VXLAN tunnel,
+it may calculate an hash of the packet to be encapsulated.
+This hash is stored in the outer header of the tunnel.
+This allow better spreading of traffic.
+
+This function can be used for packets of a flow that are not offloaded and
+pass through the SW instead of the HW, for example, SYN/FIN packets.
+
.. _flow_isolated_mode:
Flow isolated mode
diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst
index 358998e988..cf114ead89 100644
--- a/doc/guides/rel_notes/release_24_03.rst
+++ b/doc/guides/rel_notes/release_24_03.rst
@@ -60,6 +60,11 @@ New Features
* Added new function ``rte_eth_find_rss_algo`` to get RSS hash
algorithm by its name.
+* **Added hash calculation of an encapsulated packet as done by the HW.**
+
+ Added function to calculate hash when doing tunnel encapsulation:
+ ``rte_flow_calc_encap_hash()``
+
* **Added flow matching of random value.**
* Added ``RTE_FLOW_ITEM_TYPE_RANDOM`` to match random value.
@@ -102,7 +107,6 @@ New Features
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_OPT_CLASS`` flow action.
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_OPT_DATA`` flow action.
-
Removed Items
-------------
diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
index b06da0cc00..7a4f7a94f6 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -2484,3 +2484,32 @@ rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
hash, error);
return flow_err(port_id, ret, error);
}
+
+int
+rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
+ uint8_t *hash, struct rte_flow_error *error)
+{
+ int ret;
+ struct rte_eth_dev *dev;
+ const struct rte_flow_ops *ops;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ ops = rte_flow_ops_get(port_id, error);
+ if (!ops || !ops->flow_calc_encap_hash)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "calc encap hash is not supported");
+ if (dest_field > RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "hash dest field is not defined");
+ if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT && hash_len != 2) ||
+ (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID && hash_len != 1))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "hash len doesn't match the requested field len");
+ dev = &rte_eth_devices[port_id];
+ ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash, error);
+ return flow_err(port_id, ret, error);
+}
diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
index 09c1b13381..48e4f47844 100644
--- a/lib/ethdev/rte_flow.h
+++ b/lib/ethdev/rte_flow.h
@@ -6846,6 +6846,59 @@ rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
const struct rte_flow_item pattern[], uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Destination field type for the hash calculation, when encap action is used.
+ * The encap field implies the size, meaning XXX_SRC_PORT hash len is 2 bytes,
+ * while XXX_NVGRE_FLOW_ID hash len is 1 byte.
+ *
+ * @see function rte_flow_calc_encap_hash
+ */
+enum rte_flow_encap_hash_field {
+ /** Calculate hash placed in UDP source port field. */
+ RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
+ /** Calculate hash placed in NVGRE flow ID field. */
+ RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Simulate HW hash calculation that is done when an encap action is being used.
+ * This hash can be stored in tunnel outer header to improve packet distribution.
+ *
+ * @param[in] port_id
+ * Port identifier of Ethernet device.
+ * @param[in] pattern
+ * The values to be used in the hash calculation.
+ * @param[in] dest_field
+ * Type of destination field for hash calculation.
+ * @param[in] hash_len
+ * The length of the hash pointer in bytes. Should be according to dest_field.
+ * @param[out] hash
+ * Used to return the calculated hash. It will be written in network order,
+ * so hash[0] is the MSB.
+ * The number of bytes is based on the destination field type.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ * PMDs initialize this structure in case of error only.
+ *
+ * @return
+ * - (0) if success.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-ENOTSUP) if underlying device does not support this functionality.
+ * - (-EINVAL) if *pattern* doesn't hold enough information to calculate the hash
+ * or the dest is not supported.
+ */
+__rte_experimental
+int
+rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
+ uint8_t *hash, struct rte_flow_error *error);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/ethdev/rte_flow_driver.h b/lib/ethdev/rte_flow_driver.h
index f35f659503..447163655a 100644
--- a/lib/ethdev/rte_flow_driver.h
+++ b/lib/ethdev/rte_flow_driver.h
@@ -370,6 +370,11 @@ struct rte_flow_ops {
(struct rte_eth_dev *dev, const struct rte_flow_template_table *table,
const struct rte_flow_item pattern[], uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+ /** @see rte_flow_calc_encap_hash() */
+ int (*flow_calc_encap_hash)
+ (struct rte_eth_dev *dev, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t *hash,
+ struct rte_flow_error *error);
};
/**
diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
index a050baab0f..360898d067 100644
--- a/lib/ethdev/version.map
+++ b/lib/ethdev/version.map
@@ -319,6 +319,7 @@ EXPERIMENTAL {
# added in 24.03
rte_eth_find_rss_algo;
+ rte_flow_calc_encap_hash;
};
INTERNAL {
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 2/4] net/mlx5/hws: introduce encap entropy hash calculation API
2024-02-13 13:48 ` [PATCH v3 " Ori Kam
@ 2024-02-13 13:48 ` Ori Kam
2024-02-13 13:48 ` [PATCH v3 3/4] net/mlx5: add calc encap hash support Ori Kam
2024-02-13 13:48 ` [PATCH v3 4/4] app/testpmd: add encap hash calculation Ori Kam
2 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-13 13:48 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Viacheslav Ovsiienko, Suanming Mou, Matan Azrad
Cc: dev, orika, rasland, Hamdan Igbaria
From: Hamdan Igbaria <hamdani@nvidia.com>
Add new function for encap entropy hash calculation, the function
will check the device capability for the entropy hash type used
by the device, and will calculate the entropy hash value of the
user passed fields according this type.
Signed-off-by: Hamdan Igbaria <hamdani@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
drivers/common/mlx5/mlx5_prm.h | 8 ++-
drivers/net/mlx5/hws/mlx5dr.h | 38 ++++++++++++++
drivers/net/mlx5/hws/mlx5dr_cmd.c | 23 +++++++++
drivers/net/mlx5/hws/mlx5dr_cmd.h | 4 ++
drivers/net/mlx5/hws/mlx5dr_crc32.c | 78 +++++++++++++++++++++++++++++
drivers/net/mlx5/hws/mlx5dr_crc32.h | 5 ++
6 files changed, 154 insertions(+), 2 deletions(-)
diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h
index abff8e4dc3..50c681704a 100644
--- a/drivers/common/mlx5/mlx5_prm.h
+++ b/drivers/common/mlx5/mlx5_prm.h
@@ -2132,7 +2132,10 @@ struct mlx5_ifc_flow_table_prop_layout_bits {
struct mlx5_ifc_roce_caps_bits {
u8 reserved_0[0x1e];
u8 qp_ts_format[0x2];
- u8 reserved_at_20[0x7e0];
+ u8 reserved_at_20[0xa0];
+ u8 r_roce_max_src_udp_port[0x10];
+ u8 r_roce_min_src_udp_port[0x10];
+ u8 reserved_at_e0[0x720];
};
struct mlx5_ifc_ft_fields_support_bits {
@@ -2370,7 +2373,8 @@ struct mlx5_ifc_cmd_hca_cap_2_bits {
u8 format_select_dw_gtpu_first_ext_dw_0[0x8];
u8 generate_wqe_type[0x20];
u8 reserved_at_2c0[0x160];
- u8 reserved_at_420[0x1c];
+ u8 reserved_at_420[0x18];
+ u8 encap_entropy_hash_type[0x4];
u8 flow_table_hash_type[0x4];
u8 reserved_at_440[0x3c0];
};
diff --git a/drivers/net/mlx5/hws/mlx5dr.h b/drivers/net/mlx5/hws/mlx5dr.h
index d88f73ab57..321b649f8c 100644
--- a/drivers/net/mlx5/hws/mlx5dr.h
+++ b/drivers/net/mlx5/hws/mlx5dr.h
@@ -279,6 +279,27 @@ struct mlx5dr_action_dest_attr {
} reformat;
};
+union mlx5dr_crc_encap_entropy_hash_ip_field {
+ uint8_t ipv6_addr[16];
+ struct {
+ uint8_t reserved[12];
+ rte_be32_t ipv4_addr;
+ };
+};
+
+struct mlx5dr_crc_encap_entropy_hash_fields {
+ union mlx5dr_crc_encap_entropy_hash_ip_field dst;
+ union mlx5dr_crc_encap_entropy_hash_ip_field src;
+ uint8_t next_protocol;
+ rte_be16_t dst_port;
+ rte_be16_t src_port;
+}__rte_packed;
+
+enum mlx5dr_crc_encap_entropy_hash_size {
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8,
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16,
+};
+
/* Open a context used for direct rule insertion using hardware steering.
* Each context can contain multiple tables of different types.
*
@@ -845,4 +866,21 @@ int mlx5dr_send_queue_action(struct mlx5dr_context *ctx,
*/
int mlx5dr_debug_dump(struct mlx5dr_context *ctx, FILE *f);
+/* Calculate encap entropy hash value
+ *
+ * @param[in] ctx
+ * The context to get from it's capabilities the entropy hash type.
+ * @param[in] data
+ * The fields for the hash calculation.
+ * @param[in] entropy_res
+ * An array to store the hash value to it.
+ * @param[in] res_size
+ * The result size.
+ * @return zero on success non zero otherwise.
+ */
+int mlx5dr_crc_encap_entropy_hash_calc(struct mlx5dr_context *ctx,
+ struct mlx5dr_crc_encap_entropy_hash_fields *data,
+ uint8_t entropy_res[],
+ enum mlx5dr_crc_encap_entropy_hash_size res_size);
+
#endif
diff --git a/drivers/net/mlx5/hws/mlx5dr_cmd.c b/drivers/net/mlx5/hws/mlx5dr_cmd.c
index 876a47147d..f77b194708 100644
--- a/drivers/net/mlx5/hws/mlx5dr_cmd.c
+++ b/drivers/net/mlx5/hws/mlx5dr_cmd.c
@@ -1103,6 +1103,8 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
caps->ipsec_offload = MLX5_GET(query_hca_cap_out, out,
capability.cmd_hca_cap.ipsec_offload);
+ caps->roce = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.roce);
+
MLX5_SET(query_hca_cap_in, in, op_mod,
MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE_2 |
MLX5_HCA_CAP_OPMOD_GET_CUR);
@@ -1158,6 +1160,9 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
caps->flow_table_hash_type = MLX5_GET(query_hca_cap_out, out,
capability.cmd_hca_cap_2.flow_table_hash_type);
+ caps->encap_entropy_hash_type = MLX5_GET(query_hca_cap_out, out,
+ capability.cmd_hca_cap_2.encap_entropy_hash_type);
+
MLX5_SET(query_hca_cap_in, in, op_mod,
MLX5_GET_HCA_CAP_OP_MOD_NIC_FLOW_TABLE |
MLX5_HCA_CAP_OPMOD_GET_CUR);
@@ -1306,6 +1311,24 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
capability.esw_cap.merged_eswitch);
}
+ if (caps->roce) {
+ MLX5_SET(query_hca_cap_in, in, op_mod,
+ MLX5_GET_HCA_CAP_OP_MOD_ROCE |
+ MLX5_HCA_CAP_OPMOD_GET_CUR);
+
+ ret = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in), out, sizeof(out));
+ if (ret) {
+ DR_LOG(ERR, "Failed to query roce caps");
+ rte_errno = errno;
+ return rte_errno;
+ }
+
+ caps->roce_max_src_udp_port = MLX5_GET(query_hca_cap_out, out,
+ capability.roce_caps.r_roce_max_src_udp_port);
+ caps->roce_min_src_udp_port = MLX5_GET(query_hca_cap_out, out,
+ capability.roce_caps.r_roce_min_src_udp_port);
+ }
+
ret = mlx5_glue->query_device_ex(ctx, NULL, &attr_ex);
if (ret) {
DR_LOG(ERR, "Failed to query device attributes");
diff --git a/drivers/net/mlx5/hws/mlx5dr_cmd.h b/drivers/net/mlx5/hws/mlx5dr_cmd.h
index 18c2b07fc8..694231e08f 100644
--- a/drivers/net/mlx5/hws/mlx5dr_cmd.h
+++ b/drivers/net/mlx5/hws/mlx5dr_cmd.h
@@ -246,6 +246,10 @@ struct mlx5dr_cmd_query_caps {
uint32_t shared_vhca_id;
char fw_ver[64];
bool ipsec_offload;
+ uint8_t encap_entropy_hash_type;
+ bool roce;
+ uint16_t roce_max_src_udp_port;
+ uint16_t roce_min_src_udp_port;
};
int mlx5dr_cmd_destroy_obj(struct mlx5dr_devx_obj *devx_obj);
diff --git a/drivers/net/mlx5/hws/mlx5dr_crc32.c b/drivers/net/mlx5/hws/mlx5dr_crc32.c
index 9c454eda0c..7431462e14 100644
--- a/drivers/net/mlx5/hws/mlx5dr_crc32.c
+++ b/drivers/net/mlx5/hws/mlx5dr_crc32.c
@@ -50,6 +50,42 @@ uint32_t dr_ste_crc_tab32[] = {
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
+/* CRC table for the CRC-16, the polynome is 0x100b */
+uint16_t dr_crc_inner_crc_tab16[] = {
+ 0x0000, 0x100B, 0x2016, 0x301D, 0x402C, 0x5027, 0x603A, 0x7031,
+ 0x8058, 0x9053, 0xA04E, 0xB045, 0xC074, 0xD07F, 0xE062, 0xF069,
+ 0x10BB, 0x00B0, 0x30AD, 0x20A6, 0x5097, 0x409C, 0x7081, 0x608A,
+ 0x90E3, 0x80E8, 0xB0F5, 0xA0FE, 0xD0CF, 0xC0C4, 0xF0D9, 0xE0D2,
+ 0x2176, 0x317D, 0x0160, 0x116B, 0x615A, 0x7151, 0x414C, 0x5147,
+ 0xA12E, 0xB125, 0x8138, 0x9133, 0xE102, 0xF109, 0xC114, 0xD11F,
+ 0x31CD, 0x21C6, 0x11DB, 0x01D0, 0x71E1, 0x61EA, 0x51F7, 0x41FC,
+ 0xB195, 0xA19E, 0x9183, 0x8188, 0xF1B9, 0xE1B2, 0xD1AF, 0xC1A4,
+ 0x42EC, 0x52E7, 0x62FA, 0x72F1, 0x02C0, 0x12CB, 0x22D6, 0x32DD,
+ 0xC2B4, 0xD2BF, 0xE2A2, 0xF2A9, 0x8298, 0x9293, 0xA28E, 0xB285,
+ 0x5257, 0x425C, 0x7241, 0x624A, 0x127B, 0x0270, 0x326D, 0x2266,
+ 0xD20F, 0xC204, 0xF219, 0xE212, 0x9223, 0x8228, 0xB235, 0xA23E,
+ 0x639A, 0x7391, 0x438C, 0x5387, 0x23B6, 0x33BD, 0x03A0, 0x13AB,
+ 0xE3C2, 0xF3C9, 0xC3D4, 0xD3DF, 0xA3EE, 0xB3E5, 0x83F8, 0x93F3,
+ 0x7321, 0x632A, 0x5337, 0x433C, 0x330D, 0x2306, 0x131B, 0x0310,
+ 0xF379, 0xE372, 0xD36F, 0xC364, 0xB355, 0xA35E, 0x9343, 0x8348,
+ 0x85D8, 0x95D3, 0xA5CE, 0xB5C5, 0xC5F4, 0xD5FF, 0xE5E2, 0xF5E9,
+ 0x0580, 0x158B, 0x2596, 0x359D, 0x45AC, 0x55A7, 0x65BA, 0x75B1,
+ 0x9563, 0x8568, 0xB575, 0xA57E, 0xD54F, 0xC544, 0xF559, 0xE552,
+ 0x153B, 0x0530, 0x352D, 0x2526, 0x5517, 0x451C, 0x7501, 0x650A,
+ 0xA4AE, 0xB4A5, 0x84B8, 0x94B3, 0xE482, 0xF489, 0xC494, 0xD49F,
+ 0x24F6, 0x34FD, 0x04E0, 0x14EB, 0x64DA, 0x74D1, 0x44CC, 0x54C7,
+ 0xB415, 0xA41E, 0x9403, 0x8408, 0xF439, 0xE432, 0xD42F, 0xC424,
+ 0x344D, 0x2446, 0x145B, 0x0450, 0x7461, 0x646A, 0x5477, 0x447C,
+ 0xC734, 0xD73F, 0xE722, 0xF729, 0x8718, 0x9713, 0xA70E, 0xB705,
+ 0x476C, 0x5767, 0x677A, 0x7771, 0x0740, 0x174B, 0x2756, 0x375D,
+ 0xD78F, 0xC784, 0xF799, 0xE792, 0x97A3, 0x87A8, 0xB7B5, 0xA7BE,
+ 0x57D7, 0x47DC, 0x77C1, 0x67CA, 0x17FB, 0x07F0, 0x37ED, 0x27E6,
+ 0xE642, 0xF649, 0xC654, 0xD65F, 0xA66E, 0xB665, 0x8678, 0x9673,
+ 0x661A, 0x7611, 0x460C, 0x5607, 0x2636, 0x363D, 0x0620, 0x162B,
+ 0xF6F9, 0xE6F2, 0xD6EF, 0xC6E4, 0xB6D5, 0xA6DE, 0x96C3, 0x86C8,
+ 0x76A1, 0x66AA, 0x56B7, 0x46BC, 0x368D, 0x2686, 0x169B, 0x0690
+};
+
uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len)
{
uint32_t crc = 0;
@@ -59,3 +95,45 @@ uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len)
return rte_be_to_cpu_32(crc);
}
+
+uint16_t mlx5dr_crc16_calc(uint8_t *p, size_t len, uint16_t crc_tab16[])
+{
+ uint16_t crc = 0;
+
+ while (len--)
+ crc = (crc << 8) ^ crc_tab16[((crc >> 8) ^ *p++) & 0xff];
+
+ return crc;
+}
+
+int mlx5dr_crc_encap_entropy_hash_calc(struct mlx5dr_context *ctx,
+ struct mlx5dr_crc_encap_entropy_hash_fields *data,
+ uint8_t entropy_res[],
+ enum mlx5dr_crc_encap_entropy_hash_size res_size)
+{
+ struct mlx5dr_cmd_query_caps *caps = ctx->caps;
+ uint16_t max_hash, min_hash, res;
+
+ if (caps->encap_entropy_hash_type) {
+ DR_LOG(ERR, "calculation of encap_entropy_hash_type 0x%x not supported",
+ caps->encap_entropy_hash_type);
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ max_hash = caps->roce_max_src_udp_port;
+ min_hash = caps->roce_min_src_udp_port;
+
+ res = mlx5dr_crc16_calc((uint8_t *)data, sizeof(*data), dr_crc_inner_crc_tab16);
+
+ if (res_size == MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16) {
+ *(uint16_t *)entropy_res = rte_cpu_to_be_16((min_hash | res) & max_hash);
+ } else if (res_size == MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8) {
+ *entropy_res = (uint8_t)(res & 0xff);
+ } else {
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/mlx5/hws/mlx5dr_crc32.h b/drivers/net/mlx5/hws/mlx5dr_crc32.h
index 9aab9e06ca..75b6009a15 100644
--- a/drivers/net/mlx5/hws/mlx5dr_crc32.h
+++ b/drivers/net/mlx5/hws/mlx5dr_crc32.h
@@ -10,4 +10,9 @@
*/
uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len);
+/* Standard CRC16 calculation using the crc_tab16 param to indicate
+ * the pre-calculated polynome hash values.
+ */
+uint16_t mlx5dr_crc16_calc(uint8_t *p, size_t len, uint16_t crc_tab16[]);
+
#endif /* MLX5DR_CRC32_C_ */
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 3/4] net/mlx5: add calc encap hash support
2024-02-13 13:48 ` [PATCH v3 " Ori Kam
2024-02-13 13:48 ` [PATCH v3 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
@ 2024-02-13 13:48 ` Ori Kam
2024-02-13 13:48 ` [PATCH v3 4/4] app/testpmd: add encap hash calculation Ori Kam
2 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-13 13:48 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Viacheslav Ovsiienko, Suanming Mou, Matan Azrad
Cc: dev, orika, rasland
This commit adds support for encap hash calculation.
Signed-off-by: Ori Kam <orika@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
drivers/net/mlx5/mlx5_flow.c | 29 +++++++++++++++
drivers/net/mlx5/mlx5_flow.h | 8 ++++
drivers/net/mlx5/mlx5_flow_hw.c | 66 +++++++++++++++++++++++++++++++++
3 files changed, 103 insertions(+)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 40376c99ba..7c5a5da8ec 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1197,6 +1197,12 @@ mlx5_flow_calc_table_hash(struct rte_eth_dev *dev,
const struct rte_flow_item pattern[],
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+static int
+mlx5_flow_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error);
static const struct rte_flow_ops mlx5_flow_ops = {
.validate = mlx5_flow_validate,
@@ -1253,6 +1259,7 @@ static const struct rte_flow_ops mlx5_flow_ops = {
.async_action_list_handle_query_update =
mlx5_flow_async_action_list_handle_query_update,
.flow_calc_table_hash = mlx5_flow_calc_table_hash,
+ .flow_calc_encap_hash = mlx5_flow_calc_encap_hash,
};
/* Tunnel information. */
@@ -11121,6 +11128,28 @@ mlx5_flow_calc_table_hash(struct rte_eth_dev *dev,
hash, error);
}
+static int
+mlx5_flow_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error)
+{
+ enum mlx5_flow_drv_type drv_type = flow_get_drv_type(dev, NULL);
+ const struct mlx5_flow_driver_ops *fops;
+
+ if (drv_type == MLX5_FLOW_TYPE_MIN || drv_type == MLX5_FLOW_TYPE_MAX)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "invalid driver type");
+ fops = flow_get_drv_ops(drv_type);
+ if (!fops || !fops->flow_calc_encap_hash)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "no calc encap hash handler");
+ return fops->flow_calc_encap_hash(dev, pattern, dest_field, hash, error);
+}
+
/**
* Destroy all indirect actions (shared RSS).
*
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index b086dfaf28..a4d0ff7b13 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -2198,6 +2198,13 @@ typedef int
const struct rte_flow_item pattern[],
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+typedef int
+(*mlx5_flow_calc_encap_hash_t)
+ (struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error);
struct mlx5_flow_driver_ops {
mlx5_flow_validate_t validate;
@@ -2271,6 +2278,7 @@ struct mlx5_flow_driver_ops {
mlx5_flow_async_action_list_handle_query_update_t
async_action_list_handle_query_update;
mlx5_flow_calc_table_hash_t flow_calc_table_hash;
+ mlx5_flow_calc_encap_hash_t flow_calc_encap_hash;
};
/* mlx5_flow.c */
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index 3af5e1f160..ce2fb7c5f9 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -11701,6 +11701,71 @@ flow_hw_calc_table_hash(struct rte_eth_dev *dev,
return 0;
}
+static int
+flow_hw_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5dr_crc_encap_entropy_hash_fields data;
+ enum mlx5dr_crc_encap_entropy_hash_size res_size =
+ dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT ?
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16 :
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8;
+ int res;
+
+ memset(&data, 0, sizeof(struct mlx5dr_crc_encap_entropy_hash_fields));
+
+ for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+ switch (pattern->type) {
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ data.dst.ipv4_addr =
+ ((const struct rte_flow_item_ipv4 *)(pattern->spec))->hdr.dst_addr;
+ data.src.ipv4_addr =
+ ((const struct rte_flow_item_ipv4 *)(pattern->spec))->hdr.src_addr;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ memcpy(data.dst.ipv6_addr,
+ ((const struct rte_flow_item_ipv6 *)(pattern->spec))->hdr.dst_addr,
+ sizeof(data.dst.ipv6_addr));
+ memcpy(data.src.ipv6_addr,
+ ((const struct rte_flow_item_ipv6 *)(pattern->spec))->hdr.src_addr,
+ sizeof(data.src.ipv6_addr));
+ break;
+ case RTE_FLOW_ITEM_TYPE_UDP:
+ data.next_protocol = IPPROTO_UDP;
+ data.dst_port =
+ ((const struct rte_flow_item_udp *)(pattern->spec))->hdr.dst_port;
+ data.src_port =
+ ((const struct rte_flow_item_udp *)(pattern->spec))->hdr.src_port;
+ break;
+ case RTE_FLOW_ITEM_TYPE_TCP:
+ data.next_protocol = IPPROTO_TCP;
+ data.dst_port =
+ ((const struct rte_flow_item_tcp *)(pattern->spec))->hdr.dst_port;
+ data.src_port =
+ ((const struct rte_flow_item_tcp *)(pattern->spec))->hdr.src_port;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ICMP:
+ data.next_protocol = IPPROTO_ICMP;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ICMP6:
+ data.next_protocol = IPPROTO_ICMPV6;
+ break;
+ default:
+ break;
+ }
+ }
+ res = mlx5dr_crc_encap_entropy_hash_calc(priv->dr_ctx, &data, hash, res_size);
+ if (res)
+ return rte_flow_error_set(error, res,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "error while calculating encap hash");
+ return 0;
+}
+
const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
.info_get = flow_hw_info_get,
.configure = flow_hw_configure,
@@ -11746,6 +11811,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
.item_create = flow_dv_item_create,
.item_release = flow_dv_item_release,
.flow_calc_table_hash = flow_hw_calc_table_hash,
+ .flow_calc_encap_hash = flow_hw_calc_encap_hash,
};
/**
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v3 4/4] app/testpmd: add encap hash calculation
2024-02-13 13:48 ` [PATCH v3 " Ori Kam
2024-02-13 13:48 ` [PATCH v3 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
2024-02-13 13:48 ` [PATCH v3 3/4] net/mlx5: add calc encap hash support Ori Kam
@ 2024-02-13 13:48 ` Ori Kam
2 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-13 13:48 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Aman Singh, Yuying Zhang
Cc: dev, orika, rasland
This commits add support for calculating the encap hash.
Command structure:
flow hash {port} encap {target field} pattern {item} [/ {item} [...] ] / end
Example:
calculate hash to be used by VXLAN encapsulation.
flow hash 0 encap hash_field_sport pattern ipv4 dst is 7.7.7.7 src is 8.8.8.8 / udp dst is 5678 src is 1234 / end
Signed-off-by: Ori Kam <orika@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
app/test-pmd/cmdline_flow.c | 57 +++++++++++++++++++--
app/test-pmd/config.c | 30 +++++++++++
app/test-pmd/testpmd.h | 3 ++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 21 +++++++-
4 files changed, 106 insertions(+), 5 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index a4131e1b39..844840fe2d 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -219,6 +219,10 @@ enum index {
HASH_CALC_TABLE,
HASH_CALC_PATTERN_INDEX,
HASH_CALC_PATTERN,
+ HASH_CALC_ENCAP,
+ HASH_CALC_DEST,
+ ENCAP_HASH_FIELD_SRC_PORT,
+ ENCAP_HASH_FIELD_GRE_FLOW_ID,
/* Tunnel arguments. */
TUNNEL_CREATE,
@@ -1220,6 +1224,8 @@ struct buffer {
uint32_t pattern_n;
uint32_t actions_n;
uint8_t *data;
+ enum rte_flow_encap_hash_field field;
+ uint8_t encap_hash;
} vc; /**< Validate/create arguments. */
struct {
uint64_t *rule;
@@ -2618,6 +2624,18 @@ static const enum index action_nat64[] = {
ZERO,
};
+static const enum index next_hash_subcmd[] = {
+ HASH_CALC_TABLE,
+ HASH_CALC_ENCAP,
+ ZERO,
+};
+
+static const enum index next_hash_encap_dest_subcmd[] = {
+ ENCAP_HASH_FIELD_SRC_PORT,
+ ENCAP_HASH_FIELD_GRE_FLOW_ID,
+ ZERO,
+};
+
static int parse_set_raw_encap_decap(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
@@ -3875,7 +3893,7 @@ static const struct token token_list[] = {
[HASH] = {
.name = "hash",
.help = "calculate hash for a given pattern in a given template table",
- .next = NEXT(NEXT_ENTRY(HASH_CALC_TABLE), NEXT_ENTRY(COMMON_PORT_ID)),
+ .next = NEXT(next_hash_subcmd, NEXT_ENTRY(COMMON_PORT_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_hash,
},
@@ -3889,6 +3907,12 @@ static const struct token token_list[] = {
args.vc.table_id)),
.call = parse_hash,
},
+ [HASH_CALC_ENCAP] = {
+ .name = "encap",
+ .help = "calculates encap hash",
+ .next = NEXT(next_hash_encap_dest_subcmd),
+ .call = parse_hash,
+ },
[HASH_CALC_PATTERN_INDEX] = {
.name = "pattern_template",
.help = "specify pattern template id",
@@ -3898,6 +3922,18 @@ static const struct token token_list[] = {
args.vc.pat_templ_id)),
.call = parse_hash,
},
+ [ENCAP_HASH_FIELD_SRC_PORT] = {
+ .name = "hash_field_sport",
+ .help = "the encap hash field is src port",
+ .next = NEXT(NEXT_ENTRY(ITEM_PATTERN)),
+ .call = parse_hash,
+ },
+ [ENCAP_HASH_FIELD_GRE_FLOW_ID] = {
+ .name = "hash_field_flow_id",
+ .help = "the encap hash field is NVGRE flow id",
+ .next = NEXT(NEXT_ENTRY(ITEM_PATTERN)),
+ .call = parse_hash,
+ },
/* Top-level command. */
[INDIRECT_ACTION] = {
.name = "indirect_action",
@@ -11075,6 +11111,15 @@ parse_hash(struct context *ctx, const struct token *token,
ctx->object = out->args.vc.pattern;
ctx->objmask = NULL;
return len;
+ case HASH_CALC_ENCAP:
+ out->args.vc.encap_hash = 1;
+ return len;
+ case ENCAP_HASH_FIELD_SRC_PORT:
+ out->args.vc.field = RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT;
+ return len;
+ case ENCAP_HASH_FIELD_GRE_FLOW_ID:
+ out->args.vc.field = RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID;
+ return len;
default:
return -1;
}
@@ -13068,9 +13113,13 @@ cmd_flow_parsed(const struct buffer *in)
port_queue_flow_pull(in->port, in->queue);
break;
case HASH:
- port_flow_hash_calc(in->port, in->args.vc.table_id,
- in->args.vc.pat_templ_id,
- in->args.vc.pattern);
+ if (!in->args.vc.encap_hash)
+ port_flow_hash_calc(in->port, in->args.vc.table_id,
+ in->args.vc.pat_templ_id,
+ in->args.vc.pattern);
+ else
+ port_flow_hash_calc_encap(in->port, in->args.vc.field,
+ in->args.vc.pattern);
break;
case QUEUE_AGED:
port_queue_flow_aged(in->port, in->queue,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index cad7537bc6..e26b5bd18d 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -3339,6 +3339,36 @@ port_flow_hash_calc(portid_t port_id, uint32_t table_id,
return 0;
}
+/** Calculate the encap hash result for a given pattern. */
+int
+port_flow_hash_calc_encap(portid_t port_id,
+ enum rte_flow_encap_hash_field encap_hash_field,
+ const struct rte_flow_item pattern[])
+{
+ struct rte_flow_error error;
+ int ret = 0;
+ uint16_t hash = 0;
+ uint8_t len = encap_hash_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT ? 2 : 1;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL) {
+ printf("Failed to calculate encap hash - not a valid port");
+ return -EINVAL;
+ }
+
+ ret = rte_flow_calc_encap_hash(port_id, pattern, encap_hash_field, len,
+ (uint8_t *)&hash, &error);
+ if (ret < 0) {
+ printf("Failed to calculate encap hash");
+ return ret;
+ }
+ if (encap_hash_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT)
+ printf("encap hash result %#x\n", hash);
+ else
+ printf("encap hash result %#x\n", *(uint8_t *)&hash);
+ return 0;
+}
+
/** Pull queue operation results from the queue. */
static int
port_queue_aged_flow_destroy(portid_t port_id, queueid_t queue_id,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 9b10a9ea1c..e18546c46e 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -1016,6 +1016,9 @@ int port_queue_flow_push(portid_t port_id, queueid_t queue_id);
int port_queue_flow_pull(portid_t port_id, queueid_t queue_id);
int port_flow_hash_calc(portid_t port_id, uint32_t table_id,
uint8_t pattern_template_index, const struct rte_flow_item pattern[]);
+int port_flow_hash_calc_encap(portid_t port_id,
+ enum rte_flow_encap_hash_field encap_hash_field,
+ const struct rte_flow_item pattern[]);
void port_queue_flow_aged(portid_t port_id, uint32_t queue_id, uint8_t destroy);
int port_flow_validate(portid_t port_id,
const struct rte_flow_attr *attr,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 08a0b59535..bf48f01b0a 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -3297,7 +3297,7 @@ The usual error message is shown when operations results cannot be pulled::
Calculating hash
~~~~~~~~~~~~~~~~
-``flow hash`` calculates the hash for a given pattern.
+``flow hash {port_id} template_table`` calculates the hash for a given pattern.
It is bound to ``rte_flow_calc_table_hash()``::
flow hash {port_id} template_table {table_id}
@@ -3316,6 +3316,25 @@ Otherwise, it will show an error message of the form::
This command uses the same pattern items as ``flow create``,
their format is described in `Creating flow rules`_.
+
+Simulate encap hash calculation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``flow hash {port_id} encap`` adds hash query, that returns the hash value
+that the HW will calculate when encapsulating a packet.
+
+ flow hash {port_id} encap {target field} pattern {item} [/ {item} [...]] / end
+
+If successful, it will show::
+
+ encap hash result #[...]
+
+The value will be shown as uint16_t without endian conversion.
+
+Otherwise it will show an error message of the form::
+
+ Failed to calculate encap hash - [...]
+
Creating a tunnel stub for offload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v4 1/4] ethdev: introduce encap hash calculation
2024-01-28 9:39 [PATCH 0/4] introduce encap hash calculation Ori Kam
` (6 preceding siblings ...)
2024-02-13 13:48 ` [PATCH v3 " Ori Kam
@ 2024-02-13 14:16 ` Ori Kam
2024-02-13 14:16 ` [PATCH v4 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
` (3 more replies)
7 siblings, 4 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-13 14:16 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Thomas Monjalon
Cc: dev, orika, rasland
During encapsulation of a packet, it is possible to change some
outer headers to improve flow destribution.
For example, from VXLAN RFC:
"It is recommended that the UDP source port number
be calculated using a hash of fields from the inner packet --
one example being a hash of the inner Ethernet frame's headers.
This is to enable a level of entropy for the ECMP/load-balancing"
The tunnel protocol defines which outer field should hold this hash,
but it doesn't define the hash calculation algorithm.
An application that uses flow offloads gets the first few packets
(exception path) and then decides to offload the flow.
As a result, there are two
different paths that a packet from a given flow may take.
SW for the first few packets or HW for the rest.
When the packet goes through the SW, the SW encapsulates the packet
and must use the same hash calculation as the HW will do for
the rest of the packets in this flow.
the new function rte_flow_calc_encap_hash can query the hash value
from the driver for a given packet as if the packet was passed
through the HW.
Signed-off-by: Ori Kam <orika@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
doc/guides/prog_guide/rte_flow.rst | 14 +++++++
doc/guides/rel_notes/release_24_03.rst | 6 ++-
lib/ethdev/rte_flow.c | 29 ++++++++++++++
lib/ethdev/rte_flow.h | 53 ++++++++++++++++++++++++++
lib/ethdev/rte_flow_driver.h | 5 +++
lib/ethdev/version.map | 1 +
6 files changed, 107 insertions(+), 1 deletion(-)
diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 34dc06ec66..294862d502 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -4226,6 +4226,20 @@ as it would be calculated in the HW.
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+Calculate encapsulation hash
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Calculating hash of a packet as it would be calculated by the HW, when encapsulating
+a packet.
+
+When the HW execute an encapsulation action, for example VXLAN tunnel,
+it may calculate an hash of the packet to be encapsulated.
+This hash is stored in the outer header of the tunnel.
+This allow better spreading of traffic.
+
+This function can be used for packets of a flow that are not offloaded and
+pass through the SW instead of the HW, for example, SYN/FIN packets.
+
.. _flow_isolated_mode:
Flow isolated mode
diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst
index 358998e988..cf114ead89 100644
--- a/doc/guides/rel_notes/release_24_03.rst
+++ b/doc/guides/rel_notes/release_24_03.rst
@@ -60,6 +60,11 @@ New Features
* Added new function ``rte_eth_find_rss_algo`` to get RSS hash
algorithm by its name.
+* **Added hash calculation of an encapsulated packet as done by the HW.**
+
+ Added function to calculate hash when doing tunnel encapsulation:
+ ``rte_flow_calc_encap_hash()``
+
* **Added flow matching of random value.**
* Added ``RTE_FLOW_ITEM_TYPE_RANDOM`` to match random value.
@@ -102,7 +107,6 @@ New Features
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_OPT_CLASS`` flow action.
* Added HW steering support for modify field ``RTE_FLOW_FIELD_GENEVE_OPT_DATA`` flow action.
-
Removed Items
-------------
diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
index b06da0cc00..7a4f7a94f6 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -2484,3 +2484,32 @@ rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
hash, error);
return flow_err(port_id, ret, error);
}
+
+int
+rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
+ uint8_t *hash, struct rte_flow_error *error)
+{
+ int ret;
+ struct rte_eth_dev *dev;
+ const struct rte_flow_ops *ops;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+ ops = rte_flow_ops_get(port_id, error);
+ if (!ops || !ops->flow_calc_encap_hash)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "calc encap hash is not supported");
+ if (dest_field > RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "hash dest field is not defined");
+ if ((dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT && hash_len != 2) ||
+ (dest_field == RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID && hash_len != 1))
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "hash len doesn't match the requested field len");
+ dev = &rte_eth_devices[port_id];
+ ret = ops->flow_calc_encap_hash(dev, pattern, dest_field, hash, error);
+ return flow_err(port_id, ret, error);
+}
diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
index 09c1b13381..48e4f47844 100644
--- a/lib/ethdev/rte_flow.h
+++ b/lib/ethdev/rte_flow.h
@@ -6846,6 +6846,59 @@ rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
const struct rte_flow_item pattern[], uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Destination field type for the hash calculation, when encap action is used.
+ * The encap field implies the size, meaning XXX_SRC_PORT hash len is 2 bytes,
+ * while XXX_NVGRE_FLOW_ID hash len is 1 byte.
+ *
+ * @see function rte_flow_calc_encap_hash
+ */
+enum rte_flow_encap_hash_field {
+ /** Calculate hash placed in UDP source port field. */
+ RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT,
+ /** Calculate hash placed in NVGRE flow ID field. */
+ RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Simulate HW hash calculation that is done when an encap action is being used.
+ * This hash can be stored in tunnel outer header to improve packet distribution.
+ *
+ * @param[in] port_id
+ * Port identifier of Ethernet device.
+ * @param[in] pattern
+ * The values to be used in the hash calculation.
+ * @param[in] dest_field
+ * Type of destination field for hash calculation.
+ * @param[in] hash_len
+ * The length of the hash pointer in bytes. Should be according to dest_field.
+ * @param[out] hash
+ * Used to return the calculated hash. It will be written in network order,
+ * so hash[0] is the MSB.
+ * The number of bytes is based on the destination field type.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ * PMDs initialize this structure in case of error only.
+ *
+ * @return
+ * - (0) if success.
+ * - (-ENODEV) if *port_id* invalid.
+ * - (-ENOTSUP) if underlying device does not support this functionality.
+ * - (-EINVAL) if *pattern* doesn't hold enough information to calculate the hash
+ * or the dest is not supported.
+ */
+__rte_experimental
+int
+rte_flow_calc_encap_hash(uint16_t port_id, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t hash_len,
+ uint8_t *hash, struct rte_flow_error *error);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/ethdev/rte_flow_driver.h b/lib/ethdev/rte_flow_driver.h
index f35f659503..447163655a 100644
--- a/lib/ethdev/rte_flow_driver.h
+++ b/lib/ethdev/rte_flow_driver.h
@@ -370,6 +370,11 @@ struct rte_flow_ops {
(struct rte_eth_dev *dev, const struct rte_flow_template_table *table,
const struct rte_flow_item pattern[], uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+ /** @see rte_flow_calc_encap_hash() */
+ int (*flow_calc_encap_hash)
+ (struct rte_eth_dev *dev, const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field, uint8_t *hash,
+ struct rte_flow_error *error);
};
/**
diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
index a050baab0f..360898d067 100644
--- a/lib/ethdev/version.map
+++ b/lib/ethdev/version.map
@@ -319,6 +319,7 @@ EXPERIMENTAL {
# added in 24.03
rte_eth_find_rss_algo;
+ rte_flow_calc_encap_hash;
};
INTERNAL {
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v4 2/4] net/mlx5/hws: introduce encap entropy hash calculation API
2024-02-13 14:16 ` [PATCH v4 1/4] ethdev: introduce " Ori Kam
@ 2024-02-13 14:16 ` Ori Kam
2024-02-13 14:16 ` [PATCH v4 3/4] net/mlx5: add calc encap hash support Ori Kam
` (2 subsequent siblings)
3 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-13 14:16 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Viacheslav Ovsiienko, Suanming Mou, Matan Azrad
Cc: dev, orika, rasland, Hamdan Igbaria
From: Hamdan Igbaria <hamdani@nvidia.com>
Add new function for encap entropy hash calculation, the function
will check the device capability for the entropy hash type used
by the device, and will calculate the entropy hash value of the
user passed fields according this type.
Signed-off-by: Hamdan Igbaria <hamdani@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
drivers/common/mlx5/mlx5_prm.h | 8 ++-
drivers/net/mlx5/hws/mlx5dr.h | 38 ++++++++++++++
drivers/net/mlx5/hws/mlx5dr_cmd.c | 23 +++++++++
drivers/net/mlx5/hws/mlx5dr_cmd.h | 4 ++
drivers/net/mlx5/hws/mlx5dr_crc32.c | 78 +++++++++++++++++++++++++++++
drivers/net/mlx5/hws/mlx5dr_crc32.h | 5 ++
6 files changed, 154 insertions(+), 2 deletions(-)
diff --git a/drivers/common/mlx5/mlx5_prm.h b/drivers/common/mlx5/mlx5_prm.h
index abff8e4dc3..50c681704a 100644
--- a/drivers/common/mlx5/mlx5_prm.h
+++ b/drivers/common/mlx5/mlx5_prm.h
@@ -2132,7 +2132,10 @@ struct mlx5_ifc_flow_table_prop_layout_bits {
struct mlx5_ifc_roce_caps_bits {
u8 reserved_0[0x1e];
u8 qp_ts_format[0x2];
- u8 reserved_at_20[0x7e0];
+ u8 reserved_at_20[0xa0];
+ u8 r_roce_max_src_udp_port[0x10];
+ u8 r_roce_min_src_udp_port[0x10];
+ u8 reserved_at_e0[0x720];
};
struct mlx5_ifc_ft_fields_support_bits {
@@ -2370,7 +2373,8 @@ struct mlx5_ifc_cmd_hca_cap_2_bits {
u8 format_select_dw_gtpu_first_ext_dw_0[0x8];
u8 generate_wqe_type[0x20];
u8 reserved_at_2c0[0x160];
- u8 reserved_at_420[0x1c];
+ u8 reserved_at_420[0x18];
+ u8 encap_entropy_hash_type[0x4];
u8 flow_table_hash_type[0x4];
u8 reserved_at_440[0x3c0];
};
diff --git a/drivers/net/mlx5/hws/mlx5dr.h b/drivers/net/mlx5/hws/mlx5dr.h
index d88f73ab57..9c5b068c93 100644
--- a/drivers/net/mlx5/hws/mlx5dr.h
+++ b/drivers/net/mlx5/hws/mlx5dr.h
@@ -279,6 +279,27 @@ struct mlx5dr_action_dest_attr {
} reformat;
};
+union mlx5dr_crc_encap_entropy_hash_ip_field {
+ uint8_t ipv6_addr[16];
+ struct {
+ uint8_t reserved[12];
+ rte_be32_t ipv4_addr;
+ };
+};
+
+struct mlx5dr_crc_encap_entropy_hash_fields {
+ union mlx5dr_crc_encap_entropy_hash_ip_field dst;
+ union mlx5dr_crc_encap_entropy_hash_ip_field src;
+ uint8_t next_protocol;
+ rte_be16_t dst_port;
+ rte_be16_t src_port;
+} __rte_packed;
+
+enum mlx5dr_crc_encap_entropy_hash_size {
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8,
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16,
+};
+
/* Open a context used for direct rule insertion using hardware steering.
* Each context can contain multiple tables of different types.
*
@@ -845,4 +866,21 @@ int mlx5dr_send_queue_action(struct mlx5dr_context *ctx,
*/
int mlx5dr_debug_dump(struct mlx5dr_context *ctx, FILE *f);
+/* Calculate encap entropy hash value
+ *
+ * @param[in] ctx
+ * The context to get from it's capabilities the entropy hash type.
+ * @param[in] data
+ * The fields for the hash calculation.
+ * @param[in] entropy_res
+ * An array to store the hash value to it.
+ * @param[in] res_size
+ * The result size.
+ * @return zero on success non zero otherwise.
+ */
+int mlx5dr_crc_encap_entropy_hash_calc(struct mlx5dr_context *ctx,
+ struct mlx5dr_crc_encap_entropy_hash_fields *data,
+ uint8_t entropy_res[],
+ enum mlx5dr_crc_encap_entropy_hash_size res_size);
+
#endif
diff --git a/drivers/net/mlx5/hws/mlx5dr_cmd.c b/drivers/net/mlx5/hws/mlx5dr_cmd.c
index 876a47147d..f77b194708 100644
--- a/drivers/net/mlx5/hws/mlx5dr_cmd.c
+++ b/drivers/net/mlx5/hws/mlx5dr_cmd.c
@@ -1103,6 +1103,8 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
caps->ipsec_offload = MLX5_GET(query_hca_cap_out, out,
capability.cmd_hca_cap.ipsec_offload);
+ caps->roce = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.roce);
+
MLX5_SET(query_hca_cap_in, in, op_mod,
MLX5_GET_HCA_CAP_OP_MOD_GENERAL_DEVICE_2 |
MLX5_HCA_CAP_OPMOD_GET_CUR);
@@ -1158,6 +1160,9 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
caps->flow_table_hash_type = MLX5_GET(query_hca_cap_out, out,
capability.cmd_hca_cap_2.flow_table_hash_type);
+ caps->encap_entropy_hash_type = MLX5_GET(query_hca_cap_out, out,
+ capability.cmd_hca_cap_2.encap_entropy_hash_type);
+
MLX5_SET(query_hca_cap_in, in, op_mod,
MLX5_GET_HCA_CAP_OP_MOD_NIC_FLOW_TABLE |
MLX5_HCA_CAP_OPMOD_GET_CUR);
@@ -1306,6 +1311,24 @@ int mlx5dr_cmd_query_caps(struct ibv_context *ctx,
capability.esw_cap.merged_eswitch);
}
+ if (caps->roce) {
+ MLX5_SET(query_hca_cap_in, in, op_mod,
+ MLX5_GET_HCA_CAP_OP_MOD_ROCE |
+ MLX5_HCA_CAP_OPMOD_GET_CUR);
+
+ ret = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in), out, sizeof(out));
+ if (ret) {
+ DR_LOG(ERR, "Failed to query roce caps");
+ rte_errno = errno;
+ return rte_errno;
+ }
+
+ caps->roce_max_src_udp_port = MLX5_GET(query_hca_cap_out, out,
+ capability.roce_caps.r_roce_max_src_udp_port);
+ caps->roce_min_src_udp_port = MLX5_GET(query_hca_cap_out, out,
+ capability.roce_caps.r_roce_min_src_udp_port);
+ }
+
ret = mlx5_glue->query_device_ex(ctx, NULL, &attr_ex);
if (ret) {
DR_LOG(ERR, "Failed to query device attributes");
diff --git a/drivers/net/mlx5/hws/mlx5dr_cmd.h b/drivers/net/mlx5/hws/mlx5dr_cmd.h
index 18c2b07fc8..694231e08f 100644
--- a/drivers/net/mlx5/hws/mlx5dr_cmd.h
+++ b/drivers/net/mlx5/hws/mlx5dr_cmd.h
@@ -246,6 +246,10 @@ struct mlx5dr_cmd_query_caps {
uint32_t shared_vhca_id;
char fw_ver[64];
bool ipsec_offload;
+ uint8_t encap_entropy_hash_type;
+ bool roce;
+ uint16_t roce_max_src_udp_port;
+ uint16_t roce_min_src_udp_port;
};
int mlx5dr_cmd_destroy_obj(struct mlx5dr_devx_obj *devx_obj);
diff --git a/drivers/net/mlx5/hws/mlx5dr_crc32.c b/drivers/net/mlx5/hws/mlx5dr_crc32.c
index 9c454eda0c..7431462e14 100644
--- a/drivers/net/mlx5/hws/mlx5dr_crc32.c
+++ b/drivers/net/mlx5/hws/mlx5dr_crc32.c
@@ -50,6 +50,42 @@ uint32_t dr_ste_crc_tab32[] = {
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
+/* CRC table for the CRC-16, the polynome is 0x100b */
+uint16_t dr_crc_inner_crc_tab16[] = {
+ 0x0000, 0x100B, 0x2016, 0x301D, 0x402C, 0x5027, 0x603A, 0x7031,
+ 0x8058, 0x9053, 0xA04E, 0xB045, 0xC074, 0xD07F, 0xE062, 0xF069,
+ 0x10BB, 0x00B0, 0x30AD, 0x20A6, 0x5097, 0x409C, 0x7081, 0x608A,
+ 0x90E3, 0x80E8, 0xB0F5, 0xA0FE, 0xD0CF, 0xC0C4, 0xF0D9, 0xE0D2,
+ 0x2176, 0x317D, 0x0160, 0x116B, 0x615A, 0x7151, 0x414C, 0x5147,
+ 0xA12E, 0xB125, 0x8138, 0x9133, 0xE102, 0xF109, 0xC114, 0xD11F,
+ 0x31CD, 0x21C6, 0x11DB, 0x01D0, 0x71E1, 0x61EA, 0x51F7, 0x41FC,
+ 0xB195, 0xA19E, 0x9183, 0x8188, 0xF1B9, 0xE1B2, 0xD1AF, 0xC1A4,
+ 0x42EC, 0x52E7, 0x62FA, 0x72F1, 0x02C0, 0x12CB, 0x22D6, 0x32DD,
+ 0xC2B4, 0xD2BF, 0xE2A2, 0xF2A9, 0x8298, 0x9293, 0xA28E, 0xB285,
+ 0x5257, 0x425C, 0x7241, 0x624A, 0x127B, 0x0270, 0x326D, 0x2266,
+ 0xD20F, 0xC204, 0xF219, 0xE212, 0x9223, 0x8228, 0xB235, 0xA23E,
+ 0x639A, 0x7391, 0x438C, 0x5387, 0x23B6, 0x33BD, 0x03A0, 0x13AB,
+ 0xE3C2, 0xF3C9, 0xC3D4, 0xD3DF, 0xA3EE, 0xB3E5, 0x83F8, 0x93F3,
+ 0x7321, 0x632A, 0x5337, 0x433C, 0x330D, 0x2306, 0x131B, 0x0310,
+ 0xF379, 0xE372, 0xD36F, 0xC364, 0xB355, 0xA35E, 0x9343, 0x8348,
+ 0x85D8, 0x95D3, 0xA5CE, 0xB5C5, 0xC5F4, 0xD5FF, 0xE5E2, 0xF5E9,
+ 0x0580, 0x158B, 0x2596, 0x359D, 0x45AC, 0x55A7, 0x65BA, 0x75B1,
+ 0x9563, 0x8568, 0xB575, 0xA57E, 0xD54F, 0xC544, 0xF559, 0xE552,
+ 0x153B, 0x0530, 0x352D, 0x2526, 0x5517, 0x451C, 0x7501, 0x650A,
+ 0xA4AE, 0xB4A5, 0x84B8, 0x94B3, 0xE482, 0xF489, 0xC494, 0xD49F,
+ 0x24F6, 0x34FD, 0x04E0, 0x14EB, 0x64DA, 0x74D1, 0x44CC, 0x54C7,
+ 0xB415, 0xA41E, 0x9403, 0x8408, 0xF439, 0xE432, 0xD42F, 0xC424,
+ 0x344D, 0x2446, 0x145B, 0x0450, 0x7461, 0x646A, 0x5477, 0x447C,
+ 0xC734, 0xD73F, 0xE722, 0xF729, 0x8718, 0x9713, 0xA70E, 0xB705,
+ 0x476C, 0x5767, 0x677A, 0x7771, 0x0740, 0x174B, 0x2756, 0x375D,
+ 0xD78F, 0xC784, 0xF799, 0xE792, 0x97A3, 0x87A8, 0xB7B5, 0xA7BE,
+ 0x57D7, 0x47DC, 0x77C1, 0x67CA, 0x17FB, 0x07F0, 0x37ED, 0x27E6,
+ 0xE642, 0xF649, 0xC654, 0xD65F, 0xA66E, 0xB665, 0x8678, 0x9673,
+ 0x661A, 0x7611, 0x460C, 0x5607, 0x2636, 0x363D, 0x0620, 0x162B,
+ 0xF6F9, 0xE6F2, 0xD6EF, 0xC6E4, 0xB6D5, 0xA6DE, 0x96C3, 0x86C8,
+ 0x76A1, 0x66AA, 0x56B7, 0x46BC, 0x368D, 0x2686, 0x169B, 0x0690
+};
+
uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len)
{
uint32_t crc = 0;
@@ -59,3 +95,45 @@ uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len)
return rte_be_to_cpu_32(crc);
}
+
+uint16_t mlx5dr_crc16_calc(uint8_t *p, size_t len, uint16_t crc_tab16[])
+{
+ uint16_t crc = 0;
+
+ while (len--)
+ crc = (crc << 8) ^ crc_tab16[((crc >> 8) ^ *p++) & 0xff];
+
+ return crc;
+}
+
+int mlx5dr_crc_encap_entropy_hash_calc(struct mlx5dr_context *ctx,
+ struct mlx5dr_crc_encap_entropy_hash_fields *data,
+ uint8_t entropy_res[],
+ enum mlx5dr_crc_encap_entropy_hash_size res_size)
+{
+ struct mlx5dr_cmd_query_caps *caps = ctx->caps;
+ uint16_t max_hash, min_hash, res;
+
+ if (caps->encap_entropy_hash_type) {
+ DR_LOG(ERR, "calculation of encap_entropy_hash_type 0x%x not supported",
+ caps->encap_entropy_hash_type);
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ max_hash = caps->roce_max_src_udp_port;
+ min_hash = caps->roce_min_src_udp_port;
+
+ res = mlx5dr_crc16_calc((uint8_t *)data, sizeof(*data), dr_crc_inner_crc_tab16);
+
+ if (res_size == MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16) {
+ *(uint16_t *)entropy_res = rte_cpu_to_be_16((min_hash | res) & max_hash);
+ } else if (res_size == MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8) {
+ *entropy_res = (uint8_t)(res & 0xff);
+ } else {
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/mlx5/hws/mlx5dr_crc32.h b/drivers/net/mlx5/hws/mlx5dr_crc32.h
index 9aab9e06ca..75b6009a15 100644
--- a/drivers/net/mlx5/hws/mlx5dr_crc32.h
+++ b/drivers/net/mlx5/hws/mlx5dr_crc32.h
@@ -10,4 +10,9 @@
*/
uint32_t mlx5dr_crc32_calc(uint8_t *p, size_t len);
+/* Standard CRC16 calculation using the crc_tab16 param to indicate
+ * the pre-calculated polynome hash values.
+ */
+uint16_t mlx5dr_crc16_calc(uint8_t *p, size_t len, uint16_t crc_tab16[]);
+
#endif /* MLX5DR_CRC32_C_ */
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v4 3/4] net/mlx5: add calc encap hash support
2024-02-13 14:16 ` [PATCH v4 1/4] ethdev: introduce " Ori Kam
2024-02-13 14:16 ` [PATCH v4 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
@ 2024-02-13 14:16 ` Ori Kam
2024-02-13 14:16 ` [PATCH v4 4/4] app/testpmd: add encap hash calculation Ori Kam
2024-02-13 15:45 ` [PATCH v4 1/4] ethdev: introduce " Ferruh Yigit
3 siblings, 0 replies; 31+ messages in thread
From: Ori Kam @ 2024-02-13 14:16 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Viacheslav Ovsiienko, Suanming Mou, Matan Azrad
Cc: dev, orika, rasland
This commit adds support for encap hash calculation.
Signed-off-by: Ori Kam <orika@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
drivers/net/mlx5/mlx5_flow.c | 29 +++++++++++++++
drivers/net/mlx5/mlx5_flow.h | 8 ++++
drivers/net/mlx5/mlx5_flow_hw.c | 66 +++++++++++++++++++++++++++++++++
3 files changed, 103 insertions(+)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 40376c99ba..7c5a5da8ec 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1197,6 +1197,12 @@ mlx5_flow_calc_table_hash(struct rte_eth_dev *dev,
const struct rte_flow_item pattern[],
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+static int
+mlx5_flow_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error);
static const struct rte_flow_ops mlx5_flow_ops = {
.validate = mlx5_flow_validate,
@@ -1253,6 +1259,7 @@ static const struct rte_flow_ops mlx5_flow_ops = {
.async_action_list_handle_query_update =
mlx5_flow_async_action_list_handle_query_update,
.flow_calc_table_hash = mlx5_flow_calc_table_hash,
+ .flow_calc_encap_hash = mlx5_flow_calc_encap_hash,
};
/* Tunnel information. */
@@ -11121,6 +11128,28 @@ mlx5_flow_calc_table_hash(struct rte_eth_dev *dev,
hash, error);
}
+static int
+mlx5_flow_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error)
+{
+ enum mlx5_flow_drv_type drv_type = flow_get_drv_type(dev, NULL);
+ const struct mlx5_flow_driver_ops *fops;
+
+ if (drv_type == MLX5_FLOW_TYPE_MIN || drv_type == MLX5_FLOW_TYPE_MAX)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "invalid driver type");
+ fops = flow_get_drv_ops(drv_type);
+ if (!fops || !fops->flow_calc_encap_hash)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL, "no calc encap hash handler");
+ return fops->flow_calc_encap_hash(dev, pattern, dest_field, hash, error);
+}
+
/**
* Destroy all indirect actions (shared RSS).
*
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index b086dfaf28..a4d0ff7b13 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -2198,6 +2198,13 @@ typedef int
const struct rte_flow_item pattern[],
uint8_t pattern_template_index,
uint32_t *hash, struct rte_flow_error *error);
+typedef int
+(*mlx5_flow_calc_encap_hash_t)
+ (struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error);
struct mlx5_flow_driver_ops {
mlx5_flow_validate_t validate;
@@ -2271,6 +2278,7 @@ struct mlx5_flow_driver_ops {
mlx5_flow_async_action_list_handle_query_update_t
async_action_list_handle_query_update;
mlx5_flow_calc_table_hash_t flow_calc_table_hash;
+ mlx5_flow_calc_encap_hash_t flow_calc_encap_hash;
};
/* mlx5_flow.c */
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index 3af5e1f160..ce2fb7c5f9 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -11701,6 +11701,71 @@ flow_hw_calc_table_hash(struct rte_eth_dev *dev,
return 0;
}
+static int
+flow_hw_calc_encap_hash(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ enum rte_flow_encap_hash_field dest_field,
+ uint8_t *hash,
+ struct rte_flow_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5dr_crc_encap_entropy_hash_fields data;
+ enum mlx5dr_crc_encap_entropy_hash_size res_size =
+ dest_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT ?
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_16 :
+ MLX5DR_CRC_ENCAP_ENTROPY_HASH_SIZE_8;
+ int res;
+
+ memset(&data, 0, sizeof(struct mlx5dr_crc_encap_entropy_hash_fields));
+
+ for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+ switch (pattern->type) {
+ case RTE_FLOW_ITEM_TYPE_IPV4:
+ data.dst.ipv4_addr =
+ ((const struct rte_flow_item_ipv4 *)(pattern->spec))->hdr.dst_addr;
+ data.src.ipv4_addr =
+ ((const struct rte_flow_item_ipv4 *)(pattern->spec))->hdr.src_addr;
+ break;
+ case RTE_FLOW_ITEM_TYPE_IPV6:
+ memcpy(data.dst.ipv6_addr,
+ ((const struct rte_flow_item_ipv6 *)(pattern->spec))->hdr.dst_addr,
+ sizeof(data.dst.ipv6_addr));
+ memcpy(data.src.ipv6_addr,
+ ((const struct rte_flow_item_ipv6 *)(pattern->spec))->hdr.src_addr,
+ sizeof(data.src.ipv6_addr));
+ break;
+ case RTE_FLOW_ITEM_TYPE_UDP:
+ data.next_protocol = IPPROTO_UDP;
+ data.dst_port =
+ ((const struct rte_flow_item_udp *)(pattern->spec))->hdr.dst_port;
+ data.src_port =
+ ((const struct rte_flow_item_udp *)(pattern->spec))->hdr.src_port;
+ break;
+ case RTE_FLOW_ITEM_TYPE_TCP:
+ data.next_protocol = IPPROTO_TCP;
+ data.dst_port =
+ ((const struct rte_flow_item_tcp *)(pattern->spec))->hdr.dst_port;
+ data.src_port =
+ ((const struct rte_flow_item_tcp *)(pattern->spec))->hdr.src_port;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ICMP:
+ data.next_protocol = IPPROTO_ICMP;
+ break;
+ case RTE_FLOW_ITEM_TYPE_ICMP6:
+ data.next_protocol = IPPROTO_ICMPV6;
+ break;
+ default:
+ break;
+ }
+ }
+ res = mlx5dr_crc_encap_entropy_hash_calc(priv->dr_ctx, &data, hash, res_size);
+ if (res)
+ return rte_flow_error_set(error, res,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "error while calculating encap hash");
+ return 0;
+}
+
const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
.info_get = flow_hw_info_get,
.configure = flow_hw_configure,
@@ -11746,6 +11811,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
.item_create = flow_dv_item_create,
.item_release = flow_dv_item_release,
.flow_calc_table_hash = flow_hw_calc_table_hash,
+ .flow_calc_encap_hash = flow_hw_calc_encap_hash,
};
/**
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH v4 4/4] app/testpmd: add encap hash calculation
2024-02-13 14:16 ` [PATCH v4 1/4] ethdev: introduce " Ori Kam
2024-02-13 14:16 ` [PATCH v4 2/4] net/mlx5/hws: introduce encap entropy hash calculation API Ori Kam
2024-02-13 14:16 ` [PATCH v4 3/4] net/mlx5: add calc encap hash support Ori Kam
@ 2024-02-13 14:16 ` Ori Kam
2024-02-13 15:45 ` Ferruh Yigit
2024-02-13 15:45 ` [PATCH v4 1/4] ethdev: introduce " Ferruh Yigit
3 siblings, 1 reply; 31+ messages in thread
From: Ori Kam @ 2024-02-13 14:16 UTC (permalink / raw)
To: dsosnowski, ferruh.yigit, cristian.dumitrescu, andrew.rybchenko,
stephen, Aman Singh, Yuying Zhang
Cc: dev, orika, rasland
This commits add support for calculating the encap hash.
Command structure:
flow hash {port} encap {target field} pattern {item} [/ {item} [...] ] / end
Example:
calculate hash to be used by VXLAN encapsulation.
flow hash 0 encap hash_field_sport pattern ipv4 dst is 7.7.7.7 src is 8.8.8.8 / udp dst is 5678 src is 1234 / end
Signed-off-by: Ori Kam <orika@nvidia.com>
Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
---
app/test-pmd/cmdline_flow.c | 57 +++++++++++++++++++--
app/test-pmd/config.c | 30 +++++++++++
app/test-pmd/testpmd.h | 3 ++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 21 +++++++-
4 files changed, 106 insertions(+), 5 deletions(-)
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index a4131e1b39..844840fe2d 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -219,6 +219,10 @@ enum index {
HASH_CALC_TABLE,
HASH_CALC_PATTERN_INDEX,
HASH_CALC_PATTERN,
+ HASH_CALC_ENCAP,
+ HASH_CALC_DEST,
+ ENCAP_HASH_FIELD_SRC_PORT,
+ ENCAP_HASH_FIELD_GRE_FLOW_ID,
/* Tunnel arguments. */
TUNNEL_CREATE,
@@ -1220,6 +1224,8 @@ struct buffer {
uint32_t pattern_n;
uint32_t actions_n;
uint8_t *data;
+ enum rte_flow_encap_hash_field field;
+ uint8_t encap_hash;
} vc; /**< Validate/create arguments. */
struct {
uint64_t *rule;
@@ -2618,6 +2624,18 @@ static const enum index action_nat64[] = {
ZERO,
};
+static const enum index next_hash_subcmd[] = {
+ HASH_CALC_TABLE,
+ HASH_CALC_ENCAP,
+ ZERO,
+};
+
+static const enum index next_hash_encap_dest_subcmd[] = {
+ ENCAP_HASH_FIELD_SRC_PORT,
+ ENCAP_HASH_FIELD_GRE_FLOW_ID,
+ ZERO,
+};
+
static int parse_set_raw_encap_decap(struct context *, const struct token *,
const char *, unsigned int,
void *, unsigned int);
@@ -3875,7 +3893,7 @@ static const struct token token_list[] = {
[HASH] = {
.name = "hash",
.help = "calculate hash for a given pattern in a given template table",
- .next = NEXT(NEXT_ENTRY(HASH_CALC_TABLE), NEXT_ENTRY(COMMON_PORT_ID)),
+ .next = NEXT(next_hash_subcmd, NEXT_ENTRY(COMMON_PORT_ID)),
.args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_hash,
},
@@ -3889,6 +3907,12 @@ static const struct token token_list[] = {
args.vc.table_id)),
.call = parse_hash,
},
+ [HASH_CALC_ENCAP] = {
+ .name = "encap",
+ .help = "calculates encap hash",
+ .next = NEXT(next_hash_encap_dest_subcmd),
+ .call = parse_hash,
+ },
[HASH_CALC_PATTERN_INDEX] = {
.name = "pattern_template",
.help = "specify pattern template id",
@@ -3898,6 +3922,18 @@ static const struct token token_list[] = {
args.vc.pat_templ_id)),
.call = parse_hash,
},
+ [ENCAP_HASH_FIELD_SRC_PORT] = {
+ .name = "hash_field_sport",
+ .help = "the encap hash field is src port",
+ .next = NEXT(NEXT_ENTRY(ITEM_PATTERN)),
+ .call = parse_hash,
+ },
+ [ENCAP_HASH_FIELD_GRE_FLOW_ID] = {
+ .name = "hash_field_flow_id",
+ .help = "the encap hash field is NVGRE flow id",
+ .next = NEXT(NEXT_ENTRY(ITEM_PATTERN)),
+ .call = parse_hash,
+ },
/* Top-level command. */
[INDIRECT_ACTION] = {
.name = "indirect_action",
@@ -11075,6 +11111,15 @@ parse_hash(struct context *ctx, const struct token *token,
ctx->object = out->args.vc.pattern;
ctx->objmask = NULL;
return len;
+ case HASH_CALC_ENCAP:
+ out->args.vc.encap_hash = 1;
+ return len;
+ case ENCAP_HASH_FIELD_SRC_PORT:
+ out->args.vc.field = RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT;
+ return len;
+ case ENCAP_HASH_FIELD_GRE_FLOW_ID:
+ out->args.vc.field = RTE_FLOW_ENCAP_HASH_FIELD_NVGRE_FLOW_ID;
+ return len;
default:
return -1;
}
@@ -13068,9 +13113,13 @@ cmd_flow_parsed(const struct buffer *in)
port_queue_flow_pull(in->port, in->queue);
break;
case HASH:
- port_flow_hash_calc(in->port, in->args.vc.table_id,
- in->args.vc.pat_templ_id,
- in->args.vc.pattern);
+ if (!in->args.vc.encap_hash)
+ port_flow_hash_calc(in->port, in->args.vc.table_id,
+ in->args.vc.pat_templ_id,
+ in->args.vc.pattern);
+ else
+ port_flow_hash_calc_encap(in->port, in->args.vc.field,
+ in->args.vc.pattern);
break;
case QUEUE_AGED:
port_queue_flow_aged(in->port, in->queue,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index cad7537bc6..e26b5bd18d 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -3339,6 +3339,36 @@ port_flow_hash_calc(portid_t port_id, uint32_t table_id,
return 0;
}
+/** Calculate the encap hash result for a given pattern. */
+int
+port_flow_hash_calc_encap(portid_t port_id,
+ enum rte_flow_encap_hash_field encap_hash_field,
+ const struct rte_flow_item pattern[])
+{
+ struct rte_flow_error error;
+ int ret = 0;
+ uint16_t hash = 0;
+ uint8_t len = encap_hash_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT ? 2 : 1;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL) {
+ printf("Failed to calculate encap hash - not a valid port");
+ return -EINVAL;
+ }
+
+ ret = rte_flow_calc_encap_hash(port_id, pattern, encap_hash_field, len,
+ (uint8_t *)&hash, &error);
+ if (ret < 0) {
+ printf("Failed to calculate encap hash");
+ return ret;
+ }
+ if (encap_hash_field == RTE_FLOW_ENCAP_HASH_FIELD_SRC_PORT)
+ printf("encap hash result %#x\n", hash);
+ else
+ printf("encap hash result %#x\n", *(uint8_t *)&hash);
+ return 0;
+}
+
/** Pull queue operation results from the queue. */
static int
port_queue_aged_flow_destroy(portid_t port_id, queueid_t queue_id,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 9b10a9ea1c..e18546c46e 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -1016,6 +1016,9 @@ int port_queue_flow_push(portid_t port_id, queueid_t queue_id);
int port_queue_flow_pull(portid_t port_id, queueid_t queue_id);
int port_flow_hash_calc(portid_t port_id, uint32_t table_id,
uint8_t pattern_template_index, const struct rte_flow_item pattern[]);
+int port_flow_hash_calc_encap(portid_t port_id,
+ enum rte_flow_encap_hash_field encap_hash_field,
+ const struct rte_flow_item pattern[]);
void port_queue_flow_aged(portid_t port_id, uint32_t queue_id, uint8_t destroy);
int port_flow_validate(portid_t port_id,
const struct rte_flow_attr *attr,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 08a0b59535..bf48f01b0a 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -3297,7 +3297,7 @@ The usual error message is shown when operations results cannot be pulled::
Calculating hash
~~~~~~~~~~~~~~~~
-``flow hash`` calculates the hash for a given pattern.
+``flow hash {port_id} template_table`` calculates the hash for a given pattern.
It is bound to ``rte_flow_calc_table_hash()``::
flow hash {port_id} template_table {table_id}
@@ -3316,6 +3316,25 @@ Otherwise, it will show an error message of the form::
This command uses the same pattern items as ``flow create``,
their format is described in `Creating flow rules`_.
+
+Simulate encap hash calculation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``flow hash {port_id} encap`` adds hash query, that returns the hash value
+that the HW will calculate when encapsulating a packet.
+
+ flow hash {port_id} encap {target field} pattern {item} [/ {item} [...]] / end
+
+If successful, it will show::
+
+ encap hash result #[...]
+
+The value will be shown as uint16_t without endian conversion.
+
+Otherwise it will show an error message of the form::
+
+ Failed to calculate encap hash - [...]
+
Creating a tunnel stub for offload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
2.34.1
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 4/4] app/testpmd: add encap hash calculation
2024-02-13 14:16 ` [PATCH v4 4/4] app/testpmd: add encap hash calculation Ori Kam
@ 2024-02-13 15:45 ` Ferruh Yigit
0 siblings, 0 replies; 31+ messages in thread
From: Ferruh Yigit @ 2024-02-13 15:45 UTC (permalink / raw)
To: Ori Kam, dsosnowski, cristian.dumitrescu, andrew.rybchenko,
stephen, Aman Singh, Yuying Zhang
Cc: dev, rasland
On 2/13/2024 2:16 PM, Ori Kam wrote:
> This commits add support for calculating the encap hash.
>
> Command structure:
> flow hash {port} encap {target field} pattern {item} [/ {item} [...] ] / end
>
> Example:
> calculate hash to be used by VXLAN encapsulation.
> flow hash 0 encap hash_field_sport pattern ipv4 dst is 7.7.7.7 src is 8.8.8.8 / udp dst is 5678 src is 1234 / end
>
> Signed-off-by: Ori Kam <orika@nvidia.com>
> Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
>
Acked-by: Ferruh Yigit <ferruh.yigit@amd.com>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 1/4] ethdev: introduce encap hash calculation
2024-02-13 14:16 ` [PATCH v4 1/4] ethdev: introduce " Ori Kam
` (2 preceding siblings ...)
2024-02-13 14:16 ` [PATCH v4 4/4] app/testpmd: add encap hash calculation Ori Kam
@ 2024-02-13 15:45 ` Ferruh Yigit
2024-02-13 15:45 ` Ferruh Yigit
3 siblings, 1 reply; 31+ messages in thread
From: Ferruh Yigit @ 2024-02-13 15:45 UTC (permalink / raw)
To: Ori Kam, dsosnowski, cristian.dumitrescu, andrew.rybchenko,
stephen, Thomas Monjalon
Cc: dev, rasland
On 2/13/2024 2:16 PM, Ori Kam wrote:
> During encapsulation of a packet, it is possible to change some
> outer headers to improve flow destribution.
> For example, from VXLAN RFC:
> "It is recommended that the UDP source port number
> be calculated using a hash of fields from the inner packet --
> one example being a hash of the inner Ethernet frame's headers.
> This is to enable a level of entropy for the ECMP/load-balancing"
>
> The tunnel protocol defines which outer field should hold this hash,
> but it doesn't define the hash calculation algorithm.
>
> An application that uses flow offloads gets the first few packets
> (exception path) and then decides to offload the flow.
> As a result, there are two
> different paths that a packet from a given flow may take.
> SW for the first few packets or HW for the rest.
> When the packet goes through the SW, the SW encapsulates the packet
> and must use the same hash calculation as the HW will do for
> the rest of the packets in this flow.
>
> the new function rte_flow_calc_encap_hash can query the hash value
> from the driver for a given packet as if the packet was passed
> through the HW.
>
> Signed-off-by: Ori Kam <orika@nvidia.com>
> Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
>
Acked-by: Ferruh Yigit <ferruh.yigit@amd.com>
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [PATCH v4 1/4] ethdev: introduce encap hash calculation
2024-02-13 15:45 ` [PATCH v4 1/4] ethdev: introduce " Ferruh Yigit
@ 2024-02-13 15:45 ` Ferruh Yigit
0 siblings, 0 replies; 31+ messages in thread
From: Ferruh Yigit @ 2024-02-13 15:45 UTC (permalink / raw)
To: Ori Kam, dsosnowski, cristian.dumitrescu, andrew.rybchenko,
stephen, Thomas Monjalon
Cc: dev, rasland
On 2/13/2024 3:45 PM, Ferruh Yigit wrote:
> On 2/13/2024 2:16 PM, Ori Kam wrote:
>> During encapsulation of a packet, it is possible to change some
>> outer headers to improve flow destribution.
>> For example, from VXLAN RFC:
>> "It is recommended that the UDP source port number
>> be calculated using a hash of fields from the inner packet --
>> one example being a hash of the inner Ethernet frame's headers.
>> This is to enable a level of entropy for the ECMP/load-balancing"
>>
>> The tunnel protocol defines which outer field should hold this hash,
>> but it doesn't define the hash calculation algorithm.
>>
>> An application that uses flow offloads gets the first few packets
>> (exception path) and then decides to offload the flow.
>> As a result, there are two
>> different paths that a packet from a given flow may take.
>> SW for the first few packets or HW for the rest.
>> When the packet goes through the SW, the SW encapsulates the packet
>> and must use the same hash calculation as the HW will do for
>> the rest of the packets in this flow.
>>
>> the new function rte_flow_calc_encap_hash can query the hash value
>> from the driver for a given packet as if the packet was passed
>> through the HW.
>>
>> Signed-off-by: Ori Kam <orika@nvidia.com>
>> Acked-by: Dariusz Sosnowski <dsosnowski@nvidia.com>
>>
>
> Acked-by: Ferruh Yigit <ferruh.yigit@amd.com>
>
Series applied to dpdk-next-net/main, thanks.
^ permalink raw reply [flat|nested] 31+ messages in thread