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 <xuemingl@mellanox.com>
Signed-off-by: Xiaoyu Min <jackmin@mellanox.com>
Acked-by: Ori Kam <orika@mellanox.com>
This commit is contained in:
Xueming Li 2020-01-17 13:56:01 +02:00 committed by Ferruh Yigit
parent f6d7202402
commit 1e8a4e97b0
3 changed files with 119 additions and 0 deletions

View File

@ -41,6 +41,7 @@ enum index {
BOOLEAN, BOOLEAN,
STRING, STRING,
HEX, HEX,
FILE_PATH,
MAC_ADDR, MAC_ADDR,
IPV4_ADDR, IPV4_ADDR,
IPV6_ADDR, IPV6_ADDR,
@ -63,6 +64,7 @@ enum index {
CREATE, CREATE,
DESTROY, DESTROY,
FLUSH, FLUSH,
DUMP,
QUERY, QUERY,
LIST, LIST,
ISOLATE, ISOLATE,
@ -640,6 +642,9 @@ struct buffer {
uint32_t *rule; uint32_t *rule;
uint32_t rule_n; uint32_t rule_n;
} destroy; /**< Destroy arguments. */ } destroy; /**< Destroy arguments. */
struct {
char file[128];
} dump; /**< Dump arguments. */
struct { struct {
uint32_t rule; uint32_t rule;
struct rte_flow_action action; struct rte_flow_action action;
@ -694,6 +699,12 @@ static const enum index next_destroy_attr[] = {
ZERO, ZERO,
}; };
static const enum index next_dump_attr[] = {
FILE_PATH,
END,
ZERO,
};
static const enum index next_list_attr[] = { static const enum index next_list_attr[] = {
LIST_GROUP, LIST_GROUP,
END, END,
@ -1412,6 +1423,9 @@ static int parse_destroy(struct context *, const struct token *,
static int parse_flush(struct context *, const struct token *, static int parse_flush(struct context *, const struct token *,
const char *, unsigned int, const char *, unsigned int,
void *, 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 *, static int parse_query(struct context *, const struct token *,
const char *, unsigned int, const char *, unsigned int,
void *, 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, static int parse_hex(struct context *ctx, const struct token *token,
const char *str, unsigned int len, const char *str, unsigned int len,
void *buf, unsigned int size); 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 *, static int parse_mac_addr(struct context *, const struct token *,
const char *, unsigned int, const char *, unsigned int,
void *, unsigned int); void *, unsigned int);
@ -1532,6 +1549,12 @@ static const struct token token_list[] = {
.type = "HEX", .type = "HEX",
.help = "fixed string", .help = "fixed string",
.call = parse_hex, .call = parse_hex,
},
[FILE_PATH] = {
.name = "{file path}",
.type = "STRING",
.help = "file path",
.call = parse_string0,
.comp = comp_none, .comp = comp_none,
}, },
[MAC_ADDR] = { [MAC_ADDR] = {
@ -1593,6 +1616,7 @@ static const struct token token_list[] = {
CREATE, CREATE,
DESTROY, DESTROY,
FLUSH, FLUSH,
DUMP,
LIST, LIST,
QUERY, QUERY,
ISOLATE)), ISOLATE)),
@ -1627,6 +1651,14 @@ static const struct token token_list[] = {
.args = ARGS(ARGS_ENTRY(struct buffer, port)), .args = ARGS(ARGS_ENTRY(struct buffer, port)),
.call = parse_flush, .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] = { [QUERY] = {
.name = "query", .name = "query",
.help = "query an existing flow rule", .help = "query an existing flow rule",
@ -5118,6 +5150,33 @@ parse_flush(struct context *ctx, const struct token *token,
return len; 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. */ /** Parse tokens for query command. */
static int static int
parse_query(struct context *ctx, const struct token *token, parse_query(struct context *ctx, const struct token *token,
@ -5515,6 +5574,35 @@ parse_hex(struct context *ctx, const struct token *token,
} }
/**
* 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. * Parse a MAC address.
* *
@ -6174,6 +6262,9 @@ cmd_flow_parsed(const struct buffer *in)
case FLUSH: case FLUSH:
port_flow_flush(in->port); port_flow_flush(in->port);
break; break;
case DUMP:
port_flow_dump(in->port, in->args.dump.file);
break;
case QUERY: case QUERY:
port_flow_query(in->port, in->args.query.rule, port_flow_query(in->port, in->args.query.rule,
&in->args.query.action); &in->args.query.action);

View File

@ -1441,6 +1441,33 @@ port_flow_flush(portid_t port_id)
return ret; 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. */ /** Query a flow rule. */
int int
port_flow_query(portid_t port_id, uint32_t rule, port_flow_query(portid_t port_id, uint32_t rule,

View File

@ -744,6 +744,7 @@ int port_flow_create(portid_t port_id,
const struct rte_flow_action *actions); const struct rte_flow_action *actions);
int port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule); 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_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, int port_flow_query(portid_t port_id, uint32_t rule,
const struct rte_flow_action *action); const struct rte_flow_action *action);
void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group); void port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group);