> -----Original Message-----
> From: Jiawei Wang <jiaw...@mellanox.com>
> Sent: Thursday, June 25, 2020 7:26 PM
> To: Ori Kam <or...@mellanox.com>; Slava Ovsiienko
> <viachesl...@mellanox.com>; Matan Azrad <ma...@mellanox.com>
> Cc: dev@dpdk.org; Thomas Monjalon <tho...@monjalon.net>; Raslan
> Darawsheh <rasl...@mellanox.com>; ian.sto...@intel.com; f...@redhat.com;
> Jiawei(Jonny) Wang <jiaw...@mellanox.com>
> Subject: [PATCH 8/8] app/testpmd: add testpmd command for sample action
> 
> 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>
> ---
>  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

Acked-by: Ori Kam <or...@mellanox.com>
Thanks,
Ori

Reply via email to