From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id DC600A00C2; Fri, 24 Apr 2020 12:55:13 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B60801C1EC; Fri, 24 Apr 2020 12:55:13 +0200 (CEST) Received: from git-send-mailer.rdmz.labs.mlnx (unknown [37.142.13.130]) by dpdk.org (Postfix) with ESMTP id 6DD361C1E9 for ; Fri, 24 Apr 2020 12:55:12 +0200 (CEST) From: Bill Zhou To: wenzhuo.lu@intel.com, jingjing.wu@intel.com, bernard.iremonger@intel.com, orika@mellanox.com Cc: dev@dpdk.org Date: Fri, 24 Apr 2020 13:55:11 +0300 Message-Id: <20200424105511.13147-1-dongz@mellanox.com> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [dpdk-dev] [PATCH] app/testpmd: support flow aging X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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 --- 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