Thread (94 messages) 94 messages, 4 authors, 2018-11-04
STALE2774d

[PATCH v8 6/7] net/mlx5: add raw data encap decap to Direct Verbs

From: Dekel Peled <hidden>
Date: 2018-11-01 09:41:10
Subsystem: networking drivers, the rest · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

This patch implements the encap and decap actions, using raw data,
in DV flow for MLX5 PMD.

Signed-off-by: Dekel Peled <redacted>
---
 drivers/net/mlx5/mlx5_flow.h    |  12 +-
 drivers/net/mlx5/mlx5_flow_dv.c | 246 +++++++++++++++++++++++++++++++++++++---
 2 files changed, 241 insertions(+), 17 deletions(-)
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 104a1e6..908123f 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -96,15 +96,19 @@
 #define MLX5_FLOW_ACTION_VXLAN_DECAP (1u << 23)
 #define MLX5_FLOW_ACTION_NVGRE_ENCAP (1u << 24)
 #define MLX5_FLOW_ACTION_NVGRE_DECAP (1u << 25)
+#define MLX5_FLOW_ACTION_RAW_ENCAP (1u << 26)
+#define MLX5_FLOW_ACTION_RAW_DECAP (1u << 27)
 
 #define MLX5_FLOW_FATE_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)
 
-#define MLX5_FLOW_ENCAP_ACTIONS	\
-	(MLX5_FLOW_ACTION_VXLAN_ENCAP | MLX5_FLOW_ACTION_NVGRE_ENCAP)
+#define MLX5_FLOW_ENCAP_ACTIONS	(MLX5_FLOW_ACTION_VXLAN_ENCAP | \
+				 MLX5_FLOW_ACTION_NVGRE_ENCAP | \
+				 MLX5_FLOW_ACTION_RAW_ENCAP)
 
-#define MLX5_FLOW_DECAP_ACTIONS	\
-	(MLX5_FLOW_ACTION_VXLAN_DECAP | MLX5_FLOW_ACTION_NVGRE_DECAP)
+#define MLX5_FLOW_DECAP_ACTIONS	(MLX5_FLOW_ACTION_VXLAN_DECAP | \
+				 MLX5_FLOW_ACTION_NVGRE_DECAP | \
+				 MLX5_FLOW_ACTION_RAW_DECAP)
 
 #ifndef IPPROTO_MPLS
 #define IPPROTO_MPLS 137
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 6517688..dd99f00 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -178,6 +178,101 @@
 }
 
 /**
+ * Validate the raw encap action.
+ *
+ * @param[in] action_flags
+ *   Holds the actions detected until now.
+ * @param[in] action
+ *   Pointer to the encap action.
+ * @param[in] attr
+ *   Pointer to flow attributes
+ * @param[out] error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_validate_action_raw_encap(uint64_t action_flags,
+				  const struct rte_flow_action *action,
+				  const struct rte_flow_attr *attr,
+				  struct rte_flow_error *error)
+{
+	if (!(action->conf))
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, action,
+					  "configuration cannot be null");
+	if (action_flags & MLX5_FLOW_ACTION_DROP)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "can't drop and encap in same flow");
+	if (action_flags & MLX5_FLOW_ENCAP_ACTIONS)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "can only have a single encap"
+					  " action in a flow");
+	/* encap without preceding decap is not supported for ingress */
+	if (attr->ingress && !(action_flags & MLX5_FLOW_ACTION_RAW_DECAP))
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
+					  NULL,
+					  "encap action not supported for "
+					  "ingress");
+	return 0;
+}
+
+/**
+ * Validate the raw decap action.
+ *
+ * @param[in] action_flags
+ *   Holds the actions detected until now.
+ * @param[in] action
+ *   Pointer to the encap action.
+ * @param[in] attr
+ *   Pointer to flow attributes
+ * @param[out] error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_validate_action_raw_decap(uint64_t action_flags,
+				  const struct rte_flow_action *action,
+				  const struct rte_flow_attr *attr,
+				  struct rte_flow_error *error)
+{
+	if (action_flags & MLX5_FLOW_ACTION_DROP)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "can't drop and decap in same flow");
+	if (action_flags & MLX5_FLOW_ENCAP_ACTIONS)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "can't have encap action before"
+					  " decap action");
+	if (action_flags & MLX5_FLOW_DECAP_ACTIONS)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "can only have a single decap"
+					  " action in a flow");
+	/* decap action is valid on egress only if it is followed by encap */
+	if (attr->egress) {
+		for (; action->type != RTE_FLOW_ACTION_TYPE_END &&
+		       action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP;
+		       action++) {
+		}
+		if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP)
+			return rte_flow_error_set
+					(error, ENOTSUP,
+					 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
+					 NULL, "decap action not supported"
+					 " for egress");
+	}
+	return 0;
+}
+
+/**
  * Get the size of specific rte_flow_item_type
  *
  * @param[in] item_type
@@ -431,23 +526,34 @@
 {
 	struct ibv_flow_action *verbs_action = NULL;
 	const struct rte_flow_item *encap_data;
+	const struct rte_flow_action_raw_encap *raw_encap_data;
 	struct priv *priv = dev->data->dev_private;
 	uint8_t buf[MLX5_ENCAP_MAX_LEN];
+	uint8_t *buf_ptr = buf;
 	size_t size = 0;
 	int convert_result = 0;
 
-	if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
-		encap_data = ((const struct rte_flow_action_vxlan_encap *)
+	if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
+		raw_encap_data =
+			(const struct rte_flow_action_raw_encap *)action->conf;
+		buf_ptr = raw_encap_data->data;
+		size = raw_encap_data->size;
+	} else {
+		if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
+			encap_data =
+				((const struct rte_flow_action_vxlan_encap *)
 						action->conf)->definition;
-	else
-		encap_data = ((const struct rte_flow_action_nvgre_encap *)
+		else
+			encap_data =
+				((const struct rte_flow_action_nvgre_encap *)
 						action->conf)->definition;
-	convert_result = flow_dv_convert_encap_data(encap_data, buf,
-						    &size, error);
-	if (convert_result)
-		return NULL;
+		convert_result = flow_dv_convert_encap_data(encap_data, buf,
+							    &size, error);
+		if (convert_result)
+			return NULL;
+	}
 	verbs_action = mlx5_glue->dv_create_flow_action_packet_reformat
-		(priv->ctx, size, buf,
+		(priv->ctx, size, buf_ptr,
 		 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL,
 		 MLX5DV_FLOW_TABLE_TYPE_NIC_TX);
 	if (!verbs_action)
@@ -485,6 +591,50 @@
 }
 
 /**
+ * Convert raw decap/encap (L3 tunnel) action to DV specification.
+ *
+ * @param[in] dev
+ *   Pointer to rte_eth_dev structure.
+ * @param[in] action
+ *   Pointer to action structure.
+ * @param[in] attr
+ *   Pointer to the flow attributes.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   Pointer to action on success, NULL otherwise and rte_errno is set.
+ */
+static struct ibv_flow_action *
+flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
+				const struct rte_flow_action *action,
+				const struct rte_flow_attr *attr,
+				struct rte_flow_error *error)
+{
+	struct ibv_flow_action *verbs_action = NULL;
+	const struct rte_flow_action_raw_encap *encap_data;
+	struct priv *priv = dev->data->dev_private;
+	enum mlx5dv_flow_action_packet_reformat_type reformat_type;
+	enum mlx5dv_flow_table_type ft_type;
+
+	encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
+	reformat_type = attr->egress ?
+		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL :
+		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
+	ft_type = attr->egress ?
+			MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
+			MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
+	verbs_action = mlx5_glue->dv_create_flow_action_packet_reformat
+				(priv->ctx, encap_data->size,
+				(encap_data->size ? encap_data->data : NULL),
+				reformat_type, ft_type);
+	if (!verbs_action)
+		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
+				   NULL, "cannot create encap action");
+	return verbs_action;
+}
+
+/**
  * Verify the @p attributes will be correctly understood by the NIC and store
  * them in the @p flow if everything is correct.
  *
@@ -739,7 +889,6 @@
 					RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP ?
 					MLX5_FLOW_ACTION_VXLAN_ENCAP :
 					MLX5_FLOW_ACTION_NVGRE_ENCAP;
-
 			++actions_n;
 			break;
 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
@@ -752,7 +901,24 @@
 					RTE_FLOW_ACTION_TYPE_VXLAN_DECAP ?
 					MLX5_FLOW_ACTION_VXLAN_DECAP :
 					MLX5_FLOW_ACTION_NVGRE_DECAP;
-
+			++actions_n;
+			break;
+		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+			ret = flow_dv_validate_action_raw_encap(action_flags,
+								actions, attr,
+								error);
+			if (ret < 0)
+				return ret;
+			action_flags |= MLX5_FLOW_ACTION_RAW_ENCAP;
+			++actions_n;
+			break;
+		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+			ret = flow_dv_validate_action_raw_decap(action_flags,
+								actions, attr,
+								error);
+			if (ret < 0)
+				return ret;
+			action_flags |= MLX5_FLOW_ACTION_RAW_DECAP;
 			++actions_n;
 			break;
 		default:
@@ -1467,6 +1633,8 @@
  *   Flow action to translate.
  * @param[in, out] dev_flow
  *   Pointer to the mlx5_flow.
+ * @param[in] attr
+ *   Pointer to the flow attributes.
  * @param[out] error
  *   Pointer to the error structure.
  *
@@ -1477,12 +1645,14 @@
 flow_dv_create_action(struct rte_eth_dev *dev,
 		      const struct rte_flow_action *action,
 		      struct mlx5_flow *dev_flow,
+		      const struct rte_flow_attr *attr,
 		      struct rte_flow_error *error)
 {
 	const struct rte_flow_action_queue *queue;
 	const struct rte_flow_action_rss *rss;
 	int actions_n = dev_flow->dv.actions_n;
 	struct rte_flow *flow = dev_flow->flow;
+	const struct rte_flow_action *action_ptr = action;
 
 	switch (action->type) {
 	case RTE_FLOW_ACTION_TYPE_VOID:
@@ -1558,6 +1728,56 @@
 				 MLX5_FLOW_ACTION_NVGRE_DECAP;
 		actions_n++;
 		break;
+	case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+		/* Handle encap action with preceding decap */
+		if (flow->actions & MLX5_FLOW_ACTION_RAW_DECAP) {
+			dev_flow->dv.actions[actions_n].type =
+				MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION;
+			dev_flow->dv.actions[actions_n].action =
+					flow_dv_create_action_raw_encap
+								(dev, action,
+								 attr, error);
+			if (!(dev_flow->dv.actions[actions_n].action))
+				return -rte_errno;
+			dev_flow->dv.encap_decap_verbs_action =
+				dev_flow->dv.actions[actions_n].action;
+		} else {
+			/* Handle encap action without preceding decap */
+			dev_flow->dv.actions[actions_n].type =
+				MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION;
+			dev_flow->dv.actions[actions_n].action =
+					flow_dv_create_action_l2_encap
+							(dev, action, error);
+			if (!(dev_flow->dv.actions[actions_n].action))
+				return -rte_errno;
+			dev_flow->dv.encap_decap_verbs_action =
+				dev_flow->dv.actions[actions_n].action;
+		}
+		flow->actions |= MLX5_FLOW_ACTION_RAW_ENCAP;
+		actions_n++;
+		break;
+	case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+		/* Check if this decap action is followed by encap. */
+		for (; action_ptr->type != RTE_FLOW_ACTION_TYPE_END &&
+		       action_ptr->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP;
+		       action_ptr++) {
+		}
+		/* Handle decap action only if it isn't followed by encap */
+		if (action_ptr->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
+			dev_flow->dv.actions[actions_n].type =
+				MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION;
+			dev_flow->dv.actions[actions_n].action =
+					flow_dv_create_action_l2_decap(dev,
+								       error);
+			if (!(dev_flow->dv.actions[actions_n].action))
+				return -rte_errno;
+			dev_flow->dv.encap_decap_verbs_action =
+				dev_flow->dv.actions[actions_n].action;
+			actions_n++;
+		}
+		/* If decap is followed by encap, handle it at encap case. */
+		flow->actions |= MLX5_FLOW_ACTION_RAW_DECAP;
+		break;
 	default:
 		break;
 	}
@@ -1700,7 +1920,7 @@
 		  struct mlx5_flow *dev_flow,
 		  const struct rte_flow_attr *attr,
 		  const struct rte_flow_item items[],
-		  const struct rte_flow_action actions[] __rte_unused,
+		  const struct rte_flow_action actions[],
 		  struct rte_flow_error *error)
 {
 	struct priv *priv = dev->data->dev_private;
@@ -1730,7 +1950,7 @@
 	if (flow_dv_matcher_register(dev, &matcher, dev_flow, error))
 		return -rte_errno;
 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++)
-		if (flow_dv_create_action(dev, actions, dev_flow, error))
+		if (flow_dv_create_action(dev, actions, dev_flow, attr, error))
 			return -rte_errno;
 	return 0;
 }
-- 
1.8.3.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help