app/testpmd: add command for single flow dump
authorHaifei Luo <haifeil@nvidia.com>
Wed, 14 Apr 2021 10:20:00 +0000 (13:20 +0300)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 14 Apr 2021 11:19:55 +0000 (13:19 +0200)
Add support for single flow dump.
The CLIs to dump one rule: flow dump PORT rule ID
to dump all: flow dump PORT all
Examples:
testpmd> flow dump 0 all
testpmd> flow dump 0 rule 0

Signed-off-by: Haifei Luo <haifeil@nvidia.com>
Acked-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
app/test-pmd/cmdline_flow.c
app/test-pmd/config.c
app/test-pmd/testpmd.h
doc/guides/rel_notes/release_21_05.rst
doc/guides/testpmd_app_ug/testpmd_funcs.rst

index fb7a3a8..0127d9e 100644 (file)
@@ -108,6 +108,10 @@ enum index {
        TUNNEL_SET,
        TUNNEL_MATCH,
 
+       /* Dump arguments */
+       DUMP_ALL,
+       DUMP_ONE,
+
        /* Shared action arguments */
        SHARED_ACTION_CREATE,
        SHARED_ACTION_UPDATE,
@@ -793,6 +797,8 @@ struct buffer {
                } destroy; /**< Destroy arguments. */
                struct {
                        char file[128];
+                       bool mode;
+                       uint32_t rule;
                } dump; /**< Dump arguments. */
                struct {
                        uint32_t rule;
@@ -844,6 +850,12 @@ static const enum index next_sa_create_attr[] = {
        ZERO,
 };
 
+static const enum index next_dump_subcmd[] = {
+       DUMP_ALL,
+       DUMP_ONE,
+       ZERO,
+};
+
 static const enum index next_sa_subcmd[] = {
        SHARED_ACTION_CREATE,
        SHARED_ACTION_UPDATE,
@@ -2032,10 +2044,9 @@ static const struct token token_list[] = {
        },
        [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)),
+               .help = "dump single/all flow rules to file",
+               .next = NEXT(next_dump_subcmd, NEXT_ENTRY(PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
                .call = parse_dump,
        },
        [QUERY] = {
@@ -2125,6 +2136,22 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.destroy.rule)),
                .call = parse_destroy,
        },
+       /* Dump arguments. */
+       [DUMP_ALL] = {
+               .name = "all",
+               .help = "dump all",
+               .next = NEXT(next_dump_attr),
+               .args = ARGS(ARGS_ENTRY(struct buffer, args.dump.file)),
+               .call = parse_dump,
+       },
+       [DUMP_ONE] = {
+               .name = "rule",
+               .help = "dump one rule",
+               .next = NEXT(next_dump_attr, NEXT_ENTRY(RULE_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, args.dump.file),
+                               ARGS_ENTRY(struct buffer, args.dump.rule)),
+               .call = parse_dump,
+       },
        /* Query arguments. */
        [QUERY_ACTION] = {
                .name = "{action}",
@@ -6364,8 +6391,20 @@ parse_dump(struct context *ctx, const struct token *token,
                ctx->objdata = 0;
                ctx->object = out;
                ctx->objmask = NULL;
+               return len;
+       }
+       switch (ctx->curr) {
+       case DUMP_ALL:
+       case DUMP_ONE:
+               out->args.dump.mode = (ctx->curr == DUMP_ALL) ? true : false;
+               out->command = ctx->curr;
+               ctx->objdata = 0;
+               ctx->object = out;
+               ctx->objmask = NULL;
+               return len;
+       default:
+               return -1;
        }
-       return len;
 }
 
 /** Parse tokens for query command. */
@@ -7659,8 +7698,10 @@ 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);
+       case DUMP_ONE:
+       case DUMP_ALL:
+               port_flow_dump(in->port, in->args.dump.mode,
+                               in->args.dump.rule, in->args.dump.file);
                break;
        case QUERY:
                port_flow_query(in->port, in->args.query.rule,
index 995171f..d4b0e85 100644 (file)
@@ -1915,13 +1915,41 @@ port_flow_flush(portid_t port_id)
        return ret;
 }
 
-/** Dump all flow rules. */
+/** Dump flow rules. */
 int
-port_flow_dump(portid_t port_id, const char *file_name)
+port_flow_dump(portid_t port_id, bool dump_all, uint32_t rule_id,
+               const char *file_name)
 {
        int ret = 0;
        FILE *file = stdout;
        struct rte_flow_error error;
+       struct rte_port *port;
+       struct port_flow *pflow;
+       struct rte_flow *tmpFlow = NULL;
+       bool found = false;
+
+       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+               port_id == (portid_t)RTE_PORT_ALL)
+               return -EINVAL;
+
+       if (!dump_all) {
+               port = &ports[port_id];
+               pflow = port->flow_list;
+               while (pflow) {
+                       if (rule_id != pflow->id) {
+                               pflow = pflow->next;
+                       } else {
+                               tmpFlow = pflow->flow;
+                               if (tmpFlow)
+                                       found = true;
+                               break;
+                       }
+               }
+               if (found == false) {
+                       printf("Failed to dump to flow %d\n", rule_id);
+                       return -EINVAL;
+               }
+       }
 
        if (file_name && strlen(file_name)) {
                file = fopen(file_name, "w");
@@ -1931,7 +1959,11 @@ port_flow_dump(portid_t port_id, const char *file_name)
                        return -errno;
                }
        }
-       ret = rte_flow_dev_dump(port_id, NULL, file, &error);
+
+       if (!dump_all)
+               ret = rte_flow_dev_dump(port_id, tmpFlow, file, &error);
+       else
+               ret = rte_flow_dev_dump(port_id, NULL, file, &error);
        if (ret) {
                port_flow_complain(&error);
                printf("Failed to dump flow: %s\n", strerror(-ret));
index a87ccb0..36d8535 100644 (file)
@@ -825,7 +825,8 @@ void update_age_action_context(const struct rte_flow_action *actions,
                     struct port_flow *pf);
 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_dump(portid_t port_id, bool dump_all,
+                       uint32_t rule, 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);
index cbfa6b9..5261d9a 100644 (file)
@@ -203,6 +203,8 @@ New Features
     ``dpdk-testpmd -- --eth-link-speed N``
   * Added command to display Rx queue used descriptor count.
     ``show port (port_id) rxq (queue_id) desc used count``
+  * Added command to dump internal representation information of single flow.
+    ``flow dump (port_id) rule (rule_id)``
 
 * **Updated ipsec-secgw sample application.**
 
index 5785e94..72667de 100644 (file)
@@ -3335,7 +3335,11 @@ following sections.
 
 - Dump internal representation information of all flows in hardware::
 
-   flow dump {port_id} {output_file}
+   flow dump {port_id} all {output_file}
+
+  for one flow::
+
+   flow dump {port_id} rule {rule_id} {output_file}
 
 - List and destroy aged flow rules::