app/testpmd: add command for queue setup
[dpdk.git] / app / test-pmd / cmdline_flow.c
index df16d2a..f0b4b7b 100644 (file)
@@ -1,34 +1,6 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright 2016 6WIND S.A.
- *   Copyright 2016 Mellanox.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in
- *       the documentation and/or other materials provided with the
- *       distribution.
- *     * Neither the name of 6WIND S.A. nor the names of its
- *       contributors may be used to endorse or promote products derived
- *       from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2016 6WIND S.A.
+ * Copyright 2016 Mellanox Technologies, Ltd
  */
 
 #include <stddef.h>
@@ -175,6 +147,9 @@ enum index {
        ITEM_GTP_TEID,
        ITEM_GTPC,
        ITEM_GTPU,
+       ITEM_GENEVE,
+       ITEM_GENEVE_VNI,
+       ITEM_GENEVE_PROTO,
 
        /* Validate/create actions. */
        ACTIONS,
@@ -192,6 +167,10 @@ enum index {
        ACTION_DUP,
        ACTION_DUP_INDEX,
        ACTION_RSS,
+       ACTION_RSS_TYPES,
+       ACTION_RSS_TYPE,
+       ACTION_RSS_KEY,
+       ACTION_RSS_KEY_LEN,
        ACTION_RSS_QUEUES,
        ACTION_RSS_QUEUE,
        ACTION_PF,
@@ -209,13 +188,19 @@ enum index {
 #define ITEM_RAW_SIZE \
        (offsetof(struct rte_flow_item_raw, pattern) + ITEM_RAW_PATTERN_SIZE)
 
-/** Number of queue[] entries in struct rte_flow_action_rss. */
-#define ACTION_RSS_NUM 32
-
-/** Storage size for struct rte_flow_action_rss including queues. */
-#define ACTION_RSS_SIZE \
-       (offsetof(struct rte_flow_action_rss, queue) + \
-        sizeof(*((struct rte_flow_action_rss *)0)->queue) * ACTION_RSS_NUM)
+/** Maximum number of queue indices in struct rte_flow_action_rss. */
+#define ACTION_RSS_QUEUE_NUM 32
+
+/** Storage for struct rte_flow_action_rss including external data. */
+union action_rss_data {
+       struct rte_flow_action_rss conf;
+       struct {
+               uint8_t conf_data[offsetof(struct rte_flow_action_rss, queue)];
+               uint16_t queue[ACTION_RSS_QUEUE_NUM];
+               struct rte_eth_rss_conf rss_conf;
+               uint8_t rss_key[RSS_HASH_KEY_LENGTH];
+       } s;
+};
 
 /** Maximum number of subsequent tokens and arguments on the stack. */
 #define CTX_STACK_SIZE 16
@@ -242,6 +227,9 @@ struct context {
 struct arg {
        uint32_t hton:1; /**< Use network byte ordering. */
        uint32_t sign:1; /**< Value is signed. */
+       uint32_t bounded:1; /**< Value is bounded. */
+       uintmax_t min; /**< Minimum value if bounded. */
+       uintmax_t max; /**< Maximum value if bounded. */
        uint32_t offset; /**< Relative offset from ctx->object. */
        uint32_t size; /**< Field size. */
        const uint8_t *mask; /**< Bit-mask to use instead of offset/size. */
@@ -341,6 +329,23 @@ struct token {
                .size = (sz), \
        })
 
+/** Static initializer for ARGS() with arbitrary offset and size. */
+#define ARGS_ENTRY_ARB(o, s) \
+       (&(const struct arg){ \
+               .offset = (o), \
+               .size = (s), \
+       })
+
+/** Same as ARGS_ENTRY_ARB() with bounded values. */
+#define ARGS_ENTRY_ARB_BOUNDED(o, s, i, a) \
+       (&(const struct arg){ \
+               .bounded = 1, \
+               .min = (i), \
+               .max = (a), \
+               .offset = (o), \
+               .size = (s), \
+       })
+
 /** Same as ARGS_ENTRY() using network byte ordering. */
 #define ARGS_ENTRY_HTON(s, f) \
        (&(const struct arg){ \
@@ -460,6 +465,7 @@ static const enum index next_item[] = {
        ITEM_GTP,
        ITEM_GTPC,
        ITEM_GTPU,
+       ITEM_GENEVE,
        ZERO,
 };
 
@@ -603,6 +609,13 @@ static const enum index item_gtp[] = {
        ZERO,
 };
 
+static const enum index item_geneve[] = {
+       ITEM_GENEVE_VNI,
+       ITEM_GENEVE_PROTO,
+       ITEM_NEXT,
+       ZERO,
+};
+
 static const enum index next_action[] = {
        ACTION_END,
        ACTION_VOID,
@@ -639,6 +652,9 @@ static const enum index action_dup[] = {
 };
 
 static const enum index action_rss[] = {
+       ACTION_RSS_TYPES,
+       ACTION_RSS_KEY,
+       ACTION_RSS_KEY_LEN,
        ACTION_RSS_QUEUES,
        ACTION_NEXT,
        ZERO,
@@ -667,6 +683,12 @@ static int parse_vc_spec(struct context *, const struct token *,
                         const char *, unsigned int, void *, unsigned int);
 static int parse_vc_conf(struct context *, const struct token *,
                         const char *, unsigned int, void *, unsigned int);
+static int parse_vc_action_rss(struct context *, const struct token *,
+                              const char *, unsigned int, void *,
+                              unsigned int);
+static int parse_vc_action_rss_type(struct context *, const struct token *,
+                                   const char *, unsigned int, void *,
+                                   unsigned int);
 static int parse_vc_action_rss_queue(struct context *, const struct token *,
                                     const char *, unsigned int, void *,
                                     unsigned int);
@@ -722,6 +744,8 @@ static int comp_port(struct context *, const struct token *,
                     unsigned int, char *, unsigned int);
 static int comp_rule_id(struct context *, const struct token *,
                        unsigned int, char *, unsigned int);
+static int comp_vc_action_rss_type(struct context *, const struct token *,
+                                  unsigned int, char *, unsigned int);
 static int comp_vc_action_rss_queue(struct context *, const struct token *,
                                    unsigned int, char *, unsigned int);
 
@@ -1470,6 +1494,26 @@ static const struct token token_list[] = {
                .next = NEXT(item_gtp),
                .call = parse_vc,
        },
+       [ITEM_GENEVE] = {
+               .name = "geneve",
+               .help = "match GENEVE header",
+               .priv = PRIV_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
+               .next = NEXT(item_geneve),
+               .call = parse_vc,
+       },
+       [ITEM_GENEVE_VNI] = {
+               .name = "vni",
+               .help = "virtual network identifier",
+               .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve, vni)),
+       },
+       [ITEM_GENEVE_PROTO] = {
+               .name = "protocol",
+               .help = "GENEVE protocol type",
+               .next = NEXT(item_geneve, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_geneve,
+                                            protocol)),
+       },
 
        /* Validate/create actions. */
        [ACTIONS] = {
@@ -1570,9 +1614,46 @@ static const struct token token_list[] = {
        [ACTION_RSS] = {
                .name = "rss",
                .help = "spread packets among several queues",
-               .priv = PRIV_ACTION(RSS, ACTION_RSS_SIZE),
+               .priv = PRIV_ACTION(RSS, sizeof(union action_rss_data)),
                .next = NEXT(action_rss),
-               .call = parse_vc,
+               .call = parse_vc_action_rss,
+       },
+       [ACTION_RSS_TYPES] = {
+               .name = "types",
+               .help = "RSS hash types",
+               .next = NEXT(action_rss, NEXT_ENTRY(ACTION_RSS_TYPE)),
+       },
+       [ACTION_RSS_TYPE] = {
+               .name = "{type}",
+               .help = "RSS hash type",
+               .call = parse_vc_action_rss_type,
+               .comp = comp_vc_action_rss_type,
+       },
+       [ACTION_RSS_KEY] = {
+               .name = "key",
+               .help = "RSS hash key",
+               .next = NEXT(action_rss, NEXT_ENTRY(STRING)),
+               .args = ARGS(ARGS_ENTRY_ARB
+                            (((uintptr_t)&((union action_rss_data *)0)->
+                              s.rss_conf.rss_key_len),
+                             sizeof(((struct rte_eth_rss_conf *)0)->
+                                    rss_key_len)),
+                            ARGS_ENTRY_ARB
+                            (((uintptr_t)((union action_rss_data *)0)->
+                              s.rss_key),
+                             RSS_HASH_KEY_LENGTH)),
+       },
+       [ACTION_RSS_KEY_LEN] = {
+               .name = "key_len",
+               .help = "RSS hash key length in bytes",
+               .next = NEXT(action_rss, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY_ARB_BOUNDED
+                            (((uintptr_t)&((union action_rss_data *)0)->
+                              s.rss_conf.rss_key_len),
+                             sizeof(((struct rte_eth_rss_conf *)0)->
+                                    rss_key_len),
+                             0,
+                             RSS_HASH_KEY_LENGTH)),
        },
        [ACTION_RSS_QUEUES] = {
                .name = "queues",
@@ -1906,6 +1987,7 @@ parse_vc(struct context *ctx, const struct token *token,
                        return -1;
                *action = (struct rte_flow_action){
                        .type = priv->type,
+                       .conf = data_size ? data : NULL,
                };
                ++out->args.vc.actions_n;
                ctx->object = action;
@@ -1986,7 +2068,6 @@ parse_vc_conf(struct context *ctx, const struct token *token,
              void *buf, unsigned int size)
 {
        struct buffer *out = buf;
-       struct rte_flow_action *action;
 
        (void)size;
        /* Token name must match. */
@@ -1995,14 +2076,108 @@ parse_vc_conf(struct context *ctx, const struct token *token,
        /* Nothing else to do if there is no buffer. */
        if (!out)
                return len;
+       /* Point to selected object. */
+       ctx->object = out->args.vc.data;
+       ctx->objmask = NULL;
+       return len;
+}
+
+/** Parse RSS action. */
+static int
+parse_vc_action_rss(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;
+       union action_rss_data *action_rss_data;
+       unsigned int 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];
        /* Point to selected object. */
        ctx->object = out->args.vc.data;
        ctx->objmask = NULL;
-       /* Update configuration pointer. */
-       action->conf = ctx->object;
+       /* Set up default configuration. */
+       action_rss_data = ctx->object;
+       *action_rss_data = (union action_rss_data){
+               .conf = (struct rte_flow_action_rss){
+                       .rss_conf = &action_rss_data->s.rss_conf,
+                       .num = RTE_MIN(nb_rxq, ACTION_RSS_QUEUE_NUM),
+               },
+       };
+       action_rss_data->s.rss_conf = (struct rte_eth_rss_conf){
+               .rss_key = action_rss_data->s.rss_key,
+               .rss_key_len = sizeof(action_rss_data->s.rss_key),
+               .rss_hf = rss_hf,
+       };
+       strncpy((void *)action_rss_data->s.rss_key,
+               "testpmd's default RSS hash key",
+               sizeof(action_rss_data->s.rss_key));
+       for (i = 0; i < action_rss_data->conf.num; ++i)
+               action_rss_data->conf.queue[i] = i;
+       if (!port_id_is_invalid(ctx->port, DISABLED_WARN) &&
+           ctx->port != (portid_t)RTE_PORT_ALL) {
+               struct rte_eth_dev_info info;
+
+               rte_eth_dev_info_get(ctx->port, &info);
+               action_rss_data->s.rss_conf.rss_key_len =
+                       RTE_MIN(sizeof(action_rss_data->s.rss_key),
+                               info.hash_key_size);
+       }
+       action->conf = &action_rss_data->conf;
+       return ret;
+}
+
+/**
+ * Parse type field for RSS action.
+ *
+ * Valid tokens are type field names and the "end" token.
+ */
+static int
+parse_vc_action_rss_type(struct context *ctx, const struct token *token,
+                         const char *str, unsigned int len,
+                         void *buf, unsigned int size)
+{
+       static const enum index next[] = NEXT_ENTRY(ACTION_RSS_TYPE);
+       union action_rss_data *action_rss_data;
+       unsigned int i;
+
+       (void)token;
+       (void)buf;
+       (void)size;
+       if (ctx->curr != ACTION_RSS_TYPE)
+               return -1;
+       if (!(ctx->objdata >> 16) && ctx->object) {
+               action_rss_data = ctx->object;
+               action_rss_data->s.rss_conf.rss_hf = 0;
+       }
+       if (!strcmp_partial("end", str, len)) {
+               ctx->objdata &= 0xffff;
+               return len;
+       }
+       for (i = 0; rss_type_table[i].str; ++i)
+               if (!strcmp_partial(rss_type_table[i].str, str, len))
+                       break;
+       if (!rss_type_table[i].str)
+               return -1;
+       ctx->objdata = 1 << 16 | (ctx->objdata & 0xffff);
+       /* Repeat token. */
+       if (ctx->next_num == RTE_DIM(ctx->next))
+               return -1;
+       ctx->next[ctx->next_num++] = next;
+       if (!ctx->object)
+               return len;
+       action_rss_data = ctx->object;
+       action_rss_data->s.rss_conf.rss_hf |= rss_type_table[i].rss_type;
        return len;
 }
 
@@ -2017,6 +2192,7 @@ parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
                          void *buf, unsigned int size)
 {
        static const enum index next[] = NEXT_ENTRY(ACTION_RSS_QUEUE);
+       union action_rss_data *action_rss_data;
        int ret;
        int i;
 
@@ -2030,9 +2206,13 @@ parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
                ctx->objdata &= 0xffff;
                return len;
        }
-       if (i >= ACTION_RSS_NUM)
+       if (i >= ACTION_RSS_QUEUE_NUM)
                return -1;
-       if (push_args(ctx, ARGS_ENTRY(struct rte_flow_action_rss, queue[i])))
+       if (push_args(ctx,
+                     ARGS_ENTRY_ARB(offsetof(struct rte_flow_action_rss,
+                                             queue) +
+                                    i * sizeof(action_rss_data->s.queue[i]),
+                                    sizeof(action_rss_data->s.queue[i]))))
                return -1;
        ret = parse_int(ctx, token, str, len, NULL, 0);
        if (ret < 0) {
@@ -2047,7 +2227,8 @@ parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
        ctx->next[ctx->next_num++] = next;
        if (!ctx->object)
                return len;
-       ((struct rte_flow_action_rss *)ctx->object)->num = i;
+       action_rss_data = ctx->object;
+       action_rss_data->conf.num = i;
        return len;
 }
 
@@ -2266,6 +2447,11 @@ parse_int(struct context *ctx, const struct token *token,
                strtoumax(str, &end, 0);
        if (errno || (size_t)(end - str) != len)
                goto error;
+       if (arg->bounded &&
+           ((arg->sign && ((intmax_t)u < (intmax_t)arg->min ||
+                           (intmax_t)u > (intmax_t)arg->max)) ||
+            (!arg->sign && (u < arg->min || u > arg->max))))
+               goto error;
        if (!ctx->object)
                return len;
        if (arg->mask) {
@@ -2359,7 +2545,7 @@ parse_string(struct context *ctx, const struct token *token,
        buf = (uint8_t *)ctx->object + arg_data->offset;
        /* Output buffer is not necessarily NUL-terminated. */
        memcpy(buf, str, len);
-       memset((uint8_t *)buf + len, 0x55, size - len);
+       memset((uint8_t *)buf + len, 0x00, size - len);
        if (ctx->objmask)
                memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len);
        return len;
@@ -2506,6 +2692,7 @@ static const char *const boolean_name[] = {
        "false", "true",
        "no", "yes",
        "N", "Y",
+       "off", "on",
        NULL,
 };
 
@@ -2655,22 +2842,40 @@ comp_rule_id(struct context *ctx, const struct token *token,
        return i;
 }
 
+/** Complete type field for RSS action. */
+static int
+comp_vc_action_rss_type(struct context *ctx, const struct token *token,
+                       unsigned int ent, char *buf, unsigned int size)
+{
+       unsigned int i;
+
+       (void)ctx;
+       (void)token;
+       for (i = 0; rss_type_table[i].str; ++i)
+               ;
+       if (!buf)
+               return i + 1;
+       if (ent < i)
+               return snprintf(buf, size, "%s", rss_type_table[ent].str);
+       if (ent == i)
+               return snprintf(buf, size, "end");
+       return -1;
+}
+
 /** Complete queue field for RSS action. */
 static int
 comp_vc_action_rss_queue(struct context *ctx, const struct token *token,
                         unsigned int ent, char *buf, unsigned int size)
 {
-       static const char *const str[] = { "", "end", NULL };
-       unsigned int i;
-
        (void)ctx;
        (void)token;
-       for (i = 0; str[i] != NULL; ++i)
-               if (buf && i == ent)
-                       return snprintf(buf, size, "%s", str[i]);
-       if (buf)
-               return -1;
-       return i;
+       if (!buf)
+               return nb_rxq + 1;
+       if (ent < nb_rxq)
+               return snprintf(buf, size, "%u", ent);
+       if (ent == nb_rxq)
+               return snprintf(buf, size, "end");
+       return -1;
 }
 
 /** Internal context. */