> -----Original Message-----
> From: Bill Zhou <do...@mellanox.com>
> Subject: [PATCH v4] app/testpmd: support flow aging
> 
> 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:
> 
> - Add new item "flow_aged" to the current print event command arguments.
> - Add new command to list all aged flows, meanwhile, we can set parameter
>   to destroy it.
> 
> Signed-off-by: Bill Zhou <do...@mellanox.com>
> ---
> v2: Update the way of registering aging event, add new command to control
> if the event need be print or not. Update the output of the delete aged
> flow command format.
> v3: Change the command from only set aged flow output to set one gloable
> verbose bitmap for all events output.
> v4: Add the event output to current global print event arguments.
> ---

Acked-by: Ori Kam <or...@mellanox.com>
Thanks,
Ori

>  app/test-pmd/cmdline.c                      |   4 +
>  app/test-pmd/cmdline_flow.c                 |  62 +++++++++++
>  app/test-pmd/config.c                       | 108 ++++++++++++++++++--
>  app/test-pmd/parameters.c                   |   6 +-
>  app/test-pmd/testpmd.c                      |   4 +-
>  app/test-pmd/testpmd.h                      |   3 +
>  doc/guides/testpmd_app_ug/testpmd_funcs.rst |  62 +++++++++++
>  7 files changed, 235 insertions(+), 14 deletions(-)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index 1375f223eb..bcf9080c48 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]\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..4e2006c543 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,
> 
> +     /* Destroy aged flow 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 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 and 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,12 @@ 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",
> +             .call = parse_aged,
> +             .comp = comp_none,
> +     },
>       /* Validate/create attributes. */
>       [GROUP] = {
>               .name = "group",
> @@ -5367,6 +5397,35 @@ 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;
> +     }
> +     if (ctx->curr == AGED_DESTROY)
> +             out->args.aged.destroy = 1;
> +     return len;
> +}
> +
>  /** Parse tokens for isolate command. */
>  static int
>  parse_isolate(struct context *ctx, const struct token *token,
> @@ -6367,6 +6426,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..035d336ab5 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,28 +1397,27 @@ 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;
> @@ -1570,6 +1589,73 @@ 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)
> +{
> +     void **contexts;
> +     int nb_context, total = 0, idx;
> +     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) {
> +             port_flow_complain(&error);
> +             return;
> +     }
> +     if (total == 0)
> +             return;
> +     contexts = malloc(sizeof(void *) * total);
> +     if (contexts == NULL) {
> +             printf("Cannot allocate contexts for aged flow\n");
> +             return;
> +     }
> +     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) {
> +             int ret;
> +             uint32_t flow_id;
> +
> +             total = 0;
> +             printf("\n");
> +             for (idx = 0; idx < nb_context; idx++) {
> +                     pf = (struct port_flow *)contexts[idx];
> +                     if (!pf)
> +                             continue;
> +                     flow_id = pf->id;
> +                     ret = port_flow_destroy(port_id, 1, &flow_id);
> +                     if (!ret)
> +                             total++;
> +             }
> +             printf("%d flows be destroyed\n", total);
> +     }
> +     free(contexts);
> +}
> +
>  /** List flow rules. */
>  void
>  port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
> diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c
> index 30c1753c32..92b5575626 100644
> --- a/app/test-pmd/parameters.c
> +++ b/app/test-pmd/parameters.c
> @@ -187,9 +187,9 @@ usage(char* progname)
>       printf("  --no-rmv-interrupt: disable device removal interrupt.\n");
>       printf("  --bitrate-stats=N: set the logical core N to perform "
>               "bit-rate calculation.\n");
> -     printf("  --print-event
> <unknown|intr_lsc|queue_state|intr_reset|vf_mbox|macsec|intr_rmv|all>: "
> +     printf("  --print-event
> <unknown|intr_lsc|queue_state|intr_reset|vf_mbox|macsec|intr_rmv|flow_a
> ged|all>: "
>              "enable print of designated event or all of them.\n");
> -     printf("  --mask-event
> <unknown|intr_lsc|queue_state|intr_reset|vf_mbox|macsec|intr_rmv|all>: "
> +     printf("  --mask-event
> <unknown|intr_lsc|queue_state|intr_reset|vf_mbox|macsec|intr_rmv|flow_a
> ged|all>: "
>              "disable print of designated event or all of them.\n");
>       printf("  --flow-isolate-all: "
>              "requests flow API isolated mode on all ports at initialization
> time.\n");
> @@ -545,6 +545,8 @@ parse_event_printing_config(const char *optarg, int
> enable)
>               mask = UINT32_C(1) << RTE_ETH_EVENT_NEW;
>       else if (!strcmp(optarg, "dev_released"))
>               mask = UINT32_C(1) << RTE_ETH_EVENT_DESTROY;
> +     else if (!strcmp(optarg, "flow_aged"))
> +             mask = UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED;
>       else if (!strcmp(optarg, "all"))
>               mask = ~UINT32_C(0);
>       else {
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
> index 99bacddbfd..a2d0be56b3 100644
> --- a/app/test-pmd/testpmd.c
> +++ b/app/test-pmd/testpmd.c
> @@ -375,6 +375,7 @@ static const char * const eth_event_desc[] = {
>       [RTE_ETH_EVENT_INTR_RMV] = "device removal",
>       [RTE_ETH_EVENT_NEW] = "device probed",
>       [RTE_ETH_EVENT_DESTROY] = "device released",
> +     [RTE_ETH_EVENT_FLOW_AGED] = "flow aged",
>       [RTE_ETH_EVENT_MAX] = NULL,
>  };
> 
> @@ -388,7 +389,8 @@ uint32_t event_print_mask = (UINT32_C(1) <<
> RTE_ETH_EVENT_UNKNOWN) |
>                           (UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET) |
>                           (UINT32_C(1) << RTE_ETH_EVENT_IPSEC) |
>                           (UINT32_C(1) << RTE_ETH_EVENT_MACSEC) |
> -                         (UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV);
> +                         (UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV) |
> +                         (UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED);
>  /*
>   * Decide if all memory are locked for performance.
>   */
> diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
> index 7ff4c5dba3..fb391672a8 100644
> --- a/app/test-pmd/testpmd.h
> +++ b/app/test-pmd/testpmd.h
> @@ -747,12 +747,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);
> diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> index a360ecccfd..19260cc2d9 100644
> --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> @@ -3616,6 +3616,10 @@ following sections.
> 
>     flow dump {port_id} {output_file}
> 
> +- List and destroy aged flow rules::
> +
> +   flow aged {port_id} [destroy]
> +
>  Validating flow rules
>  ~~~~~~~~~~~~~~~~~~~~~
> 
> @@ -4503,6 +4507,64 @@ Otherwise, it will complain error occurred::
> 
>     Caught error type [...] ([...]): [...]
> 
> +Listing and destroying aged flow rules
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +``flow aged`` simply lists aged flow rules be get from api
> ``rte_flow_get_aged_flows``,
> +and ``destroy`` parameter can be used to destroy those flow rules in PMD.
> +
> +   flow aged {port_id} [destroy]
> +
> +Listing current aged flow rules::
> +
> +   testpmd> flow aged 0
> +   Port 0 total aged flows: 0
> +   testpmd> flow create 0 ingress pattern eth / ipv4 src is 2.2.2.14 / end
> +      actions age timeout 5 / queue index 0 /  end
> +   Flow rule #0 created
> +   testpmd> flow create 0 ingress pattern eth / ipv4 src is 2.2.2.15 / end
> +      actions age timeout 4 / queue index 0 /  end
> +   Flow rule #1 created
> +   testpmd> flow create 0 ingress pattern eth / ipv4 src is 2.2.2.16 / end
> +      actions age timeout 2 / queue index 0 /  end
> +   Flow rule #2 created
> +   testpmd> flow create 0 ingress pattern eth / ipv4 src is 2.2.2.17 / end
> +      actions age timeout 3 / queue index 0 /  end
> +   Flow rule #3 created
> +
> +
> +Aged Rules are simply list as command ``flow list {port_id}``, but strip the
> detail rule
> +information, all the aged flows are sorted by the longest timeout time. For
> example, if
> +those rules be configured in the same time, ID 2 will be the first aged out 
> rule,
> the next
> +will be ID 3, ID 1, ID 0::
> +
> +   testpmd> flow aged 0
> +   Port 0 total aged flows: 4
> +   ID      Group   Prio    Attr
> +   2       0       0       i--
> +   3       0       0       i--
> +   1       0       0       i--
> +   0       0       0       i--
> +
> +If attach ``destroy`` parameter, the command will destroy all the list aged
> flow rules.
> +
> +   testpmd> flow aged 0 destroy
> +   Port 0 total aged flows: 4
> +   ID      Group   Prio    Attr
> +   2       0       0       i--
> +   3       0       0       i--
> +   1       0       0       i--
> +   0       0       0       i--
> +
> +   Flow rule #2 destroyed
> +   Flow rule #3 destroyed
> +   Flow rule #1 destroyed
> +   Flow rule #0 destroyed
> +   4 flows be destroyed
> +   testpmd> flow aged 0
> +   Port 0 total aged flows: 0
> +
> +
>  Sample QinQ flow rules
>  ~~~~~~~~~~~~~~~~~~~~~~
> 
> --
> 2.21.0

Reply via email to