From: Ori Kam <orika@mellanox.com>
To: Bill Zhou <dongz@mellanox.com>,
"ferruh.yigit@intel.com" <ferruh.yigit@intel.com>,
Matan Azrad <matan@mellanox.com>,
"wenzhuo.lu@intel.com" <wenzhuo.lu@intel.com>,
"beilei.xing@intel.com" <beilei.xing@intel.com>,
"bernard.iremonger@intel.com" <bernard.iremonger@intel.com>,
"john.mcnamara@intel.com" <john.mcnamara@intel.com>,
"marko.kovacevic@intel.com" <marko.kovacevic@intel.com>
Cc: "dev@dpdk.org" <dev@dpdk.org>
Subject: Re: [dpdk-dev] [PATCH v4] app/testpmd: support flow aging
Date: Sun, 3 May 2020 14:58:54 +0000 [thread overview]
Message-ID: <AM6PR05MB5176726F089731759C6C94DDDBA90@AM6PR05MB5176.eurprd05.prod.outlook.com> (raw)
In-Reply-To: <20200503085948.27167-1-dongz@mellanox.com>
> -----Original Message-----
> From: Bill Zhou <dongz@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 <dongz@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 <orika@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
next prev parent reply other threads:[~2020-05-03 14:58 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-24 10:55 [dpdk-dev] [PATCH] " Bill Zhou
2020-04-24 16:25 ` Ferruh Yigit
2020-04-26 7:23 ` Bill Zhou
2020-04-27 14:13 ` Ferruh Yigit
2020-04-27 15:12 ` Matan Azrad
2020-04-30 22:26 ` Ferruh Yigit
2020-04-30 15:53 ` [dpdk-dev] [PATCH v2] " Bill Zhou
2020-04-30 22:43 ` Ferruh Yigit
2020-05-01 6:51 ` Matan Azrad
2020-05-01 9:27 ` Ferruh Yigit
2020-05-01 11:28 ` Matan Azrad
2020-05-01 11:54 ` Ferruh Yigit
2020-05-01 12:45 ` Matan Azrad
2020-05-01 13:38 ` Ferruh Yigit
2020-05-01 15:14 ` Matan Azrad
2020-05-01 15:44 ` Ferruh Yigit
2020-05-02 14:00 ` [dpdk-dev] [PATCH v3] " Bill Zhou
2020-05-03 8:59 ` [dpdk-dev] [PATCH v4] " Bill Zhou
2020-05-03 9:46 ` Matan Azrad
2020-05-03 14:58 ` Ori Kam [this message]
2020-05-05 8:37 ` Ferruh Yigit
2020-05-05 9:11 ` Matan Azrad
2020-05-05 9:23 ` Ferruh Yigit
2020-05-05 9:49 ` [dpdk-dev] [PATCH v5] " Bill Zhou
2020-05-05 10:09 ` Ori Kam
2020-05-05 15:11 ` Ferruh Yigit
2020-05-06 8:04 ` Matan Azrad
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=AM6PR05MB5176726F089731759C6C94DDDBA90@AM6PR05MB5176.eurprd05.prod.outlook.com \
--to=orika@mellanox.com \
--cc=beilei.xing@intel.com \
--cc=bernard.iremonger@intel.com \
--cc=dev@dpdk.org \
--cc=dongz@mellanox.com \
--cc=ferruh.yigit@intel.com \
--cc=john.mcnamara@intel.com \
--cc=marko.kovacevic@intel.com \
--cc=matan@mellanox.com \
--cc=wenzhuo.lu@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).