diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
index c0644d678c..0533a33ca2 100644
--- a/app/test-pmd/cmdline_flow.c
+++ b/app/test-pmd/cmdline_flow.c
@@ -72,6 +72,8 @@ enum index {
 	/* Top-level command. */
 	FLOW,
 	/* Sub-level commands. */
+	INFO,
+	CONFIGURE,
 	INDIRECT_ACTION,
 	VALIDATE,
 	CREATE,
@@ -122,6 +124,13 @@ enum index {
 	DUMP_ALL,
 	DUMP_ONE,
 
+	/* Configure arguments */
+	CONFIG_QUEUES_NUMBER,
+	CONFIG_QUEUES_SIZE,
+	CONFIG_COUNTERS_NUMBER,
+	CONFIG_AGING_OBJECTS_NUMBER,
+	CONFIG_METERS_NUMBER,
+
 	/* Indirect action arguments */
 	INDIRECT_ACTION_CREATE,
 	INDIRECT_ACTION_UPDATE,
@@ -868,6 +877,11 @@ struct buffer {
 	enum index command; /**< Flow command. */
 	portid_t port; /**< Affected port ID. */
 	union {
+		struct {
+			struct rte_flow_port_attr port_attr;
+			uint32_t nb_queue;
+			struct rte_flow_queue_attr queue_attr;
+		} configure; /**< Configuration arguments. */
 		struct {
 			uint32_t *action_id;
 			uint32_t action_id_n;
@@ -949,6 +963,16 @@ static const enum index next_flex_item[] = {
 	ZERO,
 };
 
+static const enum index next_config_attr[] = {
+	CONFIG_QUEUES_NUMBER,
+	CONFIG_QUEUES_SIZE,
+	CONFIG_COUNTERS_NUMBER,
+	CONFIG_AGING_OBJECTS_NUMBER,
+	CONFIG_METERS_NUMBER,
+	END,
+	ZERO,
+};
+
 static const enum index next_ia_create_attr[] = {
 	INDIRECT_ACTION_CREATE_ID,
 	INDIRECT_ACTION_INGRESS,
@@ -2045,6 +2069,9 @@ static int parse_aged(struct context *, const struct token *,
 static int parse_isolate(struct context *, const struct token *,
 			 const char *, unsigned int,
 			 void *, unsigned int);
+static int parse_configure(struct context *, const struct token *,
+			   const char *, unsigned int,
+			   void *, unsigned int);
 static int parse_tunnel(struct context *, const struct token *,
 			const char *, unsigned int,
 			void *, unsigned int);
@@ -2270,7 +2297,9 @@ static const struct token token_list[] = {
 		.type = "{command} {port_id} [{arg} [...]]",
 		.help = "manage ingress/egress flow rules",
 		.next = NEXT(NEXT_ENTRY
-			     (INDIRECT_ACTION,
+			     (INFO,
+			      CONFIGURE,
+			      INDIRECT_ACTION,
 			      VALIDATE,
 			      CREATE,
 			      DESTROY,
@@ -2285,6 +2314,65 @@ static const struct token token_list[] = {
 		.call = parse_init,
 	},
 	/* Top-level command. */
+	[INFO] = {
+		.name = "info",
+		.help = "get information about flow engine",
+		.next = NEXT(NEXT_ENTRY(END),
+			     NEXT_ENTRY(COMMON_PORT_ID)),
+		.args = ARGS(ARGS_ENTRY(struct buffer, port)),
+		.call = parse_configure,
+	},
+	/* Top-level command. */
+	[CONFIGURE] = {
+		.name = "configure",
+		.help = "configure flow engine",
+		.next = NEXT(next_config_attr,
+			     NEXT_ENTRY(COMMON_PORT_ID)),
+		.args = ARGS(ARGS_ENTRY(struct buffer, port)),
+		.call = parse_configure,
+	},
+	/* Configure arguments. */
+	[CONFIG_QUEUES_NUMBER] = {
+		.name = "queues_number",
+		.help = "number of queues",
+		.next = NEXT(next_config_attr,
+			     NEXT_ENTRY(COMMON_UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct buffer,
+					args.configure.nb_queue)),
+	},
+	[CONFIG_QUEUES_SIZE] = {
+		.name = "queues_size",
+		.help = "number of elements in queues",
+		.next = NEXT(next_config_attr,
+			     NEXT_ENTRY(COMMON_UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct buffer,
+					args.configure.queue_attr.size)),
+	},
+	[CONFIG_COUNTERS_NUMBER] = {
+		.name = "counters_number",
+		.help = "number of counters",
+		.next = NEXT(next_config_attr,
+			     NEXT_ENTRY(COMMON_UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct buffer,
+					args.configure.port_attr.nb_counters)),
+	},
+	[CONFIG_AGING_OBJECTS_NUMBER] = {
+		.name = "aging_counters_number",
+		.help = "number of aging objects",
+		.next = NEXT(next_config_attr,
+			     NEXT_ENTRY(COMMON_UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct buffer,
+					args.configure.port_attr.nb_aging_objects)),
+	},
+	[CONFIG_METERS_NUMBER] = {
+		.name = "meters_number",
+		.help = "number of meters",
+		.next = NEXT(next_config_attr,
+			     NEXT_ENTRY(COMMON_UNSIGNED)),
+		.args = ARGS(ARGS_ENTRY(struct buffer,
+					args.configure.port_attr.nb_meters)),
+	},
+	/* Top-level command. */
 	[INDIRECT_ACTION] = {
 		.name = "indirect_action",
 		.type = "{command} {port_id} [{arg} [...]]",
@@ -7736,6 +7824,33 @@ parse_isolate(struct context *ctx, const struct token *token,
 	return len;
 }
 
+/** Parse tokens for info/configure command. */
+static int
+parse_configure(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 != INFO && ctx->curr != CONFIGURE)
+			return -1;
+		if (sizeof(*out) > size)
+			return -1;
+		out->command = ctx->curr;
+		ctx->objdata = 0;
+		ctx->object = out;
+		ctx->objmask = NULL;
+	}
+	return len;
+}
+
 static int
 parse_flex(struct context *ctx, const struct token *token,
 	     const char *str, unsigned int len,
@@ -8964,6 +9079,15 @@ static void
 cmd_flow_parsed(const struct buffer *in)
 {
 	switch (in->command) {
+	case INFO:
+		port_flow_get_info(in->port);
+		break;
+	case CONFIGURE:
+		port_flow_configure(in->port,
+				    &in->args.configure.port_attr,
+				    in->args.configure.nb_queue,
+				    &in->args.configure.queue_attr);
+		break;
 	case INDIRECT_ACTION_CREATE:
 		port_action_handle_create(
 				in->port, in->args.vc.attr.group,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index de1ec14bc7..33a85cd7ca 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -1610,6 +1610,67 @@ action_alloc(portid_t port_id, uint32_t id,
 	return 0;
 }
 
+/** Get info about flow management resources. */
+int
+port_flow_get_info(portid_t port_id)
+{
+	struct rte_flow_port_info port_info;
+	struct rte_flow_queue_info queue_info;
+	struct rte_flow_error error;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+	/* Poisoning to make sure PMDs update it in case of error. */
+	memset(&error, 0x99, sizeof(error));
+	memset(&port_info, 0, sizeof(port_info));
+	memset(&queue_info, 0, sizeof(queue_info));
+	if (rte_flow_info_get(port_id, &port_info, &queue_info, &error))
+		return port_flow_complain(&error);
+	printf("Flow engine resources on port %u:\n"
+	       "Number of queues: %d\n"
+		   "Size of queues: %d\n"
+	       "Number of counters: %d\n"
+	       "Number of aging objects: %d\n"
+	       "Number of meter actions: %d\n",
+	       port_id, port_info.max_nb_queues,
+		   queue_info.max_size,
+	       port_info.max_nb_counters,
+	       port_info.max_nb_aging_objects,
+	       port_info.max_nb_meters);
+	return 0;
+}
+
+/** Configure flow management resources. */
+int
+port_flow_configure(portid_t port_id,
+	const struct rte_flow_port_attr *port_attr,
+	uint16_t nb_queue,
+	const struct rte_flow_queue_attr *queue_attr)
+{
+	struct rte_port *port;
+	struct rte_flow_error error;
+	const struct rte_flow_queue_attr *attr_list[nb_queue];
+	int std_queue;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+	    port_id == (portid_t)RTE_PORT_ALL)
+		return -EINVAL;
+	port = &ports[port_id];
+	port->queue_nb = nb_queue;
+	port->queue_sz = queue_attr->size;
+	for (std_queue = 0; std_queue < nb_queue; std_queue++)
+		attr_list[std_queue] = queue_attr;
+	/* Poisoning to make sure PMDs update it in case of error. */
+	memset(&error, 0x66, sizeof(error));
+	if (rte_flow_configure(port_id, port_attr, nb_queue, attr_list, &error))
+		return port_flow_complain(&error);
+	printf("Configure flows on port %u: "
+	       "number of queues %d with %d elements\n",
+	       port_id, nb_queue, queue_attr->size);
+	return 0;
+}
+
 /** Create indirect action */
 int
 port_action_handle_create(portid_t port_id, uint32_t id,
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 9967825044..096b6825eb 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -243,6 +243,8 @@ struct rte_port {
 	struct rte_eth_txconf   tx_conf[RTE_MAX_QUEUES_PER_PORT+1]; /**< per queue tx configuration */
 	struct rte_ether_addr   *mc_addr_pool; /**< pool of multicast addrs */
 	uint32_t                mc_addr_nb; /**< nb. of addr. in mc_addr_pool */
+	queueid_t               queue_nb; /**< nb. of queues for flow rules */
+	uint32_t                queue_sz; /**< size of a queue for flow rules */
 	uint8_t                 slave_flag; /**< bonding slave port */
 	struct port_flow        *flow_list; /**< Associated flows. */
 	struct port_indirect_action *actions_list;
@@ -885,6 +887,11 @@ struct rte_flow_action_handle *port_action_handle_get_by_id(portid_t port_id,
 							    uint32_t id);
 int port_action_handle_update(portid_t port_id, uint32_t id,
 			      const struct rte_flow_action *action);
+int port_flow_get_info(portid_t port_id);
+int port_flow_configure(portid_t port_id,
+			const struct rte_flow_port_attr *port_attr,
+			uint16_t nb_queue,
+			const struct rte_flow_queue_attr *queue_attr);
 int port_flow_validate(portid_t port_id,
 		       const struct rte_flow_attr *attr,
 		       const struct rte_flow_item *pattern,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 9cc248084f..c8f048aeef 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -3308,8 +3308,8 @@ Flow rules management
 ---------------------
 
 Control of the generic flow API (*rte_flow*) is fully exposed through the
-``flow`` command (validation, creation, destruction, queries and operation
-modes).
+``flow`` command (configuration, validation, creation, destruction, queries
+and operation modes).
 
 Considering *rte_flow* overlaps with all `Filter Functions`_, using both
 features simultaneously may cause undefined side-effects and is therefore
@@ -3332,6 +3332,18 @@ The first parameter stands for the operation mode. Possible operations and
 their general syntax are described below. They are covered in detail in the
 following sections.
 
+- Get info about flow engine::
+
+   flow info {port_id}
+
+- Configure flow engine::
+
+   flow configure {port_id}
+       [queues_number {number}] [queues_size {size}]
+       [counters_number {number}]
+       [aging_counters_number {number}]
+       [meters_number {number}]
+
 - Check whether a flow rule can be created::
 
    flow validate {port_id}
@@ -3391,6 +3403,51 @@ following sections.
 
    flow tunnel list {port_id}
 
+Retrieving info about flow management engine
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``flow info`` retrieves info on pre-configurable resources in the underlying
+device to give a hint of possible values for flow engine configuration.
+
+``rte_flow_info_get()``::
+
+   flow info {port_id}
+
+If successful, it will show::
+
+   Flow engine resources on port #[...]:
+   Number of queues: #[...]
+   Size of queues: #[...]
+   Number of counters: #[...]
+   Number of aging objects: #[...]
+   Number of meters: #[...]
+
+Otherwise it will show an error message of the form::
+
+   Caught error type [...] ([...]): [...]
+
+Configuring flow management engine
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``flow configure`` pre-allocates all the needed resources in the underlying
+device to be used later at the flow creation. Flow queues are allocated as well
+for asynchronous flow creation/destruction operations. It is bound to
+``rte_flow_configure()``::
+
+   flow configure {port_id}
+       [queues_number {number}] [queues_size {size}]
+       [counters_number {number}]
+       [aging_counters_number {number}]
+       [meters_number {number}]
+
+If successful, it will show::
+
+   Configure flows on port #[...]: number of queues #[...] with #[...] elements
+
+Otherwise it will show an error message of the form::
+
+   Caught error type [...] ([...]): [...]
+
 Creating a tunnel stub for offload
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
