From mboxrd@z Thu Jan 1 00:00:00 1970 From: Vasily Philipov Subject: [PATCH 2/3] net/mlx4: support for the RSS flow action Date: Thu, 25 May 2017 16:02:18 +0300 Message-ID: <5c9e0d61e840f8b9cecd999a598a5fa3a8523320.1495717153.git.vasilyf@mellanox.com> References: <0dca86aa1372d6ff09d0aff01d522c580e0e24ab.1495717153.git.vasilyf@mellanox.com> Cc: Vasily Philipov , Adrien Mazarguil , Nelio Laranjeiro To: dev@dpdk.org Return-path: Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by dpdk.org (Postfix) with ESMTP id 094B19953 for ; Thu, 25 May 2017 15:02:28 +0200 (CEST) In-Reply-To: <0dca86aa1372d6ff09d0aff01d522c580e0e24ab.1495717153.git.vasilyf@mellanox.com> In-Reply-To: <0dca86aa1372d6ff09d0aff01d522c580e0e24ab.1495717153.git.vasilyf@mellanox.com> References: <0dca86aa1372d6ff09d0aff01d522c580e0e24ab.1495717153.git.vasilyf@mellanox.com> List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" The isolated mode should be enabled. The number of queues in RSS ring must be power of 2. The sharing a queue between several RSS rings is impossible. Signed-off-by: Vasily Philipov --- drivers/net/mlx4/mlx4.c | 2 +- drivers/net/mlx4/mlx4.h | 5 ++ drivers/net/mlx4/mlx4_flow.c | 196 ++++++++++++++++++++++++++++++++++++++++++- drivers/net/mlx4/mlx4_flow.h | 3 +- 4 files changed, 200 insertions(+), 6 deletions(-) diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c index fc995c1..b51fef4 100644 --- a/drivers/net/mlx4/mlx4.c +++ b/drivers/net/mlx4/mlx4.c @@ -556,7 +556,7 @@ void priv_unlock(struct priv *priv) * @return * 0 on success, negative errno value on failure. */ -static int +int priv_create_parent(struct priv *priv, uint16_t queues[], uint16_t children_n) diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index b5fe1b4..e95e3b5 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -370,4 +370,9 @@ struct priv { void rxq_parent_cleanup(struct rxq *parent); +int +priv_create_parent(struct priv *priv, + uint16_t queues[], + uint16_t children_n); + #endif /* RTE_PMD_MLX4_H_ */ diff --git a/drivers/net/mlx4/mlx4_flow.c b/drivers/net/mlx4/mlx4_flow.c index 3fd2716..55d65b1 100644 --- a/drivers/net/mlx4/mlx4_flow.c +++ b/drivers/net/mlx4/mlx4_flow.c @@ -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 @@ struct rte_flow_drop { 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; } @@ -797,6 +868,80 @@ struct rte_flow_drop { } /** + * Get RSS parent rxq structure for given queues. + * + * Creates a new or returns a 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_get_parent(struct priv *priv, + uint16_t queues[], + uint16_t children_n, + struct rte_flow_error *error) +{ + int ret; + unsigned int i; + struct rxq *parent; + + for (parent = LIST_FIRST(&priv->parents); + parent; + parent = LIST_NEXT(parent, next)) { + unsigned int overlap = 0; + + for (i = 0; i < children_n; ++i) { + unsigned int j; + + for (j = 0; j < parent->rss.queues_n; ++j) + if (i != j && + parent->rss.queues[j] == queues[i]) { + goto error; + } else if (parent->rss.queues[j] == queues[i]) { + ++overlap; + break; + } + } + if (overlap == children_n && + children_n == parent->rss.queues_n) + return parent; + else if (overlap > 0) + 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; + } + } + ret = priv_create_parent(priv, queues, children_n); + if (ret) { + rte_flow_error_set(error, + ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, "flow rule creation failure"); + return NULL; + } + return LIST_FIRST(&priv->parents); + +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. * * @param priv @@ -831,9 +976,41 @@ struct rte_flow_drop { if (action->drop) { qp = priv->flow_drop_queue->qp; } else { - struct rxq *rxq = (*priv->rxqs)[action->queue_id]; - - qp = rxq->qp; + int ret; + unsigned int i; + struct rxq *rxq = NULL; + struct rxq *rxq_parent = NULL; + + if (action->queues_n > 1) { + rxq_parent = priv_get_parent(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) { + rxq_parent_cleanup(rxq_parent); + rte_flow_error_set( + error, + ENOMEM, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, + "flow rule creation failure"); + goto error; + } + } + } + qp = action->queues_n > 1 ? rxq_parent->qp : rxq->qp; rte_flow->qp = qp; } rte_flow->ibv_attr = ibv_attr; @@ -909,11 +1086,22 @@ struct rte_flow_drop { 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, diff --git a/drivers/net/mlx4/mlx4_flow.h b/drivers/net/mlx4/mlx4_flow.h index 6afc57f..823d3b6 100644 --- a/drivers/net/mlx4/mlx4_flow.h +++ b/drivers/net/mlx4/mlx4_flow.h @@ -97,7 +97,8 @@ struct mlx4_flow { 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); -- 1.8.3.1