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 <haif...@nvidia.com>
---
 app/test-pmd/cmdline_flow.c                 | 55 +++++++++++++++++++++++++----
 app/test-pmd/config.c                       | 38 ++++++++++++++++++--
 app/test-pmd/testpmd.h                      |  3 +-
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  6 +++-
 4 files changed, 90 insertions(+), 12 deletions(-)

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 49d9f9c..7f53b83 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -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,
@@ -791,6 +795,8 @@ struct buffer {
                } destroy; /**< Destroy arguments. */
                struct {
                        char file[128];
+                       bool mode;
+                       uint32_t rule;
                } dump; /**< Dump arguments. */
                struct {
                        uint32_t rule;
@@ -842,6 +848,12 @@ struct parse_action_priv {
        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,
@@ -2028,10 +2040,9 @@ static int comp_set_modify_field_id(struct context *, 
const struct token *,
        },
        [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] = {
@@ -2121,6 +2132,22 @@ static int comp_set_modify_field_id(struct context *, 
const struct token *,
                .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}",
@@ -6342,8 +6369,20 @@ static int comp_set_modify_field_id(struct context *, 
const struct 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. */
@@ -7637,8 +7676,10 @@ static int comp_set_modify_field_id(struct context *, 
const struct token *,
        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,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 576d5ac..c6e54b6 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -1915,13 +1915,41 @@ struct rte_flow_shared_action *
        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 @@ struct rte_flow_shared_action *
                        return -errno;
                }
        }
-       ret = rte_flow_dev_dump(port_id, file, &error);
+       if (!dump_all)
+               ret = rte_flow_dump(port_id, tmpFlow, file, &error);
+       else
+               ret = rte_flow_dev_dump(port_id, file, &error);
+
        if (ret) {
                port_flow_complain(&error);
                printf("Failed to dump flow: %s\n", strerror(-ret));
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index ce83f31..3dcbac1 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -824,7 +824,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);
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst 
b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index f59eb8a..278e1ea 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -3314,7 +3314,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::
 
-- 
1.8.3.1

Reply via email to