app/testpmd: support flow aging

Message ID 20200424105511.13147-1-dongz@mellanox.com (mailing list archive)
State Changes Requested, archived
Delegated to: Ferruh Yigit
Headers
Series app/testpmd: support flow aging |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-nxp-Performance success Performance Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-testing fail Testing issues
ci/travis-robot warning Travis build: failed
ci/Intel-compilation success Compilation OK

Commit Message

Bill Zhou April 24, 2020, 10:55 a.m. UTC
  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(-)
  

Comments

Ferruh Yigit April 24, 2020, 4:25 p.m. UTC | #1
On 4/24/2020 11:55 AM, Bill Zhou wrote:
> 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.

Can you please document new feature and command?

Instead of overloading the 'verbose', what do you think having explicit command
to register aging events? ("flow aged register <port_id>"?) I think many of the
verbose usage won't really interest in the flow aging.

> 
> Signed-off-by: Bill Zhou <dongz@mellanox.com>

<...>
  
Bill Zhou April 26, 2020, 7:23 a.m. UTC | #2
> -----Original Message-----
> From: Ferruh Yigit <ferruh.yigit@intel.com>
> Sent: Saturday, April 25, 2020 12:25 AM
> To: Bill Zhou <dongz@mellanox.com>; wenzhuo.lu@intel.com;
> jingjing.wu@intel.com; bernard.iremonger@intel.com; Ori Kam
> <orika@mellanox.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH] app/testpmd: support flow aging
> 
> On 4/24/2020 11:55 AM, Bill Zhou wrote:
> > 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.
> 
> Can you please document new feature and command?
> 
> Instead of overloading the 'verbose', what do you think having explicit
> command to register aging events? ("flow aged register <port_id>"?) I think
> many of the verbose usage won't really interest in the flow aging.
> 

Yes, some of the verbose usage indeed not interest in the flow aging. But If we use
register or unregister event to one port, sometime, it will repeat many times for
every ports.
What do you think if we register this event all the time, and introduce new global
var from command to control the event export to application ?
   for example: set aged_flow_event_print_en [0 | 1]

> >
> > Signed-off-by: Bill Zhou <dongz@mellanox.com>
> 
> <...>
  
Ferruh Yigit April 27, 2020, 2:13 p.m. UTC | #3
On 4/26/2020 8:23 AM, Bill Zhou wrote:
> 
> 
>> -----Original Message-----
>> From: Ferruh Yigit <ferruh.yigit@intel.com>
>> Sent: Saturday, April 25, 2020 12:25 AM
>> To: Bill Zhou <dongz@mellanox.com>; wenzhuo.lu@intel.com;
>> jingjing.wu@intel.com; bernard.iremonger@intel.com; Ori Kam
>> <orika@mellanox.com>
>> Cc: dev@dpdk.org
>> Subject: Re: [dpdk-dev] [PATCH] app/testpmd: support flow aging
>>
>> On 4/24/2020 11:55 AM, Bill Zhou wrote:
>>> 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.
>>
>> Can you please document new feature and command?
>>
>> Instead of overloading the 'verbose', what do you think having explicit
>> command to register aging events? ("flow aged register <port_id>"?) I think
>> many of the verbose usage won't really interest in the flow aging.
>>
> 
> Yes, some of the verbose usage indeed not interest in the flow aging. But If we use
> register or unregister event to one port, sometime, it will repeat many times for
> every ports.
> What do you think if we register this event all the time, and introduce new global
> var from command to control the event export to application ?
>    for example: set aged_flow_event_print_en [0 | 1]

I am not also sure about registering this event always, you can register for all
ports with same command, as we do in many commands:
"flow aged register <port_id>|all"

When argument is "all" it registers for all ports, when it is a specific
port_id, registers for that port id.
And it is good to have 'unregister' command too.

> 
>>>
>>> Signed-off-by: Bill Zhou <dongz@mellanox.com>
>>
>> <...>
  
Matan Azrad April 27, 2020, 3:12 p.m. UTC | #4
Hi

From: Ferruh Yigit
> On 4/26/2020 8:23 AM, Bill Zhou wrote:
> >
> >
> >> -----Original Message-----
> >> From: Ferruh Yigit <ferruh.yigit@intel.com>
> >> Sent: Saturday, April 25, 2020 12:25 AM
> >> To: Bill Zhou <dongz@mellanox.com>; wenzhuo.lu@intel.com;
> >> jingjing.wu@intel.com; bernard.iremonger@intel.com; Ori Kam
> >> <orika@mellanox.com>
> >> Cc: dev@dpdk.org
> >> Subject: Re: [dpdk-dev] [PATCH] app/testpmd: support flow aging
> >>
> >> On 4/24/2020 11:55 AM, Bill Zhou wrote:
> >>> 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.
> >>
> >> Can you please document new feature and command?
> >>
> >> Instead of overloading the 'verbose', what do you think having
> >> explicit command to register aging events? ("flow aged register
> >> <port_id>"?) I think many of the verbose usage won't really interest in
> the flow aging.
> >>
> >
> > Yes, some of the verbose usage indeed not interest in the flow aging.
> > But If we use register or unregister event to one port, sometime, it
> > will repeat many times for every ports.
> > What do you think if we register this event all the time, and
> > introduce new global var from command to control the event export to
> application ?
> >    for example: set aged_flow_event_print_en [0 | 1]
> 
> I am not also sure about registering this event always, you can register for all
> ports with same command, as we do in many commands:
> "flow aged register <port_id>|all"
> 
> When argument is "all" it registers for all ports, when it is a specific port_id,
> registers for that port id.
> And it is good to have 'unregister' command too.

As I can see in testpmd default, it all the time registers to all events..
See register_eth_event_callback.

I suggest to catch the age event in callback and print it only when set aged_flow_event_print_en is on.


Matan


> 
> >
> >>>
> >>> Signed-off-by: Bill Zhou <dongz@mellanox.com>
> >>
> >> <...>
  
Ferruh Yigit April 30, 2020, 10:26 p.m. UTC | #5
On 4/27/2020 4:12 PM, Matan Azrad wrote:
> Hi
> 
> From: Ferruh Yigit
>> On 4/26/2020 8:23 AM, Bill Zhou wrote:
>>>
>>>
>>>> -----Original Message-----
>>>> From: Ferruh Yigit <ferruh.yigit@intel.com>
>>>> Sent: Saturday, April 25, 2020 12:25 AM
>>>> To: Bill Zhou <dongz@mellanox.com>; wenzhuo.lu@intel.com;
>>>> jingjing.wu@intel.com; bernard.iremonger@intel.com; Ori Kam
>>>> <orika@mellanox.com>
>>>> Cc: dev@dpdk.org
>>>> Subject: Re: [dpdk-dev] [PATCH] app/testpmd: support flow aging
>>>>
>>>> On 4/24/2020 11:55 AM, Bill Zhou wrote:
>>>>> 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.
>>>>
>>>> Can you please document new feature and command?
>>>>
>>>> Instead of overloading the 'verbose', what do you think having
>>>> explicit command to register aging events? ("flow aged register
>>>> <port_id>"?) I think many of the verbose usage won't really interest in
>> the flow aging.
>>>>
>>>
>>> Yes, some of the verbose usage indeed not interest in the flow aging.
>>> But If we use register or unregister event to one port, sometime, it
>>> will repeat many times for every ports.
>>> What do you think if we register this event all the time, and
>>> introduce new global var from command to control the event export to
>> application ?
>>>    for example: set aged_flow_event_print_en [0 | 1]
>>
>> I am not also sure about registering this event always, you can register for all
>> ports with same command, as we do in many commands:
>> "flow aged register <port_id>|all"
>>
>> When argument is "all" it registers for all ports, when it is a specific port_id,
>> registers for that port id.
>> And it is good to have 'unregister' command too.
> 
> As I can see in testpmd default, it all the time registers to all events..
> See register_eth_event_callback.

You are right.

> 
> I suggest to catch the age event in callback and print it only when set aged_flow_event_print_en is on.

+1

> 
> 
> Matan
> 
> 
>>
>>>
>>>>>
>>>>> Signed-off-by: Bill Zhou <dongz@mellanox.com>
>>>>
>>>> <...>
>
  

Patch

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,