app/testpmd: add flow engine configuration

Add testpmd support for the rte_flow_configure API.
Provide the command line interface for the Flow management.
Usage example: flow configure 0 queues_number 8 queues_size 256

Implement rte_flow_info_get API to get available resources:
Usage example: flow info 0

Signed-off-by: Alexander Kozyrev <akozyrev@nvidia.com>
Acked-by: Ori Kam <orika@nvidia.com>
This commit is contained in:
Alexander Kozyrev 2022-02-23 05:02:34 +02:00 committed by Ferruh Yigit
parent 13cd6d5cc7
commit 9ad3a41ab2
4 changed files with 252 additions and 3 deletions

View File

@ -72,6 +72,8 @@ enum index {
/* Top-level command. */ /* Top-level command. */
FLOW, FLOW,
/* Sub-level commands. */ /* Sub-level commands. */
INFO,
CONFIGURE,
INDIRECT_ACTION, INDIRECT_ACTION,
VALIDATE, VALIDATE,
CREATE, CREATE,
@ -122,6 +124,13 @@ enum index {
DUMP_ALL, DUMP_ALL,
DUMP_ONE, 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 arguments */
INDIRECT_ACTION_CREATE, INDIRECT_ACTION_CREATE,
INDIRECT_ACTION_UPDATE, INDIRECT_ACTION_UPDATE,
@ -868,6 +877,11 @@ struct buffer {
enum index command; /**< Flow command. */ enum index command; /**< Flow command. */
portid_t port; /**< Affected port ID. */ portid_t port; /**< Affected port ID. */
union { union {
struct {
struct rte_flow_port_attr port_attr;
uint32_t nb_queue;
struct rte_flow_queue_attr queue_attr;
} configure; /**< Configuration arguments. */
struct { struct {
uint32_t *action_id; uint32_t *action_id;
uint32_t action_id_n; uint32_t action_id_n;
@ -949,6 +963,16 @@ static const enum index next_flex_item[] = {
ZERO, 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[] = { static const enum index next_ia_create_attr[] = {
INDIRECT_ACTION_CREATE_ID, INDIRECT_ACTION_CREATE_ID,
INDIRECT_ACTION_INGRESS, 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 *, static int parse_isolate(struct context *, const struct token *,
const char *, unsigned int, const char *, unsigned int,
void *, 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 *, static int parse_tunnel(struct context *, const struct token *,
const char *, unsigned int, const char *, unsigned int,
void *, unsigned int); void *, unsigned int);
@ -2270,7 +2297,9 @@ static const struct token token_list[] = {
.type = "{command} {port_id} [{arg} [...]]", .type = "{command} {port_id} [{arg} [...]]",
.help = "manage ingress/egress flow rules", .help = "manage ingress/egress flow rules",
.next = NEXT(NEXT_ENTRY .next = NEXT(NEXT_ENTRY
(INDIRECT_ACTION, (INFO,
CONFIGURE,
INDIRECT_ACTION,
VALIDATE, VALIDATE,
CREATE, CREATE,
DESTROY, DESTROY,
@ -2285,6 +2314,65 @@ static const struct token token_list[] = {
.call = parse_init, .call = parse_init,
}, },
/* Top-level command. */ /* 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] = { [INDIRECT_ACTION] = {
.name = "indirect_action", .name = "indirect_action",
.type = "{command} {port_id} [{arg} [...]]", .type = "{command} {port_id} [{arg} [...]]",
@ -7736,6 +7824,33 @@ parse_isolate(struct context *ctx, const struct token *token,
return len; 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 static int
parse_flex(struct context *ctx, const struct token *token, parse_flex(struct context *ctx, const struct token *token,
const char *str, unsigned int len, const char *str, unsigned int len,
@ -8964,6 +9079,15 @@ static void
cmd_flow_parsed(const struct buffer *in) cmd_flow_parsed(const struct buffer *in)
{ {
switch (in->command) { 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: case INDIRECT_ACTION_CREATE:
port_action_handle_create( port_action_handle_create(
in->port, in->args.vc.attr.group, in->port, in->args.vc.attr.group,

View File

@ -1610,6 +1610,67 @@ action_alloc(portid_t port_id, uint32_t id,
return 0; 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 */ /** Create indirect action */
int int
port_action_handle_create(portid_t port_id, uint32_t id, port_action_handle_create(portid_t port_id, uint32_t id,

View File

@ -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_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 */ struct rte_ether_addr *mc_addr_pool; /**< pool of multicast addrs */
uint32_t mc_addr_nb; /**< nb. of addr. in mc_addr_pool */ 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 */ uint8_t slave_flag; /**< bonding slave port */
struct port_flow *flow_list; /**< Associated flows. */ struct port_flow *flow_list; /**< Associated flows. */
struct port_indirect_action *actions_list; 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); uint32_t id);
int port_action_handle_update(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); 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, int port_flow_validate(portid_t port_id,
const struct rte_flow_attr *attr, const struct rte_flow_attr *attr,
const struct rte_flow_item *pattern, const struct rte_flow_item *pattern,

View File

@ -3308,8 +3308,8 @@ Flow rules management
--------------------- ---------------------
Control of the generic flow API (*rte_flow*) is fully exposed through the Control of the generic flow API (*rte_flow*) is fully exposed through the
``flow`` command (validation, creation, destruction, queries and operation ``flow`` command (configuration, validation, creation, destruction, queries
modes). and operation modes).
Considering *rte_flow* overlaps with all `Filter Functions`_, using both Considering *rte_flow* overlaps with all `Filter Functions`_, using both
features simultaneously may cause undefined side-effects and is therefore 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 their general syntax are described below. They are covered in detail in the
following sections. 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:: - Check whether a flow rule can be created::
flow validate {port_id} flow validate {port_id}
@ -3391,6 +3403,51 @@ following sections.
flow tunnel list {port_id} 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 Creating a tunnel stub for offload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~