[v7,07/12] app/testpmd: add testpmd command for sample action

Message ID 1600795158-67060-8-git-send-email-jiaweiw@nvidia.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series support the flow-based traffic sampling |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Jiawei Wang Sept. 22, 2020, 5:19 p.m. UTC
  Add a new testpmd command 'set sample_actions' that supports the multiple
sample actions list configuration by using the index:
set sample_actions <index> <actions list>

The examples for the sample flow use case and result as below:

1. set sample_actions 0 mark id 0x8 / queue index 2 / end
.. pattern eth / end actions sample ratio 2 index 0 / jump group 2 ...

This flow will result in all the matched ingress packets will be
jumped to next flow table, and the each second packet will be
marked and sent to queue 2 of the control application.

2. ...pattern eth / end actions sample ratio 2 / port_id id 2 ...

The flow will result in all the matched ingress packets will be
duplicated and sent to the representor peer (VF or wire) on DPDK port 2,
and the each second packet will also be sent to E-Switch manager vport.

Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
---
 app/test-pmd/cmdline_flow.c | 285 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 276 insertions(+), 9 deletions(-)
  

Patch

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 6263d30..27fa294 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -56,6 +56,8 @@  enum index {
 	SET_RAW_ENCAP,
 	SET_RAW_DECAP,
 	SET_RAW_INDEX,
+	SET_SAMPLE_ACTIONS,
+	SET_SAMPLE_INDEX,
 
 	/* Top-level command. */
 	FLOW,
@@ -358,6 +360,10 @@  enum index {
 	ACTION_SET_IPV6_DSCP_VALUE,
 	ACTION_AGE,
 	ACTION_AGE_TIMEOUT,
+	ACTION_SAMPLE,
+	ACTION_SAMPLE_RATIO,
+	ACTION_SAMPLE_INDEX,
+	ACTION_SAMPLE_INDEX_VALUE,
 };
 
 /** Maximum size for pattern in struct rte_flow_item_raw. */
@@ -493,6 +499,22 @@  struct action_nvgre_encap_data {
 
 struct mplsoudp_decap_conf mplsoudp_decap_conf;
 
+#define ACTION_SAMPLE_ACTIONS_NUM 10
+#define RAW_SAMPLE_CONFS_MAX_NUM 8
+/** Storage for struct rte_flow_action_sample including external data. */
+struct action_sample_data {
+	struct rte_flow_action_sample conf;
+	uint32_t idx;
+};
+/** Storage for struct rte_flow_action_sample. */
+struct raw_sample_conf {
+	struct rte_flow_action data[ACTION_SAMPLE_ACTIONS_NUM];
+};
+struct raw_sample_conf raw_sample_confs[RAW_SAMPLE_CONFS_MAX_NUM];
+struct rte_flow_action_mark sample_mark[RAW_SAMPLE_CONFS_MAX_NUM];
+struct rte_flow_action_queue sample_queue[RAW_SAMPLE_CONFS_MAX_NUM];
+struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM];
+
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
 
@@ -1189,6 +1211,7 @@  struct parse_action_priv {
 	ACTION_SET_IPV4_DSCP,
 	ACTION_SET_IPV6_DSCP,
 	ACTION_AGE,
+	ACTION_SAMPLE,
 	ZERO,
 };
 
@@ -1421,9 +1444,28 @@  struct parse_action_priv {
 	ZERO,
 };
 
+static const enum index action_sample[] = {
+	ACTION_SAMPLE,
+	ACTION_SAMPLE_RATIO,
+	ACTION_SAMPLE_INDEX,
+	ACTION_NEXT,
+	ZERO,
+};
+
+static const enum index next_action_sample[] = {
+	ACTION_QUEUE,
+	ACTION_MARK,
+	ACTION_COUNT,
+	ACTION_NEXT,
+	ZERO,
+};
+
 static int parse_set_raw_encap_decap(struct context *, const struct token *,
 				     const char *, unsigned int,
 				     void *, unsigned int);
+static int parse_set_sample_action(struct context *, const struct token *,
+				   const char *, unsigned int,
+				   void *, unsigned int);
 static int parse_set_init(struct context *, const struct token *,
 			  const char *, unsigned int,
 			  void *, unsigned int);
@@ -1491,7 +1533,15 @@  static int parse_vc_action_raw_decap_index(struct context *,
 static int parse_vc_action_set_meta(struct context *ctx,
 				    const struct token *token, const char *str,
 				    unsigned int len, void *buf,
+					unsigned int size);
+static int parse_vc_action_sample(struct context *ctx,
+				    const struct token *token, const char *str,
+				    unsigned int len, void *buf,
 				    unsigned int size);
+static int
+parse_vc_action_sample_index(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size);
 static int parse_destroy(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
@@ -1562,6 +1612,8 @@  static int comp_vc_action_rss_queue(struct context *, const struct token *,
 				    unsigned int, char *, unsigned int);
 static int comp_set_raw_index(struct context *, const struct token *,
 			      unsigned int, char *, unsigned int);
+static int comp_set_sample_index(struct context *, const struct token *,
+			      unsigned int, char *, unsigned int);
 
 /** Token definitions. */
 static const struct token token_list[] = {
@@ -3703,11 +3755,13 @@  static int comp_set_raw_index(struct context *, const struct token *,
 	/* Top level command. */
 	[SET] = {
 		.name = "set",
-		.help = "set raw encap/decap data",
-		.type = "set raw_encap|raw_decap <index> <pattern>",
+		.help = "set raw encap/decap/sample data",
+		.type = "set raw_encap|raw_decap <index> <pattern>"
+				" or set sample_actions <index> <action>",
 		.next = NEXT(NEXT_ENTRY
 			     (SET_RAW_ENCAP,
-			      SET_RAW_DECAP)),
+			      SET_RAW_DECAP,
+			      SET_SAMPLE_ACTIONS)),
 		.call = parse_set_init,
 	},
 	/* Sub-level commands. */
@@ -3738,6 +3792,23 @@  static int comp_set_raw_index(struct context *, const struct token *,
 		.next = NEXT(next_item),
 		.call = parse_port,
 	},
+	[SET_SAMPLE_INDEX] = {
+		.name = "{index}",
+		.type = "UNSIGNED",
+		.help = "index of sample actions",
+		.next = NEXT(next_action_sample),
+		.call = parse_port,
+	},
+	[SET_SAMPLE_ACTIONS] = {
+		.name = "sample_actions",
+		.help = "set sample actions list",
+		.next = NEXT(NEXT_ENTRY(SET_SAMPLE_INDEX)),
+		.args = ARGS(ARGS_ENTRY_ARB_BOUNDED
+				(offsetof(struct buffer, port),
+				 sizeof(((struct buffer *)0)->port),
+				 0, RAW_SAMPLE_CONFS_MAX_NUM - 1)),
+		.call = parse_set_sample_action,
+	},
 	[ACTION_SET_TAG] = {
 		.name = "set_tag",
 		.help = "set tag",
@@ -3841,6 +3912,37 @@  static int comp_set_raw_index(struct context *, const struct token *,
 		.next = NEXT(action_age, NEXT_ENTRY(UNSIGNED)),
 		.call = parse_vc_conf,
 	},
+	[ACTION_SAMPLE] = {
+		.name = "sample",
+		.help = "set a sample action",
+		.next = NEXT(action_sample),
+		.priv = PRIV_ACTION(SAMPLE,
+			sizeof(struct action_sample_data)),
+		.call = parse_vc_action_sample,
+	},
+	[ACTION_SAMPLE_RATIO] = {
+		.name = "ratio",
+		.help = "flow sample ratio value",
+		.next = NEXT(action_sample, NEXT_ENTRY(UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY_ARB
+			     (offsetof(struct action_sample_data, conf) +
+			      offsetof(struct rte_flow_action_sample, ratio),
+			      sizeof(((struct rte_flow_action_sample *)0)->
+				     ratio))),
+	},
+	[ACTION_SAMPLE_INDEX] = {
+		.name = "index",
+		.help = "the index of sample actions list",
+		.next = NEXT(NEXT_ENTRY(ACTION_SAMPLE_INDEX_VALUE)),
+	},
+	[ACTION_SAMPLE_INDEX_VALUE] = {
+		.name = "{index}",
+		.type = "UNSIGNED",
+		.help = "unsigned integer value",
+		.next = NEXT(NEXT_ENTRY(ACTION_NEXT)),
+		.call = parse_vc_action_sample_index,
+		.comp = comp_set_sample_index,
+	},
 };
 
 /** Remove and return last entry from argument stack. */
@@ -5351,6 +5453,76 @@  static int comp_set_raw_index(struct context *, const struct token *,
 	return len;
 }
 
+static int
+parse_vc_action_sample(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_sample_data *action_sample_data = NULL;
+	static struct rte_flow_action end_action = {
+		RTE_FLOW_ACTION_TYPE_END, 0
+	};
+	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];
+	/* Point to selected object. */
+	ctx->object = out->args.vc.data;
+	ctx->objmask = NULL;
+	/* Copy the headers to the buffer. */
+	action_sample_data = ctx->object;
+	action_sample_data->conf.actions = &end_action;
+	action->conf = &action_sample_data->conf;
+	return ret;
+}
+
+static int
+parse_vc_action_sample_index(struct context *ctx, const struct token *token,
+				const char *str, unsigned int len, void *buf,
+				unsigned int size)
+{
+	struct action_sample_data *action_sample_data;
+	struct rte_flow_action *action;
+	const struct arg *arg;
+	struct buffer *out = buf;
+	int ret;
+	uint16_t idx;
+
+	RTE_SET_USED(token);
+	RTE_SET_USED(buf);
+	RTE_SET_USED(size);
+	if (ctx->curr != ACTION_SAMPLE_INDEX_VALUE)
+		return -1;
+	arg = ARGS_ENTRY_ARB_BOUNDED
+		(offsetof(struct action_sample_data, idx),
+		 sizeof(((struct action_sample_data *)0)->idx),
+		 0, RAW_SAMPLE_CONFS_MAX_NUM - 1);
+	if (push_args(ctx, arg))
+		return -1;
+	ret = parse_int(ctx, token, str, len, NULL, 0);
+	if (ret < 0) {
+		pop_args(ctx);
+		return -1;
+	}
+	if (!ctx->object)
+		return len;
+	action = &out->args.vc.actions[out->args.vc.actions_n - 1];
+	action_sample_data = ctx->object;
+	idx = action_sample_data->idx;
+	action_sample_data->conf.actions = raw_sample_confs[idx].data;
+	action->conf = &action_sample_data->conf;
+	return len;
+}
+
 /** Parse tokens for destroy command. */
 static int
 parse_destroy(struct context *ctx, const struct token *token,
@@ -6115,6 +6287,38 @@  static int comp_set_raw_index(struct context *, const struct token *,
 	if (!out->command)
 		return -1;
 	out->command = ctx->curr;
+	/* For encap/decap we need is pattern */
+	out->args.vc.pattern = (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+						       sizeof(double));
+	return len;
+}
+
+/** Parse set command, initialize output buffer for subsequent tokens. */
+static int
+parse_set_sample_action(struct context *ctx, const struct token *token,
+			  const char *str, unsigned int len,
+			  void *buf, unsigned int size)
+{
+	struct buffer *out = buf;
+
+	/* Token name must match. */
+	if (parse_default(ctx, token, str, len, NULL, 0) < 0)
+		return -1;
+	/* Nothing else to do if there is no buffer. */
+	if (!out)
+		return len;
+	/* Make sure buffer is large enough. */
+	if (size < sizeof(*out))
+		return -1;
+	ctx->objdata = 0;
+	ctx->objmask = NULL;
+	ctx->object = out;
+	if (!out->command)
+		return -1;
+	out->command = ctx->curr;
+	/* For sampler we need is actions */
+	out->args.vc.actions = (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+						       sizeof(double));
 	return len;
 }
 
@@ -6151,11 +6355,8 @@  static int comp_set_raw_index(struct context *, const struct token *,
 			return -1;
 		out->command = ctx->curr;
 		out->args.vc.data = (uint8_t *)out + size;
-		/* All we need is pattern */
-		out->args.vc.pattern =
-			(void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
-					       sizeof(double));
-		ctx->object = out->args.vc.pattern;
+		ctx->object  = (void *)RTE_ALIGN_CEIL((uintptr_t)(out + 1),
+						       sizeof(double));
 	}
 	return len;
 }
@@ -6306,6 +6507,24 @@  static int comp_set_raw_index(struct context *, const struct token *,
 	return nb;
 }
 
+/** Complete index number for set raw_encap/raw_decap commands. */
+static int
+comp_set_sample_index(struct context *ctx, const struct token *token,
+		   unsigned int ent, char *buf, unsigned int size)
+{
+	uint16_t idx = 0;
+	uint16_t nb = 0;
+
+	RTE_SET_USED(ctx);
+	RTE_SET_USED(token);
+	for (idx = 0; idx < RAW_SAMPLE_CONFS_MAX_NUM; ++idx) {
+		if (buf && idx == ent)
+			return snprintf(buf, size, "%u", idx);
+		++nb;
+	}
+	return nb;
+}
+
 /** Internal context. */
 static struct context cmd_flow_context;
 
@@ -6751,7 +6970,53 @@  static int comp_set_raw_index(struct context *, const struct token *,
 	return mask;
 }
 
-
+/** Dispatch parsed buffer to function calls. */
+static void
+cmd_set_raw_parsed_sample(const struct buffer *in)
+{
+	uint32_t n = in->args.vc.actions_n;
+	uint32_t i = 0;
+	struct rte_flow_action *action = NULL;
+	struct rte_flow_action *data = NULL;
+	size_t size = 0;
+	uint16_t idx = in->port; /* We borrow port field as index */
+	uint32_t max_size = sizeof(struct rte_flow_action) *
+						ACTION_SAMPLE_ACTIONS_NUM;
+
+	RTE_ASSERT(in->command == SET_SAMPLE_ACTIONS);
+	data = (struct rte_flow_action *)&raw_sample_confs[idx].data;
+	memset(data, 0x00, max_size);
+	for (; i <= n - 1; i++) {
+		action = in->args.vc.actions + i;
+		if (action->type == RTE_FLOW_ACTION_TYPE_END)
+			break;
+		switch (action->type) {
+		case RTE_FLOW_ACTION_TYPE_MARK:
+			size = sizeof(struct rte_flow_action_mark);
+			rte_memcpy(&sample_mark[idx],
+				(const void *)action->conf, size);
+			action->conf = &sample_mark[idx];
+			break;
+		case RTE_FLOW_ACTION_TYPE_COUNT:
+			size = sizeof(struct rte_flow_action_count);
+			rte_memcpy(&sample_count[idx],
+				(const void *)action->conf, size);
+			action->conf = &sample_count[idx];
+			break;
+		case RTE_FLOW_ACTION_TYPE_QUEUE:
+			size = sizeof(struct rte_flow_action_queue);
+			rte_memcpy(&sample_queue[idx],
+				(const void *)action->conf, size);
+			action->conf = &sample_queue[idx];
+			break;
+		default:
+			printf("Error - Not supported action\n");
+			return;
+		}
+		rte_memcpy(data, action, sizeof(struct rte_flow_action));
+		data++;
+	}
+}
 
 /** Dispatch parsed buffer to function calls. */
 static void
@@ -6768,6 +7033,8 @@  static int comp_set_raw_index(struct context *, const struct token *,
 	uint16_t proto = 0;
 	uint16_t idx = in->port; /* We borrow port field as index */
 
+	if (in->command == SET_SAMPLE_ACTIONS)
+		return cmd_set_raw_parsed_sample(in);
 	RTE_ASSERT(in->command == SET_RAW_ENCAP ||
 		   in->command == SET_RAW_DECAP);
 	if (in->command == SET_RAW_ENCAP) {