xref: /dpdk/drivers/net/mlx5/mlx5_flow_verbs.c (revision 89b5642d0d45c22c0ceab57efe3fab3b49ff4324)
184c406e7SOri Kam /* SPDX-License-Identifier: BSD-3-Clause
284c406e7SOri Kam  * Copyright 2018 Mellanox Technologies, Ltd
384c406e7SOri Kam  */
484c406e7SOri Kam 
584c406e7SOri Kam #include <netinet/in.h>
684c406e7SOri Kam #include <sys/queue.h>
784c406e7SOri Kam #include <stdalign.h>
884c406e7SOri Kam #include <stdint.h>
984c406e7SOri Kam #include <string.h>
1084c406e7SOri Kam 
1184c406e7SOri Kam #include <rte_common.h>
1284c406e7SOri Kam #include <rte_ether.h>
13df96fd0dSBruce Richardson #include <ethdev_driver.h>
1484c406e7SOri Kam #include <rte_flow.h>
1584c406e7SOri Kam #include <rte_flow_driver.h>
1684c406e7SOri Kam #include <rte_malloc.h>
1784c406e7SOri Kam #include <rte_ip.h>
1884c406e7SOri Kam 
197b4f1e6bSMatan Azrad #include <mlx5_glue.h>
207b4f1e6bSMatan Azrad #include <mlx5_prm.h>
2183c2047cSSuanming Mou #include <mlx5_malloc.h>
227b4f1e6bSMatan Azrad 
2384c406e7SOri Kam #include "mlx5_defs.h"
247b4f1e6bSMatan Azrad #include "mlx5.h"
2584c406e7SOri Kam #include "mlx5_flow.h"
26151cbe3aSMichael Baum #include "mlx5_rx.h"
2772185352SMaayan Kashani #include "mlx5_flow_os.h"
2884c406e7SOri Kam 
294a78c88eSYongseok Koh #define VERBS_SPEC_INNER(item_flags) \
304a78c88eSYongseok Koh 	(!!((item_flags) & MLX5_FLOW_LAYER_TUNNEL) ? IBV_FLOW_SPEC_INNER : 0)
314a78c88eSYongseok Koh 
32f1ae0b35SOphir Munk /* Verbs specification header. */
33f1ae0b35SOphir Munk struct ibv_spec_header {
34f1ae0b35SOphir Munk 	enum ibv_flow_spec_type type;
35f1ae0b35SOphir Munk 	uint16_t size;
36f1ae0b35SOphir Munk };
37f1ae0b35SOphir Munk 
383eca5f8aSOphir Munk /**
393eca5f8aSOphir Munk  * Discover the maximum number of priority available.
403eca5f8aSOphir Munk  *
413eca5f8aSOphir Munk  * @param[in] dev
423eca5f8aSOphir Munk  *   Pointer to the Ethernet device structure.
43c5042f93SDmitry Kozlyuk  * @param[in] vprio
44c5042f93SDmitry Kozlyuk  *   Expected result variants.
45c5042f93SDmitry Kozlyuk  * @param[in] vprio_n
46c5042f93SDmitry Kozlyuk  *   Number of entries in @p vprio array.
473eca5f8aSOphir Munk  * @return
48c5042f93SDmitry Kozlyuk  *   Number of supported flow priority on success, a negative errno
493eca5f8aSOphir Munk  *   value otherwise and rte_errno is set.
503eca5f8aSOphir Munk  */
51c5042f93SDmitry Kozlyuk static int
52c5042f93SDmitry Kozlyuk flow_verbs_discover_priorities(struct rte_eth_dev *dev,
53c5042f93SDmitry Kozlyuk 			       const uint16_t *vprio, int vprio_n)
543eca5f8aSOphir Munk {
553eca5f8aSOphir Munk 	struct mlx5_priv *priv = dev->data->dev_private;
563eca5f8aSOphir Munk 	struct {
573eca5f8aSOphir Munk 		struct ibv_flow_attr attr;
583eca5f8aSOphir Munk 		struct ibv_flow_spec_eth eth;
593eca5f8aSOphir Munk 		struct ibv_flow_spec_action_drop drop;
603eca5f8aSOphir Munk 	} flow_attr = {
613eca5f8aSOphir Munk 		.attr = {
623eca5f8aSOphir Munk 			.num_of_specs = 2,
633eca5f8aSOphir Munk 			.port = (uint8_t)priv->dev_port,
643eca5f8aSOphir Munk 		},
653eca5f8aSOphir Munk 		.eth = {
663eca5f8aSOphir Munk 			.type = IBV_FLOW_SPEC_ETH,
673eca5f8aSOphir Munk 			.size = sizeof(struct ibv_flow_spec_eth),
683eca5f8aSOphir Munk 		},
693eca5f8aSOphir Munk 		.drop = {
703eca5f8aSOphir Munk 			.size = sizeof(struct ibv_flow_spec_action_drop),
713eca5f8aSOphir Munk 			.type = IBV_FLOW_SPEC_ACTION_DROP,
723eca5f8aSOphir Munk 		},
733eca5f8aSOphir Munk 	};
743eca5f8aSOphir Munk 	struct ibv_flow *flow;
7565b3cd0dSSuanming Mou 	struct mlx5_hrxq *drop = priv->drop_queue.hrxq;
763eca5f8aSOphir Munk 	int i;
773eca5f8aSOphir Munk 	int priority = 0;
783eca5f8aSOphir Munk 
791d47e933SXueming Li #if defined(HAVE_MLX5DV_DR_DEVX_PORT) || defined(HAVE_MLX5DV_DR_DEVX_PORT_V35)
801d47e933SXueming Li 	/* If DevX supported, driver must support 16 verbs flow priorities. */
81c5042f93SDmitry Kozlyuk 	priority = 16;
821d47e933SXueming Li 	goto out;
831d47e933SXueming Li #endif
8465b3cd0dSSuanming Mou 	if (!drop->qp) {
853eca5f8aSOphir Munk 		rte_errno = ENOTSUP;
863eca5f8aSOphir Munk 		return -rte_errno;
873eca5f8aSOphir Munk 	}
88c5042f93SDmitry Kozlyuk 	for (i = 0; i != vprio_n; i++) {
893eca5f8aSOphir Munk 		flow_attr.attr.priority = vprio[i] - 1;
903eca5f8aSOphir Munk 		flow = mlx5_glue->create_flow(drop->qp, &flow_attr.attr);
913eca5f8aSOphir Munk 		if (!flow)
923eca5f8aSOphir Munk 			break;
933eca5f8aSOphir Munk 		claim_zero(mlx5_glue->destroy_flow(flow));
943eca5f8aSOphir Munk 		priority = vprio[i];
953eca5f8aSOphir Munk 	}
961d47e933SXueming Li #if defined(HAVE_MLX5DV_DR_DEVX_PORT) || defined(HAVE_MLX5DV_DR_DEVX_PORT_V35)
971d47e933SXueming Li out:
981d47e933SXueming Li #endif
995f8ae44dSDong Zhou 	DRV_LOG(INFO, "port %u supported flow priorities:"
1005f8ae44dSDong Zhou 		" 0-%d for ingress or egress root table,"
1015f8ae44dSDong Zhou 		" 0-%d for non-root table or transfer root table.",
1025f8ae44dSDong Zhou 		dev->data->port_id, priority - 2,
1035f8ae44dSDong Zhou 		MLX5_NON_ROOT_FLOW_MAX_PRIO - 1);
1043eca5f8aSOphir Munk 	return priority;
1053eca5f8aSOphir Munk }
1063eca5f8aSOphir Munk 
1073eca5f8aSOphir Munk /**
108c3d3b140SSuanming Mou  * Get Verbs flow counter by index.
109c3d3b140SSuanming Mou  *
110c3d3b140SSuanming Mou  * @param[in] dev
111c3d3b140SSuanming Mou  *   Pointer to the Ethernet device structure.
112c3d3b140SSuanming Mou  * @param[in] idx
113c3d3b140SSuanming Mou  *   mlx5 flow counter index in the container.
114c3d3b140SSuanming Mou  * @param[out] ppool
115c3d3b140SSuanming Mou  *   mlx5 flow counter pool in the container,
116c3d3b140SSuanming Mou  *
117c3d3b140SSuanming Mou  * @return
118c3d3b140SSuanming Mou  *   A pointer to the counter, NULL otherwise.
119c3d3b140SSuanming Mou  */
120c3d3b140SSuanming Mou static struct mlx5_flow_counter *
121c3d3b140SSuanming Mou flow_verbs_counter_get_by_idx(struct rte_eth_dev *dev,
122c3d3b140SSuanming Mou 			      uint32_t idx,
123c3d3b140SSuanming Mou 			      struct mlx5_flow_counter_pool **ppool)
124c3d3b140SSuanming Mou {
125c3d3b140SSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
12604a4de75SMichael Baum 	struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng;
127c3d3b140SSuanming Mou 	struct mlx5_flow_counter_pool *pool;
128c3d3b140SSuanming Mou 
129df051a3eSSuanming Mou 	idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
130994829e6SSuanming Mou 	pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
131c3d3b140SSuanming Mou 	MLX5_ASSERT(pool);
132c3d3b140SSuanming Mou 	if (ppool)
133c3d3b140SSuanming Mou 		*ppool = pool;
1348d93c830SDong Zhou 	return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
135c3d3b140SSuanming Mou }
136c3d3b140SSuanming Mou 
137c3d3b140SSuanming Mou /**
138db48f9dbSViacheslav Ovsiienko  * Create Verbs flow counter with Verbs library.
139db48f9dbSViacheslav Ovsiienko  *
140db48f9dbSViacheslav Ovsiienko  * @param[in] dev
141db48f9dbSViacheslav Ovsiienko  *   Pointer to the Ethernet device structure.
142db48f9dbSViacheslav Ovsiienko  * @param[in, out] counter
143db48f9dbSViacheslav Ovsiienko  *   mlx5 flow counter object, contains the counter id,
144db48f9dbSViacheslav Ovsiienko  *   handle of created Verbs flow counter is returned
145db48f9dbSViacheslav Ovsiienko  *   in cs field (if counters are supported).
146db48f9dbSViacheslav Ovsiienko  *
147db48f9dbSViacheslav Ovsiienko  * @return
148db48f9dbSViacheslav Ovsiienko  *   0 On success else a negative errno value is returned
149db48f9dbSViacheslav Ovsiienko  *   and rte_errno is set.
150db48f9dbSViacheslav Ovsiienko  */
151db48f9dbSViacheslav Ovsiienko static int
152db48f9dbSViacheslav Ovsiienko flow_verbs_counter_create(struct rte_eth_dev *dev,
1532b5b1aebSSuanming Mou 			  struct mlx5_flow_counter *counter)
154db48f9dbSViacheslav Ovsiienko {
155db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
156dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
157ca1418ceSMichael Baum 	struct ibv_context *ctx = priv->sh->cdev->ctx;
158db48f9dbSViacheslav Ovsiienko 	struct ibv_counter_set_init_attr init = {
1592b5b1aebSSuanming Mou 			 .counter_set_id = counter->shared_info.id};
160db48f9dbSViacheslav Ovsiienko 
1612b5b1aebSSuanming Mou 	counter->dcs_when_free = mlx5_glue->create_counter_set(ctx, &init);
1622b5b1aebSSuanming Mou 	if (!counter->dcs_when_free) {
163db48f9dbSViacheslav Ovsiienko 		rte_errno = ENOTSUP;
164db48f9dbSViacheslav Ovsiienko 		return -ENOTSUP;
165db48f9dbSViacheslav Ovsiienko 	}
166db48f9dbSViacheslav Ovsiienko 	return 0;
167db48f9dbSViacheslav Ovsiienko #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
168dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
169ca1418ceSMichael Baum 	struct ibv_context *ctx = priv->sh->cdev->ctx;
170db48f9dbSViacheslav Ovsiienko 	struct ibv_counters_init_attr init = {0};
1710c15f3c0SAli Alnubani 	struct ibv_counter_attach_attr attach;
172db48f9dbSViacheslav Ovsiienko 	int ret;
173db48f9dbSViacheslav Ovsiienko 
1740c15f3c0SAli Alnubani 	memset(&attach, 0, sizeof(attach));
1752b5b1aebSSuanming Mou 	counter->dcs_when_free = mlx5_glue->create_counters(ctx, &init);
1762b5b1aebSSuanming Mou 	if (!counter->dcs_when_free) {
177db48f9dbSViacheslav Ovsiienko 		rte_errno = ENOTSUP;
178db48f9dbSViacheslav Ovsiienko 		return -ENOTSUP;
179db48f9dbSViacheslav Ovsiienko 	}
180db48f9dbSViacheslav Ovsiienko 	attach.counter_desc = IBV_COUNTER_PACKETS;
181db48f9dbSViacheslav Ovsiienko 	attach.index = 0;
1822b5b1aebSSuanming Mou 	ret = mlx5_glue->attach_counters(counter->dcs_when_free, &attach, NULL);
183db48f9dbSViacheslav Ovsiienko 	if (!ret) {
184db48f9dbSViacheslav Ovsiienko 		attach.counter_desc = IBV_COUNTER_BYTES;
185db48f9dbSViacheslav Ovsiienko 		attach.index = 1;
186db48f9dbSViacheslav Ovsiienko 		ret = mlx5_glue->attach_counters
1872b5b1aebSSuanming Mou 					(counter->dcs_when_free, &attach, NULL);
188db48f9dbSViacheslav Ovsiienko 	}
189db48f9dbSViacheslav Ovsiienko 	if (ret) {
1902b5b1aebSSuanming Mou 		claim_zero(mlx5_glue->destroy_counters(counter->dcs_when_free));
1912b5b1aebSSuanming Mou 		counter->dcs_when_free = NULL;
192db48f9dbSViacheslav Ovsiienko 		rte_errno = ret;
193db48f9dbSViacheslav Ovsiienko 		return -ret;
194db48f9dbSViacheslav Ovsiienko 	}
195db48f9dbSViacheslav Ovsiienko 	return 0;
196db48f9dbSViacheslav Ovsiienko #else
197db48f9dbSViacheslav Ovsiienko 	(void)dev;
198db48f9dbSViacheslav Ovsiienko 	(void)counter;
199db48f9dbSViacheslav Ovsiienko 	rte_errno = ENOTSUP;
200db48f9dbSViacheslav Ovsiienko 	return -ENOTSUP;
201db48f9dbSViacheslav Ovsiienko #endif
202db48f9dbSViacheslav Ovsiienko }
203db48f9dbSViacheslav Ovsiienko 
204db48f9dbSViacheslav Ovsiienko /**
20584c406e7SOri Kam  * Get a flow counter.
20684c406e7SOri Kam  *
20784c406e7SOri Kam  * @param[in] dev
20884c406e7SOri Kam  *   Pointer to the Ethernet device structure.
20984c406e7SOri Kam  * @param[in] id
21084c406e7SOri Kam  *   Counter identifier.
21184c406e7SOri Kam  *
21284c406e7SOri Kam  * @return
213956d5c74SSuanming Mou  *   Index to the counter, 0 otherwise and rte_errno is set.
21484c406e7SOri Kam  */
215956d5c74SSuanming Mou static uint32_t
21692ef4b8fSAndrew Rybchenko flow_verbs_counter_new(struct rte_eth_dev *dev, uint32_t id __rte_unused)
21784c406e7SOri Kam {
218dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
21904a4de75SMichael Baum 	struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng;
220c3d3b140SSuanming Mou 	struct mlx5_flow_counter_pool *pool = NULL;
221c3d3b140SSuanming Mou 	struct mlx5_flow_counter *cnt = NULL;
2223aa27915SSuanming Mou 	uint32_t n_valid = cmng->n_valid;
223df051a3eSSuanming Mou 	uint32_t pool_idx, cnt_idx;
224c3d3b140SSuanming Mou 	uint32_t i;
225db48f9dbSViacheslav Ovsiienko 	int ret;
22684c406e7SOri Kam 
227c3d3b140SSuanming Mou 	for (pool_idx = 0; pool_idx < n_valid; ++pool_idx) {
228994829e6SSuanming Mou 		pool = cmng->pools[pool_idx];
229c3d3b140SSuanming Mou 		if (!pool)
230c3d3b140SSuanming Mou 			continue;
231ac79183dSSuanming Mou 		cnt = TAILQ_FIRST(&pool->counters[0]);
232c3d3b140SSuanming Mou 		if (cnt)
233c3d3b140SSuanming Mou 			break;
234c3d3b140SSuanming Mou 	}
23584c406e7SOri Kam 	if (!cnt) {
236c3d3b140SSuanming Mou 		uint32_t size;
237c3d3b140SSuanming Mou 
238a94e89e4SMichael Baum 		if (n_valid == MLX5_COUNTER_POOLS_MAX_NUM) {
239a94e89e4SMichael Baum 			DRV_LOG(ERR, "All counter is in used, try again later.");
240a94e89e4SMichael Baum 			rte_errno = EAGAIN;
241956d5c74SSuanming Mou 			return 0;
242c3d3b140SSuanming Mou 		}
243c3d3b140SSuanming Mou 		/* Allocate memory for new pool */
2442b5b1aebSSuanming Mou 		size = sizeof(*pool) + sizeof(*cnt) * MLX5_COUNTERS_PER_POOL;
24583c2047cSSuanming Mou 		pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
246c3d3b140SSuanming Mou 		if (!pool)
247956d5c74SSuanming Mou 			return 0;
248c3d3b140SSuanming Mou 		for (i = 0; i < MLX5_COUNTERS_PER_POOL; ++i) {
2498d93c830SDong Zhou 			cnt = MLX5_POOL_GET_CNT(pool, i);
250ac79183dSSuanming Mou 			TAILQ_INSERT_HEAD(&pool->counters[0], cnt, next);
251c3d3b140SSuanming Mou 		}
2528d93c830SDong Zhou 		cnt = MLX5_POOL_GET_CNT(pool, 0);
253994829e6SSuanming Mou 		cmng->pools[n_valid] = pool;
254c3d3b140SSuanming Mou 		pool_idx = n_valid;
2553aa27915SSuanming Mou 		cmng->n_valid++;
25684c406e7SOri Kam 	}
2572b5b1aebSSuanming Mou 	TAILQ_REMOVE(&pool->counters[0], cnt, next);
2588d93c830SDong Zhou 	i = MLX5_CNT_ARRAY_IDX(pool, cnt);
259df051a3eSSuanming Mou 	cnt_idx = MLX5_MAKE_CNT_IDX(pool_idx, i);
2602b5b1aebSSuanming Mou 	/* Create counter with Verbs. */
2612b5b1aebSSuanming Mou 	ret = flow_verbs_counter_create(dev, cnt);
2622b5b1aebSSuanming Mou 	if (!ret) {
2632b5b1aebSSuanming Mou 		cnt->dcs_when_active = cnt->dcs_when_free;
264db48f9dbSViacheslav Ovsiienko 		cnt->hits = 0;
265db48f9dbSViacheslav Ovsiienko 		cnt->bytes = 0;
266df051a3eSSuanming Mou 		return cnt_idx;
267db48f9dbSViacheslav Ovsiienko 	}
2682b5b1aebSSuanming Mou 	TAILQ_INSERT_HEAD(&pool->counters[0], cnt, next);
269db48f9dbSViacheslav Ovsiienko 	/* Some error occurred in Verbs library. */
270db48f9dbSViacheslav Ovsiienko 	rte_errno = -ret;
271956d5c74SSuanming Mou 	return 0;
27284c406e7SOri Kam }
27384c406e7SOri Kam 
27484c406e7SOri Kam /**
27584c406e7SOri Kam  * Release a flow counter.
27684c406e7SOri Kam  *
2775382d28cSMatan Azrad  * @param[in] dev
2785382d28cSMatan Azrad  *   Pointer to the Ethernet device structure.
27984c406e7SOri Kam  * @param[in] counter
280956d5c74SSuanming Mou  *   Index to the counter handler.
28184c406e7SOri Kam  */
28284c406e7SOri Kam static void
283956d5c74SSuanming Mou flow_verbs_counter_release(struct rte_eth_dev *dev, uint32_t counter)
28484c406e7SOri Kam {
285c3d3b140SSuanming Mou 	struct mlx5_flow_counter_pool *pool;
286c3d3b140SSuanming Mou 	struct mlx5_flow_counter *cnt;
2875382d28cSMatan Azrad 
288df051a3eSSuanming Mou 	cnt = flow_verbs_counter_get_by_idx(dev, counter, &pool);
289db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
2902b5b1aebSSuanming Mou 	claim_zero(mlx5_glue->destroy_counter_set
2912b5b1aebSSuanming Mou 			((struct ibv_counter_set *)cnt->dcs_when_active));
292db48f9dbSViacheslav Ovsiienko #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
2932b5b1aebSSuanming Mou 	claim_zero(mlx5_glue->destroy_counters
2942b5b1aebSSuanming Mou 				((struct ibv_counters *)cnt->dcs_when_active));
295db48f9dbSViacheslav Ovsiienko #endif
296ac79183dSSuanming Mou 	TAILQ_INSERT_HEAD(&pool->counters[0], cnt, next);
29784c406e7SOri Kam }
29884c406e7SOri Kam 
29984c406e7SOri Kam /**
30006629d86SViacheslav Ovsiienko  * Query a flow counter via Verbs library call.
30106629d86SViacheslav Ovsiienko  *
30206629d86SViacheslav Ovsiienko  * @see rte_flow_query()
30306629d86SViacheslav Ovsiienko  * @see rte_flow_ops
30406629d86SViacheslav Ovsiienko  */
30506629d86SViacheslav Ovsiienko static int
30606629d86SViacheslav Ovsiienko flow_verbs_counter_query(struct rte_eth_dev *dev __rte_unused,
307db48f9dbSViacheslav Ovsiienko 			 struct rte_flow *flow, void *data,
30806629d86SViacheslav Ovsiienko 			 struct rte_flow_error *error)
30906629d86SViacheslav Ovsiienko {
310db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
311db48f9dbSViacheslav Ovsiienko 	defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
312956d5c74SSuanming Mou 	if (flow->counter) {
313826b8a87SSuanming Mou 		struct mlx5_flow_counter_pool *pool;
314c3d3b140SSuanming Mou 		struct mlx5_flow_counter *cnt = flow_verbs_counter_get_by_idx
315826b8a87SSuanming Mou 						(dev, flow->counter, &pool);
31606629d86SViacheslav Ovsiienko 		struct rte_flow_query_count *qc = data;
31706629d86SViacheslav Ovsiienko 		uint64_t counters[2] = {0, 0};
318db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
31906629d86SViacheslav Ovsiienko 		struct ibv_query_counter_set_attr query_cs_attr = {
3202b5b1aebSSuanming Mou 			.dcs_when_free = (struct ibv_counter_set *)
3212b5b1aebSSuanming Mou 						cnt->dcs_when_active,
32206629d86SViacheslav Ovsiienko 			.query_flags = IBV_COUNTER_SET_FORCE_UPDATE,
32306629d86SViacheslav Ovsiienko 		};
32406629d86SViacheslav Ovsiienko 		struct ibv_counter_set_data query_out = {
32506629d86SViacheslav Ovsiienko 			.out = counters,
32606629d86SViacheslav Ovsiienko 			.outlen = 2 * sizeof(uint64_t),
32706629d86SViacheslav Ovsiienko 		};
32806629d86SViacheslav Ovsiienko 		int err = mlx5_glue->query_counter_set(&query_cs_attr,
32906629d86SViacheslav Ovsiienko 						       &query_out);
330db48f9dbSViacheslav Ovsiienko #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
331db48f9dbSViacheslav Ovsiienko 		int err = mlx5_glue->query_counters
3322b5b1aebSSuanming Mou 			((struct ibv_counters *)cnt->dcs_when_active, counters,
333db48f9dbSViacheslav Ovsiienko 				RTE_DIM(counters),
334db48f9dbSViacheslav Ovsiienko 				IBV_READ_COUNTERS_ATTR_PREFER_CACHED);
335db48f9dbSViacheslav Ovsiienko #endif
33606629d86SViacheslav Ovsiienko 		if (err)
33706629d86SViacheslav Ovsiienko 			return rte_flow_error_set
33806629d86SViacheslav Ovsiienko 				(error, err,
33906629d86SViacheslav Ovsiienko 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
34006629d86SViacheslav Ovsiienko 				 NULL,
34106629d86SViacheslav Ovsiienko 				 "cannot read counter");
34206629d86SViacheslav Ovsiienko 		qc->hits_set = 1;
34306629d86SViacheslav Ovsiienko 		qc->bytes_set = 1;
344c3d3b140SSuanming Mou 		qc->hits = counters[0] - cnt->hits;
345c3d3b140SSuanming Mou 		qc->bytes = counters[1] - cnt->bytes;
34606629d86SViacheslav Ovsiienko 		if (qc->reset) {
347c3d3b140SSuanming Mou 			cnt->hits = counters[0];
348c3d3b140SSuanming Mou 			cnt->bytes = counters[1];
34906629d86SViacheslav Ovsiienko 		}
35006629d86SViacheslav Ovsiienko 		return 0;
35106629d86SViacheslav Ovsiienko 	}
35206629d86SViacheslav Ovsiienko 	return rte_flow_error_set(error, EINVAL,
35306629d86SViacheslav Ovsiienko 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
35406629d86SViacheslav Ovsiienko 				  NULL,
35506629d86SViacheslav Ovsiienko 				  "flow does not have counter");
35606629d86SViacheslav Ovsiienko #else
357db48f9dbSViacheslav Ovsiienko 	(void)flow;
358db48f9dbSViacheslav Ovsiienko 	(void)data;
35906629d86SViacheslav Ovsiienko 	return rte_flow_error_set(error, ENOTSUP,
36006629d86SViacheslav Ovsiienko 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
36106629d86SViacheslav Ovsiienko 				  NULL,
36206629d86SViacheslav Ovsiienko 				  "counters are not available");
36306629d86SViacheslav Ovsiienko #endif
36406629d86SViacheslav Ovsiienko }
36506629d86SViacheslav Ovsiienko 
36606629d86SViacheslav Ovsiienko /**
3674a78c88eSYongseok Koh  * Add a verbs item specification into @p verbs.
36884c406e7SOri Kam  *
3694a78c88eSYongseok Koh  * @param[out] verbs
3704a78c88eSYongseok Koh  *   Pointer to verbs structure.
37184c406e7SOri Kam  * @param[in] src
37284c406e7SOri Kam  *   Create specification.
37384c406e7SOri Kam  * @param[in] size
37484c406e7SOri Kam  *   Size in bytes of the specification to copy.
37584c406e7SOri Kam  */
37684c406e7SOri Kam static void
377e7bfa359SBing Zhao flow_verbs_spec_add(struct mlx5_flow_verbs_workspace *verbs,
378c42f44bdSBing Zhao 		    void *src, unsigned int size)
37984c406e7SOri Kam {
38084c406e7SOri Kam 	void *dst;
38184c406e7SOri Kam 
3824a78c88eSYongseok Koh 	if (!verbs)
3834a78c88eSYongseok Koh 		return;
3848e46d4e1SAlexander Kozyrev 	MLX5_ASSERT(verbs->specs);
38584c406e7SOri Kam 	dst = (void *)(verbs->specs + verbs->size);
38684c406e7SOri Kam 	memcpy(dst, src, size);
387e7bfa359SBing Zhao 	++verbs->attr.num_of_specs;
38884c406e7SOri Kam 	verbs->size += size;
38984c406e7SOri Kam }
39084c406e7SOri Kam 
39184c406e7SOri Kam /**
39284c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
39384c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
39484c406e7SOri Kam  * into the flow.
39584c406e7SOri Kam  *
3964a78c88eSYongseok Koh  * @param[in, out] dev_flow
3974a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
39884c406e7SOri Kam  * @param[in] item
39984c406e7SOri Kam  *   Item specification.
40084c406e7SOri Kam  * @param[in] item_flags
4014a78c88eSYongseok Koh  *   Parsed item flags.
40284c406e7SOri Kam  */
40384c406e7SOri Kam static void
4044a78c88eSYongseok Koh flow_verbs_translate_item_eth(struct mlx5_flow *dev_flow,
4054a78c88eSYongseok Koh 			      const struct rte_flow_item *item,
4064a78c88eSYongseok Koh 			      uint64_t item_flags)
40784c406e7SOri Kam {
40884c406e7SOri Kam 	const struct rte_flow_item_eth *spec = item->spec;
40984c406e7SOri Kam 	const struct rte_flow_item_eth *mask = item->mask;
41084c406e7SOri Kam 	const unsigned int size = sizeof(struct ibv_flow_spec_eth);
41184c406e7SOri Kam 	struct ibv_flow_spec_eth eth = {
4124a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags),
41384c406e7SOri Kam 		.size = size,
41484c406e7SOri Kam 	};
41584c406e7SOri Kam 
41684c406e7SOri Kam 	if (!mask)
41784c406e7SOri Kam 		mask = &rte_flow_item_eth_mask;
41884c406e7SOri Kam 	if (spec) {
41984c406e7SOri Kam 		unsigned int i;
42084c406e7SOri Kam 
4218275d5fcSThomas Monjalon 		memcpy(&eth.val.dst_mac, spec->hdr.dst_addr.addr_bytes,
42235b2d13fSOlivier Matz 			RTE_ETHER_ADDR_LEN);
4238275d5fcSThomas Monjalon 		memcpy(&eth.val.src_mac, spec->hdr.src_addr.addr_bytes,
42435b2d13fSOlivier Matz 			RTE_ETHER_ADDR_LEN);
4258275d5fcSThomas Monjalon 		eth.val.ether_type = spec->hdr.ether_type;
4268275d5fcSThomas Monjalon 		memcpy(&eth.mask.dst_mac, mask->hdr.dst_addr.addr_bytes,
42735b2d13fSOlivier Matz 			RTE_ETHER_ADDR_LEN);
4288275d5fcSThomas Monjalon 		memcpy(&eth.mask.src_mac, mask->hdr.src_addr.addr_bytes,
42935b2d13fSOlivier Matz 			RTE_ETHER_ADDR_LEN);
4308275d5fcSThomas Monjalon 		eth.mask.ether_type = mask->hdr.ether_type;
43184c406e7SOri Kam 		/* Remove unwanted bits from values. */
43235b2d13fSOlivier Matz 		for (i = 0; i < RTE_ETHER_ADDR_LEN; ++i) {
43384c406e7SOri Kam 			eth.val.dst_mac[i] &= eth.mask.dst_mac[i];
43484c406e7SOri Kam 			eth.val.src_mac[i] &= eth.mask.src_mac[i];
43584c406e7SOri Kam 		}
43684c406e7SOri Kam 		eth.val.ether_type &= eth.mask.ether_type;
43784c406e7SOri Kam 	}
4384a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &eth, size);
43984c406e7SOri Kam }
44084c406e7SOri Kam 
44184c406e7SOri Kam /**
44284c406e7SOri Kam  * Update the VLAN tag in the Verbs Ethernet specification.
44384c406e7SOri Kam  * This function assumes that the input is valid and there is space to add
44484c406e7SOri Kam  * the requested item.
44584c406e7SOri Kam  *
44684c406e7SOri Kam  * @param[in, out] attr
44784c406e7SOri Kam  *   Pointer to Verbs attributes structure.
44884c406e7SOri Kam  * @param[in] eth
44984c406e7SOri Kam  *   Verbs structure containing the VLAN information to copy.
45084c406e7SOri Kam  */
45184c406e7SOri Kam static void
45284c406e7SOri Kam flow_verbs_item_vlan_update(struct ibv_flow_attr *attr,
45384c406e7SOri Kam 			    struct ibv_flow_spec_eth *eth)
45484c406e7SOri Kam {
45584c406e7SOri Kam 	unsigned int i;
45684c406e7SOri Kam 	const enum ibv_flow_spec_type search = eth->type;
45784c406e7SOri Kam 	struct ibv_spec_header *hdr = (struct ibv_spec_header *)
45884c406e7SOri Kam 		((uint8_t *)attr + sizeof(struct ibv_flow_attr));
45984c406e7SOri Kam 
46084c406e7SOri Kam 	for (i = 0; i != attr->num_of_specs; ++i) {
46184c406e7SOri Kam 		if (hdr->type == search) {
46284c406e7SOri Kam 			struct ibv_flow_spec_eth *e =
46384c406e7SOri Kam 				(struct ibv_flow_spec_eth *)hdr;
46484c406e7SOri Kam 
46584c406e7SOri Kam 			e->val.vlan_tag = eth->val.vlan_tag;
46684c406e7SOri Kam 			e->mask.vlan_tag = eth->mask.vlan_tag;
46784c406e7SOri Kam 			e->val.ether_type = eth->val.ether_type;
46884c406e7SOri Kam 			e->mask.ether_type = eth->mask.ether_type;
46984c406e7SOri Kam 			break;
47084c406e7SOri Kam 		}
47184c406e7SOri Kam 		hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
47284c406e7SOri Kam 	}
47384c406e7SOri Kam }
47484c406e7SOri Kam 
47584c406e7SOri Kam /**
47684c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
47784c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
47884c406e7SOri Kam  * into the flow.
47984c406e7SOri Kam  *
48084c406e7SOri Kam  * @param[in, out] dev_flow
48184c406e7SOri Kam  *   Pointer to dev_flow structure.
4824a78c88eSYongseok Koh  * @param[in] item
4834a78c88eSYongseok Koh  *   Item specification.
4844a78c88eSYongseok Koh  * @param[in] item_flags
4854a78c88eSYongseok Koh  *   Parsed item flags.
48684c406e7SOri Kam  */
48784c406e7SOri Kam static void
4884a78c88eSYongseok Koh flow_verbs_translate_item_vlan(struct mlx5_flow *dev_flow,
4894a78c88eSYongseok Koh 			       const struct rte_flow_item *item,
4904a78c88eSYongseok Koh 			       uint64_t item_flags)
49184c406e7SOri Kam {
49284c406e7SOri Kam 	const struct rte_flow_item_vlan *spec = item->spec;
49384c406e7SOri Kam 	const struct rte_flow_item_vlan *mask = item->mask;
49484c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_eth);
4954a78c88eSYongseok Koh 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
49684c406e7SOri Kam 	struct ibv_flow_spec_eth eth = {
4974a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags),
49884c406e7SOri Kam 		.size = size,
49984c406e7SOri Kam 	};
50084c406e7SOri Kam 	const uint32_t l2m = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
50184c406e7SOri Kam 				      MLX5_FLOW_LAYER_OUTER_L2;
50284c406e7SOri Kam 
50384c406e7SOri Kam 	if (!mask)
50484c406e7SOri Kam 		mask = &rte_flow_item_vlan_mask;
50584c406e7SOri Kam 	if (spec) {
5068275d5fcSThomas Monjalon 		eth.val.vlan_tag = spec->hdr.vlan_tci;
5078275d5fcSThomas Monjalon 		eth.mask.vlan_tag = mask->hdr.vlan_tci;
50884c406e7SOri Kam 		eth.val.vlan_tag &= eth.mask.vlan_tag;
5098275d5fcSThomas Monjalon 		eth.val.ether_type = spec->hdr.eth_proto;
5108275d5fcSThomas Monjalon 		eth.mask.ether_type = mask->hdr.eth_proto;
51184c406e7SOri Kam 		eth.val.ether_type &= eth.mask.ether_type;
51284c406e7SOri Kam 	}
5134a78c88eSYongseok Koh 	if (!(item_flags & l2m))
5144a78c88eSYongseok Koh 		flow_verbs_spec_add(&dev_flow->verbs, &eth, size);
5154a78c88eSYongseok Koh 	else
516e7bfa359SBing Zhao 		flow_verbs_item_vlan_update(&dev_flow->verbs.attr, &eth);
517dfedf3e3SViacheslav Ovsiienko 	if (!tunnel)
518e7bfa359SBing Zhao 		dev_flow->handle->vf_vlan.tag =
5198275d5fcSThomas Monjalon 			rte_be_to_cpu_16(spec->hdr.vlan_tci) & 0x0fff;
52084c406e7SOri Kam }
52184c406e7SOri Kam 
52284c406e7SOri Kam /**
52384c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
52484c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
52584c406e7SOri Kam  * into the flow.
52684c406e7SOri Kam  *
5274a78c88eSYongseok Koh  * @param[in, out] dev_flow
5284a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
52984c406e7SOri Kam  * @param[in] item
53084c406e7SOri Kam  *   Item specification.
5314a78c88eSYongseok Koh  * @param[in] item_flags
5324a78c88eSYongseok Koh  *   Parsed item flags.
53384c406e7SOri Kam  */
53484c406e7SOri Kam static void
5354a78c88eSYongseok Koh flow_verbs_translate_item_ipv4(struct mlx5_flow *dev_flow,
5364a78c88eSYongseok Koh 			       const struct rte_flow_item *item,
5374a78c88eSYongseok Koh 			       uint64_t item_flags)
53884c406e7SOri Kam {
53984c406e7SOri Kam 	const struct rte_flow_item_ipv4 *spec = item->spec;
54084c406e7SOri Kam 	const struct rte_flow_item_ipv4 *mask = item->mask;
54184c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_ipv4_ext);
54284c406e7SOri Kam 	struct ibv_flow_spec_ipv4_ext ipv4 = {
5434a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_IPV4_EXT | VERBS_SPEC_INNER(item_flags),
54484c406e7SOri Kam 		.size = size,
54584c406e7SOri Kam 	};
54684c406e7SOri Kam 
54784c406e7SOri Kam 	if (!mask)
54884c406e7SOri Kam 		mask = &rte_flow_item_ipv4_mask;
54984c406e7SOri Kam 	if (spec) {
55084c406e7SOri Kam 		ipv4.val = (struct ibv_flow_ipv4_ext_filter){
55184c406e7SOri Kam 			.src_ip = spec->hdr.src_addr,
55284c406e7SOri Kam 			.dst_ip = spec->hdr.dst_addr,
55384c406e7SOri Kam 			.proto = spec->hdr.next_proto_id,
55484c406e7SOri Kam 			.tos = spec->hdr.type_of_service,
55584c406e7SOri Kam 		};
55684c406e7SOri Kam 		ipv4.mask = (struct ibv_flow_ipv4_ext_filter){
55784c406e7SOri Kam 			.src_ip = mask->hdr.src_addr,
55884c406e7SOri Kam 			.dst_ip = mask->hdr.dst_addr,
55984c406e7SOri Kam 			.proto = mask->hdr.next_proto_id,
56084c406e7SOri Kam 			.tos = mask->hdr.type_of_service,
56184c406e7SOri Kam 		};
56284c406e7SOri Kam 		/* Remove unwanted bits from values. */
56384c406e7SOri Kam 		ipv4.val.src_ip &= ipv4.mask.src_ip;
56484c406e7SOri Kam 		ipv4.val.dst_ip &= ipv4.mask.dst_ip;
56584c406e7SOri Kam 		ipv4.val.proto &= ipv4.mask.proto;
56684c406e7SOri Kam 		ipv4.val.tos &= ipv4.mask.tos;
56784c406e7SOri Kam 	}
5684a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &ipv4, size);
56984c406e7SOri Kam }
57084c406e7SOri Kam 
57184c406e7SOri Kam /**
57284c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
57384c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
57484c406e7SOri Kam  * into the flow.
57584c406e7SOri Kam  *
5764a78c88eSYongseok Koh  * @param[in, out] dev_flow
5774a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
57884c406e7SOri Kam  * @param[in] item
57984c406e7SOri Kam  *   Item specification.
5804a78c88eSYongseok Koh  * @param[in] item_flags
5814a78c88eSYongseok Koh  *   Parsed item flags.
58284c406e7SOri Kam  */
58384c406e7SOri Kam static void
5844a78c88eSYongseok Koh flow_verbs_translate_item_ipv6(struct mlx5_flow *dev_flow,
5854a78c88eSYongseok Koh 			       const struct rte_flow_item *item,
5864a78c88eSYongseok Koh 			       uint64_t item_flags)
58784c406e7SOri Kam {
58884c406e7SOri Kam 	const struct rte_flow_item_ipv6 *spec = item->spec;
58984c406e7SOri Kam 	const struct rte_flow_item_ipv6 *mask = item->mask;
59084c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_ipv6);
59184c406e7SOri Kam 	struct ibv_flow_spec_ipv6 ipv6 = {
5924a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_IPV6 | VERBS_SPEC_INNER(item_flags),
59384c406e7SOri Kam 		.size = size,
59484c406e7SOri Kam 	};
59584c406e7SOri Kam 
59684c406e7SOri Kam 	if (!mask)
59784c406e7SOri Kam 		mask = &rte_flow_item_ipv6_mask;
59884c406e7SOri Kam 	if (spec) {
59984c406e7SOri Kam 		unsigned int i;
60084c406e7SOri Kam 		uint32_t vtc_flow_val;
60184c406e7SOri Kam 		uint32_t vtc_flow_mask;
60284c406e7SOri Kam 
603*89b5642dSRobin Jarry 		memcpy(&ipv6.val.src_ip, &spec->hdr.src_addr,
60484c406e7SOri Kam 		       RTE_DIM(ipv6.val.src_ip));
605*89b5642dSRobin Jarry 		memcpy(&ipv6.val.dst_ip, &spec->hdr.dst_addr,
60684c406e7SOri Kam 		       RTE_DIM(ipv6.val.dst_ip));
607*89b5642dSRobin Jarry 		memcpy(&ipv6.mask.src_ip, &mask->hdr.src_addr,
60884c406e7SOri Kam 		       RTE_DIM(ipv6.mask.src_ip));
609*89b5642dSRobin Jarry 		memcpy(&ipv6.mask.dst_ip, &mask->hdr.dst_addr,
61084c406e7SOri Kam 		       RTE_DIM(ipv6.mask.dst_ip));
61184c406e7SOri Kam 		vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);
61284c406e7SOri Kam 		vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);
61384c406e7SOri Kam 		ipv6.val.flow_label =
61424ac604eSOlivier Matz 			rte_cpu_to_be_32((vtc_flow_val & RTE_IPV6_HDR_FL_MASK) >>
61524ac604eSOlivier Matz 					 RTE_IPV6_HDR_FL_SHIFT);
61624ac604eSOlivier Matz 		ipv6.val.traffic_class = (vtc_flow_val & RTE_IPV6_HDR_TC_MASK) >>
61724ac604eSOlivier Matz 					 RTE_IPV6_HDR_TC_SHIFT;
61884c406e7SOri Kam 		ipv6.val.next_hdr = spec->hdr.proto;
61984c406e7SOri Kam 		ipv6.mask.flow_label =
62024ac604eSOlivier Matz 			rte_cpu_to_be_32((vtc_flow_mask & RTE_IPV6_HDR_FL_MASK) >>
62124ac604eSOlivier Matz 					 RTE_IPV6_HDR_FL_SHIFT);
62224ac604eSOlivier Matz 		ipv6.mask.traffic_class = (vtc_flow_mask & RTE_IPV6_HDR_TC_MASK) >>
62324ac604eSOlivier Matz 					  RTE_IPV6_HDR_TC_SHIFT;
62484c406e7SOri Kam 		ipv6.mask.next_hdr = mask->hdr.proto;
62584c406e7SOri Kam 		/* Remove unwanted bits from values. */
62684c406e7SOri Kam 		for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {
62784c406e7SOri Kam 			ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];
62884c406e7SOri Kam 			ipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];
62984c406e7SOri Kam 		}
63084c406e7SOri Kam 		ipv6.val.flow_label &= ipv6.mask.flow_label;
63184c406e7SOri Kam 		ipv6.val.traffic_class &= ipv6.mask.traffic_class;
63284c406e7SOri Kam 		ipv6.val.next_hdr &= ipv6.mask.next_hdr;
63384c406e7SOri Kam 	}
6344a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &ipv6, size);
63584c406e7SOri Kam }
63684c406e7SOri Kam 
63784c406e7SOri Kam /**
63884c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
63984c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
64084c406e7SOri Kam  * into the flow.
64184c406e7SOri Kam  *
6424a78c88eSYongseok Koh  * @param[in, out] dev_flow
6434a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
64484c406e7SOri Kam  * @param[in] item
64584c406e7SOri Kam  *   Item specification.
6464a78c88eSYongseok Koh  * @param[in] item_flags
6474a78c88eSYongseok Koh  *   Parsed item flags.
64884c406e7SOri Kam  */
64984c406e7SOri Kam static void
6504a78c88eSYongseok Koh flow_verbs_translate_item_tcp(struct mlx5_flow *dev_flow,
6514a78c88eSYongseok Koh 			      const struct rte_flow_item *item,
6524a78c88eSYongseok Koh 			      uint64_t item_flags __rte_unused)
65384c406e7SOri Kam {
65484c406e7SOri Kam 	const struct rte_flow_item_tcp *spec = item->spec;
65584c406e7SOri Kam 	const struct rte_flow_item_tcp *mask = item->mask;
65684c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
65784c406e7SOri Kam 	struct ibv_flow_spec_tcp_udp tcp = {
6584a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_TCP | VERBS_SPEC_INNER(item_flags),
65984c406e7SOri Kam 		.size = size,
66084c406e7SOri Kam 	};
66184c406e7SOri Kam 
66284c406e7SOri Kam 	if (!mask)
66384c406e7SOri Kam 		mask = &rte_flow_item_tcp_mask;
66484c406e7SOri Kam 	if (spec) {
66584c406e7SOri Kam 		tcp.val.dst_port = spec->hdr.dst_port;
66684c406e7SOri Kam 		tcp.val.src_port = spec->hdr.src_port;
66784c406e7SOri Kam 		tcp.mask.dst_port = mask->hdr.dst_port;
66884c406e7SOri Kam 		tcp.mask.src_port = mask->hdr.src_port;
66984c406e7SOri Kam 		/* Remove unwanted bits from values. */
67084c406e7SOri Kam 		tcp.val.src_port &= tcp.mask.src_port;
67184c406e7SOri Kam 		tcp.val.dst_port &= tcp.mask.dst_port;
67284c406e7SOri Kam 	}
6734a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &tcp, size);
67484c406e7SOri Kam }
67584c406e7SOri Kam 
67684c406e7SOri Kam /**
67784c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
67884c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
67984c406e7SOri Kam  * into the flow.
68084c406e7SOri Kam  *
6814a78c88eSYongseok Koh  * @param[in, out] dev_flow
6824a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
68384c406e7SOri Kam  * @param[in] item
68484c406e7SOri Kam  *   Item specification.
6854a78c88eSYongseok Koh  * @param[in] item_flags
6864a78c88eSYongseok Koh  *   Parsed item flags.
68784c406e7SOri Kam  */
68872185352SMaayan Kashani #ifdef HAVE_IBV_FLOW_SPEC_ESP
68972185352SMaayan Kashani static void
69072185352SMaayan Kashani flow_verbs_translate_item_esp(struct mlx5_flow *dev_flow,
69172185352SMaayan Kashani 			      const struct rte_flow_item *item,
69272185352SMaayan Kashani 			      uint64_t item_flags __rte_unused)
69372185352SMaayan Kashani {
69472185352SMaayan Kashani 	const struct rte_flow_item_esp *spec = item->spec;
69572185352SMaayan Kashani 	const struct rte_flow_item_esp *mask = item->mask;
69672185352SMaayan Kashani 	unsigned int size = sizeof(struct ibv_flow_spec_esp);
69772185352SMaayan Kashani 	struct ibv_flow_spec_esp esp = {
69872185352SMaayan Kashani 		.type = IBV_FLOW_SPEC_ESP | VERBS_SPEC_INNER(item_flags),
69972185352SMaayan Kashani 		.size = size,
70072185352SMaayan Kashani 	};
70172185352SMaayan Kashani 
70272185352SMaayan Kashani 	if (!mask)
70372185352SMaayan Kashani 		mask = &rte_flow_item_esp_mask;
70472185352SMaayan Kashani 	if (spec) {
70572185352SMaayan Kashani 		esp.val.spi = spec->hdr.spi & mask->hdr.spi;
70672185352SMaayan Kashani 		esp.mask.spi = mask->hdr.spi;
70772185352SMaayan Kashani 	}
70872185352SMaayan Kashani 	flow_verbs_spec_add(&dev_flow->verbs, &esp, size);
70972185352SMaayan Kashani }
71072185352SMaayan Kashani #endif
71172185352SMaayan Kashani 
71272185352SMaayan Kashani /**
71372185352SMaayan Kashani  * Convert the @p item into a Verbs specification. This function assumes that
71472185352SMaayan Kashani  * the input is valid and that there is space to insert the requested item
71572185352SMaayan Kashani  * into the flow.
71672185352SMaayan Kashani  *
71772185352SMaayan Kashani  * @param[in, out] dev_flow
71872185352SMaayan Kashani  *   Pointer to dev_flow structure.
71972185352SMaayan Kashani  * @param[in] item
72072185352SMaayan Kashani  *   Item specification.
72172185352SMaayan Kashani  * @param[in] item_flags
72272185352SMaayan Kashani  *   Parsed item flags.
72372185352SMaayan Kashani  */
72484c406e7SOri Kam static void
7254a78c88eSYongseok Koh flow_verbs_translate_item_udp(struct mlx5_flow *dev_flow,
7264a78c88eSYongseok Koh 			      const struct rte_flow_item *item,
7274a78c88eSYongseok Koh 			      uint64_t item_flags __rte_unused)
7284a78c88eSYongseok Koh {
7294a78c88eSYongseok Koh 	const struct rte_flow_item_udp *spec = item->spec;
7304a78c88eSYongseok Koh 	const struct rte_flow_item_udp *mask = item->mask;
7314a78c88eSYongseok Koh 	unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
7324a78c88eSYongseok Koh 	struct ibv_flow_spec_tcp_udp udp = {
7334a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_UDP | VERBS_SPEC_INNER(item_flags),
7344a78c88eSYongseok Koh 		.size = size,
7354a78c88eSYongseok Koh 	};
7364a78c88eSYongseok Koh 
7374a78c88eSYongseok Koh 	if (!mask)
7384a78c88eSYongseok Koh 		mask = &rte_flow_item_udp_mask;
7394a78c88eSYongseok Koh 	if (spec) {
7404a78c88eSYongseok Koh 		udp.val.dst_port = spec->hdr.dst_port;
7414a78c88eSYongseok Koh 		udp.val.src_port = spec->hdr.src_port;
7424a78c88eSYongseok Koh 		udp.mask.dst_port = mask->hdr.dst_port;
7434a78c88eSYongseok Koh 		udp.mask.src_port = mask->hdr.src_port;
7444a78c88eSYongseok Koh 		/* Remove unwanted bits from values. */
7454a78c88eSYongseok Koh 		udp.val.src_port &= udp.mask.src_port;
7464a78c88eSYongseok Koh 		udp.val.dst_port &= udp.mask.dst_port;
7474a78c88eSYongseok Koh 	}
7488a2e026aSRaslan Darawsheh 	item++;
7498a2e026aSRaslan Darawsheh 	while (item->type == RTE_FLOW_ITEM_TYPE_VOID)
7508a2e026aSRaslan Darawsheh 		item++;
7518a2e026aSRaslan Darawsheh 	if (!(udp.val.dst_port & udp.mask.dst_port)) {
7528a2e026aSRaslan Darawsheh 		switch ((item)->type) {
7538a2e026aSRaslan Darawsheh 		case RTE_FLOW_ITEM_TYPE_VXLAN:
7548a2e026aSRaslan Darawsheh 			udp.val.dst_port = htons(MLX5_UDP_PORT_VXLAN);
7558a2e026aSRaslan Darawsheh 			udp.mask.dst_port = 0xffff;
7568a2e026aSRaslan Darawsheh 			break;
7578a2e026aSRaslan Darawsheh 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
7588a2e026aSRaslan Darawsheh 			udp.val.dst_port = htons(MLX5_UDP_PORT_VXLAN_GPE);
7598a2e026aSRaslan Darawsheh 			udp.mask.dst_port = 0xffff;
7608a2e026aSRaslan Darawsheh 			break;
7618a2e026aSRaslan Darawsheh 		case RTE_FLOW_ITEM_TYPE_MPLS:
7628a2e026aSRaslan Darawsheh 			udp.val.dst_port = htons(MLX5_UDP_PORT_MPLS);
7638a2e026aSRaslan Darawsheh 			udp.mask.dst_port = 0xffff;
7648a2e026aSRaslan Darawsheh 			break;
7658a2e026aSRaslan Darawsheh 		default:
7668a2e026aSRaslan Darawsheh 			break;
7678a2e026aSRaslan Darawsheh 		}
7688a2e026aSRaslan Darawsheh 	}
7698a2e026aSRaslan Darawsheh 
7704a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &udp, size);
7714a78c88eSYongseok Koh }
7724a78c88eSYongseok Koh 
7734a78c88eSYongseok Koh /**
7744a78c88eSYongseok Koh  * Convert the @p item into a Verbs specification. This function assumes that
7754a78c88eSYongseok Koh  * the input is valid and that there is space to insert the requested item
7764a78c88eSYongseok Koh  * into the flow.
7774a78c88eSYongseok Koh  *
7784a78c88eSYongseok Koh  * @param[in, out] dev_flow
7794a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
7804a78c88eSYongseok Koh  * @param[in] item
7814a78c88eSYongseok Koh  *   Item specification.
7824a78c88eSYongseok Koh  * @param[in] item_flags
7834a78c88eSYongseok Koh  *   Parsed item flags.
7844a78c88eSYongseok Koh  */
7854a78c88eSYongseok Koh static void
7864a78c88eSYongseok Koh flow_verbs_translate_item_vxlan(struct mlx5_flow *dev_flow,
7874a78c88eSYongseok Koh 				const struct rte_flow_item *item,
7884a78c88eSYongseok Koh 				uint64_t item_flags __rte_unused)
78984c406e7SOri Kam {
79084c406e7SOri Kam 	const struct rte_flow_item_vxlan *spec = item->spec;
79184c406e7SOri Kam 	const struct rte_flow_item_vxlan *mask = item->mask;
79284c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
79384c406e7SOri Kam 	struct ibv_flow_spec_tunnel vxlan = {
79484c406e7SOri Kam 		.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
79584c406e7SOri Kam 		.size = size,
79684c406e7SOri Kam 	};
79784c406e7SOri Kam 	union vni {
79884c406e7SOri Kam 		uint32_t vlan_id;
79984c406e7SOri Kam 		uint8_t vni[4];
80084c406e7SOri Kam 	} id = { .vlan_id = 0, };
80184c406e7SOri Kam 
80284c406e7SOri Kam 	if (!mask)
80384c406e7SOri Kam 		mask = &rte_flow_item_vxlan_mask;
80484c406e7SOri Kam 	if (spec) {
8055ec2a97eSThomas Monjalon 		memcpy(&id.vni[1], spec->hdr.vni, 3);
80684c406e7SOri Kam 		vxlan.val.tunnel_id = id.vlan_id;
8075ec2a97eSThomas Monjalon 		memcpy(&id.vni[1], mask->hdr.vni, 3);
80884c406e7SOri Kam 		vxlan.mask.tunnel_id = id.vlan_id;
80984c406e7SOri Kam 		/* Remove unwanted bits from values. */
81084c406e7SOri Kam 		vxlan.val.tunnel_id &= vxlan.mask.tunnel_id;
81184c406e7SOri Kam 	}
8124a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &vxlan, size);
81384c406e7SOri Kam }
81484c406e7SOri Kam 
81584c406e7SOri Kam /**
81684c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
81784c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
81884c406e7SOri Kam  * into the flow.
81984c406e7SOri Kam  *
8204a78c88eSYongseok Koh  * @param[in, out] dev_flow
8214a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
82284c406e7SOri Kam  * @param[in] item
82384c406e7SOri Kam  *   Item specification.
8244a78c88eSYongseok Koh  * @param[in] item_flags
8254a78c88eSYongseok Koh  *   Parsed item flags.
82684c406e7SOri Kam  */
82784c406e7SOri Kam static void
8284a78c88eSYongseok Koh flow_verbs_translate_item_vxlan_gpe(struct mlx5_flow *dev_flow,
8294a78c88eSYongseok Koh 				    const struct rte_flow_item *item,
8304a78c88eSYongseok Koh 				    uint64_t item_flags __rte_unused)
83184c406e7SOri Kam {
83284c406e7SOri Kam 	const struct rte_flow_item_vxlan_gpe *spec = item->spec;
83384c406e7SOri Kam 	const struct rte_flow_item_vxlan_gpe *mask = item->mask;
83484c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
83584c406e7SOri Kam 	struct ibv_flow_spec_tunnel vxlan_gpe = {
83684c406e7SOri Kam 		.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
83784c406e7SOri Kam 		.size = size,
83884c406e7SOri Kam 	};
83984c406e7SOri Kam 	union vni {
84084c406e7SOri Kam 		uint32_t vlan_id;
84184c406e7SOri Kam 		uint8_t vni[4];
84284c406e7SOri Kam 	} id = { .vlan_id = 0, };
84384c406e7SOri Kam 
84484c406e7SOri Kam 	if (!mask)
84584c406e7SOri Kam 		mask = &rte_flow_item_vxlan_gpe_mask;
84684c406e7SOri Kam 	if (spec) {
8475ec2a97eSThomas Monjalon 		memcpy(&id.vni[1], spec->hdr.vni, 3);
84884c406e7SOri Kam 		vxlan_gpe.val.tunnel_id = id.vlan_id;
8495ec2a97eSThomas Monjalon 		memcpy(&id.vni[1], mask->hdr.vni, 3);
85084c406e7SOri Kam 		vxlan_gpe.mask.tunnel_id = id.vlan_id;
85184c406e7SOri Kam 		/* Remove unwanted bits from values. */
85284c406e7SOri Kam 		vxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id;
85384c406e7SOri Kam 	}
8544a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &vxlan_gpe, size);
85584c406e7SOri Kam }
85684c406e7SOri Kam 
85784c406e7SOri Kam /**
85884c406e7SOri Kam  * Update the protocol in Verbs IPv4/IPv6 spec.
85984c406e7SOri Kam  *
86084c406e7SOri Kam  * @param[in, out] attr
86184c406e7SOri Kam  *   Pointer to Verbs attributes structure.
86284c406e7SOri Kam  * @param[in] search
86384c406e7SOri Kam  *   Specification type to search in order to update the IP protocol.
86484c406e7SOri Kam  * @param[in] protocol
86584c406e7SOri Kam  *   Protocol value to set if none is present in the specification.
86684c406e7SOri Kam  */
86784c406e7SOri Kam static void
86884c406e7SOri Kam flow_verbs_item_gre_ip_protocol_update(struct ibv_flow_attr *attr,
86984c406e7SOri Kam 				       enum ibv_flow_spec_type search,
87084c406e7SOri Kam 				       uint8_t protocol)
87184c406e7SOri Kam {
87284c406e7SOri Kam 	unsigned int i;
87384c406e7SOri Kam 	struct ibv_spec_header *hdr = (struct ibv_spec_header *)
87484c406e7SOri Kam 		((uint8_t *)attr + sizeof(struct ibv_flow_attr));
87584c406e7SOri Kam 
87684c406e7SOri Kam 	if (!attr)
87784c406e7SOri Kam 		return;
87884c406e7SOri Kam 	for (i = 0; i != attr->num_of_specs; ++i) {
87984c406e7SOri Kam 		if (hdr->type == search) {
88084c406e7SOri Kam 			union {
88184c406e7SOri Kam 				struct ibv_flow_spec_ipv4_ext *ipv4;
88284c406e7SOri Kam 				struct ibv_flow_spec_ipv6 *ipv6;
88384c406e7SOri Kam 			} ip;
88484c406e7SOri Kam 
88584c406e7SOri Kam 			switch (search) {
88684c406e7SOri Kam 			case IBV_FLOW_SPEC_IPV4_EXT:
88784c406e7SOri Kam 				ip.ipv4 = (struct ibv_flow_spec_ipv4_ext *)hdr;
88884c406e7SOri Kam 				if (!ip.ipv4->val.proto) {
88984c406e7SOri Kam 					ip.ipv4->val.proto = protocol;
89084c406e7SOri Kam 					ip.ipv4->mask.proto = 0xff;
89184c406e7SOri Kam 				}
89284c406e7SOri Kam 				break;
89384c406e7SOri Kam 			case IBV_FLOW_SPEC_IPV6:
89484c406e7SOri Kam 				ip.ipv6 = (struct ibv_flow_spec_ipv6 *)hdr;
89584c406e7SOri Kam 				if (!ip.ipv6->val.next_hdr) {
89684c406e7SOri Kam 					ip.ipv6->val.next_hdr = protocol;
89784c406e7SOri Kam 					ip.ipv6->mask.next_hdr = 0xff;
89884c406e7SOri Kam 				}
89984c406e7SOri Kam 				break;
90084c406e7SOri Kam 			default:
90184c406e7SOri Kam 				break;
90284c406e7SOri Kam 			}
90384c406e7SOri Kam 			break;
90484c406e7SOri Kam 		}
90584c406e7SOri Kam 		hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
90684c406e7SOri Kam 	}
90784c406e7SOri Kam }
90884c406e7SOri Kam 
90984c406e7SOri Kam /**
91098008ce6SDariusz Sosnowski  * Reserve space for GRE spec in spec buffer.
91184c406e7SOri Kam  *
9124a78c88eSYongseok Koh  * @param[in,out] dev_flow
9134a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
91498008ce6SDariusz Sosnowski  *
91598008ce6SDariusz Sosnowski  * @return
91698008ce6SDariusz Sosnowski  *   Pointer to reserved space in spec buffer.
91798008ce6SDariusz Sosnowski  */
91898008ce6SDariusz Sosnowski static uint8_t *
91998008ce6SDariusz Sosnowski flow_verbs_reserve_gre(struct mlx5_flow *dev_flow)
92098008ce6SDariusz Sosnowski {
92198008ce6SDariusz Sosnowski 	uint8_t *buffer;
92298008ce6SDariusz Sosnowski 	struct mlx5_flow_verbs_workspace *verbs = &dev_flow->verbs;
92398008ce6SDariusz Sosnowski #ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT
92498008ce6SDariusz Sosnowski 	unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
92598008ce6SDariusz Sosnowski 	struct ibv_flow_spec_tunnel tunnel = {
92698008ce6SDariusz Sosnowski 		.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
92798008ce6SDariusz Sosnowski 		.size = size,
92898008ce6SDariusz Sosnowski 	};
92998008ce6SDariusz Sosnowski #else
93098008ce6SDariusz Sosnowski 	unsigned int size = sizeof(struct ibv_flow_spec_gre);
93198008ce6SDariusz Sosnowski 	struct ibv_flow_spec_gre tunnel = {
93298008ce6SDariusz Sosnowski 		.type = IBV_FLOW_SPEC_GRE,
93398008ce6SDariusz Sosnowski 		.size = size,
93498008ce6SDariusz Sosnowski 	};
93598008ce6SDariusz Sosnowski #endif
93698008ce6SDariusz Sosnowski 
93798008ce6SDariusz Sosnowski 	buffer = verbs->specs + verbs->size;
93898008ce6SDariusz Sosnowski 	flow_verbs_spec_add(verbs, &tunnel, size);
93998008ce6SDariusz Sosnowski 	return buffer;
94098008ce6SDariusz Sosnowski }
94198008ce6SDariusz Sosnowski 
94298008ce6SDariusz Sosnowski /**
94398008ce6SDariusz Sosnowski  * Convert the @p item into a Verbs specification. This function assumes that
94498008ce6SDariusz Sosnowski  * the input is valid and that Verbs specification will be placed in
94598008ce6SDariusz Sosnowski  * the pre-reserved space.
94698008ce6SDariusz Sosnowski  *
94798008ce6SDariusz Sosnowski  * @param[in, out] dev_flow
94898008ce6SDariusz Sosnowski  *   Pointer to dev_flow structure.
94998008ce6SDariusz Sosnowski  * @param[in, out] gre_spec
95098008ce6SDariusz Sosnowski  *   Pointer to space reserved for GRE spec.
95184c406e7SOri Kam  * @param[in] item
95284c406e7SOri Kam  *   Item specification.
9534a78c88eSYongseok Koh  * @param[in] item_flags
9544a78c88eSYongseok Koh  *   Parsed item flags.
95584c406e7SOri Kam  */
95684c406e7SOri Kam static void
9574a78c88eSYongseok Koh flow_verbs_translate_item_gre(struct mlx5_flow *dev_flow,
95898008ce6SDariusz Sosnowski 			      uint8_t *gre_spec,
9594a78c88eSYongseok Koh 			      const struct rte_flow_item *item __rte_unused,
9604a78c88eSYongseok Koh 			      uint64_t item_flags)
96184c406e7SOri Kam {
962e7bfa359SBing Zhao 	struct mlx5_flow_verbs_workspace *verbs = &dev_flow->verbs;
96384c406e7SOri Kam #ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT
96484c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
96584c406e7SOri Kam 	struct ibv_flow_spec_tunnel tunnel = {
96684c406e7SOri Kam 		.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
96784c406e7SOri Kam 		.size = size,
96884c406e7SOri Kam 	};
96984c406e7SOri Kam #else
970985b4792SGregory Etelson 	static const struct rte_flow_item_gre empty_gre = {0,};
97184c406e7SOri Kam 	const struct rte_flow_item_gre *spec = item->spec;
97284c406e7SOri Kam 	const struct rte_flow_item_gre *mask = item->mask;
97384c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_gre);
97484c406e7SOri Kam 	struct ibv_flow_spec_gre tunnel = {
97584c406e7SOri Kam 		.type = IBV_FLOW_SPEC_GRE,
97684c406e7SOri Kam 		.size = size,
97784c406e7SOri Kam 	};
97884c406e7SOri Kam 
979985b4792SGregory Etelson 	if (!spec) {
980985b4792SGregory Etelson 		spec = &empty_gre;
981985b4792SGregory Etelson 		mask = &empty_gre;
982985b4792SGregory Etelson 	} else {
98384c406e7SOri Kam 		if (!mask)
98484c406e7SOri Kam 			mask = &rte_flow_item_gre_mask;
985985b4792SGregory Etelson 	}
98684c406e7SOri Kam 	tunnel.val.c_ks_res0_ver = spec->c_rsvd0_ver;
98784c406e7SOri Kam 	tunnel.val.protocol = spec->protocol;
98884c406e7SOri Kam 	tunnel.mask.c_ks_res0_ver = mask->c_rsvd0_ver;
98984c406e7SOri Kam 	tunnel.mask.protocol = mask->protocol;
99084c406e7SOri Kam 	/* Remove unwanted bits from values. */
99184c406e7SOri Kam 	tunnel.val.c_ks_res0_ver &= tunnel.mask.c_ks_res0_ver;
99284c406e7SOri Kam 	tunnel.val.key &= tunnel.mask.key;
993985b4792SGregory Etelson 	if (tunnel.mask.protocol) {
994985b4792SGregory Etelson 		tunnel.val.protocol &= tunnel.mask.protocol;
995985b4792SGregory Etelson 	} else {
996985b4792SGregory Etelson 		tunnel.val.protocol = mlx5_translate_tunnel_etypes(item_flags);
997985b4792SGregory Etelson 		if (tunnel.val.protocol) {
998985b4792SGregory Etelson 			tunnel.mask.protocol = 0xFFFF;
999985b4792SGregory Etelson 			tunnel.val.protocol =
1000985b4792SGregory Etelson 				rte_cpu_to_be_16(tunnel.val.protocol);
1001985b4792SGregory Etelson 		}
100284c406e7SOri Kam 	}
100384c406e7SOri Kam #endif
10044a78c88eSYongseok Koh 	if (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
1005e7bfa359SBing Zhao 		flow_verbs_item_gre_ip_protocol_update(&verbs->attr,
100684c406e7SOri Kam 						       IBV_FLOW_SPEC_IPV4_EXT,
100784c406e7SOri Kam 						       IPPROTO_GRE);
100884c406e7SOri Kam 	else
1009e7bfa359SBing Zhao 		flow_verbs_item_gre_ip_protocol_update(&verbs->attr,
101084c406e7SOri Kam 						       IBV_FLOW_SPEC_IPV6,
101184c406e7SOri Kam 						       IPPROTO_GRE);
101298008ce6SDariusz Sosnowski 	MLX5_ASSERT(gre_spec);
101398008ce6SDariusz Sosnowski 	memcpy(gre_spec, &tunnel, size);
101484c406e7SOri Kam }
101584c406e7SOri Kam 
101684c406e7SOri Kam /**
101784c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
101884c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
101984c406e7SOri Kam  * into the flow. This function also return the action that was added.
102084c406e7SOri Kam  *
10214a78c88eSYongseok Koh  * @param[in, out] dev_flow
10224a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
102384c406e7SOri Kam  * @param[in] item
102484c406e7SOri Kam  *   Item specification.
10254a78c88eSYongseok Koh  * @param[in] item_flags
10264a78c88eSYongseok Koh  *   Parsed item flags.
102784c406e7SOri Kam  */
102884c406e7SOri Kam static void
10294a78c88eSYongseok Koh flow_verbs_translate_item_mpls(struct mlx5_flow *dev_flow __rte_unused,
10304a78c88eSYongseok Koh 			       const struct rte_flow_item *item __rte_unused,
10314a78c88eSYongseok Koh 			       uint64_t item_flags __rte_unused)
103284c406e7SOri Kam {
103384c406e7SOri Kam #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
103484c406e7SOri Kam 	const struct rte_flow_item_mpls *spec = item->spec;
103584c406e7SOri Kam 	const struct rte_flow_item_mpls *mask = item->mask;
103684c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_mpls);
103784c406e7SOri Kam 	struct ibv_flow_spec_mpls mpls = {
103884c406e7SOri Kam 		.type = IBV_FLOW_SPEC_MPLS,
103984c406e7SOri Kam 		.size = size,
104084c406e7SOri Kam 	};
104184c406e7SOri Kam 
104284c406e7SOri Kam 	if (!mask)
104384c406e7SOri Kam 		mask = &rte_flow_item_mpls_mask;
104484c406e7SOri Kam 	if (spec) {
104584c406e7SOri Kam 		memcpy(&mpls.val.label, spec, sizeof(mpls.val.label));
104684c406e7SOri Kam 		memcpy(&mpls.mask.label, mask, sizeof(mpls.mask.label));
104784c406e7SOri Kam 		/* Remove unwanted bits from values.  */
104884c406e7SOri Kam 		mpls.val.label &= mpls.mask.label;
104984c406e7SOri Kam 	}
10504a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &mpls, size);
105184c406e7SOri Kam #endif
105284c406e7SOri Kam }
105384c406e7SOri Kam 
105484c406e7SOri Kam /**
105584c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
105684c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
10574a78c88eSYongseok Koh  * into the flow.
105884c406e7SOri Kam  *
105984c406e7SOri Kam  * @param[in] dev_flow
106084c406e7SOri Kam  *   Pointer to mlx5_flow.
10614a78c88eSYongseok Koh  * @param[in] action
10624a78c88eSYongseok Koh  *   Action configuration.
106384c406e7SOri Kam  */
106484c406e7SOri Kam static void
10654a78c88eSYongseok Koh flow_verbs_translate_action_drop
10664a78c88eSYongseok Koh 	(struct mlx5_flow *dev_flow,
10674a78c88eSYongseok Koh 	 const struct rte_flow_action *action __rte_unused)
106884c406e7SOri Kam {
106984c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_action_drop);
107084c406e7SOri Kam 	struct ibv_flow_spec_action_drop drop = {
107184c406e7SOri Kam 			.type = IBV_FLOW_SPEC_ACTION_DROP,
107284c406e7SOri Kam 			.size = size,
107384c406e7SOri Kam 	};
107484c406e7SOri Kam 
10754a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &drop, size);
107684c406e7SOri Kam }
107784c406e7SOri Kam 
107884c406e7SOri Kam /**
107984c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
108084c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
10814a78c88eSYongseok Koh  * into the flow.
108284c406e7SOri Kam  *
1083e745f900SSuanming Mou  * @param[in] rss_desc
1084e745f900SSuanming Mou  *   Pointer to mlx5_flow_rss_desc.
10854a78c88eSYongseok Koh  * @param[in] action
10864a78c88eSYongseok Koh  *   Action configuration.
108784c406e7SOri Kam  */
108884c406e7SOri Kam static void
1089e745f900SSuanming Mou flow_verbs_translate_action_queue(struct mlx5_flow_rss_desc *rss_desc,
10904a78c88eSYongseok Koh 				  const struct rte_flow_action *action)
109184c406e7SOri Kam {
109284c406e7SOri Kam 	const struct rte_flow_action_queue *queue = action->conf;
109384c406e7SOri Kam 
1094e745f900SSuanming Mou 	rss_desc->queue[0] = queue->index;
1095e745f900SSuanming Mou 	rss_desc->queue_num = 1;
109684c406e7SOri Kam }
109784c406e7SOri Kam 
109884c406e7SOri Kam /**
109984c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
110084c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
11014a78c88eSYongseok Koh  * into the flow.
110284c406e7SOri Kam  *
1103e745f900SSuanming Mou  * @param[in] rss_desc
1104e745f900SSuanming Mou  *   Pointer to mlx5_flow_rss_desc.
110584c406e7SOri Kam  * @param[in] action
110684c406e7SOri Kam  *   Action configuration.
110784c406e7SOri Kam  */
110884c406e7SOri Kam static void
1109e745f900SSuanming Mou flow_verbs_translate_action_rss(struct mlx5_flow_rss_desc *rss_desc,
11104a78c88eSYongseok Koh 				const struct rte_flow_action *action)
111184c406e7SOri Kam {
111284c406e7SOri Kam 	const struct rte_flow_action_rss *rss = action->conf;
1113f1b85a27SOphir Munk 	const uint8_t *rss_key;
111484c406e7SOri Kam 
1115e745f900SSuanming Mou 	memcpy(rss_desc->queue, rss->queue, rss->queue_num * sizeof(uint16_t));
1116e745f900SSuanming Mou 	rss_desc->queue_num = rss->queue_num;
1117f1b85a27SOphir Munk 	/* NULL RSS key indicates default RSS key. */
1118f1b85a27SOphir Munk 	rss_key = !rss->key ? rss_hash_default_key : rss->key;
1119e745f900SSuanming Mou 	memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
1120e205c95fSViacheslav Ovsiienko 	/*
1121e205c95fSViacheslav Ovsiienko 	 * rss->level and rss.types should be set in advance when expanding
1122e205c95fSViacheslav Ovsiienko 	 * items for RSS.
1123e205c95fSViacheslav Ovsiienko 	 */
112484c406e7SOri Kam }
112584c406e7SOri Kam 
112684c406e7SOri Kam /**
112784c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
112884c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
11294a78c88eSYongseok Koh  * into the flow.
113084c406e7SOri Kam  *
113184c406e7SOri Kam  * @param[in] dev_flow
113284c406e7SOri Kam  *   Pointer to mlx5_flow.
11334a78c88eSYongseok Koh  * @param[in] action
11344a78c88eSYongseok Koh  *   Action configuration.
113584c406e7SOri Kam  */
113684c406e7SOri Kam static void
113784c406e7SOri Kam flow_verbs_translate_action_flag
11384a78c88eSYongseok Koh 	(struct mlx5_flow *dev_flow,
11394a78c88eSYongseok Koh 	 const struct rte_flow_action *action __rte_unused)
114084c406e7SOri Kam {
114184c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
114284c406e7SOri Kam 	struct ibv_flow_spec_action_tag tag = {
114384c406e7SOri Kam 		.type = IBV_FLOW_SPEC_ACTION_TAG,
114484c406e7SOri Kam 		.size = size,
114584c406e7SOri Kam 		.tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT),
114684c406e7SOri Kam 	};
114784c406e7SOri Kam 
11484a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &tag, size);
114984c406e7SOri Kam }
115084c406e7SOri Kam 
115184c406e7SOri Kam /**
115284c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
115384c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
11544a78c88eSYongseok Koh  * into the flow.
115584c406e7SOri Kam  *
115684c406e7SOri Kam  * @param[in] dev_flow
115784c406e7SOri Kam  *   Pointer to mlx5_flow.
11584a78c88eSYongseok Koh  * @param[in] action
11594a78c88eSYongseok Koh  *   Action configuration.
116084c406e7SOri Kam  */
116184c406e7SOri Kam static void
11624a78c88eSYongseok Koh flow_verbs_translate_action_mark(struct mlx5_flow *dev_flow,
11634a78c88eSYongseok Koh 				 const struct rte_flow_action *action)
116484c406e7SOri Kam {
116584c406e7SOri Kam 	const struct rte_flow_action_mark *mark = action->conf;
116684c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
116784c406e7SOri Kam 	struct ibv_flow_spec_action_tag tag = {
116884c406e7SOri Kam 		.type = IBV_FLOW_SPEC_ACTION_TAG,
116984c406e7SOri Kam 		.size = size,
11704a78c88eSYongseok Koh 		.tag_id = mlx5_flow_mark_set(mark->id),
117184c406e7SOri Kam 	};
117284c406e7SOri Kam 
11734a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &tag, size);
117484c406e7SOri Kam }
117584c406e7SOri Kam 
117684c406e7SOri Kam /**
117784c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
117884c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
11794a78c88eSYongseok Koh  * into the flow.
118084c406e7SOri Kam  *
118184c406e7SOri Kam  * @param[in] dev
118284c406e7SOri Kam  *   Pointer to the Ethernet device structure.
118384c406e7SOri Kam  * @param[in] action
118484c406e7SOri Kam  *   Action configuration.
118584c406e7SOri Kam  * @param[in] dev_flow
118684c406e7SOri Kam  *   Pointer to mlx5_flow.
118784c406e7SOri Kam  * @param[out] error
118884c406e7SOri Kam  *   Pointer to error structure.
118984c406e7SOri Kam  *
119084c406e7SOri Kam  * @return
119184c406e7SOri Kam  *   0 On success else a negative errno value is returned and rte_errno is set.
119284c406e7SOri Kam  */
119384c406e7SOri Kam static int
11944a78c88eSYongseok Koh flow_verbs_translate_action_count(struct mlx5_flow *dev_flow,
119584c406e7SOri Kam 				  const struct rte_flow_action *action,
11964a78c88eSYongseok Koh 				  struct rte_eth_dev *dev,
119784c406e7SOri Kam 				  struct rte_flow_error *error)
119884c406e7SOri Kam {
119984c406e7SOri Kam 	const struct rte_flow_action_count *count = action->conf;
120084c406e7SOri Kam 	struct rte_flow *flow = dev_flow->flow;
1201db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
1202db48f9dbSViacheslav Ovsiienko 	defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
1203826b8a87SSuanming Mou 	struct mlx5_flow_counter_pool *pool;
1204826b8a87SSuanming Mou 	struct mlx5_flow_counter *cnt = NULL;
120584c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
120684c406e7SOri Kam 	struct ibv_flow_spec_counter_action counter = {
120784c406e7SOri Kam 		.type = IBV_FLOW_SPEC_ACTION_COUNT,
120884c406e7SOri Kam 		.size = size,
120984c406e7SOri Kam 	};
121084c406e7SOri Kam #endif
121184c406e7SOri Kam 
121284c406e7SOri Kam 	if (!flow->counter) {
121392ef4b8fSAndrew Rybchenko 		flow->counter = flow_verbs_counter_new(dev, count->id);
121484c406e7SOri Kam 		if (!flow->counter)
121584c406e7SOri Kam 			return rte_flow_error_set(error, rte_errno,
121684c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ACTION,
121784c406e7SOri Kam 						  action,
121884c406e7SOri Kam 						  "cannot get counter"
121984c406e7SOri Kam 						  " context.");
122084c406e7SOri Kam 	}
1221db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
1222826b8a87SSuanming Mou 	cnt = flow_verbs_counter_get_by_idx(dev, flow->counter, &pool);
12232b5b1aebSSuanming Mou 	counter.counter_set_handle =
12242b5b1aebSSuanming Mou 		((struct ibv_counter_set *)cnt->dcs_when_active)->handle;
12254a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &counter, size);
1226db48f9dbSViacheslav Ovsiienko #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
1227826b8a87SSuanming Mou 	cnt = flow_verbs_counter_get_by_idx(dev, flow->counter, &pool);
12282b5b1aebSSuanming Mou 	counter.counters = (struct ibv_counters *)cnt->dcs_when_active;
12294a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &counter, size);
123084c406e7SOri Kam #endif
123184c406e7SOri Kam 	return 0;
123284c406e7SOri Kam }
123384c406e7SOri Kam 
123484c406e7SOri Kam /**
1235c16e10f1SDariusz Sosnowski  * Validates @p attributes of the flow rule.
1236c16e10f1SDariusz Sosnowski  *
1237c16e10f1SDariusz Sosnowski  * This function is used if and only if legacy Verbs flow engine is used.
1238c16e10f1SDariusz Sosnowski  *
1239c16e10f1SDariusz Sosnowski  * @param[in] dev
1240c16e10f1SDariusz Sosnowski  *   Pointer to the Ethernet device structure.
1241c16e10f1SDariusz Sosnowski  * @param[in] attributes
1242c16e10f1SDariusz Sosnowski  *   Pointer to flow attributes
1243c16e10f1SDariusz Sosnowski  * @param[out] error
1244c16e10f1SDariusz Sosnowski  *   Pointer to error structure.
1245c16e10f1SDariusz Sosnowski  *
1246c16e10f1SDariusz Sosnowski  * @return
1247c16e10f1SDariusz Sosnowski  *   0 on success, a negative errno value otherwise and rte_errno is set.
1248c16e10f1SDariusz Sosnowski  */
1249c16e10f1SDariusz Sosnowski static int
1250c16e10f1SDariusz Sosnowski flow_verbs_validate_attributes(struct rte_eth_dev *dev,
1251c16e10f1SDariusz Sosnowski 			       const struct rte_flow_attr *attributes,
1252c16e10f1SDariusz Sosnowski 			       struct rte_flow_error *error)
1253c16e10f1SDariusz Sosnowski {
1254c16e10f1SDariusz Sosnowski 	struct mlx5_priv *priv = dev->data->dev_private;
1255c16e10f1SDariusz Sosnowski 	uint32_t priority_max = priv->sh->flow_max_priority - 1;
1256c16e10f1SDariusz Sosnowski 
1257c16e10f1SDariusz Sosnowski 	if (attributes->group)
1258c16e10f1SDariusz Sosnowski 		return rte_flow_error_set(error, ENOTSUP,
1259c16e10f1SDariusz Sosnowski 					  RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
1260c16e10f1SDariusz Sosnowski 					  NULL, "groups is not supported");
1261c16e10f1SDariusz Sosnowski 	if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR &&
1262c16e10f1SDariusz Sosnowski 	    attributes->priority >= priority_max)
1263c16e10f1SDariusz Sosnowski 		return rte_flow_error_set(error, ENOTSUP,
1264c16e10f1SDariusz Sosnowski 					  RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
1265c16e10f1SDariusz Sosnowski 					  NULL, "priority out of range");
1266c16e10f1SDariusz Sosnowski 	if (attributes->egress)
1267c16e10f1SDariusz Sosnowski 		return rte_flow_error_set(error, ENOTSUP,
1268c16e10f1SDariusz Sosnowski 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, NULL,
1269c16e10f1SDariusz Sosnowski 					  "egress is not supported");
1270c16e10f1SDariusz Sosnowski 	if (attributes->transfer)
1271c16e10f1SDariusz Sosnowski 		return rte_flow_error_set(error, ENOTSUP,
1272c16e10f1SDariusz Sosnowski 					  RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
1273c16e10f1SDariusz Sosnowski 					  NULL, "transfer is not supported");
1274c16e10f1SDariusz Sosnowski 	if (!attributes->ingress)
1275c16e10f1SDariusz Sosnowski 		return rte_flow_error_set(error, EINVAL,
1276c16e10f1SDariusz Sosnowski 					  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
1277c16e10f1SDariusz Sosnowski 					  NULL,
1278c16e10f1SDariusz Sosnowski 					  "ingress attribute is mandatory");
1279c16e10f1SDariusz Sosnowski 	return 0;
1280c16e10f1SDariusz Sosnowski }
1281c16e10f1SDariusz Sosnowski 
1282c16e10f1SDariusz Sosnowski /**
128384c406e7SOri Kam  * Internal validation function. For validating both actions and items.
128484c406e7SOri Kam  *
128584c406e7SOri Kam  * @param[in] dev
128684c406e7SOri Kam  *   Pointer to the Ethernet device structure.
128784c406e7SOri Kam  * @param[in] attr
128884c406e7SOri Kam  *   Pointer to the flow attributes.
128984c406e7SOri Kam  * @param[in] items
129084c406e7SOri Kam  *   Pointer to the list of items.
129184c406e7SOri Kam  * @param[in] actions
129284c406e7SOri Kam  *   Pointer to the list of actions.
1293b67b4ecbSDekel Peled  * @param[in] external
1294b67b4ecbSDekel Peled  *   This flow rule is created by request external to PMD.
129572a944dbSBing Zhao  * @param[in] hairpin
129672a944dbSBing Zhao  *   Number of hairpin TX actions, 0 means classic flow.
129784c406e7SOri Kam  * @param[out] error
129884c406e7SOri Kam  *   Pointer to the error structure.
129984c406e7SOri Kam  *
130084c406e7SOri Kam  * @return
130184c406e7SOri Kam  *   0 on success, a negative errno value otherwise and rte_errno is set.
130284c406e7SOri Kam  */
130384c406e7SOri Kam static int
130484c406e7SOri Kam flow_verbs_validate(struct rte_eth_dev *dev,
130584c406e7SOri Kam 		    const struct rte_flow_attr *attr,
130684c406e7SOri Kam 		    const struct rte_flow_item items[],
130784c406e7SOri Kam 		    const struct rte_flow_action actions[],
1308b67b4ecbSDekel Peled 		    bool external __rte_unused,
130972a944dbSBing Zhao 		    int hairpin __rte_unused,
131084c406e7SOri Kam 		    struct rte_flow_error *error)
131184c406e7SOri Kam {
131284c406e7SOri Kam 	int ret;
13130ddd1143SYongseok Koh 	uint64_t action_flags = 0;
13140ddd1143SYongseok Koh 	uint64_t item_flags = 0;
131538f7efaaSDekel Peled 	uint64_t last_item = 0;
131684c406e7SOri Kam 	uint8_t next_protocol = 0xff;
1317fba32130SXiaoyu Min 	uint16_t ether_type = 0;
1318b6aaaa22SShiri Kuzin 	bool is_empty_vlan = false;
1319a1fd0c82SRongwei Liu 	uint16_t udp_dport = 0;
1320c1f0cdaeSDariusz Sosnowski 	/* Verbs interface does not support groups higher than 0. */
1321c1f0cdaeSDariusz Sosnowski 	bool is_root = true;
132284c406e7SOri Kam 
132384c406e7SOri Kam 	if (items == NULL)
132484c406e7SOri Kam 		return -1;
1325c16e10f1SDariusz Sosnowski 	ret = flow_verbs_validate_attributes(dev, attr, error);
132684c406e7SOri Kam 	if (ret < 0)
132784c406e7SOri Kam 		return ret;
132884c406e7SOri Kam 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
13294a78c88eSYongseok Koh 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
133084c406e7SOri Kam 		int ret = 0;
133124663641SYongseok Koh 
133284c406e7SOri Kam 		switch (items->type) {
133390385c46SMaayan Kashani #ifdef HAVE_IBV_FLOW_SPEC_ESP
133472185352SMaayan Kashani 		case RTE_FLOW_ITEM_TYPE_ESP:
133580c67625SGregory Etelson 			ret = mlx5_flow_os_validate_item_esp(dev, items,
133680c67625SGregory Etelson 							     item_flags,
133772185352SMaayan Kashani 							     next_protocol,
133872185352SMaayan Kashani 							     error);
133972185352SMaayan Kashani 			if (ret < 0)
134072185352SMaayan Kashani 				return ret;
134172185352SMaayan Kashani 			last_item = MLX5_FLOW_ITEM_ESP;
134272185352SMaayan Kashani 			break;
134390385c46SMaayan Kashani #endif
134484c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VOID:
134584c406e7SOri Kam 			break;
134684c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_ETH:
134780c67625SGregory Etelson 			ret = mlx5_flow_validate_item_eth(dev, items, item_flags,
134886b59a1aSMatan Azrad 							  false, error);
134984c406e7SOri Kam 			if (ret < 0)
135084c406e7SOri Kam 				return ret;
135138f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
135284c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L2;
1353fba32130SXiaoyu Min 			if (items->mask != NULL && items->spec != NULL) {
1354fba32130SXiaoyu Min 				ether_type =
1355fba32130SXiaoyu Min 					((const struct rte_flow_item_eth *)
13568275d5fcSThomas Monjalon 					 items->spec)->hdr.ether_type;
1357fba32130SXiaoyu Min 				ether_type &=
1358fba32130SXiaoyu Min 					((const struct rte_flow_item_eth *)
13598275d5fcSThomas Monjalon 					 items->mask)->hdr.ether_type;
1360b6aaaa22SShiri Kuzin 				if (ether_type == RTE_BE16(RTE_ETHER_TYPE_VLAN))
1361b6aaaa22SShiri Kuzin 					is_empty_vlan = true;
1362fba32130SXiaoyu Min 				ether_type = rte_be_to_cpu_16(ether_type);
1363fba32130SXiaoyu Min 			} else {
1364fba32130SXiaoyu Min 				ether_type = 0;
1365fba32130SXiaoyu Min 			}
136684c406e7SOri Kam 			break;
136784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VLAN:
136884c406e7SOri Kam 			ret = mlx5_flow_validate_item_vlan(items, item_flags,
1369dfedf3e3SViacheslav Ovsiienko 							   dev, error);
137084c406e7SOri Kam 			if (ret < 0)
137184c406e7SOri Kam 				return ret;
137238f7efaaSDekel Peled 			last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
13734a78c88eSYongseok Koh 					      MLX5_FLOW_LAYER_INNER_VLAN) :
13744a78c88eSYongseok Koh 					     (MLX5_FLOW_LAYER_OUTER_L2 |
13754a78c88eSYongseok Koh 					      MLX5_FLOW_LAYER_OUTER_VLAN);
1376fba32130SXiaoyu Min 			if (items->mask != NULL && items->spec != NULL) {
1377fba32130SXiaoyu Min 				ether_type =
1378fba32130SXiaoyu Min 					((const struct rte_flow_item_vlan *)
13798275d5fcSThomas Monjalon 					 items->spec)->hdr.eth_proto;
1380fba32130SXiaoyu Min 				ether_type &=
1381fba32130SXiaoyu Min 					((const struct rte_flow_item_vlan *)
13828275d5fcSThomas Monjalon 					 items->mask)->hdr.eth_proto;
1383fba32130SXiaoyu Min 				ether_type = rte_be_to_cpu_16(ether_type);
1384fba32130SXiaoyu Min 			} else {
1385fba32130SXiaoyu Min 				ether_type = 0;
1386fba32130SXiaoyu Min 			}
1387b6aaaa22SShiri Kuzin 			is_empty_vlan = false;
138884c406e7SOri Kam 			break;
138984c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV4:
13906859e67eSDekel Peled 			ret = mlx5_flow_validate_item_ipv4
139180c67625SGregory Etelson 						(dev, items, item_flags,
13926859e67eSDekel Peled 						 last_item, ether_type, NULL,
13936859e67eSDekel Peled 						 MLX5_ITEM_RANGE_NOT_ACCEPTED,
1394fba32130SXiaoyu Min 						 error);
139584c406e7SOri Kam 			if (ret < 0)
139684c406e7SOri Kam 				return ret;
139738f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
139884c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
139984c406e7SOri Kam 			if (items->mask != NULL &&
140084c406e7SOri Kam 			    ((const struct rte_flow_item_ipv4 *)
14013193c249SYongseok Koh 			     items->mask)->hdr.next_proto_id) {
140284c406e7SOri Kam 				next_protocol =
140384c406e7SOri Kam 					((const struct rte_flow_item_ipv4 *)
140484c406e7SOri Kam 					 (items->spec))->hdr.next_proto_id;
14053193c249SYongseok Koh 				next_protocol &=
14063193c249SYongseok Koh 					((const struct rte_flow_item_ipv4 *)
14073193c249SYongseok Koh 					 (items->mask))->hdr.next_proto_id;
14083193c249SYongseok Koh 			} else {
14093193c249SYongseok Koh 				/* Reset for inner layer. */
14103193c249SYongseok Koh 				next_protocol = 0xff;
14113193c249SYongseok Koh 			}
141284c406e7SOri Kam 			break;
141384c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV6:
141480c67625SGregory Etelson 			ret = mlx5_flow_validate_item_ipv6(dev, items,
141580c67625SGregory Etelson 							   item_flags,
1416fba32130SXiaoyu Min 							   last_item,
1417fba32130SXiaoyu Min 							   ether_type, NULL,
1418fba32130SXiaoyu Min 							   error);
141984c406e7SOri Kam 			if (ret < 0)
142084c406e7SOri Kam 				return ret;
142138f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
142284c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
142384c406e7SOri Kam 			if (items->mask != NULL &&
142484c406e7SOri Kam 			    ((const struct rte_flow_item_ipv6 *)
14253193c249SYongseok Koh 			     items->mask)->hdr.proto) {
142684c406e7SOri Kam 				next_protocol =
142784c406e7SOri Kam 					((const struct rte_flow_item_ipv6 *)
142884c406e7SOri Kam 					 items->spec)->hdr.proto;
14293193c249SYongseok Koh 				next_protocol &=
14303193c249SYongseok Koh 					((const struct rte_flow_item_ipv6 *)
14313193c249SYongseok Koh 					 items->mask)->hdr.proto;
14323193c249SYongseok Koh 			} else {
14333193c249SYongseok Koh 				/* Reset for inner layer. */
14343193c249SYongseok Koh 				next_protocol = 0xff;
14353193c249SYongseok Koh 			}
143684c406e7SOri Kam 			break;
143784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_UDP:
143880c67625SGregory Etelson 			ret = mlx5_flow_validate_item_udp(dev, items,
143980c67625SGregory Etelson 							  item_flags,
144084c406e7SOri Kam 							  next_protocol,
144184c406e7SOri Kam 							  error);
1442a1fd0c82SRongwei Liu 			const struct rte_flow_item_udp *spec = items->spec;
1443a1fd0c82SRongwei Liu 			const struct rte_flow_item_udp *mask = items->mask;
1444a1fd0c82SRongwei Liu 			if (!mask)
1445a1fd0c82SRongwei Liu 				mask = &rte_flow_item_udp_mask;
1446a1fd0c82SRongwei Liu 			if (spec != NULL)
1447a1fd0c82SRongwei Liu 				udp_dport = rte_be_to_cpu_16
1448a1fd0c82SRongwei Liu 						(spec->hdr.dst_port &
1449a1fd0c82SRongwei Liu 						 mask->hdr.dst_port);
1450a1fd0c82SRongwei Liu 
145184c406e7SOri Kam 			if (ret < 0)
145284c406e7SOri Kam 				return ret;
145338f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
145484c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
145584c406e7SOri Kam 			break;
145684c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_TCP:
145792378c2bSMoti Haimovsky 			ret = mlx5_flow_validate_item_tcp
145880c67625SGregory Etelson 						(dev, items, item_flags,
145992378c2bSMoti Haimovsky 						 next_protocol,
146092378c2bSMoti Haimovsky 						 &rte_flow_item_tcp_mask,
146192378c2bSMoti Haimovsky 						 error);
146284c406e7SOri Kam 			if (ret < 0)
146384c406e7SOri Kam 				return ret;
146438f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
146584c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
146684c406e7SOri Kam 			break;
146784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN:
1468a1fd0c82SRongwei Liu 			ret = mlx5_flow_validate_item_vxlan(dev, udp_dport,
1469a1fd0c82SRongwei Liu 							    items, item_flags,
14701939eb6fSDariusz Sosnowski 							    is_root, error);
147184c406e7SOri Kam 			if (ret < 0)
147284c406e7SOri Kam 				return ret;
147338f7efaaSDekel Peled 			last_item = MLX5_FLOW_LAYER_VXLAN;
147484c406e7SOri Kam 			break;
147584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
147684c406e7SOri Kam 			ret = mlx5_flow_validate_item_vxlan_gpe(items,
147784c406e7SOri Kam 								item_flags,
147884c406e7SOri Kam 								dev, error);
147984c406e7SOri Kam 			if (ret < 0)
148084c406e7SOri Kam 				return ret;
148138f7efaaSDekel Peled 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
148284c406e7SOri Kam 			break;
148384c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_GRE:
148480c67625SGregory Etelson 			ret = mlx5_flow_validate_item_gre(dev, items, item_flags,
148584c406e7SOri Kam 							  next_protocol, error);
148684c406e7SOri Kam 			if (ret < 0)
148784c406e7SOri Kam 				return ret;
148838f7efaaSDekel Peled 			last_item = MLX5_FLOW_LAYER_GRE;
148984c406e7SOri Kam 			break;
149084c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_MPLS:
149138f7efaaSDekel Peled 			ret = mlx5_flow_validate_item_mpls(dev, items,
149238f7efaaSDekel Peled 							   item_flags,
149338f7efaaSDekel Peled 							   last_item, error);
149484c406e7SOri Kam 			if (ret < 0)
149584c406e7SOri Kam 				return ret;
149638f7efaaSDekel Peled 			last_item = MLX5_FLOW_LAYER_MPLS;
149784c406e7SOri Kam 			break;
149858df16e0SDekel Peled 		case RTE_FLOW_ITEM_TYPE_ICMP:
149958df16e0SDekel Peled 		case RTE_FLOW_ITEM_TYPE_ICMP6:
150084c406e7SOri Kam 			return rte_flow_error_set(error, ENOTSUP,
150184c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ITEM,
150258df16e0SDekel Peled 						  NULL, "ICMP/ICMP6 "
150358df16e0SDekel Peled 						  "item not supported");
150458df16e0SDekel Peled 		default:
150558df16e0SDekel Peled 			return rte_flow_error_set(error, ENOTSUP,
150658df16e0SDekel Peled 						  RTE_FLOW_ERROR_TYPE_ITEM,
150758df16e0SDekel Peled 						  NULL, "item not supported");
150884c406e7SOri Kam 		}
150938f7efaaSDekel Peled 		item_flags |= last_item;
151084c406e7SOri Kam 	}
1511b6aaaa22SShiri Kuzin 	if (is_empty_vlan)
1512b6aaaa22SShiri Kuzin 		return rte_flow_error_set(error, ENOTSUP,
1513b6aaaa22SShiri Kuzin 						 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1514b6aaaa22SShiri Kuzin 		    "VLAN matching without vid specification is not supported");
151584c406e7SOri Kam 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
151684c406e7SOri Kam 		switch (actions->type) {
151784c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_VOID:
151884c406e7SOri Kam 			break;
151984c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_FLAG:
152084c406e7SOri Kam 			ret = mlx5_flow_validate_action_flag(action_flags,
15213e9fa079SDekel Peled 							     attr,
152284c406e7SOri Kam 							     error);
152384c406e7SOri Kam 			if (ret < 0)
152484c406e7SOri Kam 				return ret;
152584c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_FLAG;
152684c406e7SOri Kam 			break;
152784c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_MARK:
1528d6dc072aSGregory Etelson 			ret = mlx5_flow_validate_action_mark(dev, actions,
152984c406e7SOri Kam 							     action_flags,
15303e9fa079SDekel Peled 							     attr,
153184c406e7SOri Kam 							     error);
153284c406e7SOri Kam 			if (ret < 0)
153384c406e7SOri Kam 				return ret;
153484c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_MARK;
153584c406e7SOri Kam 			break;
153684c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_DROP:
1537c1f0cdaeSDariusz Sosnowski 			ret = mlx5_flow_validate_action_drop(dev,
1538c1f0cdaeSDariusz Sosnowski 							     is_root,
15393e9fa079SDekel Peled 							     attr,
154084c406e7SOri Kam 							     error);
154184c406e7SOri Kam 			if (ret < 0)
154284c406e7SOri Kam 				return ret;
154384c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_DROP;
154484c406e7SOri Kam 			break;
154584c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_QUEUE:
154684c406e7SOri Kam 			ret = mlx5_flow_validate_action_queue(actions,
154784c406e7SOri Kam 							      action_flags, dev,
15483e9fa079SDekel Peled 							      attr,
154984c406e7SOri Kam 							      error);
155084c406e7SOri Kam 			if (ret < 0)
155184c406e7SOri Kam 				return ret;
155284c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
155384c406e7SOri Kam 			break;
155484c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_RSS:
155584c406e7SOri Kam 			ret = mlx5_flow_validate_action_rss(actions,
155684c406e7SOri Kam 							    action_flags, dev,
15571183f12fSOri Kam 							    attr, item_flags,
155884c406e7SOri Kam 							    error);
155984c406e7SOri Kam 			if (ret < 0)
156084c406e7SOri Kam 				return ret;
156184c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_RSS;
156284c406e7SOri Kam 			break;
156384c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_COUNT:
15643e9fa079SDekel Peled 			ret = mlx5_flow_validate_action_count(dev, attr, error);
156584c406e7SOri Kam 			if (ret < 0)
156684c406e7SOri Kam 				return ret;
156784c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_COUNT;
156884c406e7SOri Kam 			break;
156984c406e7SOri Kam 		default:
157084c406e7SOri Kam 			return rte_flow_error_set(error, ENOTSUP,
157184c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ACTION,
157284c406e7SOri Kam 						  actions,
157384c406e7SOri Kam 						  "action not supported");
157484c406e7SOri Kam 		}
157584c406e7SOri Kam 	}
157670faf9aeSDekel Peled 	/*
157770faf9aeSDekel Peled 	 * Validate the drop action mutual exclusion with other actions.
157870faf9aeSDekel Peled 	 * Drop action is mutually-exclusive with any other action, except for
157970faf9aeSDekel Peled 	 * Count action.
158070faf9aeSDekel Peled 	 */
158170faf9aeSDekel Peled 	if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
158270faf9aeSDekel Peled 	    (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT)))
158370faf9aeSDekel Peled 		return rte_flow_error_set(error, EINVAL,
158470faf9aeSDekel Peled 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
158570faf9aeSDekel Peled 					  "Drop action is mutually-exclusive "
158670faf9aeSDekel Peled 					  "with any other action, except for "
158770faf9aeSDekel Peled 					  "Count action");
158884c406e7SOri Kam 	if (!(action_flags & MLX5_FLOW_FATE_ACTIONS))
158984c406e7SOri Kam 		return rte_flow_error_set(error, EINVAL,
159084c406e7SOri Kam 					  RTE_FLOW_ERROR_TYPE_ACTION, actions,
159184c406e7SOri Kam 					  "no fate action is found");
159284c406e7SOri Kam 	return 0;
159384c406e7SOri Kam }
159484c406e7SOri Kam 
159584c406e7SOri Kam /**
159684c406e7SOri Kam  * Calculate the required bytes that are needed for the action part of the verbs
1597c1cfb132SYongseok Koh  * flow.
159884c406e7SOri Kam  *
159984c406e7SOri Kam  * @param[in] actions
160084c406e7SOri Kam  *   Pointer to the list of actions.
160184c406e7SOri Kam  *
160284c406e7SOri Kam  * @return
160384c406e7SOri Kam  *   The size of the memory needed for all actions.
160484c406e7SOri Kam  */
160584c406e7SOri Kam static int
1606c1cfb132SYongseok Koh flow_verbs_get_actions_size(const struct rte_flow_action actions[])
160784c406e7SOri Kam {
160884c406e7SOri Kam 	int size = 0;
160984c406e7SOri Kam 
161084c406e7SOri Kam 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
161184c406e7SOri Kam 		switch (actions->type) {
161284c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_VOID:
161384c406e7SOri Kam 			break;
161484c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_FLAG:
161584c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_action_tag);
161684c406e7SOri Kam 			break;
161784c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_MARK:
161884c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_action_tag);
161984c406e7SOri Kam 			break;
162084c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_DROP:
162184c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_action_drop);
162284c406e7SOri Kam 			break;
162384c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_QUEUE:
162484c406e7SOri Kam 			break;
162584c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_RSS:
162684c406e7SOri Kam 			break;
162784c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_COUNT:
1628db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
1629db48f9dbSViacheslav Ovsiienko 	defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
163084c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_counter_action);
163184c406e7SOri Kam #endif
163284c406e7SOri Kam 			break;
163384c406e7SOri Kam 		default:
163484c406e7SOri Kam 			break;
163584c406e7SOri Kam 		}
163684c406e7SOri Kam 	}
163784c406e7SOri Kam 	return size;
163884c406e7SOri Kam }
163984c406e7SOri Kam 
164084c406e7SOri Kam /**
164184c406e7SOri Kam  * Calculate the required bytes that are needed for the item part of the verbs
1642c1cfb132SYongseok Koh  * flow.
164384c406e7SOri Kam  *
1644c1cfb132SYongseok Koh  * @param[in] items
164584c406e7SOri Kam  *   Pointer to the list of items.
164684c406e7SOri Kam  *
164784c406e7SOri Kam  * @return
164884c406e7SOri Kam  *   The size of the memory needed for all items.
164984c406e7SOri Kam  */
165084c406e7SOri Kam static int
1651c1cfb132SYongseok Koh flow_verbs_get_items_size(const struct rte_flow_item items[])
165284c406e7SOri Kam {
165384c406e7SOri Kam 	int size = 0;
165484c406e7SOri Kam 
165584c406e7SOri Kam 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
165684c406e7SOri Kam 		switch (items->type) {
165784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VOID:
165884c406e7SOri Kam 			break;
165984c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_ETH:
166084c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_eth);
166184c406e7SOri Kam 			break;
166284c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VLAN:
166384c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_eth);
166484c406e7SOri Kam 			break;
166584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV4:
166684c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_ipv4_ext);
166784c406e7SOri Kam 			break;
166884c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV6:
166984c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_ipv6);
167084c406e7SOri Kam 			break;
167184c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_UDP:
167284c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tcp_udp);
167384c406e7SOri Kam 			break;
167484c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_TCP:
167584c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tcp_udp);
167684c406e7SOri Kam 			break;
167784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN:
167884c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tunnel);
167984c406e7SOri Kam 			break;
168084c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
168184c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tunnel);
168284c406e7SOri Kam 			break;
168384c406e7SOri Kam #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
168484c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_GRE:
168584c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_gre);
168684c406e7SOri Kam 			break;
168784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_MPLS:
168884c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_mpls);
168984c406e7SOri Kam 			break;
169084c406e7SOri Kam #else
169184c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_GRE:
169284c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tunnel);
169384c406e7SOri Kam 			break;
169484c406e7SOri Kam #endif
169584c406e7SOri Kam 		default:
169684c406e7SOri Kam 			break;
169784c406e7SOri Kam 		}
169884c406e7SOri Kam 	}
169984c406e7SOri Kam 	return size;
170084c406e7SOri Kam }
170184c406e7SOri Kam 
170284c406e7SOri Kam /**
170384c406e7SOri Kam  * Internal preparation function. Allocate mlx5_flow with the required size.
170484c406e7SOri Kam  * The required size is calculate based on the actions and items. This function
170584c406e7SOri Kam  * also returns the detected actions and items for later use.
170684c406e7SOri Kam  *
1707e7bfa359SBing Zhao  * @param[in] dev
1708e7bfa359SBing Zhao  *   Pointer to Ethernet device.
170984c406e7SOri Kam  * @param[in] attr
171084c406e7SOri Kam  *   Pointer to the flow attributes.
171184c406e7SOri Kam  * @param[in] items
171284c406e7SOri Kam  *   Pointer to the list of items.
171384c406e7SOri Kam  * @param[in] actions
171484c406e7SOri Kam  *   Pointer to the list of actions.
171584c406e7SOri Kam  * @param[out] error
171684c406e7SOri Kam  *   Pointer to the error structure.
171784c406e7SOri Kam  *
171884c406e7SOri Kam  * @return
171984c406e7SOri Kam  *   Pointer to mlx5_flow object on success, otherwise NULL and rte_errno
172084c406e7SOri Kam  *   is set.
172184c406e7SOri Kam  */
172284c406e7SOri Kam static struct mlx5_flow *
1723e7bfa359SBing Zhao flow_verbs_prepare(struct rte_eth_dev *dev,
1724e7bfa359SBing Zhao 		   const struct rte_flow_attr *attr __rte_unused,
172584c406e7SOri Kam 		   const struct rte_flow_item items[],
172684c406e7SOri Kam 		   const struct rte_flow_action actions[],
172784c406e7SOri Kam 		   struct rte_flow_error *error)
172884c406e7SOri Kam {
1729e7bfa359SBing Zhao 	size_t size = 0;
1730b88341caSSuanming Mou 	uint32_t handle_idx = 0;
1731e205c95fSViacheslav Ovsiienko 	struct mlx5_flow *dev_flow;
1732e7bfa359SBing Zhao 	struct mlx5_flow_handle *dev_handle;
1733e7bfa359SBing Zhao 	struct mlx5_priv *priv = dev->data->dev_private;
17348bb81f26SXueming Li 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
173584c406e7SOri Kam 
17368bb81f26SXueming Li 	MLX5_ASSERT(wks);
1737c1cfb132SYongseok Koh 	size += flow_verbs_get_actions_size(actions);
1738c1cfb132SYongseok Koh 	size += flow_verbs_get_items_size(items);
1739e7bfa359SBing Zhao 	if (size > MLX5_VERBS_MAX_SPEC_ACT_SIZE) {
1740e7bfa359SBing Zhao 		rte_flow_error_set(error, E2BIG,
174184c406e7SOri Kam 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1742e7bfa359SBing Zhao 				   "Verbs spec/action size too large");
174384c406e7SOri Kam 		return NULL;
174484c406e7SOri Kam 	}
1745e7bfa359SBing Zhao 	/* In case of corrupting the memory. */
17468bb81f26SXueming Li 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
1747e7bfa359SBing Zhao 		rte_flow_error_set(error, ENOSPC,
1748e7bfa359SBing Zhao 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1749e7bfa359SBing Zhao 				   "not free temporary device flow");
1750e7bfa359SBing Zhao 		return NULL;
1751e7bfa359SBing Zhao 	}
1752b88341caSSuanming Mou 	dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
1753b88341caSSuanming Mou 				   &handle_idx);
1754e7bfa359SBing Zhao 	if (!dev_handle) {
1755e7bfa359SBing Zhao 		rte_flow_error_set(error, ENOMEM,
1756e7bfa359SBing Zhao 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1757e7bfa359SBing Zhao 				   "not enough memory to create flow handle");
1758e7bfa359SBing Zhao 		return NULL;
1759e7bfa359SBing Zhao 	}
17608bb81f26SXueming Li 	MLX5_ASSERT(wks->flow_idx + 1 < RTE_DIM(wks->flows));
17618bb81f26SXueming Li 	dev_flow = &wks->flows[wks->flow_idx++];
1762e7bfa359SBing Zhao 	dev_flow->handle = dev_handle;
1763b88341caSSuanming Mou 	dev_flow->handle_idx = handle_idx;
1764e7bfa359SBing Zhao 	/* Memcpy is used, only size needs to be cleared to 0. */
1765e7bfa359SBing Zhao 	dev_flow->verbs.size = 0;
1766e7bfa359SBing Zhao 	dev_flow->verbs.attr.num_of_specs = 0;
1767e205c95fSViacheslav Ovsiienko 	dev_flow->ingress = attr->ingress;
17680efc99beSOphir Munk 	dev_flow->hash_fields = 0;
1769c42f44bdSBing Zhao 	/* Need to set transfer attribute: not supported in Verbs mode. */
1770e205c95fSViacheslav Ovsiienko 	return dev_flow;
177184c406e7SOri Kam }
177284c406e7SOri Kam 
177384c406e7SOri Kam /**
177484c406e7SOri Kam  * Fill the flow with verb spec.
177584c406e7SOri Kam  *
177684c406e7SOri Kam  * @param[in] dev
177784c406e7SOri Kam  *   Pointer to Ethernet device.
177884c406e7SOri Kam  * @param[in, out] dev_flow
177984c406e7SOri Kam  *   Pointer to the mlx5 flow.
178084c406e7SOri Kam  * @param[in] attr
178184c406e7SOri Kam  *   Pointer to the flow attributes.
178284c406e7SOri Kam  * @param[in] items
178384c406e7SOri Kam  *   Pointer to the list of items.
178484c406e7SOri Kam  * @param[in] actions
178584c406e7SOri Kam  *   Pointer to the list of actions.
178684c406e7SOri Kam  * @param[out] error
178784c406e7SOri Kam  *   Pointer to the error structure.
178884c406e7SOri Kam  *
178984c406e7SOri Kam  * @return
1790de90612fSDekel Peled  *   0 on success, else a negative errno value otherwise and rte_errno is set.
179184c406e7SOri Kam  */
179284c406e7SOri Kam static int
179384c406e7SOri Kam flow_verbs_translate(struct rte_eth_dev *dev,
179484c406e7SOri Kam 		     struct mlx5_flow *dev_flow,
179584c406e7SOri Kam 		     const struct rte_flow_attr *attr,
179684c406e7SOri Kam 		     const struct rte_flow_item items[],
179784c406e7SOri Kam 		     const struct rte_flow_action actions[],
179884c406e7SOri Kam 		     struct rte_flow_error *error)
179984c406e7SOri Kam {
180084c406e7SOri Kam 	uint64_t item_flags = 0;
18014a78c88eSYongseok Koh 	uint64_t action_flags = 0;
180284c406e7SOri Kam 	uint64_t priority = attr->priority;
18034a78c88eSYongseok Koh 	uint32_t subpriority = 0;
1804dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
18058bb81f26SXueming Li 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
18068bb81f26SXueming Li 	struct mlx5_flow_rss_desc *rss_desc;
1807df498655SGregory Etelson 	const struct rte_flow_item *tunnel_item = NULL;
180898008ce6SDariusz Sosnowski 	uint8_t *gre_spec = NULL;
180984c406e7SOri Kam 
18108bb81f26SXueming Li 	MLX5_ASSERT(wks);
18110064bf43SXueming Li 	rss_desc = &wks->rss_desc;
18125f8ae44dSDong Zhou 	if (priority == MLX5_FLOW_LOWEST_PRIO_INDICATOR)
18133c4338a4SJiawei Wang 		priority = priv->sh->flow_max_priority - 1;
181484c406e7SOri Kam 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
181584c406e7SOri Kam 		int ret;
18164a78c88eSYongseok Koh 
181784c406e7SOri Kam 		switch (actions->type) {
181884c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_VOID:
181984c406e7SOri Kam 			break;
182084c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_FLAG:
18214a78c88eSYongseok Koh 			flow_verbs_translate_action_flag(dev_flow, actions);
18224a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_FLAG;
1823082becbfSRaja Zidane 			wks->mark = 1;
182484c406e7SOri Kam 			break;
182584c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_MARK:
18264a78c88eSYongseok Koh 			flow_verbs_translate_action_mark(dev_flow, actions);
18274a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_MARK;
1828082becbfSRaja Zidane 			wks->mark = 1;
182984c406e7SOri Kam 			break;
183084c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_DROP:
18314a78c88eSYongseok Koh 			flow_verbs_translate_action_drop(dev_flow, actions);
18324a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_DROP;
1833488d13abSSuanming Mou 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
183484c406e7SOri Kam 			break;
183584c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_QUEUE:
1836e745f900SSuanming Mou 			flow_verbs_translate_action_queue(rss_desc, actions);
18374a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
1838488d13abSSuanming Mou 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
183984c406e7SOri Kam 			break;
184084c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_RSS:
1841e745f900SSuanming Mou 			flow_verbs_translate_action_rss(rss_desc, actions);
18424a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_RSS;
1843488d13abSSuanming Mou 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
184484c406e7SOri Kam 			break;
184584c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_COUNT:
18464a78c88eSYongseok Koh 			ret = flow_verbs_translate_action_count(dev_flow,
184784c406e7SOri Kam 								actions,
18484a78c88eSYongseok Koh 								dev, error);
184984c406e7SOri Kam 			if (ret < 0)
185084c406e7SOri Kam 				return ret;
18514a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_COUNT;
185284c406e7SOri Kam 			break;
185384c406e7SOri Kam 		default:
185484c406e7SOri Kam 			return rte_flow_error_set(error, ENOTSUP,
185584c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ACTION,
185684c406e7SOri Kam 						  actions,
185784c406e7SOri Kam 						  "action not supported");
185884c406e7SOri Kam 		}
185984c406e7SOri Kam 	}
1860488d13abSSuanming Mou 	dev_flow->act_flags = action_flags;
186184c406e7SOri Kam 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
18624a78c88eSYongseok Koh 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
18634a78c88eSYongseok Koh 
186484c406e7SOri Kam 		switch (items->type) {
186584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VOID:
186684c406e7SOri Kam 			break;
186784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_ETH:
18684a78c88eSYongseok Koh 			flow_verbs_translate_item_eth(dev_flow, items,
18694a78c88eSYongseok Koh 						      item_flags);
18704a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L2;
18714a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
18724a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L2;
187384c406e7SOri Kam 			break;
187484c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VLAN:
18754a78c88eSYongseok Koh 			flow_verbs_translate_item_vlan(dev_flow, items,
18764a78c88eSYongseok Koh 						       item_flags);
18774a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L2;
18784a78c88eSYongseok Koh 			item_flags |= tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
18794a78c88eSYongseok Koh 						MLX5_FLOW_LAYER_INNER_VLAN) :
18804a78c88eSYongseok Koh 					       (MLX5_FLOW_LAYER_OUTER_L2 |
18814a78c88eSYongseok Koh 						MLX5_FLOW_LAYER_OUTER_VLAN);
188284c406e7SOri Kam 			break;
188384c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV4:
18844a78c88eSYongseok Koh 			flow_verbs_translate_item_ipv4(dev_flow, items,
18854a78c88eSYongseok Koh 						       item_flags);
18864a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L3;
1887e205c95fSViacheslav Ovsiienko 			dev_flow->hash_fields |=
18884a78c88eSYongseok Koh 				mlx5_flow_hashfields_adjust
1889e745f900SSuanming Mou 					(rss_desc, tunnel,
18904a78c88eSYongseok Koh 					 MLX5_IPV4_LAYER_TYPES,
18914a78c88eSYongseok Koh 					 MLX5_IPV4_IBV_RX_HASH);
18924a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
18934a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L3_IPV4;
189484c406e7SOri Kam 			break;
189584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV6:
18964a78c88eSYongseok Koh 			flow_verbs_translate_item_ipv6(dev_flow, items,
18974a78c88eSYongseok Koh 						       item_flags);
18984a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L3;
1899e205c95fSViacheslav Ovsiienko 			dev_flow->hash_fields |=
19004a78c88eSYongseok Koh 				mlx5_flow_hashfields_adjust
1901e745f900SSuanming Mou 					(rss_desc, tunnel,
19024a78c88eSYongseok Koh 					 MLX5_IPV6_LAYER_TYPES,
19034a78c88eSYongseok Koh 					 MLX5_IPV6_IBV_RX_HASH);
19044a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
19054a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L3_IPV6;
190684c406e7SOri Kam 			break;
190784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_TCP:
19084a78c88eSYongseok Koh 			flow_verbs_translate_item_tcp(dev_flow, items,
19094a78c88eSYongseok Koh 						      item_flags);
19104a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L4;
19115e1db76dSLior Margalit 			if (dev_flow->hash_fields != 0)
1912e205c95fSViacheslav Ovsiienko 				dev_flow->hash_fields |=
19134a78c88eSYongseok Koh 					mlx5_flow_hashfields_adjust
1914295968d1SFerruh Yigit 					(rss_desc, tunnel, RTE_ETH_RSS_TCP,
19154a78c88eSYongseok Koh 					 (IBV_RX_HASH_SRC_PORT_TCP |
19164a78c88eSYongseok Koh 					  IBV_RX_HASH_DST_PORT_TCP));
19174a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
19184a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L4_TCP;
19194a78c88eSYongseok Koh 			break;
19204a78c88eSYongseok Koh 		case RTE_FLOW_ITEM_TYPE_UDP:
19214a78c88eSYongseok Koh 			flow_verbs_translate_item_udp(dev_flow, items,
19224a78c88eSYongseok Koh 						      item_flags);
19234a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L4;
19245e1db76dSLior Margalit 			if (dev_flow->hash_fields != 0)
1925e205c95fSViacheslav Ovsiienko 				dev_flow->hash_fields |=
19264a78c88eSYongseok Koh 					mlx5_flow_hashfields_adjust
1927295968d1SFerruh Yigit 					(rss_desc, tunnel, RTE_ETH_RSS_UDP,
19284a78c88eSYongseok Koh 					 (IBV_RX_HASH_SRC_PORT_UDP |
19294a78c88eSYongseok Koh 					  IBV_RX_HASH_DST_PORT_UDP));
19304a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
19314a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L4_UDP;
193284c406e7SOri Kam 			break;
193372185352SMaayan Kashani #ifdef HAVE_IBV_FLOW_SPEC_ESP
193472185352SMaayan Kashani 		case RTE_FLOW_ITEM_TYPE_ESP:
193572185352SMaayan Kashani 			flow_verbs_translate_item_esp(dev_flow, items,
193672185352SMaayan Kashani 						      item_flags);
193772185352SMaayan Kashani 			dev_flow->hash_fields |=
193872185352SMaayan Kashani 				mlx5_flow_hashfields_adjust
193972185352SMaayan Kashani 				(rss_desc, tunnel,
194072185352SMaayan Kashani 				RTE_ETH_RSS_ESP,
194172185352SMaayan Kashani 				IBV_RX_HASH_IPSEC_SPI);
194272185352SMaayan Kashani 			item_flags |= MLX5_FLOW_ITEM_ESP;
194372185352SMaayan Kashani 			break;
194472185352SMaayan Kashani #endif
194584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN:
19464a78c88eSYongseok Koh 			flow_verbs_translate_item_vxlan(dev_flow, items,
19474a78c88eSYongseok Koh 							item_flags);
1948750ff30aSGregory Etelson 			subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
19494a78c88eSYongseok Koh 			item_flags |= MLX5_FLOW_LAYER_VXLAN;
195084c406e7SOri Kam 			break;
195184c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
19524a78c88eSYongseok Koh 			flow_verbs_translate_item_vxlan_gpe(dev_flow, items,
19534a78c88eSYongseok Koh 							    item_flags);
1954750ff30aSGregory Etelson 			subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
19554a78c88eSYongseok Koh 			item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE;
195684c406e7SOri Kam 			break;
195784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_GRE:
195898008ce6SDariusz Sosnowski 			gre_spec = flow_verbs_reserve_gre(dev_flow);
1959750ff30aSGregory Etelson 			subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
19604a78c88eSYongseok Koh 			item_flags |= MLX5_FLOW_LAYER_GRE;
1961df498655SGregory Etelson 			tunnel_item = items;
196284c406e7SOri Kam 			break;
196384c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_MPLS:
19644a78c88eSYongseok Koh 			flow_verbs_translate_item_mpls(dev_flow, items,
19654a78c88eSYongseok Koh 						       item_flags);
1966750ff30aSGregory Etelson 			subpriority = MLX5_TUNNEL_PRIO_GET(rss_desc);
19674a78c88eSYongseok Koh 			item_flags |= MLX5_FLOW_LAYER_MPLS;
196884c406e7SOri Kam 			break;
196984c406e7SOri Kam 		default:
197084c406e7SOri Kam 			return rte_flow_error_set(error, ENOTSUP,
197184c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ITEM,
197258df16e0SDekel Peled 						  NULL, "item not supported");
197384c406e7SOri Kam 		}
197484c406e7SOri Kam 	}
1975985b4792SGregory Etelson 	if (item_flags & MLX5_FLOW_LAYER_GRE)
197698008ce6SDariusz Sosnowski 		flow_verbs_translate_item_gre(dev_flow, gre_spec,
197798008ce6SDariusz Sosnowski 					      tunnel_item, item_flags);
1978e7bfa359SBing Zhao 	dev_flow->handle->layers = item_flags;
1979e7bfa359SBing Zhao 	/* Other members of attr will be ignored. */
1980e7bfa359SBing Zhao 	dev_flow->verbs.attr.priority =
19814a78c88eSYongseok Koh 		mlx5_flow_adjust_priority(dev, priority, subpriority);
198291389890SOphir Munk 	dev_flow->verbs.attr.port = (uint8_t)priv->dev_port;
198384c406e7SOri Kam 	return 0;
198484c406e7SOri Kam }
198584c406e7SOri Kam 
198684c406e7SOri Kam /**
198784c406e7SOri Kam  * Remove the flow from the NIC but keeps it in memory.
198884c406e7SOri Kam  *
198984c406e7SOri Kam  * @param[in] dev
199084c406e7SOri Kam  *   Pointer to the Ethernet device structure.
199184c406e7SOri Kam  * @param[in, out] flow
199284c406e7SOri Kam  *   Pointer to flow structure.
199384c406e7SOri Kam  */
199484c406e7SOri Kam static void
199584c406e7SOri Kam flow_verbs_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
199684c406e7SOri Kam {
1997b88341caSSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
1998e7bfa359SBing Zhao 	struct mlx5_flow_handle *handle;
1999b88341caSSuanming Mou 	uint32_t handle_idx;
200084c406e7SOri Kam 
200184c406e7SOri Kam 	if (!flow)
200284c406e7SOri Kam 		return;
2003b88341caSSuanming Mou 	SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
2004b88341caSSuanming Mou 		       handle_idx, handle, next) {
2005341c8941SDekel Peled 		if (handle->drv_flow) {
2006341c8941SDekel Peled 			claim_zero(mlx5_glue->destroy_flow(handle->drv_flow));
2007341c8941SDekel Peled 			handle->drv_flow = NULL;
200884c406e7SOri Kam 		}
20096fc18392SSuanming Mou 		/* hrxq is union, don't touch it only the flag is set. */
201065b3cd0dSSuanming Mou 		if (handle->rix_hrxq &&
201165b3cd0dSSuanming Mou 		    handle->fate_action == MLX5_FLOW_FATE_QUEUE) {
201277749adaSSuanming Mou 			mlx5_hrxq_release(dev, handle->rix_hrxq);
201377749adaSSuanming Mou 			handle->rix_hrxq = 0;
201484c406e7SOri Kam 		}
2015e7bfa359SBing Zhao 		if (handle->vf_vlan.tag && handle->vf_vlan.created)
2016e7bfa359SBing Zhao 			mlx5_vlan_vmwa_release(dev, &handle->vf_vlan);
201784c406e7SOri Kam 	}
201884c406e7SOri Kam }
201984c406e7SOri Kam 
202084c406e7SOri Kam /**
202184c406e7SOri Kam  * Remove the flow from the NIC and the memory.
202284c406e7SOri Kam  *
202384c406e7SOri Kam  * @param[in] dev
202484c406e7SOri Kam  *   Pointer to the Ethernet device structure.
202584c406e7SOri Kam  * @param[in, out] flow
202684c406e7SOri Kam  *   Pointer to flow structure.
202784c406e7SOri Kam  */
202884c406e7SOri Kam static void
202984c406e7SOri Kam flow_verbs_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
203084c406e7SOri Kam {
2031b88341caSSuanming Mou 	struct mlx5_priv *priv = dev->data->dev_private;
2032e7bfa359SBing Zhao 	struct mlx5_flow_handle *handle;
203384c406e7SOri Kam 
203484c406e7SOri Kam 	if (!flow)
203584c406e7SOri Kam 		return;
203684c406e7SOri Kam 	flow_verbs_remove(dev, flow);
2037b88341caSSuanming Mou 	while (flow->dev_handles) {
2038b88341caSSuanming Mou 		uint32_t tmp_idx = flow->dev_handles;
2039b88341caSSuanming Mou 
2040b88341caSSuanming Mou 		handle = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
2041b88341caSSuanming Mou 				   tmp_idx);
2042b88341caSSuanming Mou 		if (!handle)
2043b88341caSSuanming Mou 			return;
2044b88341caSSuanming Mou 		flow->dev_handles = handle->next.next;
2045b88341caSSuanming Mou 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
2046b88341caSSuanming Mou 			   tmp_idx);
204784c406e7SOri Kam 	}
204884be903cSViacheslav Ovsiienko 	if (flow->counter) {
20495382d28cSMatan Azrad 		flow_verbs_counter_release(dev, flow->counter);
2050956d5c74SSuanming Mou 		flow->counter = 0;
205184be903cSViacheslav Ovsiienko 	}
205284c406e7SOri Kam }
205384c406e7SOri Kam 
205484c406e7SOri Kam /**
205584c406e7SOri Kam  * Apply the flow to the NIC.
205684c406e7SOri Kam  *
205784c406e7SOri Kam  * @param[in] dev
205884c406e7SOri Kam  *   Pointer to the Ethernet device structure.
205984c406e7SOri Kam  * @param[in, out] flow
206084c406e7SOri Kam  *   Pointer to flow structure.
206184c406e7SOri Kam  * @param[out] error
206284c406e7SOri Kam  *   Pointer to error structure.
206384c406e7SOri Kam  *
206484c406e7SOri Kam  * @return
206584c406e7SOri Kam  *   0 on success, a negative errno value otherwise and rte_errno is set.
206684c406e7SOri Kam  */
206784c406e7SOri Kam static int
206884c406e7SOri Kam flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
206984c406e7SOri Kam 		 struct rte_flow_error *error)
207084c406e7SOri Kam {
2071dfedf3e3SViacheslav Ovsiienko 	struct mlx5_priv *priv = dev->data->dev_private;
2072e7bfa359SBing Zhao 	struct mlx5_flow_handle *handle;
207384c406e7SOri Kam 	struct mlx5_flow *dev_flow;
2074772dc0ebSSuanming Mou 	struct mlx5_hrxq *hrxq;
2075b88341caSSuanming Mou 	uint32_t dev_handles;
207684c406e7SOri Kam 	int err;
2077e7bfa359SBing Zhao 	int idx;
20788bb81f26SXueming Li 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
207984c406e7SOri Kam 
20808bb81f26SXueming Li 	MLX5_ASSERT(wks);
20810064bf43SXueming Li 	for (idx = wks->flow_idx - 1; idx >= 0; idx--) {
20828bb81f26SXueming Li 		dev_flow = &wks->flows[idx];
2083e7bfa359SBing Zhao 		handle = dev_flow->handle;
2084488d13abSSuanming Mou 		if (handle->fate_action == MLX5_FLOW_FATE_DROP) {
208565b3cd0dSSuanming Mou 			MLX5_ASSERT(priv->drop_queue.hrxq);
208665b3cd0dSSuanming Mou 			hrxq = priv->drop_queue.hrxq;
208784c406e7SOri Kam 		} else {
20880064bf43SXueming Li 			struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc;
208984c406e7SOri Kam 
2090e745f900SSuanming Mou 			MLX5_ASSERT(rss_desc->queue_num);
2091e1592b6cSSuanming Mou 			rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN;
2092e1592b6cSSuanming Mou 			rss_desc->hash_fields = dev_flow->hash_fields;
2093e1592b6cSSuanming Mou 			rss_desc->tunnel = !!(handle->layers &
2094e1592b6cSSuanming Mou 					      MLX5_FLOW_LAYER_TUNNEL);
2095fabf8a37SSuanming Mou 			rss_desc->shared_rss = 0;
20963a2f674bSSuanming Mou 			hrxq = mlx5_hrxq_get(dev, rss_desc);
209784c406e7SOri Kam 			if (!hrxq) {
209884c406e7SOri Kam 				rte_flow_error_set
209984c406e7SOri Kam 					(error, rte_errno,
210084c406e7SOri Kam 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
210184c406e7SOri Kam 					 "cannot get hash queue");
210284c406e7SOri Kam 				goto error;
210384c406e7SOri Kam 			}
21043a2f674bSSuanming Mou 			handle->rix_hrxq = hrxq->idx;
210584c406e7SOri Kam 		}
2106772dc0ebSSuanming Mou 		MLX5_ASSERT(hrxq);
2107341c8941SDekel Peled 		handle->drv_flow = mlx5_glue->create_flow
2108341c8941SDekel Peled 					(hrxq->qp, &dev_flow->verbs.attr);
2109341c8941SDekel Peled 		if (!handle->drv_flow) {
211084c406e7SOri Kam 			rte_flow_error_set(error, errno,
211184c406e7SOri Kam 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
211284c406e7SOri Kam 					   NULL,
211384c406e7SOri Kam 					   "hardware refuses to create flow");
211484c406e7SOri Kam 			goto error;
211584c406e7SOri Kam 		}
2116dfedf3e3SViacheslav Ovsiienko 		if (priv->vmwa_context &&
2117e7bfa359SBing Zhao 		    handle->vf_vlan.tag && !handle->vf_vlan.created) {
2118dfedf3e3SViacheslav Ovsiienko 			/*
2119dfedf3e3SViacheslav Ovsiienko 			 * The rule contains the VLAN pattern.
2120dfedf3e3SViacheslav Ovsiienko 			 * For VF we are going to create VLAN
2121dfedf3e3SViacheslav Ovsiienko 			 * interface to make hypervisor set correct
2122dfedf3e3SViacheslav Ovsiienko 			 * e-Switch vport context.
2123dfedf3e3SViacheslav Ovsiienko 			 */
2124e7bfa359SBing Zhao 			mlx5_vlan_vmwa_acquire(dev, &handle->vf_vlan);
2125dfedf3e3SViacheslav Ovsiienko 		}
212684c406e7SOri Kam 	}
212784c406e7SOri Kam 	return 0;
212884c406e7SOri Kam error:
212984c406e7SOri Kam 	err = rte_errno; /* Save rte_errno before cleanup. */
2130b88341caSSuanming Mou 	SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
2131b88341caSSuanming Mou 		       dev_handles, handle, next) {
21326fc18392SSuanming Mou 		/* hrxq is union, don't touch it only the flag is set. */
213365b3cd0dSSuanming Mou 		if (handle->rix_hrxq &&
213465b3cd0dSSuanming Mou 		    handle->fate_action == MLX5_FLOW_FATE_QUEUE) {
213577749adaSSuanming Mou 			mlx5_hrxq_release(dev, handle->rix_hrxq);
213677749adaSSuanming Mou 			handle->rix_hrxq = 0;
213784c406e7SOri Kam 		}
2138e7bfa359SBing Zhao 		if (handle->vf_vlan.tag && handle->vf_vlan.created)
2139e7bfa359SBing Zhao 			mlx5_vlan_vmwa_release(dev, &handle->vf_vlan);
214084c406e7SOri Kam 	}
214184c406e7SOri Kam 	rte_errno = err; /* Restore rte_errno. */
214284c406e7SOri Kam 	return -rte_errno;
214384c406e7SOri Kam }
214484c406e7SOri Kam 
2145684dafe7SMoti Haimovsky /**
2146684dafe7SMoti Haimovsky  * Query a flow.
2147684dafe7SMoti Haimovsky  *
2148684dafe7SMoti Haimovsky  * @see rte_flow_query()
2149684dafe7SMoti Haimovsky  * @see rte_flow_ops
2150684dafe7SMoti Haimovsky  */
2151684dafe7SMoti Haimovsky static int
2152684dafe7SMoti Haimovsky flow_verbs_query(struct rte_eth_dev *dev,
2153684dafe7SMoti Haimovsky 		 struct rte_flow *flow,
2154684dafe7SMoti Haimovsky 		 const struct rte_flow_action *actions,
2155684dafe7SMoti Haimovsky 		 void *data,
2156684dafe7SMoti Haimovsky 		 struct rte_flow_error *error)
2157684dafe7SMoti Haimovsky {
2158684dafe7SMoti Haimovsky 	int ret = -EINVAL;
2159684dafe7SMoti Haimovsky 
2160684dafe7SMoti Haimovsky 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
2161684dafe7SMoti Haimovsky 		switch (actions->type) {
2162684dafe7SMoti Haimovsky 		case RTE_FLOW_ACTION_TYPE_VOID:
2163684dafe7SMoti Haimovsky 			break;
2164684dafe7SMoti Haimovsky 		case RTE_FLOW_ACTION_TYPE_COUNT:
216506629d86SViacheslav Ovsiienko 			ret = flow_verbs_counter_query(dev, flow, data, error);
2166684dafe7SMoti Haimovsky 			break;
2167684dafe7SMoti Haimovsky 		default:
2168684dafe7SMoti Haimovsky 			return rte_flow_error_set(error, ENOTSUP,
2169684dafe7SMoti Haimovsky 						  RTE_FLOW_ERROR_TYPE_ACTION,
2170684dafe7SMoti Haimovsky 						  actions,
2171684dafe7SMoti Haimovsky 						  "action not supported");
2172684dafe7SMoti Haimovsky 		}
2173684dafe7SMoti Haimovsky 	}
2174684dafe7SMoti Haimovsky 	return ret;
2175684dafe7SMoti Haimovsky }
2176684dafe7SMoti Haimovsky 
217723f627e0SBing Zhao static int
217823f627e0SBing Zhao flow_verbs_sync_domain(struct rte_eth_dev *dev, uint32_t domains,
217923f627e0SBing Zhao 		       uint32_t flags)
218023f627e0SBing Zhao {
218123f627e0SBing Zhao 	RTE_SET_USED(dev);
218223f627e0SBing Zhao 	RTE_SET_USED(domains);
218323f627e0SBing Zhao 	RTE_SET_USED(flags);
218423f627e0SBing Zhao 
218523f627e0SBing Zhao 	return 0;
218623f627e0SBing Zhao }
218723f627e0SBing Zhao 
21880c76d1c9SYongseok Koh const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops = {
2189e38776c3SMaayan Kashani 	.list_create = flow_legacy_list_create,
2190e38776c3SMaayan Kashani 	.list_destroy = flow_legacy_list_destroy,
219184c406e7SOri Kam 	.validate = flow_verbs_validate,
219284c406e7SOri Kam 	.prepare = flow_verbs_prepare,
219384c406e7SOri Kam 	.translate = flow_verbs_translate,
219484c406e7SOri Kam 	.apply = flow_verbs_apply,
219584c406e7SOri Kam 	.remove = flow_verbs_remove,
219684c406e7SOri Kam 	.destroy = flow_verbs_destroy,
2197684dafe7SMoti Haimovsky 	.query = flow_verbs_query,
219823f627e0SBing Zhao 	.sync_domain = flow_verbs_sync_domain,
2199c5042f93SDmitry Kozlyuk 	.discover_priorities = flow_verbs_discover_priorities,
2200c68bb7a6SAsaf Penso 	.get_aged_flows = flow_null_get_aged_flows,
2201c68bb7a6SAsaf Penso 	.counter_alloc = flow_null_counter_allocate,
2202c68bb7a6SAsaf Penso 	.counter_free = flow_null_counter_free,
2203c68bb7a6SAsaf Penso 	.counter_query = flow_null_counter_query,
220484c406e7SOri Kam };
2205