[v6] ethdev: add template table resize API

Message ID 20240212181223.596081-1-getelson@nvidia.com (mailing list archive)
State Changes Requested, archived
Delegated to: Ferruh Yigit
Headers
Series [v6] ethdev: add template table resize API |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/iol-testing warning apply patch failure
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS
ci/github-robot: build success github build: passed
ci/intel-Functional success Functional PASS

Commit Message

Gregory Etelson Feb. 12, 2024, 6:12 p.m. UTC
  Template table creation API sets table flows capacity.
If application needs more flows then the table was designed for,
the following procedures must be completed:
1. Create a new template table with larger flows capacity.
2. Re-create existing flows in the new table and delete flows from
   the original table.
3. Destroy original table.

Application cannot always execute that procedure:
* Port may not have sufficient resources to allocate a new table
  while maintaining original table.
* Application may not have existing flows "recipes" to re-create
  flows in a new table.

The patch defines a new API that allows application to resize
existing template table:

* Resizable template table must be created with the
  RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE_TABLE bit set.

* Application resizes existing table with the
  `rte_flow_template_table_resize()` function call.
  The table resize procedure updates the table maximal flow number
  only. Other table attributes are not affected by the table resize.
  ** The table resize procedure must not interrupt
     existing table flows operations in hardware.
  ** The table resize procedure must not alter flow handles held by
     application.

* After `rte_flow_template_table_resize()` returned, application must
  update table flow rules by calling
  `rte_flow_async_update_resized()`.
  The call reconfigures internal flow resources for the new table
  configuration.
  The flow update must not interrupt hardware flow operations.

* After table flows were updated, application must call
  `rte_flow_template_table_resize_complete()`.
  The function releases PMD resources related to the original
  table.
  Application can start new table resize after
  `rte_flow_template_table_resize_complete()` returned.

Testpmd commands:

* Create resizable template table
flow template_table <port-id> create table_id <tbl-id> resizable \
  [transfer|ingress|egres] group <group-id> \
  rules_number <initial table capacity> \
  pattern_template  <pt1> [ pattern_template <pt2> [ ... ]] \
  actions_template  <at1> [ actions_template <at2> [ ... ]]

* Resize table:
flow template_table <tbl-id> resize table_resize_id <tbl-id> \
  table_resize_rules_num <new table capacity>

* Queue a flow update:
flow queue <port-id> update_resized <tbl-id> rule <flow-id>

* Complete table resize:
flow template_table <port-id> resize_complete table <tbl-id>

Signed-off-by: Gregory Etelson <getelson@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
---
v2: Update the patch comment.
    Add table resize commands to testpmd user guide.
v3: Rename RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE macro.
v4: Remove inline.
    Add use case to rte_flow.rst.
v5: update API guide in the rte_flow.rst.
v6: update docs.
---
 app/test-pmd/cmdline_flow.c                 |  86 +++++++++++++-
 app/test-pmd/config.c                       | 102 +++++++++++++++++
 app/test-pmd/testpmd.h                      |   6 +
 doc/guides/howto/rte_flow.rst               |  94 ++++++++++++++++
 doc/guides/rel_notes/release_24_03.rst      |  12 ++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  15 ++-
 lib/ethdev/ethdev_trace.h                   |  33 ++++++
 lib/ethdev/ethdev_trace_points.c            |   9 ++
 lib/ethdev/rte_flow.c                       |  77 +++++++++++++
 lib/ethdev/rte_flow.h                       | 118 ++++++++++++++++++++
 lib/ethdev/rte_flow_driver.h                |  15 +++
 lib/ethdev/version.map                      |   6 +
 12 files changed, 567 insertions(+), 6 deletions(-)
  

Comments

Ferruh Yigit Feb. 12, 2024, 8:30 p.m. UTC | #1
On 2/12/2024 6:12 PM, Gregory Etelson wrote:
> Template table creation API sets table flows capacity.
> If application needs more flows then the table was designed for,
> the following procedures must be completed:
> 1. Create a new template table with larger flows capacity.
> 2. Re-create existing flows in the new table and delete flows from
>    the original table.
> 3. Destroy original table.
> 
> Application cannot always execute that procedure:
> * Port may not have sufficient resources to allocate a new table
>   while maintaining original table.
> * Application may not have existing flows "recipes" to re-create
>   flows in a new table.
> 
> The patch defines a new API that allows application to resize
> existing template table:
> 
> * Resizable template table must be created with the
>   RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE_TABLE bit set.
> 
> * Application resizes existing table with the
>   `rte_flow_template_table_resize()` function call.
>   The table resize procedure updates the table maximal flow number
>   only. Other table attributes are not affected by the table resize.
>   ** The table resize procedure must not interrupt
>      existing table flows operations in hardware.
>   ** The table resize procedure must not alter flow handles held by
>      application.
> 
> * After `rte_flow_template_table_resize()` returned, application must
>   update table flow rules by calling
>   `rte_flow_async_update_resized()`.
>   The call reconfigures internal flow resources for the new table
>   configuration.
>   The flow update must not interrupt hardware flow operations.
> 
> * After table flows were updated, application must call
>   `rte_flow_template_table_resize_complete()`.
>   The function releases PMD resources related to the original
>   table.
>   Application can start new table resize after
>   `rte_flow_template_table_resize_complete()` returned.
> 
> Testpmd commands:
> 
> * Create resizable template table
> flow template_table <port-id> create table_id <tbl-id> resizable \
>   [transfer|ingress|egres] group <group-id> \
>   rules_number <initial table capacity> \
>   pattern_template  <pt1> [ pattern_template <pt2> [ ... ]] \
>   actions_template  <at1> [ actions_template <at2> [ ... ]]
> 
> * Resize table:
> flow template_table <tbl-id> resize table_resize_id <tbl-id> \
>   table_resize_rules_num <new table capacity>
> 
> * Queue a flow update:
> flow queue <port-id> update_resized <tbl-id> rule <flow-id>
> 
> * Complete table resize:
> flow template_table <port-id> resize_complete table <tbl-id>
> 
> Signed-off-by: Gregory Etelson <getelson@nvidia.com>h
> Acked-by: Ori Kam <orika@nvidia.com>
>

There are some checkpatch warnings [1], but except that looks good to me

Acked-by: Ferruh Yigit <ferruh.yigit@amd.com>


@Thomas was reviewing the patch, I will wait him to proceed.



[1]
[PATCH] ethdev: add template table resize API

WARNING:REPEATED_WORD: Possible repeated word: 'template'
#567: FILE: doc/guides/rel_notes/release_24_03.rst:76:
+    Set when template template must be created with the resizable property.

WARNING:TYPO_SPELLING: 'wheather' may be misspelled - perhaps 'weather'?
#569: FILE: doc/guides/rel_notes/release_24_03.rst:78:
+    Query wheather template table can be resized.
           ^^^^^^^^

ERROR:SPACING: need consistent spacing around '*' (ctx:WxV)
#801: FILE: lib/ethdev/rte_flow.h:5945:
+                         rte_flow_template_table_attr *tbl_attr);
                                                       ^
(better to join to "const struct" line)
  
Thomas Monjalon Feb. 13, 2024, 11:51 a.m. UTC | #2
12/02/2024 19:12, Gregory Etelson:
> --- a/doc/guides/howto/rte_flow.rst
> +++ b/doc/guides/howto/rte_flow.rst
> +Template API resizable table
> +----------------------------
> +
> +Description
> +~~~~~~~~~~~
> +
> +The resizable template table API enables applications to dynamically adjust
> +capacity of template tables without disrupting the existing flows operation.
> +The resizable template table API allows applications to optimize the memory
> +usage and performance of template tables according to the traffic conditions
> +and requirements.
> +
> +A typical use case for the resizable template table API:
> +
> +  1. Create a resizable table with the initial capacity.
> +
> +  2. Change the table flows capacity.
> +
> +  3. Update table flows.

Isn't "flow rules" more appropriate than "flows"?

> +
> +  4. Complete the table resize.
> +
> +A resizable table can be ether in the normal or the resizable state.

s/ether/either/
drop "the"

> +When application begins to resize the table, it state is changed from

s/it/its/

> +the normal to resizable.

to resizable state. (no need from)

> +When application finishes resizing the table, the table state returns to
> +the normal state.

simpler:
until the application finishes the resize procedure.

> +Application can resize a table in the normal state only.
> +
> +Application needs to set the ``RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE`` bit in
> +the table attributes when creating a template table that can be resized.
> +A table cannot be converted to resizable if it was created without the
> +``RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE`` bit.

Redundant

> +A resizable table cannot be converted to non-resizable.
> +
> +Application triggers the table resize by calling
> +the ``rte_flow_template_table_resize()`` function. The resize process updates
> +the table configuration to fit the new flows capacity.

flows or flow rules?

> +Table resize does not change existing flows configuration.
> +Application can create new flows and modify or delete existing flows

flow rules

> +while the table is resizing, but the table performance might be
> +slower than usual.
> +
> +Flows that existed before table resize are fully functional after table resize.
> +However, application needs to update these flows to match the new table
> +configuration.

This part is not clear.
The rules are functional but needs to be updated. Why?

> +Application calls the ``rte_flow_async_update_resized()`` to update flow
> +resources for the new table configuration.
> +Flows created after table resize match new table configuration.
> +Application can track flows that need post-resize update or it can update all
> +existing flows. ``rte_flow_async_update_resized()`` returns success for flows
> +that were created after table resize.
> +
> +Application calls ``rte_flow_template_table_resize_complete()`` to return a
> +table to the normal state after it completed flows update.
> +
> +Testpmd commands (wrapped for clarity)::
> +
> +  # 1. Create resizable template table for 1 flow.
> +  testpmd> flow pattern_template 0 create ingress pattern_template_id 3
> +                template eth / ipv4 / udp src mask 0xffff / end
> +  testpmd> flow actions_template 0 create ingress actions_template_id 7
> +                template count  / rss / end
> +  testpmd> flow template_table 0 create table_id 101 resizable ingress
> +                group 1 priority 0 rules_number 1
> +                pattern_template 3 actions_template 7
> +
> +  # 2. Queue a flow rule.
> +  testpmd> flow queue 0 create 0 template_table 101
> +                pattern_template 0 actions_template 0 postpone no
> +                pattern eth / ipv4 / udp src spec 1 / end actions count / rss / end
> +
> +  # 3. Resize the template table
> +  #    The new table capacity is 32 rules
> +  testpmd> flow template_table 0 resize table_resize_id 101
> +                table_resize_rules_num 32
> +
> +  # 4. Queue more flow rules.
> +  testpmd> flow queue 0 create 0 template_table 101
> +                pattern_template 0 actions_template 0 postpone no
> +                pattern eth / ipv4 / udp src spec 2 / end actions count / rss / end
> +  testpmd> flow queue 0 create 0 template_table 101
> +                pattern_template 0 actions_template 0 postpone no
> +                pattern eth / ipv4 / udp src spec 3 / end actions count / rss / end
> +  testpmd> flow queue 0 create 0 template_table 101
> +                pattern_template 0 actions_template 0 postpone no
> +                pattern eth / ipv4 / udp src spec 4 / end actions count / rss / end
> +
> +  # 5. Queue the initial flow update.
> +  testpmd> flow queue 0 update_resized 0 rule 0
> +
> +  # 6. Complete the table resize.
> +  testpmd> flow template_table 0 resize_complete table 101
> diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst
> index 6f8ad27808..9d5115ed96 100644
> --- a/doc/guides/rel_notes/release_24_03.rst
> +++ b/doc/guides/rel_notes/release_24_03.rst
> @@ -55,6 +55,18 @@ New Features
>       Also, make sure to start the actual text at the margin.
>       =======================================================
>  
> +* **Added  API to change template table flows capacity.**
> +
> +  * ``RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE_TABLE`` table configuration bit.
> +    Set when template template must be created with the resizable property.
> +  * ``rte_flow_template_table_resizable()``.
> +    Query wheather template table can be resized.

whether

> +  * ``rte_flow_template_table_resize()``.
> +    Reconfigure template table for new flows capacity.
> +  * ``rte_flow_async_update_resized()``.
> +    Reconfigure flows for the updated table configuration.
> +  * ``rte_flow_template_table_resize_complete()``.
> +    Complete table resize.
[...]
> --- a/lib/ethdev/rte_flow.h
> +++ b/lib/ethdev/rte_flow.h
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Update flow for the new template table configuration after table resize.
> + * Can be called for *rule* created before and after *table* resize.

I feel we need to explain why it has to be called.

> + *
> + * @param port_id
> + *   Port identifier of Ethernet device.
> + * @param queue
> + *   Flow queue for async operation.
> + * @param attr
> + *   Async operation attributes.
> + * @param rule
> + *   Flow rule to update.
> + * @param user_data
> + *   The user data that will be returned on async completion event.
> + * @param error
> + *   Perform verbose error reporting if not NULL.
> + *   PMDs initialize this structure in case of error only.
> + *
> + * @return
> + *   - (0) if success.
> + *   - (-ENODEV) if *port_id* invalid.
> + *   - (-ENOTSUP) if underlying device does not support this functionality.
> + *   - (-EINVAL) if *table* was not resized.
> + *               If *rule* cannot be updated after *table* resize,
> + *               unrecoverable *table* error.
> + */
> +__rte_experimental
> +int
> +rte_flow_async_update_resized(uint16_t port_id, uint32_t queue,
> +			      const struct rte_flow_op_attr *attr,
> +			      struct rte_flow *rule, void *user_data,
> +			      struct rte_flow_error *error);
> +
  

Patch

diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index ce71818705..1a2556d53b 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -134,6 +134,7 @@  enum index {
 	/* Queue arguments. */
 	QUEUE_CREATE,
 	QUEUE_DESTROY,
+	QUEUE_FLOW_UPDATE_RESIZED,
 	QUEUE_UPDATE,
 	QUEUE_AGED,
 	QUEUE_INDIRECT_ACTION,
@@ -191,8 +192,12 @@  enum index {
 	/* Table arguments. */
 	TABLE_CREATE,
 	TABLE_DESTROY,
+	TABLE_RESIZE,
+	TABLE_RESIZE_COMPLETE,
 	TABLE_CREATE_ID,
 	TABLE_DESTROY_ID,
+	TABLE_RESIZE_ID,
+	TABLE_RESIZE_RULES_NUMBER,
 	TABLE_INSERTION_TYPE,
 	TABLE_INSERTION_TYPE_NAME,
 	TABLE_HASH_FUNC,
@@ -204,6 +209,7 @@  enum index {
 	TABLE_TRANSFER,
 	TABLE_TRANSFER_WIRE_ORIG,
 	TABLE_TRANSFER_VPORT_ORIG,
+	TABLE_RESIZABLE,
 	TABLE_RULES_NUMBER,
 	TABLE_PATTERN_TEMPLATE,
 	TABLE_ACTIONS_TEMPLATE,
@@ -1323,6 +1329,8 @@  static const enum index next_group_attr[] = {
 static const enum index next_table_subcmd[] = {
 	TABLE_CREATE,
 	TABLE_DESTROY,
+	TABLE_RESIZE,
+	TABLE_RESIZE_COMPLETE,
 	ZERO,
 };
 
@@ -1337,6 +1345,7 @@  static const enum index next_table_attr[] = {
 	TABLE_TRANSFER,
 	TABLE_TRANSFER_WIRE_ORIG,
 	TABLE_TRANSFER_VPORT_ORIG,
+	TABLE_RESIZABLE,
 	TABLE_RULES_NUMBER,
 	TABLE_PATTERN_TEMPLATE,
 	TABLE_ACTIONS_TEMPLATE,
@@ -1353,6 +1362,7 @@  static const enum index next_table_destroy_attr[] = {
 static const enum index next_queue_subcmd[] = {
 	QUEUE_CREATE,
 	QUEUE_DESTROY,
+	QUEUE_FLOW_UPDATE_RESIZED,
 	QUEUE_UPDATE,
 	QUEUE_AGED,
 	QUEUE_INDIRECT_ACTION,
@@ -3344,6 +3354,19 @@  static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY(struct buffer, port)),
 		.call = parse_table_destroy,
 	},
+	[TABLE_RESIZE] = {
+		.name = "resize",
+		.help = "resize template table",
+		.next = NEXT(NEXT_ENTRY(TABLE_RESIZE_ID)),
+		.call = parse_table
+	},
+	[TABLE_RESIZE_COMPLETE] = {
+		.name = "resize_complete",
+		.help = "complete table resize",
+		.next = NEXT(NEXT_ENTRY(TABLE_DESTROY_ID)),
+		.args = ARGS(ARGS_ENTRY(struct buffer, port)),
+		.call = parse_table_destroy,
+	},
 	/* Table  arguments. */
 	[TABLE_CREATE_ID] = {
 		.name = "table_id",
@@ -3354,13 +3377,29 @@  static const struct token token_list[] = {
 	},
 	[TABLE_DESTROY_ID] = {
 		.name = "table",
-		.help = "specify table id to destroy",
+		.help = "table id",
 		.next = NEXT(next_table_destroy_attr,
 			     NEXT_ENTRY(COMMON_TABLE_ID)),
 		.args = ARGS(ARGS_ENTRY_PTR(struct buffer,
 					    args.table_destroy.table_id)),
 		.call = parse_table_destroy,
 	},
+	[TABLE_RESIZE_ID] = {
+		.name = "table_resize_id",
+		.help = "table resize id",
+		.next = NEXT(NEXT_ENTRY(TABLE_RESIZE_RULES_NUMBER),
+			     NEXT_ENTRY(COMMON_TABLE_ID)),
+		.args = ARGS(ARGS_ENTRY(struct buffer, args.table.id)),
+		.call = parse_table
+	},
+	[TABLE_RESIZE_RULES_NUMBER] = {
+		.name = "table_resize_rules_num",
+		.help = "table resize rules number",
+		.next = NEXT(NEXT_ENTRY(END), NEXT_ENTRY(COMMON_UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct buffer,
+					args.table.attr.nb_flows)),
+		.call = parse_table
+	},
 	[TABLE_INSERTION_TYPE] = {
 		.name = "insertion_type",
 		.help = "specify insertion type",
@@ -3433,6 +3472,12 @@  static const struct token token_list[] = {
 		.next = NEXT(next_table_attr),
 		.call = parse_table,
 	},
+	[TABLE_RESIZABLE] = {
+		.name = "resizable",
+		.help = "set resizable attribute",
+		.next = NEXT(next_table_attr),
+		.call = parse_table,
+	},
 	[TABLE_RULES_NUMBER] = {
 		.name = "rules_number",
 		.help = "number of rules in table",
@@ -3525,6 +3570,14 @@  static const struct token token_list[] = {
 		.args = ARGS(ARGS_ENTRY(struct buffer, queue)),
 		.call = parse_qo_destroy,
 	},
+	[QUEUE_FLOW_UPDATE_RESIZED] = {
+		.name = "update_resized",
+		.help = "update a flow after table resize",
+		.next = NEXT(NEXT_ENTRY(QUEUE_DESTROY_ID),
+			     NEXT_ENTRY(COMMON_QUEUE_ID)),
+		.args = ARGS(ARGS_ENTRY(struct buffer, queue)),
+		.call = parse_qo_destroy,
+	},
 	[QUEUE_UPDATE] = {
 		.name = "update",
 		.help = "update a flow rule",
@@ -10334,6 +10387,7 @@  parse_table(struct context *ctx, const struct token *token,
 	}
 	switch (ctx->curr) {
 	case TABLE_CREATE:
+	case TABLE_RESIZE:
 		out->command = ctx->curr;
 		ctx->objdata = 0;
 		ctx->object = out;
@@ -10378,18 +10432,25 @@  parse_table(struct context *ctx, const struct token *token,
 	case TABLE_TRANSFER_WIRE_ORIG:
 		if (!out->args.table.attr.flow_attr.transfer)
 			return -1;
-		out->args.table.attr.specialize = RTE_FLOW_TABLE_SPECIALIZE_TRANSFER_WIRE_ORIG;
+		out->args.table.attr.specialize |= RTE_FLOW_TABLE_SPECIALIZE_TRANSFER_WIRE_ORIG;
 		return len;
 	case TABLE_TRANSFER_VPORT_ORIG:
 		if (!out->args.table.attr.flow_attr.transfer)
 			return -1;
-		out->args.table.attr.specialize = RTE_FLOW_TABLE_SPECIALIZE_TRANSFER_VPORT_ORIG;
+		out->args.table.attr.specialize |= RTE_FLOW_TABLE_SPECIALIZE_TRANSFER_VPORT_ORIG;
+		return len;
+	case TABLE_RESIZABLE:
+		out->args.table.attr.specialize |=
+			RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE;
 		return len;
 	case TABLE_RULES_NUMBER:
 		ctx->objdata = 0;
 		ctx->object = out;
 		ctx->objmask = NULL;
 		return len;
+	case TABLE_RESIZE_ID:
+	case TABLE_RESIZE_RULES_NUMBER:
+		return len;
 	default:
 		return -1;
 	}
@@ -10411,7 +10472,8 @@  parse_table_destroy(struct context *ctx, const struct token *token,
 	if (!out)
 		return len;
 	if (!out->command || out->command == TABLE) {
-		if (ctx->curr != TABLE_DESTROY)
+		if (ctx->curr != TABLE_DESTROY &&
+		    ctx->curr != TABLE_RESIZE_COMPLETE)
 			return -1;
 		if (sizeof(*out) > size)
 			return -1;
@@ -10513,7 +10575,8 @@  parse_qo_destroy(struct context *ctx, const struct token *token,
 	if (!out)
 		return len;
 	if (!out->command || out->command == QUEUE) {
-		if (ctx->curr != QUEUE_DESTROY)
+		if (ctx->curr != QUEUE_DESTROY &&
+		    ctx->curr != QUEUE_FLOW_UPDATE_RESIZED)
 			return -1;
 		if (sizeof(*out) > size)
 			return -1;
@@ -12569,10 +12632,18 @@  cmd_flow_parsed(const struct buffer *in)
 					in->args.table_destroy.table_id_n,
 					in->args.table_destroy.table_id);
 		break;
+	case TABLE_RESIZE_COMPLETE:
+		port_flow_template_table_resize_complete
+			(in->port, in->args.table_destroy.table_id[0]);
+		break;
 	case GROUP_SET_MISS_ACTIONS:
 		port_queue_group_set_miss_actions(in->port, &in->args.vc.attr,
 						  in->args.vc.actions);
 		break;
+	case TABLE_RESIZE:
+		port_flow_template_table_resize(in->port, in->args.table.id,
+						in->args.table.attr.nb_flows);
+		break;
 	case QUEUE_CREATE:
 		port_queue_flow_create(in->port, in->queue, in->postpone,
 			in->args.vc.table_id, in->args.vc.rule_id,
@@ -12584,6 +12655,11 @@  cmd_flow_parsed(const struct buffer *in)
 					in->args.destroy.rule_n,
 					in->args.destroy.rule);
 		break;
+	case QUEUE_FLOW_UPDATE_RESIZED:
+		port_queue_flow_update_resized(in->port, in->queue,
+					       in->postpone,
+					       in->args.destroy.rule[0]);
+		break;
 	case QUEUE_UPDATE:
 		port_queue_flow_update(in->port, in->queue, in->postpone,
 				in->args.vc.rule_id, in->args.vc.act_templ_id,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index cad7537bc6..e589ac614b 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -1403,6 +1403,19 @@  port_flow_new(const struct rte_flow_attr *attr,
 	return NULL;
 }
 
+static struct port_flow *
+port_flow_locate(struct port_flow *flows_list, uint32_t flow_id)
+{
+	struct port_flow *pf = flows_list;
+
+	while (pf) {
+		if (pf->id == flow_id)
+			break;
+		pf = pf->next;
+	}
+	return pf;
+}
+
 /** Print a message out of a flow error. */
 static int
 port_flow_complain(struct rte_flow_error *error)
@@ -1693,6 +1706,19 @@  table_alloc(uint32_t id, struct port_table **table,
 	return 0;
 }
 
+static struct port_table *
+port_table_locate(struct port_table *tables_list, uint32_t table_id)
+{
+	struct port_table *pt = tables_list;
+
+	while (pt) {
+		if (pt->id == table_id)
+			break;
+		pt = pt->next;
+	}
+	return pt;
+}
+
 /** Get info about flow management resources. */
 int
 port_flow_get_info(portid_t port_id)
@@ -2665,6 +2691,46 @@  port_flow_template_table_destroy(portid_t port_id,
 	return ret;
 }
 
+int
+port_flow_template_table_resize_complete(portid_t port_id, uint32_t table_id)
+{
+	struct rte_port *port;
+	struct port_table *pt;
+	struct rte_flow_error error = { 0, };
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return -EINVAL;
+	port = &ports[port_id];
+	pt = port_table_locate(port->table_list, table_id);
+	if (!pt)
+		return -EINVAL;
+	ret = rte_flow_template_table_resize_complete(port_id,
+						      pt->table, &error);
+	return !ret ? 0 : port_flow_complain(&error);
+}
+
+int
+port_flow_template_table_resize(portid_t port_id,
+				uint32_t table_id, uint32_t flows_num)
+{
+	struct rte_port *port;
+	struct port_table *pt;
+	struct rte_flow_error error = { 0, };
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return -EINVAL;
+	port = &ports[port_id];
+	pt = port_table_locate(port->table_list, table_id);
+	if (!pt)
+		return -EINVAL;
+	ret = rte_flow_template_table_resize(port_id, pt->table, flows_num, &error);
+	if (ret)
+		return port_flow_complain(&error);
+	return 0;
+}
+
 /** Flush table */
 int
 port_flow_template_table_flush(portid_t port_id)
@@ -2805,6 +2871,42 @@  port_queue_flow_create(portid_t port_id, queueid_t queue_id,
 	return 0;
 }
 
+int
+port_queue_flow_update_resized(portid_t port_id, queueid_t queue_id,
+			       bool postpone, uint32_t flow_id)
+{
+	const struct rte_flow_op_attr op_attr = { .postpone = postpone };
+	struct rte_flow_error error = { 0, };
+	struct port_flow *pf;
+	struct rte_port *port;
+	struct queue_job *job;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+	port = &ports[port_id];
+	if (queue_id >= port->queue_nb) {
+		printf("Queue #%u is invalid\n", queue_id);
+		return -EINVAL;
+	}
+	pf = port_flow_locate(port->flow_list, flow_id);
+	if (!pf)
+		return -EINVAL;
+	job = calloc(1, sizeof(*job));
+	if (!job)
+		return -ENOMEM;
+	job->type = QUEUE_JOB_TYPE_FLOW_TRANSFER;
+	job->pf = pf;
+	ret = rte_flow_async_update_resized(port_id, queue_id, &op_attr,
+					    pf->flow, job, &error);
+	if (ret) {
+		free(job);
+		return port_flow_complain(&error);
+	}
+	return 0;
+}
+
 /** Enqueue number of destroy flow rules operations. */
 int
 port_queue_flow_destroy(portid_t port_id, queueid_t queue_id,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 9b10a9ea1c..92f21e7776 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -110,6 +110,7 @@  enum {
 enum {
 	QUEUE_JOB_TYPE_FLOW_CREATE,
 	QUEUE_JOB_TYPE_FLOW_DESTROY,
+	QUEUE_JOB_TYPE_FLOW_TRANSFER,
 	QUEUE_JOB_TYPE_FLOW_UPDATE,
 	QUEUE_JOB_TYPE_ACTION_CREATE,
 	QUEUE_JOB_TYPE_ACTION_DESTROY,
@@ -981,7 +982,12 @@  int port_flow_template_table_create(portid_t port_id, uint32_t id,
 		   uint32_t nb_actions_templates, uint32_t *actions_templates);
 int port_flow_template_table_destroy(portid_t port_id,
 			    uint32_t n, const uint32_t *table);
+int port_queue_flow_update_resized(portid_t port_id, queueid_t queue_id,
+				   bool postpone, uint32_t flow_id);
 int port_flow_template_table_flush(portid_t port_id);
+int port_flow_template_table_resize_complete(portid_t port_id, uint32_t table_id);
+int port_flow_template_table_resize(portid_t port_id,
+				    uint32_t table_id, uint32_t flows_num);
 int port_queue_group_set_miss_actions(portid_t port_id, const struct rte_flow_attr *attr,
 				      const struct rte_flow_action *actions);
 int port_queue_flow_create(portid_t port_id, queueid_t queue_id,
diff --git a/doc/guides/howto/rte_flow.rst b/doc/guides/howto/rte_flow.rst
index 27d4f28f77..96c8a7f692 100644
--- a/doc/guides/howto/rte_flow.rst
+++ b/doc/guides/howto/rte_flow.rst
@@ -303,3 +303,97 @@  Terminal 1: output log::
   received packet with src ip = 176.80.50.4 sent to queue 3
   received packet with src ip = 176.80.50.5 sent to queue 1
   received packet with src ip = 176.80.50.6 sent to queue 3
+
+Template API resizable table
+----------------------------
+
+Description
+~~~~~~~~~~~
+
+The resizable template table API enables applications to dynamically adjust
+capacity of template tables without disrupting the existing flows operation.
+The resizable template table API allows applications to optimize the memory
+usage and performance of template tables according to the traffic conditions
+and requirements.
+
+A typical use case for the resizable template table API:
+
+  1. Create a resizable table with the initial capacity.
+
+  2. Change the table flows capacity.
+
+  3. Update table flows.
+
+  4. Complete the table resize.
+
+A resizable table can be ether in the normal or the resizable state.
+When application begins to resize the table, it state is changed from
+the normal to resizable.
+When application finishes resizing the table, the table state returns to
+the normal state.
+Application can resize a table in the normal state only.
+
+Application needs to set the ``RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE`` bit in
+the table attributes when creating a template table that can be resized.
+A table cannot be converted to resizable if it was created without the
+``RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE`` bit.
+A resizable table cannot be converted to non-resizable.
+
+Application triggers the table resize by calling
+the ``rte_flow_template_table_resize()`` function. The resize process updates
+the table configuration to fit the new flows capacity.
+Table resize does not change existing flows configuration.
+Application can create new flows and modify or delete existing flows
+while the table is resizing, but the table performance might be
+slower than usual.
+
+Flows that existed before table resize are fully functional after table resize.
+However, application needs to update these flows to match the new table
+configuration.
+Application calls the ``rte_flow_async_update_resized()`` to update flow
+resources for the new table configuration.
+Flows created after table resize match new table configuration.
+Application can track flows that need post-resize update or it can update all
+existing flows. ``rte_flow_async_update_resized()`` returns success for flows
+that were created after table resize.
+
+Application calls ``rte_flow_template_table_resize_complete()`` to return a
+table to the normal state after it completed flows update.
+
+Testpmd commands (wrapped for clarity)::
+
+  # 1. Create resizable template table for 1 flow.
+  testpmd> flow pattern_template 0 create ingress pattern_template_id 3
+                template eth / ipv4 / udp src mask 0xffff / end
+  testpmd> flow actions_template 0 create ingress actions_template_id 7
+                template count  / rss / end
+  testpmd> flow template_table 0 create table_id 101 resizable ingress
+                group 1 priority 0 rules_number 1
+                pattern_template 3 actions_template 7
+
+  # 2. Queue a flow rule.
+  testpmd> flow queue 0 create 0 template_table 101
+                pattern_template 0 actions_template 0 postpone no
+                pattern eth / ipv4 / udp src spec 1 / end actions count / rss / end
+
+  # 3. Resize the template table
+  #    The new table capacity is 32 rules
+  testpmd> flow template_table 0 resize table_resize_id 101
+                table_resize_rules_num 32
+
+  # 4. Queue more flow rules.
+  testpmd> flow queue 0 create 0 template_table 101
+                pattern_template 0 actions_template 0 postpone no
+                pattern eth / ipv4 / udp src spec 2 / end actions count / rss / end
+  testpmd> flow queue 0 create 0 template_table 101
+                pattern_template 0 actions_template 0 postpone no
+                pattern eth / ipv4 / udp src spec 3 / end actions count / rss / end
+  testpmd> flow queue 0 create 0 template_table 101
+                pattern_template 0 actions_template 0 postpone no
+                pattern eth / ipv4 / udp src spec 4 / end actions count / rss / end
+
+  # 5. Queue the initial flow update.
+  testpmd> flow queue 0 update_resized 0 rule 0
+
+  # 6. Complete the table resize.
+  testpmd> flow template_table 0 resize_complete table 101
diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst
index 6f8ad27808..9d5115ed96 100644
--- a/doc/guides/rel_notes/release_24_03.rst
+++ b/doc/guides/rel_notes/release_24_03.rst
@@ -55,6 +55,18 @@  New Features
      Also, make sure to start the actual text at the margin.
      =======================================================
 
+* **Added  API to change template table flows capacity.**
+
+  * ``RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE_TABLE`` table configuration bit.
+    Set when template template must be created with the resizable property.
+  * ``rte_flow_template_table_resizable()``.
+    Query wheather template table can be resized.
+  * ``rte_flow_template_table_resize()``.
+    Reconfigure template table for new flows capacity.
+  * ``rte_flow_async_update_resized()``.
+    Reconfigure flows for the updated table configuration.
+  * ``rte_flow_template_table_resize_complete()``.
+    Complete table resize.
 
 Removed Items
 -------------
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 447e28e694..d0d3adf643 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2984,12 +2984,21 @@  following sections.
 - Create a table::
 
    flow table {port_id} create
-       [table_id {id}]
+       [table_id {id}] [resizable]
        [group {group_id}] [priority {level}] [ingress] [egress] [transfer]
        rules_number {number}
        pattern_template {pattern_template_id}
        actions_template {actions_template_id}
 
+- Resize a table::
+
+   flow template_table {port_id} resize
+       table_resize_id {id} table_resize_rules_num {number}
+
+- Complete table resize::
+
+   flow template_table {port_id} resize_complete table {table_id}
+
 - Destroy a table::
 
    flow table {port_id} destroy table {id} [...]
@@ -3010,6 +3019,10 @@  following sections.
        pattern {item} [/ {item} [...]] / end
        actions {action} [/ {action} [...]] / end
 
+- Enqueue flow update following table resize::
+
+   flow queue {port_id} update_resized {table_id} rule {rule_id}
+
 - Enqueue destruction of specific flow rules::
 
    flow queue {port_id} destroy {queue_id}
diff --git a/lib/ethdev/ethdev_trace.h b/lib/ethdev/ethdev_trace.h
index 1b1ae0cfe8..cd3327a619 100644
--- a/lib/ethdev/ethdev_trace.h
+++ b/lib/ethdev/ethdev_trace.h
@@ -2572,6 +2572,39 @@  RTE_TRACE_POINT_FP(
 	rte_trace_point_emit_ptr(user_data);
 	rte_trace_point_emit_int(ret);
 )
+
+RTE_TRACE_POINT_FP(
+	rte_flow_trace_template_table_resize,
+	RTE_TRACE_POINT_ARGS(uint16_t port_id,
+			     struct rte_flow_template_table *table,
+			     uint32_t nb_rules, int ret),
+	rte_trace_point_emit_u16(port_id);
+	rte_trace_point_emit_ptr(table);
+	rte_trace_point_emit_u32(nb_rules);
+	rte_trace_point_emit_int(ret);
+)
+
+RTE_TRACE_POINT_FP(
+	rte_flow_trace_async_update_resized,
+	RTE_TRACE_POINT_ARGS(uint16_t port_id, uint32_t queue,
+			     const struct rte_flow_op_attr *attr,
+			     struct rte_flow *rule, void *user_data, int ret),
+	rte_trace_point_emit_u16(port_id);
+	rte_trace_point_emit_u32(queue);
+	rte_trace_point_emit_ptr(attr);
+	rte_trace_point_emit_ptr(rule);
+	rte_trace_point_emit_ptr(user_data);
+	rte_trace_point_emit_int(ret);
+)
+
+RTE_TRACE_POINT_FP(
+	rte_flow_trace_table_resize_complete,
+	RTE_TRACE_POINT_ARGS(uint16_t port_id,
+			     struct rte_flow_template_table *table, int ret),
+	rte_trace_point_emit_u16(port_id);
+	rte_trace_point_emit_ptr(table);
+	rte_trace_point_emit_int(ret);
+)
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/ethdev/ethdev_trace_points.c b/lib/ethdev/ethdev_trace_points.c
index 91f71d868b..1a1f685daa 100644
--- a/lib/ethdev/ethdev_trace_points.c
+++ b/lib/ethdev/ethdev_trace_points.c
@@ -774,3 +774,12 @@  RTE_TRACE_POINT_REGISTER(rte_flow_trace_async_action_list_handle_destroy,
 
 RTE_TRACE_POINT_REGISTER(rte_flow_trace_async_action_list_handle_query_update,
 			 lib.ethdev.flow.async_action_list_handle_query_update)
+
+RTE_TRACE_POINT_REGISTER(rte_flow_trace_template_table_resize,
+			 lib.ethdev.flow.template_table_resize)
+
+RTE_TRACE_POINT_REGISTER(rte_flow_trace_async_update_resized,
+			 lib.ethdev.flow.async_update_resized)
+
+RTE_TRACE_POINT_REGISTER(rte_flow_trace_table_resize_complete,
+			 lib.ethdev.flow.table_resize_complete)
diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
index f49d1d3767..5077b1a4b0 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -2481,3 +2481,80 @@  rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
 					hash, error);
 	return flow_err(port_id, ret, error);
 }
+
+bool
+rte_flow_template_table_resizable(__rte_unused uint16_t port_id,
+				  const struct rte_flow_template_table_attr *tbl_attr)
+{
+	return (tbl_attr->specialize &
+		RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE) != 0;
+}
+
+int
+rte_flow_template_table_resize(uint16_t port_id,
+			       struct rte_flow_template_table *table,
+			       uint32_t nb_rules,
+			       struct rte_flow_error *error)
+{
+	int ret;
+	struct rte_eth_dev *dev;
+	const struct rte_flow_ops *ops;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	ops = rte_flow_ops_get(port_id, error);
+	if (!ops || !ops->flow_template_table_resize)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "flow_template_table_resize not supported");
+	dev = &rte_eth_devices[port_id];
+	ret = ops->flow_template_table_resize(dev, table, nb_rules, error);
+	ret = flow_err(port_id, ret, error);
+	rte_flow_trace_template_table_resize(port_id, table, nb_rules, ret);
+	return ret;
+}
+
+int
+rte_flow_async_update_resized(uint16_t port_id, uint32_t queue,
+			      const struct rte_flow_op_attr *attr,
+			      struct rte_flow *rule, void *user_data,
+			      struct rte_flow_error *error)
+{
+	int ret;
+	struct rte_eth_dev *dev;
+	const struct rte_flow_ops *ops;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	ops = rte_flow_ops_get(port_id, error);
+	if (!ops || !ops->flow_update_resized)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "async_flow_async_transfer not supported");
+	dev = &rte_eth_devices[port_id];
+	ret = ops->flow_update_resized(dev, queue, attr, rule, user_data, error);
+	ret = flow_err(port_id, ret, error);
+	rte_flow_trace_async_update_resized(port_id, queue, attr,
+					    rule, user_data, ret);
+	return ret;
+}
+
+int
+rte_flow_template_table_resize_complete(uint16_t port_id,
+					struct rte_flow_template_table *table,
+					struct rte_flow_error *error)
+{
+	int ret;
+	struct rte_eth_dev *dev;
+	const struct rte_flow_ops *ops;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	ops = rte_flow_ops_get(port_id, error);
+	if (!ops || !ops->flow_template_table_resize_complete)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "flow_template_table_transfer_complete not supported");
+	dev = &rte_eth_devices[port_id];
+	ret = ops->flow_template_table_resize_complete(dev, table, error);
+	ret = flow_err(port_id, ret, error);
+	rte_flow_trace_table_resize_complete(port_id, table, ret);
+	return ret;
+}
diff --git a/lib/ethdev/rte_flow.h b/lib/ethdev/rte_flow.h
index 78b6bbb159..4ef4951808 100644
--- a/lib/ethdev/rte_flow.h
+++ b/lib/ethdev/rte_flow.h
@@ -5746,6 +5746,10 @@  struct rte_flow_template_table;
  * if the hint is supported.
  */
 #define RTE_FLOW_TABLE_SPECIALIZE_TRANSFER_VPORT_ORIG RTE_BIT32(1)
+/**
+ * Specialize table for resize.
+ */
+#define RTE_FLOW_TABLE_SPECIALIZE_RESIZABLE RTE_BIT32(2)
 /**@}*/
 
 /**
@@ -5824,6 +5828,26 @@  struct rte_flow_template_table_attr {
 	enum rte_flow_table_hash_func hash_func;
 };
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Query whether a table can be resized.
+ *
+ * @param port_id
+ *    Port identifier of Ethernet device.
+ * @param tbl_attr
+ *    Template table.
+ *
+ * @return
+ *    True if the table can be resized.
+ */
+__rte_experimental
+bool
+rte_flow_template_table_resizable(__rte_unused uint16_t port_id,
+				  const struct
+				  rte_flow_template_table_attr *tbl_attr);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice.
@@ -6750,6 +6774,100 @@  rte_flow_calc_table_hash(uint16_t port_id, const struct rte_flow_template_table
 			 const struct rte_flow_item pattern[], uint8_t pattern_template_index,
 			 uint32_t *hash, struct rte_flow_error *error);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update template table for new flow rules capacity.
+ *
+ * @param port_id
+ *   Port identifier of Ethernet device.
+ * @param table
+ *   Template table to modify.
+ * @param nb_rules
+ *   New flow rules capacity.
+ * @param error
+ *   Perform verbose error reporting if not NULL.
+ *   PMDs initialize this structure in case of error only.
+ *
+ * @return
+ *   - (0) if success.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - (-ENOTSUP) if underlying device does not support this functionality.
+ *   - (-EINVAL) if *table* is not resizable or
+ *               *table* resize to *nb_rules* is not supported or
+ *               unrecoverable *table* error.
+ */
+__rte_experimental
+int
+rte_flow_template_table_resize(uint16_t port_id,
+			       struct rte_flow_template_table *table,
+			       uint32_t nb_rules,
+			       struct rte_flow_error *error);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Update flow for the new template table configuration after table resize.
+ * Can be called for *rule* created before and after *table* resize.
+ *
+ * @param port_id
+ *   Port identifier of Ethernet device.
+ * @param queue
+ *   Flow queue for async operation.
+ * @param attr
+ *   Async operation attributes.
+ * @param rule
+ *   Flow rule to update.
+ * @param user_data
+ *   The user data that will be returned on async completion event.
+ * @param error
+ *   Perform verbose error reporting if not NULL.
+ *   PMDs initialize this structure in case of error only.
+ *
+ * @return
+ *   - (0) if success.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - (-ENOTSUP) if underlying device does not support this functionality.
+ *   - (-EINVAL) if *table* was not resized.
+ *               If *rule* cannot be updated after *table* resize,
+ *               unrecoverable *table* error.
+ */
+__rte_experimental
+int
+rte_flow_async_update_resized(uint16_t port_id, uint32_t queue,
+			      const struct rte_flow_op_attr *attr,
+			      struct rte_flow *rule, void *user_data,
+			      struct rte_flow_error *error);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Resume normal operational mode after table was resized and
+ * table rules were updated for the new table configuration.
+ *
+ * @param port_id
+ *   Port identifier of Ethernet device.
+ * @param table
+ *   Template table that undergoing resize operation.
+ * @param error
+ *   Perform verbose error reporting if not NULL.
+ *   PMDs initialize this structure in case of error only.
+ *
+ * @return
+ *   - (0) if success.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - (-ENOTSUP) if underlying device does not support this functionality.
+ *   - (-EINVAL) if there are rules that were not updated or
+ *               *table* cannot complete table resize,
+ *               unrecoverable error.
+ */
+__rte_experimental
+int
+rte_flow_template_table_resize_complete(uint16_t port_id,
+					struct rte_flow_template_table *table,
+					struct rte_flow_error *error);
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/ethdev/rte_flow_driver.h b/lib/ethdev/rte_flow_driver.h
index f35f659503..53d9393575 100644
--- a/lib/ethdev/rte_flow_driver.h
+++ b/lib/ethdev/rte_flow_driver.h
@@ -370,6 +370,21 @@  struct rte_flow_ops {
 		(struct rte_eth_dev *dev, const struct rte_flow_template_table *table,
 		 const struct rte_flow_item pattern[], uint8_t pattern_template_index,
 		 uint32_t *hash, struct rte_flow_error *error);
+	/** @see rte_flow_template_table_resize() */
+	int (*flow_template_table_resize)(struct rte_eth_dev *dev,
+					  struct rte_flow_template_table *table,
+					  uint32_t nb_rules,
+					  struct rte_flow_error *error);
+	/** @see rte_flow_async_update_resized() */
+	int (*flow_update_resized)(struct rte_eth_dev *dev, uint32_t queue,
+				   const struct rte_flow_op_attr *attr,
+				   struct rte_flow *rule, void *user_data,
+				   struct rte_flow_error *error);
+	/** @see rte_flow_template_table_resize_complete() */
+	int (*flow_template_table_resize_complete)
+			(struct rte_eth_dev *dev,
+			 struct rte_flow_template_table *table,
+			 struct rte_flow_error *error);
 };
 
 /**
diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
index 5c4917c020..cf56de6ea6 100644
--- a/lib/ethdev/version.map
+++ b/lib/ethdev/version.map
@@ -316,6 +316,12 @@  EXPERIMENTAL {
 	rte_eth_recycle_rx_queue_info_get;
 	rte_flow_group_set_miss_actions;
 	rte_flow_calc_table_hash;
+
+	# added in 24.03
+	rte_flow_async_update_resized;
+	rte_flow_template_table_resizable;
+	rte_flow_template_table_resize;
+	rte_flow_template_table_resize_complete;
 };
 
 INTERNAL {