app/testpmd: use SPDX tags in 6WIND copyrighted files
[dpdk.git] / app / test-pmd / cmdline_flow.c
index 0fd69f9..a5cf84f 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.
  */
 
 #include <stddef.h>
@@ -80,6 +52,7 @@ enum index {
        FLUSH,
        QUERY,
        LIST,
+       ISOLATE,
 
        /* Destroy arguments. */
        DESTROY_RULE,
@@ -152,6 +125,7 @@ enum index {
        ITEM_TCP,
        ITEM_TCP_SRC,
        ITEM_TCP_DST,
+       ITEM_TCP_FLAGS,
        ITEM_SCTP,
        ITEM_SCTP_SRC,
        ITEM_SCTP_DST,
@@ -167,6 +141,15 @@ enum index {
        ITEM_MPLS_LABEL,
        ITEM_GRE,
        ITEM_GRE_PROTO,
+       ITEM_FUZZY,
+       ITEM_FUZZY_THRESH,
+       ITEM_GTP,
+       ITEM_GTP_TEID,
+       ITEM_GTPC,
+       ITEM_GTPU,
+       ITEM_GENEVE,
+       ITEM_GENEVE_VNI,
+       ITEM_GENEVE_PROTO,
 
        /* Validate/create actions. */
        ACTIONS,
@@ -190,6 +173,8 @@ enum index {
        ACTION_VF,
        ACTION_VF_ORIGINAL,
        ACTION_VF_ID,
+       ACTION_METER,
+       ACTION_METER_ID,
 };
 
 /** Size of pattern[] field in struct rte_flow_item_raw. */
@@ -220,10 +205,9 @@ struct context {
        enum index prev; /**< Index of the last token seen. */
        int next_num; /**< Number of entries in next[]. */
        int args_num; /**< Number of entries in args[]. */
-       uint32_t reparse:1; /**< Start over from the beginning. */
        uint32_t eol:1; /**< EOL has been detected. */
        uint32_t last:1; /**< No more arguments. */
-       uint16_t port; /**< Current port ID (for completions). */
+       portid_t port; /**< Current port ID (for completions). */
        uint32_t objdata; /**< Object-specific data. */
        void *object; /**< Address of current object for relative offsets. */
        void *objmask; /**< Object a full mask must be written to. */
@@ -343,7 +327,7 @@ struct token {
 /** Parser output buffer layout expected by cmd_flow_parsed(). */
 struct buffer {
        enum index command; /**< Flow command. */
-       uint16_t port; /**< Affected port ID. */
+       portid_t port; /**< Affected port ID. */
        union {
                struct {
                        struct rte_flow_attr attr;
@@ -365,6 +349,9 @@ struct buffer {
                        uint32_t *group;
                        uint32_t group_n;
                } list; /**< List arguments. */
+               struct {
+                       int set;
+               } isolate; /**< Isolated mode arguments. */
        } args; /**< Command arguments. */
 };
 
@@ -444,6 +431,17 @@ static const enum index next_item[] = {
        ITEM_NVGRE,
        ITEM_MPLS,
        ITEM_GRE,
+       ITEM_FUZZY,
+       ITEM_GTP,
+       ITEM_GTPC,
+       ITEM_GTPU,
+       ITEM_GENEVE,
+       ZERO,
+};
+
+static const enum index item_fuzzy[] = {
+       ITEM_FUZZY_THRESH,
+       ITEM_NEXT,
        ZERO,
 };
 
@@ -531,6 +529,7 @@ static const enum index item_udp[] = {
 static const enum index item_tcp[] = {
        ITEM_TCP_SRC,
        ITEM_TCP_DST,
+       ITEM_TCP_FLAGS,
        ITEM_NEXT,
        ZERO,
 };
@@ -574,6 +573,19 @@ static const enum index item_gre[] = {
        ZERO,
 };
 
+static const enum index item_gtp[] = {
+       ITEM_GTP_TEID,
+       ITEM_NEXT,
+       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,
@@ -587,6 +599,7 @@ static const enum index next_action[] = {
        ACTION_RSS,
        ACTION_PF,
        ACTION_VF,
+       ACTION_METER,
        ZERO,
 };
 
@@ -621,6 +634,12 @@ static const enum index action_vf[] = {
        ZERO,
 };
 
+static const enum index action_meter[] = {
+       ACTION_METER_ID,
+       ACTION_NEXT,
+       ZERO,
+};
+
 static int parse_init(struct context *, const struct token *,
                      const char *, unsigned int,
                      void *, unsigned int);
@@ -649,6 +668,9 @@ static int parse_action(struct context *, const struct token *,
 static int parse_list(struct context *, const struct token *,
                      const char *, unsigned int,
                      void *, unsigned int);
+static int parse_isolate(struct context *, const struct token *,
+                        const char *, unsigned int,
+                        void *, unsigned int);
 static int parse_int(struct context *, const struct token *,
                     const char *, unsigned int,
                     void *, unsigned int);
@@ -795,7 +817,8 @@ static const struct token token_list[] = {
                              DESTROY,
                              FLUSH,
                              LIST,
-                             QUERY)),
+                             QUERY,
+                             ISOLATE)),
                .call = parse_init,
        },
        /* Sub-level commands. */
@@ -845,6 +868,15 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY(struct buffer, port)),
                .call = parse_list,
        },
+       [ISOLATE] = {
+               .name = "isolate",
+               .help = "restrict ingress traffic to the defined flow rules",
+               .next = NEXT(NEXT_ENTRY(BOOLEAN),
+                            NEXT_ENTRY(PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, args.isolate.set),
+                            ARGS_ENTRY(struct buffer, port)),
+               .call = parse_isolate,
+       },
        /* Destroy arguments. */
        [DESTROY_RULE] = {
                .name = "rule",
@@ -1267,6 +1299,13 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
                                             hdr.dst_port)),
        },
+       [ITEM_TCP_FLAGS] = {
+               .name = "flags",
+               .help = "TCP flags",
+               .next = NEXT(item_tcp, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_tcp,
+                                            hdr.tcp_flags)),
+       },
        [ITEM_SCTP] = {
                .name = "sctp",
                .help = "match SCTP header",
@@ -1372,6 +1411,69 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gre,
                                             protocol)),
        },
+       [ITEM_FUZZY] = {
+               .name = "fuzzy",
+               .help = "fuzzy pattern match, expect faster than default",
+               .priv = PRIV_ITEM(FUZZY,
+                               sizeof(struct rte_flow_item_fuzzy)),
+               .next = NEXT(item_fuzzy),
+               .call = parse_vc,
+       },
+       [ITEM_FUZZY_THRESH] = {
+               .name = "thresh",
+               .help = "match accuracy threshold",
+               .next = NEXT(item_fuzzy, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_item_fuzzy,
+                                       thresh)),
+       },
+       [ITEM_GTP] = {
+               .name = "gtp",
+               .help = "match GTP header",
+               .priv = PRIV_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),
+               .next = NEXT(item_gtp),
+               .call = parse_vc,
+       },
+       [ITEM_GTP_TEID] = {
+               .name = "teid",
+               .help = "tunnel endpoint identifier",
+               .next = NEXT(item_gtp, NEXT_ENTRY(UNSIGNED), item_param),
+               .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_gtp, teid)),
+       },
+       [ITEM_GTPC] = {
+               .name = "gtpc",
+               .help = "match GTP header",
+               .priv = PRIV_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),
+               .next = NEXT(item_gtp),
+               .call = parse_vc,
+       },
+       [ITEM_GTPU] = {
+               .name = "gtpu",
+               .help = "match GTP header",
+               .priv = PRIV_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),
+               .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] = {
                .name = "actions",
@@ -1516,6 +1618,21 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY(struct rte_flow_action_vf, id)),
                .call = parse_vc_conf,
        },
+       [ACTION_METER] = {
+               .name = "meter",
+               .help = "meter the directed packets at given id",
+               .priv = PRIV_ACTION(METER,
+                                   sizeof(struct rte_flow_action_meter)),
+               .next = NEXT(action_meter),
+               .call = parse_vc,
+       },
+       [ACTION_METER_ID] = {
+               .name = "mtr_id",
+               .help = "meter id to use",
+               .next = NEXT(action_meter, NEXT_ENTRY(UNSIGNED)),
+               .args = ARGS(ARGS_ENTRY(struct rte_flow_action_meter, mtr_id)),
+               .call = parse_vc_conf,
+       },
 };
 
 /** Remove and return last entry from argument stack. */
@@ -1574,6 +1691,19 @@ arg_entry_bf_fill(void *dst, uintmax_t val, const struct arg *arg)
        return len;
 }
 
+/** Compare a string with a partial one of a given length. */
+static int
+strcmp_partial(const char *full, const char *partial, size_t partial_len)
+{
+       int r = strncmp(full, partial, partial_len);
+
+       if (r)
+               return r;
+       if (strlen(full) <= partial_len)
+               return 0;
+       return full[partial_len];
+}
+
 /**
  * Parse a prefix length and generate a bit-mask.
  *
@@ -1656,7 +1786,7 @@ parse_default(struct context *ctx, const struct token *token,
        (void)ctx;
        (void)buf;
        (void)size;
-       if (strncmp(str, token->name, len))
+       if (strcmp_partial(token->name, str, len))
                return -1;
        return len;
 }
@@ -1899,7 +2029,7 @@ parse_vc_action_rss_queue(struct context *ctx, const struct token *token,
        if (ctx->curr != ACTION_RSS_QUEUE)
                return -1;
        i = ctx->objdata >> 16;
-       if (!strncmp(str, "end", len)) {
+       if (!strcmp_partial("end", str, len)) {
                ctx->objdata &= 0xffff;
                return len;
        }
@@ -2034,7 +2164,7 @@ parse_action(struct context *ctx, const struct token *token,
                const struct parse_action_priv *priv;
 
                token = &token_list[next_action[i]];
-               if (strncmp(token->name, str, len))
+               if (strcmp_partial(token->name, str, len))
                        continue;
                priv = token->priv;
                if (!priv)
@@ -2087,6 +2217,33 @@ parse_list(struct context *ctx, const struct token *token,
        return len;
 }
 
+/** Parse tokens for isolate command. */
+static int
+parse_isolate(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;
+       if (!out->command) {
+               if (ctx->curr != ISOLATE)
+                       return -1;
+               if (sizeof(*out) > size)
+                       return -1;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+       }
+       return len;
+}
+
 /**
  * Parse signed/unsigned integers 8 to 64-bit long.
  *
@@ -2374,7 +2531,7 @@ parse_boolean(struct context *ctx, const struct token *token,
        if (!arg)
                return -1;
        for (i = 0; boolean_name[i]; ++i)
-               if (!strncmp(str, boolean_name[i], len))
+               if (!strcmp_partial(boolean_name[i], str, len))
                        break;
        /* Process token as integer. */
        if (boolean_name[i])
@@ -2488,7 +2645,7 @@ comp_rule_id(struct context *ctx, const struct token *token,
 
        (void)token;
        if (port_id_is_invalid(ctx->port, DISABLED_WARN) ||
-           ctx->port == (uint16_t)RTE_PORT_ALL)
+           ctx->port == (portid_t)RTE_PORT_ALL)
                return -1;
        port = &ports[ctx->port];
        for (pf = port->flow_list; pf != NULL; pf = pf->next) {
@@ -2534,7 +2691,6 @@ cmd_flow_context_init(struct context *ctx)
        ctx->prev = ZERO;
        ctx->next_num = 0;
        ctx->args_num = 0;
-       ctx->reparse = 0;
        ctx->eol = 0;
        ctx->last = 0;
        ctx->port = 0;
@@ -2555,9 +2711,6 @@ cmd_flow_parse(cmdline_parse_token_hdr_t *hdr, const char *src, void *result,
        int i;
 
        (void)hdr;
-       /* Restart as requested. */
-       if (ctx->reparse)
-               cmd_flow_context_init(ctx);
        token = &token_list[ctx->curr];
        /* Check argument length. */
        ctx->eol = 0;
@@ -2633,8 +2786,6 @@ cmd_flow_complete_get_nb(cmdline_parse_token_hdr_t *hdr)
        int i;
 
        (void)hdr;
-       /* Tell cmd_flow_parse() that context must be reinitialized. */
-       ctx->reparse = 1;
        /* Count number of tokens in current list. */
        if (ctx->next_num)
                list = ctx->next[ctx->next_num - 1];
@@ -2668,8 +2819,6 @@ cmd_flow_complete_get_elt(cmdline_parse_token_hdr_t *hdr, int index,
        int i;
 
        (void)hdr;
-       /* Tell cmd_flow_parse() that context must be reinitialized. */
-       ctx->reparse = 1;
        /* Count number of tokens in current list. */
        if (ctx->next_num)
                list = ctx->next[ctx->next_num - 1];
@@ -2704,8 +2853,6 @@ cmd_flow_get_help(cmdline_parse_token_hdr_t *hdr, char *dst, unsigned int size)
        const struct token *token = &token_list[ctx->prev];
 
        (void)hdr;
-       /* Tell cmd_flow_parse() that context must be reinitialized. */
-       ctx->reparse = 1;
        if (!size)
                return -1;
        /* Set token type and update global help with details. */
@@ -2731,12 +2878,12 @@ static struct cmdline_token_hdr cmd_flow_token_hdr = {
 /** Populate the next dynamic token. */
 static void
 cmd_flow_tok(cmdline_parse_token_hdr_t **hdr,
-            cmdline_parse_token_hdr_t *(*hdrs)[])
+            cmdline_parse_token_hdr_t **hdr_inst)
 {
        struct context *ctx = &cmd_flow_context;
 
        /* Always reinitialize context before requesting the first token. */
-       if (!(hdr - *hdrs))
+       if (!(hdr_inst - cmd_flow.tokens))
                cmd_flow_context_init(ctx);
        /* Return NULL when no more tokens are expected. */
        if (!ctx->next_num && ctx->curr) {
@@ -2786,6 +2933,9 @@ cmd_flow_parsed(const struct buffer *in)
                port_flow_list(in->port, in->args.list.group_n,
                               in->args.list.group);
                break;
+       case ISOLATE:
+               port_flow_isolate(in->port, in->args.isolate.set);
+               break;
        default:
                break;
        }