From 1e8a4e97b057c2ec4350bfe2eeb67e1746e14568 Mon Sep 17 00:00:00 2001 From: Xueming Li Date: Fri, 17 Jan 2020 13:56:01 +0200 Subject: [PATCH] app/testpmd: add flow dump command New flow dump CLI to dump device internal representation information of flows into screen. Signed-off-by: Xueming Li Signed-off-by: Xiaoyu Min Acked-by: Ori Kam --- app/test-pmd/cmdline_flow.c | 91 +++++++++++++++++++++++++++++++++++++ app/test-pmd/config.c | 27 +++++++++++ app/test-pmd/testpmd.h | 1 + 3 files changed, 119 insertions(+) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index 3c56bdbe6b..e99e24c29f 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -41,6 +41,7 @@ enum index { BOOLEAN, STRING, HEX, + FILE_PATH, MAC_ADDR, IPV4_ADDR, IPV6_ADDR, @@ -63,6 +64,7 @@ enum index { CREATE, DESTROY, FLUSH, + DUMP, QUERY, LIST, ISOLATE, @@ -640,6 +642,9 @@ struct buffer { uint32_t *rule; uint32_t rule_n; } destroy; /**< Destroy arguments. */ + struct { + char file[128]; + } dump; /**< Dump arguments. */ struct { uint32_t rule; struct rte_flow_action action; @@ -694,6 +699,12 @@ static const enum index next_destroy_attr[] = { ZERO, }; +static const enum index next_dump_attr[] = { + FILE_PATH, + END, + ZERO, +}; + static const enum index next_list_attr[] = { LIST_GROUP, END, @@ -1412,6 +1423,9 @@ static int parse_destroy(struct context *, const struct token *, static int parse_flush(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); +static int parse_dump(struct context *, const struct token *, + const char *, unsigned int, + void *, unsigned int); static int parse_query(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1439,6 +1453,9 @@ static int parse_string(struct context *, const struct token *, static int parse_hex(struct context *ctx, const struct token *token, const char *str, unsigned int len, void *buf, unsigned int size); +static int parse_string0(struct context *, const struct token *, + const char *, unsigned int, + void *, unsigned int); static int parse_mac_addr(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1532,6 +1549,12 @@ static const struct token token_list[] = { .type = "HEX", .help = "fixed string", .call = parse_hex, + }, + [FILE_PATH] = { + .name = "{file path}", + .type = "STRING", + .help = "file path", + .call = parse_string0, .comp = comp_none, }, [MAC_ADDR] = { @@ -1593,6 +1616,7 @@ static const struct token token_list[] = { CREATE, DESTROY, FLUSH, + DUMP, LIST, QUERY, ISOLATE)), @@ -1627,6 +1651,14 @@ static const struct token token_list[] = { .args = ARGS(ARGS_ENTRY(struct buffer, port)), .call = parse_flush, }, + [DUMP] = { + .name = "dump", + .help = "dump all flow rules to file", + .next = NEXT(next_dump_attr, NEXT_ENTRY(PORT_ID)), + .args = ARGS(ARGS_ENTRY(struct buffer, args.dump.file), + ARGS_ENTRY(struct buffer, port)), + .call = parse_dump, + }, [QUERY] = { .name = "query", .help = "query an existing flow rule", @@ -5118,6 +5150,33 @@ parse_flush(struct context *ctx, const struct token *token, return len; } +/** Parse tokens for dump command. */ +static int +parse_dump(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 != DUMP) + return -1; + if (sizeof(*out) > size) + return -1; + out->command = ctx->curr; + ctx->objdata = 0; + ctx->object = out; + ctx->objmask = NULL; + } + return len; +} + /** Parse tokens for query command. */ static int parse_query(struct context *ctx, const struct token *token, @@ -5515,6 +5574,35 @@ error: } +/** + * Parse a zero-ended string. + */ +static int +parse_string0(struct context *ctx, const struct token *token __rte_unused, + const char *str, unsigned int len, + void *buf, unsigned int size) +{ + const struct arg *arg_data = pop_args(ctx); + + /* Arguments are expected. */ + if (!arg_data) + return -1; + size = arg_data->size; + /* Bit-mask fill is not supported. */ + if (arg_data->mask || size < len + 1) + goto error; + if (!ctx->object) + return len; + buf = (uint8_t *)ctx->object + arg_data->offset; + strncpy(buf, str, len); + if (ctx->objmask) + memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len); + return len; +error: + push_args(ctx, arg_data); + return -1; +} + /** * Parse a MAC address. * @@ -6174,6 +6262,9 @@ cmd_flow_parsed(const struct buffer *in) case FLUSH: port_flow_flush(in->port); break; + case DUMP: + port_flow_dump(in->port, in->args.dump.file); + break; case QUERY: port_flow_query(in->port, in->args.query.rule, &in->args.query.action); diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index 4ac763849b..52f1d9d928 100644 --- a/app/test-pmd/config.c +++ b/app/test-pmd/config.c @@ -1441,6 +1441,33 @@ port_flow_flush(portid_t port_id) return ret; } +/** Dump all flow rules. */ +int +port_flow_dump(portid_t port_id, const char *file_name) +{ + int ret = 0; + FILE *file = stdout; + struct rte_flow_error error; + + if (file_name && strlen(file_name)) { + file = fopen(file_name, "w"); + if (!file) { + printf("Failed to create file %s: %s\n", file_name, + strerror(errno)); + return -errno; + } + } + ret = rte_flow_dev_dump(port_id, file, &error); + if (ret) { + port_flow_complain(&error); + printf("Failed to dump flow: %s\n", strerror(-ret)); + } else + printf("Flow dump finished\n"); + if (file_name && strlen(file_name)) + fclose(file); + return ret; +} + /** Query a flow rule. */ int port_flow_query(portid_t port_id, uint32_t rule, diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index c407bd2741..7cf48d005b 100644 --- a/app/test-pmd/testpmd.h +++ b/app/test-pmd/testpmd.h @@ -744,6 +744,7 @@ int port_flow_create(portid_t port_id, const struct rte_flow_action *actions); int port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule); int port_flow_flush(portid_t port_id); +int port_flow_dump(portid_t port_id, const char *file_name); int port_flow_query(portid_t port_id, uint32_t rule, const struct rte_flow_action *action); void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group); -- 2.20.1