[dpdk-dev] [RFC 2/4] net/mlx5: support E-Switch mirroring and jump in one flow

Jiawei Wang jiaweiw at nvidia.com
Tue Dec 15 08:49:49 CET 2020


mlx5 E-Switch mirroring is implemented as multiple destination array in
one steering table. The array currently supports only port ID as
destination actions.

This patch adds the jump action support to the array as one of destination.
The packets can be mirrored to the port and jump to next table in the same
destination array allowing to continue handling in the new table.

For example:
    set sample_actions 0 port_id id 1 / end
    flow create 0 ingress transfer pattern eth / end actions
    sample ratio 1 index 0 / jump group 1 / end
    flow create 1 ingress transfer group 1 pattern eth / end actions
    set_mac_dst mac_addr 00:aa:bb:cc:dd:ee / port_id id 2 / end

The flow results all the matched ingress packets are mirrored
to port id 1 and go to group 1. In the group 1, packets are modified
with the destination mac and sent to port id 2.

Signed-off-by: Jiawei Wang <jiaweiw at nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.c    | 36 ++++++++++--------
 drivers/net/mlx5/mlx5_flow.h    |  2 +
 drivers/net/mlx5/mlx5_flow_dv.c | 81 +++++++++++++++++++++++++++++------------
 3 files changed, 80 insertions(+), 39 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 82e24d7..3bf4484 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4478,7 +4478,6 @@ struct mlx5_hlist_entry *
 {
 	const struct rte_flow_action_sample *sample;
 	int actions_n = 0;
-	int jump_flag = 0;
 	uint32_t ratio = 0;
 	int sub_type = 0;
 	int flag = 0;
@@ -4493,8 +4492,6 @@ struct mlx5_hlist_entry *
 		if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE ||
 		    actions->type == RTE_FLOW_ACTION_TYPE_RSS)
 			*qrss_action_pos = actions_n;
-		if (actions->type == RTE_FLOW_ACTION_TYPE_JUMP)
-			jump_flag = 1;
 		if (actions->type == RTE_FLOW_ACTION_TYPE_SAMPLE) {
 			sample = actions->conf;
 			ratio = sample->ratio;
@@ -4505,10 +4502,10 @@ struct mlx5_hlist_entry *
 	}
 	if (flag && action == RTE_FLOW_ACTION_TYPE_SAMPLE && attr->transfer) {
 		if (ratio == 1) {
-			/* JUMP Action not support for Mirroring;
-			 * Mirroring support multi-destination;
+			/* FDB mirroring uses the destination array to implement
+			 * instead of FLOW_SAMPLER object.
 			 */
-			if (!jump_flag && sub_type != RTE_FLOW_ACTION_TYPE_END)
+			if (sub_type != RTE_FLOW_ACTION_TYPE_END)
 				flag = 0;
 		}
 	}
@@ -4529,8 +4526,8 @@ struct mlx5_hlist_entry *
  *
  * @param dev
  *   Pointer to Ethernet device.
- * @param[in] fdb_tx
- *   FDB egress flow flag.
+ * @param[in] add_tag
+ *   Add extra tag action flag.
  * @param[out] sfx_items
  *   Suffix flow match items (list terminated by the END pattern item).
  * @param[in] actions
@@ -4554,7 +4551,7 @@ struct mlx5_hlist_entry *
  */
 static int
 flow_sample_split_prep(struct rte_eth_dev *dev,
-		       uint32_t fdb_tx,
+		       int add_tag,
 		       struct rte_flow_item sfx_items[],
 		       const struct rte_flow_action actions[],
 		       struct rte_flow_action actions_sfx[],
@@ -4577,7 +4574,11 @@ struct mlx5_hlist_entry *
 					  RTE_FLOW_ERROR_TYPE_ACTION,
 					  NULL, "invalid position of sample "
 					  "action in list");
-	if (!fdb_tx) {
+	/* For CX5, add an extra tag action for NIC-RX and E-Switch ingress.
+	 * For CX6DX and above, metadata registers Cx preserve their value,
+	 * add an extra tag action for NIC-RX and E-Switch ingress and egress.
+	 */
+	if (add_tag) {
 		/* Prepare the prefix tag action. */
 		set_tag = (void *)(actions_pre + actions_n + 1);
 		ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 0, error);
@@ -4628,8 +4629,7 @@ struct mlx5_hlist_entry *
 			memcpy(actions_pre, actions,
 			       sizeof(struct rte_flow_action) * index);
 	}
-	/* Add the extra tag action for NIC-RX and E-Switch ingress. */
-	if (!fdb_tx) {
+	if (add_tag) {
 		actions_pre[index++] =
 			(struct rte_flow_action){
 			.type = (enum rte_flow_action_type)
@@ -5042,6 +5042,7 @@ struct mlx5_hlist_entry *
 	int actions_n = 0;
 	int sample_action_pos;
 	int qrss_action_pos;
+	int add_tag = 0;
 	int ret = 0;
 
 	if (priv->sampler_en)
@@ -5063,16 +5064,21 @@ struct mlx5_hlist_entry *
 						  "sample flow");
 		/* The representor_id is -1 for uplink. */
 		fdb_tx = (attr->transfer && priv->representor_id != -1);
-		if (!fdb_tx)
+		/*
+		 * When reg_c_preserve is set, metadata registers Cx preserve
+		 * their value even through packet duplication.
+		 */
+		add_tag = (!fdb_tx || priv->config.hca_attr.reg_c_preserve);
+		if (add_tag)
 			sfx_items = (struct rte_flow_item *)((char *)sfx_actions
 					+ act_size);
 		pre_actions = sfx_actions + actions_n;
-		tag_id = flow_sample_split_prep(dev, fdb_tx, sfx_items,
+		tag_id = flow_sample_split_prep(dev, add_tag, sfx_items,
 						actions, sfx_actions,
 						pre_actions, actions_n,
 						sample_action_pos,
 						qrss_action_pos, error);
-		if (tag_id < 0 || (!fdb_tx && !tag_id)) {
+		if (tag_id < 0 || (add_tag && !tag_id)) {
 			ret = -rte_errno;
 			goto exit;
 		}
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index d85dd19..0172ee5 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -552,6 +552,7 @@ struct mlx5_flow_sub_actions_list {
 	void *dr_cnt_action;
 	void *dr_port_id_action;
 	void *dr_encap_action;
+	void *dr_jump_action;
 };
 
 /* Sample sub-actions resource list. */
@@ -561,6 +562,7 @@ struct mlx5_flow_sub_actions_idx {
 	uint32_t cnt;
 	uint32_t rix_port_id_action; /**< Index to port ID action resource. */
 	uint32_t rix_encap_decap; /**< Index to encap/decap resource. */
+	uint32_t rix_jump; /**< Index to the jump action resource. */
 };
 
 /* Sample action resource structure. */
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index c317376..4a8154f 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -76,7 +76,7 @@
 
 static int
 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
-				      uint32_t encap_decap_idx);
+				     uint32_t encap_decap_idx);
 
 static int
 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
@@ -84,6 +84,10 @@
 static void
 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss);
 
+static int
+flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
+				  uint32_t rix_jump);
+
 /**
  * Initialize flow attributes structure according to flow items' types.
  *
@@ -3580,7 +3584,7 @@ struct mlx5_cache_entry *
 					    (dev, &res, dev_flow, error);
 }
 
-static int fdb_mirror;
+static int fdb_mirror_limit;
 
 /**
  * Validate the modify-header actions.
@@ -3609,7 +3613,7 @@ struct mlx5_cache_entry *
 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
 					  "can't have encap action before"
 					  " modify action");
-	if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror)
+	if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror_limit)
 		return rte_flow_error_set(error, EINVAL,
 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
 					  "can't support sample action before"
@@ -3945,12 +3949,6 @@ struct mlx5_cache_entry *
 		return rte_flow_error_set(error, ENOTSUP,
 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
 					  "jump with meter not support");
-	if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror)
-		return rte_flow_error_set(error, EINVAL,
-					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
-					  "E-Switch mirroring can't support"
-					  " Sample action and jump action in"
-					  " same flow now");
 	if (!action->conf)
 		return rte_flow_error_set(error, EINVAL,
 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
@@ -4347,8 +4345,8 @@ struct mlx5_hlist_entry *
 	uint16_t queue_index = 0xFFFF;
 	int actions_n = 0;
 	int ret;
-	fdb_mirror = 0;
 
+	fdb_mirror_limit = 0;
 	if (!sample)
 		return rte_flow_error_set(error, EINVAL,
 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
@@ -4465,7 +4463,7 @@ struct mlx5_hlist_entry *
 						  "E-Switch doesn't support "
 						  "any optional action "
 						  "for sampling");
-		fdb_mirror = 1;
+		fdb_mirror_limit = 1;
 		if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE)
 			return rte_flow_error_set(error, ENOTSUP,
 						  RTE_FLOW_ERROR_TYPE_ACTION,
@@ -8685,6 +8683,10 @@ struct mlx5_hlist_entry *
 		flow_dv_counter_free(dev, act_res->cnt);
 		act_res->cnt = 0;
 	}
+	if (act_res->rix_jump) {
+		flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump);
+		act_res->rix_jump = 0;
+	}
 }
 
 int
@@ -8896,6 +8898,7 @@ struct mlx5_cache_entry *
 	struct mlx5dv_dr_domain *domain;
 	uint32_t idx = 0, res_idx = 0;
 	struct rte_flow_error *error = ctx->error;
+	uint64_t action_flags;
 
 	/* Register new destination array resource. */
 	cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
@@ -8928,19 +8931,31 @@ struct mlx5_cache_entry *
 		}
 		dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST;
 		sample_act = &resource->sample_act[idx];
-		if (sample_act->action_flags == MLX5_FLOW_ACTION_QUEUE) {
+		action_flags = sample_act->action_flags;
+		switch (action_flags) {
+		case MLX5_FLOW_ACTION_QUEUE:
 			dest_attr[idx]->dest = sample_act->dr_queue_action;
-		} else if (sample_act->action_flags ==
-			  (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP)) {
+			break;
+		case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP):
 			dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT;
 			dest_attr[idx]->dest_reformat = &dest_reformat[idx];
 			dest_attr[idx]->dest_reformat->reformat =
 					sample_act->dr_encap_action;
 			dest_attr[idx]->dest_reformat->dest =
 					sample_act->dr_port_id_action;
-		} else if (sample_act->action_flags ==
-			   MLX5_FLOW_ACTION_PORT_ID) {
+			break;
+		case MLX5_FLOW_ACTION_PORT_ID:
 			dest_attr[idx]->dest = sample_act->dr_port_id_action;
+			break;
+		case MLX5_FLOW_ACTION_JUMP:
+			dest_attr[idx]->dest = sample_act->dr_jump_action;
+			break;
+		default:
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ACTION,
+					   NULL,
+					   "unsupported actions type");
+			goto error;
 		}
 	}
 	/* create a dest array actioin */
@@ -8976,6 +8991,10 @@ struct mlx5_cache_entry *
 			!flow_dv_port_id_action_resource_release(dev,
 				act_res->rix_port_id_action))
 			act_res->rix_port_id_action = 0;
+		if (act_res->rix_jump &&
+			!flow_dv_jump_tbl_resource_release(dev,
+				act_res->rix_jump))
+			act_res->rix_jump = 0;
 		if (dest_attr[idx])
 			mlx5_free(dest_attr[idx]);
 	}
@@ -9312,6 +9331,14 @@ struct mlx5_cache_entry *
 			sample_act->dr_port_id_action =
 				dev_flow->dv.port_id_action->action;
 		}
+		if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) {
+			normal_idx++;
+			mdest_res->sample_idx[dest_index].rix_jump =
+				dev_flow->handle->rix_jump;
+			sample_act->dr_jump_action =
+				dev_flow->dv.jump->action;
+			dev_flow->handle->rix_jump = 0;
+		}
 		sample_act->actions_num = normal_idx;
 		/* update sample action resource into first index of array */
 		mdest_res->ft_type = res->ft_type;
@@ -10070,6 +10097,8 @@ struct mlx5_cache_entry *
 					dev_flow->dv.jump->action;
 			action_flags |= MLX5_FLOW_ACTION_JUMP;
 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP;
+			sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP;
+			num_of_dest++;
 			break;
 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
@@ -10292,7 +10321,8 @@ struct mlx5_cache_entry *
 	 * So need remove the original these actions in the flow and only
 	 * use the sample action instead of.
 	 */
-	if (num_of_dest > 1 && sample_act->dr_port_id_action) {
+	if (num_of_dest > 1 &&
+	    (sample_act->dr_port_id_action || sample_act->dr_jump_action)) {
 		int i;
 		void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
 
@@ -10302,6 +10332,9 @@ struct mlx5_cache_entry *
 				dev_flow->dv.actions[i]) ||
 				(sample_act->dr_port_id_action &&
 				sample_act->dr_port_id_action ==
+				dev_flow->dv.actions[i]) ||
+				(sample_act->dr_jump_action &&
+				sample_act->dr_jump_action ==
 				dev_flow->dv.actions[i]))
 				continue;
 			temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];
@@ -10923,21 +10956,21 @@ struct mlx5_cache_entry *
  *
  * @param dev
  *   Pointer to Ethernet device.
- * @param handle
- *   Pointer to mlx5_flow_handle.
+ * @param rix_jump
+ *   Index to the jump action resource.
  *
  * @return
  *   1 while a reference on it exists, 0 when freed.
  */
 static int
 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
-				  struct mlx5_flow_handle *handle)
+				  uint32_t rix_jump)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_tbl_data_entry *tbl_data;
 
 	tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP],
-			     handle->rix_jump);
+				  rix_jump);
 	if (!tbl_data)
 		return 0;
 	return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl);
@@ -11091,7 +11124,7 @@ struct mlx5_cache_entry *
 		mlx5_hrxq_release(dev, handle->rix_hrxq);
 		break;
 	case MLX5_FLOW_FATE_JUMP:
-		flow_dv_jump_tbl_resource_release(dev, handle);
+		flow_dv_jump_tbl_resource_release(dev, handle->rix_jump);
 		break;
 	case MLX5_FLOW_FATE_PORT_ID:
 		flow_dv_port_id_action_resource_release(dev,
@@ -11190,8 +11223,8 @@ struct mlx5_cache_entry *
  *
  * @param dev
  *   Pointer to Ethernet device.
- * @param handle
- *   Pointer to mlx5_flow_handle.
+ * @param port_id
+ *   Index to port ID action resource.
  *
  * @return
  *   1 while a reference on it exists, 0 when freed.
-- 
1.8.3.1



More information about the dev mailing list