Signed-off-by: Nelio Laranjeiro <nelio.laranje...@6wind.com>
---
 drivers/net/mlx5/mlx5_flow.c | 83 +++++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 6 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 85dc5edaf..3e16f67d6 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -53,6 +53,7 @@ extern const struct eth_dev_ops mlx5_dev_ops_isolate;
 
 /* Action fate on the packet. */
 #define MLX5_FLOW_FATE_DROP (1u << 0)
+#define MLX5_FLOW_FATE_QUEUE (1u << 1)
 
 /* Verbs flow priority per layer level. */
 #define MLX5_FLOW_PRIO_L4 0
@@ -83,7 +84,8 @@ struct mlx5_flow_verbs {
 struct rte_flow {
        TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */
        struct rte_flow_attr attributes; /**< User flow attribute. */
-       struct mlx5_flow_verbs verbs; /* Verbs drop flow. */
+       struct mlx5_flow_verbs verbs; /* Verbs flow. */
+       uint16_t queue; /**< Destination queue to redirect traffic to. */
 };
 
 static const struct rte_flow_ops mlx5_flow_ops = {
@@ -150,6 +152,8 @@ mlx5_flow_print(struct rte_flow *flow __rte_unused)
                flow->verbs.layers & MLX5_FLOW_LAYER_L4 ? "l4" : "-");
        if (flow->verbs.fate & MLX5_FLOW_FATE_DROP)
                fprintf(stdout, " fate: drop queue\n");
+       else if (flow->verbs.fate & MLX5_FLOW_FATE_QUEUE)
+               fprintf(stdout, " fate: target queue %u\n", flow->queue);
        if (flow->verbs.attr) {
                struct ibv_spec_header *hdr =
                        (struct ibv_spec_header *)flow->verbs.specs;
@@ -442,6 +446,48 @@ mlx5_flow_action_drop(const struct rte_flow_action 
*actions,
        return 0;
 }
 
+/**
+ * Validate action queue provided by the user.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param actions
+ *   Pointer to flow actions array.
+ * @param flow
+ *   Pointer to the rte_flow structure.
+ * @param error
+ *   Pointer to error structure.
+ */
+static int
+mlx5_flow_action_queue(struct rte_eth_dev *dev,
+                      const struct rte_flow_action *actions,
+                      struct rte_flow *flow,
+                      struct rte_flow_error *error)
+{
+       struct priv *priv = dev->data->dev_private;
+       const struct rte_flow_action_queue *queue = actions->conf;
+
+       if (flow->verbs.fate)
+               return rte_flow_error_set(error, ENOTSUP,
+                                         RTE_FLOW_ERROR_TYPE_ACTION,
+                                         actions,
+                                         "multiple fate actions are not"
+                                         " supported");
+       if (queue->index >= priv->rxqs_n)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+                                         &queue->index,
+                                         "queue index out of range");
+       if (!(*priv->rxqs)[queue->index])
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+                                         &queue->index,
+                                         "queue is not configured");
+       flow->queue = queue->index;
+       flow->verbs.fate |= MLX5_FLOW_FATE_QUEUE;
+       return 0;
+}
+
 /**
  * Validate actions provided by the user.
  *
@@ -455,9 +501,9 @@ mlx5_flow_action_drop(const struct rte_flow_action *actions,
  *   Pointer to error structure.
  */
 static int
-mlx5_flow_actions(struct rte_eth_dev *dev __rte_unused,
+mlx5_flow_actions(struct rte_eth_dev *dev,
                  const struct rte_flow_action actions[],
-                 struct rte_flow *flow __rte_unused,
+                 struct rte_flow *flow,
                  struct rte_flow_error *error)
 {
        int ret;
@@ -469,6 +515,9 @@ mlx5_flow_actions(struct rte_eth_dev *dev __rte_unused,
                case RTE_FLOW_ACTION_TYPE_DROP:
                        ret = mlx5_flow_action_drop(actions, flow, error);
                        break;
+               case RTE_FLOW_ACTION_TYPE_QUEUE:
+                       ret = mlx5_flow_action_queue(dev, actions, flow, error);
+                       break;
                default:
                        return rte_flow_error_set(error, ENOTSUP,
                                                  RTE_FLOW_ERROR_TYPE_ACTION,
@@ -581,7 +630,10 @@ mlx5_flow_fate_remove(struct rte_eth_dev *dev, struct 
rte_flow *flow)
                }
        }
        if (flow->verbs.hrxq) {
-               mlx5_hrxq_drop_release(dev, flow->verbs.hrxq);
+               if (flow->verbs.fate & MLX5_FLOW_FATE_DROP)
+                       mlx5_hrxq_drop_release(dev, flow->verbs.hrxq);
+               else if (flow->verbs.fate & MLX5_FLOW_FATE_QUEUE)
+                       mlx5_hrxq_release(dev, flow->verbs.hrxq);
                flow->verbs.hrxq = NULL;
        }
 }
@@ -627,7 +679,7 @@ static int
 mlx5_flow_fate_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
               struct rte_flow_error *error)
 {
-       if (flow->verbs.fate & MLX5_FLOW_FATE_DROP)
+       if (flow->verbs.fate & MLX5_FLOW_FATE_DROP) {
                flow->verbs.hrxq = mlx5_hrxq_drop_new(dev);
                if (!flow->verbs.hrxq)
                        return rte_flow_error_set
@@ -635,11 +687,28 @@ mlx5_flow_fate_apply(struct rte_eth_dev *dev, struct 
rte_flow *flow,
                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
                                 NULL,
                                 "cannot allocate Drop queue");
-       else
+       } else if (flow->verbs.fate & MLX5_FLOW_FATE_QUEUE) {
+               struct mlx5_hrxq *hrxq;
+
+               hrxq = mlx5_hrxq_get(dev, rss_hash_default_key,
+                                    rss_hash_default_key_len, 0,
+                                    &flow->queue, 1, 0, 0);
+               if (!hrxq)
+                       hrxq = mlx5_hrxq_new(dev, rss_hash_default_key,
+                                            rss_hash_default_key_len, 0,
+                                            &flow->queue, 1, 0, 0);
+               if (!hrxq)
+                       return rte_flow_error_set(error, rte_errno,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                       NULL,
+                                       "cannot create flow");
+               flow->verbs.hrxq = hrxq;
+       } else {
                return rte_flow_error_set(error, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
                                          NULL,
                                          "no fate found");
+       }
        mlx5_flow_verbs_priority(flow->verbs.layers, flow->verbs.attr,
                                 flow->attributes.priority == MLX5_FLOW_CTRL);
        flow->verbs.flow =
@@ -647,6 +716,8 @@ mlx5_flow_fate_apply(struct rte_eth_dev *dev, struct 
rte_flow *flow,
        if (!flow->verbs.flow) {
                if (flow->verbs.fate & MLX5_FLOW_FATE_DROP)
                        mlx5_hrxq_drop_release(dev, flow->verbs.hrxq);
+               else
+                       mlx5_hrxq_release(dev, flow->verbs.hrxq);
                flow->verbs.hrxq = NULL;
                return rte_flow_error_set(error, errno,
                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-- 
2.17.0

Reply via email to