Currently, there is no way to check the aging event or to get the current
aged flows in testpmd, this patch include those implements, it's included:
- Registering aging event based on verbose level, when set verbose > 0,
  will register this event, otherwise, remove this event. In this event
  only dump one line of log to user there is one aging event coming.
- Add new command to list all aged flows, meanwhile, we can set parameter
  to destroy it.

Signed-off-by: Bill Zhou <do...@mellanox.com>
---
 app/test-pmd/cmdline.c      |   4 +
 app/test-pmd/cmdline_flow.c |  61 ++++++++++++++
 app/test-pmd/config.c       | 153 +++++++++++++++++++++++++++++++++---
 app/test-pmd/testpmd.c      |   2 +
 app/test-pmd/testpmd.h      |   9 +++
 5 files changed, 217 insertions(+), 12 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 22fb23a92d..01aed7cc1f 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -1125,6 +1125,10 @@ static void cmd_help_long_parsed(void *parsed_result,
                        "    Restrict ingress traffic to the defined"
                        " flow rules\n\n"
 
+                       "flow aged {port_id} destroy {boolean}\n"
+                       "    List and destroy aged flows"
+                       " flow rules\n\n"
+
                        "set vxlan ip-version (ipv4|ipv6) vni (vni) udp-src"
                        " (udp-src) udp-dst (udp-dst) ip-src (ip-src) ip-dst"
                        " (ip-dst) eth-src (eth-src) eth-dst (eth-dst)\n"
diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index 45bcff3cf5..0349875591 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -67,6 +67,7 @@ enum index {
        DUMP,
        QUERY,
        LIST,
+       AGED,
        ISOLATE,
 
        /* Destroy arguments. */
@@ -78,6 +79,9 @@ enum index {
        /* List arguments. */
        LIST_GROUP,
 
+       /* List aged arguments. */
+       AGED_DESTROY,
+
        /* Validate/create arguments. */
        GROUP,
        PRIORITY,
@@ -664,6 +668,9 @@ struct buffer {
                struct {
                        int set;
                } isolate; /**< Isolated mode arguments. */
+               struct {
+                       int destroy;
+               } aged; /**< Aged list arguments. */
        } args; /**< Command arguments. */
 };
 
@@ -719,6 +726,12 @@ static const enum index next_list_attr[] = {
        ZERO,
 };
 
+static const enum index next_aged_attr[] = {
+       AGED_DESTROY,
+       END,
+       ZERO,
+};
+
 static const enum index item_param[] = {
        ITEM_PARAM_IS,
        ITEM_PARAM_SPEC,
@@ -1466,6 +1479,9 @@ static int parse_action(struct context *, const struct 
token *,
 static int parse_list(struct context *, const struct token *,
                      const char *, unsigned int,
                      void *, unsigned int);
+static int parse_aged(struct context *, const struct token *,
+                     const char *, unsigned int,
+                     void *, unsigned int);
 static int parse_isolate(struct context *, const struct token *,
                         const char *, unsigned int,
                         void *, unsigned int);
@@ -1649,6 +1665,7 @@ static const struct token token_list[] = {
                              FLUSH,
                              DUMP,
                              LIST,
+                             AGED,
                              QUERY,
                              ISOLATE)),
                .call = parse_init,
@@ -1708,6 +1725,13 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY(struct buffer, port)),
                .call = parse_list,
        },
+       [AGED] = {
+               .name = "aged",
+               .help = "list or destroy aged flows",
+               .next = NEXT(next_aged_attr, NEXT_ENTRY(PORT_ID)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, port)),
+               .call = parse_aged,
+       },
        [ISOLATE] = {
                .name = "isolate",
                .help = "restrict ingress traffic to the defined flow rules",
@@ -1741,6 +1765,13 @@ static const struct token token_list[] = {
                .args = ARGS(ARGS_ENTRY_PTR(struct buffer, args.list.group)),
                .call = parse_list,
        },
+       [AGED_DESTROY] = {
+               .name = "destroy",
+               .help = "specify aged flows need be destroyed",
+               .next = NEXT(NEXT_ENTRY(BOOLEAN)),
+               .args = ARGS(ARGS_ENTRY(struct buffer, args.aged.destroy)),
+               .comp = comp_none,
+       },
        /* Validate/create attributes. */
        [GROUP] = {
                .name = "group",
@@ -5367,6 +5398,33 @@ parse_list(struct context *ctx, const struct token 
*token,
        return len;
 }
 
+/** Parse tokens for list all aged flows command. */
+static int
+parse_aged(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 != AGED)
+                       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 isolate command. */
 static int
 parse_isolate(struct context *ctx, const struct token *token,
@@ -6367,6 +6425,9 @@ cmd_flow_parsed(const struct buffer *in)
        case ISOLATE:
                port_flow_isolate(in->port, in->args.isolate.set);
                break;
+       case AGED:
+               port_flow_aged(in->port, in->args.aged.destroy);
+               break;
        default:
                break;
        }
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 72f25d1521..b1133ece84 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -1367,6 +1367,26 @@ port_flow_validate(portid_t port_id,
        return 0;
 }
 
+/** Update age action context by port_flow pointer. */
+void
+update_age_action_context(const struct rte_flow_action *actions,
+                       struct port_flow *pf)
+{
+       struct rte_flow_action_age *age = NULL;
+
+       for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+               switch (actions->type) {
+               case RTE_FLOW_ACTION_TYPE_AGE:
+                       age = (struct rte_flow_action_age *)
+                               (uintptr_t)actions->conf;
+                       age->context = pf;
+                       return;
+               default:
+                       break;
+               }
+       }
+}
+
 /** Create flow rule. */
 int
 port_flow_create(portid_t port_id,
@@ -1377,32 +1397,34 @@ port_flow_create(portid_t port_id,
        struct rte_flow *flow;
        struct rte_port *port;
        struct port_flow *pf;
-       uint32_t id;
+       uint32_t id = 0;
        struct rte_flow_error error;
 
-       /* Poisoning to make sure PMDs update it in case of error. */
-       memset(&error, 0x22, sizeof(error));
-       flow = rte_flow_create(port_id, attr, pattern, actions, &error);
-       if (!flow)
-               return port_flow_complain(&error);
        port = &ports[port_id];
        if (port->flow_list) {
                if (port->flow_list->id == UINT32_MAX) {
                        printf("Highest rule ID is already assigned, delete"
                               " it first");
-                       rte_flow_destroy(port_id, flow, NULL);
                        return -ENOMEM;
                }
                id = port->flow_list->id + 1;
-       } else
-               id = 0;
+       }
        pf = port_flow_new(attr, pattern, actions, &error);
-       if (!pf) {
-               rte_flow_destroy(port_id, flow, NULL);
+       if (!pf)
+               return port_flow_complain(&error);
+       update_age_action_context(actions, pf);
+       /* Poisoning to make sure PMDs update it in case of error. */
+       memset(&error, 0x22, sizeof(error));
+       flow = rte_flow_create(port_id, attr, pattern, actions, &error);
+       if (!flow) {
+               free(pf);
                return port_flow_complain(&error);
        }
-       pf->next = port->flow_list;
        pf->id = id;
+       pf->prev = NULL;
+       pf->next = port->flow_list;
+       if (pf->next)
+               pf->next->prev = pf;
        pf->flow = flow;
        port->flow_list = pf;
        printf("Flow rule #%u created\n", pf->id);
@@ -1570,6 +1592,64 @@ port_flow_query(portid_t port_id, uint32_t rule,
        return 0;
 }
 
+/** List simply and destroy all aged flows. */
+void
+port_flow_aged(portid_t port_id, uint8_t destroy)
+{
+       int nb_context, total = 0, idx;
+       void **contexts;
+       struct rte_flow_error error;
+       struct port_flow *pf;
+
+       if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+           port_id == (portid_t)RTE_PORT_ALL)
+               return;
+       total = rte_flow_get_aged_flows(port_id, NULL, 0, &error);
+       printf("Port %u total aged flows: %d\n", port_id, total);
+       if (total <= 0)
+               return;
+       contexts = malloc(sizeof(void *) * total);
+       printf("ID\tGroup\tPrio\tAttr\n");
+       nb_context = rte_flow_get_aged_flows(port_id, contexts, total, &error);
+       if (nb_context != total) {
+               printf("Port:%d get aged flows count(%d) != total(%d)\n",
+                       port_id, nb_context, total);
+               free(contexts);
+               return;
+       }
+       for (idx = 0; idx < nb_context; idx++) {
+               pf = (struct port_flow *)contexts[idx];
+               if (!pf) {
+                       printf("Error: get Null context in port %u\n", port_id);
+                       continue;
+               }
+               printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c%c\t\n",
+                      pf->id,
+                      pf->rule.attr->group,
+                      pf->rule.attr->priority,
+                      pf->rule.attr->ingress ? 'i' : '-',
+                      pf->rule.attr->egress ? 'e' : '-',
+                      pf->rule.attr->transfer ? 't' : '-');
+               if (!destroy)
+                       continue;
+               if (pf->next)
+                       pf->next->prev = pf->prev;
+               if (pf->prev)
+                       pf->prev->next = pf->next;
+               else
+                       (&ports[port_id])->flow_list = pf->next;
+               /*
+                * Poisoning to make sure PMDs update it in case
+                * of error.
+                */
+               memset(&error, 0x33, sizeof(error));
+               if (rte_flow_destroy(port_id, pf->flow, &error))
+                       port_flow_complain(&error);
+               free(pf);
+       }
+       free(contexts);
+}
+
 /** List flow rules. */
 void
 port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
@@ -3162,6 +3242,54 @@ configure_rxtx_dump_callbacks(uint16_t verbose)
        }
 }
 
+int
+aging_event_callback(uint16_t portid,
+               enum rte_eth_event_type event __rte_unused,
+               void *cb_arg __rte_unused,
+               void *ret_param __rte_unused)
+{
+       printf("port %u RTE_ETH_EVENT_FLOW_AGED triggered\n", portid);
+       return 0;
+}
+
+void
+add_aging_event_callbacks(portid_t portid)
+{
+       if (rte_eth_dev_callback_register(portid,
+                                         RTE_ETH_EVENT_FLOW_AGED,
+                                         aging_event_callback,
+                                         NULL))
+               printf("port %u register RTE_ETH_EVENT_FLOW_AGED fail\n",
+                       portid);
+}
+
+void
+remove_aging_event_callbacks(portid_t portid)
+{
+       if (rte_eth_dev_callback_unregister(portid,
+                                       RTE_ETH_EVENT_FLOW_AGED,
+                                       aging_event_callback,
+                                       NULL))
+               printf("port %u unregister RTE_ETH_EVENT_FLOW_AGED fail\n",
+                       portid);
+}
+
+void
+configure_aging_event_callbacks(uint16_t verbose)
+{
+       portid_t portid;
+
+       RTE_ETH_FOREACH_DEV(portid)
+       {
+               if (port_id_is_invalid(portid, ENABLED_WARN))
+                       continue;
+               if (verbose)
+                       add_aging_event_callbacks(portid);
+               else
+                       remove_aging_event_callbacks(portid);
+       }
+}
+
 void
 set_verbose_level(uint16_t vb_level)
 {
@@ -3169,6 +3297,7 @@ set_verbose_level(uint16_t vb_level)
               (unsigned int) verbose_level, (unsigned int) vb_level);
        verbose_level = vb_level;
        configure_rxtx_dump_callbacks(verbose_level);
+       configure_aging_event_callbacks(verbose_level);
 }
 
 void
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 99bacddbfd..0227ba1c30 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -2418,6 +2418,7 @@ start_port(portid_t pid)
                                }
                        }
                        configure_rxtx_dump_callbacks(0);
+                       configure_aging_event_callbacks(0);
                        printf("Configuring Port %d (socket %u)\n", pi,
                                        port->socket_id);
                        if (nb_hairpinq > 0 &&
@@ -2527,6 +2528,7 @@ start_port(portid_t pid)
                                return -1;
                }
                configure_rxtx_dump_callbacks(verbose_level);
+               configure_aging_event_callbacks(verbose_level);
                if (clear_ptypes) {
                        diag = rte_eth_dev_set_ptypes(pi, RTE_PTYPE_UNKNOWN,
                                        NULL, 0);
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 7ff4c5dba3..64af8fa4be 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -146,6 +146,7 @@ struct fwd_stream {
 
 /** Descriptor for a single flow. */
 struct port_flow {
+       struct port_flow *prev; /**< Previous flow in list. */
        struct port_flow *next; /**< Next flow in list. */
        struct port_flow *tmp; /**< Temporary linking. */
        uint32_t id; /**< Flow rule ID. */
@@ -747,12 +748,15 @@ int port_flow_create(portid_t port_id,
                     const struct rte_flow_attr *attr,
                     const struct rte_flow_item *pattern,
                     const struct rte_flow_action *actions);
+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_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);
+void port_flow_aged(portid_t port_id, uint8_t destroy);
 int port_flow_isolate(portid_t port_id, int set);
 
 void rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id);
@@ -895,6 +899,11 @@ void remove_rx_dump_callbacks(portid_t portid);
 void add_tx_dump_callbacks(portid_t portid);
 void remove_tx_dump_callbacks(portid_t portid);
 void configure_rxtx_dump_callbacks(uint16_t verbose);
+int aging_event_callback(uint16_t portid, enum rte_eth_event_type event,
+                     void *cb_arg, void *ret_param);
+void remove_aging_event_callbacks(portid_t portid);
+void add_aging_event_callbacks(portid_t portid);
+void configure_aging_event_callbacks(uint16_t verbose);
 
 uint16_t tx_pkt_set_md(uint16_t port_id, __rte_unused uint16_t queue,
                       struct rte_mbuf *pkts[], uint16_t nb_pkts,
-- 
2.21.0

Reply via email to