[dpdk-dev,18.08,v1,11/12] net/mlx5: add mark/flag flow action

Message ID bc962987760c8ca28b931322640a6d3e73e6ba15.1527506071.git.nelio.laranjeiro@6wind.com (mailing list archive)
State Superseded, archived
Delegated to: Shahaf Shuler
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation fail apply patch file failure

Commit Message

Nélio Laranjeiro May 28, 2018, 11:21 a.m. UTC
  Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
---
 drivers/net/mlx5/mlx5_flow.c | 156 +++++++++++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)
  

Patch

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: