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:
parent
13cd6d5cc7
commit
9ad3a41ab2
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user