From: Dong Zhou Date: Tue, 5 May 2020 09:49:06 +0000 (+0300) Subject: app/testpmd: support flow aging X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=0e459ffa08891a3ba238821a80499b9b17e2f2d3;p=dpdk.git 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: Dong Zhou Acked-by: Matan Azrad Acked-by: Ori Kam Reviewed-by: Ferruh Yigit --- 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 : " + printf(" --print-event : " "enable print of designated event or all of them.\n"); - printf(" --mask-event : " + printf(" --mask-event : " "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/run_app.rst b/doc/guides/testpmd_app_ug/run_app.rst index 727ef52b8f..71213361b4 100644 --- a/doc/guides/testpmd_app_ug/run_app.rst +++ b/doc/guides/testpmd_app_ug/run_app.rst @@ -388,12 +388,12 @@ The command line options are: Set the logical core N to perform bitrate calculation. -* ``--print-event `` +* ``--print-event `` Enable printing the occurrence of the designated event. Using all will enable all of them. -* ``--mask-event `` +* ``--mask-event `` Disable printing the occurrence of the designated event. Using all will disable all of them. 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 ~~~~~~~~~~~~~~~~~~~~~~