[v3,02/11] net/mlx5: add flow prepare function
diff mbox series

Message ID 20180924231721.15799-3-yskoh@mellanox.com
State Accepted, archived
Delegated to: Thomas Monjalon
Headers show
Series
  • net/mlx5: add Direct Verbs flow driver support
Related show

Checks

Context Check Description
ci/Intel-compilation success Compilation OK

Commit Message

Yongseok Koh Sept. 24, 2018, 11:17 p.m. UTC
From: Ori Kam <orika@mellanox.com>

In current implementation the calculation of the flow size is done
during the validation stage, and the same function is also used to
translate the input parameters into verbs spec. This is hard to maintain
and error prone. Another issue is that dev-flows (flows that are created
implicitly in order to support the requested flow for example when the
user request RSS on UDP 2 rules need to be created one for IPv4 and one
for IPv6). In current implementation the dev-flows are created on the same
memory allocation. This will be harder to implement in future drivers.

The commits extract the calculation and creation of the dev-flow from
the translation part (the part that converts the parameters into the
format required by the driver). This results in that the prepare
function only function is to allocate the dev-flow.

Signed-off-by: Ori Kam <orika@mellanox.com>
Acked-by: Yongseok Koh <yskoh@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.c | 269 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 263 insertions(+), 6 deletions(-)

Patch
diff mbox series

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 799064c0c..166fee555 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -292,6 +292,15 @@  struct mlx5_flow_verbs {
 	uint64_t hash_fields; /**< Verbs hash Rx queue hash fields. */
 };
 
+/** Device flow structure. */
+struct mlx5_flow {
+	LIST_ENTRY(mlx5_flow) next;
+	struct rte_flow *flow; /**< Pointer to the main flow. */
+	union {
+		struct mlx5_flow_verbs verbs; /**< Holds the verbs dev-flow. */
+	};
+};
+
 /* Counters information. */
 struct mlx5_flow_counter {
 	LIST_ENTRY(mlx5_flow_counter) next; /**< Pointer to the next counter. */
@@ -321,6 +330,8 @@  struct rte_flow {
 	uint8_t key[MLX5_RSS_HASH_KEY_LEN]; /**< RSS hash key. */
 	uint16_t (*queue)[]; /**< Destination queues to redirect traffic to. */
 	void *nl_flow; /**< Netlink flow buffer if relevant. */
+	LIST_HEAD(dev_flows, mlx5_flow) dev_flows;
+	/**< Device flows that are part of the flow. */
 };
 
 static const struct rte_flow_ops mlx5_flow_ops = {
@@ -2322,7 +2333,7 @@  mlx5_flow_rxq_flags_clear(struct rte_eth_dev *dev)
  *   Pointer to error structure.
  *
  * @return
- *   0 on success, a negative errno value otherwise and rte_ernno is set.
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
 static int
 mlx5_flow_validate_action_flag(uint64_t action_flags,
@@ -2425,7 +2436,6 @@  mlx5_flow_validate_action_drop(uint64_t action_flags,
 }
 
 /*
- *
  * Validate the queue action.
  *
  * @param[in] action
@@ -2469,7 +2479,6 @@  mlx5_flow_validate_action_queue(const struct rte_flow_action *action,
 }
 
 /*
- *
  * Validate the rss action.
  *
  * @param[in] action
@@ -3211,7 +3220,7 @@  mlx5_flow_validate_item_mpls(const struct rte_flow_item *item __rte_unused,
 	if (ret < 0)
 		return ret;
 	return 0;
-#endif /* !HAVE_IBV_DEVICE_MPLS_SUPPORT */
+#endif
 	return rte_flow_error_set(error, ENOTSUP,
 				  RTE_FLOW_ERROR_TYPE_ITEM, item,
 				  "MPLS is not supported by Verbs, please"
@@ -3219,7 +3228,6 @@  mlx5_flow_validate_item_mpls(const struct rte_flow_item *item __rte_unused,
 }
 
 /**
- *
  * Internal validation function.
  *
  * @param[in] dev
@@ -3444,6 +3452,222 @@  mlx5_flow_validate(struct rte_eth_dev *dev,
 }
 
 /**
+ * Calculate the required bytes that are needed for the action part of the verbs
+ * flow, in addtion returns bit-fields with all the detected action, in order to
+ * avoid another interation over the actions.
+ *
+ * @param[in] actions
+ *   Pointer to the list of actions.
+ * @param[out] action_flags
+ *   Pointer to the detected actions.
+ *
+ * @return
+ *   The size of the memory needed for all actions.
+ */
+static int
+mlx5_flow_verbs_get_actions_and_size(const struct rte_flow_action actions[],
+				     uint64_t *action_flags)
+{
+	int size = 0;
+	uint64_t detected_actions = 0;
+
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		switch (actions->type) {
+		case RTE_FLOW_ACTION_TYPE_VOID:
+			break;
+		case RTE_FLOW_ACTION_TYPE_FLAG:
+			size += sizeof(struct ibv_flow_spec_action_tag);
+			detected_actions |= MLX5_ACTION_FLAG;
+			break;
+		case RTE_FLOW_ACTION_TYPE_MARK:
+			size += sizeof(struct ibv_flow_spec_action_tag);
+			detected_actions |= MLX5_ACTION_MARK;
+			break;
+		case RTE_FLOW_ACTION_TYPE_DROP:
+			size += sizeof(struct ibv_flow_spec_action_drop);
+			detected_actions |= MLX5_ACTION_DROP;
+			break;
+		case RTE_FLOW_ACTION_TYPE_QUEUE:
+			detected_actions |= MLX5_ACTION_QUEUE;
+			break;
+		case RTE_FLOW_ACTION_TYPE_RSS:
+			detected_actions |= MLX5_ACTION_RSS;
+			break;
+		case RTE_FLOW_ACTION_TYPE_COUNT:
+#ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
+			size += sizeof(struct ibv_flow_spec_counter_action);
+#endif
+			detected_actions |= MLX5_ACTION_COUNT;
+			break;
+		default:
+			break;
+		}
+	}
+	*action_flags = detected_actions;
+	return size;
+}
+
+/**
+ * Calculate the required bytes that are needed for the item part of the verbs
+ * flow, in addtion returns bit-fields with all the detected action, in order to
+ * avoid another interation over the actions.
+ *
+ * @param[in] actions
+ *   Pointer to the list of items.
+ * @param[in, out] item_flags
+ *   Pointer to the detected items.
+ *
+ * @return
+ *   The size of the memory needed for all items.
+ */
+static int
+mlx5_flow_verbs_get_items_and_size(const struct rte_flow_item items[],
+				   uint64_t *item_flags)
+{
+	int size = 0;
+	uint64_t detected_items = 0;
+	const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);
+
+	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
+		switch (items->type) {
+		case RTE_FLOW_ITEM_TYPE_VOID:
+			break;
+		case RTE_FLOW_ITEM_TYPE_ETH:
+			size += sizeof(struct ibv_flow_spec_eth);
+			detected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
+					MLX5_FLOW_LAYER_OUTER_L2;
+			break;
+		case RTE_FLOW_ITEM_TYPE_VLAN:
+			size += sizeof(struct ibv_flow_spec_eth);
+			detected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
+					MLX5_FLOW_LAYER_OUTER_VLAN;
+			break;
+		case RTE_FLOW_ITEM_TYPE_IPV4:
+			size += sizeof(struct ibv_flow_spec_ipv4_ext);
+			detected_items |= tunnel ?
+					MLX5_FLOW_LAYER_INNER_L3_IPV4 :
+					MLX5_FLOW_LAYER_OUTER_L3_IPV4;
+			break;
+		case RTE_FLOW_ITEM_TYPE_IPV6:
+			size += sizeof(struct ibv_flow_spec_ipv6);
+			detected_items |= tunnel ?
+				MLX5_FLOW_LAYER_INNER_L3_IPV6 :
+				MLX5_FLOW_LAYER_OUTER_L3_IPV6;
+			break;
+		case RTE_FLOW_ITEM_TYPE_UDP:
+			size += sizeof(struct ibv_flow_spec_tcp_udp);
+			detected_items |= tunnel ?
+					MLX5_FLOW_LAYER_INNER_L4_UDP :
+					MLX5_FLOW_LAYER_OUTER_L4_UDP;
+			break;
+		case RTE_FLOW_ITEM_TYPE_TCP:
+			size += sizeof(struct ibv_flow_spec_tcp_udp);
+			detected_items |= tunnel ?
+					MLX5_FLOW_LAYER_INNER_L4_TCP :
+					MLX5_FLOW_LAYER_OUTER_L4_TCP;
+			break;
+		case RTE_FLOW_ITEM_TYPE_VXLAN:
+			size += sizeof(struct ibv_flow_spec_tunnel);
+			detected_items |= MLX5_FLOW_LAYER_VXLAN;
+			break;
+		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
+			size += sizeof(struct ibv_flow_spec_tunnel);
+			detected_items |= MLX5_FLOW_LAYER_VXLAN_GPE;
+			break;
+		case RTE_FLOW_ITEM_TYPE_GRE:
+#ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
+			size += sizeof(struct ibv_flow_spec_gre);
+			detected_items |= MLX5_FLOW_LAYER_GRE;
+#else
+			size += sizeof(struct ibv_flow_spec_tunnel);
+			detected_items |= MLX5_FLOW_LAYER_TUNNEL;
+#endif
+			break;
+		case RTE_FLOW_ITEM_TYPE_MPLS:
+#ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
+			size += sizeof(struct ibv_flow_spec_mpls);
+			detected_items |= MLX5_FLOW_LAYER_MPLS;
+#endif
+			break;
+		default:
+			break;
+		}
+	}
+	*item_flags = detected_items;
+	return size;
+}
+
+/**
+ * Get RSS action from the action list.
+ *
+ * @param[in] actions
+ *   Pointer to the list of actions.
+ *
+ * @return
+ *   Pointer to the RSS action if exist, else return NULL.
+ */
+static const struct rte_flow_action_rss*
+mlx5_flow_get_rss_action(const struct rte_flow_action actions[])
+{
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		switch (actions->type) {
+		case RTE_FLOW_ACTION_TYPE_RSS:
+			return (const struct rte_flow_action_rss *)
+			       actions->conf;
+		default:
+			break;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * Internal preparation function. Allocate mlx5_flow with the required size.
+ * The required size is calculate based on the actions and items. This function
+ * also returns the detected actions and items for later use.
+ *
+ * @param[in] attr
+ *   Pointer to the flow attributes.
+ * @param[in] items
+ *   Pointer to the list of items.
+ * @param[in] actions
+ *   Pointer to the list of actions.
+ * @param[out] item_flags
+ *   Pointer to bit mask of all items detected.
+ * @param[out] action_flags
+ *   Pointer to bit mask of all actions detected.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   Pointer to mlx5_flow object on success, otherwise NULL and rte_errno
+ *   is set.
+ */
+static struct mlx5_flow *
+mlx5_flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused,
+			const struct rte_flow_item items[],
+			const struct rte_flow_action actions[],
+			uint64_t *item_flags,
+			uint64_t *action_flags,
+			struct rte_flow_error *error)
+{
+	uint32_t size = sizeof(struct ibv_flow_attr);
+	struct mlx5_flow *flow;
+
+	size += mlx5_flow_verbs_get_actions_and_size(actions, action_flags);
+	size += mlx5_flow_verbs_get_items_and_size(items, item_flags);
+	flow = rte_calloc(__func__, 1, size, 0);
+	if (!flow) {
+		rte_flow_error_set(error, ENOMEM,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				   NULL,
+				   "not enough memory to create flow");
+		return NULL;
+	}
+	return flow;
+}
+
+/**
  * Remove the flow.
  *
  * @param[in] dev
@@ -3594,12 +3818,46 @@  mlx5_flow_list_create(struct rte_eth_dev *dev,
 		      struct rte_flow_error *error)
 {
 	struct rte_flow *flow = NULL;
+	struct mlx5_flow *dev_flow;
 	size_t size = 0;
+	uint64_t action_flags = 0;
+	uint64_t item_flags = 0;
+	const struct rte_flow_action_rss *rss;
+	union {
+		struct rte_flow_expand_rss buf;
+		uint8_t buffer[2048];
+	} expand_buffer;
+	struct rte_flow_expand_rss *buf = &expand_buffer.buf;
 	int ret;
+	uint32_t i;
 
 	ret = mlx5_flow_validate(dev, attr, items, actions, error);
 	if (ret < 0)
 		return NULL;
+	flow = rte_calloc(__func__, 1, sizeof(*flow), 0);
+	LIST_INIT(&flow->dev_flows);
+	rss = mlx5_flow_get_rss_action(actions);
+	if (rss && rss->types) {
+		unsigned int graph_root;
+
+		graph_root = mlx5_find_graph_root(items, rss->level);
+		ret = rte_flow_expand_rss(buf, sizeof(expand_buffer.buffer),
+					  items, rss->types,
+					  mlx5_support_expansion,
+					  graph_root);
+		assert(ret > 0 &&
+		       (unsigned int)ret < sizeof(expand_buffer.buffer));
+	} else {
+		buf->entries = 1;
+		buf->entry[0].pattern = (void *)(uintptr_t)items;
+	}
+	for (i = 0; i < buf->entries; ++i) {
+		dev_flow = mlx5_flow_verbs_prepare(attr, buf->entry[i].pattern,
+						   actions, &item_flags,
+						   &action_flags, error);
+		dev_flow->flow = flow;
+		LIST_INSERT_HEAD(&flow->dev_flows, dev_flow, next);
+	}
 	ret = mlx5_flow_merge(dev, flow, size, attr, items, actions, error);
 	if (ret < 0)
 		return NULL;
@@ -4091,7 +4349,6 @@  mlx5_fdir_filter_convert(struct rte_eth_dev *dev,
 			.dst_addr = input->flow.ip4_flow.dst_ip,
 			.time_to_live = input->flow.ip4_flow.ttl,
 			.type_of_service = input->flow.ip4_flow.tos,
-			.next_proto_id = input->flow.ip4_flow.proto,
 		};
 		attributes->l3_mask.ipv4.hdr = (struct ipv4_hdr){
 			.src_addr = mask->ipv4_mask.src_ip,