X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=app%2Ftest-pmd%2Fcmdline_flow.c;h=f0b4b7bc4070f6580c5244312bf3b369926204d2;hb=66ba596aa6b5750b16549a322ef9a09fa7f0e3f6;hp=b5d394d762efd89cc475ac6e69572e3fc5e46ccf;hpb=5d3a35ff0670d0805289e9b030db926b1bee0e6f;p=dpdk.git diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index b5d394d762..f0b4b7bc40 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -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 @@ -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,12 +167,18 @@ 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, ACTION_VF, ACTION_VF_ORIGINAL, ACTION_VF_ID, + ACTION_METER, + ACTION_METER_ID, }; /** Size of pattern[] field in struct rte_flow_item_raw. */ @@ -207,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 @@ -240,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. */ @@ -339,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){ \ @@ -458,6 +465,7 @@ static const enum index next_item[] = { ITEM_GTP, ITEM_GTPC, ITEM_GTPU, + ITEM_GENEVE, ZERO, }; @@ -601,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, @@ -614,6 +629,7 @@ static const enum index next_action[] = { ACTION_RSS, ACTION_PF, ACTION_VF, + ACTION_METER, ZERO, }; @@ -636,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, @@ -648,6 +667,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); @@ -658,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); @@ -713,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); @@ -1461,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] = { @@ -1561,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", @@ -1606,6 +1696,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. */ @@ -1882,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; @@ -1962,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. */ @@ -1971,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; } @@ -1993,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; @@ -2006,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) { @@ -2023,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; } @@ -2242,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) { @@ -2335,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; @@ -2482,6 +2692,7 @@ static const char *const boolean_name[] = { "false", "true", "no", "yes", "N", "Y", + "off", "on", NULL, }; @@ -2631,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. */