[v2] app/testpmd: enable cli for programmable action

Message ID 20231005114238.243388-1-qi.z.zhang@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series [v2] app/testpmd: enable cli for programmable action |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/github-robot: build fail github build: failed
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-sample-apps-testing success Testing PASS
ci/iol-unit-arm64-testing success Testing PASS
ci/iol-compile-amd64-testing success Testing PASS
ci/iol-unit-amd64-testing success Testing PASS
ci/iol-compile-arm64-testing success Testing PASS

Commit Message

Qi Zhang Oct. 5, 2023, 11:42 a.m. UTC
  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(+)
  

Comments

Stephen Hemminger Oct. 5, 2023, 4:32 a.m. UTC | #1
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.
  
Qi Zhang Oct. 6, 2023, 2:37 a.m. UTC | #2
> -----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.
  

Patch

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,