net/mlx4: support flow API RSS action
This commit adds support for the flow API RSS action with the following limitations: - Only supported when isolated mode is enabled. - The number of queues specified by the action (rte_flow_action_rss.num) must be a power of two. - Each queue index can be specified at most once in the configuration (rte_flow_action_rss.queue[]). - Because a queue can be associated with a single RSS context, it cannot be targeted by multiple RSS actions simultaneously. Signed-off-by: Vasily Philipov <vasilyf@mellanox.com> Acked-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
This commit is contained in:
parent
ff00a0dc56
commit
d7769c7c08
@ -569,7 +569,7 @@ rxq_cleanup(struct rxq *rxq);
|
||||
* @return
|
||||
* Pointer to a parent rxq structure, NULL on failure.
|
||||
*/
|
||||
static struct rxq *
|
||||
struct rxq *
|
||||
priv_parent_create(struct priv *priv,
|
||||
uint16_t queues[],
|
||||
uint16_t children_n)
|
||||
@ -705,10 +705,8 @@ dev_configure(struct rte_eth_dev *dev)
|
||||
priv->rss = 1;
|
||||
tmp = priv->rxqs_n;
|
||||
priv->rxqs_n = rxqs_n;
|
||||
if (priv->isolated) {
|
||||
priv->rss = 0;
|
||||
if (priv->isolated)
|
||||
return 0;
|
||||
}
|
||||
if (priv_parent_create(priv, NULL, priv->rxqs_n))
|
||||
return 0;
|
||||
/* Failure, rollback. */
|
||||
|
@ -372,4 +372,9 @@ rxq_create_qp(struct rxq *rxq,
|
||||
void
|
||||
rxq_parent_cleanup(struct rxq *parent);
|
||||
|
||||
struct rxq *
|
||||
priv_parent_create(struct priv *priv,
|
||||
uint16_t queues[],
|
||||
uint16_t children_n);
|
||||
|
||||
#endif /* RTE_PMD_MLX4_H_ */
|
||||
|
@ -112,6 +112,7 @@ struct rte_flow_drop {
|
||||
static const enum rte_flow_action_type valid_actions[] = {
|
||||
RTE_FLOW_ACTION_TYPE_DROP,
|
||||
RTE_FLOW_ACTION_TYPE_QUEUE,
|
||||
RTE_FLOW_ACTION_TYPE_RSS,
|
||||
RTE_FLOW_ACTION_TYPE_END,
|
||||
};
|
||||
|
||||
@ -672,6 +673,76 @@ priv_flow_validate(struct priv *priv,
|
||||
if (!queue || (queue->index > (priv->rxqs_n - 1)))
|
||||
goto exit_action_not_supported;
|
||||
action.queue = 1;
|
||||
action.queues_n = 1;
|
||||
action.queues[0] = queue->index;
|
||||
} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
|
||||
int i;
|
||||
int ierr;
|
||||
const struct rte_flow_action_rss *rss =
|
||||
(const struct rte_flow_action_rss *)
|
||||
actions->conf;
|
||||
|
||||
if (!priv->hw_rss) {
|
||||
rte_flow_error_set(error, ENOTSUP,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION,
|
||||
actions,
|
||||
"RSS cannot be used with "
|
||||
"the current configuration");
|
||||
return -rte_errno;
|
||||
}
|
||||
if (!priv->isolated) {
|
||||
rte_flow_error_set(error, ENOTSUP,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION,
|
||||
actions,
|
||||
"RSS cannot be used without "
|
||||
"isolated mode");
|
||||
return -rte_errno;
|
||||
}
|
||||
if (!rte_is_power_of_2(rss->num)) {
|
||||
rte_flow_error_set(error, ENOTSUP,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION,
|
||||
actions,
|
||||
"the number of queues "
|
||||
"should be power of two");
|
||||
return -rte_errno;
|
||||
}
|
||||
if (priv->max_rss_tbl_sz < rss->num) {
|
||||
rte_flow_error_set(error, ENOTSUP,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION,
|
||||
actions,
|
||||
"the number of queues "
|
||||
"is too large");
|
||||
return -rte_errno;
|
||||
}
|
||||
/* checking indexes array */
|
||||
ierr = 0;
|
||||
for (i = 0; i < rss->num; ++i) {
|
||||
int j;
|
||||
if (rss->queue[i] >= priv->rxqs_n)
|
||||
ierr = 1;
|
||||
/*
|
||||
* Prevent the user from specifying
|
||||
* the same queue twice in the RSS array.
|
||||
*/
|
||||
for (j = i + 1; j < rss->num && !ierr; ++j)
|
||||
if (rss->queue[j] == rss->queue[i])
|
||||
ierr = 1;
|
||||
if (ierr) {
|
||||
rte_flow_error_set(
|
||||
error,
|
||||
ENOTSUP,
|
||||
RTE_FLOW_ERROR_TYPE_HANDLE,
|
||||
NULL,
|
||||
"RSS action only supports "
|
||||
"unique queue indices "
|
||||
"in a list");
|
||||
return -rte_errno;
|
||||
}
|
||||
}
|
||||
action.queue = 1;
|
||||
action.queues_n = rss->num;
|
||||
for (i = 0; i < rss->num; ++i)
|
||||
action.queues[i] = rss->queue[i];
|
||||
} else {
|
||||
goto exit_action_not_supported;
|
||||
}
|
||||
@ -796,6 +867,82 @@ mlx4_flow_create_drop_queue(struct priv *priv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get RSS parent rxq structure for given queues.
|
||||
*
|
||||
* Creates a new or returns an existed one.
|
||||
*
|
||||
* @param priv
|
||||
* Pointer to private structure.
|
||||
* @param queues
|
||||
* queues indices array, NULL in default RSS case.
|
||||
* @param children_n
|
||||
* the size of queues array.
|
||||
*
|
||||
* @return
|
||||
* Pointer to a parent rxq structure, NULL on failure.
|
||||
*/
|
||||
static struct rxq *
|
||||
priv_parent_get(struct priv *priv,
|
||||
uint16_t queues[],
|
||||
uint16_t children_n,
|
||||
struct rte_flow_error *error)
|
||||
{
|
||||
unsigned int i;
|
||||
struct rxq *parent;
|
||||
|
||||
for (parent = LIST_FIRST(&priv->parents);
|
||||
parent;
|
||||
parent = LIST_NEXT(parent, next)) {
|
||||
unsigned int same = 0;
|
||||
unsigned int overlap = 0;
|
||||
|
||||
/*
|
||||
* Find out whether an appropriate parent queue already exists
|
||||
* and can be reused, otherwise make sure there are no overlaps.
|
||||
*/
|
||||
for (i = 0; i < children_n; ++i) {
|
||||
unsigned int j;
|
||||
|
||||
for (j = 0; j < parent->rss.queues_n; ++j) {
|
||||
if (parent->rss.queues[j] != queues[i])
|
||||
continue;
|
||||
++overlap;
|
||||
if (i == j)
|
||||
++same;
|
||||
}
|
||||
}
|
||||
if (same == children_n &&
|
||||
children_n == parent->rss.queues_n)
|
||||
return parent;
|
||||
else if (overlap)
|
||||
goto error;
|
||||
}
|
||||
/* Exclude the cases when some QPs were created without RSS */
|
||||
for (i = 0; i < children_n; ++i) {
|
||||
struct rxq *rxq = (*priv->rxqs)[queues[i]];
|
||||
if (rxq->qp)
|
||||
goto error;
|
||||
}
|
||||
parent = priv_parent_create(priv, queues, children_n);
|
||||
if (!parent) {
|
||||
rte_flow_error_set(error,
|
||||
ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL, "flow rule creation failure");
|
||||
return NULL;
|
||||
}
|
||||
return parent;
|
||||
|
||||
error:
|
||||
rte_flow_error_set(error,
|
||||
EEXIST,
|
||||
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
|
||||
NULL,
|
||||
"sharing a queue between several"
|
||||
" RSS groups is not supported");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete flow rule creation.
|
||||
*
|
||||
@ -819,6 +966,7 @@ priv_flow_create_action_queue(struct priv *priv,
|
||||
{
|
||||
struct ibv_qp *qp;
|
||||
struct rte_flow *rte_flow;
|
||||
struct rxq *rxq_parent = NULL;
|
||||
|
||||
assert(priv->pd);
|
||||
assert(priv->ctx);
|
||||
@ -832,23 +980,38 @@ priv_flow_create_action_queue(struct priv *priv,
|
||||
qp = priv->flow_drop_queue->qp;
|
||||
} else {
|
||||
int ret;
|
||||
struct rxq *rxq = (*priv->rxqs)[action->queue_id];
|
||||
unsigned int i;
|
||||
struct rxq *rxq = NULL;
|
||||
|
||||
if (!rxq->qp) {
|
||||
assert(priv->isolated);
|
||||
ret = rxq_create_qp(rxq, rxq->elts_n,
|
||||
0, 0, NULL);
|
||||
if (ret) {
|
||||
rte_flow_error_set(
|
||||
error,
|
||||
ENOMEM,
|
||||
RTE_FLOW_ERROR_TYPE_HANDLE,
|
||||
NULL,
|
||||
"flow rule creation failure");
|
||||
if (action->queues_n > 1) {
|
||||
rxq_parent = priv_parent_get(priv, action->queues,
|
||||
action->queues_n, error);
|
||||
if (!rxq_parent)
|
||||
goto error;
|
||||
}
|
||||
for (i = 0; i < action->queues_n; ++i) {
|
||||
rxq = (*priv->rxqs)[action->queues[i]];
|
||||
/*
|
||||
* In case of isolated mode we postpone
|
||||
* ibv receive queue creation till the first
|
||||
* rte_flow rule will be applied on that queue.
|
||||
*/
|
||||
if (!rxq->qp) {
|
||||
assert(priv->isolated);
|
||||
ret = rxq_create_qp(rxq, rxq->elts_n,
|
||||
0, 0, rxq_parent);
|
||||
if (ret) {
|
||||
rte_flow_error_set(
|
||||
error,
|
||||
ENOMEM,
|
||||
RTE_FLOW_ERROR_TYPE_HANDLE,
|
||||
NULL,
|
||||
"flow rule creation failure");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
qp = rxq->qp;
|
||||
qp = action->queues_n > 1 ? rxq_parent->qp : rxq->qp;
|
||||
rte_flow->qp = qp;
|
||||
}
|
||||
rte_flow->ibv_attr = ibv_attr;
|
||||
@ -861,6 +1024,8 @@ priv_flow_create_action_queue(struct priv *priv,
|
||||
return rte_flow;
|
||||
|
||||
error:
|
||||
if (rxq_parent)
|
||||
rxq_parent_cleanup(rxq_parent);
|
||||
rte_free(rte_flow);
|
||||
return NULL;
|
||||
}
|
||||
@ -924,11 +1089,22 @@ priv_flow_create(struct priv *priv,
|
||||
continue;
|
||||
} else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
|
||||
action.queue = 1;
|
||||
action.queue_id =
|
||||
action.queues_n = 1;
|
||||
action.queues[0] =
|
||||
((const struct rte_flow_action_queue *)
|
||||
actions->conf)->index;
|
||||
} else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
|
||||
action.drop = 1;
|
||||
} else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
|
||||
unsigned int i;
|
||||
const struct rte_flow_action_rss *rss =
|
||||
(const struct rte_flow_action_rss *)
|
||||
actions->conf;
|
||||
|
||||
action.queue = 1;
|
||||
action.queues_n = rss->num;
|
||||
for (i = 0; i < rss->num; ++i)
|
||||
action.queues[i] = rss->queue[i];
|
||||
} else {
|
||||
rte_flow_error_set(error, ENOTSUP,
|
||||
RTE_FLOW_ERROR_TYPE_ACTION,
|
||||
|
@ -98,7 +98,8 @@ mlx4_flow_isolate(struct rte_eth_dev *dev,
|
||||
struct mlx4_flow_action {
|
||||
uint32_t drop:1; /**< Target is a drop queue. */
|
||||
uint32_t queue:1; /**< Target is a receive queue. */
|
||||
uint32_t queue_id; /**< Identifier of the queue. */
|
||||
uint16_t queues[RTE_MAX_QUEUES_PER_PORT]; /**< Queue indices to use. */
|
||||
uint16_t queues_n; /**< Number of entries in queue[] */
|
||||
};
|
||||
|
||||
int mlx4_priv_flow_start(struct priv *priv);
|
||||
|
Loading…
Reference in New Issue
Block a user