@@ -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: