From: Bill Zhou <dongz@mellanox.com>
To: wenzhuo.lu@intel.com, jingjing.wu@intel.com,
bernard.iremonger@intel.com, orika@mellanox.com
Cc: dev@dpdk.org
Subject: [dpdk-dev] [PATCH] app/testpmd: support flow aging
Date: Fri, 24 Apr 2020 13:55:11 +0300 [thread overview]
Message-ID: <20200424105511.13147-1-dongz@mellanox.com> (raw)
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 <dongz@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
next reply other threads:[~2020-04-24 10:55 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-24 10:55 Bill Zhou [this message]
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
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=20200424105511.13147-1-dongz@mellanox.com \
--to=dongz@mellanox.com \
--cc=bernard.iremonger@intel.com \
--cc=dev@dpdk.org \
--cc=jingjing.wu@intel.com \
--cc=orika@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).