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

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index ce1b4e94b..4ef0a3fee 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -55,6 +55,10 @@ extern const struct eth_dev_ops mlx5_dev_ops_isolate;
 #define MLX5_FLOW_FATE_DROP (1u << 0)
 #define MLX5_FLOW_FATE_QUEUE (1u << 1)
 
+/* Modify a packet. */
+#define MLX5_FLOW_MOD_FLAG (1u << 0)
+#define MLX5_FLOW_MOD_MARK (1u << 1)
+
 /* Verbs flow priority per layer level. */
 #define MLX5_FLOW_PRIO_L4 0
 #define MLX5_FLOW_PRIO_L3 1
@@ -69,6 +73,8 @@ struct mlx5_flow_verbs {
        unsigned int size; /**< Size of the attribute. */
        uint32_t layers;
        /**< Bit-fields of present layers see MLX5_FLOW_ITEMS_*. */
+       uint32_t modifier;
+       /**< Bit-fields of present modifier see MLX5_FLOW_MOD_*. */
        uint32_t fate;
        /**< Bit-fields of present fate see MLX5_FLOW_FATE_*. */
        struct {
@@ -893,6 +899,107 @@ mlx5_flow_action_queue(struct rte_eth_dev *dev,
        return 0;
 }
 
+/**
+ * Validate action flag provided by the user.
+ *
+ * @param flow
+ *   Pointer to the rte_flow structure.
+ * @param error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_action_flag(struct rte_flow *flow)
+{
+       unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
+       struct ibv_flow_spec_action_tag tag = {
+               .type = IBV_FLOW_SPEC_ACTION_TAG,
+               .size = size,
+               .tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT),
+       };
+
+       if (flow->verbs.modifier & MLX5_FLOW_MOD_MARK)
+               return 0;
+       mlx5_flow_spec_verbs_add(flow, &tag, size);
+       flow->verbs.modifier |= MLX5_FLOW_MOD_FLAG;
+       return 0;
+}
+
+/**
+ * Update verbs specification to modify the flag to mark.
+ *
+ * @param flow
+ *   Pointer to the rte_flow structure.
+ * @param mark_id
+ *   Mark identifier to replace the flag.
+ */
+static void
+mlx5_flow_action_mark_fate_queue(struct rte_flow *flow, uint32_t mark_id)
+{
+       int i;
+
+       /* Update Verbs specification. */
+       for (i = 0; i != flow->verbs.attr->num_of_specs; ++i) {
+               struct ibv_spec_header *hdr =
+                       (struct ibv_spec_header *)flow->verbs.attr;
+
+               if (hdr->type == IBV_FLOW_SPEC_ACTION_TAG) {
+                       struct ibv_flow_spec_action_tag *t =
+                               (struct ibv_flow_spec_action_tag *)hdr;
+
+                       t->tag_id = mlx5_flow_mark_set(mark_id);
+               }
+       }
+}
+
+/**
+ * Validate action mark provided by the user.
+ *
+ * @param actions
+ *   Pointer to flow actions array.
+ * @param flow
+ *   Pointer to the rte_flow structure.
+ * @param error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_action_mark(const struct rte_flow_action *actions,
+                     struct rte_flow *flow,
+                     struct rte_flow_error *error)
+{
+       const struct rte_flow_action_mark *mark = actions->conf;
+       unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
+       struct ibv_flow_spec_action_tag tag = {
+               .type = IBV_FLOW_SPEC_ACTION_TAG,
+               .size = size,
+       };
+
+       if (!mark)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION,
+                                         actions,
+                                         "configuration cannot be null");
+       if (mark->id >= MLX5_FLOW_MARK_MAX)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+                                         &mark->id,
+                                         "mark must be between 0 and"
+                                         " 16777199");
+       if (flow->verbs.modifier & MLX5_FLOW_MOD_FLAG) {
+               mlx5_flow_action_mark_fate_queue(flow, mark->id);
+       } else {
+               tag.tag_id = mlx5_flow_mark_set(mark->id);
+               mlx5_flow_spec_verbs_add(flow, &tag, size);
+       }
+       flow->verbs.modifier |= MLX5_FLOW_MOD_MARK;
+       return 0;
+}
+
 /**
  * Validate actions provided by the user.
  *
@@ -917,6 +1024,18 @@ mlx5_flow_actions(struct rte_eth_dev *dev,
                switch (actions->type) {
                case RTE_FLOW_ACTION_TYPE_VOID:
                        break;
+               case RTE_FLOW_ACTION_TYPE_FLAG:
+                       if (flow->verbs.modifier & MLX5_FLOW_MOD_MARK)
+                               return rte_flow_error_set
+                                       (error, ENOTSUP,
+                                        RTE_FLOW_ERROR_TYPE_ACTION,
+                                        actions,
+                                        "Flag after Mark is not supported");
+                       ret = mlx5_flow_action_flag(flow);
+                       break;
+               case RTE_FLOW_ACTION_TYPE_MARK:
+                       ret = mlx5_flow_action_mark(actions, flow, error);
+                       break;
                case RTE_FLOW_ACTION_TYPE_DROP:
                        ret = mlx5_flow_action_drop(actions, flow, error);
                        break;
@@ -997,6 +1116,42 @@ mlx5_flow_merge(struct rte_eth_dev *dev, struct rte_flow 
*flow,
        return size;
 }
 
+/**
+ * Enable/Disable Mark flag in Rx queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param flow
+ *   Pointer to flow structure.
+ * @param enable
+ *   0 to disabled, positive value otherwise.
+ */
+static void
+mlx5_flow_rxq_mark(struct rte_eth_dev *dev, struct rte_flow *flow, int enable)
+{
+       struct priv *priv = dev->data->dev_private;
+       struct mlx5_rxq_data *rxq_data;
+       const uint32_t mask = MLX5_FLOW_MOD_FLAG | MLX5_FLOW_MOD_MARK;
+       struct rte_flow *tmp;
+       uint32_t mark = !!enable;
+
+       if (!(flow->verbs.modifier & mask))
+               return;
+       rxq_data = (*priv->rxqs)[flow->queue];
+       /**
+        * Mark/Flag bit can only be disabled when there is no other
+        * flow applied using the same queue has a MARK/FLOW action
+        * configured.
+        */
+       TAILQ_FOREACH(tmp, &priv->flows, next) {
+               if (tmp == flow)
+                       continue;
+               if (tmp->queue == flow->queue)
+                       mark |= !!(tmp->verbs.modifier & mask);
+       }
+       rxq_data->mark = mark;
+}
+
 /**
  * Validate a flow supported by the NIC.
  *
@@ -1187,6 +1342,7 @@ mlx5_flow_list_create(struct rte_eth_dev *dev,
        ret = mlx5_flow_fate_apply(dev, flow, error);
        if (ret < 0)
                goto error;
+       mlx5_flow_rxq_mark(dev, flow, 1);
        TAILQ_INSERT_TAIL(list, flow, next);
        return flow;
 error:
-- 
2.17.0

Reply via email to