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 sent to
port 2, and the each second packet will also be sent to e-switch
manager vport.

Signed-off-by: Jiawei Wang <jiaw...@mellanox.com>
Acked-by: Ori Kam <or...@mellanox.com>
---
 app/test-pmd/cmdline_flow.c | 285 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 276 insertions(+), 9 deletions(-)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 4e2006c..6b1e515 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,
@@ -349,6 +351,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. */
@@ -484,6 +490,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
 
@@ -1161,6 +1183,7 @@ struct parse_action_priv {
        ACTION_SET_IPV4_DSCP,
        ACTION_SET_IPV6_DSCP,
        ACTION_AGE,
+       ACTION_SAMPLE,
        ZERO,
 };
 
@@ -1393,9 +1416,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);
@@ -1460,7 +1502,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);
@@ -1531,6 +1581,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[] = {
@@ -3612,11 +3664,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. */
@@ -3647,6 +3701,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",
@@ -3750,6 +3821,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. */
@@ -5207,6 +5309,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,
@@ -5971,6 +6143,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;
 }
 
@@ -6007,11 +6211,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;
 }
@@ -6162,6 +6363,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;
 
@@ -6607,7 +6826,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
@@ -6624,6 +6889,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) {
-- 
1.8.3.1

Reply via email to