DPDK patches and discussions
 help / color / mirror / Atom feed
* Re: [PATCH v2] app/testpmd: enable cli for programmable action
  2023-10-05 11:42 ` [PATCH v2] " Qi Zhang
@ 2023-10-05  4:32   ` Stephen Hemminger
  2023-10-06  2:37     ` Zhang, Qi Z
  0 siblings, 1 reply; 20+ messages in thread
From: Stephen Hemminger @ 2023-10-05  4:32 UTC (permalink / raw)
  To: Qi Zhang
  Cc: aman.deep.singh, yuying.zhang, dev, cristian.dumitrescu, orika,
	ferruh.yigit

On Thu,  5 Oct 2023 07:42:38 -0400
Qi Zhang <qi.z.zhang@intel.com> wrote:

> +	char name[ACTION_PROG_NAME_SIZE_MAX];
> +	struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX];
> +	char arg_names[ACTION_PROG_ARG_NUM_MAX][ACTION_PROG_NAME_SIZE_MAX];
> +	uint8_t value[ACTION_PROG_ARG_NUM_MAX][ACTION_PROG_ARG_VALUE_SIZE_MAX];
> +};
> +

IMHO if you have this many array elements the data structure makes more sense as.

	struct flow_arg {
		char name[ACTION_PROG_NAME_SIZE_MAX];
		struct {
			struct rte_flow_prog_argument prog;
			char names[ACTION_PROG_NAME_SIZE_MAX];
			uint8_t value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
		} args[ACTION_PROG_ARG_NUM_MAX];
	};

Or better yet get rid of PROG_ARG_NUM_MAX and use a flex array.
Somebody will want more than 8 args.

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

* [PATCH 1/2] app/testpmd: enable cli for programmable action
@ 2023-10-05 10:02 Qi Zhang
  2023-10-05 11:42 ` [PATCH v2] " Qi Zhang
                   ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: Qi Zhang @ 2023-10-05 10:02 UTC (permalink / raw)
  To: aman.deep.singh, yuying.zhang
  Cc: dev, cristian.dumitrescu, orika, ferruh.yigit, Qi Zhang

Parsing command line for rte_flow_action_prog.

Syntax:

"prog name <name> [arguments <arg_name_0> <arg_value_0> \
 <arg_name_1> <arg_value1> ... end]"

Use parse_string0 to parse name string.
Use parse_hex to parse hex string.
Use struct action_prog_data to store parsed result.

Example:

Action with 2 arguments:

"prog name action0 arguments field0 03FF field1 55AA end"

Action without argument:

"prog name action1"

Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
---
 app/test-pmd/cmdline_flow.c | 223 ++++++++++++++++++++++++++++++++++++
 1 file changed, 223 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 21828c144c..028cff0150 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -719,6 +719,13 @@ enum index {
 	ACTION_IPV6_EXT_PUSH,
 	ACTION_IPV6_EXT_PUSH_INDEX,
 	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
+	ACTION_PROG,
+	ACTION_PROG_NAME,
+	ACTION_PROG_NAME_STRING,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_PROG_ARG_NAME,
+	ACTION_PROG_ARG_VALUE,
+	ACTION_PROG_ARG_END,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -749,6 +756,19 @@ struct action_rss_data {
 	uint16_t queue[ACTION_RSS_QUEUE_NUM];
 };
 
+#define ACTION_PROG_NAME_SIZE_MAX 32
+#define ACTION_PROG_ARG_NUM_MAX 8
+#define ACTION_PROG_ARG_VALUE_SIZE_MAX 16
+
+/** Storage for struct rte_flow_action_prog including external data. */
+struct action_prog_data {
+	struct rte_flow_action_prog conf;
+	char name[ACTION_PROG_NAME_SIZE_MAX];
+	struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX];
+	char arg_names[ACTION_PROG_ARG_NUM_MAX][ACTION_PROG_NAME_SIZE_MAX];
+	uint8_t value[ACTION_PROG_ARG_NUM_MAX][ACTION_PROG_ARG_VALUE_SIZE_MAX];
+};
+
 /** Maximum data size in struct rte_flow_action_raw_encap. */
 #define ACTION_RAW_ENCAP_MAX_DATA 512
 #define RAW_ENCAP_CONFS_MAX_NUM 8
@@ -2169,6 +2189,7 @@ static const enum index next_action[] = {
 	ACTION_QUOTA_QU,
 	ACTION_IPV6_EXT_REMOVE,
 	ACTION_IPV6_EXT_PUSH,
+	ACTION_PROG,
 	ZERO,
 };
 
@@ -2510,6 +2531,13 @@ static const enum index action_represented_port[] = {
 	ZERO,
 };
 
+static const enum index action_prog[] = {
+	ACTION_PROG_NAME,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_NEXT,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -2786,6 +2814,18 @@ static int
 parse_qu_mode_name(struct context *ctx, const struct token *token,
 		   const char *str, unsigned int len, void *buf,
 		   unsigned int size);
+static int
+parse_vc_action_prog(struct context *, const struct token *,
+		     const char *, unsigned int, void *,
+		     unsigned int);
+static int
+parse_vc_action_prog_arg_name(struct context *, const struct token *,
+			      const char *, unsigned int, void *,
+			      unsigned int);
+static int
+parse_vc_action_prog_arg_value(struct context *, const struct token *,
+			       const char *, unsigned int, void *,
+			       unsigned int);
 static int comp_none(struct context *, const struct token *,
 		     unsigned int, char *, unsigned int);
 static int comp_boolean(struct context *, const struct token *,
@@ -7518,6 +7558,48 @@ static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
 					tx_queue)),
 	},
+	[ACTION_PROG] = {
+		.name = "prog",
+		.help = "match a programmable action",
+		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
+		.next = NEXT(action_prog),
+		.call = parse_vc_action_prog,
+	},
+	[ACTION_PROG_NAME] = {
+		.name = "name",
+		.help = "programble action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
+		.args = ARGS(ARGS_ENTRY(struct action_prog_data, name)),
+	},
+	[ACTION_PROG_NAME_STRING] = {
+		.name = "{string}",
+		.type = "STRING",
+		.help = "programmable action name string",
+		.call = parse_string0,
+	},
+	[ACTION_PROG_ARGUMENTS] = {
+		.name = "arguments",
+		.help = "programmable action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_PROG_ARG_NAME] = {
+		.name = "{string}",
+		.help = "programmable action argument name",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
+		.call = parse_vc_action_prog_arg_name,
+	},
+	[ACTION_PROG_ARG_VALUE] = {
+		.name = "{hex}",
+		.help = "programmable action argument value",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END, ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_action_prog_arg_value,
+	},
+	[ACTION_PROG_ARG_END] = {
+		.name = "end",
+		.help = "end of the programmable action arguments",
+	},
+
 };
 
 /** Remove and return last entry from argument stack. */
@@ -11675,6 +11757,147 @@ parse_qu_mode_name(struct context *ctx, const struct token *token,
 				   (uint32_t *)&out->args.ia.qu_mode);
 }
 
+/** Parse prog action. */
+static int
+parse_vc_action_prog(struct context *ctx, const struct token *token,
+		     const char *str, unsigned int len,
+		     void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_prog_data *action_prog_data;
+	uint16_t i;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+	/* Nothing else to do if there is no buffer. */
+	if (!out)
+		return ret;
+	if (!out->args.vc.actions_n)
+		return -1;
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	ctx->object = out->args.vc.data;
+	action_prog_data = ctx->object;
+	*action_prog_data = (struct action_prog_data) {
+		.conf = (struct rte_flow_action_prog) {
+			.args_num = 0,
+			.name = action_prog_data->name,
+			.args = action_prog_data->args,
+		},
+	};
+	for (i = 0; i < ACTION_PROG_ARG_NUM_MAX; ++i)
+		action_prog_data->args[i].name = action_prog_data->arg_names[i];
+	action->conf = &action_prog_data->conf;
+
+	return ret;
+}
+
+static int
+parse_vc_action_prog_arg_name(struct context *ctx, const struct token *token,
+			      const char *str, unsigned int len,
+			      void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	struct buffer *out = buf;
+	const struct arg *arg;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_NAME)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	if (i >= ACTION_PROG_ARG_NUM_MAX)
+		return -1;
+
+	arg = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, arg_names) +
+				      i * ACTION_PROG_NAME_SIZE_MAX,
+				      ACTION_PROG_NAME_SIZE_MAX);
+
+	if (push_args(ctx, arg))
+		return -1;
+
+	ret = parse_string0(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	return len;
+}
+
+static int
+parse_vc_action_prog_arg_value(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	const struct arg *arg_addr;
+	const struct arg *arg_size;
+	const struct arg *arg_data;
+	struct buffer *out = buf;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_VALUE)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	arg_addr  = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, args) +
+				   i * sizeof(struct rte_flow_action_prog_argument) +
+				   offsetof(struct rte_flow_action_prog_argument, value),
+				   sizeof(action_prog_data->args[i].value));
+
+	arg_size = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, args) +
+					   i * sizeof(struct rte_flow_action_prog_argument) +
+					   offsetof(struct rte_flow_action_prog_argument, size),
+					   sizeof(action_prog_data->args[i].size));
+
+	arg_data = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, value) +
+					   i * ACTION_PROG_ARG_VALUE_SIZE_MAX,
+					   ACTION_PROG_ARG_VALUE_SIZE_MAX);
+
+	if (push_args(ctx, arg_addr))
+		return -1;
+	if (push_args(ctx, arg_size)) {
+		pop_args(ctx);
+		return -1;
+	}
+	if (push_args(ctx, arg_data)) {
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	ret = parse_hex(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+	action_prog_data->conf.args_num++;
+	return len;
+}
+
 /** No completion. */
 static int
 comp_none(struct context *ctx, const struct token *token,
-- 
2.31.1


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

* [PATCH v2] app/testpmd: enable cli for programmable action
  2023-10-05 10:02 [PATCH 1/2] app/testpmd: enable cli for programmable action Qi Zhang
@ 2023-10-05 11:42 ` Qi Zhang
  2023-10-05  4:32   ` Stephen Hemminger
  2023-10-06 11:07 ` [PATCH v3] " Qi Zhang
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Qi Zhang @ 2023-10-05 11:42 UTC (permalink / raw)
  To: aman.deep.singh, yuying.zhang
  Cc: dev, cristian.dumitrescu, orika, ferruh.yigit, Qi Zhang

Parsing command line for rte_flow_action_prog.

Syntax:

"prog name <name> [arguments <arg_name_0> <arg_value_0> \
 <arg_name_1> <arg_value1> ... end]"

Use parse_string0 to parse name string.
Use parse_hex to parse hex string.
Use struct action_prog_data to store parsed result.

Example:

Action with 2 arguments:

"prog name action0 arguments field0 03FF field1 55AA end"

Action without argument:

"prog name action1"

Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
---

v2:
- fix title
- minor coding style refine.

 app/test-pmd/cmdline_flow.c | 230 ++++++++++++++++++++++++++++++++++++
 1 file changed, 230 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 21828c144c..c11b756360 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -719,6 +719,13 @@ enum index {
 	ACTION_IPV6_EXT_PUSH,
 	ACTION_IPV6_EXT_PUSH_INDEX,
 	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
+	ACTION_PROG,
+	ACTION_PROG_NAME,
+	ACTION_PROG_NAME_STRING,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_PROG_ARG_NAME,
+	ACTION_PROG_ARG_VALUE,
+	ACTION_PROG_ARG_END,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -749,6 +756,19 @@ struct action_rss_data {
 	uint16_t queue[ACTION_RSS_QUEUE_NUM];
 };
 
+#define ACTION_PROG_NAME_SIZE_MAX 32
+#define ACTION_PROG_ARG_NUM_MAX 8
+#define ACTION_PROG_ARG_VALUE_SIZE_MAX 16
+
+/** Storage for struct rte_flow_action_prog including external data. */
+struct action_prog_data {
+	struct rte_flow_action_prog conf;
+	char name[ACTION_PROG_NAME_SIZE_MAX];
+	struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX];
+	char arg_names[ACTION_PROG_ARG_NUM_MAX][ACTION_PROG_NAME_SIZE_MAX];
+	uint8_t value[ACTION_PROG_ARG_NUM_MAX][ACTION_PROG_ARG_VALUE_SIZE_MAX];
+};
+
 /** Maximum data size in struct rte_flow_action_raw_encap. */
 #define ACTION_RAW_ENCAP_MAX_DATA 512
 #define RAW_ENCAP_CONFS_MAX_NUM 8
@@ -2169,6 +2189,7 @@ static const enum index next_action[] = {
 	ACTION_QUOTA_QU,
 	ACTION_IPV6_EXT_REMOVE,
 	ACTION_IPV6_EXT_PUSH,
+	ACTION_PROG,
 	ZERO,
 };
 
@@ -2510,6 +2531,13 @@ static const enum index action_represented_port[] = {
 	ZERO,
 };
 
+static const enum index action_prog[] = {
+	ACTION_PROG_NAME,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_NEXT,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -2786,6 +2814,18 @@ static int
 parse_qu_mode_name(struct context *ctx, const struct token *token,
 		   const char *str, unsigned int len, void *buf,
 		   unsigned int size);
+static int
+parse_vc_action_prog(struct context *, const struct token *,
+		     const char *, unsigned int, void *,
+		     unsigned int);
+static int
+parse_vc_action_prog_arg_name(struct context *, const struct token *,
+			      const char *, unsigned int, void *,
+			      unsigned int);
+static int
+parse_vc_action_prog_arg_value(struct context *, const struct token *,
+			       const char *, unsigned int, void *,
+			       unsigned int);
 static int comp_none(struct context *, const struct token *,
 		     unsigned int, char *, unsigned int);
 static int comp_boolean(struct context *, const struct token *,
@@ -7518,6 +7558,48 @@ static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
 					tx_queue)),
 	},
+	[ACTION_PROG] = {
+		.name = "prog",
+		.help = "match a programmable action",
+		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
+		.next = NEXT(action_prog),
+		.call = parse_vc_action_prog,
+	},
+	[ACTION_PROG_NAME] = {
+		.name = "name",
+		.help = "programble action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
+		.args = ARGS(ARGS_ENTRY(struct action_prog_data, name)),
+	},
+	[ACTION_PROG_NAME_STRING] = {
+		.name = "{string}",
+		.type = "STRING",
+		.help = "programmable action name string",
+		.call = parse_string0,
+	},
+	[ACTION_PROG_ARGUMENTS] = {
+		.name = "arguments",
+		.help = "programmable action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_PROG_ARG_NAME] = {
+		.name = "{string}",
+		.help = "programmable action argument name",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
+		.call = parse_vc_action_prog_arg_name,
+	},
+	[ACTION_PROG_ARG_VALUE] = {
+		.name = "{hex}",
+		.help = "programmable action argument value",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END, ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_action_prog_arg_value,
+	},
+	[ACTION_PROG_ARG_END] = {
+		.name = "end",
+		.help = "end of the programmable action arguments",
+	},
+
 };
 
 /** Remove and return last entry from argument stack. */
@@ -11675,6 +11757,154 @@ parse_qu_mode_name(struct context *ctx, const struct token *token,
 				   (uint32_t *)&out->args.ia.qu_mode);
 }
 
+/** Parse prog action. */
+static int
+parse_vc_action_prog(struct context *ctx, const struct token *token,
+		     const char *str, unsigned int len,
+		     void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_prog_data *action_prog_data;
+	uint16_t i;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+
+	if (!out)
+		return ret;
+
+	if (!out->args.vc.actions_n)
+		return -1;
+
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	ctx->object = out->args.vc.data;
+	action_prog_data = ctx->object;
+	*action_prog_data = (struct action_prog_data) {
+		.conf = (struct rte_flow_action_prog) {
+			.args_num = 0,
+			.name = action_prog_data->name,
+			.args = action_prog_data->args,
+		},
+	};
+
+	for (i = 0; i < ACTION_PROG_ARG_NUM_MAX; ++i)
+		action_prog_data->args[i].name = action_prog_data->arg_names[i];
+	action->conf = &action_prog_data->conf;
+
+	return ret;
+}
+
+static int
+parse_vc_action_prog_arg_name(struct context *ctx, const struct token *token,
+			      const char *str, unsigned int len,
+			      void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	struct buffer *out = buf;
+	const struct arg *arg;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_NAME)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	if (i >= ACTION_PROG_ARG_NUM_MAX)
+		return -1;
+
+	arg = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, arg_names) +
+				      i * ACTION_PROG_NAME_SIZE_MAX,
+				      ACTION_PROG_NAME_SIZE_MAX);
+
+	if (push_args(ctx, arg))
+		return -1;
+
+	ret = parse_string0(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	return len;
+}
+
+static int
+parse_vc_action_prog_arg_value(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	const struct arg *arg_addr;
+	const struct arg *arg_size;
+	const struct arg *arg_data;
+	struct buffer *out = buf;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_VALUE)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	arg_addr  = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, args) +
+				   i * sizeof(struct rte_flow_action_prog_argument) +
+				   offsetof(struct rte_flow_action_prog_argument, value),
+				   sizeof(action_prog_data->args[i].value));
+
+	arg_size = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, args) +
+					   i * sizeof(struct rte_flow_action_prog_argument) +
+					   offsetof(struct rte_flow_action_prog_argument, size),
+					   sizeof(action_prog_data->args[i].size));
+
+	arg_data = ARGS_ENTRY_ARB(offsetof(struct action_prog_data, value) +
+					   i * ACTION_PROG_ARG_VALUE_SIZE_MAX,
+					   ACTION_PROG_ARG_VALUE_SIZE_MAX);
+
+	if (push_args(ctx, arg_addr))
+		return -1;
+
+	if (push_args(ctx, arg_size)) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	if (push_args(ctx, arg_data)) {
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	ret = parse_hex(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	action_prog_data->conf.args_num++;
+
+	return len;
+}
+
 /** No completion. */
 static int
 comp_none(struct context *ctx, const struct token *token,
-- 
2.31.1


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

* RE: [PATCH v2] app/testpmd: enable cli for programmable action
  2023-10-05  4:32   ` Stephen Hemminger
@ 2023-10-06  2:37     ` Zhang, Qi Z
  0 siblings, 0 replies; 20+ messages in thread
From: Zhang, Qi Z @ 2023-10-06  2:37 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Singh, Aman Deep, Zhang, Yuying, dev, Dumitrescu, Cristian,
	orika, ferruh.yigit



> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Thursday, October 5, 2023 12:32 PM
> To: Zhang, Qi Z <qi.z.zhang@intel.com>
> Cc: Singh, Aman Deep <aman.deep.singh@intel.com>; Zhang, Yuying
> <yuying.zhang@intel.com>; dev@dpdk.org; Dumitrescu, Cristian
> <cristian.dumitrescu@intel.com>; orika@nvidia.com; ferruh.yigit@amd.com
> Subject: Re: [PATCH v2] app/testpmd: enable cli for programmable action
> 
> On Thu,  5 Oct 2023 07:42:38 -0400
> Qi Zhang <qi.z.zhang@intel.com> wrote:
> 
> > +	char name[ACTION_PROG_NAME_SIZE_MAX];
> > +	struct rte_flow_action_prog_argument
> args[ACTION_PROG_ARG_NUM_MAX];
> > +	char
> arg_names[ACTION_PROG_ARG_NUM_MAX][ACTION_PROG_NAME_SIZE_MAX
> ];
> > +	uint8_t
> value[ACTION_PROG_ARG_NUM_MAX][ACTION_PROG_ARG_VALUE_SIZE_MAX
> ];
> > +};
> > +
> 
> IMHO if you have this many array elements the data structure makes more
> sense as.
> 
> 	struct flow_arg {
> 		char name[ACTION_PROG_NAME_SIZE_MAX];
> 		struct {
> 			struct rte_flow_prog_argument prog;
> 			char names[ACTION_PROG_NAME_SIZE_MAX];
> 			uint8_t value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
> 		} args[ACTION_PROG_ARG_NUM_MAX];
> 	};
> 

The memory of rte_flow_action_prog_argument need to be continues due to the definition of rte_flow_action_prog.

But follow your idea, it still can be refined as below to get a better view.

struct action_prog_data {
        struct rte_flow_action_prog conf;
        struct {
                char name[ACTION_PROG_NAME_SIZE_MAX];
                struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX];
                struct {
                        char names[ACTION_PROG_NAME_SIZE_MAX];
                        uint8_t value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
                } arg_data[ACTION_PROG_ARG_NUM_MAX];
        } data;
};


> Or better yet get rid of PROG_ARG_NUM_MAX and use a flex array.

My understanding is to make the array flex will introduce additional complexity, currently fixed size data structure is required to be allocated for parser buffer for all action commands
Also to support variant size at runtime, we may introduce another testpmd parameter which seems a little bit overused to me.

> Somebody will want more than 8 args.

Sure, I can made it bigger.

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

* [PATCH v3] app/testpmd: enable cli for programmable action
  2023-10-05 10:02 [PATCH 1/2] app/testpmd: enable cli for programmable action Qi Zhang
  2023-10-05 11:42 ` [PATCH v2] " Qi Zhang
@ 2023-10-06 11:07 ` Qi Zhang
  2023-10-06 12:35   ` Dumitrescu, Cristian
  2023-10-07 10:47 ` [PATCH v4] " Qi Zhang
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Qi Zhang @ 2023-10-06 11:07 UTC (permalink / raw)
  To: aman.deep.singh, yuying.zhang
  Cc: dev, cristian.dumitrescu, orika, ferruh.yigit, Qi Zhang

Parsing command line for rte_flow_action_prog.

Syntax:

"prog name <name> [arguments <arg_name_0> <arg_value_0> \
 <arg_name_1> <arg_value1> ... end]"

Use parse_string0 to parse name string.
Use parse_hex to parse hex string.
Use struct action_prog_data to store parsed result.

Example:

Action with 2 arguments:

"prog name action0 arguments field0 03FF field1 55AA end"

Action without argument:

"prog name action1"

Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
---

v3:
- refine struct action_prog_data
- enlarge the max size

v2:
- fix title
- minor coding style refine.

 app/test-pmd/cmdline_flow.c | 232 ++++++++++++++++++++++++++++++++++++
 1 file changed, 232 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 21828c144c..7b40b988ae 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -719,6 +719,13 @@ enum index {
 	ACTION_IPV6_EXT_PUSH,
 	ACTION_IPV6_EXT_PUSH_INDEX,
 	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
+	ACTION_PROG,
+	ACTION_PROG_NAME,
+	ACTION_PROG_NAME_STRING,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_PROG_ARG_NAME,
+	ACTION_PROG_ARG_VALUE,
+	ACTION_PROG_ARG_END,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -749,6 +756,23 @@ struct action_rss_data {
 	uint16_t queue[ACTION_RSS_QUEUE_NUM];
 };
 
+#define ACTION_PROG_NAME_SIZE_MAX 32
+#define ACTION_PROG_ARG_NUM_MAX 16
+#define ACTION_PROG_ARG_VALUE_SIZE_MAX 32
+
+/** Storage for struct rte_flow_action_prog including external data. */
+struct action_prog_data {
+	struct rte_flow_action_prog conf;
+	struct {
+		char name[ACTION_PROG_NAME_SIZE_MAX];
+		struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX];
+		struct {
+			char names[ACTION_PROG_NAME_SIZE_MAX];
+			uint8_t value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
+		} arg_data[ACTION_PROG_ARG_NUM_MAX];
+	} data;
+};
+
 /** Maximum data size in struct rte_flow_action_raw_encap. */
 #define ACTION_RAW_ENCAP_MAX_DATA 512
 #define RAW_ENCAP_CONFS_MAX_NUM 8
@@ -2169,6 +2193,7 @@ static const enum index next_action[] = {
 	ACTION_QUOTA_QU,
 	ACTION_IPV6_EXT_REMOVE,
 	ACTION_IPV6_EXT_PUSH,
+	ACTION_PROG,
 	ZERO,
 };
 
@@ -2510,6 +2535,13 @@ static const enum index action_represented_port[] = {
 	ZERO,
 };
 
+static const enum index action_prog[] = {
+	ACTION_PROG_NAME,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_NEXT,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -2786,6 +2818,18 @@ static int
 parse_qu_mode_name(struct context *ctx, const struct token *token,
 		   const char *str, unsigned int len, void *buf,
 		   unsigned int size);
+static int
+parse_vc_action_prog(struct context *, const struct token *,
+		     const char *, unsigned int, void *,
+		     unsigned int);
+static int
+parse_vc_action_prog_arg_name(struct context *, const struct token *,
+			      const char *, unsigned int, void *,
+			      unsigned int);
+static int
+parse_vc_action_prog_arg_value(struct context *, const struct token *,
+			       const char *, unsigned int, void *,
+			       unsigned int);
 static int comp_none(struct context *, const struct token *,
 		     unsigned int, char *, unsigned int);
 static int comp_boolean(struct context *, const struct token *,
@@ -7518,6 +7562,48 @@ static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
 					tx_queue)),
 	},
+	[ACTION_PROG] = {
+		.name = "prog",
+		.help = "match a programmable action",
+		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
+		.next = NEXT(action_prog),
+		.call = parse_vc_action_prog,
+	},
+	[ACTION_PROG_NAME] = {
+		.name = "name",
+		.help = "programble action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
+		.args = ARGS(ARGS_ENTRY(struct action_prog_data, data.name)),
+	},
+	[ACTION_PROG_NAME_STRING] = {
+		.name = "{string}",
+		.type = "STRING",
+		.help = "programmable action name string",
+		.call = parse_string0,
+	},
+	[ACTION_PROG_ARGUMENTS] = {
+		.name = "arguments",
+		.help = "programmable action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_PROG_ARG_NAME] = {
+		.name = "{string}",
+		.help = "programmable action argument name",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
+		.call = parse_vc_action_prog_arg_name,
+	},
+	[ACTION_PROG_ARG_VALUE] = {
+		.name = "{hex}",
+		.help = "programmable action argument value",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END, ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_action_prog_arg_value,
+	},
+	[ACTION_PROG_ARG_END] = {
+		.name = "end",
+		.help = "end of the programmable action arguments",
+	},
+
 };
 
 /** Remove and return last entry from argument stack. */
@@ -11675,6 +11761,152 @@ parse_qu_mode_name(struct context *ctx, const struct token *token,
 				   (uint32_t *)&out->args.ia.qu_mode);
 }
 
+/** Parse prog action. */
+static int
+parse_vc_action_prog(struct context *ctx, const struct token *token,
+		     const char *str, unsigned int len,
+		     void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_prog_data *action_prog_data;
+	uint16_t i;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+
+	if (!out)
+		return ret;
+
+	if (!out->args.vc.actions_n)
+		return -1;
+
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	ctx->object = out->args.vc.data;
+	action_prog_data = ctx->object;
+	*action_prog_data = (struct action_prog_data) {
+		.conf = (struct rte_flow_action_prog) {
+			.args_num = 0,
+			.name = action_prog_data->data.name,
+			.args = action_prog_data->data.args,
+		},
+	};
+
+	for (i = 0; i < ACTION_PROG_ARG_NUM_MAX; ++i)
+		action_prog_data->data.args[i].name = action_prog_data->data.arg_data[i].names;
+	action->conf = &action_prog_data->conf;
+
+	return ret;
+}
+
+static int
+parse_vc_action_prog_arg_name(struct context *ctx, const struct token *token,
+			      const char *str, unsigned int len,
+			      void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	struct buffer *out = buf;
+	const struct arg *arg;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_NAME)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	if (i >= ACTION_PROG_ARG_NUM_MAX)
+		return -1;
+
+	arg = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+				      data.arg_data[i].names),
+			     ACTION_PROG_NAME_SIZE_MAX);
+
+	if (push_args(ctx, arg))
+		return -1;
+
+	ret = parse_string0(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	return len;
+}
+
+static int
+parse_vc_action_prog_arg_value(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	const struct arg *arg_addr;
+	const struct arg *arg_size;
+	const struct arg *arg_data;
+	struct buffer *out = buf;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_VALUE)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	arg_addr  = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					    data.args[i].value),
+				   sizeof(action_prog_data->data.args[i].value));
+
+	arg_size = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					   data.args[i].size),
+				   sizeof(action_prog_data->data.args[i].size));
+
+	arg_data = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					   data.arg_data[i].value),
+				  ACTION_PROG_ARG_VALUE_SIZE_MAX);
+
+	if (push_args(ctx, arg_addr))
+		return -1;
+
+	if (push_args(ctx, arg_size)) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	if (push_args(ctx, arg_data)) {
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	ret = parse_hex(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	action_prog_data->conf.args_num++;
+
+	return len;
+}
+
 /** No completion. */
 static int
 comp_none(struct context *ctx, const struct token *token,
-- 
2.31.1


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

* RE: [PATCH v3] app/testpmd: enable cli for programmable action
  2023-10-06 11:07 ` [PATCH v3] " Qi Zhang
@ 2023-10-06 12:35   ` Dumitrescu, Cristian
  2023-10-07  1:50     ` Zhang, Qi Z
  0 siblings, 1 reply; 20+ messages in thread
From: Dumitrescu, Cristian @ 2023-10-06 12:35 UTC (permalink / raw)
  To: Zhang, Qi Z, Singh, Aman Deep, Zhang, Yuying; +Cc: dev, orika, ferruh.yigit


Hi Qi,

<snip>

> 
> +#define ACTION_PROG_NAME_SIZE_MAX 32
> +#define ACTION_PROG_ARG_NUM_MAX 16
> +#define ACTION_PROG_ARG_VALUE_SIZE_MAX 32

Let's be a bit more generous with some of these sizes, please.

The action name might be hierarchical, i.e. include the control block and table path separated by dots, e.g. "dev5.ingress.forwarding.routing_table.set_next_hop", so:
#define ACTION_PROG_NAME_SIZE_MAX 256

Some parameters could be 128-bit IPv6 addresses, which may be specified in hex with additional characters such as '0x' or ':', so:
#define ACTION_PROG_ARG_VALUE_SIZE_MAX 64

<snip>

Regards,
Cristian

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

* RE: [PATCH v3] app/testpmd: enable cli for programmable action
  2023-10-06 12:35   ` Dumitrescu, Cristian
@ 2023-10-07  1:50     ` Zhang, Qi Z
  0 siblings, 0 replies; 20+ messages in thread
From: Zhang, Qi Z @ 2023-10-07  1:50 UTC (permalink / raw)
  To: Dumitrescu, Cristian, Singh, Aman Deep, Zhang, Yuying
  Cc: dev, orika, ferruh.yigit



> -----Original Message-----
> From: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Sent: Friday, October 6, 2023 8:36 PM
> To: Zhang, Qi Z <qi.z.zhang@intel.com>; Singh, Aman Deep
> <aman.deep.singh@intel.com>; Zhang, Yuying <yuying.zhang@intel.com>
> Cc: dev@dpdk.org; orika@nvidia.com; ferruh.yigit@amd.com
> Subject: RE: [PATCH v3] app/testpmd: enable cli for programmable action
> 
> 
> Hi Qi,
> 
> <snip>
> 
> >
> > +#define ACTION_PROG_NAME_SIZE_MAX 32
> > +#define ACTION_PROG_ARG_NUM_MAX 16
> > +#define ACTION_PROG_ARG_VALUE_SIZE_MAX 32
> 
> Let's be a bit more generous with some of these sizes, please.
> 
> The action name might be hierarchical, i.e. include the control block and table
> path separated by dots, e.g.
> "dev5.ingress.forwarding.routing_table.set_next_hop", so:
> #define ACTION_PROG_NAME_SIZE_MAX 256
> 
> Some parameters could be 128-bit IPv6 addresses, which may be specified in
> hex with additional characters such as '0x' or ':', so:
> #define ACTION_PROG_ARG_VALUE_SIZE_MAX 64
> 
> <snip>

Yes, definitely we may need to support a larger name and value from p4, I will fix that, thanks.

> 
> Regards,
> Cristian

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

* [PATCH v4] app/testpmd: enable cli for programmable action
  2023-10-05 10:02 [PATCH 1/2] app/testpmd: enable cli for programmable action Qi Zhang
  2023-10-05 11:42 ` [PATCH v2] " Qi Zhang
  2023-10-06 11:07 ` [PATCH v3] " Qi Zhang
@ 2023-10-07 10:47 ` Qi Zhang
  2023-10-08  0:06   ` Dumitrescu, Cristian
  2023-10-10 10:49   ` Ferruh Yigit
  2023-10-11 11:58 ` [PATCH v5] " Qi Zhang
  2023-10-11 12:03 ` [PATCH v6] " Qi Zhang
  4 siblings, 2 replies; 20+ messages in thread
From: Qi Zhang @ 2023-10-07 10:47 UTC (permalink / raw)
  To: aman.deep.singh, yuying.zhang
  Cc: dev, cristian.dumitrescu, orika, ferruh.yigit, Qi Zhang

Parsing command line for rte_flow_action_prog.

Syntax:

"prog name <name> [arguments <arg_name_0> <arg_value_0> \
 <arg_name_1> <arg_value1> ... end]"

Use parse_string0 to parse name string.
Use parse_hex to parse hex string.
Use struct action_prog_data to store parsed result.

Example:

Action with 2 arguments:

"prog name action0 arguments field0 03FF field1 55AA end"

Action without argument:

"prog name action1"

Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
---

v4:
- be more generous on the max size of name and value.

v3:
- refine struct action_prog_data
- enlarge the max size

v2:
- fix title
- minor coding style refine.

 app/test-pmd/cmdline_flow.c | 232 ++++++++++++++++++++++++++++++++++++
 1 file changed, 232 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 21828c144c..ae5556e704 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -719,6 +719,13 @@ enum index {
 	ACTION_IPV6_EXT_PUSH,
 	ACTION_IPV6_EXT_PUSH_INDEX,
 	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
+	ACTION_PROG,
+	ACTION_PROG_NAME,
+	ACTION_PROG_NAME_STRING,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_PROG_ARG_NAME,
+	ACTION_PROG_ARG_VALUE,
+	ACTION_PROG_ARG_END,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -749,6 +756,23 @@ struct action_rss_data {
 	uint16_t queue[ACTION_RSS_QUEUE_NUM];
 };
 
+#define ACTION_PROG_NAME_SIZE_MAX 256
+#define ACTION_PROG_ARG_NUM_MAX 16
+#define ACTION_PROG_ARG_VALUE_SIZE_MAX 64
+
+/** Storage for struct rte_flow_action_prog including external data. */
+struct action_prog_data {
+	struct rte_flow_action_prog conf;
+	struct {
+		char name[ACTION_PROG_NAME_SIZE_MAX];
+		struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX];
+		struct {
+			char names[ACTION_PROG_NAME_SIZE_MAX];
+			uint8_t value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
+		} arg_data[ACTION_PROG_ARG_NUM_MAX];
+	} data;
+};
+
 /** Maximum data size in struct rte_flow_action_raw_encap. */
 #define ACTION_RAW_ENCAP_MAX_DATA 512
 #define RAW_ENCAP_CONFS_MAX_NUM 8
@@ -2169,6 +2193,7 @@ static const enum index next_action[] = {
 	ACTION_QUOTA_QU,
 	ACTION_IPV6_EXT_REMOVE,
 	ACTION_IPV6_EXT_PUSH,
+	ACTION_PROG,
 	ZERO,
 };
 
@@ -2510,6 +2535,13 @@ static const enum index action_represented_port[] = {
 	ZERO,
 };
 
+static const enum index action_prog[] = {
+	ACTION_PROG_NAME,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_NEXT,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -2786,6 +2818,18 @@ static int
 parse_qu_mode_name(struct context *ctx, const struct token *token,
 		   const char *str, unsigned int len, void *buf,
 		   unsigned int size);
+static int
+parse_vc_action_prog(struct context *, const struct token *,
+		     const char *, unsigned int, void *,
+		     unsigned int);
+static int
+parse_vc_action_prog_arg_name(struct context *, const struct token *,
+			      const char *, unsigned int, void *,
+			      unsigned int);
+static int
+parse_vc_action_prog_arg_value(struct context *, const struct token *,
+			       const char *, unsigned int, void *,
+			       unsigned int);
 static int comp_none(struct context *, const struct token *,
 		     unsigned int, char *, unsigned int);
 static int comp_boolean(struct context *, const struct token *,
@@ -7518,6 +7562,48 @@ static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
 					tx_queue)),
 	},
+	[ACTION_PROG] = {
+		.name = "prog",
+		.help = "match a programmable action",
+		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
+		.next = NEXT(action_prog),
+		.call = parse_vc_action_prog,
+	},
+	[ACTION_PROG_NAME] = {
+		.name = "name",
+		.help = "programble action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
+		.args = ARGS(ARGS_ENTRY(struct action_prog_data, data.name)),
+	},
+	[ACTION_PROG_NAME_STRING] = {
+		.name = "{string}",
+		.type = "STRING",
+		.help = "programmable action name string",
+		.call = parse_string0,
+	},
+	[ACTION_PROG_ARGUMENTS] = {
+		.name = "arguments",
+		.help = "programmable action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_PROG_ARG_NAME] = {
+		.name = "{string}",
+		.help = "programmable action argument name",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
+		.call = parse_vc_action_prog_arg_name,
+	},
+	[ACTION_PROG_ARG_VALUE] = {
+		.name = "{hex}",
+		.help = "programmable action argument value",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END, ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_action_prog_arg_value,
+	},
+	[ACTION_PROG_ARG_END] = {
+		.name = "end",
+		.help = "end of the programmable action arguments",
+	},
+
 };
 
 /** Remove and return last entry from argument stack. */
@@ -11675,6 +11761,152 @@ parse_qu_mode_name(struct context *ctx, const struct token *token,
 				   (uint32_t *)&out->args.ia.qu_mode);
 }
 
+/** Parse prog action. */
+static int
+parse_vc_action_prog(struct context *ctx, const struct token *token,
+		     const char *str, unsigned int len,
+		     void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_prog_data *action_prog_data;
+	uint16_t i;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+
+	if (!out)
+		return ret;
+
+	if (!out->args.vc.actions_n)
+		return -1;
+
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	ctx->object = out->args.vc.data;
+	action_prog_data = ctx->object;
+	*action_prog_data = (struct action_prog_data) {
+		.conf = (struct rte_flow_action_prog) {
+			.args_num = 0,
+			.name = action_prog_data->data.name,
+			.args = action_prog_data->data.args,
+		},
+	};
+
+	for (i = 0; i < ACTION_PROG_ARG_NUM_MAX; ++i)
+		action_prog_data->data.args[i].name = action_prog_data->data.arg_data[i].names;
+	action->conf = &action_prog_data->conf;
+
+	return ret;
+}
+
+static int
+parse_vc_action_prog_arg_name(struct context *ctx, const struct token *token,
+			      const char *str, unsigned int len,
+			      void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	struct buffer *out = buf;
+	const struct arg *arg;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_NAME)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	if (i >= ACTION_PROG_ARG_NUM_MAX)
+		return -1;
+
+	arg = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+				      data.arg_data[i].names),
+			     ACTION_PROG_NAME_SIZE_MAX);
+
+	if (push_args(ctx, arg))
+		return -1;
+
+	ret = parse_string0(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	return len;
+}
+
+static int
+parse_vc_action_prog_arg_value(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	const struct arg *arg_addr;
+	const struct arg *arg_size;
+	const struct arg *arg_data;
+	struct buffer *out = buf;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_VALUE)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	arg_addr  = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					    data.args[i].value),
+				   sizeof(action_prog_data->data.args[i].value));
+
+	arg_size = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					   data.args[i].size),
+				   sizeof(action_prog_data->data.args[i].size));
+
+	arg_data = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					   data.arg_data[i].value),
+				  ACTION_PROG_ARG_VALUE_SIZE_MAX);
+
+	if (push_args(ctx, arg_addr))
+		return -1;
+
+	if (push_args(ctx, arg_size)) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	if (push_args(ctx, arg_data)) {
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	ret = parse_hex(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	action_prog_data->conf.args_num++;
+
+	return len;
+}
+
 /** No completion. */
 static int
 comp_none(struct context *ctx, const struct token *token,
-- 
2.31.1


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

* RE: [PATCH v4] app/testpmd: enable cli for programmable action
  2023-10-07 10:47 ` [PATCH v4] " Qi Zhang
@ 2023-10-08  0:06   ` Dumitrescu, Cristian
  2023-10-10 10:49   ` Ferruh Yigit
  1 sibling, 0 replies; 20+ messages in thread
From: Dumitrescu, Cristian @ 2023-10-08  0:06 UTC (permalink / raw)
  To: Zhang, Qi Z, Singh, Aman Deep, Zhang, Yuying; +Cc: dev, orika, ferruh.yigit



> -----Original Message-----
> From: Zhang, Qi Z <qi.z.zhang@intel.com>
> Sent: Saturday, October 7, 2023 11:48 AM
> To: Singh, Aman Deep <aman.deep.singh@intel.com>; Zhang, Yuying
> <yuying.zhang@intel.com>
> Cc: dev@dpdk.org; Dumitrescu, Cristian <cristian.dumitrescu@intel.com>;
> orika@nvidia.com; ferruh.yigit@amd.com; Zhang, Qi Z <qi.z.zhang@intel.com>
> Subject: [PATCH v4] app/testpmd: enable cli for programmable action
> 
> Parsing command line for rte_flow_action_prog.
> 
> Syntax:
> 
> "prog name <name> [arguments <arg_name_0> <arg_value_0> \
>  <arg_name_1> <arg_value1> ... end]"
> 
> Use parse_string0 to parse name string.
> Use parse_hex to parse hex string.
> Use struct action_prog_data to store parsed result.
> 
> Example:
> 
> Action with 2 arguments:
> 
> "prog name action0 arguments field0 03FF field1 55AA end"
> 
> Action without argument:
> 
> "prog name action1"
> 
> Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
> ---
> 
> v4:
> - be more generous on the max size of name and value.

Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>


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

* Re: [PATCH v4] app/testpmd: enable cli for programmable action
  2023-10-07 10:47 ` [PATCH v4] " Qi Zhang
  2023-10-08  0:06   ` Dumitrescu, Cristian
@ 2023-10-10 10:49   ` Ferruh Yigit
  2023-10-11  2:24     ` Zhang, Qi Z
  1 sibling, 1 reply; 20+ messages in thread
From: Ferruh Yigit @ 2023-10-10 10:49 UTC (permalink / raw)
  To: Qi Zhang, aman.deep.singh, yuying.zhang; +Cc: dev, cristian.dumitrescu, orika

On 10/7/2023 11:47 AM, Qi Zhang wrote:
> Parsing command line for rte_flow_action_prog.
> 
> Syntax:
> 
> "prog name <name> [arguments <arg_name_0> <arg_value_0> \
>  <arg_name_1> <arg_value1> ... end]"
> 

Can you please put full rte flow command in the commit log? Like what is
the 'pattern' for above command?


> Use parse_string0 to parse name string.
> Use parse_hex to parse hex string.
> Use struct action_prog_data to store parsed result.
> 
> Example:
> 
> Action with 2 arguments:
> 
> "prog name action0 arguments field0 03FF field1 55AA end"
> 
> Action without argument:
> 
> "prog name action1"
> 
> Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
>

Is there an existing driver implementation, checking it helps to
understand feature implementation?


> ---
> 
> v4:
> - be more generous on the max size of name and value.
> 
> v3:
> - refine struct action_prog_data
> - enlarge the max size
> 
> v2:
> - fix title
> - minor coding style refine.
> 
>  app/test-pmd/cmdline_flow.c | 232 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 232 insertions(+)
> 

Hi Qi,

Can you please update documentation too,
`doc/guides/testpmd_app_ug/testpmd_funcs.rst`, `Flow rules management`
section.


> diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
> index 21828c144c..ae5556e704 100644
> --- a/app/test-pmd/cmdline_flow.c
> +++ b/app/test-pmd/cmdline_flow.c
> @@ -719,6 +719,13 @@ enum index {
>  	ACTION_IPV6_EXT_PUSH,
>  	ACTION_IPV6_EXT_PUSH_INDEX,
>  	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
> +	ACTION_PROG,
> +	ACTION_PROG_NAME,
> +	ACTION_PROG_NAME_STRING,
> +	ACTION_PROG_ARGUMENTS,
> +	ACTION_PROG_ARG_NAME,
> +	ACTION_PROG_ARG_VALUE,
> +	ACTION_PROG_ARG_END,
>  };
>  
>  /** Maximum size for pattern in struct rte_flow_item_raw. */
> @@ -749,6 +756,23 @@ struct action_rss_data {
>  	uint16_t queue[ACTION_RSS_QUEUE_NUM];
>  };
>  
> +#define ACTION_PROG_NAME_SIZE_MAX 256
> +#define ACTION_PROG_ARG_NUM_MAX 16
> +#define ACTION_PROG_ARG_VALUE_SIZE_MAX 64
> +
> +/** Storage for struct rte_flow_action_prog including external data. */
> +struct action_prog_data {
> +	struct rte_flow_action_prog conf;
> +	struct {
> +		char name[ACTION_PROG_NAME_SIZE_MAX];
> +		struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX];
> +		struct {
> +			char names[ACTION_PROG_NAME_SIZE_MAX];
> +			uint8_t value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
> +		} arg_data[ACTION_PROG_ARG_NUM_MAX];
> +	} data;
> +};
> +
>  /** Maximum data size in struct rte_flow_action_raw_encap. */
>  #define ACTION_RAW_ENCAP_MAX_DATA 512
>  #define RAW_ENCAP_CONFS_MAX_NUM 8
> @@ -2169,6 +2193,7 @@ static const enum index next_action[] = {
>  	ACTION_QUOTA_QU,
>  	ACTION_IPV6_EXT_REMOVE,
>  	ACTION_IPV6_EXT_PUSH,
> +	ACTION_PROG,
>  	ZERO,
>  };
>  
> @@ -2510,6 +2535,13 @@ static const enum index action_represented_port[] = {
>  	ZERO,
>  };
>  
> +static const enum index action_prog[] = {
> +	ACTION_PROG_NAME,
> +	ACTION_PROG_ARGUMENTS,
> +	ACTION_NEXT,
> +	ZERO,
> +};
> +
>  static int parse_set_raw_encap_decap(struct context *, const struct token *,
>  				     const char *, unsigned int,
>  				     void *, unsigned int);
> @@ -2786,6 +2818,18 @@ static int
>  parse_qu_mode_name(struct context *ctx, const struct token *token,
>  		   const char *str, unsigned int len, void *buf,
>  		   unsigned int size);
> +static int
> +parse_vc_action_prog(struct context *, const struct token *,
> +		     const char *, unsigned int, void *,
> +		     unsigned int);
> +static int
> +parse_vc_action_prog_arg_name(struct context *, const struct token *,
> +			      const char *, unsigned int, void *,
> +			      unsigned int);
> +static int
> +parse_vc_action_prog_arg_value(struct context *, const struct token *,
> +			       const char *, unsigned int, void *,
> +			       unsigned int);
>  static int comp_none(struct context *, const struct token *,
>  		     unsigned int, char *, unsigned int);
>  static int comp_boolean(struct context *, const struct token *,
> @@ -7518,6 +7562,48 @@ static const struct token token_list[] = {
>  		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
>  					tx_queue)),
>  	},
> +	[ACTION_PROG] = {
> +		.name = "prog",
> +		.help = "match a programmable action",
> +		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
> +		.next = NEXT(action_prog),
> +		.call = parse_vc_action_prog,
> +	},
> +	[ACTION_PROG_NAME] = {
> +		.name = "name",
> +		.help = "programble action name",
>

Can you please remind me again what was the 'name' filed of "struct
rte_flow_action_prog" was for?


> +		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
> +		.args = ARGS(ARGS_ENTRY(struct action_prog_data, data.name)),
> +	},
> +	[ACTION_PROG_NAME_STRING] = {
> +		.name = "{string}",
> +		.type = "STRING",
> +		.help = "programmable action name string",
> +		.call = parse_string0,
> +	},
> +	[ACTION_PROG_ARGUMENTS] = {
> +		.name = "arguments",
> +		.help = "programmable action name",
> +		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
> +		.call = parse_vc_conf,
> +	},
> +	[ACTION_PROG_ARG_NAME] = {
> +		.name = "{string}",
> +		.help = "programmable action argument name",
> +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
> +		.call = parse_vc_action_prog_arg_name,
> +	},
> +	[ACTION_PROG_ARG_VALUE] = {
> +		.name = "{hex}",
> +		.help = "programmable action argument value",
> +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END, ACTION_PROG_ARG_NAME)),
> +		.call = parse_vc_action_prog_arg_value,
> +	},
> +	[ACTION_PROG_ARG_END] = {
> +		.name = "end",
> +		.help = "end of the programmable action arguments",
> +	},
> +
>

Does this means two 'end' required if multiple args provided, like:
prog name "name" arguments field0 03FF field1 1 end / end

I am aware there is variable length of key/value, and need a marker to
stop, but this end specific for action is not used, I wonder if that is
because there is a better way to do it, @Ori may comment better.




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

* RE: [PATCH v4] app/testpmd: enable cli for programmable action
  2023-10-10 10:49   ` Ferruh Yigit
@ 2023-10-11  2:24     ` Zhang, Qi Z
  2023-10-11 10:20       ` Ferruh Yigit
  0 siblings, 1 reply; 20+ messages in thread
From: Zhang, Qi Z @ 2023-10-11  2:24 UTC (permalink / raw)
  To: Ferruh Yigit, Singh, Aman Deep, Zhang, Yuying
  Cc: dev, Dumitrescu, Cristian, orika


> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@amd.com>
> Sent: Tuesday, October 10, 2023 6:49 PM
> To: Zhang, Qi Z <qi.z.zhang@intel.com>; Singh, Aman Deep
> <aman.deep.singh@intel.com>; Zhang, Yuying <yuying.zhang@intel.com>
> Cc: dev@dpdk.org; Dumitrescu, Cristian <cristian.dumitrescu@intel.com>;
> orika@nvidia.com
> Subject: Re: [PATCH v4] app/testpmd: enable cli for programmable action
> 
> On 10/7/2023 11:47 AM, Qi Zhang wrote:
> > Parsing command line for rte_flow_action_prog.
> >
> > Syntax:
> >
> > "prog name <name> [arguments <arg_name_0> <arg_value_0> \
> > <arg_name_1> <arg_value1> ... end]"
> >
> 
> Can you please put full rte flow command in the commit log? Like what is the
> 'pattern' for above command?

The pattern part should be independent of the action part,

though for our P4 device, we will prefer use rte_flow_flex_item, something like:

flow create 0 pattern flex item is xxx pattern is xxx / flex item is xxx pattern is / actions prog name ......

but it does not limit PMD to support flow like below

flow create 0 pattern eth / ipv4 src is 1.1.1.1 / actions prog name ......

So I think it may not be necessary to highlight the pattern format here.

> 
> 
> > Use parse_string0 to parse name string.
> > Use parse_hex to parse hex string.
> > Use struct action_prog_data to store parsed result.
> >
> > Example:
> >
> > Action with 2 arguments:
> >
> > "prog name action0 arguments field0 03FF field1 55AA end"
> >
> > Action without argument:
> >
> > "prog name action1"
> >
> > Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
> >
> 
> Is there an existing driver implementation, checking it helps to understand
> feature implementation?

This work is still ongoing, currently we target to upstream on DPDK 24.03

> 
> 
> > ---
> >
> > v4:
> > - be more generous on the max size of name and value.
> >
> > v3:
> > - refine struct action_prog_data
> > - enlarge the max size
> >
> > v2:
> > - fix title
> > - minor coding style refine.
> >
> >  app/test-pmd/cmdline_flow.c | 232
> > ++++++++++++++++++++++++++++++++++++
> >  1 file changed, 232 insertions(+)
> >
> 
> Hi Qi,
> 
> Can you please update documentation too,
> `doc/guides/testpmd_app_ug/testpmd_funcs.rst`, `Flow rules management`
> section.

Sure.

> 
> 
> > diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
> > index 21828c144c..ae5556e704 100644
> > --- a/app/test-pmd/cmdline_flow.c
> > +++ b/app/test-pmd/cmdline_flow.c
> > @@ -719,6 +719,13 @@ enum index {
> >  	ACTION_IPV6_EXT_PUSH,
> >  	ACTION_IPV6_EXT_PUSH_INDEX,
> >  	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
> > +	ACTION_PROG,
> > +	ACTION_PROG_NAME,
> > +	ACTION_PROG_NAME_STRING,
> > +	ACTION_PROG_ARGUMENTS,
> > +	ACTION_PROG_ARG_NAME,
> > +	ACTION_PROG_ARG_VALUE,
> > +	ACTION_PROG_ARG_END,
> >  };
> >
> >  /** Maximum size for pattern in struct rte_flow_item_raw. */ @@
> > -749,6 +756,23 @@ struct action_rss_data {
> >  	uint16_t queue[ACTION_RSS_QUEUE_NUM];  };
> >
> > +#define ACTION_PROG_NAME_SIZE_MAX 256 #define
> ACTION_PROG_ARG_NUM_MAX
> > +16 #define ACTION_PROG_ARG_VALUE_SIZE_MAX 64
> > +
> > +/** Storage for struct rte_flow_action_prog including external data.
> > +*/ struct action_prog_data {
> > +	struct rte_flow_action_prog conf;
> > +	struct {
> > +		char name[ACTION_PROG_NAME_SIZE_MAX];
> > +		struct rte_flow_action_prog_argument
> args[ACTION_PROG_ARG_NUM_MAX];
> > +		struct {
> > +			char names[ACTION_PROG_NAME_SIZE_MAX];
> > +			uint8_t
> value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
> > +		} arg_data[ACTION_PROG_ARG_NUM_MAX];
> > +	} data;
> > +};
> > +
> >  /** Maximum data size in struct rte_flow_action_raw_encap. */
> > #define ACTION_RAW_ENCAP_MAX_DATA 512  #define
> RAW_ENCAP_CONFS_MAX_NUM
> > 8 @@ -2169,6 +2193,7 @@ static const enum index next_action[] = {
> >  	ACTION_QUOTA_QU,
> >  	ACTION_IPV6_EXT_REMOVE,
> >  	ACTION_IPV6_EXT_PUSH,
> > +	ACTION_PROG,
> >  	ZERO,
> >  };
> >
> > @@ -2510,6 +2535,13 @@ static const enum index
> action_represented_port[] = {
> >  	ZERO,
> >  };
> >
> > +static const enum index action_prog[] = {
> > +	ACTION_PROG_NAME,
> > +	ACTION_PROG_ARGUMENTS,
> > +	ACTION_NEXT,
> > +	ZERO,
> > +};
> > +
> >  static int parse_set_raw_encap_decap(struct context *, const struct token *,
> >  				     const char *, unsigned int,
> >  				     void *, unsigned int);
> > @@ -2786,6 +2818,18 @@ static int
> >  parse_qu_mode_name(struct context *ctx, const struct token *token,
> >  		   const char *str, unsigned int len, void *buf,
> >  		   unsigned int size);
> > +static int
> > +parse_vc_action_prog(struct context *, const struct token *,
> > +		     const char *, unsigned int, void *,
> > +		     unsigned int);
> > +static int
> > +parse_vc_action_prog_arg_name(struct context *, const struct token *,
> > +			      const char *, unsigned int, void *,
> > +			      unsigned int);
> > +static int
> > +parse_vc_action_prog_arg_value(struct context *, const struct token *,
> > +			       const char *, unsigned int, void *,
> > +			       unsigned int);
> >  static int comp_none(struct context *, const struct token *,
> >  		     unsigned int, char *, unsigned int);  static int
> > comp_boolean(struct context *, const struct token *, @@ -7518,6
> > +7562,48 @@ static const struct token token_list[] = {
> >  		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
> >  					tx_queue)),
> >  	},
> > +	[ACTION_PROG] = {
> > +		.name = "prog",
> > +		.help = "match a programmable action",
> > +		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
> > +		.next = NEXT(action_prog),
> > +		.call = parse_vc_action_prog,
> > +	},
> > +	[ACTION_PROG_NAME] = {
> > +		.name = "name",
> > +		.help = "programble action name",
> >
> 
> Can you please remind me again what was the 'name' filed of "struct
> rte_flow_action_prog" was for?

The 'name' field serves as a means for the driver to identify an action schema, enabling it to verify if the number of parameters and the size of each parameter value align with the P4 definition.
Subsequently, the driver translates these values into hardware-specific configurations. If there is a misalignment, the PMD will return a failure.

> 
> 
> > +		.next = NEXT(action_prog,
> NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
> > +		.args = ARGS(ARGS_ENTRY(struct action_prog_data,
> data.name)),
> > +	},
> > +	[ACTION_PROG_NAME_STRING] = {
> > +		.name = "{string}",
> > +		.type = "STRING",
> > +		.help = "programmable action name string",
> > +		.call = parse_string0,
> > +	},
> > +	[ACTION_PROG_ARGUMENTS] = {
> > +		.name = "arguments",
> > +		.help = "programmable action name",
> > +		.next = NEXT(action_prog,
> NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
> > +		.call = parse_vc_conf,
> > +	},
> > +	[ACTION_PROG_ARG_NAME] = {
> > +		.name = "{string}",
> > +		.help = "programmable action argument name",
> > +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
> > +		.call = parse_vc_action_prog_arg_name,
> > +	},
> > +	[ACTION_PROG_ARG_VALUE] = {
> > +		.name = "{hex}",
> > +		.help = "programmable action argument value",
> > +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END,
> ACTION_PROG_ARG_NAME)),
> > +		.call = parse_vc_action_prog_arg_value,
> > +	},
> > +	[ACTION_PROG_ARG_END] = {
> > +		.name = "end",
> > +		.help = "end of the programmable action arguments",
> > +	},
> > +
> >
> 
> Does this means two 'end' required if multiple args provided, like:
> prog name "name" arguments field0 03FF field1 1 end / end
> I am aware there is variable length of key/value, and need a marker to stop,
> but this end specific for action is not used, 

 Actually I borrowed the idea from the queue group in the RSS action:

'actions rss queues 0 1 2 3 end / end ..."

The difference is that the 'end' check was previously hidden within the 'parse_vc_action_rss_queue' function, while in my implementation, I've defined it as a distinct state.

Thanks
Qi

>I wonder if that is because there is
> a better way to do it, @Ori may comment better.
> 
> 


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

* Re: [PATCH v4] app/testpmd: enable cli for programmable action
  2023-10-11  2:24     ` Zhang, Qi Z
@ 2023-10-11 10:20       ` Ferruh Yigit
  2023-10-11 13:19         ` Zhang, Qi Z
  0 siblings, 1 reply; 20+ messages in thread
From: Ferruh Yigit @ 2023-10-11 10:20 UTC (permalink / raw)
  To: Zhang, Qi Z, Singh, Aman Deep, Zhang, Yuying
  Cc: dev, Dumitrescu, Cristian, orika

On 10/11/2023 3:24 AM, Zhang, Qi Z wrote:
> 
>> -----Original Message-----
>> From: Ferruh Yigit <ferruh.yigit@amd.com>
>> Sent: Tuesday, October 10, 2023 6:49 PM
>> To: Zhang, Qi Z <qi.z.zhang@intel.com>; Singh, Aman Deep
>> <aman.deep.singh@intel.com>; Zhang, Yuying <yuying.zhang@intel.com>
>> Cc: dev@dpdk.org; Dumitrescu, Cristian <cristian.dumitrescu@intel.com>;
>> orika@nvidia.com
>> Subject: Re: [PATCH v4] app/testpmd: enable cli for programmable action
>>
>> On 10/7/2023 11:47 AM, Qi Zhang wrote:
>>> Parsing command line for rte_flow_action_prog.
>>>
>>> Syntax:
>>>
>>> "prog name <name> [arguments <arg_name_0> <arg_value_0> \
>>> <arg_name_1> <arg_value1> ... end]"
>>>
>>
>> Can you please put full rte flow command in the commit log? Like what is the
>> 'pattern' for above command?
> 
> The pattern part should be independent of the action part,
> 
> though for our P4 device, we will prefer use rte_flow_flex_item, something like:
> 
> flow create 0 pattern flex item is xxx pattern is xxx / flex item is xxx pattern is / actions prog name ......
> 
> but it does not limit PMD to support flow like below
> 

I think agreement was to use flex pattern, and my understand is "struct
rte_flow_item_flex" will be used to present the table_id.

Without not using flex, how driver will detect which table to update?


> flow create 0 pattern eth / ipv4 src is 1.1.1.1 / actions prog name ......
> 
> So I think it may not be necessary to highlight the pattern format here.
> 

Complete samples helps a lot to user, can you please include the full
rte flow command, you can have flex pattern sample and if you want add
more samples with other patterns but we need to clarify it first.


>>
>>
>>> Use parse_string0 to parse name string.
>>> Use parse_hex to parse hex string.
>>> Use struct action_prog_data to store parsed result.
>>>
>>> Example:
>>>
>>> Action with 2 arguments:
>>>
>>> "prog name action0 arguments field0 03FF field1 55AA end"
>>>
>>> Action without argument:
>>>
>>> "prog name action1"
>>>
>>> Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
>>>
>>
>> Is there an existing driver implementation, checking it helps to understand
>> feature implementation?
> 
> This work is still ongoing, currently we target to upstream on DPDK 24.03
> 

If you won't have driver yet, do you have a way to test these commands?
Or is this implementation just theoretical at this stage?


>>
>>
>>> ---
>>>
>>> v4:
>>> - be more generous on the max size of name and value.
>>>
>>> v3:
>>> - refine struct action_prog_data
>>> - enlarge the max size
>>>
>>> v2:
>>> - fix title
>>> - minor coding style refine.
>>>
>>>  app/test-pmd/cmdline_flow.c | 232
>>> ++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 232 insertions(+)
>>>
>>
>> Hi Qi,
>>
>> Can you please update documentation too,
>> `doc/guides/testpmd_app_ug/testpmd_funcs.rst`, `Flow rules management`
>> section.
> 
> Sure.
> 
>>
>>
>>> diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
>>> index 21828c144c..ae5556e704 100644
>>> --- a/app/test-pmd/cmdline_flow.c
>>> +++ b/app/test-pmd/cmdline_flow.c
>>> @@ -719,6 +719,13 @@ enum index {
>>>  	ACTION_IPV6_EXT_PUSH,
>>>  	ACTION_IPV6_EXT_PUSH_INDEX,
>>>  	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
>>> +	ACTION_PROG,
>>> +	ACTION_PROG_NAME,
>>> +	ACTION_PROG_NAME_STRING,
>>> +	ACTION_PROG_ARGUMENTS,
>>> +	ACTION_PROG_ARG_NAME,
>>> +	ACTION_PROG_ARG_VALUE,
>>> +	ACTION_PROG_ARG_END,
>>>  };
>>>
>>>  /** Maximum size for pattern in struct rte_flow_item_raw. */ @@
>>> -749,6 +756,23 @@ struct action_rss_data {
>>>  	uint16_t queue[ACTION_RSS_QUEUE_NUM];  };
>>>
>>> +#define ACTION_PROG_NAME_SIZE_MAX 256 #define
>> ACTION_PROG_ARG_NUM_MAX
>>> +16 #define ACTION_PROG_ARG_VALUE_SIZE_MAX 64
>>> +
>>> +/** Storage for struct rte_flow_action_prog including external data.
>>> +*/ struct action_prog_data {
>>> +	struct rte_flow_action_prog conf;
>>> +	struct {
>>> +		char name[ACTION_PROG_NAME_SIZE_MAX];
>>> +		struct rte_flow_action_prog_argument
>> args[ACTION_PROG_ARG_NUM_MAX];
>>> +		struct {
>>> +			char names[ACTION_PROG_NAME_SIZE_MAX];
>>> +			uint8_t
>> value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
>>> +		} arg_data[ACTION_PROG_ARG_NUM_MAX];
>>> +	} data;
>>> +};
>>> +
>>>  /** Maximum data size in struct rte_flow_action_raw_encap. */
>>> #define ACTION_RAW_ENCAP_MAX_DATA 512  #define
>> RAW_ENCAP_CONFS_MAX_NUM
>>> 8 @@ -2169,6 +2193,7 @@ static const enum index next_action[] = {
>>>  	ACTION_QUOTA_QU,
>>>  	ACTION_IPV6_EXT_REMOVE,
>>>  	ACTION_IPV6_EXT_PUSH,
>>> +	ACTION_PROG,
>>>  	ZERO,
>>>  };
>>>
>>> @@ -2510,6 +2535,13 @@ static const enum index
>> action_represented_port[] = {
>>>  	ZERO,
>>>  };
>>>
>>> +static const enum index action_prog[] = {
>>> +	ACTION_PROG_NAME,
>>> +	ACTION_PROG_ARGUMENTS,
>>> +	ACTION_NEXT,
>>> +	ZERO,
>>> +};
>>> +
>>>  static int parse_set_raw_encap_decap(struct context *, const struct token *,
>>>  				     const char *, unsigned int,
>>>  				     void *, unsigned int);
>>> @@ -2786,6 +2818,18 @@ static int
>>>  parse_qu_mode_name(struct context *ctx, const struct token *token,
>>>  		   const char *str, unsigned int len, void *buf,
>>>  		   unsigned int size);
>>> +static int
>>> +parse_vc_action_prog(struct context *, const struct token *,
>>> +		     const char *, unsigned int, void *,
>>> +		     unsigned int);
>>> +static int
>>> +parse_vc_action_prog_arg_name(struct context *, const struct token *,
>>> +			      const char *, unsigned int, void *,
>>> +			      unsigned int);
>>> +static int
>>> +parse_vc_action_prog_arg_value(struct context *, const struct token *,
>>> +			       const char *, unsigned int, void *,
>>> +			       unsigned int);
>>>  static int comp_none(struct context *, const struct token *,
>>>  		     unsigned int, char *, unsigned int);  static int
>>> comp_boolean(struct context *, const struct token *, @@ -7518,6
>>> +7562,48 @@ static const struct token token_list[] = {
>>>  		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
>>>  					tx_queue)),
>>>  	},
>>> +	[ACTION_PROG] = {
>>> +		.name = "prog",
>>> +		.help = "match a programmable action",
>>> +		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
>>> +		.next = NEXT(action_prog),
>>> +		.call = parse_vc_action_prog,
>>> +	},
>>> +	[ACTION_PROG_NAME] = {
>>> +		.name = "name",
>>> +		.help = "programble action name",
>>>
>>
>> Can you please remind me again what was the 'name' filed of "struct
>> rte_flow_action_prog" was for?
> 
> The 'name' field serves as a means for the driver to identify an action schema, enabling it to verify if the number of parameters and the size of each parameter value align with the P4 definition.
> Subsequently, the driver translates these values into hardware-specific configurations. If there is a misalignment, the PMD will return a failure.
> 

As I understand it is used for kind of unique action handler, but we
have rte_flow handler already, I am still not clear why an action
handler is required.

Why driver is not using rte flow handler?

Again driver implementation would clear more the intended usage.

>>
>>
>>> +		.next = NEXT(action_prog,
>> NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
>>> +		.args = ARGS(ARGS_ENTRY(struct action_prog_data,
>> data.name)),
>>> +	},
>>> +	[ACTION_PROG_NAME_STRING] = {
>>> +		.name = "{string}",
>>> +		.type = "STRING",
>>> +		.help = "programmable action name string",
>>> +		.call = parse_string0,
>>> +	},
>>> +	[ACTION_PROG_ARGUMENTS] = {
>>> +		.name = "arguments",
>>> +		.help = "programmable action name",
>>> +		.next = NEXT(action_prog,
>> NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
>>> +		.call = parse_vc_conf,
>>> +	},
>>> +	[ACTION_PROG_ARG_NAME] = {
>>> +		.name = "{string}",
>>> +		.help = "programmable action argument name",
>>> +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
>>> +		.call = parse_vc_action_prog_arg_name,
>>> +	},
>>> +	[ACTION_PROG_ARG_VALUE] = {
>>> +		.name = "{hex}",
>>> +		.help = "programmable action argument value",
>>> +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END,
>> ACTION_PROG_ARG_NAME)),
>>> +		.call = parse_vc_action_prog_arg_value,
>>> +	},
>>> +	[ACTION_PROG_ARG_END] = {
>>> +		.name = "end",
>>> +		.help = "end of the programmable action arguments",
>>> +	},
>>> +
>>>
>>
>> Does this means two 'end' required if multiple args provided, like:
>> prog name "name" arguments field0 03FF field1 1 end / end
>> I am aware there is variable length of key/value, and need a marker to stop,
>> but this end specific for action is not used, 
> 
>  Actually I borrowed the idea from the queue group in the RSS action:
> 
> 'actions rss queues 0 1 2 3 end / end ..."
> 
> The difference is that the 'end' check was previously hidden within the 'parse_vc_action_rss_queue' function, while in my implementation, I've defined it as a distinct state.
> 


My concern is if ACTION_xxx_END tokens be confusing or redundant if we
have more of them.

Is there a benefit to have it as token, comparing to have it in the
parser functions as RSS does?


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

* [PATCH v5] app/testpmd: enable cli for programmable action
  2023-10-05 10:02 [PATCH 1/2] app/testpmd: enable cli for programmable action Qi Zhang
                   ` (2 preceding siblings ...)
  2023-10-07 10:47 ` [PATCH v4] " Qi Zhang
@ 2023-10-11 11:58 ` Qi Zhang
  2023-10-11 12:03 ` [PATCH v6] " Qi Zhang
  4 siblings, 0 replies; 20+ messages in thread
From: Qi Zhang @ 2023-10-11 11:58 UTC (permalink / raw)
  To: aman.deep.singh, yuying.zhang
  Cc: dev, cristian.dumitrescu, orika, ferruh.yigit, Qi Zhang

Parsing command line for rte_flow_action_prog.

Syntax:

"prog name <name> [arguments <arg_name_0> <arg_value_0> \
 <arg_name_1> <arg_value1> ... end]"

Use parse_string0 to parse name string.
Use parse_hex to parse hex string.
Use struct action_prog_data to store parsed result.

Example:

Action with 2 arguments:

"prog name action0 arguments field0 03FF field1 55AA end"

Action without argument:

"prog name action1"

Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
---
v5:
- complete testpmd document.

v4:
- be more generous on the max size of name and value.

v3:
- refine struct action_prog_data
- enlarge the max size

v2:
- fix title
- minor coding style refine.

 app/test-pmd/cmdline_flow.c                 | 232 ++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  17 ++
 2 files changed, 249 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 70eef3e34d..d9152f9485 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -721,6 +721,13 @@ enum index {
 	ACTION_IPV6_EXT_PUSH,
 	ACTION_IPV6_EXT_PUSH_INDEX,
 	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
+	ACTION_PROG,
+	ACTION_PROG_NAME,
+	ACTION_PROG_NAME_STRING,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_PROG_ARG_NAME,
+	ACTION_PROG_ARG_VALUE,
+	ACTION_PROG_ARG_END,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -751,6 +758,23 @@ struct action_rss_data {
 	uint16_t queue[ACTION_RSS_QUEUE_NUM];
 };
 
+#define ACTION_PROG_NAME_SIZE_MAX 256
+#define ACTION_PROG_ARG_NUM_MAX 16
+#define ACTION_PROG_ARG_VALUE_SIZE_MAX 64
+
+/** Storage for struct rte_flow_action_prog including external data. */
+struct action_prog_data {
+	struct rte_flow_action_prog conf;
+	struct {
+		char name[ACTION_PROG_NAME_SIZE_MAX];
+		struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX];
+		struct {
+			char names[ACTION_PROG_NAME_SIZE_MAX];
+			uint8_t value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
+		} arg_data[ACTION_PROG_ARG_NUM_MAX];
+	} data;
+};
+
 /** Maximum data size in struct rte_flow_action_raw_encap. */
 #define ACTION_RAW_ENCAP_MAX_DATA 512
 #define RAW_ENCAP_CONFS_MAX_NUM 8
@@ -2178,6 +2202,7 @@ static const enum index next_action[] = {
 	ACTION_QUOTA_QU,
 	ACTION_IPV6_EXT_REMOVE,
 	ACTION_IPV6_EXT_PUSH,
+	ACTION_PROG,
 	ZERO,
 };
 
@@ -2519,6 +2544,13 @@ static const enum index action_represented_port[] = {
 	ZERO,
 };
 
+static const enum index action_prog[] = {
+	ACTION_PROG_NAME,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_NEXT,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -2795,6 +2827,18 @@ static int
 parse_qu_mode_name(struct context *ctx, const struct token *token,
 		   const char *str, unsigned int len, void *buf,
 		   unsigned int size);
+static int
+parse_vc_action_prog(struct context *, const struct token *,
+		     const char *, unsigned int, void *,
+		     unsigned int);
+static int
+parse_vc_action_prog_arg_name(struct context *, const struct token *,
+			      const char *, unsigned int, void *,
+			      unsigned int);
+static int
+parse_vc_action_prog_arg_value(struct context *, const struct token *,
+			       const char *, unsigned int, void *,
+			       unsigned int);
 static int comp_none(struct context *, const struct token *,
 		     unsigned int, char *, unsigned int);
 static int comp_boolean(struct context *, const struct token *,
@@ -7543,6 +7587,48 @@ static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
 					tx_queue)),
 	},
+	[ACTION_PROG] = {
+		.name = "prog",
+		.help = "match a programmable action",
+		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
+		.next = NEXT(action_prog),
+		.call = parse_vc_action_prog,
+	},
+	[ACTION_PROG_NAME] = {
+		.name = "name",
+		.help = "programble action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
+		.args = ARGS(ARGS_ENTRY(struct action_prog_data, data.name)),
+	},
+	[ACTION_PROG_NAME_STRING] = {
+		.name = "{string}",
+		.type = "STRING",
+		.help = "programmable action name string",
+		.call = parse_string0,
+	},
+	[ACTION_PROG_ARGUMENTS] = {
+		.name = "arguments",
+		.help = "programmable action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_PROG_ARG_NAME] = {
+		.name = "{string}",
+		.help = "programmable action argument name",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
+		.call = parse_vc_action_prog_arg_name,
+	},
+	[ACTION_PROG_ARG_VALUE] = {
+		.name = "{hex}",
+		.help = "programmable action argument value",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END, ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_action_prog_arg_value,
+	},
+	[ACTION_PROG_ARG_END] = {
+		.name = "end",
+		.help = "end of the programmable action arguments",
+	},
+
 };
 
 /** Remove and return last entry from argument stack. */
@@ -11700,6 +11786,152 @@ parse_qu_mode_name(struct context *ctx, const struct token *token,
 				   (uint32_t *)&out->args.ia.qu_mode);
 }
 
+/** Parse prog action. */
+static int
+parse_vc_action_prog(struct context *ctx, const struct token *token,
+		     const char *str, unsigned int len,
+		     void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_prog_data *action_prog_data;
+	uint16_t i;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+
+	if (!out)
+		return ret;
+
+	if (!out->args.vc.actions_n)
+		return -1;
+
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	ctx->object = out->args.vc.data;
+	action_prog_data = ctx->object;
+	*action_prog_data = (struct action_prog_data) {
+		.conf = (struct rte_flow_action_prog) {
+			.args_num = 0,
+			.name = action_prog_data->data.name,
+			.args = action_prog_data->data.args,
+		},
+	};
+
+	for (i = 0; i < ACTION_PROG_ARG_NUM_MAX; ++i)
+		action_prog_data->data.args[i].name = action_prog_data->data.arg_data[i].names;
+	action->conf = &action_prog_data->conf;
+
+	return ret;
+}
+
+static int
+parse_vc_action_prog_arg_name(struct context *ctx, const struct token *token,
+			      const char *str, unsigned int len,
+			      void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	struct buffer *out = buf;
+	const struct arg *arg;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_NAME)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	if (i >= ACTION_PROG_ARG_NUM_MAX)
+		return -1;
+
+	arg = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+				      data.arg_data[i].names),
+			     ACTION_PROG_NAME_SIZE_MAX);
+
+	if (push_args(ctx, arg))
+		return -1;
+
+	ret = parse_string0(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	return len;
+}
+
+static int
+parse_vc_action_prog_arg_value(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	const struct arg *arg_addr;
+	const struct arg *arg_size;
+	const struct arg *arg_data;
+	struct buffer *out = buf;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_VALUE)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	arg_addr  = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					    data.args[i].value),
+				   sizeof(action_prog_data->data.args[i].value));
+
+	arg_size = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					   data.args[i].size),
+				   sizeof(action_prog_data->data.args[i].size));
+
+	arg_data = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					   data.arg_data[i].value),
+				  ACTION_PROG_ARG_VALUE_SIZE_MAX);
+
+	if (push_args(ctx, arg_addr))
+		return -1;
+
+	if (push_args(ctx, arg_size)) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	if (push_args(ctx, arg_data)) {
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	ret = parse_hex(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	action_prog_data->conf.args_num++;
+
+	return len;
+}
+
 /** No completion. */
 static int
 comp_none(struct context *ctx, const struct token *token,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 67968ecb7f..84be67625a 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -4108,6 +4108,14 @@ This section lists supported actions and their attributes, if any.
   - ``mtr_init_color {value}``: initial color value (green/yellow/red)
   - ``mtr_state {unsigned}``: meter state (disabled/enabled)
 
+- ``prog``: Set a Programmable Action that aligns with the current device
+  configuration, typically intended for use with a P4 programmable device.
+
+  - ``name {string}``: The name of a Programmable Action schema
+  - ``aguments [{string} {hex string} [...]] end``: It is optional, the names
+    and values of each argument for the Programmable Action in a list, the
+    name is represented as {string} and value is represented as {hex string}
+
 Destroying flow rules
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -5262,6 +5270,15 @@ A RAW rule can be created as following using ``pattern_hex`` key and mask.
              pattern_hex mask 0000000000000000000000000000000000000000000000000000ffffffff / end actions
              queue index 4 / end
 
+Sample Programmable Action rule
+
+A rule use Programmable Action to perform a customized tunnel header encap for specific IP packets.
+
+::
+
+    testpmd> flow create 0 ingress pattern eth / ipv4 src is 1.2.3.4 / end actions prog name cust_tun_encap
+             arguments tunn_id 55AA meta0 2E meta1 9000 end / end
+
 BPF Functions
 --------------
 
-- 
2.31.1


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

* [PATCH v6] app/testpmd: enable cli for programmable action
  2023-10-05 10:02 [PATCH 1/2] app/testpmd: enable cli for programmable action Qi Zhang
                   ` (3 preceding siblings ...)
  2023-10-11 11:58 ` [PATCH v5] " Qi Zhang
@ 2023-10-11 12:03 ` Qi Zhang
  2024-02-08  1:10   ` Ferruh Yigit
  4 siblings, 1 reply; 20+ messages in thread
From: Qi Zhang @ 2023-10-11 12:03 UTC (permalink / raw)
  To: aman.deep.singh, yuying.zhang
  Cc: dev, cristian.dumitrescu, orika, ferruh.yigit, Qi Zhang

Parsing command line for rte_flow_action_prog.

Syntax:

"prog name <name> [arguments <arg_name_0> <arg_value_0> \
 <arg_name_1> <arg_value1> ... end]"

Use parse_string0 to parse name string.
Use parse_hex to parse hex string.
Use struct action_prog_data to store parsed result.

Example:

Action with 2 arguments:

"prog name action0 arguments field0 03FF field1 55AA end"

Action without argument:

"prog name action1"

Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
---
v6:
- fix typo.

v5:
- complete testpmd document.

v4:
- be more generous on the max size of name and value.

v3:
- refine struct action_prog_data
- enlarge the max size

v2:
- fix title
- minor coding style refine.

 app/test-pmd/cmdline_flow.c                 | 232 ++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  17 ++
 2 files changed, 249 insertions(+)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 70eef3e34d..d9152f9485 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -721,6 +721,13 @@ enum index {
 	ACTION_IPV6_EXT_PUSH,
 	ACTION_IPV6_EXT_PUSH_INDEX,
 	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
+	ACTION_PROG,
+	ACTION_PROG_NAME,
+	ACTION_PROG_NAME_STRING,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_PROG_ARG_NAME,
+	ACTION_PROG_ARG_VALUE,
+	ACTION_PROG_ARG_END,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -751,6 +758,23 @@ struct action_rss_data {
 	uint16_t queue[ACTION_RSS_QUEUE_NUM];
 };
 
+#define ACTION_PROG_NAME_SIZE_MAX 256
+#define ACTION_PROG_ARG_NUM_MAX 16
+#define ACTION_PROG_ARG_VALUE_SIZE_MAX 64
+
+/** Storage for struct rte_flow_action_prog including external data. */
+struct action_prog_data {
+	struct rte_flow_action_prog conf;
+	struct {
+		char name[ACTION_PROG_NAME_SIZE_MAX];
+		struct rte_flow_action_prog_argument args[ACTION_PROG_ARG_NUM_MAX];
+		struct {
+			char names[ACTION_PROG_NAME_SIZE_MAX];
+			uint8_t value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
+		} arg_data[ACTION_PROG_ARG_NUM_MAX];
+	} data;
+};
+
 /** Maximum data size in struct rte_flow_action_raw_encap. */
 #define ACTION_RAW_ENCAP_MAX_DATA 512
 #define RAW_ENCAP_CONFS_MAX_NUM 8
@@ -2178,6 +2202,7 @@ static const enum index next_action[] = {
 	ACTION_QUOTA_QU,
 	ACTION_IPV6_EXT_REMOVE,
 	ACTION_IPV6_EXT_PUSH,
+	ACTION_PROG,
 	ZERO,
 };
 
@@ -2519,6 +2544,13 @@ static const enum index action_represented_port[] = {
 	ZERO,
 };
 
+static const enum index action_prog[] = {
+	ACTION_PROG_NAME,
+	ACTION_PROG_ARGUMENTS,
+	ACTION_NEXT,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
@@ -2795,6 +2827,18 @@ static int
 parse_qu_mode_name(struct context *ctx, const struct token *token,
 		   const char *str, unsigned int len, void *buf,
 		   unsigned int size);
+static int
+parse_vc_action_prog(struct context *, const struct token *,
+		     const char *, unsigned int, void *,
+		     unsigned int);
+static int
+parse_vc_action_prog_arg_name(struct context *, const struct token *,
+			      const char *, unsigned int, void *,
+			      unsigned int);
+static int
+parse_vc_action_prog_arg_value(struct context *, const struct token *,
+			       const char *, unsigned int, void *,
+			       unsigned int);
 static int comp_none(struct context *, const struct token *,
 		     unsigned int, char *, unsigned int);
 static int comp_boolean(struct context *, const struct token *,
@@ -7543,6 +7587,48 @@ static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
 					tx_queue)),
 	},
+	[ACTION_PROG] = {
+		.name = "prog",
+		.help = "match a programmable action",
+		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
+		.next = NEXT(action_prog),
+		.call = parse_vc_action_prog,
+	},
+	[ACTION_PROG_NAME] = {
+		.name = "name",
+		.help = "programble action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
+		.args = ARGS(ARGS_ENTRY(struct action_prog_data, data.name)),
+	},
+	[ACTION_PROG_NAME_STRING] = {
+		.name = "{string}",
+		.type = "STRING",
+		.help = "programmable action name string",
+		.call = parse_string0,
+	},
+	[ACTION_PROG_ARGUMENTS] = {
+		.name = "arguments",
+		.help = "programmable action name",
+		.next = NEXT(action_prog, NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_conf,
+	},
+	[ACTION_PROG_ARG_NAME] = {
+		.name = "{string}",
+		.help = "programmable action argument name",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
+		.call = parse_vc_action_prog_arg_name,
+	},
+	[ACTION_PROG_ARG_VALUE] = {
+		.name = "{hex}",
+		.help = "programmable action argument value",
+		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END, ACTION_PROG_ARG_NAME)),
+		.call = parse_vc_action_prog_arg_value,
+	},
+	[ACTION_PROG_ARG_END] = {
+		.name = "end",
+		.help = "end of the programmable action arguments",
+	},
+
 };
 
 /** Remove and return last entry from argument stack. */
@@ -11700,6 +11786,152 @@ parse_qu_mode_name(struct context *ctx, const struct token *token,
 				   (uint32_t *)&out->args.ia.qu_mode);
 }
 
+/** Parse prog action. */
+static int
+parse_vc_action_prog(struct context *ctx, const struct token *token,
+		     const char *str, unsigned int len,
+		     void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+	struct rte_flow_action *action;
+	struct action_prog_data *action_prog_data;
+	uint16_t i;
+	int ret;
+
+	ret = parse_vc(ctx, token, str, len, buf, size);
+	if (ret < 0)
+		return ret;
+
+	if (!out)
+		return ret;
+
+	if (!out->args.vc.actions_n)
+		return -1;
+
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	ctx->object = out->args.vc.data;
+	action_prog_data = ctx->object;
+	*action_prog_data = (struct action_prog_data) {
+		.conf = (struct rte_flow_action_prog) {
+			.args_num = 0,
+			.name = action_prog_data->data.name,
+			.args = action_prog_data->data.args,
+		},
+	};
+
+	for (i = 0; i < ACTION_PROG_ARG_NUM_MAX; ++i)
+		action_prog_data->data.args[i].name = action_prog_data->data.arg_data[i].names;
+	action->conf = &action_prog_data->conf;
+
+	return ret;
+}
+
+static int
+parse_vc_action_prog_arg_name(struct context *ctx, const struct token *token,
+			      const char *str, unsigned int len,
+			      void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	struct buffer *out = buf;
+	const struct arg *arg;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_NAME)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	if (i >= ACTION_PROG_ARG_NUM_MAX)
+		return -1;
+
+	arg = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+				      data.arg_data[i].names),
+			     ACTION_PROG_NAME_SIZE_MAX);
+
+	if (push_args(ctx, arg))
+		return -1;
+
+	ret = parse_string0(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	return len;
+}
+
+static int
+parse_vc_action_prog_arg_value(struct context *ctx, const struct token *token,
+			       const char *str, unsigned int len,
+			       void *buf, unsigned int size)
+{
+	struct action_prog_data *action_prog_data;
+	const struct arg *arg_addr;
+	const struct arg *arg_size;
+	const struct arg *arg_data;
+	struct buffer *out = buf;
+	uint32_t i;
+	int ret;
+
+	(void)token;
+	(void)buf;
+	(void)size;
+	if (ctx->curr != ACTION_PROG_ARG_VALUE)
+		return -1;
+
+	if (!out)
+		return len;
+
+	action_prog_data = (void *)out->args.vc.data;
+	i = action_prog_data->conf.args_num;
+
+	arg_addr  = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					    data.args[i].value),
+				   sizeof(action_prog_data->data.args[i].value));
+
+	arg_size = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					   data.args[i].size),
+				   sizeof(action_prog_data->data.args[i].size));
+
+	arg_data = ARGS_ENTRY_ARB(offsetof(struct action_prog_data,
+					   data.arg_data[i].value),
+				  ACTION_PROG_ARG_VALUE_SIZE_MAX);
+
+	if (push_args(ctx, arg_addr))
+		return -1;
+
+	if (push_args(ctx, arg_size)) {
+		pop_args(ctx);
+		return -1;
+	}
+
+	if (push_args(ctx, arg_data)) {
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	ret = parse_hex(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		pop_args(ctx);
+		pop_args(ctx);
+		return -1;
+	}
+
+	action_prog_data->conf.args_num++;
+
+	return len;
+}
+
 /** No completion. */
 static int
 comp_none(struct context *ctx, const struct token *token,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 67968ecb7f..84be67625a 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -4108,6 +4108,14 @@ This section lists supported actions and their attributes, if any.
   - ``mtr_init_color {value}``: initial color value (green/yellow/red)
   - ``mtr_state {unsigned}``: meter state (disabled/enabled)
 
+- ``prog``: Set a Programmable Action that aligns with the current device
+  configuration, typically intended for use with a P4 programmable device.
+
+  - ``name {string}``: The name of a Programmable Action schema
+  - ``arguments [{string} {hex string} [...]] end``: It is optional, the names
+    and values of each argument for the Programmable Action in a list, the
+    name is represented as {string} and value is represented as {hex string}
+
 Destroying flow rules
 ~~~~~~~~~~~~~~~~~~~~~
 
@@ -5262,6 +5270,15 @@ A RAW rule can be created as following using ``pattern_hex`` key and mask.
              pattern_hex mask 0000000000000000000000000000000000000000000000000000ffffffff / end actions
              queue index 4 / end
 
+Sample Programmable Action rule
+
+A rule use Programmable Action to perform a customized tunnel header encap for specific IP packets.
+
+::
+
+    testpmd> flow create 0 ingress pattern eth / ipv4 src is 1.2.3.4 / end actions prog name cust_tun_encap
+             arguments tunn_id 55AA meta0 2E meta1 9000 end / end
+
 BPF Functions
 --------------
 
-- 
2.31.1


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

* RE: [PATCH v4] app/testpmd: enable cli for programmable action
  2023-10-11 10:20       ` Ferruh Yigit
@ 2023-10-11 13:19         ` Zhang, Qi Z
  2023-10-12  0:04           ` Zhang, Qi Z
  0 siblings, 1 reply; 20+ messages in thread
From: Zhang, Qi Z @ 2023-10-11 13:19 UTC (permalink / raw)
  To: Ferruh Yigit, Singh, Aman Deep, Zhang, Yuying
  Cc: dev, Dumitrescu, Cristian, orika



> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@amd.com>
> Sent: Wednesday, October 11, 2023 6:21 PM
> To: Zhang, Qi Z <qi.z.zhang@intel.com>; Singh, Aman Deep
> <aman.deep.singh@intel.com>; Zhang, Yuying <yuying.zhang@intel.com>
> Cc: dev@dpdk.org; Dumitrescu, Cristian <cristian.dumitrescu@intel.com>;
> orika@nvidia.com
> Subject: Re: [PATCH v4] app/testpmd: enable cli for programmable action
> 
> On 10/11/2023 3:24 AM, Zhang, Qi Z wrote:
> >
> >> -----Original Message-----
> >> From: Ferruh Yigit <ferruh.yigit@amd.com>
> >> Sent: Tuesday, October 10, 2023 6:49 PM
> >> To: Zhang, Qi Z <qi.z.zhang@intel.com>; Singh, Aman Deep
> >> <aman.deep.singh@intel.com>; Zhang, Yuying <yuying.zhang@intel.com>
> >> Cc: dev@dpdk.org; Dumitrescu, Cristian
> >> <cristian.dumitrescu@intel.com>; orika@nvidia.com
> >> Subject: Re: [PATCH v4] app/testpmd: enable cli for programmable
> >> action
> >>
> >> On 10/7/2023 11:47 AM, Qi Zhang wrote:
> >>> Parsing command line for rte_flow_action_prog.
> >>>
> >>> Syntax:
> >>>
> >>> "prog name <name> [arguments <arg_name_0> <arg_value_0> \
> >>> <arg_name_1> <arg_value1> ... end]"
> >>>
> >>
> >> Can you please put full rte flow command in the commit log? Like what
> >> is the 'pattern' for above command?
> >
> > The pattern part should be independent of the action part,
> >
> > though for our P4 device, we will prefer use rte_flow_flex_item, something
> like:
> >
> > flow create 0 pattern flex item is xxx pattern is xxx / flex item is xxx pattern
> is / actions prog name ......
> >
> > but it does not limit PMD to support flow like below
> >
> 
> I think agreement was to use flex pattern, and my understand is "struct
> rte_flow_item_flex" will be used to present the table_id.
> 
> Without not using flex, how driver will detect which table to update?
> 
> 
> > flow create 0 pattern eth / ipv4 src is 1.1.1.1 / actions prog name ......
> >
> > So I think it may not be necessary to highlight the pattern format here.
> >
> 
> Complete samples helps a lot to user, can you please include the full rte flow
> command, you can have flex pattern sample and if you want add more
> samples with other patterns but we need to clarify it first.

Agree, I have added full sample on v6 in testpmd document as below:

...
    A rule use Programmable Action to perform a customized tunnel header encap for specific IP packets

    testpmd> flow create 0 ingress pattern eth / ipv4 src is 1.2.3.4 / end actions prog name cust_tun_encap arguments tunn_id 55AA meta0 2E meta1 9000 end / end"
...

The reason I did not include a sample with a flex item is that, in the context of our P4 device, there is no requirement to utilize the 'rte_flow_item_flex_handle' within 'rte_flow_item_flex.' 
However, the current testpmd does not offer support for this configuration.

Therefore, it may be necessary to introduce a new syntax, such as ... pattern flex pattern is xxxx / flex pattern is xxx / end ..., which would also map to 'rte_flow_item_flex'.

> 
> 
> >>
> >>
> >>> Use parse_string0 to parse name string.
> >>> Use parse_hex to parse hex string.
> >>> Use struct action_prog_data to store parsed result.
> >>>
> >>> Example:
> >>>
> >>> Action with 2 arguments:
> >>>
> >>> "prog name action0 arguments field0 03FF field1 55AA end"
> >>>
> >>> Action without argument:
> >>>
> >>> "prog name action1"
> >>>
> >>> Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
> >>>
> >>
> >> Is there an existing driver implementation, checking it helps to
> >> understand feature implementation?
> >
> > This work is still ongoing, currently we target to upstream on DPDK
> > 24.03
> >
> 
> If you won't have driver yet, do you have a way to test these commands?
> Or is this implementation just theoretical at this stage?

Yes, internally, we are very close to have an implementation that will leverage this new API, 
The JSON file loaded by CPFL PMD contains the mapping rule that direct PMD how to handling
 an action_prog,  currently we didn't see any gap of the new API.

> 
> 
> >>
> >>
> >>> ---
> >>>
> >>> v4:
> >>> - be more generous on the max size of name and value.
> >>>
> >>> v3:
> >>> - refine struct action_prog_data
> >>> - enlarge the max size
> >>>
> >>> v2:
> >>> - fix title
> >>> - minor coding style refine.
> >>>
> >>>  app/test-pmd/cmdline_flow.c | 232
> >>> ++++++++++++++++++++++++++++++++++++
> >>>  1 file changed, 232 insertions(+)
> >>>
> >>
> >> Hi Qi,
> >>
> >> Can you please update documentation too,
> >> `doc/guides/testpmd_app_ug/testpmd_funcs.rst`, `Flow rules
> >> management` section.
> >
> > Sure.
> >
> >>
> >>
> >>> diff --git a/app/test-pmd/cmdline_flow.c
> >>> b/app/test-pmd/cmdline_flow.c index 21828c144c..ae5556e704 100644
> >>> --- a/app/test-pmd/cmdline_flow.c
> >>> +++ b/app/test-pmd/cmdline_flow.c
> >>> @@ -719,6 +719,13 @@ enum index {
> >>>  	ACTION_IPV6_EXT_PUSH,
> >>>  	ACTION_IPV6_EXT_PUSH_INDEX,
> >>>  	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
> >>> +	ACTION_PROG,
> >>> +	ACTION_PROG_NAME,
> >>> +	ACTION_PROG_NAME_STRING,
> >>> +	ACTION_PROG_ARGUMENTS,
> >>> +	ACTION_PROG_ARG_NAME,
> >>> +	ACTION_PROG_ARG_VALUE,
> >>> +	ACTION_PROG_ARG_END,
> >>>  };
> >>>
> >>>  /** Maximum size for pattern in struct rte_flow_item_raw. */ @@
> >>> -749,6 +756,23 @@ struct action_rss_data {
> >>>  	uint16_t queue[ACTION_RSS_QUEUE_NUM];  };
> >>>
> >>> +#define ACTION_PROG_NAME_SIZE_MAX 256 #define
> >> ACTION_PROG_ARG_NUM_MAX
> >>> +16 #define ACTION_PROG_ARG_VALUE_SIZE_MAX 64
> >>> +
> >>> +/** Storage for struct rte_flow_action_prog including external data.
> >>> +*/ struct action_prog_data {
> >>> +	struct rte_flow_action_prog conf;
> >>> +	struct {
> >>> +		char name[ACTION_PROG_NAME_SIZE_MAX];
> >>> +		struct rte_flow_action_prog_argument
> >> args[ACTION_PROG_ARG_NUM_MAX];
> >>> +		struct {
> >>> +			char names[ACTION_PROG_NAME_SIZE_MAX];
> >>> +			uint8_t
> >> value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
> >>> +		} arg_data[ACTION_PROG_ARG_NUM_MAX];
> >>> +	} data;
> >>> +};
> >>> +
> >>>  /** Maximum data size in struct rte_flow_action_raw_encap. */
> >>> #define ACTION_RAW_ENCAP_MAX_DATA 512  #define
> >> RAW_ENCAP_CONFS_MAX_NUM
> >>> 8 @@ -2169,6 +2193,7 @@ static const enum index next_action[] = {
> >>>  	ACTION_QUOTA_QU,
> >>>  	ACTION_IPV6_EXT_REMOVE,
> >>>  	ACTION_IPV6_EXT_PUSH,
> >>> +	ACTION_PROG,
> >>>  	ZERO,
> >>>  };
> >>>
> >>> @@ -2510,6 +2535,13 @@ static const enum index
> >> action_represented_port[] = {
> >>>  	ZERO,
> >>>  };
> >>>
> >>> +static const enum index action_prog[] = {
> >>> +	ACTION_PROG_NAME,
> >>> +	ACTION_PROG_ARGUMENTS,
> >>> +	ACTION_NEXT,
> >>> +	ZERO,
> >>> +};
> >>> +
> >>>  static int parse_set_raw_encap_decap(struct context *, const struct token
> *,
> >>>  				     const char *, unsigned int,
> >>>  				     void *, unsigned int);
> >>> @@ -2786,6 +2818,18 @@ static int
> >>>  parse_qu_mode_name(struct context *ctx, const struct token *token,
> >>>  		   const char *str, unsigned int len, void *buf,
> >>>  		   unsigned int size);
> >>> +static int
> >>> +parse_vc_action_prog(struct context *, const struct token *,
> >>> +		     const char *, unsigned int, void *,
> >>> +		     unsigned int);
> >>> +static int
> >>> +parse_vc_action_prog_arg_name(struct context *, const struct token *,
> >>> +			      const char *, unsigned int, void *,
> >>> +			      unsigned int);
> >>> +static int
> >>> +parse_vc_action_prog_arg_value(struct context *, const struct token *,
> >>> +			       const char *, unsigned int, void *,
> >>> +			       unsigned int);
> >>>  static int comp_none(struct context *, const struct token *,
> >>>  		     unsigned int, char *, unsigned int);  static int
> >>> comp_boolean(struct context *, const struct token *, @@ -7518,6
> >>> +7562,48 @@ static const struct token token_list[] = {
> >>>  		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
> >>>  					tx_queue)),
> >>>  	},
> >>> +	[ACTION_PROG] = {
> >>> +		.name = "prog",
> >>> +		.help = "match a programmable action",
> >>> +		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
> >>> +		.next = NEXT(action_prog),
> >>> +		.call = parse_vc_action_prog,
> >>> +	},
> >>> +	[ACTION_PROG_NAME] = {
> >>> +		.name = "name",
> >>> +		.help = "programble action name",
> >>>
> >>
> >> Can you please remind me again what was the 'name' filed of "struct
> >> rte_flow_action_prog" was for?
> >
> > The 'name' field serves as a means for the driver to identify an action
> schema, enabling it to verify if the number of parameters and the size of each
> parameter value align with the P4 definition.
> > Subsequently, the driver translates these values into hardware-specific
> configurations. If there is a misalignment, the PMD will return a failure.
> >
> 
> As I understand it is used for kind of unique action handler, but we have
> rte_flow handler already, I am still not clear why an action handler is
> required.
> 
> Why driver is not using rte flow handler?

Not sure if I have understood your question correctly.
But, the "name" field you're referring to is not related with an action handler, it's more like an action type. 
Just like 'RTE_FLOW_ACTION_TYPE_XXX,' which is predefined, but this action type is defined as device-specific.

> 
> Again driver implementation would clear more the intended usage.

At this time, I hope above sample testpmd command can be helpful in this matter.

> 
> >>
> >>
> >>> +		.next = NEXT(action_prog,
> >> NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
> >>> +		.args = ARGS(ARGS_ENTRY(struct action_prog_data,
> >> data.name)),
> >>> +	},
> >>> +	[ACTION_PROG_NAME_STRING] = {
> >>> +		.name = "{string}",
> >>> +		.type = "STRING",
> >>> +		.help = "programmable action name string",
> >>> +		.call = parse_string0,
> >>> +	},
> >>> +	[ACTION_PROG_ARGUMENTS] = {
> >>> +		.name = "arguments",
> >>> +		.help = "programmable action name",
> >>> +		.next = NEXT(action_prog,
> >> NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
> >>> +		.call = parse_vc_conf,
> >>> +	},
> >>> +	[ACTION_PROG_ARG_NAME] = {
> >>> +		.name = "{string}",
> >>> +		.help = "programmable action argument name",
> >>> +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
> >>> +		.call = parse_vc_action_prog_arg_name,
> >>> +	},
> >>> +	[ACTION_PROG_ARG_VALUE] = {
> >>> +		.name = "{hex}",
> >>> +		.help = "programmable action argument value",
> >>> +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END,
> >> ACTION_PROG_ARG_NAME)),
> >>> +		.call = parse_vc_action_prog_arg_value,
> >>> +	},
> >>> +	[ACTION_PROG_ARG_END] = {
> >>> +		.name = "end",
> >>> +		.help = "end of the programmable action arguments",
> >>> +	},
> >>> +
> >>>
> >>
> >> Does this means two 'end' required if multiple args provided, like:
> >> prog name "name" arguments field0 03FF field1 1 end / end I am aware
> >> there is variable length of key/value, and need a marker to stop, but
> >> this end specific for action is not used,
> >
> >  Actually I borrowed the idea from the queue group in the RSS action:
> >
> > 'actions rss queues 0 1 2 3 end / end ..."
> >
> > The difference is that the 'end' check was previously hidden within the
> 'parse_vc_action_rss_queue' function, while in my implementation, I've
> defined it as a distinct state.
> >
> 
> 
> My concern is if ACTION_xxx_END tokens be confusing or redundant if we
> have more of them.
> 
> Is there a benefit to have it as token, comparing to have it in the parser
> functions as RSS does?

In my opinion, adding more 'ACTION_xxx_END' won't negatively impact code readability. 
It enhances the transparency of the syntax and may even facilitate potential automation.


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

* RE: [PATCH v4] app/testpmd: enable cli for programmable action
  2023-10-11 13:19         ` Zhang, Qi Z
@ 2023-10-12  0:04           ` Zhang, Qi Z
  2023-10-12  1:32             ` Stephen Hemminger
  0 siblings, 1 reply; 20+ messages in thread
From: Zhang, Qi Z @ 2023-10-12  0:04 UTC (permalink / raw)
  To: Zhang, Qi Z, Ferruh Yigit, Singh, Aman Deep, Zhang, Yuying
  Cc: dev, Dumitrescu, Cristian, orika



> -----Original Message-----
> From: Zhang, Qi Z <qi.z.zhang@intel.com>
> Sent: Wednesday, October 11, 2023 9:20 PM
> To: Ferruh Yigit <ferruh.yigit@amd.com>; Singh, Aman Deep
> <aman.deep.singh@intel.com>; Zhang, Yuying <yuying.zhang@intel.com>
> Cc: dev@dpdk.org; Dumitrescu, Cristian <cristian.dumitrescu@intel.com>;
> orika@nvidia.com
> Subject: RE: [PATCH v4] app/testpmd: enable cli for programmable action
> 
> 
> 
> > -----Original Message-----
> > From: Ferruh Yigit <ferruh.yigit@amd.com>
> > Sent: Wednesday, October 11, 2023 6:21 PM
> > To: Zhang, Qi Z <qi.z.zhang@intel.com>; Singh, Aman Deep
> > <aman.deep.singh@intel.com>; Zhang, Yuying <yuying.zhang@intel.com>
> > Cc: dev@dpdk.org; Dumitrescu, Cristian
> > <cristian.dumitrescu@intel.com>; orika@nvidia.com
> > Subject: Re: [PATCH v4] app/testpmd: enable cli for programmable
> > action
> >
> > On 10/11/2023 3:24 AM, Zhang, Qi Z wrote:
> > >
> > >> -----Original Message-----
> > >> From: Ferruh Yigit <ferruh.yigit@amd.com>
> > >> Sent: Tuesday, October 10, 2023 6:49 PM
> > >> To: Zhang, Qi Z <qi.z.zhang@intel.com>; Singh, Aman Deep
> > >> <aman.deep.singh@intel.com>; Zhang, Yuying
> <yuying.zhang@intel.com>
> > >> Cc: dev@dpdk.org; Dumitrescu, Cristian
> > >> <cristian.dumitrescu@intel.com>; orika@nvidia.com
> > >> Subject: Re: [PATCH v4] app/testpmd: enable cli for programmable
> > >> action
> > >>
> > >> On 10/7/2023 11:47 AM, Qi Zhang wrote:
> > >>> Parsing command line for rte_flow_action_prog.
> > >>>
> > >>> Syntax:
> > >>>
> > >>> "prog name <name> [arguments <arg_name_0> <arg_value_0> \
> > >>> <arg_name_1> <arg_value1> ... end]"
> > >>>
> > >>
> > >> Can you please put full rte flow command in the commit log? Like
> > >> what is the 'pattern' for above command?
> > >
> > > The pattern part should be independent of the action part,
> > >
> > > though for our P4 device, we will prefer use rte_flow_flex_item,
> > > something
> > like:
> > >
> > > flow create 0 pattern flex item is xxx pattern is xxx / flex item is
> > > xxx pattern
> > is / actions prog name ......
> > >
> > > but it does not limit PMD to support flow like below
> > >
> >
> > I think agreement was to use flex pattern, and my understand is
> > "struct rte_flow_item_flex" will be used to present the table_id.
> >
> > Without not using flex, how driver will detect which table to update?
> >
> >
> > > flow create 0 pattern eth / ipv4 src is 1.1.1.1 / actions prog name ......
> > >
> > > So I think it may not be necessary to highlight the pattern format here.
> > >
> >
> > Complete samples helps a lot to user, can you please include the full
> > rte flow command, you can have flex pattern sample and if you want add
> > more samples with other patterns but we need to clarify it first.
> 
> Agree, I have added full sample on v6 in testpmd document as below:
> 
> ...
>     A rule use Programmable Action to perform a customized tunnel header
> encap for specific IP packets
> 
>     testpmd> flow create 0 ingress pattern eth / ipv4 src is 1.2.3.4 / end actions
> prog name cust_tun_encap arguments tunn_id 55AA meta0 2E meta1 9000
> end / end"
> ...
> 
> The reason I did not include a sample with a flex item is that, in the context of
> our P4 device, there is no requirement to utilize the
> 'rte_flow_item_flex_handle' within 'rte_flow_item_flex.'
> However, the current testpmd does not offer support for this configuration.
> 
> Therefore, it may be necessary to introduce a new syntax, such as ... pattern
> flex pattern is xxxx / flex pattern is xxx / end ..., which would also map to
> 'rte_flow_item_flex'.
> 
> >
> >
> > >>
> > >>
> > >>> Use parse_string0 to parse name string.
> > >>> Use parse_hex to parse hex string.
> > >>> Use struct action_prog_data to store parsed result.
> > >>>
> > >>> Example:
> > >>>
> > >>> Action with 2 arguments:
> > >>>
> > >>> "prog name action0 arguments field0 03FF field1 55AA end"
> > >>>
> > >>> Action without argument:
> > >>>
> > >>> "prog name action1"
> > >>>
> > >>> Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
> > >>>
> > >>
> > >> Is there an existing driver implementation, checking it helps to
> > >> understand feature implementation?
> > >
> > > This work is still ongoing, currently we target to upstream on DPDK
> > > 24.03
> > >
> >
> > If you won't have driver yet, do you have a way to test these commands?
> > Or is this implementation just theoretical at this stage?

I may not get your point in my previous reply, to verify the correctness of the new commands before the driver is ready, 
Actually, I added some dump code in port_flow_create to verify each prog action and its arguments' size , value

> 
> Yes, internally, we are very close to have an implementation that will leverage
> this new API, The JSON file loaded by CPFL PMD contains the mapping rule
> that direct PMD how to handling  an action_prog,  currently we didn't see any
> gap of the new API.
> 
> >
> >
> > >>
> > >>
> > >>> ---
> > >>>
> > >>> v4:
> > >>> - be more generous on the max size of name and value.
> > >>>
> > >>> v3:
> > >>> - refine struct action_prog_data
> > >>> - enlarge the max size
> > >>>
> > >>> v2:
> > >>> - fix title
> > >>> - minor coding style refine.
> > >>>
> > >>>  app/test-pmd/cmdline_flow.c | 232
> > >>> ++++++++++++++++++++++++++++++++++++
> > >>>  1 file changed, 232 insertions(+)
> > >>>
> > >>
> > >> Hi Qi,
> > >>
> > >> Can you please update documentation too,
> > >> `doc/guides/testpmd_app_ug/testpmd_funcs.rst`, `Flow rules
> > >> management` section.
> > >
> > > Sure.
> > >
> > >>
> > >>
> > >>> diff --git a/app/test-pmd/cmdline_flow.c
> > >>> b/app/test-pmd/cmdline_flow.c index 21828c144c..ae5556e704 100644
> > >>> --- a/app/test-pmd/cmdline_flow.c
> > >>> +++ b/app/test-pmd/cmdline_flow.c
> > >>> @@ -719,6 +719,13 @@ enum index {
> > >>>  	ACTION_IPV6_EXT_PUSH,
> > >>>  	ACTION_IPV6_EXT_PUSH_INDEX,
> > >>>  	ACTION_IPV6_EXT_PUSH_INDEX_VALUE,
> > >>> +	ACTION_PROG,
> > >>> +	ACTION_PROG_NAME,
> > >>> +	ACTION_PROG_NAME_STRING,
> > >>> +	ACTION_PROG_ARGUMENTS,
> > >>> +	ACTION_PROG_ARG_NAME,
> > >>> +	ACTION_PROG_ARG_VALUE,
> > >>> +	ACTION_PROG_ARG_END,
> > >>>  };
> > >>>
> > >>>  /** Maximum size for pattern in struct rte_flow_item_raw. */ @@
> > >>> -749,6 +756,23 @@ struct action_rss_data {
> > >>>  	uint16_t queue[ACTION_RSS_QUEUE_NUM];  };
> > >>>
> > >>> +#define ACTION_PROG_NAME_SIZE_MAX 256 #define
> > >> ACTION_PROG_ARG_NUM_MAX
> > >>> +16 #define ACTION_PROG_ARG_VALUE_SIZE_MAX 64
> > >>> +
> > >>> +/** Storage for struct rte_flow_action_prog including external data.
> > >>> +*/ struct action_prog_data {
> > >>> +	struct rte_flow_action_prog conf;
> > >>> +	struct {
> > >>> +		char name[ACTION_PROG_NAME_SIZE_MAX];
> > >>> +		struct rte_flow_action_prog_argument
> > >> args[ACTION_PROG_ARG_NUM_MAX];
> > >>> +		struct {
> > >>> +			char names[ACTION_PROG_NAME_SIZE_MAX];
> > >>> +			uint8_t
> > >> value[ACTION_PROG_ARG_VALUE_SIZE_MAX];
> > >>> +		} arg_data[ACTION_PROG_ARG_NUM_MAX];
> > >>> +	} data;
> > >>> +};
> > >>> +
> > >>>  /** Maximum data size in struct rte_flow_action_raw_encap. */
> > >>> #define ACTION_RAW_ENCAP_MAX_DATA 512  #define
> > >> RAW_ENCAP_CONFS_MAX_NUM
> > >>> 8 @@ -2169,6 +2193,7 @@ static const enum index next_action[] = {
> > >>>  	ACTION_QUOTA_QU,
> > >>>  	ACTION_IPV6_EXT_REMOVE,
> > >>>  	ACTION_IPV6_EXT_PUSH,
> > >>> +	ACTION_PROG,
> > >>>  	ZERO,
> > >>>  };
> > >>>
> > >>> @@ -2510,6 +2535,13 @@ static const enum index
> > >> action_represented_port[] = {
> > >>>  	ZERO,
> > >>>  };
> > >>>
> > >>> +static const enum index action_prog[] = {
> > >>> +	ACTION_PROG_NAME,
> > >>> +	ACTION_PROG_ARGUMENTS,
> > >>> +	ACTION_NEXT,
> > >>> +	ZERO,
> > >>> +};
> > >>> +
> > >>>  static int parse_set_raw_encap_decap(struct context *, const
> > >>> struct token
> > *,
> > >>>  				     const char *, unsigned int,
> > >>>  				     void *, unsigned int);
> > >>> @@ -2786,6 +2818,18 @@ static int
> > >>>  parse_qu_mode_name(struct context *ctx, const struct token *token,
> > >>>  		   const char *str, unsigned int len, void *buf,
> > >>>  		   unsigned int size);
> > >>> +static int
> > >>> +parse_vc_action_prog(struct context *, const struct token *,
> > >>> +		     const char *, unsigned int, void *,
> > >>> +		     unsigned int);
> > >>> +static int
> > >>> +parse_vc_action_prog_arg_name(struct context *, const struct token *,
> > >>> +			      const char *, unsigned int, void *,
> > >>> +			      unsigned int);
> > >>> +static int
> > >>> +parse_vc_action_prog_arg_value(struct context *, const struct token *,
> > >>> +			       const char *, unsigned int, void *,
> > >>> +			       unsigned int);
> > >>>  static int comp_none(struct context *, const struct token *,
> > >>>  		     unsigned int, char *, unsigned int);  static int
> > >>> comp_boolean(struct context *, const struct token *, @@ -7518,6
> > >>> +7562,48 @@ static const struct token token_list[] = {
> > >>>  		.args = ARGS(ARGS_ENTRY(struct rte_flow_item_tx_queue,
> > >>>  					tx_queue)),
> > >>>  	},
> > >>> +	[ACTION_PROG] = {
> > >>> +		.name = "prog",
> > >>> +		.help = "match a programmable action",
> > >>> +		.priv = PRIV_ACTION(PROG, sizeof(struct action_prog_data)),
> > >>> +		.next = NEXT(action_prog),
> > >>> +		.call = parse_vc_action_prog,
> > >>> +	},
> > >>> +	[ACTION_PROG_NAME] = {
> > >>> +		.name = "name",
> > >>> +		.help = "programble action name",
> > >>>
> > >>
> > >> Can you please remind me again what was the 'name' filed of "struct
> > >> rte_flow_action_prog" was for?
> > >
> > > The 'name' field serves as a means for the driver to identify an
> > > action
> > schema, enabling it to verify if the number of parameters and the size
> > of each parameter value align with the P4 definition.
> > > Subsequently, the driver translates these values into
> > > hardware-specific
> > configurations. If there is a misalignment, the PMD will return a failure.
> > >
> >
> > As I understand it is used for kind of unique action handler, but we
> > have rte_flow handler already, I am still not clear why an action
> > handler is required.
> >
> > Why driver is not using rte flow handler?
> 
> Not sure if I have understood your question correctly.
> But, the "name" field you're referring to is not related with an action handler,
> it's more like an action type.
> Just like 'RTE_FLOW_ACTION_TYPE_XXX,' which is predefined, but this action
> type is defined as device-specific.
> 
> >
> > Again driver implementation would clear more the intended usage.
> 
> At this time, I hope above sample testpmd command can be helpful in this
> matter.
> 
> >
> > >>
> > >>
> > >>> +		.next = NEXT(action_prog,
> > >> NEXT_ENTRY(ACTION_PROG_NAME_STRING)),
> > >>> +		.args = ARGS(ARGS_ENTRY(struct action_prog_data,
> > >> data.name)),
> > >>> +	},
> > >>> +	[ACTION_PROG_NAME_STRING] = {
> > >>> +		.name = "{string}",
> > >>> +		.type = "STRING",
> > >>> +		.help = "programmable action name string",
> > >>> +		.call = parse_string0,
> > >>> +	},
> > >>> +	[ACTION_PROG_ARGUMENTS] = {
> > >>> +		.name = "arguments",
> > >>> +		.help = "programmable action name",
> > >>> +		.next = NEXT(action_prog,
> > >> NEXT_ENTRY(ACTION_PROG_ARG_NAME)),
> > >>> +		.call = parse_vc_conf,
> > >>> +	},
> > >>> +	[ACTION_PROG_ARG_NAME] = {
> > >>> +		.name = "{string}",
> > >>> +		.help = "programmable action argument name",
> > >>> +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_VALUE)),
> > >>> +		.call = parse_vc_action_prog_arg_name,
> > >>> +	},
> > >>> +	[ACTION_PROG_ARG_VALUE] = {
> > >>> +		.name = "{hex}",
> > >>> +		.help = "programmable action argument value",
> > >>> +		.next = NEXT(NEXT_ENTRY(ACTION_PROG_ARG_END,
> > >> ACTION_PROG_ARG_NAME)),
> > >>> +		.call = parse_vc_action_prog_arg_value,
> > >>> +	},
> > >>> +	[ACTION_PROG_ARG_END] = {
> > >>> +		.name = "end",
> > >>> +		.help = "end of the programmable action arguments",
> > >>> +	},
> > >>> +
> > >>>
> > >>
> > >> Does this means two 'end' required if multiple args provided, like:
> > >> prog name "name" arguments field0 03FF field1 1 end / end I am
> > >> aware there is variable length of key/value, and need a marker to
> > >> stop, but this end specific for action is not used,
> > >
> > >  Actually I borrowed the idea from the queue group in the RSS action:
> > >
> > > 'actions rss queues 0 1 2 3 end / end ..."
> > >
> > > The difference is that the 'end' check was previously hidden within
> > > the
> > 'parse_vc_action_rss_queue' function, while in my implementation, I've
> > defined it as a distinct state.
> > >
> >
> >
> > My concern is if ACTION_xxx_END tokens be confusing or redundant if we
> > have more of them.
> >
> > Is there a benefit to have it as token, comparing to have it in the
> > parser functions as RSS does?
> 
> In my opinion, adding more 'ACTION_xxx_END' won't negatively impact code
> readability.
> It enhances the transparency of the syntax and may even facilitate potential
> automation.


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

* Re: [PATCH v4] app/testpmd: enable cli for programmable action
  2023-10-12  0:04           ` Zhang, Qi Z
@ 2023-10-12  1:32             ` Stephen Hemminger
  2023-10-27 11:06               ` Zhang, Qi Z
  0 siblings, 1 reply; 20+ messages in thread
From: Stephen Hemminger @ 2023-10-12  1:32 UTC (permalink / raw)
  To: Zhang, Qi Z
  Cc: Ferruh Yigit, Singh, Aman Deep, Zhang, Yuying, dev, Dumitrescu,
	Cristian, orika

On Thu, 12 Oct 2023 00:04:00 +0000
"Zhang, Qi Z" <qi.z.zhang@intel.com> wrote:

> > > >> Is there an existing driver implementation, checking it helps to
> > > >> understand feature implementation?  
> > > >
> > > > This work is still ongoing, currently we target to upstream on DPDK
> > > > 24.03

Then the testpmd changes must wait for 24.03!
Please no infrastructure before any users, you will get it wrong and have
to change it when driver is ready.

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

* RE: [PATCH v4] app/testpmd: enable cli for programmable action
  2023-10-12  1:32             ` Stephen Hemminger
@ 2023-10-27 11:06               ` Zhang, Qi Z
  0 siblings, 0 replies; 20+ messages in thread
From: Zhang, Qi Z @ 2023-10-27 11:06 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Ferruh Yigit, Singh, Aman Deep, Zhang, Yuying, dev, Dumitrescu,
	Cristian, orika



> -----Original Message-----
> From: Stephen Hemminger <stephen@networkplumber.org>
> Sent: Thursday, October 12, 2023 9:32 AM
> To: Zhang, Qi Z <qi.z.zhang@intel.com>
> Cc: Ferruh Yigit <ferruh.yigit@amd.com>; Singh, Aman Deep
> <aman.deep.singh@intel.com>; Zhang, Yuying <yuying.zhang@intel.com>;
> dev@dpdk.org; Dumitrescu, Cristian <cristian.dumitrescu@intel.com>;
> orika@nvidia.com
> Subject: Re: [PATCH v4] app/testpmd: enable cli for programmable action
> 
> On Thu, 12 Oct 2023 00:04:00 +0000
> "Zhang, Qi Z" <qi.z.zhang@intel.com> wrote:
> 
> > > > >> Is there an existing driver implementation, checking it helps
> > > > >> to understand feature implementation?
> > > > >
> > > > > This work is still ongoing, currently we target to upstream on
> > > > > DPDK
> > > > > 24.03
> 
> Then the testpmd changes must wait for 24.03!
> Please no infrastructure before any users, you will get it wrong and have to
> change it when driver is ready.

Kindly FYI
The patch that prove the usage on CPFL PMD.
https://patchwork.dpdk.org/project/dpdk/patch/20231027094258.3775320-1-wenjing.qiao@intel.com/

Regards
Qi

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

* Re: [PATCH v6] app/testpmd: enable cli for programmable action
  2023-10-11 12:03 ` [PATCH v6] " Qi Zhang
@ 2024-02-08  1:10   ` Ferruh Yigit
  2024-04-18 15:39     ` Ferruh Yigit
  0 siblings, 1 reply; 20+ messages in thread
From: Ferruh Yigit @ 2024-02-08  1:10 UTC (permalink / raw)
  To: Qi Zhang, aman.deep.singh, yuying.zhang, orika, cristian.dumitrescu; +Cc: dev

On 10/11/2023 1:03 PM, Qi Zhang wrote:
> Parsing command line for rte_flow_action_prog.
> 
> Syntax:
> 
> "prog name <name> [arguments <arg_name_0> <arg_value_0> \
>  <arg_name_1> <arg_value1> ... end]"
> 
> Use parse_string0 to parse name string.
> Use parse_hex to parse hex string.
> Use struct action_prog_data to store parsed result.
> 
> Example:
> 
> Action with 2 arguments:
> 
> "prog name action0 arguments field0 03FF field1 55AA end"
> 
> Action without argument:
> 
> "prog name action1"
> 
> Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
> 
>

Hi Ori, Cristian, can you please help reviewing this patch?


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

* Re: [PATCH v6] app/testpmd: enable cli for programmable action
  2024-02-08  1:10   ` Ferruh Yigit
@ 2024-04-18 15:39     ` Ferruh Yigit
  0 siblings, 0 replies; 20+ messages in thread
From: Ferruh Yigit @ 2024-04-18 15:39 UTC (permalink / raw)
  To: Qi Zhang, aman.deep.singh, yuying.zhang, orika, cristian.dumitrescu
  Cc: dev, Mcnamara, John, Bruce Richardson

On 2/8/2024 1:10 AM, Ferruh Yigit wrote:
> On 10/11/2023 1:03 PM, Qi Zhang wrote:
>> Parsing command line for rte_flow_action_prog.
>>
>> Syntax:
>>
>> "prog name <name> [arguments <arg_name_0> <arg_value_0> \
>>  <arg_name_1> <arg_value1> ... end]"
>>
>> Use parse_string0 to parse name string.
>> Use parse_hex to parse hex string.
>> Use struct action_prog_data to store parsed result.
>>
>> Example:
>>
>> Action with 2 arguments:
>>
>> "prog name action0 arguments field0 03FF field1 55AA end"
>>
>> Action without argument:
>>
>> "prog name action1"
>>
>> Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
>>
>>
> 
> Hi Ori, Cristian, can you please help reviewing this patch?
> 

Is this patch still/active valid?

Without this patch 'RTE_FLOW_ACTION_TYPE_PROG', programming via P4
language, is not supported via testpmd, so I believe missing this patch
makes testing the feature difficult.


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

end of thread, other threads:[~2024-04-18 15:39 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-05 10:02 [PATCH 1/2] app/testpmd: enable cli for programmable action Qi Zhang
2023-10-05 11:42 ` [PATCH v2] " Qi Zhang
2023-10-05  4:32   ` Stephen Hemminger
2023-10-06  2:37     ` Zhang, Qi Z
2023-10-06 11:07 ` [PATCH v3] " Qi Zhang
2023-10-06 12:35   ` Dumitrescu, Cristian
2023-10-07  1:50     ` Zhang, Qi Z
2023-10-07 10:47 ` [PATCH v4] " Qi Zhang
2023-10-08  0:06   ` Dumitrescu, Cristian
2023-10-10 10:49   ` Ferruh Yigit
2023-10-11  2:24     ` Zhang, Qi Z
2023-10-11 10:20       ` Ferruh Yigit
2023-10-11 13:19         ` Zhang, Qi Z
2023-10-12  0:04           ` Zhang, Qi Z
2023-10-12  1:32             ` Stephen Hemminger
2023-10-27 11:06               ` Zhang, Qi Z
2023-10-11 11:58 ` [PATCH v5] " Qi Zhang
2023-10-11 12:03 ` [PATCH v6] " Qi Zhang
2024-02-08  1:10   ` Ferruh Yigit
2024-04-18 15:39     ` Ferruh Yigit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).