DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
@ 2021-01-08  6:32 Alexander Kozyrev
  2021-01-10  8:00 ` Ori Kam
                   ` (2 more replies)
  0 siblings, 3 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-08  6:32 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Implement a generic copy flow API to allow copying of an arbitrary
header field (as well as mark, metadata or tag) to another item.

This generic copy mechanism removes the necessity to implement a
separate RTE Flow action every time we need to modify a new packet
field in the future. A user-provided value can be used from a
specified tag/metadata or directly copied from other packet field.

The number of bits to copy as well as the offset to start from can
be specified to allow a partial copy or copy into an arbitrary
place in a packet for greater flexibility.

RFC: http://patches.dpdk.org/patch/85384/

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
---
 doc/guides/prog_guide/rte_flow.rst | 35 ++++++++++++++++++
 lib/librte_ethdev/rte_flow.c       |  1 +
 lib/librte_ethdev/rte_flow.h       | 59 ++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 86b3444803..b737ff9dad 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2766,6 +2766,41 @@ The behaviour of the shared action defined by ``action`` argument of type
    | no properties |
    +---------------+
 
+Action: ``COPY_ITEM``
+^^^^^^^^^^^^^^^^^^^^^
+
+Copy ``width`` bits from ``src`` item to ``dst`` item.
+
+An arbitrary header field (as well as mark, metadata or tag values)
+can be used as both source and destination items as set by ``item``.
+
+Inner packet header fields can be accessed using the ``index`` and
+it is possible to start the copy from the ``offset`` bits in an item.
+
+.. _table_rte_flow_action_copy_item:
+
+.. table:: COPY_ITEM
+
+   +-----------------------------------------+
+   | Field         | Value                   |
+   +===============+=========================+
+   | ``dst``       | destination item        |
+   | ``src``       | source item             |
+   | ``width``     | number of bits to copy  |
+   +---------------+-------------------------+
+
+.. _table_rte_flow_action_copy_data:
+
+.. table:: destination/source item definition
+
+   +----------------------------------------------------------+
+   | Field         | Value                                    |
+   +===============+==========================================+
+   | ``item``      | ID of a packet field/mark/metadata/tag   |
+   | ``index``     | index of outer/inner header or tag array |
+   | ``offset``    | number of bits to skip during the copy   |
+   +---------------+------------------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index a06f64c271..fdbabefc47 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -176,6 +176,7 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
 	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
 	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
+	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct rte_flow_action_copy_item)),
 	/**
 	 * Shared action represented as handle of type
 	 * (struct rte_flow_shared action *) stored in conf field (see
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 0977a78270..0540c861fb 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
 	 * struct rte_flow_shared_action).
 	 */
 	RTE_FLOW_ACTION_TYPE_SHARED,
+
+	/**
+	 * Copy a packet header field, tag, mark or metadata.
+	 *
+	 * Allow saving an arbitrary header field by copying its value
+	 * to a tag/mark/metadata or copy it into another header field.
+	 *
+	 * See struct rte_flow_action_copy_item.
+	 */
+	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
 };
 
 /**
@@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+enum rte_flow_item_id {
+	RTE_FLOW_ITEM_NONE = 0,
+	RTE_FLOW_ITEM_MAC_DST,
+	RTE_FLOW_ITEM_MAC_SRC,
+	RTE_FLOW_ITEM_VLAN_TYPE,
+	RTE_FLOW_ITEM_VLAN_ID,
+	RTE_FLOW_ITEM_MAC_TYPE,
+	RTE_FLOW_ITEM_IPV4_DSCP,
+	RTE_FLOW_ITEM_IPV4_TTL,
+	RTE_FLOW_ITEM_IPV4_SRC,
+	RTE_FLOW_ITEM_IPV4_DST,
+	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
+	RTE_FLOW_ITEM_IPV6_SRC,
+	RTE_FLOW_ITEM_IPV6_DST,
+	RTE_FLOW_ITEM_TCP_PORT_SRC,
+	RTE_FLOW_ITEM_TCP_PORT_DST,
+	RTE_FLOW_ITEM_TCP_SEQ_NUM,
+	RTE_FLOW_ITEM_TCP_ACK_NUM,
+	RTE_FLOW_ITEM_TCP_FLAGS,
+	RTE_FLOW_ITEM_UDP_PORT_SRC,
+	RTE_FLOW_ITEM_UDP_PORT_DST,
+	RTE_FLOW_ITEM_VXLAN_VNI,
+	RTE_FLOW_ITEM_GENEVE_VNI,
+	RTE_FLOW_ITEM_GTP_TEID,
+	RTE_FLOW_ITEM_TAG,
+	RTE_FLOW_ITEM_MARK,
+	RTE_FLOW_ITEM_META,
+};
+
+struct rte_flow_action_copy_data {
+	enum rte_flow_item_id item;
+	uint32_t index;
+	uint32_t offset;
+};
+
+/**
+ * RTE_FLOW_ACTION_TYPE_COPY_ITEM
+ *
+ * Copies a specified number of bits from a source header field
+ * to a destination header field. Tag, mark or metadata can also
+ * be used as a source/destination to allow saving/overwriting
+ * an arbituary header field with a user-specified value.
+ */
+struct rte_flow_action_copy_item {
+	struct rte_flow_action_copy_data dst;
+	struct rte_flow_action_copy_data src;
+	uint32_t width;
+};
+
 /* Mbuf dynamic field offset for metadata. */
 extern int32_t rte_flow_dynf_metadata_offs;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-08  6:32 [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action Alexander Kozyrev
@ 2021-01-10  8:00 ` Ori Kam
  2021-01-10  9:36   ` Asaf Penso
  2021-01-12 14:15   ` Alexander Kozyrev
  2021-01-12  5:01 ` [dpdk-dev] [PATCH v2 0/2] generic copy rte flow action support Alexander Kozyrev
  2021-01-14 13:59 ` [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action Jerin Jacob
  2 siblings, 2 replies; 48+ messages in thread
From: Ori Kam @ 2021-01-10  8:00 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

Hi Alexander,

I guess that the test-pmd part will be available later right?

> -----Original Message-----
> From: Alexander Kozyrev <akozyrev@nvidia.com>
> Sent: Friday, January 8, 2021 8:33 AM
> Subject: [PATCH] ethdev: introduce generic copy rte flow action
> 
> Implement a generic copy flow API to allow copying of an arbitrary
> header field (as well as mark, metadata or tag) to another item.
> 
> This generic copy mechanism removes the necessity to implement a
> separate RTE Flow action every time we need to modify a new packet
> field in the future. A user-provided value can be used from a
> specified tag/metadata or directly copied from other packet field.
> 
> The number of bits to copy as well as the offset to start from can
> be specified to allow a partial copy or copy into an arbitrary
> place in a packet for greater flexibility.
> 

Since the question why you are using enum and not just offset from 
the start of the packet, was discussed and raised by number of people it will be best
if it will appear in the commit log, at least the advantages to this implementation.

> RFC:
> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatches.d
> pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com%
> 7Cd04c2e49c3a840994da408d8b39f3304%7C43083d15727340c1b7db39efd9cc
> c17a%7C0%7C0%7C637456843629116269%7CUnknown%7CTWFpbGZsb3d8eyJ
> WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C
> 1000&amp;sdata=85096rASBtzbjU42pV6sPkl3nVt5HlR6%2BL9nxI3qgFA%3D&a
> mp;reserved=0
> 
> Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> ---
>  doc/guides/prog_guide/rte_flow.rst | 35 ++++++++++++++++++
>  lib/librte_ethdev/rte_flow.c       |  1 +
>  lib/librte_ethdev/rte_flow.h       | 59 ++++++++++++++++++++++++++++++
>  3 files changed, 95 insertions(+)
> 
> diff --git a/doc/guides/prog_guide/rte_flow.rst
> b/doc/guides/prog_guide/rte_flow.rst
> index 86b3444803..b737ff9dad 100644
> --- a/doc/guides/prog_guide/rte_flow.rst
> +++ b/doc/guides/prog_guide/rte_flow.rst
> @@ -2766,6 +2766,41 @@ The behaviour of the shared action defined by
> ``action`` argument of type
>     | no properties |
>     +---------------+
> 
> +Action: ``COPY_ITEM``
> +^^^^^^^^^^^^^^^^^^^^^
> +
> +Copy ``width`` bits from ``src`` item to ``dst`` item.
> +
> +An arbitrary header field (as well as mark, metadata or tag values)
> +can be used as both source and destination items as set by ``item``.
> +

For tag I think you should also use the index right?

> +Inner packet header fields can be accessed using the ``index`` and
> +it is possible to start the copy from the ``offset`` bits in an item.

Please specify  what means index 0 /1 ... 0 is outer most? Inner most?
You can look at the RSS level for reference.
I think it will be best to use the same values.

What happens if we want to copy between different sizes?
for example copy IPV6 src to number of tags? I assume we will be using offset and
split the copy command to number of actions right?

> +
> +.. _table_rte_flow_action_copy_item:
> +
> +.. table:: COPY_ITEM
> +
> +   +-----------------------------------------+
> +   | Field         | Value                   |
> +   +===============+=========================+
> +   | ``dst``       | destination item        |
> +   | ``src``       | source item             |
> +   | ``width``     | number of bits to copy  |
> +   +---------------+-------------------------+
> +
> +.. _table_rte_flow_action_copy_data:
> +
> +.. table:: destination/source item definition
> +
> +   +----------------------------------------------------------+
> +   | Field         | Value                                    |
> +   +===============+==========================================+
> +   | ``item``      | ID of a packet field/mark/metadata/tag   |
> +   | ``index``     | index of outer/inner header or tag array |
> +   | ``offset``    | number of bits to skip during the copy   |
> +   +---------------+------------------------------------------+
> +
>  Negative types
>  ~~~~~~~~~~~~~~
> 
> diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
> index a06f64c271..fdbabefc47 100644
> --- a/lib/librte_ethdev/rte_flow.c
> +++ b/lib/librte_ethdev/rte_flow.c
> @@ -176,6 +176,7 @@ static const struct rte_flow_desc_data
> rte_flow_desc_action[] = {
>  	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct
> rte_flow_action_set_dscp)),
>  	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
>  	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
> +	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct
> rte_flow_action_copy_item)),
>  	/**
>  	 * Shared action represented as handle of type
>  	 * (struct rte_flow_shared action *) stored in conf field (see
> diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
> index 0977a78270..0540c861fb 100644
> --- a/lib/librte_ethdev/rte_flow.h
> +++ b/lib/librte_ethdev/rte_flow.h
> @@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
>  	 * struct rte_flow_shared_action).
>  	 */
>  	RTE_FLOW_ACTION_TYPE_SHARED,
> +
> +	/**
> +	 * Copy a packet header field, tag, mark or metadata.
> +	 *
> +	 * Allow saving an arbitrary header field by copying its value
> +	 * to a tag/mark/metadata or copy it into another header field.
> +	 *
> +	 * See struct rte_flow_action_copy_item.
> +	 */
> +	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
>  };
> 
>  /**
> @@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
>   */
>  struct rte_flow_shared_action;
> 
> +enum rte_flow_item_id {
> +	RTE_FLOW_ITEM_NONE = 0,
> +	RTE_FLOW_ITEM_MAC_DST,
> +	RTE_FLOW_ITEM_MAC_SRC,
> +	RTE_FLOW_ITEM_VLAN_TYPE,
> +	RTE_FLOW_ITEM_VLAN_ID,
> +	RTE_FLOW_ITEM_MAC_TYPE,
> +	RTE_FLOW_ITEM_IPV4_DSCP,
> +	RTE_FLOW_ITEM_IPV4_TTL,
> +	RTE_FLOW_ITEM_IPV4_SRC,
> +	RTE_FLOW_ITEM_IPV4_DST,
> +	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
> +	RTE_FLOW_ITEM_IPV6_SRC,
> +	RTE_FLOW_ITEM_IPV6_DST,
> +	RTE_FLOW_ITEM_TCP_PORT_SRC,
> +	RTE_FLOW_ITEM_TCP_PORT_DST,
> +	RTE_FLOW_ITEM_TCP_SEQ_NUM,
> +	RTE_FLOW_ITEM_TCP_ACK_NUM,
> +	RTE_FLOW_ITEM_TCP_FLAGS,
> +	RTE_FLOW_ITEM_UDP_PORT_SRC,
> +	RTE_FLOW_ITEM_UDP_PORT_DST,
> +	RTE_FLOW_ITEM_VXLAN_VNI,
> +	RTE_FLOW_ITEM_GENEVE_VNI,
> +	RTE_FLOW_ITEM_GTP_TEID,
> +	RTE_FLOW_ITEM_TAG,
> +	RTE_FLOW_ITEM_MARK,
> +	RTE_FLOW_ITEM_META,
> +};

I don't think this name is good since it not rte_flow_item this is just internal enumeration
for this action.

> +
> +struct rte_flow_action_copy_data {
> +	enum rte_flow_item_id item;
> +	uint32_t index;
> +	uint32_t offset;

Why use 32 bits? Since this copy only one register with max len of 32 bit.
The max offset can 31? Same for the index.

> +};
> +
> +/**
> + * RTE_FLOW_ACTION_TYPE_COPY_ITEM
> + *
> + * Copies a specified number of bits from a source header field
> + * to a destination header field. Tag, mark or metadata can also
> + * be used as a source/destination to allow saving/overwriting
> + * an arbituary header field with a user-specified value.
> + */
> +struct rte_flow_action_copy_item {
> +	struct rte_flow_action_copy_data dst;
> +	struct rte_flow_action_copy_data src;
> +	uint32_t width;

Why use 32 bit register?

> +};
> +
>  /* Mbuf dynamic field offset for metadata. */
>  extern int32_t rte_flow_dynf_metadata_offs;
> 
> --
> 2.24.1

Best,
Ori


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-10  8:00 ` Ori Kam
@ 2021-01-10  9:36   ` Asaf Penso
  2021-01-12 14:15   ` Alexander Kozyrev
  1 sibling, 0 replies; 48+ messages in thread
From: Asaf Penso @ 2021-01-10  9:36 UTC (permalink / raw)
  To: Ori Kam, Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

Correct, Ori. We'll soon send the testpmd part and pmd draft.

Regards,
Asaf Penso

>-----Original Message-----
>From: dev <dev-bounces@dpdk.org> On Behalf Of Ori Kam
>Sent: Sunday, January 10, 2021 10:01 AM
>To: Alexander Kozyrev <akozyrev@nvidia.com>; dev@dpdk.org
>Cc: Slava Ovsiienko <viacheslavo@nvidia.com>; NBU-Contact-Thomas
>Monjalon <thomas@monjalon.net>; ferruh.yigit@intel.com;
>andrew.rybchenko@oktetlabs.ru
>Subject: Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow
>action
>
>Hi Alexander,
>
>I guess that the test-pmd part will be available later right?
>
>> -----Original Message-----
>> From: Alexander Kozyrev <akozyrev@nvidia.com>
>> Sent: Friday, January 8, 2021 8:33 AM
>> Subject: [PATCH] ethdev: introduce generic copy rte flow action
>>
>> Implement a generic copy flow API to allow copying of an arbitrary
>> header field (as well as mark, metadata or tag) to another item.
>>
>> This generic copy mechanism removes the necessity to implement a
>> separate RTE Flow action every time we need to modify a new packet
>> field in the future. A user-provided value can be used from a
>> specified tag/metadata or directly copied from other packet field.
>>
>> The number of bits to copy as well as the offset to start from can be
>> specified to allow a partial copy or copy into an arbitrary place in a
>> packet for greater flexibility.
>>
>
>Since the question why you are using enum and not just offset from the start
>of the packet, was discussed and raised by number of people it will be best if
>it will appear in the commit log, at least the advantages to this
>implementation.
>
>> RFC:
>>
>https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatch
>> es.d
>pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com
>%
>> 7Cd04c2e49c3a840994da408d8b39f3304%7C43083d15727340c1b7db39efd9cc
>>
>c17a%7C0%7C0%7C637456843629116269%7CUnknown%7CTWFpbGZsb3d8eyJ
>>
>WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7
>C
>>
>1000&amp;sdata=85096rASBtzbjU42pV6sPkl3nVt5HlR6%2BL9nxI3qgFA%3D&a
>> mp;reserved=0
>>
>> Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
>> ---
>>  doc/guides/prog_guide/rte_flow.rst | 35 ++++++++++++++++++
>>  lib/librte_ethdev/rte_flow.c       |  1 +
>>  lib/librte_ethdev/rte_flow.h       | 59
>++++++++++++++++++++++++++++++
>>  3 files changed, 95 insertions(+)
>>
>> diff --git a/doc/guides/prog_guide/rte_flow.rst
>> b/doc/guides/prog_guide/rte_flow.rst
>> index 86b3444803..b737ff9dad 100644
>> --- a/doc/guides/prog_guide/rte_flow.rst
>> +++ b/doc/guides/prog_guide/rte_flow.rst
>> @@ -2766,6 +2766,41 @@ The behaviour of the shared action defined by
>> ``action`` argument of type
>>     | no properties |
>>     +---------------+
>>
>> +Action: ``COPY_ITEM``
>> +^^^^^^^^^^^^^^^^^^^^^
>> +
>> +Copy ``width`` bits from ``src`` item to ``dst`` item.
>> +
>> +An arbitrary header field (as well as mark, metadata or tag values)
>> +can be used as both source and destination items as set by ``item``.
>> +
>
>For tag I think you should also use the index right?
>
>> +Inner packet header fields can be accessed using the ``index`` and it
>> +is possible to start the copy from the ``offset`` bits in an item.
>
>Please specify  what means index 0 /1 ... 0 is outer most? Inner most?
>You can look at the RSS level for reference.
>I think it will be best to use the same values.
>
>What happens if we want to copy between different sizes?
>for example copy IPV6 src to number of tags? I assume we will be using offset
>and split the copy command to number of actions right?
>
>> +
>> +.. _table_rte_flow_action_copy_item:
>> +
>> +.. table:: COPY_ITEM
>> +
>> +   +-----------------------------------------+
>> +   | Field         | Value                   |
>> +   +===============+=========================+
>> +   | ``dst``       | destination item        |
>> +   | ``src``       | source item             |
>> +   | ``width``     | number of bits to copy  |
>> +   +---------------+-------------------------+
>> +
>> +.. _table_rte_flow_action_copy_data:
>> +
>> +.. table:: destination/source item definition
>> +
>> +   +----------------------------------------------------------+
>> +   | Field         | Value                                    |
>> +
>+===============+==========================================
>+
>> +   | ``item``      | ID of a packet field/mark/metadata/tag   |
>> +   | ``index``     | index of outer/inner header or tag array |
>> +   | ``offset``    | number of bits to skip during the copy   |
>> +   +---------------+------------------------------------------+
>> +
>>  Negative types
>>  ~~~~~~~~~~~~~~
>>
>> diff --git a/lib/librte_ethdev/rte_flow.c
>> b/lib/librte_ethdev/rte_flow.c index a06f64c271..fdbabefc47 100644
>> --- a/lib/librte_ethdev/rte_flow.c
>> +++ b/lib/librte_ethdev/rte_flow.c
>> @@ -176,6 +176,7 @@ static const struct rte_flow_desc_data
>> rte_flow_desc_action[] = {
>>  	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct
>> rte_flow_action_set_dscp)),
>>  	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
>>  	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
>> +	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct
>> rte_flow_action_copy_item)),
>>  	/**
>>  	 * Shared action represented as handle of type
>>  	 * (struct rte_flow_shared action *) stored in conf field (see diff
>> --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
>> index 0977a78270..0540c861fb 100644
>> --- a/lib/librte_ethdev/rte_flow.h
>> +++ b/lib/librte_ethdev/rte_flow.h
>> @@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
>>  	 * struct rte_flow_shared_action).
>>  	 */
>>  	RTE_FLOW_ACTION_TYPE_SHARED,
>> +
>> +	/**
>> +	 * Copy a packet header field, tag, mark or metadata.
>> +	 *
>> +	 * Allow saving an arbitrary header field by copying its value
>> +	 * to a tag/mark/metadata or copy it into another header field.
>> +	 *
>> +	 * See struct rte_flow_action_copy_item.
>> +	 */
>> +	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
>>  };
>>
>>  /**
>> @@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
>>   */
>>  struct rte_flow_shared_action;
>>
>> +enum rte_flow_item_id {
>> +	RTE_FLOW_ITEM_NONE = 0,
>> +	RTE_FLOW_ITEM_MAC_DST,
>> +	RTE_FLOW_ITEM_MAC_SRC,
>> +	RTE_FLOW_ITEM_VLAN_TYPE,
>> +	RTE_FLOW_ITEM_VLAN_ID,
>> +	RTE_FLOW_ITEM_MAC_TYPE,
>> +	RTE_FLOW_ITEM_IPV4_DSCP,
>> +	RTE_FLOW_ITEM_IPV4_TTL,
>> +	RTE_FLOW_ITEM_IPV4_SRC,
>> +	RTE_FLOW_ITEM_IPV4_DST,
>> +	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
>> +	RTE_FLOW_ITEM_IPV6_SRC,
>> +	RTE_FLOW_ITEM_IPV6_DST,
>> +	RTE_FLOW_ITEM_TCP_PORT_SRC,
>> +	RTE_FLOW_ITEM_TCP_PORT_DST,
>> +	RTE_FLOW_ITEM_TCP_SEQ_NUM,
>> +	RTE_FLOW_ITEM_TCP_ACK_NUM,
>> +	RTE_FLOW_ITEM_TCP_FLAGS,
>> +	RTE_FLOW_ITEM_UDP_PORT_SRC,
>> +	RTE_FLOW_ITEM_UDP_PORT_DST,
>> +	RTE_FLOW_ITEM_VXLAN_VNI,
>> +	RTE_FLOW_ITEM_GENEVE_VNI,
>> +	RTE_FLOW_ITEM_GTP_TEID,
>> +	RTE_FLOW_ITEM_TAG,
>> +	RTE_FLOW_ITEM_MARK,
>> +	RTE_FLOW_ITEM_META,
>> +};
>
>I don't think this name is good since it not rte_flow_item this is just internal
>enumeration for this action.
>
>> +
>> +struct rte_flow_action_copy_data {
>> +	enum rte_flow_item_id item;
>> +	uint32_t index;
>> +	uint32_t offset;
>
>Why use 32 bits? Since this copy only one register with max len of 32 bit.
>The max offset can 31? Same for the index.
>
>> +};
>> +
>> +/**
>> + * RTE_FLOW_ACTION_TYPE_COPY_ITEM
>> + *
>> + * Copies a specified number of bits from a source header field
>> + * to a destination header field. Tag, mark or metadata can also
>> + * be used as a source/destination to allow saving/overwriting
>> + * an arbituary header field with a user-specified value.
>> + */
>> +struct rte_flow_action_copy_item {
>> +	struct rte_flow_action_copy_data dst;
>> +	struct rte_flow_action_copy_data src;
>> +	uint32_t width;
>
>Why use 32 bit register?
>
>> +};
>> +
>>  /* Mbuf dynamic field offset for metadata. */  extern int32_t
>> rte_flow_dynf_metadata_offs;
>>
>> --
>> 2.24.1
>
>Best,
>Ori


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 0/2] generic copy rte flow action support
  2021-01-08  6:32 [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action Alexander Kozyrev
  2021-01-10  8:00 ` Ori Kam
@ 2021-01-12  5:01 ` Alexander Kozyrev
  2021-01-12  5:01   ` [dpdk-dev] [PATCH v2 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
                     ` (2 more replies)
  2021-01-14 13:59 ` [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action Jerin Jacob
  2 siblings, 3 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-12  5:01 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Implement a generic copy rte flow API as described in RFC:
http://patches.dpdk.org/patch/85384/

This API allows copying a specified number of bits from a source
header field to a destination header field. Tag, mark or metadata
can also be used as a source/destination to allow saving/overwriting
an arbitrary header field with a user-specified value.

Outermost/innermost packet fields (and Tag array elements) are
accessible via the index parameter to facilitate the modification
of encapsulated packet header fields. The offset parameter provides
the flexibility to copy/set any part of a packet starting the
specified packet header field.

---
v1: https://patchwork.dpdk.org/patch/86173/
v2: Added testpmd support.

Alexander Kozyrev (2):
  ethdev: introduce generic copy rte flow action
  app/testpmd: add support for generic copy rte flow action

 app/test-pmd/cmdline_flow.c        | 156 +++++++++++++++++++++++++++++
 doc/guides/prog_guide/rte_flow.rst |  35 +++++++
 lib/librte_ethdev/rte_flow.c       |   1 +
 lib/librte_ethdev/rte_flow.h       |  59 +++++++++++
 4 files changed, 251 insertions(+)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 1/2] ethdev: introduce generic copy rte flow action
  2021-01-12  5:01 ` [dpdk-dev] [PATCH v2 0/2] generic copy rte flow action support Alexander Kozyrev
@ 2021-01-12  5:01   ` Alexander Kozyrev
  2021-01-12  5:01   ` [dpdk-dev] [PATCH v2 2/2] app/testpmd: add support for " Alexander Kozyrev
  2021-01-13  3:38   ` [dpdk-dev] [PATCH v3 0/2] generic copy rte flow action support Alexander Kozyrev
  2 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-12  5:01 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Implement a generic copy flow API to allow copying of an arbitrary
header field (as well as mark, metadata or tag) to another item.

This generic copy mechanism removes the necessity to implement a
separate RTE Flow action every time we need to modify a new packet
field in the future. A user-provided value can be used from a
specified tag/metadata or directly copied from other packet field.

The number of bits to copy as well as the offset to start from can
be specified to allow a partial copy or copy into an arbitrary
place in a packet for greater flexibility.

RFC: http://patches.dpdk.org/patch/85384/

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
---
 doc/guides/prog_guide/rte_flow.rst | 35 ++++++++++++++++++
 lib/librte_ethdev/rte_flow.c       |  1 +
 lib/librte_ethdev/rte_flow.h       | 59 ++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 86b3444803..b737ff9dad 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2766,6 +2766,41 @@ The behaviour of the shared action defined by ``action`` argument of type
    | no properties |
    +---------------+
 
+Action: ``COPY_ITEM``
+^^^^^^^^^^^^^^^^^^^^^
+
+Copy ``width`` bits from ``src`` item to ``dst`` item.
+
+An arbitrary header field (as well as mark, metadata or tag values)
+can be used as both source and destination items as set by ``item``.
+
+Inner packet header fields can be accessed using the ``index`` and
+it is possible to start the copy from the ``offset`` bits in an item.
+
+.. _table_rte_flow_action_copy_item:
+
+.. table:: COPY_ITEM
+
+   +-----------------------------------------+
+   | Field         | Value                   |
+   +===============+=========================+
+   | ``dst``       | destination item        |
+   | ``src``       | source item             |
+   | ``width``     | number of bits to copy  |
+   +---------------+-------------------------+
+
+.. _table_rte_flow_action_copy_data:
+
+.. table:: destination/source item definition
+
+   +----------------------------------------------------------+
+   | Field         | Value                                    |
+   +===============+==========================================+
+   | ``item``      | ID of a packet field/mark/metadata/tag   |
+   | ``index``     | index of outer/inner header or tag array |
+   | ``offset``    | number of bits to skip during the copy   |
+   +---------------+------------------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index a06f64c271..fdbabefc47 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -176,6 +176,7 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
 	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
 	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
+	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct rte_flow_action_copy_item)),
 	/**
 	 * Shared action represented as handle of type
 	 * (struct rte_flow_shared action *) stored in conf field (see
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 0977a78270..5f10c38ffe 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
 	 * struct rte_flow_shared_action).
 	 */
 	RTE_FLOW_ACTION_TYPE_SHARED,
+
+	/**
+	 * Copy a packet header field, tag, mark or metadata.
+	 *
+	 * Allow saving an arbitrary header field by copying its value
+	 * to a tag/mark/metadata or copy it into another header field.
+	 *
+	 * See struct rte_flow_action_copy_item.
+	 */
+	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
 };
 
 /**
@@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+enum rte_flow_item_id {
+	RTE_FLOW_ITEM_NONE = 0,
+	RTE_FLOW_ITEM_MAC_DST,
+	RTE_FLOW_ITEM_MAC_SRC,
+	RTE_FLOW_ITEM_VLAN_TYPE,
+	RTE_FLOW_ITEM_VLAN_ID,
+	RTE_FLOW_ITEM_MAC_TYPE,
+	RTE_FLOW_ITEM_IPV4_DSCP,
+	RTE_FLOW_ITEM_IPV4_TTL,
+	RTE_FLOW_ITEM_IPV4_SRC,
+	RTE_FLOW_ITEM_IPV4_DST,
+	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
+	RTE_FLOW_ITEM_IPV6_SRC,
+	RTE_FLOW_ITEM_IPV6_DST,
+	RTE_FLOW_ITEM_TCP_PORT_SRC,
+	RTE_FLOW_ITEM_TCP_PORT_DST,
+	RTE_FLOW_ITEM_TCP_SEQ_NUM,
+	RTE_FLOW_ITEM_TCP_ACK_NUM,
+	RTE_FLOW_ITEM_TCP_FLAGS,
+	RTE_FLOW_ITEM_UDP_PORT_SRC,
+	RTE_FLOW_ITEM_UDP_PORT_DST,
+	RTE_FLOW_ITEM_VXLAN_VNI,
+	RTE_FLOW_ITEM_GENEVE_VNI,
+	RTE_FLOW_ITEM_GTP_TEID,
+	RTE_FLOW_ITEM_TAG,
+	RTE_FLOW_ITEM_MARK,
+	RTE_FLOW_ITEM_META,
+};
+
+struct rte_flow_action_copy_data {
+	enum rte_flow_item_id item;
+	uint32_t index;
+	uint32_t offset;
+};
+
+/**
+ * RTE_FLOW_ACTION_TYPE_COPY_ITEM
+ *
+ * Copies a specified number of bits from a source header field
+ * to a destination header field. Tag, mark or metadata can also
+ * be used as a source/destination to allow saving/overwriting
+ * an arbitrary header field with a user-specified value.
+ */
+struct rte_flow_action_copy_item {
+	struct rte_flow_action_copy_data dst;
+	struct rte_flow_action_copy_data src;
+	uint32_t width;
+};
+
 /* Mbuf dynamic field offset for metadata. */
 extern int32_t rte_flow_dynf_metadata_offs;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v2 2/2] app/testpmd: add support for generic copy rte flow action
  2021-01-12  5:01 ` [dpdk-dev] [PATCH v2 0/2] generic copy rte flow action support Alexander Kozyrev
  2021-01-12  5:01   ` [dpdk-dev] [PATCH v2 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
@ 2021-01-12  5:01   ` Alexander Kozyrev
  2021-01-12 14:58     ` Ori Kam
  2021-01-13  3:38   ` [dpdk-dev] [PATCH v3 0/2] generic copy rte flow action support Alexander Kozyrev
  2 siblings, 1 reply; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-12  5:01 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Add support for the RTE_FLOW_ACTION_COPY_ITEM to the testpmd.
Implement CLI to create the copy_item action and supply all the
needed parameters to copy an arbitrary packet field (as well as
mark, tag or metadata) into another item.

Example of the flow is the following:
flow create 0 egress group 1 pattern eth / ipv4 / udp / end
     actions copy_item dst_type tag dst_index 0 dst_offset 8
     src_type gtp_teid src_index 0 src_offset 0 width 32 / end

This flow copies 32 bits from the first Tag in the Tags array
into the outermost GTP TEID packet header field. 8 bits of the Tag
are skipped as indicated by the dst_offset action parameter.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
---
 app/test-pmd/cmdline_flow.c | 156 ++++++++++++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 585cab98b4..1acf8fddf8 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -408,6 +408,16 @@ enum index {
 	ACTION_SAMPLE_INDEX_VALUE,
 	ACTION_SHARED,
 	SHARED_ACTION_ID2PTR,
+	ACTION_COPY_ITEM,
+	ACTION_COPY_ITEM_DST_TYPE,
+	ACTION_COPY_ITEM_DST_TYPE_VALUE,
+	ACTION_COPY_ITEM_DST_INDEX,
+	ACTION_COPY_ITEM_DST_OFFSET,
+	ACTION_COPY_ITEM_SRC_TYPE,
+	ACTION_COPY_ITEM_SRC_TYPE_VALUE,
+	ACTION_COPY_ITEM_SRC_INDEX,
+	ACTION_COPY_ITEM_SRC_OFFSET,
+	ACTION_COPY_ITEM_WIDTH,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -561,6 +571,18 @@ struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 
+static const char *const copy_item_table[] = {
+	"none", "mac_dst", "mac_src",
+	"vlan_type", "vlan_id", "mac_type",
+	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
+	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
+	"tcp_port_src", "tcp_port_dst",
+	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
+	"udp_port_src", "udp_port_dst",
+	"vxlan_vni", "geneve_vni", "gtp_teid",
+	"tag", "mark", "meta", NULL
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -1306,6 +1328,7 @@ static const enum index next_action[] = {
 	ACTION_AGE,
 	ACTION_SAMPLE,
 	ACTION_SHARED,
+	ACTION_COPY_ITEM,
 	ZERO,
 };
 
@@ -1638,6 +1661,10 @@ static int
 parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 				const char *str, unsigned int len, void *buf,
 				unsigned int size);
+static int
+parse_vc_copy_item(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1722,6 +1749,8 @@ static int comp_set_raw_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
 static int comp_set_sample_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
+static int comp_set_copy_item(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -4037,6 +4066,85 @@ static const struct token token_list[] = {
 		.call = parse_vc_action_raw_decap_index,
 		.comp = comp_set_raw_index,
 	},
+	[ACTION_COPY_ITEM] = {
+		.name = "copy_item",
+		.help = "copy data from dst to src item",
+		.priv = PRIV_ACTION(COPY_ITEM,
+			sizeof(struct rte_flow_action_copy_item)),
+		.next = NEXT(NEXT_ENTRY(ACTION_COPY_ITEM_DST_TYPE)),
+		.call = parse_vc,
+	},
+	[ACTION_COPY_ITEM_DST_TYPE] = {
+		.name = "dst_type",
+		.help = "destination item type",
+		.next = NEXT(NEXT_ENTRY(ACTION_COPY_ITEM_DST_INDEX),
+			NEXT_ENTRY(ACTION_COPY_ITEM_DST_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_DST_TYPE_VALUE] = {
+		.name = "{type}",
+		.help = "destination item type value",
+		.call = parse_vc_copy_item,
+		.comp = comp_set_copy_item,
+	},
+	[ACTION_COPY_ITEM_DST_INDEX] = {
+		.name = "dst_index",
+		.help = "destination item index",
+		.next = NEXT(NEXT_ENTRY(ACTION_COPY_ITEM_DST_OFFSET),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					dst.index)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_DST_OFFSET] = {
+		.name = "dst_offset",
+		.help = "destination item offset",
+		.next = NEXT(NEXT_ENTRY(ACTION_COPY_ITEM_SRC_TYPE),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					dst.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_SRC_TYPE] = {
+		.name = "src_type",
+		.help = "source item type",
+		.next = NEXT(NEXT_ENTRY(ACTION_COPY_ITEM_SRC_INDEX),
+			NEXT_ENTRY(ACTION_COPY_ITEM_SRC_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_SRC_TYPE_VALUE] = {
+		.name = "{type}",
+		.help = "source item type value",
+		.call = parse_vc_copy_item,
+		.comp = comp_set_copy_item,
+	},
+	[ACTION_COPY_ITEM_SRC_INDEX] = {
+		.name = "src_index",
+		.help = "source item type index",
+		.next = NEXT(NEXT_ENTRY(ACTION_COPY_ITEM_SRC_OFFSET),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					src.index)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_SRC_OFFSET] = {
+		.name = "src_offset",
+		.help = "source item type offset",
+		.next = NEXT(NEXT_ENTRY(ACTION_COPY_ITEM_WIDTH),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					src.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_WIDTH] = {
+		.name = "width",
+		.help = "number of bits to copy",
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					width)),
+		.call = parse_vc_conf,
+	},
 	/* Top level command. */
 	[SET] = {
 		.name = "set",
@@ -5960,6 +6068,36 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse tokens for copy_item command. */
+static int
+parse_vc_copy_item(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_copy_item *action_copy_item;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_COPY_ITEM_DST_TYPE_VALUE &&
+		ctx->curr != ACTION_COPY_ITEM_SRC_TYPE_VALUE)
+		return -1;
+	for (i = 0; copy_item_table[i]; ++i)
+		if (!strcmp_partial(copy_item_table[i], str, len))
+			break;
+	if (!copy_item_table[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_copy_item = ctx->object;
+	if (ctx->curr == ACTION_COPY_ITEM_DST_TYPE_VALUE)
+		action_copy_item->dst.item = i;
+	else
+		action_copy_item->src.item = i;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -7029,6 +7167,24 @@ comp_set_sample_index(struct context *ctx, const struct token *token,
 	return nb;
 }
 
+/** Complete item type for copy_item command. */
+static int
+comp_set_copy_item(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; copy_item_table[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, copy_item_table[ent], size);
+	return -1;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-10  8:00 ` Ori Kam
  2021-01-10  9:36   ` Asaf Penso
@ 2021-01-12 14:15   ` Alexander Kozyrev
  2021-01-12 14:52     ` Ori Kam
  1 sibling, 1 reply; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-12 14:15 UTC (permalink / raw)
  To: Ori Kam, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

> From: Ori Kam <orika@nvidia.com> on Sunday, January 10, 2021 3:01
> Hi Alexander,
> 
> I guess that the test-pmd part will be available later right?
Yes, please take a look at v2 version for testpmd implementation.

> > -----Original Message-----
> > From: Alexander Kozyrev <akozyrev@nvidia.com>
> > Sent: Friday, January 8, 2021 8:33 AM
> > Subject: [PATCH] ethdev: introduce generic copy rte flow action
> >
> > Implement a generic copy flow API to allow copying of an arbitrary
> > header field (as well as mark, metadata or tag) to another item.
> >
> > This generic copy mechanism removes the necessity to implement a
> > separate RTE Flow action every time we need to modify a new packet
> > field in the future. A user-provided value can be used from a
> > specified tag/metadata or directly copied from other packet field.
> >
> > The number of bits to copy as well as the offset to start from can
> > be specified to allow a partial copy or copy into an arbitrary
> > place in a packet for greater flexibility.
> >
> 
> Since the question why you are using enum and not just offset from
> the start of the packet, was discussed and raised by number of people it will be
> best
> if it will appear in the commit log, at least the advantages to this
> implementation.
Ok, will add to v3 commit message.

> > RFC:
> >
> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatches.
> d
> >
> pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com%
> >
> 7Cd04c2e49c3a840994da408d8b39f3304%7C43083d15727340c1b7db39efd9cc
> >
> c17a%7C0%7C0%7C637456843629116269%7CUnknown%7CTWFpbGZsb3d8eyJ
> >
> WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C
> > 1000&amp;sdata=85096rASBtzbjU42pV6sPkl3nVt5HlR6%2BL9nxI3qgFA%3D&a
> > mp;reserved=0
> >
> > Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> > ---
> >  doc/guides/prog_guide/rte_flow.rst | 35 ++++++++++++++++++
> >  lib/librte_ethdev/rte_flow.c       |  1 +
> >  lib/librte_ethdev/rte_flow.h       | 59 ++++++++++++++++++++++++++++++
> >  3 files changed, 95 insertions(+)
> >
> > diff --git a/doc/guides/prog_guide/rte_flow.rst
> > b/doc/guides/prog_guide/rte_flow.rst
> > index 86b3444803..b737ff9dad 100644
> > --- a/doc/guides/prog_guide/rte_flow.rst
> > +++ b/doc/guides/prog_guide/rte_flow.rst
> > @@ -2766,6 +2766,41 @@ The behaviour of the shared action defined by
> > ``action`` argument of type
> >     | no properties |
> >     +---------------+
> >
> > +Action: ``COPY_ITEM``
> > +^^^^^^^^^^^^^^^^^^^^^
> > +
> > +Copy ``width`` bits from ``src`` item to ``dst`` item.
> > +
> > +An arbitrary header field (as well as mark, metadata or tag values)
> > +can be used as both source and destination items as set by ``item``.
> > +
> 
> For tag I think you should also use the index right?
Right, index is here to access any element in the tag array in addition to
outermost or any inner packet header fields. Will specify explicitly in the doc.

> > +Inner packet header fields can be accessed using the ``index`` and
> > +it is possible to start the copy from the ``offset`` bits in an item.
> 
> Please specify  what means index 0 /1 ... 0 is outer most? Inner most?
> You can look at the RSS level for reference.
> I think it will be best to use the same values.
0 is outer most, of course,  I'Il add some clarification about that.

> What happens if we want to copy between different sizes?
> for example copy IPV6 src to number of tags? I assume we will be using offset
> and
> split the copy command to number of actions right?
That is the correct understanding. We can utilize 4 copy_item actions in this case to
copy 32-bits of an IPv6 SRC at the time (specifying different offsets) to 4 different Tag fields.

> > +
> > +.. _table_rte_flow_action_copy_item:
> > +
> > +.. table:: COPY_ITEM
> > +
> > +   +-----------------------------------------+
> > +   | Field         | Value                   |
> > +   +===============+=========================+
> > +   | ``dst``       | destination item        |
> > +   | ``src``       | source item             |
> > +   | ``width``     | number of bits to copy  |
> > +   +---------------+-------------------------+
> > +
> > +.. _table_rte_flow_action_copy_data:
> > +
> > +.. table:: destination/source item definition
> > +
> > +   +----------------------------------------------------------+
> > +   | Field         | Value                                    |
> > +   +===============+==========================================+
> > +   | ``item``      | ID of a packet field/mark/metadata/tag   |
> > +   | ``index``     | index of outer/inner header or tag array |
> > +   | ``offset``    | number of bits to skip during the copy   |
> > +   +---------------+------------------------------------------+
> > +
> >  Negative types
> >  ~~~~~~~~~~~~~~
> >
> > diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
> > index a06f64c271..fdbabefc47 100644
> > --- a/lib/librte_ethdev/rte_flow.c
> > +++ b/lib/librte_ethdev/rte_flow.c
> > @@ -176,6 +176,7 @@ static const struct rte_flow_desc_data
> > rte_flow_desc_action[] = {
> >  	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct
> > rte_flow_action_set_dscp)),
> >  	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
> >  	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
> > +	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct
> > rte_flow_action_copy_item)),
> >  	/**
> >  	 * Shared action represented as handle of type
> >  	 * (struct rte_flow_shared action *) stored in conf field (see
> > diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
> > index 0977a78270..0540c861fb 100644
> > --- a/lib/librte_ethdev/rte_flow.h
> > +++ b/lib/librte_ethdev/rte_flow.h
> > @@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
> >  	 * struct rte_flow_shared_action).
> >  	 */
> >  	RTE_FLOW_ACTION_TYPE_SHARED,
> > +
> > +	/**
> > +	 * Copy a packet header field, tag, mark or metadata.
> > +	 *
> > +	 * Allow saving an arbitrary header field by copying its value
> > +	 * to a tag/mark/metadata or copy it into another header field.
> > +	 *
> > +	 * See struct rte_flow_action_copy_item.
> > +	 */
> > +	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
> >  };
> >
> >  /**
> > @@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
> >   */
> >  struct rte_flow_shared_action;
> >
> > +enum rte_flow_item_id {
> > +	RTE_FLOW_ITEM_NONE = 0,
> > +	RTE_FLOW_ITEM_MAC_DST,
> > +	RTE_FLOW_ITEM_MAC_SRC,
> > +	RTE_FLOW_ITEM_VLAN_TYPE,
> > +	RTE_FLOW_ITEM_VLAN_ID,
> > +	RTE_FLOW_ITEM_MAC_TYPE,
> > +	RTE_FLOW_ITEM_IPV4_DSCP,
> > +	RTE_FLOW_ITEM_IPV4_TTL,
> > +	RTE_FLOW_ITEM_IPV4_SRC,
> > +	RTE_FLOW_ITEM_IPV4_DST,
> > +	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
> > +	RTE_FLOW_ITEM_IPV6_SRC,
> > +	RTE_FLOW_ITEM_IPV6_DST,
> > +	RTE_FLOW_ITEM_TCP_PORT_SRC,
> > +	RTE_FLOW_ITEM_TCP_PORT_DST,
> > +	RTE_FLOW_ITEM_TCP_SEQ_NUM,
> > +	RTE_FLOW_ITEM_TCP_ACK_NUM,
> > +	RTE_FLOW_ITEM_TCP_FLAGS,
> > +	RTE_FLOW_ITEM_UDP_PORT_SRC,
> > +	RTE_FLOW_ITEM_UDP_PORT_DST,
> > +	RTE_FLOW_ITEM_VXLAN_VNI,
> > +	RTE_FLOW_ITEM_GENEVE_VNI,
> > +	RTE_FLOW_ITEM_GTP_TEID,
> > +	RTE_FLOW_ITEM_TAG,
> > +	RTE_FLOW_ITEM_MARK,
> > +	RTE_FLOW_ITEM_META,
> > +};
> 
> I don't think this name is good since it not rte_flow_item this is just internal
> enumeration
> for this action.
Will rename to rte_flow_action_copy_item_id in v3? Is this ok?

> > +
> > +struct rte_flow_action_copy_data {
> > +	enum rte_flow_item_id item;
> > +	uint32_t index;
> > +	uint32_t offset;
> 
> Why use 32 bits? Since this copy only one register with max len of 32 bit.
> The max offset can 31? Same for the index.
This extends the flexibility of the copy API. This way you can modify any place
in a packet as you desire by specifying RTE_FLOW_ITEM_NONE to start with the
beginning of a packet and choosing a particular offset value to point in a desired place.
And since packet length can be pretty big we need to accommodate this.
Do you think this flexibility is not necessary and we should bound the offset to the
length of a selected packet field only? Index is 32 bit for the same field in RSS.

> > +};
> > +
> > +/**
> > + * RTE_FLOW_ACTION_TYPE_COPY_ITEM
> > + *
> > + * Copies a specified number of bits from a source header field
> > + * to a destination header field. Tag, mark or metadata can also
> > + * be used as a source/destination to allow saving/overwriting
> > + * an arbituary header field with a user-specified value.
> > + */
> > +struct rte_flow_action_copy_item {
> > +	struct rte_flow_action_copy_data dst;
> > +	struct rte_flow_action_copy_data src;
> > +	uint32_t width;
> 
> Why use 32 bit register?
Again, to make API as generic as possible in case there will be a PMD driver
that can copy a huge chunk of a packet into the another place of this packet.
What is your opinion on that?

> 
> > +};
> > +
> >  /* Mbuf dynamic field offset for metadata. */
> >  extern int32_t rte_flow_dynf_metadata_offs;
> >
> > --
> > 2.24.1
> 
> Best,
> Ori


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-12 14:15   ` Alexander Kozyrev
@ 2021-01-12 14:52     ` Ori Kam
  2021-01-12 15:13       ` Ori Kam
  0 siblings, 1 reply; 48+ messages in thread
From: Ori Kam @ 2021-01-12 14:52 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

Hi,

> -----Original Message-----
> From: Alexander Kozyrev <akozyrev@nvidia.com>
> Sent: Tuesday, January 12, 2021 4:16 PM
> To: Ori Kam <orika@nvidia.com>; dev@dpdk.org
> Cc: Slava Ovsiienko <viacheslavo@nvidia.com>; NBU-Contact-Thomas Monjalon
> <thomas@monjalon.net>; ferruh.yigit@intel.com;
> andrew.rybchenko@oktetlabs.ru
> Subject: RE: [PATCH] ethdev: introduce generic copy rte flow action
> 
> > From: Ori Kam <orika@nvidia.com> on Sunday, January 10, 2021 3:01
> > Hi Alexander,
> >
> > I guess that the test-pmd part will be available later right?
> Yes, please take a look at v2 version for testpmd implementation.
> 
> > > -----Original Message-----
> > > From: Alexander Kozyrev <akozyrev@nvidia.com>
> > > Sent: Friday, January 8, 2021 8:33 AM
> > > Subject: [PATCH] ethdev: introduce generic copy rte flow action
> > >
> > > Implement a generic copy flow API to allow copying of an arbitrary
> > > header field (as well as mark, metadata or tag) to another item.
> > >
> > > This generic copy mechanism removes the necessity to implement a
> > > separate RTE Flow action every time we need to modify a new packet
> > > field in the future. A user-provided value can be used from a
> > > specified tag/metadata or directly copied from other packet field.
> > >
> > > The number of bits to copy as well as the offset to start from can
> > > be specified to allow a partial copy or copy into an arbitrary
> > > place in a packet for greater flexibility.
> > >
> >
> > Since the question why you are using enum and not just offset from
> > the start of the packet, was discussed and raised by number of people it will
> be
> > best
> > if it will appear in the commit log, at least the advantages to this
> > implementation.
> Ok, will add to v3 commit message.
> 
> > > RFC:
> > >
> > https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatches.
> > d
> > >
> >
> pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com%
> > >
> >
> 7Cd04c2e49c3a840994da408d8b39f3304%7C43083d15727340c1b7db39efd9cc
> > >
> >
> c17a%7C0%7C0%7C637456843629116269%7CUnknown%7CTWFpbGZsb3d8eyJ
> > >
> >
> WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C
> > >
> 1000&amp;sdata=85096rASBtzbjU42pV6sPkl3nVt5HlR6%2BL9nxI3qgFA%3D&a
> > > mp;reserved=0
> > >
> > > Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> > > ---
> > >  doc/guides/prog_guide/rte_flow.rst | 35 ++++++++++++++++++
> > >  lib/librte_ethdev/rte_flow.c       |  1 +
> > >  lib/librte_ethdev/rte_flow.h       | 59 ++++++++++++++++++++++++++++++
> > >  3 files changed, 95 insertions(+)
> > >
> > > diff --git a/doc/guides/prog_guide/rte_flow.rst
> > > b/doc/guides/prog_guide/rte_flow.rst
> > > index 86b3444803..b737ff9dad 100644
> > > --- a/doc/guides/prog_guide/rte_flow.rst
> > > +++ b/doc/guides/prog_guide/rte_flow.rst
> > > @@ -2766,6 +2766,41 @@ The behaviour of the shared action defined by
> > > ``action`` argument of type
> > >     | no properties |
> > >     +---------------+
> > >
> > > +Action: ``COPY_ITEM``
> > > +^^^^^^^^^^^^^^^^^^^^^
> > > +
> > > +Copy ``width`` bits from ``src`` item to ``dst`` item.
> > > +
> > > +An arbitrary header field (as well as mark, metadata or tag values)
> > > +can be used as both source and destination items as set by ``item``.
> > > +
> >
> > For tag I think you should also use the index right?
> Right, index is here to access any element in the tag array in addition to
> outermost or any inner packet header fields. Will specify explicitly in the doc.
> 
> > > +Inner packet header fields can be accessed using the ``index`` and
> > > +it is possible to start the copy from the ``offset`` bits in an item.
> >
> > Please specify  what means index 0 /1 ... 0 is outer most? Inner most?
> > You can look at the RSS level for reference.
> > I think it will be best to use the same values.
> 0 is outer most, of course,  I'Il add some clarification about that.
> 
Not necessary, like I said please look at the RSS, 0 can mean the inner most.

> > What happens if we want to copy between different sizes?
> > for example copy IPV6 src to number of tags? I assume we will be using offset
> > and
> > split the copy command to number of actions right?
> That is the correct understanding. We can utilize 4 copy_item actions in this
> case to
> copy 32-bits of an IPv6 SRC at the time (specifying different offsets) to 4
> different Tag fields.
> 
> > > +
> > > +.. _table_rte_flow_action_copy_item:
> > > +
> > > +.. table:: COPY_ITEM
> > > +
> > > +   +-----------------------------------------+
> > > +   | Field         | Value                   |
> > > +   +===============+=========================+
> > > +   | ``dst``       | destination item        |
> > > +   | ``src``       | source item             |
> > > +   | ``width``     | number of bits to copy  |
> > > +   +---------------+-------------------------+
> > > +
> > > +.. _table_rte_flow_action_copy_data:
> > > +
> > > +.. table:: destination/source item definition
> > > +
> > > +   +----------------------------------------------------------+
> > > +   | Field         | Value                                    |
> > > +
> +===============+==========================================+
> > > +   | ``item``      | ID of a packet field/mark/metadata/tag   |
> > > +   | ``index``     | index of outer/inner header or tag array |
> > > +   | ``offset``    | number of bits to skip during the copy   |
> > > +   +---------------+------------------------------------------+
> > > +
> > >  Negative types
> > >  ~~~~~~~~~~~~~~
> > >
> > > diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
> > > index a06f64c271..fdbabefc47 100644
> > > --- a/lib/librte_ethdev/rte_flow.c
> > > +++ b/lib/librte_ethdev/rte_flow.c
> > > @@ -176,6 +176,7 @@ static const struct rte_flow_desc_data
> > > rte_flow_desc_action[] = {
> > >  	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct
> > > rte_flow_action_set_dscp)),
> > >  	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
> > >  	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
> > > +	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct
> > > rte_flow_action_copy_item)),
> > >  	/**
> > >  	 * Shared action represented as handle of type
> > >  	 * (struct rte_flow_shared action *) stored in conf field (see
> > > diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
> > > index 0977a78270..0540c861fb 100644
> > > --- a/lib/librte_ethdev/rte_flow.h
> > > +++ b/lib/librte_ethdev/rte_flow.h
> > > @@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
> > >  	 * struct rte_flow_shared_action).
> > >  	 */
> > >  	RTE_FLOW_ACTION_TYPE_SHARED,
> > > +
> > > +	/**
> > > +	 * Copy a packet header field, tag, mark or metadata.
> > > +	 *
> > > +	 * Allow saving an arbitrary header field by copying its value
> > > +	 * to a tag/mark/metadata or copy it into another header field.
> > > +	 *
> > > +	 * See struct rte_flow_action_copy_item.
> > > +	 */
> > > +	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
> > >  };
> > >
> > >  /**
> > > @@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
> > >   */
> > >  struct rte_flow_shared_action;
> > >
> > > +enum rte_flow_item_id {
> > > +	RTE_FLOW_ITEM_NONE = 0,
> > > +	RTE_FLOW_ITEM_MAC_DST,
> > > +	RTE_FLOW_ITEM_MAC_SRC,
> > > +	RTE_FLOW_ITEM_VLAN_TYPE,
> > > +	RTE_FLOW_ITEM_VLAN_ID,
> > > +	RTE_FLOW_ITEM_MAC_TYPE,
> > > +	RTE_FLOW_ITEM_IPV4_DSCP,
> > > +	RTE_FLOW_ITEM_IPV4_TTL,
> > > +	RTE_FLOW_ITEM_IPV4_SRC,
> > > +	RTE_FLOW_ITEM_IPV4_DST,
> > > +	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
> > > +	RTE_FLOW_ITEM_IPV6_SRC,
> > > +	RTE_FLOW_ITEM_IPV6_DST,
> > > +	RTE_FLOW_ITEM_TCP_PORT_SRC,
> > > +	RTE_FLOW_ITEM_TCP_PORT_DST,
> > > +	RTE_FLOW_ITEM_TCP_SEQ_NUM,
> > > +	RTE_FLOW_ITEM_TCP_ACK_NUM,
> > > +	RTE_FLOW_ITEM_TCP_FLAGS,
> > > +	RTE_FLOW_ITEM_UDP_PORT_SRC,
> > > +	RTE_FLOW_ITEM_UDP_PORT_DST,
> > > +	RTE_FLOW_ITEM_VXLAN_VNI,
> > > +	RTE_FLOW_ITEM_GENEVE_VNI,
> > > +	RTE_FLOW_ITEM_GTP_TEID,
> > > +	RTE_FLOW_ITEM_TAG,
> > > +	RTE_FLOW_ITEM_MARK,
> > > +	RTE_FLOW_ITEM_META,
> > > +};
> >
> > I don't think this name is good since it not rte_flow_item this is just internal
> > enumeration
> > for this action.
> Will rename to rte_flow_action_copy_item_id in v3? Is this ok?
> 
Yes better,
Or rte_flow_copy_item_id?

> > > +
> > > +struct rte_flow_action_copy_data {
> > > +	enum rte_flow_item_id item;
> > > +	uint32_t index;
> > > +	uint32_t offset;
> >
> > Why use 32 bits? Since this copy only one register with max len of 32 bit.
> > The max offset can 31? Same for the index.
> This extends the flexibility of the copy API. This way you can modify any place
> in a packet as you desire by specifying RTE_FLOW_ITEM_NONE to start with
> the
> beginning of a packet and choosing a particular offset value to point in a
> desired place.
> And since packet length can be pretty big we need to accommodate this.
> Do you think this flexibility is not necessary and we should bound the offset to
> the
> length of a selected packet field only? Index is 32 bit for the same field in RSS.
> 
Nice idea but then I would add ITEM_OFFSET or something
around this name, I don't think NONE is a valid value.

> > > +};
> > > +
> > > +/**
> > > + * RTE_FLOW_ACTION_TYPE_COPY_ITEM
> > > + *
> > > + * Copies a specified number of bits from a source header field
> > > + * to a destination header field. Tag, mark or metadata can also
> > > + * be used as a source/destination to allow saving/overwriting
> > > + * an arbituary header field with a user-specified value.
> > > + */
> > > +struct rte_flow_action_copy_item {
> > > +	struct rte_flow_action_copy_data dst;
> > > +	struct rte_flow_action_copy_data src;
> > > +	uint32_t width;
> >
> > Why use 32 bit register?
> Again, to make API as generic as possible in case there will be a PMD driver
> that can copy a huge chunk of a packet into the another place of this packet.
> What is your opinion on that?
> 
Nice thinking,

> >
> > > +};
> > > +
> > >  /* Mbuf dynamic field offset for metadata. */
> > >  extern int32_t rte_flow_dynf_metadata_offs;
> > >
> > > --
> > > 2.24.1
> >
> > Best,
> > Ori


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v2 2/2] app/testpmd: add support for generic copy rte flow action
  2021-01-12  5:01   ` [dpdk-dev] [PATCH v2 2/2] app/testpmd: add support for " Alexander Kozyrev
@ 2021-01-12 14:58     ` Ori Kam
  0 siblings, 0 replies; 48+ messages in thread
From: Ori Kam @ 2021-01-12 14:58 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

Hi Alexander,

> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Alexander Kozyrev
> Subject: [dpdk-dev] [PATCH v2 2/2] app/testpmd: add support for generic copy
> rte flow action
> 
> Add support for the RTE_FLOW_ACTION_COPY_ITEM to the testpmd.
> Implement CLI to create the copy_item action and supply all the
> needed parameters to copy an arbitrary packet field (as well as
> mark, tag or metadata) into another item.
> 
> Example of the flow is the following:
> flow create 0 egress group 1 pattern eth / ipv4 / udp / end
>      actions copy_item dst_type tag dst_index 0 dst_offset 8
>      src_type gtp_teid src_index 0 src_offset 0 width 32 / end
> 
This is a long command, and for most cases holds to many extra values.
I suggest to allow default values, meaning that the application must
say the src and the dest fields but all the rest of the information can be
extract from those two parameters (offset =0, len(field_type).
If the user request he can add those parameters for more control.

> This flow copies 32 bits from the first Tag in the Tags array
> into the outermost GTP TEID packet header field. 8 bits of the Tag
> are skipped as indicated by the dst_offset action parameter.
> 
> Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> ---


Best,
Ori

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-12 14:52     ` Ori Kam
@ 2021-01-12 15:13       ` Ori Kam
  2021-01-12 17:19         ` Alexander Kozyrev
  0 siblings, 1 reply; 48+ messages in thread
From: Ori Kam @ 2021-01-12 15:13 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

Hi,


> -----Original Message-----
> From: Ori Kam
> Sent: Tuesday, January 12, 2021 4:53 PM
> To: Alexander Kozyrev <akozyrev@nvidia.com>; dev@dpdk.org
> Cc: Slava Ovsiienko <viacheslavo@nvidia.com>; NBU-Contact-Thomas Monjalon
> <thomas@monjalon.net>; ferruh.yigit@intel.com;
> andrew.rybchenko@oktetlabs.ru
> Subject: RE: [PATCH] ethdev: introduce generic copy rte flow action
> 
> Hi,
> 
> > -----Original Message-----
> > From: Alexander Kozyrev <akozyrev@nvidia.com>
> > Sent: Tuesday, January 12, 2021 4:16 PM
> > To: Ori Kam <orika@nvidia.com>; dev@dpdk.org
> > Cc: Slava Ovsiienko <viacheslavo@nvidia.com>; NBU-Contact-Thomas
> Monjalon
> > <thomas@monjalon.net>; ferruh.yigit@intel.com;
> > andrew.rybchenko@oktetlabs.ru
> > Subject: RE: [PATCH] ethdev: introduce generic copy rte flow action
> >
> > > From: Ori Kam <orika@nvidia.com> on Sunday, January 10, 2021 3:01
> > > Hi Alexander,
> > >
> > > I guess that the test-pmd part will be available later right?
> > Yes, please take a look at v2 version for testpmd implementation.
> >
> > > > -----Original Message-----
> > > > From: Alexander Kozyrev <akozyrev@nvidia.com>
> > > > Sent: Friday, January 8, 2021 8:33 AM
> > > > Subject: [PATCH] ethdev: introduce generic copy rte flow action
> > > >
> > > > Implement a generic copy flow API to allow copying of an arbitrary
> > > > header field (as well as mark, metadata or tag) to another item.
> > > >
> > > > This generic copy mechanism removes the necessity to implement a
> > > > separate RTE Flow action every time we need to modify a new packet
> > > > field in the future. A user-provided value can be used from a
> > > > specified tag/metadata or directly copied from other packet field.
> > > >
> > > > The number of bits to copy as well as the offset to start from can
> > > > be specified to allow a partial copy or copy into an arbitrary
> > > > place in a packet for greater flexibility.
> > > >
> > >
> > > Since the question why you are using enum and not just offset from
> > > the start of the packet, was discussed and raised by number of people it will
> > be
> > > best
> > > if it will appear in the commit log, at least the advantages to this
> > > implementation.
> > Ok, will add to v3 commit message.
> >
> > > > RFC:
> > > >
> > >
> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatches.
> > > d
> > > >
> > >
> >
> pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com%
> > > >
> > >
> >
> 7Cd04c2e49c3a840994da408d8b39f3304%7C43083d15727340c1b7db39efd9cc
> > > >
> > >
> >
> c17a%7C0%7C0%7C637456843629116269%7CUnknown%7CTWFpbGZsb3d8eyJ
> > > >
> > >
> >
> WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C
> > > >
> >
> 1000&amp;sdata=85096rASBtzbjU42pV6sPkl3nVt5HlR6%2BL9nxI3qgFA%3D&a
> > > > mp;reserved=0
> > > >
> > > > Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> > > > ---
> > > >  doc/guides/prog_guide/rte_flow.rst | 35 ++++++++++++++++++
> > > >  lib/librte_ethdev/rte_flow.c       |  1 +
> > > >  lib/librte_ethdev/rte_flow.h       | 59
> ++++++++++++++++++++++++++++++
> > > >  3 files changed, 95 insertions(+)
> > > >
> > > > diff --git a/doc/guides/prog_guide/rte_flow.rst
> > > > b/doc/guides/prog_guide/rte_flow.rst
> > > > index 86b3444803..b737ff9dad 100644
> > > > --- a/doc/guides/prog_guide/rte_flow.rst
> > > > +++ b/doc/guides/prog_guide/rte_flow.rst
> > > > @@ -2766,6 +2766,41 @@ The behaviour of the shared action defined by
> > > > ``action`` argument of type
> > > >     | no properties |
> > > >     +---------------+
> > > >
> > > > +Action: ``COPY_ITEM``
> > > > +^^^^^^^^^^^^^^^^^^^^^
> > > > +
> > > > +Copy ``width`` bits from ``src`` item to ``dst`` item.
> > > > +
> > > > +An arbitrary header field (as well as mark, metadata or tag values)
> > > > +can be used as both source and destination items as set by ``item``.
> > > > +
> > >
> > > For tag I think you should also use the index right?
> > Right, index is here to access any element in the tag array in addition to
> > outermost or any inner packet header fields. Will specify explicitly in the doc.
> >
> > > > +Inner packet header fields can be accessed using the ``index`` and
> > > > +it is possible to start the copy from the ``offset`` bits in an item.
> > >
> > > Please specify  what means index 0 /1 ... 0 is outer most? Inner most?
> > > You can look at the RSS level for reference.
> > > I think it will be best to use the same values.
> > 0 is outer most, of course,  I'Il add some clarification about that.
> >
> Not necessary, like I said please look at the RSS, 0 can mean the inner most.
> 
> > > What happens if we want to copy between different sizes?
> > > for example copy IPV6 src to number of tags? I assume we will be using
> offset
> > > and
> > > split the copy command to number of actions right?
> > That is the correct understanding. We can utilize 4 copy_item actions in this
> > case to
> > copy 32-bits of an IPv6 SRC at the time (specifying different offsets) to 4
> > different Tag fields.
> >
> > > > +
> > > > +.. _table_rte_flow_action_copy_item:
> > > > +
> > > > +.. table:: COPY_ITEM
> > > > +
> > > > +   +-----------------------------------------+
> > > > +   | Field         | Value                   |
> > > > +   +===============+=========================+
> > > > +   | ``dst``       | destination item        |
> > > > +   | ``src``       | source item             |
> > > > +   | ``width``     | number of bits to copy  |
> > > > +   +---------------+-------------------------+
> > > > +
> > > > +.. _table_rte_flow_action_copy_data:
> > > > +
> > > > +.. table:: destination/source item definition
> > > > +
> > > > +   +----------------------------------------------------------+
> > > > +   | Field         | Value                                    |
> > > > +
> > +===============+==========================================+
> > > > +   | ``item``      | ID of a packet field/mark/metadata/tag   |
> > > > +   | ``index``     | index of outer/inner header or tag array |
> > > > +   | ``offset``    | number of bits to skip during the copy   |
> > > > +   +---------------+------------------------------------------+
> > > > +
> > > >  Negative types
> > > >  ~~~~~~~~~~~~~~
> > > >
> > > > diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
> > > > index a06f64c271..fdbabefc47 100644
> > > > --- a/lib/librte_ethdev/rte_flow.c
> > > > +++ b/lib/librte_ethdev/rte_flow.c
> > > > @@ -176,6 +176,7 @@ static const struct rte_flow_desc_data
> > > > rte_flow_desc_action[] = {
> > > >  	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct
> > > > rte_flow_action_set_dscp)),
> > > >  	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
> > > >  	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
> > > > +	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct
> > > > rte_flow_action_copy_item)),
> > > >  	/**
> > > >  	 * Shared action represented as handle of type
> > > >  	 * (struct rte_flow_shared action *) stored in conf field (see
> > > > diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
> > > > index 0977a78270..0540c861fb 100644
> > > > --- a/lib/librte_ethdev/rte_flow.h
> > > > +++ b/lib/librte_ethdev/rte_flow.h
> > > > @@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
> > > >  	 * struct rte_flow_shared_action).
> > > >  	 */
> > > >  	RTE_FLOW_ACTION_TYPE_SHARED,
> > > > +
> > > > +	/**
> > > > +	 * Copy a packet header field, tag, mark or metadata.
> > > > +	 *
> > > > +	 * Allow saving an arbitrary header field by copying its value
> > > > +	 * to a tag/mark/metadata or copy it into another header field.
> > > > +	 *
> > > > +	 * See struct rte_flow_action_copy_item.
> > > > +	 */
> > > > +	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
> > > >  };
> > > >
> > > >  /**
> > > > @@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
> > > >   */
> > > >  struct rte_flow_shared_action;
> > > >
> > > > +enum rte_flow_item_id {
> > > > +	RTE_FLOW_ITEM_NONE = 0,
> > > > +	RTE_FLOW_ITEM_MAC_DST,
> > > > +	RTE_FLOW_ITEM_MAC_SRC,
> > > > +	RTE_FLOW_ITEM_VLAN_TYPE,
> > > > +	RTE_FLOW_ITEM_VLAN_ID,
> > > > +	RTE_FLOW_ITEM_MAC_TYPE,
> > > > +	RTE_FLOW_ITEM_IPV4_DSCP,
> > > > +	RTE_FLOW_ITEM_IPV4_TTL,
> > > > +	RTE_FLOW_ITEM_IPV4_SRC,
> > > > +	RTE_FLOW_ITEM_IPV4_DST,
> > > > +	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
> > > > +	RTE_FLOW_ITEM_IPV6_SRC,
> > > > +	RTE_FLOW_ITEM_IPV6_DST,
> > > > +	RTE_FLOW_ITEM_TCP_PORT_SRC,
> > > > +	RTE_FLOW_ITEM_TCP_PORT_DST,
> > > > +	RTE_FLOW_ITEM_TCP_SEQ_NUM,
> > > > +	RTE_FLOW_ITEM_TCP_ACK_NUM,
> > > > +	RTE_FLOW_ITEM_TCP_FLAGS,
> > > > +	RTE_FLOW_ITEM_UDP_PORT_SRC,
> > > > +	RTE_FLOW_ITEM_UDP_PORT_DST,
> > > > +	RTE_FLOW_ITEM_VXLAN_VNI,
> > > > +	RTE_FLOW_ITEM_GENEVE_VNI,
> > > > +	RTE_FLOW_ITEM_GTP_TEID,
> > > > +	RTE_FLOW_ITEM_TAG,
> > > > +	RTE_FLOW_ITEM_MARK,
> > > > +	RTE_FLOW_ITEM_META,
> > > > +};
> > >
> > > I don't think this name is good since it not rte_flow_item this is just internal
> > > enumeration
> > > for this action.
> > Will rename to rte_flow_action_copy_item_id in v3? Is this ok?
> >
> Yes better,
> Or rte_flow_copy_item_id?
> 
On second thought I think a better name should be:
rte_flow_field_id - I removed  the copy since we may use it in other actions
for example set/add

> > > > +
> > > > +struct rte_flow_action_copy_data {
> > > > +	enum rte_flow_item_id item;
> > > > +	uint32_t index;
> > > > +	uint32_t offset;
> > >
> > > Why use 32 bits? Since this copy only one register with max len of 32 bit.
> > > The max offset can 31? Same for the index.
> > This extends the flexibility of the copy API. This way you can modify any place
> > in a packet as you desire by specifying RTE_FLOW_ITEM_NONE to start with
> > the
> > beginning of a packet and choosing a particular offset value to point in a
> > desired place.
> > And since packet length can be pretty big we need to accommodate this.
> > Do you think this flexibility is not necessary and we should bound the offset to
> > the
> > length of a selected packet field only? Index is 32 bit for the same field in RSS.
> >
> Nice idea but then I would add ITEM_OFFSET or something
> around this name, I don't think NONE is a valid value.
> 
> > > > +};
> > > > +
> > > > +/**
> > > > + * RTE_FLOW_ACTION_TYPE_COPY_ITEM
> > > > + *
> > > > + * Copies a specified number of bits from a source header field
> > > > + * to a destination header field. Tag, mark or metadata can also
> > > > + * be used as a source/destination to allow saving/overwriting
> > > > + * an arbituary header field with a user-specified value.
> > > > + */
> > > > +struct rte_flow_action_copy_item {
> > > > +	struct rte_flow_action_copy_data dst;
> > > > +	struct rte_flow_action_copy_data src;
> > > > +	uint32_t width;
> > >
> > > Why use 32 bit register?
> > Again, to make API as generic as possible in case there will be a PMD driver
> > that can copy a huge chunk of a packet into the another place of this packet.
> > What is your opinion on that?
> >
> Nice thinking,
> 
> > >
> > > > +};
> > > > +
> > > >  /* Mbuf dynamic field offset for metadata. */
> > > >  extern int32_t rte_flow_dynf_metadata_offs;
> > > >
> > > > --
> > > > 2.24.1
> > >
> > > Best,
> > > Ori


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-12 15:13       ` Ori Kam
@ 2021-01-12 17:19         ` Alexander Kozyrev
  0 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-12 17:19 UTC (permalink / raw)
  To: Ori Kam, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

> > From: Ori Kam onTuesday, January 12, 2021 4:53 PM
> > To: Alexander Kozyrev <akozyrev@nvidia.com>; dev@dpdk.org
> > Cc: Slava Ovsiienko <viacheslavo@nvidia.com>; NBU-Contact-Thomas
> Monjalon
> > <thomas@monjalon.net>; ferruh.yigit@intel.com;
> > andrew.rybchenko@oktetlabs.ru
> > Subject: RE: [PATCH] ethdev: introduce generic copy rte flow action
> >
> > Hi,
> >
> > > -----Original Message-----
> > > From: Alexander Kozyrev <akozyrev@nvidia.com>
> > > Sent: Tuesday, January 12, 2021 4:16 PM
> > > To: Ori Kam <orika@nvidia.com>; dev@dpdk.org
> > > Cc: Slava Ovsiienko <viacheslavo@nvidia.com>; NBU-Contact-Thomas
> > Monjalon
> > > <thomas@monjalon.net>; ferruh.yigit@intel.com;
> > > andrew.rybchenko@oktetlabs.ru
> > > Subject: RE: [PATCH] ethdev: introduce generic copy rte flow action
> > >
> > > > From: Ori Kam <orika@nvidia.com> on Sunday, January 10, 2021 3:01
> > > > Hi Alexander,
> > > >
> > > > I guess that the test-pmd part will be available later right?
> > > Yes, please take a look at v2 version for testpmd implementation.
> > >
> > > > > -----Original Message-----
> > > > > From: Alexander Kozyrev <akozyrev@nvidia.com>
> > > > > Sent: Friday, January 8, 2021 8:33 AM
> > > > > Subject: [PATCH] ethdev: introduce generic copy rte flow action
> > > > >
> > > > > Implement a generic copy flow API to allow copying of an arbitrary
> > > > > header field (as well as mark, metadata or tag) to another item.
> > > > >
> > > > > This generic copy mechanism removes the necessity to implement a
> > > > > separate RTE Flow action every time we need to modify a new packet
> > > > > field in the future. A user-provided value can be used from a
> > > > > specified tag/metadata or directly copied from other packet field.
> > > > >
> > > > > The number of bits to copy as well as the offset to start from can
> > > > > be specified to allow a partial copy or copy into an arbitrary
> > > > > place in a packet for greater flexibility.
> > > > >
> > > >
> > > > Since the question why you are using enum and not just offset from
> > > > the start of the packet, was discussed and raised by number of people it
> will
> > > be
> > > > best
> > > > if it will appear in the commit log, at least the advantages to this
> > > > implementation.
> > > Ok, will add to v3 commit message.
> > >
> > > > > RFC:
> > > > >
> > > >
> >
> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatches.
> > > > d
> > > > >
> > > >
> > >
> >
> pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com%
> > > > >
> > > >
> > >
> >
> 7Cd04c2e49c3a840994da408d8b39f3304%7C43083d15727340c1b7db39efd9cc
> > > > >
> > > >
> > >
> >
> c17a%7C0%7C0%7C637456843629116269%7CUnknown%7CTWFpbGZsb3d8eyJ
> > > > >
> > > >
> > >
> >
> WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C
> > > > >
> > >
> > 1000&amp;sdata=85096rASBtzbjU42pV6sPkl3nVt5HlR6%2BL9nxI3qgFA%3D&a
> > > > > mp;reserved=0
> > > > >
> > > > > Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> > > > > ---
> > > > >  doc/guides/prog_guide/rte_flow.rst | 35 ++++++++++++++++++
> > > > >  lib/librte_ethdev/rte_flow.c       |  1 +
> > > > >  lib/librte_ethdev/rte_flow.h       | 59
> > ++++++++++++++++++++++++++++++
> > > > >  3 files changed, 95 insertions(+)
> > > > >
> > > > > diff --git a/doc/guides/prog_guide/rte_flow.rst
> > > > > b/doc/guides/prog_guide/rte_flow.rst
> > > > > index 86b3444803..b737ff9dad 100644
> > > > > --- a/doc/guides/prog_guide/rte_flow.rst
> > > > > +++ b/doc/guides/prog_guide/rte_flow.rst
> > > > > @@ -2766,6 +2766,41 @@ The behaviour of the shared action defined
> by
> > > > > ``action`` argument of type
> > > > >     | no properties |
> > > > >     +---------------+
> > > > >
> > > > > +Action: ``COPY_ITEM``
> > > > > +^^^^^^^^^^^^^^^^^^^^^
> > > > > +
> > > > > +Copy ``width`` bits from ``src`` item to ``dst`` item.
> > > > > +
> > > > > +An arbitrary header field (as well as mark, metadata or tag values)
> > > > > +can be used as both source and destination items as set by ``item``.
> > > > > +
> > > >
> > > > For tag I think you should also use the index right?
> > > Right, index is here to access any element in the tag array in addition to
> > > outermost or any inner packet header fields. Will specify explicitly in the doc.
> > >
> > > > > +Inner packet header fields can be accessed using the ``index`` and
> > > > > +it is possible to start the copy from the ``offset`` bits in an item.
> > > >
> > > > Please specify  what means index 0 /1 ... 0 is outer most? Inner most?
> > > > You can look at the RSS level for reference.
> > > > I think it will be best to use the same values.
> > > 0 is outer most, of course,  I'Il add some clarification about that.
> > >
> > Not necessary, like I said please look at the RSS, 0 can mean the inner most.
> >
> > > > What happens if we want to copy between different sizes?
> > > > for example copy IPV6 src to number of tags? I assume we will be using
> > offset
> > > > and
> > > > split the copy command to number of actions right?
> > > That is the correct understanding. We can utilize 4 copy_item actions in this
> > > case to
> > > copy 32-bits of an IPv6 SRC at the time (specifying different offsets) to 4
> > > different Tag fields.
> > >
> > > > > +
> > > > > +.. _table_rte_flow_action_copy_item:
> > > > > +
> > > > > +.. table:: COPY_ITEM
> > > > > +
> > > > > +   +-----------------------------------------+
> > > > > +   | Field         | Value                   |
> > > > > +   +===============+=========================+
> > > > > +   | ``dst``       | destination item        |
> > > > > +   | ``src``       | source item             |
> > > > > +   | ``width``     | number of bits to copy  |
> > > > > +   +---------------+-------------------------+
> > > > > +
> > > > > +.. _table_rte_flow_action_copy_data:
> > > > > +
> > > > > +.. table:: destination/source item definition
> > > > > +
> > > > > +   +----------------------------------------------------------+
> > > > > +   | Field         | Value                                    |
> > > > > +
> > > +===============+==========================================+
> > > > > +   | ``item``      | ID of a packet field/mark/metadata/tag   |
> > > > > +   | ``index``     | index of outer/inner header or tag array |
> > > > > +   | ``offset``    | number of bits to skip during the copy   |
> > > > > +   +---------------+------------------------------------------+
> > > > > +
> > > > >  Negative types
> > > > >  ~~~~~~~~~~~~~~
> > > > >
> > > > > diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
> > > > > index a06f64c271..fdbabefc47 100644
> > > > > --- a/lib/librte_ethdev/rte_flow.c
> > > > > +++ b/lib/librte_ethdev/rte_flow.c
> > > > > @@ -176,6 +176,7 @@ static const struct rte_flow_desc_data
> > > > > rte_flow_desc_action[] = {
> > > > >  	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct
> > > > > rte_flow_action_set_dscp)),
> > > > >  	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
> > > > >  	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
> > > > > +	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct
> > > > > rte_flow_action_copy_item)),
> > > > >  	/**
> > > > >  	 * Shared action represented as handle of type
> > > > >  	 * (struct rte_flow_shared action *) stored in conf field (see
> > > > > diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
> > > > > index 0977a78270..0540c861fb 100644
> > > > > --- a/lib/librte_ethdev/rte_flow.h
> > > > > +++ b/lib/librte_ethdev/rte_flow.h
> > > > > @@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
> > > > >  	 * struct rte_flow_shared_action).
> > > > >  	 */
> > > > >  	RTE_FLOW_ACTION_TYPE_SHARED,
> > > > > +
> > > > > +	/**
> > > > > +	 * Copy a packet header field, tag, mark or metadata.
> > > > > +	 *
> > > > > +	 * Allow saving an arbitrary header field by copying its value
> > > > > +	 * to a tag/mark/metadata or copy it into another header field.
> > > > > +	 *
> > > > > +	 * See struct rte_flow_action_copy_item.
> > > > > +	 */
> > > > > +	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
> > > > >  };
> > > > >
> > > > >  /**
> > > > > @@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
> > > > >   */
> > > > >  struct rte_flow_shared_action;
> > > > >
> > > > > +enum rte_flow_item_id {
> > > > > +	RTE_FLOW_ITEM_NONE = 0,
> > > > > +	RTE_FLOW_ITEM_MAC_DST,
> > > > > +	RTE_FLOW_ITEM_MAC_SRC,
> > > > > +	RTE_FLOW_ITEM_VLAN_TYPE,
> > > > > +	RTE_FLOW_ITEM_VLAN_ID,
> > > > > +	RTE_FLOW_ITEM_MAC_TYPE,
> > > > > +	RTE_FLOW_ITEM_IPV4_DSCP,
> > > > > +	RTE_FLOW_ITEM_IPV4_TTL,
> > > > > +	RTE_FLOW_ITEM_IPV4_SRC,
> > > > > +	RTE_FLOW_ITEM_IPV4_DST,
> > > > > +	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
> > > > > +	RTE_FLOW_ITEM_IPV6_SRC,
> > > > > +	RTE_FLOW_ITEM_IPV6_DST,
> > > > > +	RTE_FLOW_ITEM_TCP_PORT_SRC,
> > > > > +	RTE_FLOW_ITEM_TCP_PORT_DST,
> > > > > +	RTE_FLOW_ITEM_TCP_SEQ_NUM,
> > > > > +	RTE_FLOW_ITEM_TCP_ACK_NUM,
> > > > > +	RTE_FLOW_ITEM_TCP_FLAGS,
> > > > > +	RTE_FLOW_ITEM_UDP_PORT_SRC,
> > > > > +	RTE_FLOW_ITEM_UDP_PORT_DST,
> > > > > +	RTE_FLOW_ITEM_VXLAN_VNI,
> > > > > +	RTE_FLOW_ITEM_GENEVE_VNI,
> > > > > +	RTE_FLOW_ITEM_GTP_TEID,
> > > > > +	RTE_FLOW_ITEM_TAG,
> > > > > +	RTE_FLOW_ITEM_MARK,
> > > > > +	RTE_FLOW_ITEM_META,
> > > > > +};
> > > >
> > > > I don't think this name is good since it not rte_flow_item this is just internal
> > > > enumeration
> > > > for this action.
> > > Will rename to rte_flow_action_copy_item_id in v3? Is this ok?
> > >
> > Yes better,
> > Or rte_flow_copy_item_id?
> >
> On second thought I think a better name should be:
> rte_flow_field_id - I removed  the copy since we may use it in other actions
> for example set/add
Then I would prefer sticking to the original rte_flow_item_id naming.
It allows room for anyone to use it as a general enum and incrorporates tag/metadata
and other future extensions, not just packet fields.

> > > > > +
> > > > > +struct rte_flow_action_copy_data {
> > > > > +	enum rte_flow_item_id item;
> > > > > +	uint32_t index;
> > > > > +	uint32_t offset;
> > > >
> > > > Why use 32 bits? Since this copy only one register with max len of 32 bit.
> > > > The max offset can 31? Same for the index.
> > > This extends the flexibility of the copy API. This way you can modify any
> place
> > > in a packet as you desire by specifying RTE_FLOW_ITEM_NONE to start with
> > > the
> > > beginning of a packet and choosing a particular offset value to point in a
> > > desired place.
> > > And since packet length can be pretty big we need to accommodate this.
> > > Do you think this flexibility is not necessary and we should bound the offset
> to
> > > the
> > > length of a selected packet field only? Index is 32 bit for the same field in
> RSS.
> > >
> > Nice idea but then I would add ITEM_OFFSET or something
> > around this name, I don't think NONE is a valid value.
> >
> > > > > +};
> > > > > +
> > > > > +/**
> > > > > + * RTE_FLOW_ACTION_TYPE_COPY_ITEM
> > > > > + *
> > > > > + * Copies a specified number of bits from a source header field
> > > > > + * to a destination header field. Tag, mark or metadata can also
> > > > > + * be used as a source/destination to allow saving/overwriting
> > > > > + * an arbituary header field with a user-specified value.
> > > > > + */
> > > > > +struct rte_flow_action_copy_item {
> > > > > +	struct rte_flow_action_copy_data dst;
> > > > > +	struct rte_flow_action_copy_data src;
> > > > > +	uint32_t width;
> > > >
> > > > Why use 32 bit register?
> > > Again, to make API as generic as possible in case there will be a PMD driver
> > > that can copy a huge chunk of a packet into the another place of this packet.
> > > What is your opinion on that?
> > >
> > Nice thinking,
> >
> > > >
> > > > > +};
> > > > > +
> > > > >  /* Mbuf dynamic field offset for metadata. */
> > > > >  extern int32_t rte_flow_dynf_metadata_offs;
> > > > >
> > > > > --
> > > > > 2.24.1
> > > >
> > > > Best,
> > > > Ori


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 0/2] generic copy rte flow action support
  2021-01-12  5:01 ` [dpdk-dev] [PATCH v2 0/2] generic copy rte flow action support Alexander Kozyrev
  2021-01-12  5:01   ` [dpdk-dev] [PATCH v2 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
  2021-01-12  5:01   ` [dpdk-dev] [PATCH v2 2/2] app/testpmd: add support for " Alexander Kozyrev
@ 2021-01-13  3:38   ` Alexander Kozyrev
  2021-01-13  3:38     ` [dpdk-dev] [PATCH v3 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
                       ` (2 more replies)
  2 siblings, 3 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-13  3:38 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Implement a generic copy rte flow API as described in RFC:
http://patches.dpdk.org/patch/85384/

This API allows copying a specified number of bits from a source
header field to a destination header field. Tag, mark or metadata
can also be used as a source/destination to allow saving/overwriting
an arbitrary header field with a user-specified value.

Outermost/innermost packet fields (and Tag array elements) are
accessible via the level parameter to facilitate the modification
of encapsulated packet header fields. The offset parameter provides
the flexibility to copy/set any part of a packet starting the
specified packet header field.

---
v1: https://patchwork.dpdk.org/patch/86173/
v2: https://patchwork.dpdk.org/cover/86369/
Added testpmd support.
v3:
Made dst_type and src_type only mandatory parameters.

Alexander Kozyrev (2):
  ethdev: introduce generic copy rte flow action
  app/testpmd: add support for generic copy rte flow action

 app/test-pmd/cmdline_flow.c            | 167 +++++++++++++++++++++++++
 doc/guides/prog_guide/rte_flow.rst     |  50 ++++++++
 doc/guides/rel_notes/release_21_02.rst |   5 +
 lib/librte_ethdev/rte_flow.c           |   1 +
 lib/librte_ethdev/rte_flow.h           |  59 +++++++++
 5 files changed, 282 insertions(+)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 1/2] ethdev: introduce generic copy rte flow action
  2021-01-13  3:38   ` [dpdk-dev] [PATCH v3 0/2] generic copy rte flow action support Alexander Kozyrev
@ 2021-01-13  3:38     ` Alexander Kozyrev
  2021-01-13 11:12       ` Ori Kam
  2021-01-13  3:38     ` [dpdk-dev] [PATCH v3 2/2] app/testpmd: add support for " Alexander Kozyrev
  2021-01-13 17:07     ` [dpdk-dev] [PATCH v4 0/2] generic copy rte flow action support Alexander Kozyrev
  2 siblings, 1 reply; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-13  3:38 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Implement a generic copy flow API to allow copying of an arbitrary
header field (as well as mark, metadata or tag) to another item.

This generic copy mechanism removes the necessity to implement a
separate RTE Flow action every time we need to modify a new packet
field in the future. A user-provided value can be used from a
specified tag/metadata/mark or directly copied from another packet field.

The item ID is used to specify the desired source/destination packet
field in order to simplify the API for various encapsulation models.
Specifying the packet field ID with the needed encapsulation level
is able to quickly get a packet field for any inner packet header.

Alternatively, the special ID (ITEM_START) can be used to point to the
very beginning of a packet. This ID in conjunction with the offset
parameter provides great flexibility to copy/modify any part of a packet
 as needed.

The number of bits to copy as well as the offset to start from can
be specified to allow a partial copy or dividing a big packet field
into multiple small items (let's say copying 128 bits of IPv6 to 4 tags).

RFC: http://patches.dpdk.org/patch/85384/

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
---
 doc/guides/prog_guide/rte_flow.rst     | 50 ++++++++++++++++++++++
 doc/guides/rel_notes/release_21_02.rst |  5 +++
 lib/librte_ethdev/rte_flow.c           |  1 +
 lib/librte_ethdev/rte_flow.h           | 59 ++++++++++++++++++++++++++
 4 files changed, 115 insertions(+)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 86b3444803..d6420edc83 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2766,6 +2766,56 @@ The behaviour of the shared action defined by ``action`` argument of type
    | no properties |
    +---------------+
 
+Action: ``COPY_ITEM``
+^^^^^^^^^^^^^^^^^^^^^
+
+Copy ``width`` bits from ``src`` item to ``dst`` item.
+
+Any arbitrary header field (as well as mark, metadata or tag values)
+can be used as both source and destination items as set by ``item``.
+``RTE_FLOW_ITEM_START`` is used to point to the beginning of a packet.
+The copy is ignored in case the item specified is not present in a packet.
+
+ ``level`` is used to access any packet field on any encapsulation level
+ as well as any tag element in the tag array.
+- ``0`` means the default behaviour. Depending on the packet type, it can
+  mean outermost, innermost or anything in between.
+- ``1`` requests access to the outermost packet encapsulation level.
+- ``2`` and subsequent values requests access to the specified packet
+  encapsulation level, from outermost to innermost (lower to higher values).
+  For the tag array ``level`` translates directly into the array index.
+
+``offset`` specifies the number of bits to skip from an item start.
+That allows performing a partial copy of the needed part or to divide a big
+packet field into multiple smaller items. Alternatively, ``offset`` allows
+going past the specified packet field boundary to copy an item to an
+arbitrary place in a packet essentially providing a way to copy any part of
+a packet to any other part of it if supported by a underlying PMD driver.
+
+.. _table_rte_flow_action_copy_item:
+
+.. table:: COPY_ITEM
+
+   +-----------------------------------------+
+   | Field         | Value                   |
+   +===============+=========================+
+   | ``dst``       | destination item        |
+   | ``src``       | source item             |
+   | ``width``     | number of bits to copy  |
+   +---------------+-------------------------+
+
+.. _table_rte_flow_action_copy_data:
+
+.. table:: destination/source item definition
+
+   +--------------------------------------------------------------------------+
+   | Field         | Value                                                    |
+   +===============+==========================================================+
+   | ``item``      | item ID of a packet field or mark/metadata/tag           |
+   | ``level``     | encapsulation level of a packet field or tag array index |
+   | ``offset``    | number of bits to skip at the beginning during the copy  |
+   +---------------+----------------------------------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst
index 706cbf8f0c..6bc482a6bf 100644
--- a/doc/guides/rel_notes/release_21_02.rst
+++ b/doc/guides/rel_notes/release_21_02.rst
@@ -55,6 +55,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added support of copy action in the flow API.**
+
+  Added copy action support to copy any arbitrary header field
+  (as well as mark, metadata or tag values) to another one:
+  ``RTE_FLOW_ACTION_TYPE_COPY_ITEM``.
 
 Removed Items
 -------------
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index a06f64c271..fdbabefc47 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -176,6 +176,7 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
 	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
 	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
+	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct rte_flow_action_copy_item)),
 	/**
 	 * Shared action represented as handle of type
 	 * (struct rte_flow_shared action *) stored in conf field (see
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 0977a78270..794e59f99b 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
 	 * struct rte_flow_shared_action).
 	 */
 	RTE_FLOW_ACTION_TYPE_SHARED,
+
+	/**
+	 * Copy a packet header field, tag, mark or metadata.
+	 *
+	 * Allow saving an arbitrary header field by copying its value
+	 * to a tag/mark/metadata or copy it into another header field.
+	 *
+	 * See struct rte_flow_action_copy_item.
+	 */
+	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
 };
 
 /**
@@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+enum rte_flow_item_id {
+	RTE_FLOW_ITEM_START = 0,
+	RTE_FLOW_ITEM_MAC_DST,
+	RTE_FLOW_ITEM_MAC_SRC,
+	RTE_FLOW_ITEM_VLAN_TYPE,
+	RTE_FLOW_ITEM_VLAN_ID,
+	RTE_FLOW_ITEM_MAC_TYPE,
+	RTE_FLOW_ITEM_IPV4_DSCP,
+	RTE_FLOW_ITEM_IPV4_TTL,
+	RTE_FLOW_ITEM_IPV4_SRC,
+	RTE_FLOW_ITEM_IPV4_DST,
+	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
+	RTE_FLOW_ITEM_IPV6_SRC,
+	RTE_FLOW_ITEM_IPV6_DST,
+	RTE_FLOW_ITEM_TCP_PORT_SRC,
+	RTE_FLOW_ITEM_TCP_PORT_DST,
+	RTE_FLOW_ITEM_TCP_SEQ_NUM,
+	RTE_FLOW_ITEM_TCP_ACK_NUM,
+	RTE_FLOW_ITEM_TCP_FLAGS,
+	RTE_FLOW_ITEM_UDP_PORT_SRC,
+	RTE_FLOW_ITEM_UDP_PORT_DST,
+	RTE_FLOW_ITEM_VXLAN_VNI,
+	RTE_FLOW_ITEM_GENEVE_VNI,
+	RTE_FLOW_ITEM_GTP_TEID,
+	RTE_FLOW_ITEM_TAG,
+	RTE_FLOW_ITEM_MARK,
+	RTE_FLOW_ITEM_META,
+};
+
+struct rte_flow_action_copy_data {
+	enum rte_flow_item_id item;
+	uint32_t level;
+	uint32_t offset;
+};
+
+/**
+ * RTE_FLOW_ACTION_TYPE_COPY_ITEM
+ *
+ * Copies a specified number of bits from a source header field
+ * to a destination header field. Tag, mark or metadata can also
+ * be used as a source/destination to allow saving/overwriting
+ * an arbitrary header field with a user-specified value.
+ */
+struct rte_flow_action_copy_item {
+	struct rte_flow_action_copy_data dst;
+	struct rte_flow_action_copy_data src;
+	uint32_t width;
+};
+
 /* Mbuf dynamic field offset for metadata. */
 extern int32_t rte_flow_dynf_metadata_offs;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v3 2/2] app/testpmd: add support for generic copy rte flow action
  2021-01-13  3:38   ` [dpdk-dev] [PATCH v3 0/2] generic copy rte flow action support Alexander Kozyrev
  2021-01-13  3:38     ` [dpdk-dev] [PATCH v3 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
@ 2021-01-13  3:38     ` Alexander Kozyrev
  2021-01-13 17:07     ` [dpdk-dev] [PATCH v4 0/2] generic copy rte flow action support Alexander Kozyrev
  2 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-13  3:38 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Add support for the RTE_FLOW_ACTION_COPY_ITEM to the testpmd.
Implement CLI to create the copy_item action and supply all the
needed parameters to copy an arbitrary packet field (as well as
mark, tag or metadata) into another item.

Example of the flow is the following:
flow create 0 egress group 1 pattern eth / ipv4 / udp / end
     actions copy_item dst_type tag dst_level 0 dst_offset 8
     src_type gtp_teid src_level 0 src_offset 0 width 32 / end

This flow copies 32 bits from the first Tag in the Tags array
into the outermost GTP TEID packet header field. 8 bits of the
Tag are skipped as indicated by the dst_offset action parameter.

dst_type and src_type are the only mandatory parameters to
specify. Levels and offset are 0 by default if they are not
overriden by a user. The width parameter gets the smallest width
from the source and destination sizes if it is not specified.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
---
 app/test-pmd/cmdline_flow.c | 167 ++++++++++++++++++++++++++++++++++++
 1 file changed, 167 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 585cab98b4..374642c1c1 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -408,6 +408,16 @@ enum index {
 	ACTION_SAMPLE_INDEX_VALUE,
 	ACTION_SHARED,
 	SHARED_ACTION_ID2PTR,
+	ACTION_COPY_ITEM,
+	ACTION_COPY_ITEM_DST_TYPE,
+	ACTION_COPY_ITEM_DST_TYPE_VALUE,
+	ACTION_COPY_ITEM_DST_LEVEL,
+	ACTION_COPY_ITEM_DST_OFFSET,
+	ACTION_COPY_ITEM_SRC_TYPE,
+	ACTION_COPY_ITEM_SRC_TYPE_VALUE,
+	ACTION_COPY_ITEM_SRC_LEVEL,
+	ACTION_COPY_ITEM_SRC_OFFSET,
+	ACTION_COPY_ITEM_WIDTH,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -561,6 +571,18 @@ struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 
+static const char *const copy_item_table[] = {
+	"start", "mac_dst", "mac_src",
+	"vlan_type", "vlan_id", "mac_type",
+	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
+	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
+	"tcp_port_src", "tcp_port_dst",
+	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
+	"udp_port_src", "udp_port_dst",
+	"vxlan_vni", "geneve_vni", "gtp_teid",
+	"tag", "mark", "meta", NULL
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -1306,6 +1328,7 @@ static const enum index next_action[] = {
 	ACTION_AGE,
 	ACTION_SAMPLE,
 	ACTION_SHARED,
+	ACTION_COPY_ITEM,
 	ZERO,
 };
 
@@ -1556,6 +1579,21 @@ static const enum index next_action_sample[] = {
 	ZERO,
 };
 
+static const enum index action_copy_item_dst[] = {
+	ACTION_COPY_ITEM_DST_LEVEL,
+	ACTION_COPY_ITEM_DST_OFFSET,
+	ACTION_COPY_ITEM_SRC_TYPE,
+	ZERO,
+};
+
+static const enum index action_copy_item_src[] = {
+	ACTION_COPY_ITEM_SRC_LEVEL,
+	ACTION_COPY_ITEM_SRC_OFFSET,
+	ACTION_COPY_ITEM_WIDTH,
+	ACTION_NEXT,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -1638,6 +1676,10 @@ static int
 parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 				const char *str, unsigned int len, void *buf,
 				unsigned int size);
+static int
+parse_vc_copy_item(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1722,6 +1764,8 @@ static int comp_set_raw_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
 static int comp_set_sample_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
+static int comp_set_copy_item(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -4037,6 +4081,81 @@ static const struct token token_list[] = {
 		.call = parse_vc_action_raw_decap_index,
 		.comp = comp_set_raw_index,
 	},
+	[ACTION_COPY_ITEM] = {
+		.name = "copy_item",
+		.help = "copy data from destination to source item",
+		.priv = PRIV_ACTION(COPY_ITEM,
+			sizeof(struct rte_flow_action_copy_item)),
+		.next = NEXT(NEXT_ENTRY(ACTION_COPY_ITEM_DST_TYPE)),
+		.call = parse_vc,
+	},
+	[ACTION_COPY_ITEM_DST_TYPE] = {
+		.name = "dst_type",
+		.help = "destination item type",
+		.next = NEXT(action_copy_item_dst,
+			NEXT_ENTRY(ACTION_COPY_ITEM_DST_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_DST_TYPE_VALUE] = {
+		.name = "{type}",
+		.help = "destination item type value",
+		.call = parse_vc_copy_item,
+		.comp = comp_set_copy_item,
+	},
+	[ACTION_COPY_ITEM_DST_LEVEL] = {
+		.name = "dst_level",
+		.help = "destination item level",
+		.next = NEXT(action_copy_item_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					dst.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_DST_OFFSET] = {
+		.name = "dst_offset",
+		.help = "destination item bit offset",
+		.next = NEXT(action_copy_item_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					dst.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_SRC_TYPE] = {
+		.name = "src_type",
+		.help = "source item type",
+		.next = NEXT(action_copy_item_src,
+			NEXT_ENTRY(ACTION_COPY_ITEM_SRC_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_SRC_TYPE_VALUE] = {
+		.name = "{type}",
+		.help = "source item type value",
+		.call = parse_vc_copy_item,
+		.comp = comp_set_copy_item,
+	},
+	[ACTION_COPY_ITEM_SRC_LEVEL] = {
+		.name = "src_level",
+		.help = "source item level",
+		.next = NEXT(action_copy_item_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					src.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_SRC_OFFSET] = {
+		.name = "src_offset",
+		.help = "source item bit offset",
+		.next = NEXT(action_copy_item_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					src.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_ITEM_WIDTH] = {
+		.name = "width",
+		.help = "number of bits to copy",
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_item,
+					width)),
+		.call = parse_vc_conf,
+	},
 	/* Top level command. */
 	[SET] = {
 		.name = "set",
@@ -5960,6 +6079,36 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse tokens for copy_item command. */
+static int
+parse_vc_copy_item(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_copy_item *action_copy_item;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_COPY_ITEM_DST_TYPE_VALUE &&
+		ctx->curr != ACTION_COPY_ITEM_SRC_TYPE_VALUE)
+		return -1;
+	for (i = 0; copy_item_table[i]; ++i)
+		if (!strcmp_partial(copy_item_table[i], str, len))
+			break;
+	if (!copy_item_table[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_copy_item = ctx->object;
+	if (ctx->curr == ACTION_COPY_ITEM_DST_TYPE_VALUE)
+		action_copy_item->dst.item = (enum rte_flow_item_id)i;
+	else
+		action_copy_item->src.item = (enum rte_flow_item_id)i;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -7029,6 +7178,24 @@ comp_set_sample_index(struct context *ctx, const struct token *token,
 	return nb;
 }
 
+/** Complete item type for copy_item command. */
+static int
+comp_set_copy_item(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; copy_item_table[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, copy_item_table[ent], size);
+	return -1;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v3 1/2] ethdev: introduce generic copy rte flow action
  2021-01-13  3:38     ` [dpdk-dev] [PATCH v3 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
@ 2021-01-13 11:12       ` Ori Kam
  0 siblings, 0 replies; 48+ messages in thread
From: Ori Kam @ 2021-01-13 11:12 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

Hi Alexander,

> -----Original Message-----
> From: Alexander Kozyrev <akozyrev@nvidia.com>
> Sent: Wednesday, January 13, 2021 5:39 AM
> Subject: [PATCH v3 1/2] ethdev: introduce generic copy rte flow action
> 
> Implement a generic copy flow API to allow copying of an arbitrary
> header field (as well as mark, metadata or tag) to another item.
> 
> This generic copy mechanism removes the necessity to implement a
> separate RTE Flow action every time we need to modify a new packet
> field in the future. A user-provided value can be used from a
> specified tag/metadata/mark or directly copied from another packet field.
> 
> The item ID is used to specify the desired source/destination packet
> field in order to simplify the API for various encapsulation models.
> Specifying the packet field ID with the needed encapsulation level
> is able to quickly get a packet field for any inner packet header.
> 
> Alternatively, the special ID (ITEM_START) can be used to point to the
> very beginning of a packet. This ID in conjunction with the offset
> parameter provides great flexibility to copy/modify any part of a packet
>  as needed.
> 
> The number of bits to copy as well as the offset to start from can
> be specified to allow a partial copy or dividing a big packet field
> into multiple small items (let's say copying 128 bits of IPv6 to 4 tags).
> 
> RFC:
> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatches.d
> pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com%
> 7C57d1832b57bf4d6852e808d8b774c4b9%7C43083d15727340c1b7db39efd9cc
> c17a%7C0%7C0%7C637461059443472688%7CUnknown%7CTWFpbGZsb3d8eyJ
> WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C
> 1000&amp;sdata=7g5wYtlhsN9z2m%2FGMMMGt6rV2bx2z6oFLW1pzGJVGqA%3
> D&amp;reserved=0
> 
> Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> ---
>  doc/guides/prog_guide/rte_flow.rst     | 50 ++++++++++++++++++++++
>  doc/guides/rel_notes/release_21_02.rst |  5 +++
>  lib/librte_ethdev/rte_flow.c           |  1 +
>  lib/librte_ethdev/rte_flow.h           | 59 ++++++++++++++++++++++++++
>  4 files changed, 115 insertions(+)
> 
> diff --git a/doc/guides/prog_guide/rte_flow.rst
> b/doc/guides/prog_guide/rte_flow.rst
> index 86b3444803..d6420edc83 100644
> --- a/doc/guides/prog_guide/rte_flow.rst
> +++ b/doc/guides/prog_guide/rte_flow.rst
> @@ -2766,6 +2766,56 @@ The behaviour of the shared action defined by
> ``action`` argument of type
>     | no properties |
>     +---------------+
> 
> +Action: ``COPY_ITEM``
> +^^^^^^^^^^^^^^^^^^^^^
> +
> +Copy ``width`` bits from ``src`` item to ``dst`` item.
> +
> +Any arbitrary header field (as well as mark, metadata or tag values)
> +can be used as both source and destination items as set by ``item``.
> +``RTE_FLOW_ITEM_START`` is used to point to the beginning of a packet.
> +The copy is ignored in case the item specified is not present in a packet.
> +
> + ``level`` is used to access any packet field on any encapsulation level
> + as well as any tag element in the tag array.
> +- ``0`` means the default behaviour. Depending on the packet type, it can
> +  mean outermost, innermost or anything in between.
> +- ``1`` requests access to the outermost packet encapsulation level.
> +- ``2`` and subsequent values requests access to the specified packet
> +  encapsulation level, from outermost to innermost (lower to higher values).
> +  For the tag array ``level`` translates directly into the array index.
> +
> +``offset`` specifies the number of bits to skip from an item start.
> +That allows performing a partial copy of the needed part or to divide a big
> +packet field into multiple smaller items. Alternatively, ``offset`` allows
> +going past the specified packet field boundary to copy an item to an
> +arbitrary place in a packet essentially providing a way to copy any part of
> +a packet to any other part of it if supported by a underlying PMD driver.
> +
> +.. _table_rte_flow_action_copy_item:
> +
> +.. table:: COPY_ITEM
> +
> +   +-----------------------------------------+
> +   | Field         | Value                   |
> +   +===============+=========================+
> +   | ``dst``       | destination item        |
> +   | ``src``       | source item             |
> +   | ``width``     | number of bits to copy  |
> +   +---------------+-------------------------+
> +
> +.. _table_rte_flow_action_copy_data:
> +
> +.. table:: destination/source item definition
> +
> +   +--------------------------------------------------------------------------+
> +   | Field         | Value                                                    |
> +
> +===============+===============================================
> ===========+
> +   | ``item``      | item ID of a packet field or mark/metadata/tag           |
> +   | ``level``     | encapsulation level of a packet field or tag array index |
> +   | ``offset``    | number of bits to skip at the beginning during the copy  |
> +   +---------------+----------------------------------------------------------+
> +
>  Negative types
>  ~~~~~~~~~~~~~~
> 
> diff --git a/doc/guides/rel_notes/release_21_02.rst
> b/doc/guides/rel_notes/release_21_02.rst
> index 706cbf8f0c..6bc482a6bf 100644
> --- a/doc/guides/rel_notes/release_21_02.rst
> +++ b/doc/guides/rel_notes/release_21_02.rst
> @@ -55,6 +55,11 @@ New Features
>       Also, make sure to start the actual text at the margin.
>       =======================================================
> 
> +* **Added support of copy action in the flow API.**
> +
> +  Added copy action support to copy any arbitrary header field
> +  (as well as mark, metadata or tag values) to another one:
> +  ``RTE_FLOW_ACTION_TYPE_COPY_ITEM``.
> 
>  Removed Items
>  -------------
> diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
> index a06f64c271..fdbabefc47 100644
> --- a/lib/librte_ethdev/rte_flow.c
> +++ b/lib/librte_ethdev/rte_flow.c
> @@ -176,6 +176,7 @@ static const struct rte_flow_desc_data
> rte_flow_desc_action[] = {
>  	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct
> rte_flow_action_set_dscp)),
>  	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
>  	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
> +	MK_FLOW_ACTION(COPY_ITEM, sizeof(struct
> rte_flow_action_copy_item)),
>  	/**
>  	 * Shared action represented as handle of type
>  	 * (struct rte_flow_shared action *) stored in conf field (see
> diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
> index 0977a78270..794e59f99b 100644
> --- a/lib/librte_ethdev/rte_flow.h
> +++ b/lib/librte_ethdev/rte_flow.h
> @@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
>  	 * struct rte_flow_shared_action).
>  	 */
>  	RTE_FLOW_ACTION_TYPE_SHARED,
> +
> +	/**
> +	 * Copy a packet header field, tag, mark or metadata.
> +	 *
> +	 * Allow saving an arbitrary header field by copying its value
> +	 * to a tag/mark/metadata or copy it into another header field.
> +	 *
> +	 * See struct rte_flow_action_copy_item.
> +	 */
> +	RTE_FLOW_ACTION_TYPE_COPY_ITEM,
>  };
> 
>  /**
> @@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
>   */
>  struct rte_flow_shared_action;
> 
> +enum rte_flow_item_id {
> +	RTE_FLOW_ITEM_START = 0,
> +	RTE_FLOW_ITEM_MAC_DST,
> +	RTE_FLOW_ITEM_MAC_SRC,
> +	RTE_FLOW_ITEM_VLAN_TYPE,
> +	RTE_FLOW_ITEM_VLAN_ID,
> +	RTE_FLOW_ITEM_MAC_TYPE,
> +	RTE_FLOW_ITEM_IPV4_DSCP,
> +	RTE_FLOW_ITEM_IPV4_TTL,
> +	RTE_FLOW_ITEM_IPV4_SRC,
> +	RTE_FLOW_ITEM_IPV4_DST,
> +	RTE_FLOW_ITEM_IPV6_HOPLIMIT,
> +	RTE_FLOW_ITEM_IPV6_SRC,
> +	RTE_FLOW_ITEM_IPV6_DST,
> +	RTE_FLOW_ITEM_TCP_PORT_SRC,
> +	RTE_FLOW_ITEM_TCP_PORT_DST,
> +	RTE_FLOW_ITEM_TCP_SEQ_NUM,
> +	RTE_FLOW_ITEM_TCP_ACK_NUM,
> +	RTE_FLOW_ITEM_TCP_FLAGS,
> +	RTE_FLOW_ITEM_UDP_PORT_SRC,
> +	RTE_FLOW_ITEM_UDP_PORT_DST,
> +	RTE_FLOW_ITEM_VXLAN_VNI,
> +	RTE_FLOW_ITEM_GENEVE_VNI,
> +	RTE_FLOW_ITEM_GTP_TEID,
> +	RTE_FLOW_ITEM_TAG,
> +	RTE_FLOW_ITEM_MARK,
> +	RTE_FLOW_ITEM_META,
> +};
> +
Please change the names, RTE_FLOW_ITEM_XXX means that it can be
used as rte_flow item this is not the case here.
Maybe RTE_FLOW_FIELD_XXX?


> +struct rte_flow_action_copy_data {
> +	enum rte_flow_item_id item;
> +	uint32_t level;
> +	uint32_t offset;
> +};
> +
> +/**
> + * RTE_FLOW_ACTION_TYPE_COPY_ITEM
> + *
> + * Copies a specified number of bits from a source header field
> + * to a destination header field. Tag, mark or metadata can also
> + * be used as a source/destination to allow saving/overwriting
> + * an arbitrary header field with a user-specified value.
> + */
> +struct rte_flow_action_copy_item {
> +	struct rte_flow_action_copy_data dst;
> +	struct rte_flow_action_copy_data src;
> +	uint32_t width;
> +};
> +
>  /* Mbuf dynamic field offset for metadata. */
>  extern int32_t rte_flow_dynf_metadata_offs;
> 
> --
> 2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v4 0/2] generic copy rte flow action support
  2021-01-13  3:38   ` [dpdk-dev] [PATCH v3 0/2] generic copy rte flow action support Alexander Kozyrev
  2021-01-13  3:38     ` [dpdk-dev] [PATCH v3 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
  2021-01-13  3:38     ` [dpdk-dev] [PATCH v3 2/2] app/testpmd: add support for " Alexander Kozyrev
@ 2021-01-13 17:07     ` Alexander Kozyrev
  2021-01-13 17:07       ` [dpdk-dev] [PATCH v4 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
                         ` (2 more replies)
  2 siblings, 3 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-13 17:07 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Implement a generic copy rte flow API as described in RFC:
http://patches.dpdk.org/patch/85384/

This API allows copying a specified number of bits from a source
header field to a destination header field. Tag, mark or metadata
can also be used as a source/destination to allow saving/overwriting
an arbitrary header field with a user-specified value.

Outermost/innermost packet fields (and Tag array elements) are
accessible via the level parameter to facilitate the modification
of encapsulated packet header fields. The offset parameter provides
the flexibility to copy/set any part of a packet starting the
specified packet header field.

---
v1: https://patchwork.dpdk.org/patch/86173/
v2: https://patchwork.dpdk.org/cover/86369/
Added testpmd support.
v3: https://patchwork.dpdk.org/cover/86442/
Made dst_type, src_type and width only mandatory parameters.
v4:
Renamed action to TE_FLOW_ACTION_TYPE_COPY_FIELD.


Alexander Kozyrev (2):
  ethdev: introduce generic copy rte flow action
  app/testpmd: add support for generic copy rte flow action

 app/test-pmd/cmdline_flow.c            | 166 +++++++++++++++++++++++++
 doc/guides/prog_guide/rte_flow.rst     |  57 +++++++++
 doc/guides/rel_notes/release_21_02.rst |   5 +
 lib/librte_ethdev/rte_flow.c           |   1 +
 lib/librte_ethdev/rte_flow.h           |  59 +++++++++
 5 files changed, 288 insertions(+)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v4 1/2] ethdev: introduce generic copy rte flow action
  2021-01-13 17:07     ` [dpdk-dev] [PATCH v4 0/2] generic copy rte flow action support Alexander Kozyrev
@ 2021-01-13 17:07       ` Alexander Kozyrev
  2021-01-14 12:22         ` Ori Kam
  2021-01-13 17:07       ` [dpdk-dev] [PATCH v4 2/2] app/testpmd: add support for " Alexander Kozyrev
  2021-01-15 15:42       ` [dpdk-dev] [PATCH v5 0/2] generic modify rte flow action support Alexander Kozyrev
  2 siblings, 1 reply; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-13 17:07 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Implement a generic copy flow API to allow copying of an arbitrary
header field (as well as mark, metadata or tag) to another field.

This generic copy mechanism removes the necessity to implement a
separate RTE Flow action every time we need to modify a new packet
field in the future. A user-provided value can be used from a
specified tag/metadata/mark or directly copied from another packet field.

The field ID is used to specify the desired source/destination packet
field in order to simplify the API for various encapsulation models.
Specifying the packet field ID with the needed encapsulation level
is able to quickly get a packet field for any inner packet header.

Alternatively, the special ID (ITEM_START) can be used to point to the
very beginning of a packet. This ID in conjunction with the offset
parameter provides great flexibility to copy/modify any part of a packet
 as needed.

The number of bits to copy as well as the offset to start from can
be specified to allow a partial copy or dividing a big packet field
into multiple small fields (let's say copying 128 bits of IPv6 to 4 tags).

RFC: http://patches.dpdk.org/patch/85384/

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
---
 doc/guides/prog_guide/rte_flow.rst     | 57 +++++++++++++++++++++++++
 doc/guides/rel_notes/release_21_02.rst |  5 +++
 lib/librte_ethdev/rte_flow.c           |  1 +
 lib/librte_ethdev/rte_flow.h           | 59 ++++++++++++++++++++++++++
 4 files changed, 122 insertions(+)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 86b3444803..9617b9c1ba 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2766,6 +2766,63 @@ The behaviour of the shared action defined by ``action`` argument of type
    | no properties |
    +---------------+
 
+Action: ``COPY_FIELD``
+^^^^^^^^^^^^^^^^^^^^^^
+
+Copy ``width`` bits from ``src`` field to ``dst`` field.
+
+Any arbitrary header field (as well as mark, metadata or tag values)
+can be used as both source and destination fields as set by ``field``.
+``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet.
+The copy is ignored in case the field specified is not present in a packet.
+
+ ``width`` defines a number of bits to copy. A user is responsible for
+ supplying the appropriate length to copy. The width that exceeds the
+ hardware capabilities is rejected.
+
+ ``level`` is used to access any packet field on any encapsulation level
+ as well as any tag element in the tag array.
+
+- ``0`` means the default behaviour. Depending on the packet type, it can
+  mean outermost, innermost or anything in between.
+
+- ``1`` requests access to the outermost packet encapsulation level.
+
+- ``2`` and subsequent values requests access to the specified packet
+  encapsulation level, from outermost to innermost (lower to higher values).
+  For the tag array ``level`` translates directly into the array index.
+
+``offset`` specifies the number of bits to skip from an field's start.
+That allows performing a partial copy of the needed part or to divide a big
+packet field into multiple smaller fields. Alternatively, ``offset`` allows
+going past the specified packet field boundary to copy an field to an
+arbitrary place in a packet essentially providing a way to copy any part of
+a packet to any other part of it if supported by a underlying PMD driver.
+
+.. _table_rte_flow_action_copy_field:
+
+.. table:: COPY_FIELD
+
+   +-----------------------------------------+
+   | Field         | Value                   |
+   +===============+=========================+
+   | ``dst``       | destination field       |
+   | ``src``       | source field            |
+   | ``width``     | number of bits to copy  |
+   +---------------+-------------------------+
+
+.. _table_rte_flow_action_copy_data:
+
+.. table:: destination/source field definition
+
+   +--------------------------------------------------------------------------+
+   | Field         | Value                                                    |
+   +===============+==========================================================+
+   | ``field``     | field ID of a packet field or mark/metadata/tag          |
+   | ``level``     | encapsulation level of a packet field or tag array index |
+   | ``offset``    | number of bits to skip at the beginning during the copy  |
+   +---------------+----------------------------------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst
index 706cbf8f0c..109b082931 100644
--- a/doc/guides/rel_notes/release_21_02.rst
+++ b/doc/guides/rel_notes/release_21_02.rst
@@ -55,6 +55,11 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added support of copy action in the flow API.**
+
+  Added copy action support to copy any arbitrary header field
+  (as well as mark, metadata or tag values) to another one:
+  ``RTE_FLOW_ACTION_TYPE_COPY_FIELD``.
 
 Removed Items
 -------------
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index a06f64c271..c3154a29e2 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -176,6 +176,7 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
 	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
 	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
+	MK_FLOW_ACTION(COPY_FIELD, sizeof(struct rte_flow_action_copy_field)),
 	/**
 	 * Shared action represented as handle of type
 	 * (struct rte_flow_shared action *) stored in conf field (see
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 0977a78270..e2a2807f65 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2198,6 +2198,16 @@ enum rte_flow_action_type {
 	 * struct rte_flow_shared_action).
 	 */
 	RTE_FLOW_ACTION_TYPE_SHARED,
+
+	/**
+	 * Copy a packet header field, tag, mark or metadata.
+	 *
+	 * Allow saving an arbitrary header field by copying its value
+	 * to a tag/mark/metadata or copy it into another header field.
+	 *
+	 * See struct rte_flow_action_copy_field.
+	 */
+	RTE_FLOW_ACTION_TYPE_COPY_FIELD,
 };
 
 /**
@@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+enum rte_flow_field_id {
+	RTE_FLOW_FIELD_START = 0,
+	RTE_FLOW_FIELD_MAC_DST,
+	RTE_FLOW_FIELD_MAC_SRC,
+	RTE_FLOW_FIELD_VLAN_TYPE,
+	RTE_FLOW_FIELD_VLAN_ID,
+	RTE_FLOW_FIELD_MAC_TYPE,
+	RTE_FLOW_FIELD_IPV4_DSCP,
+	RTE_FLOW_FIELD_IPV4_TTL,
+	RTE_FLOW_FIELD_IPV4_SRC,
+	RTE_FLOW_FIELD_IPV4_DST,
+	RTE_FLOW_FIELD_IPV6_HOPLIMIT,
+	RTE_FLOW_FIELD_IPV6_SRC,
+	RTE_FLOW_FIELD_IPV6_DST,
+	RTE_FLOW_FIELD_TCP_PORT_SRC,
+	RTE_FLOW_FIELD_TCP_PORT_DST,
+	RTE_FLOW_FIELD_TCP_SEQ_NUM,
+	RTE_FLOW_FIELD_TCP_ACK_NUM,
+	RTE_FLOW_FIELD_TCP_FLAGS,
+	RTE_FLOW_FIELD_UDP_PORT_SRC,
+	RTE_FLOW_FIELD_UDP_PORT_DST,
+	RTE_FLOW_FIELD_VXLAN_VNI,
+	RTE_FLOW_FIELD_GENEVE_VNI,
+	RTE_FLOW_FIELD_GTP_TEID,
+	RTE_FLOW_FIELD_TAG,
+	RTE_FLOW_FIELD_MARK,
+	RTE_FLOW_FIELD_META,
+};
+
+struct rte_flow_action_copy_data {
+	enum rte_flow_field_id field;
+	uint32_t level;
+	uint32_t offset;
+};
+
+/**
+ * RTE_FLOW_ACTION_TYPE_COPY_FIELD
+ *
+ * Copies a specified number of bits from a source header field
+ * to a destination header field. Tag, mark or metadata can also
+ * be used as a source/destination to allow saving/overwriting
+ * an arbitrary header field with a user-specified value.
+ */
+struct rte_flow_action_copy_field {
+	struct rte_flow_action_copy_data dst;
+	struct rte_flow_action_copy_data src;
+	uint32_t width;
+};
+
 /* Mbuf dynamic field offset for metadata. */
 extern int32_t rte_flow_dynf_metadata_offs;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v4 2/2] app/testpmd: add support for generic copy rte flow action
  2021-01-13 17:07     ` [dpdk-dev] [PATCH v4 0/2] generic copy rte flow action support Alexander Kozyrev
  2021-01-13 17:07       ` [dpdk-dev] [PATCH v4 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
@ 2021-01-13 17:07       ` Alexander Kozyrev
  2021-01-14 15:18         ` Ori Kam
  2021-01-15 15:42       ` [dpdk-dev] [PATCH v5 0/2] generic modify rte flow action support Alexander Kozyrev
  2 siblings, 1 reply; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-13 17:07 UTC (permalink / raw)
  To: dev; +Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko

Add support for the RTE_FLOW_ACTION_COPY_FIELD to the testpmd.
Implement CLI to create the copy_field action and supply all the
needed parameters to copy an arbitrary packet field (as well as
mark, tag or metadata) into another field.

Example of the flow is the following:
flow create 0 egress group 1 pattern eth / ipv4 / udp / end
     actions copy_field dst_type tag dst_level 0 dst_offset 8
     src_type gtp_teid src_level 0 src_offset 0 width 32 / end

This flow copies 32 bits from the first Tag in the Tags array
into the outermost GTP TEID packet header field. 8 bits of the
Tag are skipped as indicated by the dst_offset action parameter.

dst_type and src_type are the only mandatory parameters to
specify. Levels and offset are 0 by default if they are not
overridden by a user. The width parameter gets the smallest width
from the source and destination sizes if it is not specified.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
---
 app/test-pmd/cmdline_flow.c | 166 ++++++++++++++++++++++++++++++++++++
 1 file changed, 166 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 585cab98b4..115d4772f9 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -408,6 +408,16 @@ enum index {
 	ACTION_SAMPLE_INDEX_VALUE,
 	ACTION_SHARED,
 	SHARED_ACTION_ID2PTR,
+	ACTION_COPY_FIELD,
+	ACTION_COPY_FIELD_DST_TYPE,
+	ACTION_COPY_FIELD_DST_TYPE_VALUE,
+	ACTION_COPY_FIELD_DST_LEVEL,
+	ACTION_COPY_FIELD_DST_OFFSET,
+	ACTION_COPY_FIELD_SRC_TYPE,
+	ACTION_COPY_FIELD_SRC_TYPE_VALUE,
+	ACTION_COPY_FIELD_SRC_LEVEL,
+	ACTION_COPY_FIELD_SRC_OFFSET,
+	ACTION_COPY_FIELD_WIDTH,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -561,6 +571,18 @@ struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 
+static const char *const copy_field_table[] = {
+	"start", "mac_dst", "mac_src",
+	"vlan_type", "vlan_id", "mac_type",
+	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
+	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
+	"tcp_port_src", "tcp_port_dst",
+	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
+	"udp_port_src", "udp_port_dst",
+	"vxlan_vni", "geneve_vni", "gtp_teid",
+	"tag", "mark", "meta", NULL
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -1306,6 +1328,7 @@ static const enum index next_action[] = {
 	ACTION_AGE,
 	ACTION_SAMPLE,
 	ACTION_SHARED,
+	ACTION_COPY_FIELD,
 	ZERO,
 };
 
@@ -1556,6 +1579,20 @@ static const enum index next_action_sample[] = {
 	ZERO,
 };
 
+static const enum index action_copy_field_dst[] = {
+	ACTION_COPY_FIELD_DST_LEVEL,
+	ACTION_COPY_FIELD_DST_OFFSET,
+	ACTION_COPY_FIELD_SRC_TYPE,
+	ZERO,
+};
+
+static const enum index action_copy_field_src[] = {
+	ACTION_COPY_FIELD_SRC_LEVEL,
+	ACTION_COPY_FIELD_SRC_OFFSET,
+	ACTION_COPY_FIELD_WIDTH,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -1638,6 +1675,10 @@ static int
 parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 				const char *str, unsigned int len, void *buf,
 				unsigned int size);
+static int
+parse_vc_copy_field(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1722,6 +1763,8 @@ static int comp_set_raw_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
 static int comp_set_sample_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
+static int comp_set_copy_field(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -4037,6 +4080,81 @@ static const struct token token_list[] = {
 		.call = parse_vc_action_raw_decap_index,
 		.comp = comp_set_raw_index,
 	},
+	[ACTION_COPY_FIELD] = {
+		.name = "copy_field",
+		.help = "copy data from destination field to source field",
+		.priv = PRIV_ACTION(COPY_FIELD,
+			sizeof(struct rte_flow_action_copy_field)),
+		.next = NEXT(NEXT_ENTRY(ACTION_COPY_FIELD_DST_TYPE)),
+		.call = parse_vc,
+	},
+	[ACTION_COPY_FIELD_DST_TYPE] = {
+		.name = "dst_type",
+		.help = "destination field type",
+		.next = NEXT(action_copy_field_dst,
+			NEXT_ENTRY(ACTION_COPY_FIELD_DST_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_FIELD_DST_TYPE_VALUE] = {
+		.name = "{type}",
+		.help = "destination field type value",
+		.call = parse_vc_copy_field,
+		.comp = comp_set_copy_field,
+	},
+	[ACTION_COPY_FIELD_DST_LEVEL] = {
+		.name = "dst_level",
+		.help = "destination field level",
+		.next = NEXT(action_copy_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
+					dst.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_FIELD_DST_OFFSET] = {
+		.name = "dst_offset",
+		.help = "destination field bit offset",
+		.next = NEXT(action_copy_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
+					dst.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_FIELD_SRC_TYPE] = {
+		.name = "src_type",
+		.help = "source field type",
+		.next = NEXT(action_copy_field_src,
+			NEXT_ENTRY(ACTION_COPY_FIELD_SRC_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_FIELD_SRC_TYPE_VALUE] = {
+		.name = "{type}",
+		.help = "source field type value",
+		.call = parse_vc_copy_field,
+		.comp = comp_set_copy_field,
+	},
+	[ACTION_COPY_FIELD_SRC_LEVEL] = {
+		.name = "src_level",
+		.help = "source field level",
+		.next = NEXT(action_copy_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
+					src.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_FIELD_SRC_OFFSET] = {
+		.name = "src_offset",
+		.help = "source field bit offset",
+		.next = NEXT(action_copy_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
+					src.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_COPY_FIELD_WIDTH] = {
+		.name = "width",
+		.help = "number of bits to copy",
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
+					width)),
+		.call = parse_vc_conf,
+	},
 	/* Top level command. */
 	[SET] = {
 		.name = "set",
@@ -5960,6 +6078,36 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse tokens for copy_field command. */
+static int
+parse_vc_copy_field(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_copy_field *action_copy_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_COPY_FIELD_DST_TYPE_VALUE &&
+		ctx->curr != ACTION_COPY_FIELD_SRC_TYPE_VALUE)
+		return -1;
+	for (i = 0; copy_field_table[i]; ++i)
+		if (!strcmp_partial(copy_field_table[i], str, len))
+			break;
+	if (!copy_field_table[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_copy_field = ctx->object;
+	if (ctx->curr == ACTION_COPY_FIELD_DST_TYPE_VALUE)
+		action_copy_field->dst.field = (enum rte_flow_field_id)i;
+	else
+		action_copy_field->src.field = (enum rte_flow_field_id)i;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -7029,6 +7177,24 @@ comp_set_sample_index(struct context *ctx, const struct token *token,
 	return nb;
 }
 
+/** Complete field type for copy_field command. */
+static int
+comp_set_copy_field(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; copy_field_table[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, copy_field_table[ent], size);
+	return -1;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/2] ethdev: introduce generic copy rte flow action
  2021-01-13 17:07       ` [dpdk-dev] [PATCH v4 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
@ 2021-01-14 12:22         ` Ori Kam
  0 siblings, 0 replies; 48+ messages in thread
From: Ori Kam @ 2021-01-14 12:22 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

Hi Alexander,

> -----Original Message-----
> From: Alexander Kozyrev <akozyrev@nvidia.com>
> Sent: Wednesday, January 13, 2021 7:08 PM
> Subject: [PATCH v4 1/2] ethdev: introduce generic copy rte flow action
> 
> Implement a generic copy flow API to allow copying of an arbitrary
> header field (as well as mark, metadata or tag) to another field.
> 
> This generic copy mechanism removes the necessity to implement a
> separate RTE Flow action every time we need to modify a new packet
> field in the future. A user-provided value can be used from a
> specified tag/metadata/mark or directly copied from another packet field.
> 
> The field ID is used to specify the desired source/destination packet
> field in order to simplify the API for various encapsulation models.
> Specifying the packet field ID with the needed encapsulation level
> is able to quickly get a packet field for any inner packet header.
> 
> Alternatively, the special ID (ITEM_START) can be used to point to the
> very beginning of a packet. This ID in conjunction with the offset
> parameter provides great flexibility to copy/modify any part of a packet
>  as needed.
> 
> The number of bits to copy as well as the offset to start from can
> be specified to allow a partial copy or dividing a big packet field
> into multiple small fields (let's say copying 128 bits of IPv6 to 4 tags).
> 
> RFC:
> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatches.d
> pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com%
> 7C17fcc82431974e7e56f108d8b7e5c877%7C43083d15727340c1b7db39efd9ccc
> 17a%7C0%7C0%7C637461544825998974%7CUnknown%7CTWFpbGZsb3d8eyJW
> IjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C10
> 00&amp;sdata=kTd45BEYhWsYtRuB9r5Y%2BTwa88wnkKgwUhWFFIutcvc%3D&
> amp;reserved=0
> 
> Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> ---
>  doc/guides/prog_guide/rte_flow.rst     | 57 +++++++++++++++++++++++++
>  doc/guides/rel_notes/release_21_02.rst |  5 +++
>  lib/librte_ethdev/rte_flow.c           |  1 +
>  lib/librte_ethdev/rte_flow.h           | 59 ++++++++++++++++++++++++++
>  4 files changed, 122 insertions(+)
> 

Acked-by: Ori Kam <orika@nvidia.com>
Thanks,
Ori


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-08  6:32 [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action Alexander Kozyrev
  2021-01-10  8:00 ` Ori Kam
  2021-01-12  5:01 ` [dpdk-dev] [PATCH v2 0/2] generic copy rte flow action support Alexander Kozyrev
@ 2021-01-14 13:59 ` Jerin Jacob
  2021-01-14 15:02   ` Ori Kam
  2 siblings, 1 reply; 48+ messages in thread
From: Jerin Jacob @ 2021-01-14 13:59 UTC (permalink / raw)
  To: Alexander Kozyrev, Cristian Dumitrescu, aboyer
  Cc: dpdk-dev, Viacheslav Ovsiienko, orika, Thomas Monjalon,
	Ferruh Yigit, Andrew Rybchenko

On Fri, Jan 8, 2021 at 12:02 PM Alexander Kozyrev <akozyrev@nvidia.com> wrote:
>
> Implement a generic copy flow API to allow copying of an arbitrary
> header field (as well as mark, metadata or tag) to another item.
>
> This generic copy mechanism removes the necessity to implement a
> separate RTE Flow action every time we need to modify a new packet
> field in the future. A user-provided value can be used from a
> specified tag/metadata or directly copied from other packet field.
>
> The number of bits to copy as well as the offset to start from can
> be specified to allow a partial copy or copy into an arbitrary
> place in a packet for greater flexibility.
>
> RFC: http://patches.dpdk.org/patch/85384/
>
> Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> ---

>
> +Action: ``COPY_ITEM``
> +^^^^^^^^^^^^^^^^^^^^^
> +
> +Copy ``width`` bits from ``src`` item to ``dst`` item.
> +
> +An arbitrary header field (as well as mark, metadata or tag values)
> +can be used as both source and destination items as set by ``item``.
> +
> +Inner packet header fields can be accessed using the ``index`` and
> +it is possible to start the copy from the ``offset`` bits in an item.
> +
> +.. _table_rte_flow_action_copy_item:
> +
> +.. table:: COPY_ITEM
> +
> +   +-----------------------------------------+
> +   | Field         | Value                   |
> +   +===============+=========================+
> +   | ``dst``       | destination item        |
> +   | ``src``       | source item             |
> +   | ``width``     | number of bits to copy  |



Overall it is a good improvement.

I think, if we add transform "op" here then it can be more generic. In
other words, A generic packet transform and copy operation is just one
of the operations.
ie.. making it as rte_flow_action_xform_item and introduce COPY, ADD,
SUB, etc transform along with existing rte_flow_action_copy_item
fields.

It may useful for expressing P4 packet transforms to rte_flow.

The current generation of Marvell HW does not have COPY transform so I
am leaving suggestions to vendors with this HW capablity.


> +   +---------------+-------------------------+




> +
> +.. _table_rte_flow_action_copy_data:
> +
> +.. table:: destination/source item definition
> +
> +   +----------------------------------------------------------+
> +   | Field         | Value                                    |
> +   +===============+==========================================+
> +   | ``item``      | ID of a packet field/mark/metadata/tag   |
> +   | ``index``     | index of outer/inner header or tag array |
> +   | ``offset``    | number of bits to skip during the copy   |
> +   +---------------+------------------------------------------+
> +

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-14 13:59 ` [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action Jerin Jacob
@ 2021-01-14 15:02   ` Ori Kam
  2021-01-15 14:00     ` Jerin Jacob
  0 siblings, 1 reply; 48+ messages in thread
From: Ori Kam @ 2021-01-14 15:02 UTC (permalink / raw)
  To: Jerin Jacob, Alexander Kozyrev, Cristian Dumitrescu, aboyer
  Cc: dpdk-dev, Slava Ovsiienko, NBU-Contact-Thomas Monjalon,
	Ferruh Yigit, Andrew Rybchenko

Hi Jerin,

> -----Original Message-----
> From: Jerin Jacob <jerinjacobk@gmail.com>
> Sent: Thursday, January 14, 2021 4:00 PM
> Subject: Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
> 
> On Fri, Jan 8, 2021 at 12:02 PM Alexander Kozyrev <akozyrev@nvidia.com>
> wrote:
> >
> > Implement a generic copy flow API to allow copying of an arbitrary
> > header field (as well as mark, metadata or tag) to another item.
> >
> > This generic copy mechanism removes the necessity to implement a
> > separate RTE Flow action every time we need to modify a new packet
> > field in the future. A user-provided value can be used from a
> > specified tag/metadata or directly copied from other packet field.
> >
> > The number of bits to copy as well as the offset to start from can
> > be specified to allow a partial copy or copy into an arbitrary
> > place in a packet for greater flexibility.
> >
> > RFC:
> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatches.d
> pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com%
> 7C62ab41b9ed5948d056c308d8b894af02%7C43083d15727340c1b7db39efd9cc
> c17a%7C0%7C0%7C637462296023413253%7CUnknown%7CTWFpbGZsb3d8eyJ
> WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C
> 1000&amp;sdata=ovpEss3%2B7TgZRYFiDkrvuMFW52747Gno5oOIeDLwrBQ%3D
> &amp;reserved=0
> >
> > Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> > ---
> 
> >
> > +Action: ``COPY_ITEM``
> > +^^^^^^^^^^^^^^^^^^^^^
> > +
> > +Copy ``width`` bits from ``src`` item to ``dst`` item.
> > +
> > +An arbitrary header field (as well as mark, metadata or tag values)
> > +can be used as both source and destination items as set by ``item``.
> > +
> > +Inner packet header fields can be accessed using the ``index`` and
> > +it is possible to start the copy from the ``offset`` bits in an item.
> > +
> > +.. _table_rte_flow_action_copy_item:
> > +
> > +.. table:: COPY_ITEM
> > +
> > +   +-----------------------------------------+
> > +   | Field         | Value                   |
> > +   +===============+=========================+
> > +   | ``dst``       | destination item        |
> > +   | ``src``       | source item             |
> > +   | ``width``     | number of bits to copy  |
> 
> 
> 
> Overall it is a good improvement.
> 
> I think, if we add transform "op" here then it can be more generic. In
> other words, A generic packet transform and copy operation is just one
> of the operations.
> ie.. making it as rte_flow_action_xform_item and introduce COPY, ADD,
> SUB, etc transform along with existing rte_flow_action_copy_item
> fields.
> 
> It may useful for expressing P4 packet transforms to rte_flow.
> 
> The current generation of Marvell HW does not have COPY transform so I
> am leaving suggestions to vendors with this HW capablity.
> 
> 

+1 
Lest have dst, src, width, op members,
and change the action name to rte_flow_action_modify_field()

also lest add new field name immediate  so the copy can be used as set.
(copy of an immediate value is a set)

Possible op = copy / add / sub

> > +   +---------------+-------------------------+
> 
> 
> 
> 
> > +
> > +.. _table_rte_flow_action_copy_data:
> > +
> > +.. table:: destination/source item definition
> > +
> > +   +----------------------------------------------------------+
> > +   | Field         | Value                                    |
> > +   +===============+==========================================+
> > +   | ``item``      | ID of a packet field/mark/metadata/tag   |
> > +   | ``index``     | index of outer/inner header or tag array |
> > +   | ``offset``    | number of bits to skip during the copy   |
> > +   +---------------+------------------------------------------+
> > +

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v4 2/2] app/testpmd: add support for generic copy rte flow action
  2021-01-13 17:07       ` [dpdk-dev] [PATCH v4 2/2] app/testpmd: add support for " Alexander Kozyrev
@ 2021-01-14 15:18         ` Ori Kam
  2021-01-15 15:37           ` Alexander Kozyrev
  0 siblings, 1 reply; 48+ messages in thread
From: Ori Kam @ 2021-01-14 15:18 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

Hi

> -----Original Message-----
> From: Alexander Kozyrev <akozyrev@nvidia.com>
> Sent: Wednesday, January 13, 2021 7:08 PM
> Subject: [PATCH v4 2/2] app/testpmd: add support for generic copy rte flow
> action
> 
> Add support for the RTE_FLOW_ACTION_COPY_FIELD to the testpmd.
> Implement CLI to create the copy_field action and supply all the
> needed parameters to copy an arbitrary packet field (as well as
> mark, tag or metadata) into another field.
> 
> Example of the flow is the following:
> flow create 0 egress group 1 pattern eth / ipv4 / udp / end
>      actions copy_field dst_type tag dst_level 0 dst_offset 8
>      src_type gtp_teid src_level 0 src_offset 0 width 32 / end
> 
> This flow copies 32 bits from the first Tag in the Tags array
> into the outermost GTP TEID packet header field. 8 bits of the
> Tag are skipped as indicated by the dst_offset action parameter.
> 
> dst_type and src_type are the only mandatory parameters to
> specify. Levels and offset are 0 by default if they are not
> overridden by a user. The width parameter gets the smallest width
> from the source and destination sizes if it is not specified.
> 
> Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> ---
>  app/test-pmd/cmdline_flow.c | 166
> ++++++++++++++++++++++++++++++++++++
>  1 file changed, 166 insertions(+)
> 
> diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
> index 585cab98b4..115d4772f9 100644
> --- a/app/test-pmd/cmdline_flow.c
> +++ b/app/test-pmd/cmdline_flow.c
> @@ -408,6 +408,16 @@ enum index {
>  	ACTION_SAMPLE_INDEX_VALUE,
>  	ACTION_SHARED,
>  	SHARED_ACTION_ID2PTR,
> +	ACTION_COPY_FIELD,
> +	ACTION_COPY_FIELD_DST_TYPE,
> +	ACTION_COPY_FIELD_DST_TYPE_VALUE,
> +	ACTION_COPY_FIELD_DST_LEVEL,
> +	ACTION_COPY_FIELD_DST_OFFSET,
> +	ACTION_COPY_FIELD_SRC_TYPE,
> +	ACTION_COPY_FIELD_SRC_TYPE_VALUE,
> +	ACTION_COPY_FIELD_SRC_LEVEL,
> +	ACTION_COPY_FIELD_SRC_OFFSET,
> +	ACTION_COPY_FIELD_WIDTH,
>  };
> 
>  /** Maximum size for pattern in struct rte_flow_item_raw. */
> @@ -561,6 +571,18 @@ struct rte_flow_action_count
> sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
>  struct rte_flow_action_port_id
> sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
>  struct rte_flow_action_raw_encap
> sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
> 
> +static const char *const copy_field_table[] = {
> +	"start", "mac_dst", "mac_src",
> +	"vlan_type", "vlan_id", "mac_type",
> +	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
> +	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
> +	"tcp_port_src", "tcp_port_dst",
> +	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
> +	"udp_port_src", "udp_port_dst",
> +	"vxlan_vni", "geneve_vni", "gtp_teid",
> +	"tag", "mark", "meta", NULL
> +};
> +
>  /** Maximum number of subsequent tokens and arguments on the stack. */
>  #define CTX_STACK_SIZE 16
> 
> @@ -1306,6 +1328,7 @@ static const enum index next_action[] = {
>  	ACTION_AGE,
>  	ACTION_SAMPLE,
>  	ACTION_SHARED,
> +	ACTION_COPY_FIELD,
>  	ZERO,
>  };
> 
> @@ -1556,6 +1579,20 @@ static const enum index next_action_sample[] = {
>  	ZERO,
>  };
> 
> +static const enum index action_copy_field_dst[] = {
> +	ACTION_COPY_FIELD_DST_LEVEL,
> +	ACTION_COPY_FIELD_DST_OFFSET,
> +	ACTION_COPY_FIELD_SRC_TYPE,
> +	ZERO,
> +};
> +
> +static const enum index action_copy_field_src[] = {
> +	ACTION_COPY_FIELD_SRC_LEVEL,
> +	ACTION_COPY_FIELD_SRC_OFFSET,
> +	ACTION_COPY_FIELD_WIDTH,
> +	ZERO,
> +};
> +
I think if we remove the order of actions then it is possible to use the same struct
both for the src and the dst. What do you think? (see my comment below)

>  static int parse_set_raw_encap_decap(struct context *, const struct token *,
>  				     const char *, unsigned int,
>  				     void *, unsigned int);
> @@ -1638,6 +1675,10 @@ static int
>  parse_vc_action_sample_index(struct context *ctx, const struct token *token,
>  				const char *str, unsigned int len, void *buf,
>  				unsigned int size);
> +static int
> +parse_vc_copy_field(struct context *ctx, const struct token *token,
> +				const char *str, unsigned int len, void *buf,
> +				unsigned int size);
>  static int parse_destroy(struct context *, const struct token *,
>  			 const char *, unsigned int,
>  			 void *, unsigned int);
> @@ -1722,6 +1763,8 @@ static int comp_set_raw_index(struct context *,
> const struct token *,
>  			      unsigned int, char *, unsigned int);
>  static int comp_set_sample_index(struct context *, const struct token *,
>  			      unsigned int, char *, unsigned int);
> +static int comp_set_copy_field(struct context *, const struct token *,
> +			      unsigned int, char *, unsigned int);
> 
>  /** Token definitions. */
>  static const struct token token_list[] = {
> @@ -4037,6 +4080,81 @@ static const struct token token_list[] = {
>  		.call = parse_vc_action_raw_decap_index,
>  		.comp = comp_set_raw_index,
>  	},
> +	[ACTION_COPY_FIELD] = {
> +		.name = "copy_field",
> +		.help = "copy data from destination field to source field",
> +		.priv = PRIV_ACTION(COPY_FIELD,
> +			sizeof(struct rte_flow_action_copy_field)),
> +		.next = NEXT(NEXT_ENTRY(ACTION_COPY_FIELD_DST_TYPE)),
> +		.call = parse_vc,

You are forcing that the first parameter will be the source, what do you think about
removing this limitation?

> +	},
> +	[ACTION_COPY_FIELD_DST_TYPE] = {
> +		.name = "dst_type",
> +		.help = "destination field type",
> +		.next = NEXT(action_copy_field_dst,
> +
> 	NEXT_ENTRY(ACTION_COPY_FIELD_DST_TYPE_VALUE)),
> +		.call = parse_vc_conf,
> +	},
> +	[ACTION_COPY_FIELD_DST_TYPE_VALUE] = {
> +		.name = "{type}",
> +		.help = "destination field type value",
> +		.call = parse_vc_copy_field,
> +		.comp = comp_set_copy_field,
> +	},
> +	[ACTION_COPY_FIELD_DST_LEVEL] = {
> +		.name = "dst_level",
> +		.help = "destination field level",
> +		.next = NEXT(action_copy_field_dst, NEXT_ENTRY(UNSIGNED)),
> +		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
> +					dst.level)),
> +		.call = parse_vc_conf,
> +	},
> +	[ACTION_COPY_FIELD_DST_OFFSET] = {
> +		.name = "dst_offset",
> +		.help = "destination field bit offset",
> +		.next = NEXT(action_copy_field_dst, NEXT_ENTRY(UNSIGNED)),
> +		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
> +					dst.offset)),
> +		.call = parse_vc_conf,
> +	},
> +	[ACTION_COPY_FIELD_SRC_TYPE] = {
> +		.name = "src_type",
> +		.help = "source field type",
> +		.next = NEXT(action_copy_field_src,
> +
> 	NEXT_ENTRY(ACTION_COPY_FIELD_SRC_TYPE_VALUE)),
> +		.call = parse_vc_conf,
> +	},
> +	[ACTION_COPY_FIELD_SRC_TYPE_VALUE] = {
> +		.name = "{type}",
> +		.help = "source field type value",
> +		.call = parse_vc_copy_field,
> +		.comp = comp_set_copy_field,
> +	},
> +	[ACTION_COPY_FIELD_SRC_LEVEL] = {
> +		.name = "src_level",
> +		.help = "source field level",
> +		.next = NEXT(action_copy_field_src, NEXT_ENTRY(UNSIGNED)),
> +		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
> +					src.level)),
> +		.call = parse_vc_conf,
> +	},
> +	[ACTION_COPY_FIELD_SRC_OFFSET] = {
> +		.name = "src_offset",
> +		.help = "source field bit offset",
> +		.next = NEXT(action_copy_field_src, NEXT_ENTRY(UNSIGNED)),
> +		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
> +					src.offset)),
> +		.call = parse_vc_conf,
> +	},
> +	[ACTION_COPY_FIELD_WIDTH] = {
> +		.name = "width",
> +		.help = "number of bits to copy",
> +		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
> +			NEXT_ENTRY(UNSIGNED)),
> +		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field,
> +					width)),
> +		.call = parse_vc_conf,
> +	},
>  	/* Top level command. */
>  	[SET] = {
>  		.name = "set",
> @@ -5960,6 +6078,36 @@ parse_vc_action_sample_index(struct context *ctx,
> const struct token *token,
>  	return len;
>  }
> 
> +/** Parse tokens for copy_field command. */
> +static int
> +parse_vc_copy_field(struct context *ctx, const struct token *token,
> +			 const char *str, unsigned int len, void *buf,
> +			 unsigned int size)
> +{
> +	struct rte_flow_action_copy_field *action_copy_field;
> +	unsigned int i;
> +
> +	(void)token;
> +	(void)buf;
> +	(void)size;
> +	if (ctx->curr != ACTION_COPY_FIELD_DST_TYPE_VALUE &&
> +		ctx->curr != ACTION_COPY_FIELD_SRC_TYPE_VALUE)
> +		return -1;
> +	for (i = 0; copy_field_table[i]; ++i)
> +		if (!strcmp_partial(copy_field_table[i], str, len))
> +			break;
> +	if (!copy_field_table[i])
> +		return -1;
> +	if (!ctx->object)
> +		return len;
> +	action_copy_field = ctx->object;
> +	if (ctx->curr == ACTION_COPY_FIELD_DST_TYPE_VALUE)
> +		action_copy_field->dst.field = (enum rte_flow_field_id)i;
> +	else
> +		action_copy_field->src.field = (enum rte_flow_field_id)i;
> +	return len;
> +}
> +
>  /** Parse tokens for destroy command. */
>  static int
>  parse_destroy(struct context *ctx, const struct token *token,
> @@ -7029,6 +7177,24 @@ comp_set_sample_index(struct context *ctx, const
> struct token *token,
>  	return nb;
>  }
> 
> +/** Complete field type for copy_field command. */
> +static int
> +comp_set_copy_field(struct context *ctx, const struct token *token,
> +		   unsigned int ent, char *buf, unsigned int size)
> +{
> +	uint16_t idx = 0;
> +
> +	RTE_SET_USED(ctx);
> +	RTE_SET_USED(token);
> +	for (idx = 0; copy_field_table[idx]; ++idx)
> +		;
> +	if (!buf)
> +		return idx + 1;
> +	if (ent < idx)
> +		return strlcpy(buf, copy_field_table[ent], size);
> +	return -1;
> +}
> +
>  /** Internal context. */
>  static struct context cmd_flow_context;
> 
> --
> 2.24.1


Acked-by: Ori Kam <orika@nvidia.com>
Best,
Ori

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-14 15:02   ` Ori Kam
@ 2021-01-15 14:00     ` Jerin Jacob
  2021-01-15 15:33       ` Alexander Kozyrev
  0 siblings, 1 reply; 48+ messages in thread
From: Jerin Jacob @ 2021-01-15 14:00 UTC (permalink / raw)
  To: Ori Kam
  Cc: Alexander Kozyrev, Cristian Dumitrescu, aboyer, dpdk-dev,
	Slava Ovsiienko, NBU-Contact-Thomas Monjalon, Ferruh Yigit,
	Andrew Rybchenko

On Thu, Jan 14, 2021 at 8:32 PM Ori Kam <orika@nvidia.com> wrote:
>
> Hi Jerin,
>
> > -----Original Message-----
> > From: Jerin Jacob <jerinjacobk@gmail.com>
> > Sent: Thursday, January 14, 2021 4:00 PM
> > Subject: Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
> >
> > On Fri, Jan 8, 2021 at 12:02 PM Alexander Kozyrev <akozyrev@nvidia.com>
> > wrote:
> > >
> > > Implement a generic copy flow API to allow copying of an arbitrary
> > > header field (as well as mark, metadata or tag) to another item.
> > >
> > > This generic copy mechanism removes the necessity to implement a
> > > separate RTE Flow action every time we need to modify a new packet
> > > field in the future. A user-provided value can be used from a
> > > specified tag/metadata or directly copied from other packet field.
> > >
> > > The number of bits to copy as well as the offset to start from can
> > > be specified to allow a partial copy or copy into an arbitrary
> > > place in a packet for greater flexibility.
> > >
> > > RFC:
> > https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatches.d
> > pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com%
> > 7C62ab41b9ed5948d056c308d8b894af02%7C43083d15727340c1b7db39efd9cc
> > c17a%7C0%7C0%7C637462296023413253%7CUnknown%7CTWFpbGZsb3d8eyJ
> > WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C
> > 1000&amp;sdata=ovpEss3%2B7TgZRYFiDkrvuMFW52747Gno5oOIeDLwrBQ%3D
> > &amp;reserved=0
> > >
> > > Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> > > ---
> >
> > >
> > > +Action: ``COPY_ITEM``
> > > +^^^^^^^^^^^^^^^^^^^^^
> > > +
> > > +Copy ``width`` bits from ``src`` item to ``dst`` item.
> > > +
> > > +An arbitrary header field (as well as mark, metadata or tag values)
> > > +can be used as both source and destination items as set by ``item``.
> > > +
> > > +Inner packet header fields can be accessed using the ``index`` and
> > > +it is possible to start the copy from the ``offset`` bits in an item.
> > > +
> > > +.. _table_rte_flow_action_copy_item:
> > > +
> > > +.. table:: COPY_ITEM
> > > +
> > > +   +-----------------------------------------+
> > > +   | Field         | Value                   |
> > > +   +===============+=========================+
> > > +   | ``dst``       | destination item        |
> > > +   | ``src``       | source item             |
> > > +   | ``width``     | number of bits to copy  |
> >
> >
> >
> > Overall it is a good improvement.
> >
> > I think, if we add transform "op" here then it can be more generic. In
> > other words, A generic packet transform and copy operation is just one
> > of the operations.
> > ie.. making it as rte_flow_action_xform_item and introduce COPY, ADD,
> > SUB, etc transform along with existing rte_flow_action_copy_item
> > fields.
> >
> > It may useful for expressing P4 packet transforms to rte_flow.
> >
> > The current generation of Marvell HW does not have COPY transform so I
> > am leaving suggestions to vendors with this HW capablity.
> >
> >
>
> +1
> Lest have dst, src, width, op members,
> and change the action name to rte_flow_action_modify_field()
>
> also lest add new field name immediate  so the copy can be used as set.
> (copy of an immediate value is a set)
>
> Possible op = copy / add / sub

+1

>
> > > +   +---------------+-------------------------+
> >
> >
> >
> >
> > > +
> > > +.. _table_rte_flow_action_copy_data:
> > > +
> > > +.. table:: destination/source item definition
> > > +
> > > +   +----------------------------------------------------------+
> > > +   | Field         | Value                                    |
> > > +   +===============+==========================================+
> > > +   | ``item``      | ID of a packet field/mark/metadata/tag   |
> > > +   | ``index``     | index of outer/inner header or tag array |
> > > +   | ``offset``    | number of bits to skip during the copy   |
> > > +   +---------------+------------------------------------------+
> > > +

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action
  2021-01-15 14:00     ` Jerin Jacob
@ 2021-01-15 15:33       ` Alexander Kozyrev
  0 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-15 15:33 UTC (permalink / raw)
  To: Jerin Jacob, Ori Kam
  Cc: Cristian Dumitrescu, aboyer, dpdk-dev, Slava Ovsiienko,
	NBU-Contact-Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko

> From: Jerin Jacob <jerinjacobk@gmail.com> on  Friday, January 15, 2021 9:01
> Subject: Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow
> action
> 
> On Thu, Jan 14, 2021 at 8:32 PM Ori Kam <orika@nvidia.com> wrote:
> >
> > Hi Jerin,
> >
> > > -----Original Message-----
> > > From: Jerin Jacob <jerinjacobk@gmail.com>
> > > Sent: Thursday, January 14, 2021 4:00 PM
> > > Subject: Re: [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow
> action
> > >
> > > On Fri, Jan 8, 2021 at 12:02 PM Alexander Kozyrev
> <akozyrev@nvidia.com>
> > > wrote:
> > > >
> > > > Implement a generic copy flow API to allow copying of an arbitrary
> > > > header field (as well as mark, metadata or tag) to another item.
> > > >
> > > > This generic copy mechanism removes the necessity to implement a
> > > > separate RTE Flow action every time we need to modify a new packet
> > > > field in the future. A user-provided value can be used from a
> > > > specified tag/metadata or directly copied from other packet field.
> > > >
> > > > The number of bits to copy as well as the offset to start from can
> > > > be specified to allow a partial copy or copy into an arbitrary
> > > > place in a packet for greater flexibility.
> > > >
> > > > RFC:
> > >
> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatch
> es.d
> > >
> pdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Corika%40nvidia.com
> %
> > >
> 7C62ab41b9ed5948d056c308d8b894af02%7C43083d15727340c1b7db39efd9cc
> > >
> c17a%7C0%7C0%7C637462296023413253%7CUnknown%7CTWFpbGZsb3d8ey
> J
> > >
> WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%
> 7C
> > >
> 1000&amp;sdata=ovpEss3%2B7TgZRYFiDkrvuMFW52747Gno5oOIeDLwrBQ%
> 3D
> > > &amp;reserved=0
> > > >
> > > > Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> > > > ---
> > >
> > > >
> > > > +Action: ``COPY_ITEM``
> > > > +^^^^^^^^^^^^^^^^^^^^^
> > > > +
> > > > +Copy ``width`` bits from ``src`` item to ``dst`` item.
> > > > +
> > > > +An arbitrary header field (as well as mark, metadata or tag values)
> > > > +can be used as both source and destination items as set by ``item``.
> > > > +
> > > > +Inner packet header fields can be accessed using the ``index`` and
> > > > +it is possible to start the copy from the ``offset`` bits in an item.
> > > > +
> > > > +.. _table_rte_flow_action_copy_item:
> > > > +
> > > > +.. table:: COPY_ITEM
> > > > +
> > > > +   +-----------------------------------------+
> > > > +   | Field         | Value                   |
> > > > +   +===============+=========================+
> > > > +   | ``dst``       | destination item        |
> > > > +   | ``src``       | source item             |
> > > > +   | ``width``     | number of bits to copy  |
> > >
> > >
> > >
> > > Overall it is a good improvement.
> > >
> > > I think, if we add transform "op" here then it can be more generic. In
> > > other words, A generic packet transform and copy operation is just one
> > > of the operations.
> > > ie.. making it as rte_flow_action_xform_item and introduce COPY, ADD,
> > > SUB, etc transform along with existing rte_flow_action_copy_item
> > > fields.
> > >
> > > It may useful for expressing P4 packet transforms to rte_flow.
> > >
> > > The current generation of Marvell HW does not have COPY transform so I
> > > am leaving suggestions to vendors with this HW capablity.
> > >
> > >
> >
> > +1
> > Lest have dst, src, width, op members,
> > and change the action name to rte_flow_action_modify_field()
> >
> > also lest add new field name immediate  so the copy can be used as set.
> > (copy of an immediate value is a set)
> >
> > Possible op = copy / add / sub
> 
> +1
Thank you, Jerin, for a great idea. I'm issuing a v4 patch with generic modify_field design. 

> 
> >
> > > > +   +---------------+-------------------------+
> > >
> > >
> > >
> > >
> > > > +
> > > > +.. _table_rte_flow_action_copy_data:
> > > > +
> > > > +.. table:: destination/source item definition
> > > > +
> > > > +   +----------------------------------------------------------+
> > > > +   | Field         | Value                                    |
> > > > +
> +===============+=========================================
> =+
> > > > +   | ``item``      | ID of a packet field/mark/metadata/tag   |
> > > > +   | ``index``     | index of outer/inner header or tag array |
> > > > +   | ``offset``    | number of bits to skip during the copy   |
> > > > +   +---------------+------------------------------------------+
> > > > +

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v4 2/2] app/testpmd: add support for generic copy rte flow action
  2021-01-14 15:18         ` Ori Kam
@ 2021-01-15 15:37           ` Alexander Kozyrev
  0 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-15 15:37 UTC (permalink / raw)
  To: Ori Kam, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko

> From: Ori Kam <orika@nvidia.com> on Thursday, January 14, 2021 10:19
> Subject: RE: [PATCH v4 2/2] app/testpmd: add support for generic copy rte
> flow action
> 
> Hi
> 
> > -----Original Message-----
> > From: Alexander Kozyrev <akozyrev@nvidia.com>
> > Sent: Wednesday, January 13, 2021 7:08 PM
> > Subject: [PATCH v4 2/2] app/testpmd: add support for generic copy rte
> flow
> > action
> >
> > Add support for the RTE_FLOW_ACTION_COPY_FIELD to the testpmd.
> > Implement CLI to create the copy_field action and supply all the
> > needed parameters to copy an arbitrary packet field (as well as
> > mark, tag or metadata) into another field.
> >
> > Example of the flow is the following:
> > flow create 0 egress group 1 pattern eth / ipv4 / udp / end
> >      actions copy_field dst_type tag dst_level 0 dst_offset 8
> >      src_type gtp_teid src_level 0 src_offset 0 width 32 / end
> >
> > This flow copies 32 bits from the first Tag in the Tags array
> > into the outermost GTP TEID packet header field. 8 bits of the
> > Tag are skipped as indicated by the dst_offset action parameter.
> >
> > dst_type and src_type are the only mandatory parameters to
> > specify. Levels and offset are 0 by default if they are not
> > overridden by a user. The width parameter gets the smallest width
> > from the source and destination sizes if it is not specified.
> >
> > Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> > ---
> >  app/test-pmd/cmdline_flow.c | 166
> > ++++++++++++++++++++++++++++++++++++
> >  1 file changed, 166 insertions(+)
> >
> > diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
> > index 585cab98b4..115d4772f9 100644
> > --- a/app/test-pmd/cmdline_flow.c
> > +++ b/app/test-pmd/cmdline_flow.c
> > @@ -408,6 +408,16 @@ enum index {
> >  	ACTION_SAMPLE_INDEX_VALUE,
> >  	ACTION_SHARED,
> >  	SHARED_ACTION_ID2PTR,
> > +	ACTION_COPY_FIELD,
> > +	ACTION_COPY_FIELD_DST_TYPE,
> > +	ACTION_COPY_FIELD_DST_TYPE_VALUE,
> > +	ACTION_COPY_FIELD_DST_LEVEL,
> > +	ACTION_COPY_FIELD_DST_OFFSET,
> > +	ACTION_COPY_FIELD_SRC_TYPE,
> > +	ACTION_COPY_FIELD_SRC_TYPE_VALUE,
> > +	ACTION_COPY_FIELD_SRC_LEVEL,
> > +	ACTION_COPY_FIELD_SRC_OFFSET,
> > +	ACTION_COPY_FIELD_WIDTH,
> >  };
> >
> >  /** Maximum size for pattern in struct rte_flow_item_raw. */
> > @@ -561,6 +571,18 @@ struct rte_flow_action_count
> > sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
> >  struct rte_flow_action_port_id
> > sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
> >  struct rte_flow_action_raw_encap
> > sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
> >
> > +static const char *const copy_field_table[] = {
> > +	"start", "mac_dst", "mac_src",
> > +	"vlan_type", "vlan_id", "mac_type",
> > +	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
> > +	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
> > +	"tcp_port_src", "tcp_port_dst",
> > +	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
> > +	"udp_port_src", "udp_port_dst",
> > +	"vxlan_vni", "geneve_vni", "gtp_teid",
> > +	"tag", "mark", "meta", NULL
> > +};
> > +
> >  /** Maximum number of subsequent tokens and arguments on the stack.
> */
> >  #define CTX_STACK_SIZE 16
> >
> > @@ -1306,6 +1328,7 @@ static const enum index next_action[] = {
> >  	ACTION_AGE,
> >  	ACTION_SAMPLE,
> >  	ACTION_SHARED,
> > +	ACTION_COPY_FIELD,
> >  	ZERO,
> >  };
> >
> > @@ -1556,6 +1579,20 @@ static const enum index next_action_sample[] =
> {
> >  	ZERO,
> >  };
> >
> > +static const enum index action_copy_field_dst[] = {
> > +	ACTION_COPY_FIELD_DST_LEVEL,
> > +	ACTION_COPY_FIELD_DST_OFFSET,
> > +	ACTION_COPY_FIELD_SRC_TYPE,
> > +	ZERO,
> > +};
> > +
> > +static const enum index action_copy_field_src[] = {
> > +	ACTION_COPY_FIELD_SRC_LEVEL,
> > +	ACTION_COPY_FIELD_SRC_OFFSET,
> > +	ACTION_COPY_FIELD_WIDTH,
> > +	ZERO,
> > +};
> > +
> I think if we remove the order of actions then it is possible to use the same
> struct
> both for the src and the dst. What do you think? (see my comment below)
This is done intentionally so user can get away without specifying all the mandatory
parameters. That saves us a trouble to validate if they are present or not later.

> >  static int parse_set_raw_encap_decap(struct context *, const struct token
> *,
> >  				     const char *, unsigned int,
> >  				     void *, unsigned int);
> > @@ -1638,6 +1675,10 @@ static int
> >  parse_vc_action_sample_index(struct context *ctx, const struct token
> *token,
> >  				const char *str, unsigned int len, void *buf,
> >  				unsigned int size);
> > +static int
> > +parse_vc_copy_field(struct context *ctx, const struct token *token,
> > +				const char *str, unsigned int len, void *buf,
> > +				unsigned int size);
> >  static int parse_destroy(struct context *, const struct token *,
> >  			 const char *, unsigned int,
> >  			 void *, unsigned int);
> > @@ -1722,6 +1763,8 @@ static int comp_set_raw_index(struct context *,
> > const struct token *,
> >  			      unsigned int, char *, unsigned int);
> >  static int comp_set_sample_index(struct context *, const struct token *,
> >  			      unsigned int, char *, unsigned int);
> > +static int comp_set_copy_field(struct context *, const struct token *,
> > +			      unsigned int, char *, unsigned int);
> >
> >  /** Token definitions. */
> >  static const struct token token_list[] = {
> > @@ -4037,6 +4080,81 @@ static const struct token token_list[] = {
> >  		.call = parse_vc_action_raw_decap_index,
> >  		.comp = comp_set_raw_index,
> >  	},
> > +	[ACTION_COPY_FIELD] = {
> > +		.name = "copy_field",
> > +		.help = "copy data from destination field to source field",
> > +		.priv = PRIV_ACTION(COPY_FIELD,
> > +			sizeof(struct rte_flow_action_copy_field)),
> > +		.next =
> NEXT(NEXT_ENTRY(ACTION_COPY_FIELD_DST_TYPE)),
> > +		.call = parse_vc,
> 
> You are forcing that the first parameter will be the source, what do you think
> about
> removing this limitation?
I'm forcing the first parameter to be the destination, then the source, then the width.
This way I can be sure that all of them are specified when the flow is created.

> 
> > +	},
> > +	[ACTION_COPY_FIELD_DST_TYPE] = {
> > +		.name = "dst_type",
> > +		.help = "destination field type",
> > +		.next = NEXT(action_copy_field_dst,
> > +
> > 	NEXT_ENTRY(ACTION_COPY_FIELD_DST_TYPE_VALUE)),
> > +		.call = parse_vc_conf,
> > +	},
> > +	[ACTION_COPY_FIELD_DST_TYPE_VALUE] = {
> > +		.name = "{type}",
> > +		.help = "destination field type value",
> > +		.call = parse_vc_copy_field,
> > +		.comp = comp_set_copy_field,
> > +	},
> > +	[ACTION_COPY_FIELD_DST_LEVEL] = {
> > +		.name = "dst_level",
> > +		.help = "destination field level",
> > +		.next = NEXT(action_copy_field_dst,
> NEXT_ENTRY(UNSIGNED)),
> > +		.args = ARGS(ARGS_ENTRY(struct
> rte_flow_action_copy_field,
> > +					dst.level)),
> > +		.call = parse_vc_conf,
> > +	},
> > +	[ACTION_COPY_FIELD_DST_OFFSET] = {
> > +		.name = "dst_offset",
> > +		.help = "destination field bit offset",
> > +		.next = NEXT(action_copy_field_dst,
> NEXT_ENTRY(UNSIGNED)),
> > +		.args = ARGS(ARGS_ENTRY(struct
> rte_flow_action_copy_field,
> > +					dst.offset)),
> > +		.call = parse_vc_conf,
> > +	},
> > +	[ACTION_COPY_FIELD_SRC_TYPE] = {
> > +		.name = "src_type",
> > +		.help = "source field type",
> > +		.next = NEXT(action_copy_field_src,
> > +
> > 	NEXT_ENTRY(ACTION_COPY_FIELD_SRC_TYPE_VALUE)),
> > +		.call = parse_vc_conf,
> > +	},
> > +	[ACTION_COPY_FIELD_SRC_TYPE_VALUE] = {
> > +		.name = "{type}",
> > +		.help = "source field type value",
> > +		.call = parse_vc_copy_field,
> > +		.comp = comp_set_copy_field,
> > +	},
> > +	[ACTION_COPY_FIELD_SRC_LEVEL] = {
> > +		.name = "src_level",
> > +		.help = "source field level",
> > +		.next = NEXT(action_copy_field_src,
> NEXT_ENTRY(UNSIGNED)),
> > +		.args = ARGS(ARGS_ENTRY(struct
> rte_flow_action_copy_field,
> > +					src.level)),
> > +		.call = parse_vc_conf,
> > +	},
> > +	[ACTION_COPY_FIELD_SRC_OFFSET] = {
> > +		.name = "src_offset",
> > +		.help = "source field bit offset",
> > +		.next = NEXT(action_copy_field_src,
> NEXT_ENTRY(UNSIGNED)),
> > +		.args = ARGS(ARGS_ENTRY(struct
> rte_flow_action_copy_field,
> > +					src.offset)),
> > +		.call = parse_vc_conf,
> > +	},
> > +	[ACTION_COPY_FIELD_WIDTH] = {
> > +		.name = "width",
> > +		.help = "number of bits to copy",
> > +		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
> > +			NEXT_ENTRY(UNSIGNED)),
> > +		.args = ARGS(ARGS_ENTRY(struct
> rte_flow_action_copy_field,
> > +					width)),
> > +		.call = parse_vc_conf,
> > +	},
> >  	/* Top level command. */
> >  	[SET] = {
> >  		.name = "set",
> > @@ -5960,6 +6078,36 @@ parse_vc_action_sample_index(struct context
> *ctx,
> > const struct token *token,
> >  	return len;
> >  }
> >
> > +/** Parse tokens for copy_field command. */
> > +static int
> > +parse_vc_copy_field(struct context *ctx, const struct token *token,
> > +			 const char *str, unsigned int len, void *buf,
> > +			 unsigned int size)
> > +{
> > +	struct rte_flow_action_copy_field *action_copy_field;
> > +	unsigned int i;
> > +
> > +	(void)token;
> > +	(void)buf;
> > +	(void)size;
> > +	if (ctx->curr != ACTION_COPY_FIELD_DST_TYPE_VALUE &&
> > +		ctx->curr != ACTION_COPY_FIELD_SRC_TYPE_VALUE)
> > +		return -1;
> > +	for (i = 0; copy_field_table[i]; ++i)
> > +		if (!strcmp_partial(copy_field_table[i], str, len))
> > +			break;
> > +	if (!copy_field_table[i])
> > +		return -1;
> > +	if (!ctx->object)
> > +		return len;
> > +	action_copy_field = ctx->object;
> > +	if (ctx->curr == ACTION_COPY_FIELD_DST_TYPE_VALUE)
> > +		action_copy_field->dst.field = (enum rte_flow_field_id)i;
> > +	else
> > +		action_copy_field->src.field = (enum rte_flow_field_id)i;
> > +	return len;
> > +}
> > +
> >  /** Parse tokens for destroy command. */
> >  static int
> >  parse_destroy(struct context *ctx, const struct token *token,
> > @@ -7029,6 +7177,24 @@ comp_set_sample_index(struct context *ctx,
> const
> > struct token *token,
> >  	return nb;
> >  }
> >
> > +/** Complete field type for copy_field command. */
> > +static int
> > +comp_set_copy_field(struct context *ctx, const struct token *token,
> > +		   unsigned int ent, char *buf, unsigned int size)
> > +{
> > +	uint16_t idx = 0;
> > +
> > +	RTE_SET_USED(ctx);
> > +	RTE_SET_USED(token);
> > +	for (idx = 0; copy_field_table[idx]; ++idx)
> > +		;
> > +	if (!buf)
> > +		return idx + 1;
> > +	if (ent < idx)
> > +		return strlcpy(buf, copy_field_table[ent], size);
> > +	return -1;
> > +}
> > +
> >  /** Internal context. */
> >  static struct context cmd_flow_context;
> >
> > --
> > 2.24.1
> 
> 
> Acked-by: Ori Kam <orika@nvidia.com>
> Best,
> Ori

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v5 0/2] generic modify rte flow action support
  2021-01-13 17:07     ` [dpdk-dev] [PATCH v4 0/2] generic copy rte flow action support Alexander Kozyrev
  2021-01-13 17:07       ` [dpdk-dev] [PATCH v4 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
  2021-01-13 17:07       ` [dpdk-dev] [PATCH v4 2/2] app/testpmd: add support for " Alexander Kozyrev
@ 2021-01-15 15:42       ` Alexander Kozyrev
  2021-01-15 15:42         ` [dpdk-dev] [PATCH v5 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
                           ` (2 more replies)
  2 siblings, 3 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-15 15:42 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Implement a generic modify rte flow API as described in RFC:
http://patches.dpdk.org/patch/85384/

This API allows modifying a destination header field with data from
a source header field. Number of bits to use from source is specified.
Tag, mark or metadata can also be used as a source/destination to
allow saving/overwriting an arbitrary header field with a user-specified value.
Alternatively, an immediate value can be provided by a user as a source.

Outermost/innermost packet fields (and Tag array elements) are
accessible via the level parameter to facilitate the modification
of encapsulated packet header fields. The offset parameter provides
the flexibility to copy/set any part of a packet starting the
specified packet header field.

---
v1: https://patchwork.dpdk.org/patch/86173/
Initial design.
v2: https://patchwork.dpdk.org/cover/86369/
Added testpmd support.
v3: https://patchwork.dpdk.org/cover/86442/
Made dst_type, src_type and width only mandatory parameters.
v4: https://patchwork.dpdk.org/cover/86488/
Renamed action to RTE_FLOW_ACTION_TYPE_COPY_FIELD.
v5: 
Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD.

Alexander Kozyrev (2):
  ethdev: introduce generic modify rte flow action
  app/testpmd: add support for modify field flow action

 app/test-pmd/cmdline_flow.c            | 246 +++++++++++++++++++++++++
 doc/guides/prog_guide/rte_flow.rst     |  65 +++++++
 doc/guides/rel_notes/release_21_02.rst |   8 +
 lib/librte_ethdev/rte_flow.c           |   2 +
 lib/librte_ethdev/rte_flow.h           |  79 +++++++-
 5 files changed, 399 insertions(+), 1 deletion(-)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v5 1/2] ethdev: introduce generic modify rte flow action
  2021-01-15 15:42       ` [dpdk-dev] [PATCH v5 0/2] generic modify rte flow action support Alexander Kozyrev
@ 2021-01-15 15:42         ` Alexander Kozyrev
  2021-01-15 18:03           ` Ori Kam
  2021-01-15 15:42         ` [dpdk-dev] [PATCH v5 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
  2021-01-16  4:44         ` [dpdk-dev] [PATCH v6 0/2] generic modify rte flow action support Alexander Kozyrev
  2 siblings, 1 reply; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-15 15:42 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Implement the generic modify flow API to allow manipulations on
an arbitrary header field (as well as mark, metadata or tag) using
data from another field or a user-specified value.

This generic modify mechanism removes the necessity to implement
a separate RTE Flow action every time we need to modify a new packet
field in the future. A user-provided value can be used from a
specified packet field/tag/metadata/mark/memory location or directly
provided by a user.

Supported operation are:
- mov: copy data from source to destination.
- add: integer addition, stores the result in destination.
- sub: integer subtraction, stores the result in destination.

The field ID is used to specify the desired source/destination packet
field in order to simplify the API for various encapsulation models.
Specifying the packet field ID with the needed encapsulation level
is able to quickly get a packet field for any inner packet header.

Alternatively, the special ID (ITEM_START) can be used to point to
the very beginning of a packet. This ID in conjunction with the
offset parameter provides great flexibility to copy/modify any part of
a packet as needed.

The number of bits to use from a source as well as the offset can be
be specified to allow a partial copy or dividing a big packet field
into multiple small fields (e.g. copying 128 bits of IPv6 to 4 tags).

An immediate value (or pointer to it) can be specified instead of the
level and the offset for the special FIELD_VALUE ID (or FIELD_POINTER).
Can be used as a source only, in case of user-provided values.

RFC: http://patches.dpdk.org/patch/85384/

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>

---
v1: Initialy RTE_FLOW_ACTION_TYPE_COPY_ITEM
v2: Renamed to RTE_FLOW_ACTION_TYPE_COPY_FIELD
v3: Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
---
 doc/guides/prog_guide/rte_flow.rst     | 65 +++++++++++++++++++++
 doc/guides/rel_notes/release_21_02.rst |  8 +++
 lib/librte_ethdev/rte_flow.c           |  2 +
 lib/librte_ethdev/rte_flow.h           | 79 +++++++++++++++++++++++++-
 4 files changed, 153 insertions(+), 1 deletion(-)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 86b3444803..3b1babd587 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2766,6 +2766,71 @@ The behaviour of the shared action defined by ``action`` argument of type
    | no properties |
    +---------------+
 
+Action: ``MODIFY_FIELD``
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Modify ``dst`` field according to ``op`` selected (move, addition,
+substraction) with ``width`` bits of data from ``src`` field.
+
+Any arbitrary header field (as well as mark, metadata or tag values)
+can be used as both source and destination fields as set by ``field``.
+The immediate value ``RTE_FLOW_FIELD_VALUE`` (or a pointer to it
+``RTE_FLOW_FIELD_POINTER``) is allowed as a source only.
+``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet.
+
+``op`` selects the operation to perform on a destination field.
+- ``mov`` copies the data from ``src`` field to ``dst`` field.
+- ``add`` adds together ``dst`` and ``src`` and stores the result into ``dst``.
+- ``sub`` substracts ``src`` from ``dst`` and stores the result into ``dst``
+
+ ``width`` defines a number of bits to use from ``src`` field.
+
+ ``level`` is used to access any packet field on any encapsulation level
+ as well as any tag element in the tag array.
+- ``0`` means the default behaviour. Depending on the packet type, it can
+  mean outermost, innermost or anything in between.
+- ``1`` requests access to the outermost packet encapsulation level.
+- ``2`` and subsequent values requests access to the specified packet
+  encapsulation level, from outermost to innermost (lower to higher values).
+  For the tag array ``level`` translates directly into the array index.
+
+``offset`` specifies the number of bits to skip from a field's start.
+That allows performing a partial copy of the needed part or to divide a big
+packet field into multiple smaller fields. Alternatively, ``offset`` allows
+going past the specified packet field boundary to copy a field to an
+arbitrary place in a packet, essentially providing a way to copy any part of
+a packet to any other part of it if supported by an underlying PMD driver.
+
+``value`` sets an immediate value to be used as a source or points to a
+location of the value in memory. It is used instead of ``level`` and ``offset``
+for ``RTE_FLOW_FIELD_VALUE`` and ``RTE_FLOW_FIELD_POINTER`` respectively.
+
+.. _table_rte_flow_action_modify_field:
+
+.. table:: MODIFY_FIELD
+
+   +-----------------------------------------+
+   | Field         | Value                   |
+   +===============+=========================+
+   | ``op``        | operation to perform    |
+   | ``dst``       | destination field       |
+   | ``src``       | source field            |
+   | ``width``     | number of bits to use   |
+   +---------------+-------------------------+
+
+.. _table_rte_flow_action_modify_data:
+
+.. table:: destination/source field definition
+
+   +--------------------------------------------------------------------------+
+   | Field         | Value                                                    |
+   +===============+==========================================================+
+   | ``field``     | ID: packet field, mark, meta, tag, immediate, pointer    |
+   | ``level``     | encapsulation level of a packet field or tag array index |
+   | ``offset``    | number of bits to skip at the beginning                  |
+   | ``value``     | immediate value or a poiner to it                        |
+   +---------------+----------------------------------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst
index c64294e7a6..fc828cb21d 100644
--- a/doc/guides/rel_notes/release_21_02.rst
+++ b/doc/guides/rel_notes/release_21_02.rst
@@ -55,6 +55,14 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added support of modify field action in the flow API.**
+
+  Added modify action support to perform various operations on
+  any arbitrary header field (as well as mark, metadata or tag values):
+  ``RTE_FLOW_ACTION_TYPE_MODIFY_FIELD``.
+  supported operations are: overwriting the field with the content from
+  another field, addition and subtraction of an immediate value.
+
 * **Updated Broadcom bnxt driver.**
 
   Updated the Broadcom bnxt driver with fixes and improvements, including:
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index a06f64c271..9dd051f3c2 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -176,6 +176,8 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
 	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
 	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
+	MK_FLOW_ACTION(MODIFY_FIELD,
+		       sizeof(struct rte_flow_action_modify_field)),
 	/**
 	 * Shared action represented as handle of type
 	 * (struct rte_flow_shared action *) stored in conf field (see
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 0977a78270..6610e638d7 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2198,6 +2198,17 @@ enum rte_flow_action_type {
 	 * struct rte_flow_shared_action).
 	 */
 	RTE_FLOW_ACTION_TYPE_SHARED,
+
+	/**
+	 * Modify a packet header field, tag, mark or metadata.
+	 *
+	 * Allow the modification of an arbitrary header field via
+	 * set, add and sub operations or copying its content into
+	 * tag, meta or mark for future processing.
+	 *
+	 * See struct rte_flow_action_modify_field.
+	 */
+	RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,
 };
 
 /**
@@ -2777,7 +2788,6 @@ struct rte_flow_action_set_dscp {
 	uint8_t dscp;
 };
 
-
 /**
  * RTE_FLOW_ACTION_TYPE_SHARED
  *
@@ -2791,6 +2801,73 @@ struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+enum rte_flow_field_id {
+	RTE_FLOW_FIELD_START = 0,
+	RTE_FLOW_FIELD_MAC_DST,
+	RTE_FLOW_FIELD_MAC_SRC,
+	RTE_FLOW_FIELD_VLAN_TYPE,
+	RTE_FLOW_FIELD_VLAN_ID,
+	RTE_FLOW_FIELD_MAC_TYPE,
+	RTE_FLOW_FIELD_IPV4_DSCP,
+	RTE_FLOW_FIELD_IPV4_TTL,
+	RTE_FLOW_FIELD_IPV4_SRC,
+	RTE_FLOW_FIELD_IPV4_DST,
+	RTE_FLOW_FIELD_IPV6_HOPLIMIT,
+	RTE_FLOW_FIELD_IPV6_SRC,
+	RTE_FLOW_FIELD_IPV6_DST,
+	RTE_FLOW_FIELD_TCP_PORT_SRC,
+	RTE_FLOW_FIELD_TCP_PORT_DST,
+	RTE_FLOW_FIELD_TCP_SEQ_NUM,
+	RTE_FLOW_FIELD_TCP_ACK_NUM,
+	RTE_FLOW_FIELD_TCP_FLAGS,
+	RTE_FLOW_FIELD_UDP_PORT_SRC,
+	RTE_FLOW_FIELD_UDP_PORT_DST,
+	RTE_FLOW_FIELD_VXLAN_VNI,
+	RTE_FLOW_FIELD_GENEVE_VNI,
+	RTE_FLOW_FIELD_GTP_TEID,
+	RTE_FLOW_FIELD_TAG,
+	RTE_FLOW_FIELD_MARK,
+	RTE_FLOW_FIELD_META,
+	RTE_FLOW_FIELD_POINTER,
+	RTE_FLOW_FIELD_VALUE,
+};
+
+struct rte_flow_action_modify_data {
+	enum rte_flow_field_id field;
+	RTE_STD_C11
+	union {
+		struct {
+			uint32_t level;
+			uint32_t offset;
+		};
+		uint64_t value;
+	};
+};
+
+enum rte_flow_modify_op {
+	RTE_FLOW_MODIFY_MOV = 0,
+	RTE_FLOW_MODIFY_ADD,
+	RTE_FLOW_MODIFY_SUB,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
+ *
+ * Modifies a destination header field according to the specified
+ * operation. Another packet field can be used as a source as well
+ * as tag, mark, metadata or an immediate value or a pointer to it.
+ * Width is the number of bits used from the source item.
+ */
+struct rte_flow_action_modify_field {
+	enum rte_flow_modify_op operation;
+	struct rte_flow_action_modify_data dst;
+	struct rte_flow_action_modify_data src;
+	uint32_t width;
+};
+
 /* Mbuf dynamic field offset for metadata. */
 extern int32_t rte_flow_dynf_metadata_offs;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v5 2/2] app/testpmd: add support for modify field flow action
  2021-01-15 15:42       ` [dpdk-dev] [PATCH v5 0/2] generic modify rte flow action support Alexander Kozyrev
  2021-01-15 15:42         ` [dpdk-dev] [PATCH v5 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
@ 2021-01-15 15:42         ` Alexander Kozyrev
  2021-01-15 18:04           ` Ori Kam
  2021-01-16  4:44         ` [dpdk-dev] [PATCH v6 0/2] generic modify rte flow action support Alexander Kozyrev
  2 siblings, 1 reply; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-15 15:42 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Add support for the RTE_FLOW_ACTION_MODIFY_FIELD to the testpmd.
Implement CLI to create the modify_field action and supply all the
needed parameters to modify an arbitrary packet field (as well as
mark, tag or metadata) with data from another field or immediate
value.

Example of the flow is the following:
flow create 0 egress group 1 pattern eth / ipv4 / udp / end
  actions modify_field op mov dst_type tag dst_level 2 dst_offset 8
          src_type gtp_teid src_level 0 src_offset 0 width 16 / end

This flow copies 16 bits from the second Tag in the Tags array
into the outermost GTP TEID packet header field. 8 bits of the
Tag are skipped as indicated by the dst_offset action parameter.

op, dst_type, src_type and width are the mandatory parameters to
specify. Levels and offset are 0 by default if they are not
overridden by a user. The operation can be mov, add or sub.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>

---
v1: Initial implementation.
v2: Made dst_type, src_type and width only mandatory parameters.
v3: Reworked to accomodate API change from copy_field to modify_field.
---
 app/test-pmd/cmdline_flow.c | 246 ++++++++++++++++++++++++++++++++++++
 1 file changed, 246 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 585cab98b4..62305b7fb7 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -408,6 +408,19 @@ enum index {
 	ACTION_SAMPLE_INDEX_VALUE,
 	ACTION_SHARED,
 	SHARED_ACTION_ID2PTR,
+	ACTION_MODIFY_FIELD,
+	ACTION_MODIFY_FIELD_OP,
+	ACTION_MODIFY_FIELD_OP_VALUE,
+	ACTION_MODIFY_FIELD_DST_TYPE,
+	ACTION_MODIFY_FIELD_DST_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ACTION_MODIFY_FIELD_SRC_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -561,6 +574,22 @@ struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 
+static const char *const modify_field_ops[] = {
+	"mov", "add", "sub", NULL
+};
+
+static const char *const modify_field_ids[] = {
+	"start", "mac_dst", "mac_src",
+	"vlan_type", "vlan_id", "mac_type",
+	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
+	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
+	"tcp_port_src", "tcp_port_dst",
+	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
+	"udp_port_src", "udp_port_dst",
+	"vxlan_vni", "geneve_vni", "gtp_teid",
+	"tag", "mark", "meta", "value", "pointer", NULL
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -1306,6 +1335,7 @@ static const enum index next_action[] = {
 	ACTION_AGE,
 	ACTION_SAMPLE,
 	ACTION_SHARED,
+	ACTION_MODIFY_FIELD,
 	ZERO,
 };
 
@@ -1556,6 +1586,21 @@ static const enum index next_action_sample[] = {
 	ZERO,
 };
 
+static const enum index action_modify_field_dst[] = {
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ZERO,
+};
+
+static const enum index action_modify_field_src[] = {
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -1638,6 +1683,14 @@ static int
 parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 				const char *str, unsigned int len, void *buf,
 				unsigned int size);
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1722,6 +1775,10 @@ static int comp_set_raw_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
 static int comp_set_sample_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_op(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_id(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -4037,6 +4094,103 @@ static const struct token token_list[] = {
 		.call = parse_vc_action_raw_decap_index,
 		.comp = comp_set_raw_index,
 	},
+	[ACTION_MODIFY_FIELD] = {
+		.name = "modify_field",
+		.help = "modify destination field with data from source field",
+		.priv = PRIV_ACTION(MODIFY_FIELD,
+			sizeof(struct rte_flow_action_modify_field)),
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_OP)),
+		.call = parse_vc,
+	},
+	[ACTION_MODIFY_FIELD_OP] = {
+		.name = "op",
+		.help = "operation type",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE),
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_OP_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_OP_VALUE] = {
+		.name = "{operation}",
+		.help = "operation type value",
+		.call = parse_vc_modify_field_op,
+		.comp = comp_set_modify_field_op,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE] = {
+		.name = "dst_type",
+		.help = "destination field type",
+		.next = NEXT(action_modify_field_dst,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE_VALUE] = {
+		.name = "{dst_type}",
+		.help = "destination field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_DST_LEVEL] = {
+		.name = "dst_level",
+		.help = "destination field level",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_OFFSET] = {
+		.name = "dst_offset",
+		.help = "destination field bit offset",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE] = {
+		.name = "src_type",
+		.help = "source field type",
+		.next = NEXT(action_modify_field_src,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE_VALUE] = {
+		.name = "{src_type}",
+		.help = "source field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_SRC_LEVEL] = {
+		.name = "src_level",
+		.help = "source field level",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_OFFSET] = {
+		.name = "src_offset",
+		.help = "source field bit offset",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_VALUE] = {
+		.name = "src_value",
+		.help = "source immediate value",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_WIDTH),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.value)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_WIDTH] = {
+		.name = "width",
+		.help = "number of bits to copy",
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					width)),
+		.call = parse_vc_conf,
+	},
 	/* Top level command. */
 	[SET] = {
 		.name = "set",
@@ -5960,6 +6114,62 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse operation for modify_field command. */
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_OP_VALUE)
+		return -1;
+	for (i = 0; modify_field_ops[i]; ++i)
+		if (!strcmp_partial(modify_field_ops[i], str, len))
+			break;
+	if (!modify_field_ops[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	action_modify_field->operation = (enum rte_flow_modify_op)i;
+	return len;
+}
+
+/** Parse id for modify_field command. */
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_DST_TYPE_VALUE &&
+		ctx->curr != ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)
+		return -1;
+	for (i = 0; modify_field_ids[i]; ++i)
+		if (!strcmp_partial(modify_field_ids[i], str, len))
+			break;
+	if (!modify_field_ids[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	if (ctx->curr == ACTION_MODIFY_FIELD_DST_TYPE_VALUE)
+		action_modify_field->dst.field = (enum rte_flow_field_id)i;
+	else
+		action_modify_field->src.field = (enum rte_flow_field_id)i;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -7029,6 +7239,42 @@ comp_set_sample_index(struct context *ctx, const struct token *token,
 	return nb;
 }
 
+/** Complete operation for modify_field command. */
+static int
+comp_set_modify_field_op(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ops[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ops[ent], size);
+	return -1;
+}
+
+/** Complete field id for modify_field command. */
+static int
+comp_set_modify_field_id(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ids[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ids[ent], size);
+	return -1;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/2] ethdev: introduce generic modify rte flow action
  2021-01-15 15:42         ` [dpdk-dev] [PATCH v5 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
@ 2021-01-15 18:03           ` Ori Kam
  2021-01-17  9:23             ` Slava Ovsiienko
  0 siblings, 1 reply; 48+ messages in thread
From: Ori Kam @ 2021-01-15 18:03 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko, jerinjacobk

Hi Alexander,

Small inline, but I leave it to you if you want to change it.

> -----Original Message-----
> From: Alexander Kozyrev <akozyrev@nvidia.com>
> Sent: Friday, January 15, 2021 5:43 PM
> Subject: [PATCH v5 1/2] ethdev: introduce generic modify rte flow action
> 
> Implement the generic modify flow API to allow manipulations on
> an arbitrary header field (as well as mark, metadata or tag) using
> data from another field or a user-specified value.
> 
> This generic modify mechanism removes the necessity to implement
> a separate RTE Flow action every time we need to modify a new packet
> field in the future. A user-provided value can be used from a
> specified packet field/tag/metadata/mark/memory location or directly
>
 provided by a user.
>

[Snip]
 
> +
> +enum rte_flow_modify_op {
> +	RTE_FLOW_MODIFY_MOV = 0,
> +	RTE_FLOW_MODIFY_ADD,
> +	RTE_FLOW_MODIFY_SUB,
> +};
> +
I think  mov is not the best option, since we the value in src stays
I think copy or set will be better.
If you change it feel free to add my ack.

> +/**
> + * @warning
> + * @b EXPERIMENTAL: this structure may change without prior notice
> + *
> + * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
> + *
> + * Modifies a destination header field according to the specified
> + * operation. Another packet field can be used as a source as well
> + * as tag, mark, metadata or an immediate value or a pointer to it.
> + * Width is the number of bits used from the source item.
> + */
> +struct rte_flow_action_modify_field {
> +	enum rte_flow_modify_op operation;
> +	struct rte_flow_action_modify_data dst;
> +	struct rte_flow_action_modify_data src;
> +	uint32_t width;
> +};
> +
>  /* Mbuf dynamic field offset for metadata. */
>  extern int32_t rte_flow_dynf_metadata_offs;
> 
> --
> 2.24.1

Acked-by: Ori Kam <orika@nvidia.com>
Best,
Ori

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/2] app/testpmd: add support for modify field flow action
  2021-01-15 15:42         ` [dpdk-dev] [PATCH v5 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
@ 2021-01-15 18:04           ` Ori Kam
  0 siblings, 0 replies; 48+ messages in thread
From: Ori Kam @ 2021-01-15 18:04 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: Slava Ovsiienko, NBU-Contact-Thomas Monjalon, ferruh.yigit,
	andrew.rybchenko, jerinjacobk



> -----Original Message-----
> From: Alexander Kozyrev <akozyrev@nvidia.com>
> Sent: Friday, January 15, 2021 5:43 PM
> Subject: [PATCH v5 2/2] app/testpmd: add support for modify field flow action
> 
> Add support for the RTE_FLOW_ACTION_MODIFY_FIELD to the testpmd.
> Implement CLI to create the modify_field action and supply all the
> needed parameters to modify an arbitrary packet field (as well as
> mark, tag or metadata) with data from another field or immediate
> value.
> 
> Example of the flow is the following:
> flow create 0 egress group 1 pattern eth / ipv4 / udp / end
>   actions modify_field op mov dst_type tag dst_level 2 dst_offset 8
>           src_type gtp_teid src_level 0 src_offset 0 width 16 / end
> 
> This flow copies 16 bits from the second Tag in the Tags array
> into the outermost GTP TEID packet header field. 8 bits of the
> Tag are skipped as indicated by the dst_offset action parameter.
> 
> op, dst_type, src_type and width are the mandatory parameters to
> specify. Levels and offset are 0 by default if they are not
> overridden by a user. The operation can be mov, add or sub.
> 
> Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> 
> ---
> v1: Initial implementation.
> v2: Made dst_type, src_type and width only mandatory parameters.
> v3: Reworked to accomodate API change from copy_field to modify_field.
> ---

Acked-by: Ori Kam <orika@nvidia.com>
Thanks,
Ori


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v6 0/2] generic modify rte flow action support
  2021-01-15 15:42       ` [dpdk-dev] [PATCH v5 0/2] generic modify rte flow action support Alexander Kozyrev
  2021-01-15 15:42         ` [dpdk-dev] [PATCH v5 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
  2021-01-15 15:42         ` [dpdk-dev] [PATCH v5 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
@ 2021-01-16  4:44         ` Alexander Kozyrev
  2021-01-16  4:44           ` [dpdk-dev] [PATCH v6 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
                             ` (2 more replies)
  2 siblings, 3 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-16  4:44 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Implement a generic modify rte flow API as described in RFC:
http://patches.dpdk.org/patch/85384/

This API allows modifying a destination header field with data from
a source header field. Number of bits to use from the source is specified.
Tag, Mark or Metadata can also be used as a source/destination to allow
saving/overwriting an arbitrary header field with a user-specified value.
Alternatively, an immediate value can be provided by a user as a source.

Outermost/innermost packet fields (and Tag array elements) are
accessible via the level parameter to facilitate the modification
of encapsulated packet header fields. The offset parameter provides
the flexibility to copy/set any part of a packet starting the
specified packet header field.

---
v1: https://patchwork.dpdk.org/patch/86173/
Initial design.
v2: https://patchwork.dpdk.org/cover/86369/
Added testpmd support.
v3: https://patchwork.dpdk.org/cover/86442/
Made dst_type, src_type and width only mandatory parameters.
v4: https://patchwork.dpdk.org/cover/86488/
Renamed action to RTE_FLOW_ACTION_TYPE_COPY_FIELD.
v5: 
Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD.
v6:
Fixed typos in documentation.

Alexander Kozyrev (2):
  ethdev: introduce generic modify rte flow action
  app/testpmd: add support for modify field flow action

 app/test-pmd/cmdline_flow.c            | 246 +++++++++++++++++++++++++
 doc/guides/prog_guide/rte_flow.rst     |  65 +++++++
 doc/guides/rel_notes/release_21_02.rst |   8 +
 lib/librte_ethdev/rte_flow.c           |   2 +
 lib/librte_ethdev/rte_flow.h           |  79 +++++++-
 5 files changed, 399 insertions(+), 1 deletion(-)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v6 1/2] ethdev: introduce generic modify rte flow action
  2021-01-16  4:44         ` [dpdk-dev] [PATCH v6 0/2] generic modify rte flow action support Alexander Kozyrev
@ 2021-01-16  4:44           ` Alexander Kozyrev
  2021-01-16  4:44           ` [dpdk-dev] [PATCH v6 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
  2021-01-16  4:50           ` [dpdk-dev] [PATCH v7 0/2] generic modify rte flow action support Alexander Kozyrev
  2 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-16  4:44 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Implement the generic modify flow API to allow manipulations on
an arbitrary header field (as well as mark, metadata or tag) using
data from another field or a user-specified value.
This generic modify mechanism removes the necessity to implement
a separate RTE Flow action every time we need to modify a new packet
field in the future.

Supported operation are:
- set: copy data from source to destination.
- add: integer addition, stores the result in destination.
- sub: integer subtraction, stores the result in destination.

The field ID is used to specify the desired source/destination packet
field in order to simplify the API for various encapsulation models.
Specifying the packet field ID with the needed encapsulation level
is able to quickly get a packet field for any inner packet header.

Alternatively, the special ID (ITEM_START) can be used to point to
the very beginning of a packet. This ID in conjunction with the
offset parameter provides great flexibility to copy/modify any part of
a packet as needed.

The number of bits to use from a source as well as the offset can be
be specified to allow a partial copy or dividing a big packet field
into multiple small fields (e.g. copying 128 bits of IPv6 to 4 tags).

An immediate value (or pointer to it) can be specified instead of the
level and the offset for the special FIELD_VALUE ID (or FIELD_POINTER).
Can be used as a source only, in case of user-provided values.

RFC: http://patches.dpdk.org/patch/85384/

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>

---
v1: Initialy RTE_FLOW_ACTION_TYPE_COPY_ITEM
v2: Renamed to RTE_FLOW_ACTION_TYPE_COPY_FIELD
v3: Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
v4: Fixed typos in documentation, renamed mov operation to set.
---
 doc/guides/prog_guide/rte_flow.rst     | 65 +++++++++++++++++++++
 doc/guides/rel_notes/release_21_02.rst |  8 +++
 lib/librte_ethdev/rte_flow.c           |  2 +
 lib/librte_ethdev/rte_flow.h           | 79 +++++++++++++++++++++++++-
 4 files changed, 153 insertions(+), 1 deletion(-)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 86b3444803..575cc8ed15 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2766,6 +2766,71 @@ The behaviour of the shared action defined by ``action`` argument of type
    | no properties |
    +---------------+
 
+Action: ``MODIFY_FIELD``
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Modify ``dst`` field according to ``op`` selected (move, addition,
+substraction) with ``width`` bits of data from ``src`` field.
+
+Any arbitrary header field (as well as mark, metadata or tag values)
+can be used as both source and destination fields as set by ``field``.
+The immediate value ``RTE_FLOW_FIELD_VALUE`` (or a pointer to it
+``RTE_FLOW_FIELD_POINTER``) is allowed as a source only.
+``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet.
+
+``op`` selects the operation to perform on a destination field.
+- ``set`` copies the data from ``src`` field to ``dst`` field.
+- ``add`` adds together ``dst`` and ``src`` and stores the result into ``dst``.
+- ``sub`` substracts ``src`` from ``dst`` and stores the result into ``dst``
+
+``width`` defines a number of bits to use from ``src`` field.
+
+``level`` is used to access any packet field on any encapsulation level
+as well as any tag element in the tag array.
+- ``0`` means the default behaviour. Depending on the packet type, it can
+mean outermost, innermost or anything in between.
+- ``1`` requests access to the outermost packet encapsulation level.
+- ``2`` and subsequent values requests access to the specified packet
+encapsulation level, from outermost to innermost (lower to higher values).
+For the tag array ``level`` translates directly into the array index.
+
+``offset`` specifies the number of bits to skip from a field's start.
+That allows performing a partial copy of the needed part or to divide a big
+packet field into multiple smaller fields. Alternatively, ``offset`` allows
+going past the specified packet field boundary to copy a field to an
+arbitrary place in a packet, essentially providing a way to copy any part of
+a packet to any other part of it if supported by an underlying PMD driver.
+
+``value`` sets an immediate value to be used as a source or points to a
+location of the value in memory. It is used instead of ``level`` and ``offset``
+for ``RTE_FLOW_FIELD_VALUE`` and ``RTE_FLOW_FIELD_POINTER`` respectively.
+
+.. _table_rte_flow_action_modify_field:
+
+.. table:: MODIFY_FIELD
+
+   +-----------------------------------------+
+   | Field         | Value                   |
+   +===============+=========================+
+   | ``op``        | operation to perform    |
+   | ``dst``       | destination field       |
+   | ``src``       | source field            |
+   | ``width``     | number of bits to use   |
+   +---------------+-------------------------+
+
+.. _table_rte_flow_action_modify_data:
+
+.. table:: destination/source field definition
+
+   +--------------------------------------------------------------------------+
+   | Field         | Value                                                    |
+   +===============+==========================================================+
+   | ``field``     | ID: packet field, mark, meta, tag, immediate, pointer    |
+   | ``level``     | encapsulation level of a packet field or tag array index |
+   | ``offset``    | number of bits to skip at the beginning                  |
+   | ``value``     | immediate value or a poiner to it                        |
+   +---------------+----------------------------------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst
index c64294e7a6..5962c9f80b 100644
--- a/doc/guides/rel_notes/release_21_02.rst
+++ b/doc/guides/rel_notes/release_21_02.rst
@@ -55,6 +55,14 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added support of modify field action in the flow API.**
+
+  Added modify action support to perform various operations on
+  any arbitrary header field (as well as mark, metadata or tag values):
+  ``RTE_FLOW_ACTION_TYPE_MODIFY_FIELD``.
+  supported operations are: overwriting a field with the content from
+  another field, addition and subtraction using an immediate value.
+
 * **Updated Broadcom bnxt driver.**
 
   Updated the Broadcom bnxt driver with fixes and improvements, including:
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index a06f64c271..9dd051f3c2 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -176,6 +176,8 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
 	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
 	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
+	MK_FLOW_ACTION(MODIFY_FIELD,
+		       sizeof(struct rte_flow_action_modify_field)),
 	/**
 	 * Shared action represented as handle of type
 	 * (struct rte_flow_shared action *) stored in conf field (see
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 0977a78270..07c4d859c2 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2198,6 +2198,17 @@ enum rte_flow_action_type {
 	 * struct rte_flow_shared_action).
 	 */
 	RTE_FLOW_ACTION_TYPE_SHARED,
+
+	/**
+	 * Modify a packet header field, tag, mark or metadata.
+	 *
+	 * Allow the modification of an arbitrary header field via
+	 * set, add and sub operations or copying its content into
+	 * tag, meta or mark for future processing.
+	 *
+	 * See struct rte_flow_action_modify_field.
+	 */
+	RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,
 };
 
 /**
@@ -2777,7 +2788,6 @@ struct rte_flow_action_set_dscp {
 	uint8_t dscp;
 };
 
-
 /**
  * RTE_FLOW_ACTION_TYPE_SHARED
  *
@@ -2791,6 +2801,73 @@ struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+enum rte_flow_field_id {
+	RTE_FLOW_FIELD_START = 0,
+	RTE_FLOW_FIELD_MAC_DST,
+	RTE_FLOW_FIELD_MAC_SRC,
+	RTE_FLOW_FIELD_VLAN_TYPE,
+	RTE_FLOW_FIELD_VLAN_ID,
+	RTE_FLOW_FIELD_MAC_TYPE,
+	RTE_FLOW_FIELD_IPV4_DSCP,
+	RTE_FLOW_FIELD_IPV4_TTL,
+	RTE_FLOW_FIELD_IPV4_SRC,
+	RTE_FLOW_FIELD_IPV4_DST,
+	RTE_FLOW_FIELD_IPV6_HOPLIMIT,
+	RTE_FLOW_FIELD_IPV6_SRC,
+	RTE_FLOW_FIELD_IPV6_DST,
+	RTE_FLOW_FIELD_TCP_PORT_SRC,
+	RTE_FLOW_FIELD_TCP_PORT_DST,
+	RTE_FLOW_FIELD_TCP_SEQ_NUM,
+	RTE_FLOW_FIELD_TCP_ACK_NUM,
+	RTE_FLOW_FIELD_TCP_FLAGS,
+	RTE_FLOW_FIELD_UDP_PORT_SRC,
+	RTE_FLOW_FIELD_UDP_PORT_DST,
+	RTE_FLOW_FIELD_VXLAN_VNI,
+	RTE_FLOW_FIELD_GENEVE_VNI,
+	RTE_FLOW_FIELD_GTP_TEID,
+	RTE_FLOW_FIELD_TAG,
+	RTE_FLOW_FIELD_MARK,
+	RTE_FLOW_FIELD_META,
+	RTE_FLOW_FIELD_POINTER,
+	RTE_FLOW_FIELD_VALUE,
+};
+
+struct rte_flow_action_modify_data {
+	enum rte_flow_field_id field;
+	RTE_STD_C11
+	union {
+		struct {
+			uint32_t level;
+			uint32_t offset;
+		};
+		uint64_t value;
+	};
+};
+
+enum rte_flow_modify_op {
+	RTE_FLOW_MODIFY_SET = 0,
+	RTE_FLOW_MODIFY_ADD,
+	RTE_FLOW_MODIFY_SUB,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
+ *
+ * Modifies a destination header field according to the specified
+ * operation. Another packet field can be used as a source as well
+ * as tag, mark, metadata or an immediate value or a pointer to it.
+ * Width is the number of bits used from the source item.
+ */
+struct rte_flow_action_modify_field {
+	enum rte_flow_modify_op operation;
+	struct rte_flow_action_modify_data dst;
+	struct rte_flow_action_modify_data src;
+	uint32_t width;
+};
+
 /* Mbuf dynamic field offset for metadata. */
 extern int32_t rte_flow_dynf_metadata_offs;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v6 2/2] app/testpmd: add support for modify field flow action
  2021-01-16  4:44         ` [dpdk-dev] [PATCH v6 0/2] generic modify rte flow action support Alexander Kozyrev
  2021-01-16  4:44           ` [dpdk-dev] [PATCH v6 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
@ 2021-01-16  4:44           ` Alexander Kozyrev
  2021-01-16  4:50           ` [dpdk-dev] [PATCH v7 0/2] generic modify rte flow action support Alexander Kozyrev
  2 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-16  4:44 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Add support for the RTE_FLOW_ACTION_MODIFY_FIELD to the testpmd.
Implement CLI to create the modify_field action and supply all the
needed parameters to modify an arbitrary packet field (as well as
mark, tag or metadata) with data from another field or immediate
value.

Example of the flow is the following:
flow create 0 egress group 1 pattern eth / ipv4 / udp / end
  actions modify_field op set dst_type tag dst_level 2 dst_offset 8
          src_type gtp_teid src_level 0 src_offset 0 width 16 / end

This flow copies 16 bits from the second Tag in the Tags array
into the outermost GTP TEID packet header field. 8 bits of the
Tag are skipped as indicated by the dst_offset action parameter.

op, dst_type, src_type and width are the mandatory parameters to
specify. Levels and offset are 0 by default if they are not
overridden by a user. The operation can be set, add or sub.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>

---
v1: Initial implementation.
v2: Made dst_type, src_type and width only mandatory parameters.
v3: Reworked to accomodate API change from copy_field to modify_field.
v4: Renamed the mov operation to set.
---
 app/test-pmd/cmdline_flow.c | 246 ++++++++++++++++++++++++++++++++++++
 1 file changed, 246 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 585cab98b4..782caa8278 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -408,6 +408,19 @@ enum index {
 	ACTION_SAMPLE_INDEX_VALUE,
 	ACTION_SHARED,
 	SHARED_ACTION_ID2PTR,
+	ACTION_MODIFY_FIELD,
+	ACTION_MODIFY_FIELD_OP,
+	ACTION_MODIFY_FIELD_OP_VALUE,
+	ACTION_MODIFY_FIELD_DST_TYPE,
+	ACTION_MODIFY_FIELD_DST_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ACTION_MODIFY_FIELD_SRC_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -561,6 +574,22 @@ struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 
+static const char *const modify_field_ops[] = {
+	"set", "add", "sub", NULL
+};
+
+static const char *const modify_field_ids[] = {
+	"start", "mac_dst", "mac_src",
+	"vlan_type", "vlan_id", "mac_type",
+	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
+	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
+	"tcp_port_src", "tcp_port_dst",
+	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
+	"udp_port_src", "udp_port_dst",
+	"vxlan_vni", "geneve_vni", "gtp_teid",
+	"tag", "mark", "meta", "value", "pointer", NULL
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -1306,6 +1335,7 @@ static const enum index next_action[] = {
 	ACTION_AGE,
 	ACTION_SAMPLE,
 	ACTION_SHARED,
+	ACTION_MODIFY_FIELD,
 	ZERO,
 };
 
@@ -1556,6 +1586,21 @@ static const enum index next_action_sample[] = {
 	ZERO,
 };
 
+static const enum index action_modify_field_dst[] = {
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ZERO,
+};
+
+static const enum index action_modify_field_src[] = {
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -1638,6 +1683,14 @@ static int
 parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 				const char *str, unsigned int len, void *buf,
 				unsigned int size);
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1722,6 +1775,10 @@ static int comp_set_raw_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
 static int comp_set_sample_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_op(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_id(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -4037,6 +4094,103 @@ static const struct token token_list[] = {
 		.call = parse_vc_action_raw_decap_index,
 		.comp = comp_set_raw_index,
 	},
+	[ACTION_MODIFY_FIELD] = {
+		.name = "modify_field",
+		.help = "modify destination field with data from source field",
+		.priv = PRIV_ACTION(MODIFY_FIELD,
+			sizeof(struct rte_flow_action_modify_field)),
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_OP)),
+		.call = parse_vc,
+	},
+	[ACTION_MODIFY_FIELD_OP] = {
+		.name = "op",
+		.help = "operation type",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE),
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_OP_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_OP_VALUE] = {
+		.name = "{operation}",
+		.help = "operation type value",
+		.call = parse_vc_modify_field_op,
+		.comp = comp_set_modify_field_op,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE] = {
+		.name = "dst_type",
+		.help = "destination field type",
+		.next = NEXT(action_modify_field_dst,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE_VALUE] = {
+		.name = "{dst_type}",
+		.help = "destination field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_DST_LEVEL] = {
+		.name = "dst_level",
+		.help = "destination field level",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_OFFSET] = {
+		.name = "dst_offset",
+		.help = "destination field bit offset",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE] = {
+		.name = "src_type",
+		.help = "source field type",
+		.next = NEXT(action_modify_field_src,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE_VALUE] = {
+		.name = "{src_type}",
+		.help = "source field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_SRC_LEVEL] = {
+		.name = "src_level",
+		.help = "source field level",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_OFFSET] = {
+		.name = "src_offset",
+		.help = "source field bit offset",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_VALUE] = {
+		.name = "src_value",
+		.help = "source immediate value",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_WIDTH),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.value)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_WIDTH] = {
+		.name = "width",
+		.help = "number of bits to copy",
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					width)),
+		.call = parse_vc_conf,
+	},
 	/* Top level command. */
 	[SET] = {
 		.name = "set",
@@ -5960,6 +6114,62 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse operation for modify_field command. */
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_OP_VALUE)
+		return -1;
+	for (i = 0; modify_field_ops[i]; ++i)
+		if (!strcmp_partial(modify_field_ops[i], str, len))
+			break;
+	if (!modify_field_ops[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	action_modify_field->operation = (enum rte_flow_modify_op)i;
+	return len;
+}
+
+/** Parse id for modify_field command. */
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_DST_TYPE_VALUE &&
+		ctx->curr != ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)
+		return -1;
+	for (i = 0; modify_field_ids[i]; ++i)
+		if (!strcmp_partial(modify_field_ids[i], str, len))
+			break;
+	if (!modify_field_ids[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	if (ctx->curr == ACTION_MODIFY_FIELD_DST_TYPE_VALUE)
+		action_modify_field->dst.field = (enum rte_flow_field_id)i;
+	else
+		action_modify_field->src.field = (enum rte_flow_field_id)i;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -7029,6 +7239,42 @@ comp_set_sample_index(struct context *ctx, const struct token *token,
 	return nb;
 }
 
+/** Complete operation for modify_field command. */
+static int
+comp_set_modify_field_op(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ops[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ops[ent], size);
+	return -1;
+}
+
+/** Complete field id for modify_field command. */
+static int
+comp_set_modify_field_id(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ids[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ids[ent], size);
+	return -1;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v7 0/2] generic modify rte flow action support
  2021-01-16  4:44         ` [dpdk-dev] [PATCH v6 0/2] generic modify rte flow action support Alexander Kozyrev
  2021-01-16  4:44           ` [dpdk-dev] [PATCH v6 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
  2021-01-16  4:44           ` [dpdk-dev] [PATCH v6 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
@ 2021-01-16  4:50           ` Alexander Kozyrev
  2021-01-16  4:50             ` [dpdk-dev] [PATCH v7 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
                               ` (2 more replies)
  2 siblings, 3 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-16  4:50 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Implement a generic modify rte flow API as described in RFC:
http://patches.dpdk.org/patch/85384/

This API allows modifying a destination header field with data from
a source header field. Number of bits to use from the source is specified.
Tag, Mark or Metadata can also be used as a source/destination to allow
saving/overwriting an arbitrary header field with a user-specified value.
Alternatively, an immediate value can be provided by a user as a source.

Outermost/innermost packet fields (and Tag array elements) are
accessible via the level parameter to facilitate the modification
of encapsulated packet header fields. The offset parameter provides
the flexibility to copy/set any part of a packet starting the
specified packet header field.

---
v1: https://patchwork.dpdk.org/patch/86173/
Initial design.
v2: https://patchwork.dpdk.org/cover/86369/
Added testpmd support.
v3: https://patchwork.dpdk.org/cover/86442/
Made dst_type, src_type and width only mandatory parameters.
v4: https://patchwork.dpdk.org/cover/86488/
Renamed action to RTE_FLOW_ACTION_TYPE_COPY_FIELD.
v5: 
Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD.
v6:
Fixed typos in documentation.

Alexander Kozyrev (2):
  ethdev: introduce generic modify rte flow action
  app/testpmd: add support for modify field flow action

 app/test-pmd/cmdline_flow.c            | 246 +++++++++++++++++++++++++
 doc/guides/prog_guide/rte_flow.rst     |  65 +++++++
 doc/guides/rel_notes/release_21_02.rst |   8 +
 lib/librte_ethdev/rte_flow.c           |   2 +
 lib/librte_ethdev/rte_flow.h           |  79 +++++++-
 5 files changed, 399 insertions(+), 1 deletion(-)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v7 1/2] ethdev: introduce generic modify rte flow action
  2021-01-16  4:50           ` [dpdk-dev] [PATCH v7 0/2] generic modify rte flow action support Alexander Kozyrev
@ 2021-01-16  4:50             ` Alexander Kozyrev
  2021-01-17 23:15               ` Thomas Monjalon
  2021-01-16  4:50             ` [dpdk-dev] [PATCH v7 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
  2021-01-18 16:18             ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Alexander Kozyrev
  2 siblings, 1 reply; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-16  4:50 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Implement the generic modify flow API to allow manipulations on
an arbitrary header field (as well as mark, metadata or tag) using
data from another field or a user-specified value.
This generic modify mechanism removes the necessity to implement
a separate RTE Flow action every time we need to modify a new packet
field in the future.

Supported operation are:
- set: copy data from source to destination.
- add: integer addition, stores the result in destination.
- sub: integer subtraction, stores the result in destination.

The field ID is used to specify the desired source/destination packet
field in order to simplify the API for various encapsulation models.
Specifying the packet field ID with the needed encapsulation level
is able to quickly get a packet field for any inner packet header.

Alternatively, the special ID (ITEM_START) can be used to point to
the very beginning of a packet. This ID in conjunction with the
offset parameter provides great flexibility to copy/modify any part of
a packet as needed.

The number of bits to use from a source as well as the offset can be
be specified to allow a partial copy or dividing a big packet field
into multiple small fields (e.g. copying 128 bits of IPv6 to 4 tags).

An immediate value (or pointer to it) can be specified instead of the
level and the offset for the special FIELD_VALUE ID (or FIELD_POINTER).
Can be used as a source only.

RFC: http://patches.dpdk.org/patch/85384/

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>

---
v1: Initialy RTE_FLOW_ACTION_TYPE_COPY_ITEM
v2: Renamed to RTE_FLOW_ACTION_TYPE_COPY_FIELD
v3: Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
v4: Fixed typos in documentation, renamed mov operation to set.
---
 doc/guides/prog_guide/rte_flow.rst     | 65 +++++++++++++++++++++
 doc/guides/rel_notes/release_21_02.rst |  8 +++
 lib/librte_ethdev/rte_flow.c           |  2 +
 lib/librte_ethdev/rte_flow.h           | 79 +++++++++++++++++++++++++-
 4 files changed, 153 insertions(+), 1 deletion(-)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 86b3444803..d959ca4a8c 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2766,6 +2766,71 @@ The behaviour of the shared action defined by ``action`` argument of type
    | no properties |
    +---------------+
 
+Action: ``MODIFY_FIELD``
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Modify ``dst`` field according to ``op`` selected (move, addition,
+subtraction) with ``width`` bits of data from ``src`` field.
+
+Any arbitrary header field (as well as mark, metadata or tag values)
+can be used as both source and destination fields as set by ``field``.
+The immediate value ``RTE_FLOW_FIELD_VALUE`` (or a pointer to it
+``RTE_FLOW_FIELD_POINTER``) is allowed as a source only.
+``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet.
+
+``op`` selects the operation to perform on a destination field.
+- ``set`` copies the data from ``src`` field to ``dst`` field.
+- ``add`` adds together ``dst`` and ``src`` and stores the result into ``dst``.
+- ``sub`` subtracts ``src`` from ``dst`` and stores the result into ``dst``
+
+``width`` defines a number of bits to use from ``src`` field.
+
+``level`` is used to access any packet field on any encapsulation level
+as well as any tag element in the tag array.
+- ``0`` means the default behaviour. Depending on the packet type, it can
+mean outermost, innermost or anything in between.
+- ``1`` requests access to the outermost packet encapsulation level.
+- ``2`` and subsequent values requests access to the specified packet
+encapsulation level, from outermost to innermost (lower to higher values).
+For the tag array ``level`` translates directly into the array index.
+
+``offset`` specifies the number of bits to skip from a field's start.
+That allows performing a partial copy of the needed part or to divide a big
+packet field into multiple smaller fields. Alternatively, ``offset`` allows
+going past the specified packet field boundary to copy a field to an
+arbitrary place in a packet, essentially providing a way to copy any part of
+a packet to any other part of it if supported by an underlying PMD driver.
+
+``value`` sets an immediate value to be used as a source or points to a
+location of the value in memory. It is used instead of ``level`` and ``offset``
+for ``RTE_FLOW_FIELD_VALUE`` and ``RTE_FLOW_FIELD_POINTER`` respectively.
+
+.. _table_rte_flow_action_modify_field:
+
+.. table:: MODIFY_FIELD
+
+   +-----------------------------------------+
+   | Field         | Value                   |
+   +===============+=========================+
+   | ``op``        | operation to perform    |
+   | ``dst``       | destination field       |
+   | ``src``       | source field            |
+   | ``width``     | number of bits to use   |
+   +---------------+-------------------------+
+
+.. _table_rte_flow_action_modify_data:
+
+.. table:: destination/source field definition
+
+   +--------------------------------------------------------------------------+
+   | Field         | Value                                                    |
+   +===============+==========================================================+
+   | ``field``     | ID: packet field, mark, meta, tag, immediate, pointer    |
+   | ``level``     | encapsulation level of a packet field or tag array index |
+   | ``offset``    | number of bits to skip at the beginning                  |
+   | ``value``     | immediate value or a pointer to this value               |
+   +---------------+----------------------------------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst
index c64294e7a6..5962c9f80b 100644
--- a/doc/guides/rel_notes/release_21_02.rst
+++ b/doc/guides/rel_notes/release_21_02.rst
@@ -55,6 +55,14 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added support of modify field action in the flow API.**
+
+  Added modify action support to perform various operations on
+  any arbitrary header field (as well as mark, metadata or tag values):
+  ``RTE_FLOW_ACTION_TYPE_MODIFY_FIELD``.
+  supported operations are: overwriting a field with the content from
+  another field, addition and subtraction using an immediate value.
+
 * **Updated Broadcom bnxt driver.**
 
   Updated the Broadcom bnxt driver with fixes and improvements, including:
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index a06f64c271..9dd051f3c2 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -176,6 +176,8 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
 	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
 	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
+	MK_FLOW_ACTION(MODIFY_FIELD,
+		       sizeof(struct rte_flow_action_modify_field)),
 	/**
 	 * Shared action represented as handle of type
 	 * (struct rte_flow_shared action *) stored in conf field (see
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 0977a78270..07c4d859c2 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2198,6 +2198,17 @@ enum rte_flow_action_type {
 	 * struct rte_flow_shared_action).
 	 */
 	RTE_FLOW_ACTION_TYPE_SHARED,
+
+	/**
+	 * Modify a packet header field, tag, mark or metadata.
+	 *
+	 * Allow the modification of an arbitrary header field via
+	 * set, add and sub operations or copying its content into
+	 * tag, meta or mark for future processing.
+	 *
+	 * See struct rte_flow_action_modify_field.
+	 */
+	RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,
 };
 
 /**
@@ -2777,7 +2788,6 @@ struct rte_flow_action_set_dscp {
 	uint8_t dscp;
 };
 
-
 /**
  * RTE_FLOW_ACTION_TYPE_SHARED
  *
@@ -2791,6 +2801,73 @@ struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+enum rte_flow_field_id {
+	RTE_FLOW_FIELD_START = 0,
+	RTE_FLOW_FIELD_MAC_DST,
+	RTE_FLOW_FIELD_MAC_SRC,
+	RTE_FLOW_FIELD_VLAN_TYPE,
+	RTE_FLOW_FIELD_VLAN_ID,
+	RTE_FLOW_FIELD_MAC_TYPE,
+	RTE_FLOW_FIELD_IPV4_DSCP,
+	RTE_FLOW_FIELD_IPV4_TTL,
+	RTE_FLOW_FIELD_IPV4_SRC,
+	RTE_FLOW_FIELD_IPV4_DST,
+	RTE_FLOW_FIELD_IPV6_HOPLIMIT,
+	RTE_FLOW_FIELD_IPV6_SRC,
+	RTE_FLOW_FIELD_IPV6_DST,
+	RTE_FLOW_FIELD_TCP_PORT_SRC,
+	RTE_FLOW_FIELD_TCP_PORT_DST,
+	RTE_FLOW_FIELD_TCP_SEQ_NUM,
+	RTE_FLOW_FIELD_TCP_ACK_NUM,
+	RTE_FLOW_FIELD_TCP_FLAGS,
+	RTE_FLOW_FIELD_UDP_PORT_SRC,
+	RTE_FLOW_FIELD_UDP_PORT_DST,
+	RTE_FLOW_FIELD_VXLAN_VNI,
+	RTE_FLOW_FIELD_GENEVE_VNI,
+	RTE_FLOW_FIELD_GTP_TEID,
+	RTE_FLOW_FIELD_TAG,
+	RTE_FLOW_FIELD_MARK,
+	RTE_FLOW_FIELD_META,
+	RTE_FLOW_FIELD_POINTER,
+	RTE_FLOW_FIELD_VALUE,
+};
+
+struct rte_flow_action_modify_data {
+	enum rte_flow_field_id field;
+	RTE_STD_C11
+	union {
+		struct {
+			uint32_t level;
+			uint32_t offset;
+		};
+		uint64_t value;
+	};
+};
+
+enum rte_flow_modify_op {
+	RTE_FLOW_MODIFY_SET = 0,
+	RTE_FLOW_MODIFY_ADD,
+	RTE_FLOW_MODIFY_SUB,
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
+ *
+ * Modifies a destination header field according to the specified
+ * operation. Another packet field can be used as a source as well
+ * as tag, mark, metadata or an immediate value or a pointer to it.
+ * Width is the number of bits used from the source item.
+ */
+struct rte_flow_action_modify_field {
+	enum rte_flow_modify_op operation;
+	struct rte_flow_action_modify_data dst;
+	struct rte_flow_action_modify_data src;
+	uint32_t width;
+};
+
 /* Mbuf dynamic field offset for metadata. */
 extern int32_t rte_flow_dynf_metadata_offs;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v7 2/2] app/testpmd: add support for modify field flow action
  2021-01-16  4:50           ` [dpdk-dev] [PATCH v7 0/2] generic modify rte flow action support Alexander Kozyrev
  2021-01-16  4:50             ` [dpdk-dev] [PATCH v7 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
@ 2021-01-16  4:50             ` Alexander Kozyrev
  2021-01-18 16:18             ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Alexander Kozyrev
  2 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-16  4:50 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Add support for the RTE_FLOW_ACTION_MODIFY_FIELD to the testpmd.
Implement CLI to create the modify_field action and supply all the
needed parameters to modify an arbitrary packet field (as well as
mark, tag or metadata) with data from another field or immediate
value.

Example of the flow is the following:
flow create 0 egress group 1 pattern eth / ipv4 / udp / end
  actions modify_field op set dst_type tag dst_level 2 dst_offset 8
          src_type gtp_teid src_level 0 src_offset 0 width 16 / end

This flow copies 16 bits from the second Tag in the Tags array
into the outermost GTP TEID packet header field. 8 bits of the
Tag are skipped as indicated by the dst_offset action parameter.

op, dst_type, src_type and width are the mandatory parameters to
specify. Levels and offset are 0 by default if they are not
overridden by a user. The operation can be set, add or sub.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>

---
v1: Initial implementation.
v2: Made dst_type, src_type and width only mandatory parameters.
v3: Reworked to accomodate API change from copy_field to modify_field.
v4: Renamed the mov operation to set.
---
 app/test-pmd/cmdline_flow.c | 246 ++++++++++++++++++++++++++++++++++++
 1 file changed, 246 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 585cab98b4..782caa8278 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -408,6 +408,19 @@ enum index {
 	ACTION_SAMPLE_INDEX_VALUE,
 	ACTION_SHARED,
 	SHARED_ACTION_ID2PTR,
+	ACTION_MODIFY_FIELD,
+	ACTION_MODIFY_FIELD_OP,
+	ACTION_MODIFY_FIELD_OP_VALUE,
+	ACTION_MODIFY_FIELD_DST_TYPE,
+	ACTION_MODIFY_FIELD_DST_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ACTION_MODIFY_FIELD_SRC_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -561,6 +574,22 @@ struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 
+static const char *const modify_field_ops[] = {
+	"set", "add", "sub", NULL
+};
+
+static const char *const modify_field_ids[] = {
+	"start", "mac_dst", "mac_src",
+	"vlan_type", "vlan_id", "mac_type",
+	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
+	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
+	"tcp_port_src", "tcp_port_dst",
+	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
+	"udp_port_src", "udp_port_dst",
+	"vxlan_vni", "geneve_vni", "gtp_teid",
+	"tag", "mark", "meta", "value", "pointer", NULL
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -1306,6 +1335,7 @@ static const enum index next_action[] = {
 	ACTION_AGE,
 	ACTION_SAMPLE,
 	ACTION_SHARED,
+	ACTION_MODIFY_FIELD,
 	ZERO,
 };
 
@@ -1556,6 +1586,21 @@ static const enum index next_action_sample[] = {
 	ZERO,
 };
 
+static const enum index action_modify_field_dst[] = {
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ZERO,
+};
+
+static const enum index action_modify_field_src[] = {
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -1638,6 +1683,14 @@ static int
 parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 				const char *str, unsigned int len, void *buf,
 				unsigned int size);
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1722,6 +1775,10 @@ static int comp_set_raw_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
 static int comp_set_sample_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_op(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_id(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -4037,6 +4094,103 @@ static const struct token token_list[] = {
 		.call = parse_vc_action_raw_decap_index,
 		.comp = comp_set_raw_index,
 	},
+	[ACTION_MODIFY_FIELD] = {
+		.name = "modify_field",
+		.help = "modify destination field with data from source field",
+		.priv = PRIV_ACTION(MODIFY_FIELD,
+			sizeof(struct rte_flow_action_modify_field)),
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_OP)),
+		.call = parse_vc,
+	},
+	[ACTION_MODIFY_FIELD_OP] = {
+		.name = "op",
+		.help = "operation type",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE),
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_OP_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_OP_VALUE] = {
+		.name = "{operation}",
+		.help = "operation type value",
+		.call = parse_vc_modify_field_op,
+		.comp = comp_set_modify_field_op,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE] = {
+		.name = "dst_type",
+		.help = "destination field type",
+		.next = NEXT(action_modify_field_dst,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE_VALUE] = {
+		.name = "{dst_type}",
+		.help = "destination field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_DST_LEVEL] = {
+		.name = "dst_level",
+		.help = "destination field level",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_OFFSET] = {
+		.name = "dst_offset",
+		.help = "destination field bit offset",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE] = {
+		.name = "src_type",
+		.help = "source field type",
+		.next = NEXT(action_modify_field_src,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE_VALUE] = {
+		.name = "{src_type}",
+		.help = "source field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_SRC_LEVEL] = {
+		.name = "src_level",
+		.help = "source field level",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_OFFSET] = {
+		.name = "src_offset",
+		.help = "source field bit offset",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_VALUE] = {
+		.name = "src_value",
+		.help = "source immediate value",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_WIDTH),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.value)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_WIDTH] = {
+		.name = "width",
+		.help = "number of bits to copy",
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					width)),
+		.call = parse_vc_conf,
+	},
 	/* Top level command. */
 	[SET] = {
 		.name = "set",
@@ -5960,6 +6114,62 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse operation for modify_field command. */
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_OP_VALUE)
+		return -1;
+	for (i = 0; modify_field_ops[i]; ++i)
+		if (!strcmp_partial(modify_field_ops[i], str, len))
+			break;
+	if (!modify_field_ops[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	action_modify_field->operation = (enum rte_flow_modify_op)i;
+	return len;
+}
+
+/** Parse id for modify_field command. */
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_DST_TYPE_VALUE &&
+		ctx->curr != ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)
+		return -1;
+	for (i = 0; modify_field_ids[i]; ++i)
+		if (!strcmp_partial(modify_field_ids[i], str, len))
+			break;
+	if (!modify_field_ids[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	if (ctx->curr == ACTION_MODIFY_FIELD_DST_TYPE_VALUE)
+		action_modify_field->dst.field = (enum rte_flow_field_id)i;
+	else
+		action_modify_field->src.field = (enum rte_flow_field_id)i;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -7029,6 +7239,42 @@ comp_set_sample_index(struct context *ctx, const struct token *token,
 	return nb;
 }
 
+/** Complete operation for modify_field command. */
+static int
+comp_set_modify_field_op(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ops[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ops[ent], size);
+	return -1;
+}
+
+/** Complete field id for modify_field command. */
+static int
+comp_set_modify_field_id(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ids[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ids[ent], size);
+	return -1;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/2] ethdev: introduce generic modify rte flow action
  2021-01-15 18:03           ` Ori Kam
@ 2021-01-17  9:23             ` Slava Ovsiienko
  0 siblings, 0 replies; 48+ messages in thread
From: Slava Ovsiienko @ 2021-01-17  9:23 UTC (permalink / raw)
  To: Ori Kam, Alexander Kozyrev, dev
  Cc: NBU-Contact-Thomas Monjalon, ferruh.yigit, andrew.rybchenko, jerinjacobk

> -----Original Message-----
> From: Ori Kam <orika@nvidia.com>
> Sent: Friday, January 15, 2021 20:04
> To: Alexander Kozyrev <akozyrev@nvidia.com>; dev@dpdk.org
> Cc: Slava Ovsiienko <viacheslavo@nvidia.com>; NBU-Contact-Thomas
> Monjalon <thomas@monjalon.net>; ferruh.yigit@intel.com;
> andrew.rybchenko@oktetlabs.ru; jerinjacobk@gmail.com
> Subject: RE: [PATCH v5 1/2] ethdev: introduce generic modify rte flow action
> 
> Hi Alexander,
> 
> Small inline, but I leave it to you if you want to change it.
> 
> > -----Original Message-----
> > From: Alexander Kozyrev <akozyrev@nvidia.com>
> > Sent: Friday, January 15, 2021 5:43 PM
> > Subject: [PATCH v5 1/2] ethdev: introduce generic modify rte flow
> > action
> >
> > Implement the generic modify flow API to allow manipulations on an
> > arbitrary header field (as well as mark, metadata or tag) using data
> > from another field or a user-specified value.
> >
> > This generic modify mechanism removes the necessity to implement a
> > separate RTE Flow action every time we need to modify a new packet
> > field in the future. A user-provided value can be used from a
> > specified packet field/tag/metadata/mark/memory location or directly
> >
>  provided by a user.
> >
> 
> [Snip]
> 
> > +
> > +enum rte_flow_modify_op {
> > +	RTE_FLOW_MODIFY_MOV = 0,
> > +	RTE_FLOW_MODIFY_ADD,
> > +	RTE_FLOW_MODIFY_SUB,
> > +};
> > +
> I think  mov is not the best option, since we the value in src stays I think copy
> or set will be better.
> If you change it feel free to add my ack.

MOV is quite common usage (in Assembly) to specify  exactly the operation
we are going to introduce.

And we are going to assign the destination both from field and some immediate
value provided. So, MOV in my opinion would be more relevant than COPY.

With best regards,
Slava

> 
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this structure may change without prior notice
> > + *
> > + * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
> > + *
> > + * Modifies a destination header field according to the specified
> > + * operation. Another packet field can be used as a source as well
> > + * as tag, mark, metadata or an immediate value or a pointer to it.
> > + * Width is the number of bits used from the source item.
> > + */
> > +struct rte_flow_action_modify_field {
> > +	enum rte_flow_modify_op operation;
> > +	struct rte_flow_action_modify_data dst;
> > +	struct rte_flow_action_modify_data src;
> > +	uint32_t width;
> > +};
> > +
> >  /* Mbuf dynamic field offset for metadata. */  extern int32_t
> > rte_flow_dynf_metadata_offs;
> >
> > --
> > 2.24.1
> 
> Acked-by: Ori Kam <orika@nvidia.com>
> Best,
> Ori

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v7 1/2] ethdev: introduce generic modify rte flow action
  2021-01-16  4:50             ` [dpdk-dev] [PATCH v7 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
@ 2021-01-17 23:15               ` Thomas Monjalon
  2021-01-18 16:03                 ` Alexander Kozyrev
  0 siblings, 1 reply; 48+ messages in thread
From: Thomas Monjalon @ 2021-01-17 23:15 UTC (permalink / raw)
  To: Alexander Kozyrev
  Cc: dev, viacheslavo, orika, ferruh.yigit, andrew.rybchenko, jerinjacobk

16/01/2021 05:50, Alexander Kozyrev:
> Implement the generic modify flow API to allow manipulations on
> an arbitrary header field (as well as mark, metadata or tag) using
> data from another field or a user-specified value.
> This generic modify mechanism removes the necessity to implement
> a separate RTE Flow action every time we need to modify a new packet
> field in the future.
> 
> Supported operation are:
> - set: copy data from source to destination.
> - add: integer addition, stores the result in destination.
> - sub: integer subtraction, stores the result in destination.
> 
> The field ID is used to specify the desired source/destination packet
> field in order to simplify the API for various encapsulation models.
> Specifying the packet field ID with the needed encapsulation level
> is able to quickly get a packet field for any inner packet header.
> 
> Alternatively, the special ID (ITEM_START) can be used to point to
> the very beginning of a packet. This ID in conjunction with the
> offset parameter provides great flexibility to copy/modify any part of
> a packet as needed.
> 
> The number of bits to use from a source as well as the offset can be
> be specified to allow a partial copy or dividing a big packet field
> into multiple small fields (e.g. copying 128 bits of IPv6 to 4 tags).
> 
> An immediate value (or pointer to it) can be specified instead of the
> level and the offset for the special FIELD_VALUE ID (or FIELD_POINTER).
> Can be used as a source only.
> 
> RFC: http://patches.dpdk.org/patch/85384/

You don't need to refer to the RFC in the commit message.

> Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> Acked-by: Ori Kam <orika@nvidia.com>
> 
> ---
> +Action: ``MODIFY_FIELD``
> +^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +Modify ``dst`` field according to ``op`` selected (move, addition,
> +subtraction) with ``width`` bits of data from ``src`` field.

"move" is changed to "set", right?

> +Any arbitrary header field (as well as mark, metadata or tag values)
> +can be used as both source and destination fields as set by ``field``.
> +The immediate value ``RTE_FLOW_FIELD_VALUE`` (or a pointer to it
> +``RTE_FLOW_FIELD_POINTER``) is allowed as a source only.
> +``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet.
> +
> +``op`` selects the operation to perform on a destination field.
> +- ``set`` copies the data from ``src`` field to ``dst`` field.
> +- ``add`` adds together ``dst`` and ``src`` and stores the result into ``dst``.
> +- ``sub`` subtracts ``src`` from ``dst`` and stores the result into ``dst``
> +
> +``width`` defines a number of bits to use from ``src`` field.
> +
> +``level`` is used to access any packet field on any encapsulation level
> +as well as any tag element in the tag array.
> +- ``0`` means the default behaviour. Depending on the packet type, it can
> +mean outermost, innermost or anything in between.

I feel the interpretation of the level 0 is driver-dependent?

> +- ``1`` requests access to the outermost packet encapsulation level.
> +- ``2`` and subsequent values requests access to the specified packet
> +encapsulation level, from outermost to innermost (lower to higher values).
> +For the tag array ``level`` translates directly into the array index.

You should define what is a tag array.

> +
> +``offset`` specifies the number of bits to skip from a field's start.
> +That allows performing a partial copy of the needed part or to divide a big
> +packet field into multiple smaller fields. Alternatively, ``offset`` allows
> +going past the specified packet field boundary to copy a field to an
> +arbitrary place in a packet, essentially providing a way to copy any part of
> +a packet to any other part of it if supported by an underlying PMD driver.

All features of this specification require PMD support,
so I think it is useless to mention here.

> +
> +``value`` sets an immediate value to be used as a source or points to a
> +location of the value in memory. It is used instead of ``level`` and ``offset``
> +for ``RTE_FLOW_FIELD_VALUE`` and ``RTE_FLOW_FIELD_POINTER`` respectively.
> +
> +.. _table_rte_flow_action_modify_field:
> +
> +.. table:: MODIFY_FIELD
> +
> +   +-----------------------------------------+
> +   | Field         | Value                   |
> +   +===============+=========================+
> +   | ``op``        | operation to perform    |
> +   | ``dst``       | destination field       |
> +   | ``src``       | source field            |
> +   | ``width``     | number of bits to use   |
> +   +---------------+-------------------------+
> +
> +.. _table_rte_flow_action_modify_data:
> +
> +.. table:: destination/source field definition
> +
> +   +--------------------------------------------------------------------------+
> +   | Field         | Value                                                    |
> +   +===============+==========================================================+
> +   | ``field``     | ID: packet field, mark, meta, tag, immediate, pointer    |
> +   | ``level``     | encapsulation level of a packet field or tag array index |
> +   | ``offset``    | number of bits to skip at the beginning                  |
> +   | ``value``     | immediate value or a pointer to this value               |
> +   +---------------+----------------------------------------------------------+

I know the whole rte_flow guide has this kind of table,
but really it looks like doxygen and can be skipped here.

If really this redundant info is required, it should be RST definition lists,
not tables.

[...]

In my opinion, the most important info is in the doxygen comments.

Please add a doxygen comment for this enum.

> +enum rte_flow_field_id {
> +	RTE_FLOW_FIELD_START = 0,

Please add a doxygen comment for the value RTE_FLOW_FIELD_START.

> +	RTE_FLOW_FIELD_MAC_DST,
> +	RTE_FLOW_FIELD_MAC_SRC,
> +	RTE_FLOW_FIELD_VLAN_TYPE,
> +	RTE_FLOW_FIELD_VLAN_ID,
> +	RTE_FLOW_FIELD_MAC_TYPE,
> +	RTE_FLOW_FIELD_IPV4_DSCP,
> +	RTE_FLOW_FIELD_IPV4_TTL,
> +	RTE_FLOW_FIELD_IPV4_SRC,
> +	RTE_FLOW_FIELD_IPV4_DST,
> +	RTE_FLOW_FIELD_IPV6_HOPLIMIT,
> +	RTE_FLOW_FIELD_IPV6_SRC,
> +	RTE_FLOW_FIELD_IPV6_DST,
> +	RTE_FLOW_FIELD_TCP_PORT_SRC,
> +	RTE_FLOW_FIELD_TCP_PORT_DST,
> +	RTE_FLOW_FIELD_TCP_SEQ_NUM,
> +	RTE_FLOW_FIELD_TCP_ACK_NUM,
> +	RTE_FLOW_FIELD_TCP_FLAGS,
> +	RTE_FLOW_FIELD_UDP_PORT_SRC,
> +	RTE_FLOW_FIELD_UDP_PORT_DST,
> +	RTE_FLOW_FIELD_VXLAN_VNI,
> +	RTE_FLOW_FIELD_GENEVE_VNI,
> +	RTE_FLOW_FIELD_GTP_TEID,
> +	RTE_FLOW_FIELD_TAG,
> +	RTE_FLOW_FIELD_MARK,
> +	RTE_FLOW_FIELD_META,
> +	RTE_FLOW_FIELD_POINTER,

Please add a doxygen comment for the value RTE_FLOW_FIELD_POINTER.

> +	RTE_FLOW_FIELD_VALUE,

Please add a doxygen comment for the value RTE_FLOW_FIELD_VALUE.

> +struct rte_flow_action_modify_data {
> +	enum rte_flow_field_id field;
> +	RTE_STD_C11
> +	union {
> +		struct {
> +			uint32_t level;
> +			uint32_t offset;
> +		};
> +		uint64_t value;
> +	};
> +};

Please add doxygen for this struct and fields.

> +
> +enum rte_flow_modify_op {
> +	RTE_FLOW_MODIFY_SET = 0,
> +	RTE_FLOW_MODIFY_ADD,
> +	RTE_FLOW_MODIFY_SUB,
> +};

Please add doxygen for this enum.

> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this structure may change without prior notice
> + *
> + * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
> + *
> + * Modifies a destination header field according to the specified
> + * operation. Another packet field can be used as a source as well
> + * as tag, mark, metadata or an immediate value or a pointer to it.
> + * Width is the number of bits used from the source item.

width should be documented below as other fields.

> + */
> +struct rte_flow_action_modify_field {
> +	enum rte_flow_modify_op operation;
> +	struct rte_flow_action_modify_data dst;
> +	struct rte_flow_action_modify_data src;
> +	uint32_t width;
> +};




^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v7 1/2] ethdev: introduce generic modify rte flow action
  2021-01-17 23:15               ` Thomas Monjalon
@ 2021-01-18 16:03                 ` Alexander Kozyrev
  0 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-18 16:03 UTC (permalink / raw)
  To: NBU-Contact-Thomas Monjalon
  Cc: dev, Slava Ovsiienko, Ori Kam, ferruh.yigit, andrew.rybchenko,
	jerinjacobk

> From: Thomas Monjalon <thomas@monjalon.net> on Sunday, January 17, 2021 18:16
> 16/01/2021 05:50, Alexander Kozyrev:
> > Implement the generic modify flow API to allow manipulations on
> > an arbitrary header field (as well as mark, metadata or tag) using
> > data from another field or a user-specified value.
> > This generic modify mechanism removes the necessity to implement
> > a separate RTE Flow action every time we need to modify a new packet
> > field in the future.
> >
> > Supported operation are:
> > - set: copy data from source to destination.
> > - add: integer addition, stores the result in destination.
> > - sub: integer subtraction, stores the result in destination.
> >
> > The field ID is used to specify the desired source/destination packet
> > field in order to simplify the API for various encapsulation models.
> > Specifying the packet field ID with the needed encapsulation level
> > is able to quickly get a packet field for any inner packet header.
> >
> > Alternatively, the special ID (ITEM_START) can be used to point to
> > the very beginning of a packet. This ID in conjunction with the
> > offset parameter provides great flexibility to copy/modify any part of
> > a packet as needed.
> >
> > The number of bits to use from a source as well as the offset can be
> > be specified to allow a partial copy or dividing a big packet field
> > into multiple small fields (e.g. copying 128 bits of IPv6 to 4 tags).
> >
> > An immediate value (or pointer to it) can be specified instead of the
> > level and the offset for the special FIELD_VALUE ID (or FIELD_POINTER).
> > Can be used as a source only.
> >
> > RFC:
> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpatch
> es.dpdk.org%2Fpatch%2F85384%2F&amp;data=04%7C01%7Cakozyrev%40nv
> idia.com%7Ce20d2c38372b4062420d08d8bb3dd549%7C43083d15727340c1b7d
> b39efd9ccc17a%7C0%7C0%7C637465221537183554%7CUnknown%7CTWFpb
> GZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI
> 6Mn0%3D%7C1000&amp;sdata=gWEdmyAabnCCmeFyi%2FvHs0aheMmWNx
> IyR%2BTC96O3Yck%3D&amp;reserved=0
> 
> You don't need to refer to the RFC in the commit message.
Removing link to it.

> 
> > Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
> > Acked-by: Ori Kam <orika@nvidia.com>
> >
> > ---
> > +Action: ``MODIFY_FIELD``
> > +^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +Modify ``dst`` field according to ``op`` selected (move, addition,
> > +subtraction) with ``width`` bits of data from ``src`` field.
> 
> "move" is changed to "set", right?
Right, thanks for catching this.

> 
> > +Any arbitrary header field (as well as mark, metadata or tag values)
> > +can be used as both source and destination fields as set by ``field``.
> > +The immediate value ``RTE_FLOW_FIELD_VALUE`` (or a pointer to it
> > +``RTE_FLOW_FIELD_POINTER``) is allowed as a source only.
> > +``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet.
> > +
> > +``op`` selects the operation to perform on a destination field.
> > +- ``set`` copies the data from ``src`` field to ``dst`` field.
> > +- ``add`` adds together ``dst`` and ``src`` and stores the result into ``dst``.
> > +- ``sub`` subtracts ``src`` from ``dst`` and stores the result into ``dst``
> > +
> > +``width`` defines a number of bits to use from ``src`` field.
> > +
> > +``level`` is used to access any packet field on any encapsulation level
> > +as well as any tag element in the tag array.
> > +- ``0`` means the default behaviour. Depending on the packet type, it can
> > +mean outermost, innermost or anything in between.
> 
> I feel the interpretation of the level 0 is driver-dependent?
It is driver-dependent, the behavior is the same as in case of RSS.

> > +- ``1`` requests access to the outermost packet encapsulation level.
> > +- ``2`` and subsequent values requests access to the specified packet
> > +encapsulation level, from outermost to innermost (lower to higher
> values).
> > +For the tag array ``level`` translates directly into the array index.
> 
> You should define what is a tag array.
Ok, but it is defined already in RTE_FLOW_ACTION_TYPE_SET_TAG action.

> > +
> > +``offset`` specifies the number of bits to skip from a field's start.
> > +That allows performing a partial copy of the needed part or to divide a big
> > +packet field into multiple smaller fields. Alternatively, ``offset`` allows
> > +going past the specified packet field boundary to copy a field to an
> > +arbitrary place in a packet, essentially providing a way to copy any part of
> > +a packet to any other part of it if supported by an underlying PMD driver.
> 
> All features of this specification require PMD support,
> so I think it is useless to mention here.
Removing.
 
> > +
> > +``value`` sets an immediate value to be used as a source or points to a
> > +location of the value in memory. It is used instead of ``level`` and ``offset``
> > +for ``RTE_FLOW_FIELD_VALUE`` and ``RTE_FLOW_FIELD_POINTER``
> respectively.
> > +
> > +.. _table_rte_flow_action_modify_field:
> > +
> > +.. table:: MODIFY_FIELD
> > +
> > +   +-----------------------------------------+
> > +   | Field         | Value                   |
> > +   +===============+=========================+
> > +   | ``op``        | operation to perform    |
> > +   | ``dst``       | destination field       |
> > +   | ``src``       | source field            |
> > +   | ``width``     | number of bits to use   |
> > +   +---------------+-------------------------+
> > +
> > +.. _table_rte_flow_action_modify_data:
> > +
> > +.. table:: destination/source field definition
> > +
> > +   +--------------------------------------------------------------------------+
> > +   | Field         | Value                                                    |
> > +
> +===============+=========================================
> =================+
> > +   | ``field``     | ID: packet field, mark, meta, tag, immediate, pointer    |
> > +   | ``level``     | encapsulation level of a packet field or tag array index |
> > +   | ``offset``    | number of bits to skip at the beginning                  |
> > +   | ``value``     | immediate value or a pointer to this value               |
> > +   +---------------+----------------------------------------------------------+
> 
> I know the whole rte_flow guide has this kind of table,
> but really it looks like doxygen and can be skipped here.
> 
> If really this redundant info is required, it should be RST definition lists,
> not tables.
I would keep these tables for the sake of consistency of the rte_flow guide.

> [...]
> 
> In my opinion, the most important info is in the doxygen comments.
Agree, adding them for all the structures/fields mentioned below.

> Please add a doxygen comment for this enum.
> 
> > +enum rte_flow_field_id {
> > +	RTE_FLOW_FIELD_START = 0,
> 
> Please add a doxygen comment for the value RTE_FLOW_FIELD_START.
> 
> > +	RTE_FLOW_FIELD_MAC_DST,
> > +	RTE_FLOW_FIELD_MAC_SRC,
> > +	RTE_FLOW_FIELD_VLAN_TYPE,
> > +	RTE_FLOW_FIELD_VLAN_ID,
> > +	RTE_FLOW_FIELD_MAC_TYPE,
> > +	RTE_FLOW_FIELD_IPV4_DSCP,
> > +	RTE_FLOW_FIELD_IPV4_TTL,
> > +	RTE_FLOW_FIELD_IPV4_SRC,
> > +	RTE_FLOW_FIELD_IPV4_DST,
> > +	RTE_FLOW_FIELD_IPV6_HOPLIMIT,
> > +	RTE_FLOW_FIELD_IPV6_SRC,
> > +	RTE_FLOW_FIELD_IPV6_DST,
> > +	RTE_FLOW_FIELD_TCP_PORT_SRC,
> > +	RTE_FLOW_FIELD_TCP_PORT_DST,
> > +	RTE_FLOW_FIELD_TCP_SEQ_NUM,
> > +	RTE_FLOW_FIELD_TCP_ACK_NUM,
> > +	RTE_FLOW_FIELD_TCP_FLAGS,
> > +	RTE_FLOW_FIELD_UDP_PORT_SRC,
> > +	RTE_FLOW_FIELD_UDP_PORT_DST,
> > +	RTE_FLOW_FIELD_VXLAN_VNI,
> > +	RTE_FLOW_FIELD_GENEVE_VNI,
> > +	RTE_FLOW_FIELD_GTP_TEID,
> > +	RTE_FLOW_FIELD_TAG,
> > +	RTE_FLOW_FIELD_MARK,
> > +	RTE_FLOW_FIELD_META,
> > +	RTE_FLOW_FIELD_POINTER,
> 
> Please add a doxygen comment for the value RTE_FLOW_FIELD_POINTER.
> 
> > +	RTE_FLOW_FIELD_VALUE,
> 
> Please add a doxygen comment for the value RTE_FLOW_FIELD_VALUE.
> 
> > +struct rte_flow_action_modify_data {
> > +	enum rte_flow_field_id field;
> > +	RTE_STD_C11
> > +	union {
> > +		struct {
> > +			uint32_t level;
> > +			uint32_t offset;
> > +		};
> > +		uint64_t value;
> > +	};
> > +};
> 
> Please add doxygen for this struct and fields.
> 
> > +
> > +enum rte_flow_modify_op {
> > +	RTE_FLOW_MODIFY_SET = 0,
> > +	RTE_FLOW_MODIFY_ADD,
> > +	RTE_FLOW_MODIFY_SUB,
> > +};
> 
> Please add doxygen for this enum.
> 
> > +
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this structure may change without prior notice
> > + *
> > + * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
> > + *
> > + * Modifies a destination header field according to the specified
> > + * operation. Another packet field can be used as a source as well
> > + * as tag, mark, metadata or an immediate value or a pointer to it.
> > + * Width is the number of bits used from the source item.
> 
> width should be documented below as other fields.
> 
> > + */
> > +struct rte_flow_action_modify_field {
> > +	enum rte_flow_modify_op operation;
> > +	struct rte_flow_action_modify_data dst;
> > +	struct rte_flow_action_modify_data src;
> > +	uint32_t width;
> > +};
> 
> 


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support
  2021-01-16  4:50           ` [dpdk-dev] [PATCH v7 0/2] generic modify rte flow action support Alexander Kozyrev
  2021-01-16  4:50             ` [dpdk-dev] [PATCH v7 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
  2021-01-16  4:50             ` [dpdk-dev] [PATCH v7 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
@ 2021-01-18 16:18             ` Alexander Kozyrev
  2021-01-18 16:18               ` [dpdk-dev] [PATCH v8 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
                                 ` (3 more replies)
  2 siblings, 4 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-18 16:18 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Implement a generic modify rte flow API as described in RFC:
http://patches.dpdk.org/patch/85384/

This API allows modifying a destination header field with data from
a source header field. Number of bits to use from the source is specified.
Tag, Mark or Metadata can also be used as a source/destination to allow
saving/overwriting an arbitrary header field with a user-specified value.
Alternatively, an immediate value can be provided by a user as a source.

Outermost/innermost packet fields (and Tag array elements) are
accessible via the level parameter to facilitate the modification
of encapsulated packet header fields. The offset parameter provides
the flexibility to copy/set any part of a packet starting the
specified packet header field.

Example of RTE_FLOW_ACTION_TYPE_MODIFY_FIELD implementation for MLX5:
https://patchwork.dpdk.org/patch/86736/

---
v1: https://patchwork.dpdk.org/patch/86173/
Initial design.
v2: https://patchwork.dpdk.org/cover/86369/
Added testpmd support.
v3: https://patchwork.dpdk.org/cover/86442/
Made dst_type, src_type and width only mandatory parameters.
v4: https://patchwork.dpdk.org/cover/86488/
Renamed action to RTE_FLOW_ACTION_TYPE_COPY_FIELD.
v5: https://patchwork.dpdk.org/cover/86705/
Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD.
v6: https://patchwork.dpdk.org/cover/86715/
Fixed typos in documentation.
v7: https://patchwork.dpdk.org/cover/86718/
Fixed warnings.
v8:
Added doxygen comments.

Alexander Kozyrev (2):
  ethdev: introduce generic modify rte flow action
  app/testpmd: add support for modify field flow action

 app/test-pmd/cmdline_flow.c            | 246 +++++++++++++++++++++++++
 doc/guides/prog_guide/rte_flow.rst     |  66 +++++++
 doc/guides/rel_notes/release_21_02.rst |   8 +
 lib/librte_ethdev/rte_flow.c           |   2 +
 lib/librte_ethdev/rte_flow.h           |  87 ++++++++-
 5 files changed, 408 insertions(+), 1 deletion(-)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v8 1/2] ethdev: introduce generic modify rte flow action
  2021-01-18 16:18             ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Alexander Kozyrev
@ 2021-01-18 16:18               ` Alexander Kozyrev
  2021-01-18 17:51                 ` Thomas Monjalon
  2021-01-18 16:18               ` [dpdk-dev] [PATCH v8 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
                                 ` (2 subsequent siblings)
  3 siblings, 1 reply; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-18 16:18 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Implement the generic modify flow API to allow manipulations on
an arbitrary header field (as well as mark, metadata or tag) using
data from another field or a user-specified value.
This generic modify mechanism removes the necessity to implement
a separate RTE Flow action every time we need to modify a new packet
field in the future.

Supported operation are:
- set: copy data from source to destination.
- add: integer addition, stores the result in destination.
- sub: integer subtraction, stores the result in destination.

The field ID is used to specify the desired source/destination packet
field in order to simplify the API for various encapsulation models.
Specifying the packet field ID with the needed encapsulation level
is able to quickly get a packet field for any inner packet header.

Alternatively, the special ID (ITEM_START) can be used to point to
the very beginning of a packet. This ID in conjunction with the
offset parameter provides great flexibility to copy/modify any part of
a packet as needed.

The number of bits to use from a source as well as the offset can be
be specified to allow a partial copy or dividing a big packet field
into multiple small fields (e.g. copying 128 bits of IPv6 to 4 tags).

An immediate value (or a pointer to it) can be specified instead of the
level and the offset for the special FIELD_VALUE ID (or FIELD_POINTER).
Can be used as a source only.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>

---
v1: Initialy RTE_FLOW_ACTION_TYPE_COPY_ITEM
v2: Renamed to RTE_FLOW_ACTION_TYPE_COPY_FIELD
v3: Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
v4: Fixed typos in documentation, renamed mov operation to set
v5: Added doxygen comments
---
 doc/guides/prog_guide/rte_flow.rst     | 66 +++++++++++++++++++
 doc/guides/rel_notes/release_21_02.rst |  8 +++
 lib/librte_ethdev/rte_flow.c           |  2 +
 lib/librte_ethdev/rte_flow.h           | 87 +++++++++++++++++++++++++-
 4 files changed, 162 insertions(+), 1 deletion(-)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 86b3444803..0b8c243fe1 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2766,6 +2766,72 @@ The behaviour of the shared action defined by ``action`` argument of type
    | no properties |
    +---------------+
 
+Action: ``MODIFY_FIELD``
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Modify ``dst`` field according to ``op`` selected (set, addition,
+subtraction) with ``width`` bits of data from ``src`` field.
+
+Any arbitrary header field (as well as mark, metadata or tag values)
+can be used as both source and destination fields as set by ``field``.
+The immediate value ``RTE_FLOW_FIELD_VALUE`` (or a pointer to it
+``RTE_FLOW_FIELD_POINTER``) is allowed as a source only.
+``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet.
+
+``op`` selects the operation to perform on a destination field.
+- ``set`` copies the data from ``src`` field to ``dst`` field.
+- ``add`` adds together ``dst`` and ``src`` and stores the result into ``dst``.
+- ``sub`` subtracts ``src`` from ``dst`` and stores the result into ``dst``
+
+``width`` defines a number of bits to use from ``src`` field.
+
+``level`` is used to access any packet field on any encapsulation level
+as well as any tag element in the tag array.
+- ``0`` means the default behaviour. Depending on the packet type, it can
+mean outermost, innermost or anything in between.
+- ``1`` requests access to the outermost packet encapsulation level.
+- ``2`` and subsequent values requests access to the specified packet
+encapsulation level, from outermost to innermost (lower to higher values).
+For the tag array (in case of multiple tags are supported and present)
+``level`` translates directly into the array index.
+
+``offset`` specifies the number of bits to skip from a field's start.
+That allows performing a partial copy of the needed part or to divide a big
+packet field into multiple smaller fields. Alternatively, ``offset`` allows
+going past the specified packet field boundary to copy a field to an
+arbitrary place in a packet, essentially providing a way to copy any part of
+a packet to any other part of it.
+
+``value`` sets an immediate value to be used as a source or points to a
+location of the value in memory. It is used instead of ``level`` and ``offset``
+for ``RTE_FLOW_FIELD_VALUE`` and ``RTE_FLOW_FIELD_POINTER`` respectively.
+
+.. _table_rte_flow_action_modify_field:
+
+.. table:: MODIFY_FIELD
+
+   +-----------------------------------------+
+   | Field         | Value                   |
+   +===============+=========================+
+   | ``op``        | operation to perform    |
+   | ``dst``       | destination field       |
+   | ``src``       | source field            |
+   | ``width``     | number of bits to use   |
+   +---------------+-------------------------+
+
+.. _table_rte_flow_action_modify_data:
+
+.. table:: destination/source field definition
+
+   +--------------------------------------------------------------------------+
+   | Field         | Value                                                    |
+   +===============+==========================================================+
+   | ``field``     | ID: packet field, mark, meta, tag, immediate, pointer    |
+   | ``level``     | encapsulation level of a packet field or tag array index |
+   | ``offset``    | number of bits to skip at the beginning                  |
+   | ``value``     | immediate value or a pointer to this value               |
+   +---------------+----------------------------------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst
index 3bb0b9a9ed..bb3cccd2e3 100644
--- a/doc/guides/rel_notes/release_21_02.rst
+++ b/doc/guides/rel_notes/release_21_02.rst
@@ -55,6 +55,14 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added support of modify field action in the flow API.**
+
+  Added modify action support to perform various operations on
+  any arbitrary header field (as well as mark, metadata or tag values):
+  ``RTE_FLOW_ACTION_TYPE_MODIFY_FIELD``.
+  supported operations are: overwriting a field with the content from
+  another field, addition and subtraction using an immediate value.
+
 * **Updated Broadcom bnxt driver.**
 
   Updated the Broadcom bnxt driver with fixes and improvements, including:
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index a06f64c271..9dd051f3c2 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -176,6 +176,8 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
 	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
 	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
+	MK_FLOW_ACTION(MODIFY_FIELD,
+		       sizeof(struct rte_flow_action_modify_field)),
 	/**
 	 * Shared action represented as handle of type
 	 * (struct rte_flow_shared action *) stored in conf field (see
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 0977a78270..0e1c7aa4ae 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2198,6 +2198,17 @@ enum rte_flow_action_type {
 	 * struct rte_flow_shared_action).
 	 */
 	RTE_FLOW_ACTION_TYPE_SHARED,
+
+	/**
+	 * Modify a packet header field, tag, mark or metadata.
+	 *
+	 * Allow the modification of an arbitrary header field via
+	 * set, add and sub operations or copying its content into
+	 * tag, meta or mark for future processing.
+	 *
+	 * See struct rte_flow_action_modify_field.
+	 */
+	RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,
 };
 
 /**
@@ -2777,7 +2788,6 @@ struct rte_flow_action_set_dscp {
 	uint8_t dscp;
 };
 
-
 /**
  * RTE_FLOW_ACTION_TYPE_SHARED
  *
@@ -2791,6 +2801,81 @@ struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+/**
+ * Field IDs for MODIFY_FIELD action.
+ */
+enum rte_flow_field_id {
+	RTE_FLOW_FIELD_START = 0, /**< Start of a packet */
+	RTE_FLOW_FIELD_MAC_DST,
+	RTE_FLOW_FIELD_MAC_SRC,
+	RTE_FLOW_FIELD_VLAN_TYPE,
+	RTE_FLOW_FIELD_VLAN_ID,
+	RTE_FLOW_FIELD_MAC_TYPE,
+	RTE_FLOW_FIELD_IPV4_DSCP,
+	RTE_FLOW_FIELD_IPV4_TTL,
+	RTE_FLOW_FIELD_IPV4_SRC,
+	RTE_FLOW_FIELD_IPV4_DST,
+	RTE_FLOW_FIELD_IPV6_HOPLIMIT,
+	RTE_FLOW_FIELD_IPV6_SRC,
+	RTE_FLOW_FIELD_IPV6_DST,
+	RTE_FLOW_FIELD_TCP_PORT_SRC,
+	RTE_FLOW_FIELD_TCP_PORT_DST,
+	RTE_FLOW_FIELD_TCP_SEQ_NUM,
+	RTE_FLOW_FIELD_TCP_ACK_NUM,
+	RTE_FLOW_FIELD_TCP_FLAGS,
+	RTE_FLOW_FIELD_UDP_PORT_SRC,
+	RTE_FLOW_FIELD_UDP_PORT_DST,
+	RTE_FLOW_FIELD_VXLAN_VNI,
+	RTE_FLOW_FIELD_GENEVE_VNI,
+	RTE_FLOW_FIELD_GTP_TEID,
+	RTE_FLOW_FIELD_TAG,
+	RTE_FLOW_FIELD_MARK,
+	RTE_FLOW_FIELD_META,
+	RTE_FLOW_FIELD_POINTER, /**< Memory pointer to immediate value */
+	RTE_FLOW_FIELD_VALUE,   /**< Immediate value */
+};
+
+/**
+ * Field description for MODIFY_FIELD action.
+ */
+struct rte_flow_action_modify_data {
+	enum rte_flow_field_id field; /**< Field ID */
+	RTE_STD_C11
+	union {
+		struct {
+			uint32_t level; /**< Encapsulation level or tag index */
+			uint32_t offset; /**< Number of bits to skip from src */
+		};
+		uint64_t value; /**< Immediate value or memory address of it */
+	};
+};
+
+/**
+ * Operation types for MODIFY_FIELD action.
+ */
+enum rte_flow_modify_op {
+	RTE_FLOW_MODIFY_SET = 0, /**< Set a new value */
+	RTE_FLOW_MODIFY_ADD,     /**< Add a value to a field  */
+	RTE_FLOW_MODIFY_SUB,     /**< Subtract a value from a field */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
+ *
+ * Modifies a destination header field according to the specified
+ * operation. Another packet field can be used as a source as well
+ * as tag, mark, metadata, immediate value or a pointer to it.
+ */
+struct rte_flow_action_modify_field {
+	enum rte_flow_modify_op operation; /**< Operation to perform on dst*/
+	struct rte_flow_action_modify_data dst; /**< Destination field */
+	struct rte_flow_action_modify_data src; /**< Source field */
+	uint32_t width; /**< Number of bits to use from a source field */
+};
+
 /* Mbuf dynamic field offset for metadata. */
 extern int32_t rte_flow_dynf_metadata_offs;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v8 2/2] app/testpmd: add support for modify field flow action
  2021-01-18 16:18             ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Alexander Kozyrev
  2021-01-18 16:18               ` [dpdk-dev] [PATCH v8 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
@ 2021-01-18 16:18               ` Alexander Kozyrev
  2021-01-18 20:05               ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Ajit Khaparde
  2021-01-18 21:40               ` [dpdk-dev] [PATCH v9 " Alexander Kozyrev
  3 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-18 16:18 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko, jerinjacobk

Add support for the RTE_FLOW_ACTION_MODIFY_FIELD to the testpmd.
Implement CLI to create the modify_field action and supply all the
needed parameters to modify an arbitrary packet field (as well as
mark, tag or metadata) with data from another field or immediate
value.

Example of the flow is the following:
flow create 0 egress group 1 pattern eth / ipv4 / udp / end
  actions modify_field op set dst_type tag dst_level 2 dst_offset 8
          src_type gtp_teid src_level 0 src_offset 0 width 16 / end

This flow copies 16 bits from the second Tag in the Tags array
into the outermost GTP TEID packet header field. 8 bits of the
Tag are skipped as indicated by the dst_offset action parameter.

op, dst_type, src_type and width are the mandatory parameters to
specify. Levels and offset are 0 by default if they are not
overridden by a user. The operation can be set, add or sub.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>

---
v1: Initial implementation.
v2: Made dst_type, src_type and width only mandatory parameters.
v3: Reworked to accomodate API change from copy_field to modify_field.
v4: Renamed the mov operation to set.
---
 app/test-pmd/cmdline_flow.c | 246 ++++++++++++++++++++++++++++++++++++
 1 file changed, 246 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 37b10e61bf..aa5ccbbcd7 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -408,6 +408,19 @@ enum index {
 	ACTION_SAMPLE_INDEX_VALUE,
 	ACTION_SHARED,
 	SHARED_ACTION_ID2PTR,
+	ACTION_MODIFY_FIELD,
+	ACTION_MODIFY_FIELD_OP,
+	ACTION_MODIFY_FIELD_OP_VALUE,
+	ACTION_MODIFY_FIELD_DST_TYPE,
+	ACTION_MODIFY_FIELD_DST_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ACTION_MODIFY_FIELD_SRC_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -561,6 +574,22 @@ struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 
+static const char *const modify_field_ops[] = {
+	"set", "add", "sub", NULL
+};
+
+static const char *const modify_field_ids[] = {
+	"start", "mac_dst", "mac_src",
+	"vlan_type", "vlan_id", "mac_type",
+	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
+	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
+	"tcp_port_src", "tcp_port_dst",
+	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
+	"udp_port_src", "udp_port_dst",
+	"vxlan_vni", "geneve_vni", "gtp_teid",
+	"tag", "mark", "meta", "pointer", "value", NULL
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -1306,6 +1335,7 @@ static const enum index next_action[] = {
 	ACTION_AGE,
 	ACTION_SAMPLE,
 	ACTION_SHARED,
+	ACTION_MODIFY_FIELD,
 	ZERO,
 };
 
@@ -1556,6 +1586,21 @@ static const enum index next_action_sample[] = {
 	ZERO,
 };
 
+static const enum index action_modify_field_dst[] = {
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ZERO,
+};
+
+static const enum index action_modify_field_src[] = {
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -1638,6 +1683,14 @@ static int
 parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 				const char *str, unsigned int len, void *buf,
 				unsigned int size);
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1722,6 +1775,10 @@ static int comp_set_raw_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
 static int comp_set_sample_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_op(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_id(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -4037,6 +4094,103 @@ static const struct token token_list[] = {
 		.call = parse_vc_action_raw_decap_index,
 		.comp = comp_set_raw_index,
 	},
+	[ACTION_MODIFY_FIELD] = {
+		.name = "modify_field",
+		.help = "modify destination field with data from source field",
+		.priv = PRIV_ACTION(MODIFY_FIELD,
+			sizeof(struct rte_flow_action_modify_field)),
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_OP)),
+		.call = parse_vc,
+	},
+	[ACTION_MODIFY_FIELD_OP] = {
+		.name = "op",
+		.help = "operation type",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE),
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_OP_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_OP_VALUE] = {
+		.name = "{operation}",
+		.help = "operation type value",
+		.call = parse_vc_modify_field_op,
+		.comp = comp_set_modify_field_op,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE] = {
+		.name = "dst_type",
+		.help = "destination field type",
+		.next = NEXT(action_modify_field_dst,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE_VALUE] = {
+		.name = "{dst_type}",
+		.help = "destination field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_DST_LEVEL] = {
+		.name = "dst_level",
+		.help = "destination field level",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_OFFSET] = {
+		.name = "dst_offset",
+		.help = "destination field bit offset",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE] = {
+		.name = "src_type",
+		.help = "source field type",
+		.next = NEXT(action_modify_field_src,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE_VALUE] = {
+		.name = "{src_type}",
+		.help = "source field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_SRC_LEVEL] = {
+		.name = "src_level",
+		.help = "source field level",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_OFFSET] = {
+		.name = "src_offset",
+		.help = "source field bit offset",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_VALUE] = {
+		.name = "src_value",
+		.help = "source immediate value",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_WIDTH),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.value)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_WIDTH] = {
+		.name = "width",
+		.help = "number of bits to copy",
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					width)),
+		.call = parse_vc_conf,
+	},
 	/* Top level command. */
 	[SET] = {
 		.name = "set",
@@ -5960,6 +6114,62 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse operation for modify_field command. */
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_OP_VALUE)
+		return -1;
+	for (i = 0; modify_field_ops[i]; ++i)
+		if (!strcmp_partial(modify_field_ops[i], str, len))
+			break;
+	if (!modify_field_ops[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	action_modify_field->operation = (enum rte_flow_modify_op)i;
+	return len;
+}
+
+/** Parse id for modify_field command. */
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_DST_TYPE_VALUE &&
+		ctx->curr != ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)
+		return -1;
+	for (i = 0; modify_field_ids[i]; ++i)
+		if (!strcmp_partial(modify_field_ids[i], str, len))
+			break;
+	if (!modify_field_ids[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	if (ctx->curr == ACTION_MODIFY_FIELD_DST_TYPE_VALUE)
+		action_modify_field->dst.field = (enum rte_flow_field_id)i;
+	else
+		action_modify_field->src.field = (enum rte_flow_field_id)i;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -7029,6 +7239,42 @@ comp_set_sample_index(struct context *ctx, const struct token *token,
 	return nb;
 }
 
+/** Complete operation for modify_field command. */
+static int
+comp_set_modify_field_op(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ops[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ops[ent], size);
+	return -1;
+}
+
+/** Complete field id for modify_field command. */
+static int
+comp_set_modify_field_id(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ids[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ids[ent], size);
+	return -1;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v8 1/2] ethdev: introduce generic modify rte flow action
  2021-01-18 16:18               ` [dpdk-dev] [PATCH v8 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
@ 2021-01-18 17:51                 ` Thomas Monjalon
  0 siblings, 0 replies; 48+ messages in thread
From: Thomas Monjalon @ 2021-01-18 17:51 UTC (permalink / raw)
  To: Alexander Kozyrev
  Cc: dev, viacheslavo, orika, ferruh.yigit, andrew.rybchenko, jerinjacobk

18/01/2021 17:18, Alexander Kozyrev:
> +/**
> + * Field description for MODIFY_FIELD action.
> + */
> +struct rte_flow_action_modify_data {
> +	enum rte_flow_field_id field; /**< Field ID */

more accurate:
	Field or memory type

> +	RTE_STD_C11
> +	union {
> +		struct {
> +			uint32_t level; /**< Encapsulation level or tag index */
> +			uint32_t offset; /**< Number of bits to skip from src */

"from src" only?
I think we could use it for dst as well.
I would remove "from src".

> +		};
> +		uint64_t value; /**< Immediate value or memory address of it */

You should specify for RTE_FLOW_FIELD_POINTER and RTE_FLOW_FIELD_VALUE.

Please add a dot at the end of each comment.

[...]
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this structure may change without prior notice
> + *
> + * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
> + *
> + * Modifies a destination header field according to the specified

s/Modifies/Modify/  (imperative form is preferred)

> + * operation. Another packet field can be used as a source as well
> + * as tag, mark, metadata, immediate value or a pointer to it.
> + */
> +struct rte_flow_action_modify_field {
> +	enum rte_flow_modify_op operation; /**< Operation to perform on dst*/
> +	struct rte_flow_action_modify_data dst; /**< Destination field */
> +	struct rte_flow_action_modify_data src; /**< Source field */
> +	uint32_t width; /**< Number of bits to use from a source field */
> +};


With above changes,
Acked-by: Thomas Monjalon <thomas@monjalon.net>



^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support
  2021-01-18 16:18             ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Alexander Kozyrev
  2021-01-18 16:18               ` [dpdk-dev] [PATCH v8 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
  2021-01-18 16:18               ` [dpdk-dev] [PATCH v8 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
@ 2021-01-18 20:05               ` Ajit Khaparde
  2021-01-18 21:40               ` [dpdk-dev] [PATCH v9 " Alexander Kozyrev
  3 siblings, 0 replies; 48+ messages in thread
From: Ajit Khaparde @ 2021-01-18 20:05 UTC (permalink / raw)
  To: Alexander Kozyrev
  Cc: dpdk-dev, Slava Ovsiienko, Ori Kam, Thomas Monjalon,
	Ferruh Yigit, Andrew Rybchenko, Jerin Jacob

[-- Attachment #1: Type: text/plain, Size: 2255 bytes --]

On Mon, Jan 18, 2021 at 8:18 AM Alexander Kozyrev <akozyrev@nvidia.com> wrote:
>
> Implement a generic modify rte flow API as described in RFC:
> http://patches.dpdk.org/patch/85384/
>
> This API allows modifying a destination header field with data from
> a source header field. Number of bits to use from the source is specified.
> Tag, Mark or Metadata can also be used as a source/destination to allow
> saving/overwriting an arbitrary header field with a user-specified value.
> Alternatively, an immediate value can be provided by a user as a source.
>
> Outermost/innermost packet fields (and Tag array elements) are
> accessible via the level parameter to facilitate the modification
> of encapsulated packet header fields. The offset parameter provides
> the flexibility to copy/set any part of a packet starting the
> specified packet header field.
>
> Example of RTE_FLOW_ACTION_TYPE_MODIFY_FIELD implementation for MLX5:
> https://patchwork.dpdk.org/patch/86736/
>
> ---
> v1: https://patchwork.dpdk.org/patch/86173/
> Initial design.
> v2: https://patchwork.dpdk.org/cover/86369/
> Added testpmd support.
> v3: https://patchwork.dpdk.org/cover/86442/
> Made dst_type, src_type and width only mandatory parameters.
> v4: https://patchwork.dpdk.org/cover/86488/
> Renamed action to RTE_FLOW_ACTION_TYPE_COPY_FIELD.
> v5: https://patchwork.dpdk.org/cover/86705/
> Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD.
> v6: https://patchwork.dpdk.org/cover/86715/
> Fixed typos in documentation.
> v7: https://patchwork.dpdk.org/cover/86718/
> Fixed warnings.
> v8:
> Added doxygen comments.
>
> Alexander Kozyrev (2):
>   ethdev: introduce generic modify rte flow action
>   app/testpmd: add support for modify field flow action
I see Thomas has some comments on one of the patches.
Please address that. Otherwise ack for the series.
Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>

>
>  app/test-pmd/cmdline_flow.c            | 246 +++++++++++++++++++++++++
>  doc/guides/prog_guide/rte_flow.rst     |  66 +++++++
>  doc/guides/rel_notes/release_21_02.rst |   8 +
>  lib/librte_ethdev/rte_flow.c           |   2 +
>  lib/librte_ethdev/rte_flow.h           |  87 ++++++++-
>  5 files changed, 408 insertions(+), 1 deletion(-)
>
> --
> 2.24.1
>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v9 0/2] generic modify rte flow action support
  2021-01-18 16:18             ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Alexander Kozyrev
                                 ` (2 preceding siblings ...)
  2021-01-18 20:05               ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Ajit Khaparde
@ 2021-01-18 21:40               ` Alexander Kozyrev
  2021-01-18 21:40                 ` [dpdk-dev] [PATCH v9 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
                                   ` (2 more replies)
  3 siblings, 3 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-18 21:40 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko,
	jerinjacobk, ajit.khaparde

Implement a generic modify rte flow API as described in RFC:
http://patches.dpdk.org/patch/85384/

This API allows modifying a destination header field with data from
a source header field. Number of bits to use from the source is specified.
Tag, Mark or Metadata can also be used as a source/destination to allow
saving/overwriting an arbitrary header field with a user-specified value.
Alternatively, an immediate value can be provided by a user as a source.

Outermost/innermost packet fields (and Tag array elements) are
accessible via the level parameter to facilitate the modification
of encapsulated packet header fields. The offset parameter provides
the flexibility to copy/set any part of a packet starting the
specified packet header field.

Example of RTE_FLOW_ACTION_TYPE_MODIFY_FIELD implementation for MLX5:
https://patchwork.dpdk.org/patch/86736/

---
v1: https://patchwork.dpdk.org/patch/86173/
Initial design.
v2: https://patchwork.dpdk.org/cover/86369/
Added testpmd support.
v3: https://patchwork.dpdk.org/cover/86442/
Made dst_type, src_type and width only mandatory parameters.
v4: https://patchwork.dpdk.org/cover/86488/
Renamed action to RTE_FLOW_ACTION_TYPE_COPY_FIELD.
v5: https://patchwork.dpdk.org/cover/86705/
Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD.
v6: https://patchwork.dpdk.org/cover/86715/
Fixed typos in documentation.
v7: https://patchwork.dpdk.org/cover/86718/
Fixed warnings.
v8: https://patchwork.dpdk.org/cover/86816/
Added doxygen comments.
v9:
Minor documentation corrections.

Alexander Kozyrev (2):
  ethdev: introduce generic modify rte flow action
  app/testpmd: add support for modify field flow action

 app/test-pmd/cmdline_flow.c            | 246 +++++++++++++++++++++++++
 doc/guides/prog_guide/rte_flow.rst     |  66 +++++++
 doc/guides/rel_notes/release_21_02.rst |   8 +
 lib/librte_ethdev/rte_flow.c           |   2 +
 lib/librte_ethdev/rte_flow.h           |  93 +++++++++-
 5 files changed, 414 insertions(+), 1 deletion(-)

-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v9 1/2] ethdev: introduce generic modify rte flow action
  2021-01-18 21:40               ` [dpdk-dev] [PATCH v9 " Alexander Kozyrev
@ 2021-01-18 21:40                 ` Alexander Kozyrev
  2021-01-18 21:40                 ` [dpdk-dev] [PATCH v9 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
  2021-01-19  1:21                 ` [dpdk-dev] [PATCH v9 0/2] generic modify rte flow action support Ferruh Yigit
  2 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-18 21:40 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko,
	jerinjacobk, ajit.khaparde

Implement the generic modify flow API to allow manipulations on
an arbitrary header field (as well as mark, metadata or tag) using
data from another field or a user-specified value.
This generic modify mechanism removes the necessity to implement
a separate RTE Flow action every time we need to modify a new packet
field in the future.

Supported operation are:
- set: copy data from source to destination.
- add: integer addition, stores the result in destination.
- sub: integer subtraction, stores the result in destination.

The field ID is used to specify the desired source/destination packet
field in order to simplify the API for various encapsulation models.
Specifying the packet field ID with the needed encapsulation level
is able to quickly get a packet field for any inner packet header.

Alternatively, the special ID (ITEM_START) can be used to point to
the very beginning of a packet. This ID in conjunction with the
offset parameter provides great flexibility to copy/modify any part of
a packet as needed.

The number of bits to use from a source as well as the offset can be
be specified to allow a partial copy or dividing a big packet field
into multiple small fields (e.g. copying 128 bits of IPv6 to 4 tags).

An immediate value (or a pointer to it) can be specified instead of the
level and the offset for the special FIELD_VALUE ID (or FIELD_POINTER).
Can be used as a source only.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
Acked-by: Thomas Monjalon <thomas@monjalon.net>
Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>

---
v1: Initialy RTE_FLOW_ACTION_TYPE_COPY_ITEM
v2: Renamed to RTE_FLOW_ACTION_TYPE_COPY_FIELD
v3: Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
v4: Fixed typos in documentation, renamed mov operation to set
v5: Added doxygen comments
v6: Minor documentation edits.
---
 doc/guides/prog_guide/rte_flow.rst     | 66 ++++++++++++++++++
 doc/guides/rel_notes/release_21_02.rst |  8 +++
 lib/librte_ethdev/rte_flow.c           |  2 +
 lib/librte_ethdev/rte_flow.h           | 93 +++++++++++++++++++++++++-
 4 files changed, 168 insertions(+), 1 deletion(-)

diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index 86b3444803..0b8c243fe1 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2766,6 +2766,72 @@ The behaviour of the shared action defined by ``action`` argument of type
    | no properties |
    +---------------+
 
+Action: ``MODIFY_FIELD``
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Modify ``dst`` field according to ``op`` selected (set, addition,
+subtraction) with ``width`` bits of data from ``src`` field.
+
+Any arbitrary header field (as well as mark, metadata or tag values)
+can be used as both source and destination fields as set by ``field``.
+The immediate value ``RTE_FLOW_FIELD_VALUE`` (or a pointer to it
+``RTE_FLOW_FIELD_POINTER``) is allowed as a source only.
+``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet.
+
+``op`` selects the operation to perform on a destination field.
+- ``set`` copies the data from ``src`` field to ``dst`` field.
+- ``add`` adds together ``dst`` and ``src`` and stores the result into ``dst``.
+- ``sub`` subtracts ``src`` from ``dst`` and stores the result into ``dst``
+
+``width`` defines a number of bits to use from ``src`` field.
+
+``level`` is used to access any packet field on any encapsulation level
+as well as any tag element in the tag array.
+- ``0`` means the default behaviour. Depending on the packet type, it can
+mean outermost, innermost or anything in between.
+- ``1`` requests access to the outermost packet encapsulation level.
+- ``2`` and subsequent values requests access to the specified packet
+encapsulation level, from outermost to innermost (lower to higher values).
+For the tag array (in case of multiple tags are supported and present)
+``level`` translates directly into the array index.
+
+``offset`` specifies the number of bits to skip from a field's start.
+That allows performing a partial copy of the needed part or to divide a big
+packet field into multiple smaller fields. Alternatively, ``offset`` allows
+going past the specified packet field boundary to copy a field to an
+arbitrary place in a packet, essentially providing a way to copy any part of
+a packet to any other part of it.
+
+``value`` sets an immediate value to be used as a source or points to a
+location of the value in memory. It is used instead of ``level`` and ``offset``
+for ``RTE_FLOW_FIELD_VALUE`` and ``RTE_FLOW_FIELD_POINTER`` respectively.
+
+.. _table_rte_flow_action_modify_field:
+
+.. table:: MODIFY_FIELD
+
+   +-----------------------------------------+
+   | Field         | Value                   |
+   +===============+=========================+
+   | ``op``        | operation to perform    |
+   | ``dst``       | destination field       |
+   | ``src``       | source field            |
+   | ``width``     | number of bits to use   |
+   +---------------+-------------------------+
+
+.. _table_rte_flow_action_modify_data:
+
+.. table:: destination/source field definition
+
+   +--------------------------------------------------------------------------+
+   | Field         | Value                                                    |
+   +===============+==========================================================+
+   | ``field``     | ID: packet field, mark, meta, tag, immediate, pointer    |
+   | ``level``     | encapsulation level of a packet field or tag array index |
+   | ``offset``    | number of bits to skip at the beginning                  |
+   | ``value``     | immediate value or a pointer to this value               |
+   +---------------+----------------------------------------------------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst
index 3bb0b9a9ed..bb3cccd2e3 100644
--- a/doc/guides/rel_notes/release_21_02.rst
+++ b/doc/guides/rel_notes/release_21_02.rst
@@ -55,6 +55,14 @@ New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added support of modify field action in the flow API.**
+
+  Added modify action support to perform various operations on
+  any arbitrary header field (as well as mark, metadata or tag values):
+  ``RTE_FLOW_ACTION_TYPE_MODIFY_FIELD``.
+  supported operations are: overwriting a field with the content from
+  another field, addition and subtraction using an immediate value.
+
 * **Updated Broadcom bnxt driver.**
 
   Updated the Broadcom bnxt driver with fixes and improvements, including:
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index a06f64c271..9dd051f3c2 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -176,6 +176,8 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
 	MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)),
 	MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)),
 	MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)),
+	MK_FLOW_ACTION(MODIFY_FIELD,
+		       sizeof(struct rte_flow_action_modify_field)),
 	/**
 	 * Shared action represented as handle of type
 	 * (struct rte_flow_shared action *) stored in conf field (see
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 0977a78270..d63fd79e1a 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2198,6 +2198,17 @@ enum rte_flow_action_type {
 	 * struct rte_flow_shared_action).
 	 */
 	RTE_FLOW_ACTION_TYPE_SHARED,
+
+	/**
+	 * Modify a packet header field, tag, mark or metadata.
+	 *
+	 * Allow the modification of an arbitrary header field via
+	 * set, add and sub operations or copying its content into
+	 * tag, meta or mark for future processing.
+	 *
+	 * See struct rte_flow_action_modify_field.
+	 */
+	RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,
 };
 
 /**
@@ -2777,7 +2788,6 @@ struct rte_flow_action_set_dscp {
 	uint8_t dscp;
 };
 
-
 /**
  * RTE_FLOW_ACTION_TYPE_SHARED
  *
@@ -2791,6 +2801,87 @@ struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+/**
+ * Field IDs for MODIFY_FIELD action.
+ */
+enum rte_flow_field_id {
+	RTE_FLOW_FIELD_START = 0, /**< Start of a packet. */
+	RTE_FLOW_FIELD_MAC_DST,
+	RTE_FLOW_FIELD_MAC_SRC,
+	RTE_FLOW_FIELD_VLAN_TYPE,
+	RTE_FLOW_FIELD_VLAN_ID,
+	RTE_FLOW_FIELD_MAC_TYPE,
+	RTE_FLOW_FIELD_IPV4_DSCP,
+	RTE_FLOW_FIELD_IPV4_TTL,
+	RTE_FLOW_FIELD_IPV4_SRC,
+	RTE_FLOW_FIELD_IPV4_DST,
+	RTE_FLOW_FIELD_IPV6_HOPLIMIT,
+	RTE_FLOW_FIELD_IPV6_SRC,
+	RTE_FLOW_FIELD_IPV6_DST,
+	RTE_FLOW_FIELD_TCP_PORT_SRC,
+	RTE_FLOW_FIELD_TCP_PORT_DST,
+	RTE_FLOW_FIELD_TCP_SEQ_NUM,
+	RTE_FLOW_FIELD_TCP_ACK_NUM,
+	RTE_FLOW_FIELD_TCP_FLAGS,
+	RTE_FLOW_FIELD_UDP_PORT_SRC,
+	RTE_FLOW_FIELD_UDP_PORT_DST,
+	RTE_FLOW_FIELD_VXLAN_VNI,
+	RTE_FLOW_FIELD_GENEVE_VNI,
+	RTE_FLOW_FIELD_GTP_TEID,
+	RTE_FLOW_FIELD_TAG,
+	RTE_FLOW_FIELD_MARK,
+	RTE_FLOW_FIELD_META,
+	RTE_FLOW_FIELD_POINTER, /**< Memory pointer. */
+	RTE_FLOW_FIELD_VALUE,   /**< Immediate value. */
+};
+
+/**
+ * Field description for MODIFY_FIELD action.
+ */
+struct rte_flow_action_modify_data {
+	enum rte_flow_field_id field; /**< Field or memory type ID. */
+	RTE_STD_C11
+	union {
+		struct {
+			/**< Encapsulation level or tag index. */
+			uint32_t level;
+			/**< Number of bits to skip from a field. */
+			uint32_t offset;
+		};
+		/**
+		 * Immediate value for RTE_FLOW_FIELD_VALUE or
+		 * memory address for RTE_FLOW_FIELD_POINTER.
+		 */
+		uint64_t value;
+	};
+};
+
+/**
+ * Operation types for MODIFY_FIELD action.
+ */
+enum rte_flow_modify_op {
+	RTE_FLOW_MODIFY_SET = 0, /**< Set a new value. */
+	RTE_FLOW_MODIFY_ADD,     /**< Add a value to a field.  */
+	RTE_FLOW_MODIFY_SUB,     /**< Subtract a value from a field. */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD
+ *
+ * Modify a destination header field according to the specified
+ * operation. Another packet field can be used as a source as well
+ * as tag, mark, metadata, immediate value or a pointer to it.
+ */
+struct rte_flow_action_modify_field {
+	enum rte_flow_modify_op operation; /**< Operation to perform. */
+	struct rte_flow_action_modify_data dst; /**< Destination field. */
+	struct rte_flow_action_modify_data src; /**< Source field. */
+	uint32_t width; /**< Number of bits to use from a source field. */
+};
+
 /* Mbuf dynamic field offset for metadata. */
 extern int32_t rte_flow_dynf_metadata_offs;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [dpdk-dev] [PATCH v9 2/2] app/testpmd: add support for modify field flow action
  2021-01-18 21:40               ` [dpdk-dev] [PATCH v9 " Alexander Kozyrev
  2021-01-18 21:40                 ` [dpdk-dev] [PATCH v9 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
@ 2021-01-18 21:40                 ` Alexander Kozyrev
  2021-01-19  1:21                 ` [dpdk-dev] [PATCH v9 0/2] generic modify rte flow action support Ferruh Yigit
  2 siblings, 0 replies; 48+ messages in thread
From: Alexander Kozyrev @ 2021-01-18 21:40 UTC (permalink / raw)
  To: dev
  Cc: viacheslavo, orika, thomas, ferruh.yigit, andrew.rybchenko,
	jerinjacobk, ajit.khaparde

Add support for the RTE_FLOW_ACTION_MODIFY_FIELD to the testpmd.
Implement CLI to create the modify_field action and supply all the
needed parameters to modify an arbitrary packet field (as well as
mark, tag or metadata) with data from another field or immediate
value.

Example of the flow is the following:
flow create 0 egress group 1 pattern eth / ipv4 / udp / end
  actions modify_field op set dst_type tag dst_level 2 dst_offset 8
          src_type gtp_teid src_level 0 src_offset 0 width 16 / end

This flow copies 16 bits from the second Tag in the Tags array
into the outermost GTP TEID packet header field. 8 bits of the
Tag are skipped as indicated by the dst_offset action parameter.

op, dst_type, src_type and width are the mandatory parameters to
specify. Levels and offset are 0 by default if they are not
overridden by a user. The operation can be set, add or sub.

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>

---
v1: Initial implementation.
v2: Made dst_type, src_type and width only mandatory parameters.
v3: Reworked to accomodate API change from copy_field to modify_field.
v4: Renamed the mov operation to set.
---
 app/test-pmd/cmdline_flow.c | 246 ++++++++++++++++++++++++++++++++++++
 1 file changed, 246 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 37b10e61bf..aa5ccbbcd7 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -408,6 +408,19 @@ enum index {
 	ACTION_SAMPLE_INDEX_VALUE,
 	ACTION_SHARED,
 	SHARED_ACTION_ID2PTR,
+	ACTION_MODIFY_FIELD,
+	ACTION_MODIFY_FIELD_OP,
+	ACTION_MODIFY_FIELD_OP_VALUE,
+	ACTION_MODIFY_FIELD_DST_TYPE,
+	ACTION_MODIFY_FIELD_DST_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ACTION_MODIFY_FIELD_SRC_TYPE_VALUE,
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -561,6 +574,22 @@ struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM];
 struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM];
 
+static const char *const modify_field_ops[] = {
+	"set", "add", "sub", NULL
+};
+
+static const char *const modify_field_ids[] = {
+	"start", "mac_dst", "mac_src",
+	"vlan_type", "vlan_id", "mac_type",
+	"ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst",
+	"ipv6_hoplimit", "ipv6_src", "ipv6_dst",
+	"tcp_port_src", "tcp_port_dst",
+	"tcp_seq_num", "tcp_ack_num", "tcp_flags",
+	"udp_port_src", "udp_port_dst",
+	"vxlan_vni", "geneve_vni", "gtp_teid",
+	"tag", "mark", "meta", "pointer", "value", NULL
+};
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -1306,6 +1335,7 @@ static const enum index next_action[] = {
 	ACTION_AGE,
 	ACTION_SAMPLE,
 	ACTION_SHARED,
+	ACTION_MODIFY_FIELD,
 	ZERO,
 };
 
@@ -1556,6 +1586,21 @@ static const enum index next_action_sample[] = {
 	ZERO,
 };
 
+static const enum index action_modify_field_dst[] = {
+	ACTION_MODIFY_FIELD_DST_LEVEL,
+	ACTION_MODIFY_FIELD_DST_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_TYPE,
+	ZERO,
+};
+
+static const enum index action_modify_field_src[] = {
+	ACTION_MODIFY_FIELD_SRC_LEVEL,
+	ACTION_MODIFY_FIELD_SRC_OFFSET,
+	ACTION_MODIFY_FIELD_SRC_VALUE,
+	ACTION_MODIFY_FIELD_WIDTH,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -1638,6 +1683,14 @@ static int
 parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 				const char *str, unsigned int len, void *buf,
 				unsigned int size);
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1722,6 +1775,10 @@ static int comp_set_raw_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
 static int comp_set_sample_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_op(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
+static int comp_set_modify_field_id(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -4037,6 +4094,103 @@ static const struct token token_list[] = {
 		.call = parse_vc_action_raw_decap_index,
 		.comp = comp_set_raw_index,
 	},
+	[ACTION_MODIFY_FIELD] = {
+		.name = "modify_field",
+		.help = "modify destination field with data from source field",
+		.priv = PRIV_ACTION(MODIFY_FIELD,
+			sizeof(struct rte_flow_action_modify_field)),
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_OP)),
+		.call = parse_vc,
+	},
+	[ACTION_MODIFY_FIELD_OP] = {
+		.name = "op",
+		.help = "operation type",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE),
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_OP_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_OP_VALUE] = {
+		.name = "{operation}",
+		.help = "operation type value",
+		.call = parse_vc_modify_field_op,
+		.comp = comp_set_modify_field_op,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE] = {
+		.name = "dst_type",
+		.help = "destination field type",
+		.next = NEXT(action_modify_field_dst,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_TYPE_VALUE] = {
+		.name = "{dst_type}",
+		.help = "destination field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_DST_LEVEL] = {
+		.name = "dst_level",
+		.help = "destination field level",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_DST_OFFSET] = {
+		.name = "dst_offset",
+		.help = "destination field bit offset",
+		.next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					dst.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE] = {
+		.name = "src_type",
+		.help = "source field type",
+		.next = NEXT(action_modify_field_src,
+			NEXT_ENTRY(ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_TYPE_VALUE] = {
+		.name = "{src_type}",
+		.help = "source field type value",
+		.call = parse_vc_modify_field_id,
+		.comp = comp_set_modify_field_id,
+	},
+	[ACTION_MODIFY_FIELD_SRC_LEVEL] = {
+		.name = "src_level",
+		.help = "source field level",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.level)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_OFFSET] = {
+		.name = "src_offset",
+		.help = "source field bit offset",
+		.next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.offset)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_SRC_VALUE] = {
+		.name = "src_value",
+		.help = "source immediate value",
+		.next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_WIDTH),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					src.value)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_MODIFY_FIELD_WIDTH] = {
+		.name = "width",
+		.help = "number of bits to copy",
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT),
+			NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field,
+					width)),
+		.call = parse_vc_conf,
+	},
 	/* Top level command. */
 	[SET] = {
 		.name = "set",
@@ -5960,6 +6114,62 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse operation for modify_field command. */
+static int
+parse_vc_modify_field_op(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_OP_VALUE)
+		return -1;
+	for (i = 0; modify_field_ops[i]; ++i)
+		if (!strcmp_partial(modify_field_ops[i], str, len))
+			break;
+	if (!modify_field_ops[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	action_modify_field->operation = (enum rte_flow_modify_op)i;
+	return len;
+}
+
+/** Parse id for modify_field command. */
+static int
+parse_vc_modify_field_id(struct context *ctx, const struct token *token,
+			 const char *str, unsigned int len, void *buf,
+			 unsigned int size)
+{
+	struct rte_flow_action_modify_field *action_modify_field;
+	unsigned int i;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_MODIFY_FIELD_DST_TYPE_VALUE &&
+		ctx->curr != ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)
+		return -1;
+	for (i = 0; modify_field_ids[i]; ++i)
+		if (!strcmp_partial(modify_field_ids[i], str, len))
+			break;
+	if (!modify_field_ids[i])
+		return -1;
+	if (!ctx->object)
+		return len;
+	action_modify_field = ctx->object;
+	if (ctx->curr == ACTION_MODIFY_FIELD_DST_TYPE_VALUE)
+		action_modify_field->dst.field = (enum rte_flow_field_id)i;
+	else
+		action_modify_field->src.field = (enum rte_flow_field_id)i;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -7029,6 +7239,42 @@ comp_set_sample_index(struct context *ctx, const struct token *token,
 	return nb;
 }
 
+/** Complete operation for modify_field command. */
+static int
+comp_set_modify_field_op(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ops[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ops[ent], size);
+	return -1;
+}
+
+/** Complete field id for modify_field command. */
+static int
+comp_set_modify_field_id(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; modify_field_ids[idx]; ++idx)
+		;
+	if (!buf)
+		return idx + 1;
+	if (ent < idx)
+		return strlcpy(buf, modify_field_ids[ent], size);
+	return -1;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
-- 
2.24.1


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [dpdk-dev] [PATCH v9 0/2] generic modify rte flow action support
  2021-01-18 21:40               ` [dpdk-dev] [PATCH v9 " Alexander Kozyrev
  2021-01-18 21:40                 ` [dpdk-dev] [PATCH v9 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
  2021-01-18 21:40                 ` [dpdk-dev] [PATCH v9 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
@ 2021-01-19  1:21                 ` Ferruh Yigit
  2 siblings, 0 replies; 48+ messages in thread
From: Ferruh Yigit @ 2021-01-19  1:21 UTC (permalink / raw)
  To: Alexander Kozyrev, dev
  Cc: viacheslavo, orika, thomas, andrew.rybchenko, jerinjacobk, ajit.khaparde

On 1/18/2021 9:40 PM, Alexander Kozyrev wrote:
> Implement a generic modify rte flow API as described in RFC:
> http://patches.dpdk.org/patch/85384/
> 
> This API allows modifying a destination header field with data from
> a source header field. Number of bits to use from the source is specified.
> Tag, Mark or Metadata can also be used as a source/destination to allow
> saving/overwriting an arbitrary header field with a user-specified value.
> Alternatively, an immediate value can be provided by a user as a source.
> 
> Outermost/innermost packet fields (and Tag array elements) are
> accessible via the level parameter to facilitate the modification
> of encapsulated packet header fields. The offset parameter provides
> the flexibility to copy/set any part of a packet starting the
> specified packet header field.
> 
> Example of RTE_FLOW_ACTION_TYPE_MODIFY_FIELD implementation for MLX5:
> https://patchwork.dpdk.org/patch/86736/
> 
> ---
> v1: https://patchwork.dpdk.org/patch/86173/
> Initial design.
> v2: https://patchwork.dpdk.org/cover/86369/
> Added testpmd support.
> v3: https://patchwork.dpdk.org/cover/86442/
> Made dst_type, src_type and width only mandatory parameters.
> v4: https://patchwork.dpdk.org/cover/86488/
> Renamed action to RTE_FLOW_ACTION_TYPE_COPY_FIELD.
> v5: https://patchwork.dpdk.org/cover/86705/
> Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD.
> v6: https://patchwork.dpdk.org/cover/86715/
> Fixed typos in documentation.
> v7: https://patchwork.dpdk.org/cover/86718/
> Fixed warnings.
> v8: https://patchwork.dpdk.org/cover/86816/
> Added doxygen comments.
> v9:
> Minor documentation corrections.
> 
> Alexander Kozyrev (2):
>    ethdev: introduce generic modify rte flow action
>    app/testpmd: add support for modify field flow action
> 

Series applied to dpdk-next-net/main, thanks.


^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2021-01-19  1:21 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-08  6:32 [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action Alexander Kozyrev
2021-01-10  8:00 ` Ori Kam
2021-01-10  9:36   ` Asaf Penso
2021-01-12 14:15   ` Alexander Kozyrev
2021-01-12 14:52     ` Ori Kam
2021-01-12 15:13       ` Ori Kam
2021-01-12 17:19         ` Alexander Kozyrev
2021-01-12  5:01 ` [dpdk-dev] [PATCH v2 0/2] generic copy rte flow action support Alexander Kozyrev
2021-01-12  5:01   ` [dpdk-dev] [PATCH v2 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
2021-01-12  5:01   ` [dpdk-dev] [PATCH v2 2/2] app/testpmd: add support for " Alexander Kozyrev
2021-01-12 14:58     ` Ori Kam
2021-01-13  3:38   ` [dpdk-dev] [PATCH v3 0/2] generic copy rte flow action support Alexander Kozyrev
2021-01-13  3:38     ` [dpdk-dev] [PATCH v3 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
2021-01-13 11:12       ` Ori Kam
2021-01-13  3:38     ` [dpdk-dev] [PATCH v3 2/2] app/testpmd: add support for " Alexander Kozyrev
2021-01-13 17:07     ` [dpdk-dev] [PATCH v4 0/2] generic copy rte flow action support Alexander Kozyrev
2021-01-13 17:07       ` [dpdk-dev] [PATCH v4 1/2] ethdev: introduce generic copy rte flow action Alexander Kozyrev
2021-01-14 12:22         ` Ori Kam
2021-01-13 17:07       ` [dpdk-dev] [PATCH v4 2/2] app/testpmd: add support for " Alexander Kozyrev
2021-01-14 15:18         ` Ori Kam
2021-01-15 15:37           ` Alexander Kozyrev
2021-01-15 15:42       ` [dpdk-dev] [PATCH v5 0/2] generic modify rte flow action support Alexander Kozyrev
2021-01-15 15:42         ` [dpdk-dev] [PATCH v5 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
2021-01-15 18:03           ` Ori Kam
2021-01-17  9:23             ` Slava Ovsiienko
2021-01-15 15:42         ` [dpdk-dev] [PATCH v5 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
2021-01-15 18:04           ` Ori Kam
2021-01-16  4:44         ` [dpdk-dev] [PATCH v6 0/2] generic modify rte flow action support Alexander Kozyrev
2021-01-16  4:44           ` [dpdk-dev] [PATCH v6 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
2021-01-16  4:44           ` [dpdk-dev] [PATCH v6 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
2021-01-16  4:50           ` [dpdk-dev] [PATCH v7 0/2] generic modify rte flow action support Alexander Kozyrev
2021-01-16  4:50             ` [dpdk-dev] [PATCH v7 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
2021-01-17 23:15               ` Thomas Monjalon
2021-01-18 16:03                 ` Alexander Kozyrev
2021-01-16  4:50             ` [dpdk-dev] [PATCH v7 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
2021-01-18 16:18             ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Alexander Kozyrev
2021-01-18 16:18               ` [dpdk-dev] [PATCH v8 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
2021-01-18 17:51                 ` Thomas Monjalon
2021-01-18 16:18               ` [dpdk-dev] [PATCH v8 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
2021-01-18 20:05               ` [dpdk-dev] [PATCH v8 0/2] generic modify rte flow action support Ajit Khaparde
2021-01-18 21:40               ` [dpdk-dev] [PATCH v9 " Alexander Kozyrev
2021-01-18 21:40                 ` [dpdk-dev] [PATCH v9 1/2] ethdev: introduce generic modify rte flow action Alexander Kozyrev
2021-01-18 21:40                 ` [dpdk-dev] [PATCH v9 2/2] app/testpmd: add support for modify field " Alexander Kozyrev
2021-01-19  1:21                 ` [dpdk-dev] [PATCH v9 0/2] generic modify rte flow action support Ferruh Yigit
2021-01-14 13:59 ` [dpdk-dev] [PATCH] ethdev: introduce generic copy rte flow action Jerin Jacob
2021-01-14 15:02   ` Ori Kam
2021-01-15 14:00     ` Jerin Jacob
2021-01-15 15:33       ` Alexander Kozyrev

DPDK patches and discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://inbox.dpdk.org/dev/0 dev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 dev dev/ https://inbox.dpdk.org/dev \
		dev@dpdk.org
	public-inbox-index dev

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://inbox.dpdk.org/inbox.dpdk.dev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git