xref: /dpdk/drivers/net/mlx5/mlx5_flow_verbs.c (revision c42f44bd1b42cf21df3d94c738f22032fae308b4)
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 /* Verbs header. */
1284c406e7SOri Kam /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
1384c406e7SOri Kam #ifdef PEDANTIC
1484c406e7SOri Kam #pragma GCC diagnostic ignored "-Wpedantic"
1584c406e7SOri Kam #endif
1684c406e7SOri Kam #include <infiniband/verbs.h>
1784c406e7SOri Kam #ifdef PEDANTIC
1884c406e7SOri Kam #pragma GCC diagnostic error "-Wpedantic"
1984c406e7SOri Kam #endif
2084c406e7SOri Kam 
2184c406e7SOri Kam #include <rte_common.h>
2284c406e7SOri Kam #include <rte_ether.h>
2384c406e7SOri Kam #include <rte_ethdev_driver.h>
2484c406e7SOri Kam #include <rte_flow.h>
2584c406e7SOri Kam #include <rte_flow_driver.h>
2684c406e7SOri Kam #include <rte_malloc.h>
2784c406e7SOri Kam #include <rte_ip.h>
2884c406e7SOri Kam 
297b4f1e6bSMatan Azrad #include <mlx5_glue.h>
307b4f1e6bSMatan Azrad #include <mlx5_prm.h>
317b4f1e6bSMatan Azrad 
3284c406e7SOri Kam #include "mlx5_defs.h"
337b4f1e6bSMatan Azrad #include "mlx5.h"
3484c406e7SOri Kam #include "mlx5_flow.h"
35227684feSYongseok Koh #include "mlx5_rxtx.h"
3684c406e7SOri Kam 
374a78c88eSYongseok Koh #define VERBS_SPEC_INNER(item_flags) \
384a78c88eSYongseok Koh 	(!!((item_flags) & MLX5_FLOW_LAYER_TUNNEL) ? IBV_FLOW_SPEC_INNER : 0)
394a78c88eSYongseok Koh 
4084c406e7SOri Kam /**
41db48f9dbSViacheslav Ovsiienko  * Create Verbs flow counter with Verbs library.
42db48f9dbSViacheslav Ovsiienko  *
43db48f9dbSViacheslav Ovsiienko  * @param[in] dev
44db48f9dbSViacheslav Ovsiienko  *   Pointer to the Ethernet device structure.
45db48f9dbSViacheslav Ovsiienko  * @param[in, out] counter
46db48f9dbSViacheslav Ovsiienko  *   mlx5 flow counter object, contains the counter id,
47db48f9dbSViacheslav Ovsiienko  *   handle of created Verbs flow counter is returned
48db48f9dbSViacheslav Ovsiienko  *   in cs field (if counters are supported).
49db48f9dbSViacheslav Ovsiienko  *
50db48f9dbSViacheslav Ovsiienko  * @return
51db48f9dbSViacheslav Ovsiienko  *   0 On success else a negative errno value is returned
52db48f9dbSViacheslav Ovsiienko  *   and rte_errno is set.
53db48f9dbSViacheslav Ovsiienko  */
54db48f9dbSViacheslav Ovsiienko static int
55db48f9dbSViacheslav Ovsiienko flow_verbs_counter_create(struct rte_eth_dev *dev,
56db48f9dbSViacheslav Ovsiienko 			  struct mlx5_flow_counter *counter)
57db48f9dbSViacheslav Ovsiienko {
58db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
59dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
60f048f3d4SViacheslav Ovsiienko 	struct ibv_context *ctx = priv->sh->ctx;
61db48f9dbSViacheslav Ovsiienko 	struct ibv_counter_set_init_attr init = {
62db48f9dbSViacheslav Ovsiienko 			 .counter_set_id = counter->id};
63db48f9dbSViacheslav Ovsiienko 
64f048f3d4SViacheslav Ovsiienko 	counter->cs = mlx5_glue->create_counter_set(ctx, &init);
65db48f9dbSViacheslav Ovsiienko 	if (!counter->cs) {
66db48f9dbSViacheslav Ovsiienko 		rte_errno = ENOTSUP;
67db48f9dbSViacheslav Ovsiienko 		return -ENOTSUP;
68db48f9dbSViacheslav Ovsiienko 	}
69db48f9dbSViacheslav Ovsiienko 	return 0;
70db48f9dbSViacheslav Ovsiienko #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
71dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
72f048f3d4SViacheslav Ovsiienko 	struct ibv_context *ctx = priv->sh->ctx;
73db48f9dbSViacheslav Ovsiienko 	struct ibv_counters_init_attr init = {0};
740c15f3c0SAli Alnubani 	struct ibv_counter_attach_attr attach;
75db48f9dbSViacheslav Ovsiienko 	int ret;
76db48f9dbSViacheslav Ovsiienko 
770c15f3c0SAli Alnubani 	memset(&attach, 0, sizeof(attach));
78f048f3d4SViacheslav Ovsiienko 	counter->cs = mlx5_glue->create_counters(ctx, &init);
79db48f9dbSViacheslav Ovsiienko 	if (!counter->cs) {
80db48f9dbSViacheslav Ovsiienko 		rte_errno = ENOTSUP;
81db48f9dbSViacheslav Ovsiienko 		return -ENOTSUP;
82db48f9dbSViacheslav Ovsiienko 	}
83db48f9dbSViacheslav Ovsiienko 	attach.counter_desc = IBV_COUNTER_PACKETS;
84db48f9dbSViacheslav Ovsiienko 	attach.index = 0;
85db48f9dbSViacheslav Ovsiienko 	ret = mlx5_glue->attach_counters(counter->cs, &attach, NULL);
86db48f9dbSViacheslav Ovsiienko 	if (!ret) {
87db48f9dbSViacheslav Ovsiienko 		attach.counter_desc = IBV_COUNTER_BYTES;
88db48f9dbSViacheslav Ovsiienko 		attach.index = 1;
89db48f9dbSViacheslav Ovsiienko 		ret = mlx5_glue->attach_counters
90db48f9dbSViacheslav Ovsiienko 					(counter->cs, &attach, NULL);
91db48f9dbSViacheslav Ovsiienko 	}
92db48f9dbSViacheslav Ovsiienko 	if (ret) {
93db48f9dbSViacheslav Ovsiienko 		claim_zero(mlx5_glue->destroy_counters(counter->cs));
94db48f9dbSViacheslav Ovsiienko 		counter->cs = NULL;
95db48f9dbSViacheslav Ovsiienko 		rte_errno = ret;
96db48f9dbSViacheslav Ovsiienko 		return -ret;
97db48f9dbSViacheslav Ovsiienko 	}
98db48f9dbSViacheslav Ovsiienko 	return 0;
99db48f9dbSViacheslav Ovsiienko #else
100db48f9dbSViacheslav Ovsiienko 	(void)dev;
101db48f9dbSViacheslav Ovsiienko 	(void)counter;
102db48f9dbSViacheslav Ovsiienko 	rte_errno = ENOTSUP;
103db48f9dbSViacheslav Ovsiienko 	return -ENOTSUP;
104db48f9dbSViacheslav Ovsiienko #endif
105db48f9dbSViacheslav Ovsiienko }
106db48f9dbSViacheslav Ovsiienko 
107db48f9dbSViacheslav Ovsiienko /**
10884c406e7SOri Kam  * Get a flow counter.
10984c406e7SOri Kam  *
11084c406e7SOri Kam  * @param[in] dev
11184c406e7SOri Kam  *   Pointer to the Ethernet device structure.
11284c406e7SOri Kam  * @param[in] shared
11384c406e7SOri Kam  *   Indicate if this counter is shared with other flows.
11484c406e7SOri Kam  * @param[in] id
11584c406e7SOri Kam  *   Counter identifier.
11684c406e7SOri Kam  *
11784c406e7SOri Kam  * @return
11884c406e7SOri Kam  *   A pointer to the counter, NULL otherwise and rte_errno is set.
11984c406e7SOri Kam  */
12084c406e7SOri Kam static struct mlx5_flow_counter *
12184c406e7SOri Kam flow_verbs_counter_new(struct rte_eth_dev *dev, uint32_t shared, uint32_t id)
12284c406e7SOri Kam {
123dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
12484c406e7SOri Kam 	struct mlx5_flow_counter *cnt;
125db48f9dbSViacheslav Ovsiienko 	int ret;
12684c406e7SOri Kam 
1275f09e80cSMoti Haimovsky 	if (shared) {
1285382d28cSMatan Azrad 		TAILQ_FOREACH(cnt, &priv->sh->cmng.flow_counters, next) {
1295f09e80cSMoti Haimovsky 			if (cnt->shared && cnt->id == id) {
13084c406e7SOri Kam 				cnt->ref_cnt++;
13184c406e7SOri Kam 				return cnt;
13284c406e7SOri Kam 			}
1335f09e80cSMoti Haimovsky 		}
1345f09e80cSMoti Haimovsky 	}
13584c406e7SOri Kam 	cnt = rte_calloc(__func__, 1, sizeof(*cnt), 0);
13684c406e7SOri Kam 	if (!cnt) {
13784c406e7SOri Kam 		rte_errno = ENOMEM;
13884c406e7SOri Kam 		return NULL;
13984c406e7SOri Kam 	}
140db48f9dbSViacheslav Ovsiienko 	cnt->id = id;
141db48f9dbSViacheslav Ovsiienko 	cnt->shared = shared;
142db48f9dbSViacheslav Ovsiienko 	cnt->ref_cnt = 1;
143db48f9dbSViacheslav Ovsiienko 	cnt->hits = 0;
144db48f9dbSViacheslav Ovsiienko 	cnt->bytes = 0;
145db48f9dbSViacheslav Ovsiienko 	/* Create counter with Verbs. */
146db48f9dbSViacheslav Ovsiienko 	ret = flow_verbs_counter_create(dev, cnt);
147db48f9dbSViacheslav Ovsiienko 	if (!ret) {
1485382d28cSMatan Azrad 		TAILQ_INSERT_HEAD(&priv->sh->cmng.flow_counters, cnt, next);
14984c406e7SOri Kam 		return cnt;
150db48f9dbSViacheslav Ovsiienko 	}
151db48f9dbSViacheslav Ovsiienko 	/* Some error occurred in Verbs library. */
152db48f9dbSViacheslav Ovsiienko 	rte_free(cnt);
153db48f9dbSViacheslav Ovsiienko 	rte_errno = -ret;
15484c406e7SOri Kam 	return NULL;
15584c406e7SOri Kam }
15684c406e7SOri Kam 
15784c406e7SOri Kam /**
15884c406e7SOri Kam  * Release a flow counter.
15984c406e7SOri Kam  *
1605382d28cSMatan Azrad  * @param[in] dev
1615382d28cSMatan Azrad  *   Pointer to the Ethernet device structure.
16284c406e7SOri Kam  * @param[in] counter
16384c406e7SOri Kam  *   Pointer to the counter handler.
16484c406e7SOri Kam  */
16584c406e7SOri Kam static void
1665382d28cSMatan Azrad flow_verbs_counter_release(struct rte_eth_dev *dev,
1675382d28cSMatan Azrad 			   struct mlx5_flow_counter *counter)
16884c406e7SOri Kam {
1695382d28cSMatan Azrad 	struct mlx5_priv *priv = dev->data->dev_private;
1705382d28cSMatan Azrad 
17184c406e7SOri Kam 	if (--counter->ref_cnt == 0) {
172db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
17384c406e7SOri Kam 		claim_zero(mlx5_glue->destroy_counter_set(counter->cs));
174db48f9dbSViacheslav Ovsiienko #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
175db48f9dbSViacheslav Ovsiienko 		claim_zero(mlx5_glue->destroy_counters(counter->cs));
176db48f9dbSViacheslav Ovsiienko #endif
1775382d28cSMatan Azrad 		TAILQ_REMOVE(&priv->sh->cmng.flow_counters, counter, next);
17884c406e7SOri Kam 		rte_free(counter);
17984c406e7SOri Kam 	}
18084c406e7SOri Kam }
18184c406e7SOri Kam 
18284c406e7SOri Kam /**
18306629d86SViacheslav Ovsiienko  * Query a flow counter via Verbs library call.
18406629d86SViacheslav Ovsiienko  *
18506629d86SViacheslav Ovsiienko  * @see rte_flow_query()
18606629d86SViacheslav Ovsiienko  * @see rte_flow_ops
18706629d86SViacheslav Ovsiienko  */
18806629d86SViacheslav Ovsiienko static int
18906629d86SViacheslav Ovsiienko flow_verbs_counter_query(struct rte_eth_dev *dev __rte_unused,
190db48f9dbSViacheslav Ovsiienko 			 struct rte_flow *flow, void *data,
19106629d86SViacheslav Ovsiienko 			 struct rte_flow_error *error)
19206629d86SViacheslav Ovsiienko {
193db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
194db48f9dbSViacheslav Ovsiienko 	defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
19550d23b9aSDekel Peled 	if (flow->counter && flow->counter->cs) {
19606629d86SViacheslav Ovsiienko 		struct rte_flow_query_count *qc = data;
19706629d86SViacheslav Ovsiienko 		uint64_t counters[2] = {0, 0};
198db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
19906629d86SViacheslav Ovsiienko 		struct ibv_query_counter_set_attr query_cs_attr = {
20006629d86SViacheslav Ovsiienko 			.cs = flow->counter->cs,
20106629d86SViacheslav Ovsiienko 			.query_flags = IBV_COUNTER_SET_FORCE_UPDATE,
20206629d86SViacheslav Ovsiienko 		};
20306629d86SViacheslav Ovsiienko 		struct ibv_counter_set_data query_out = {
20406629d86SViacheslav Ovsiienko 			.out = counters,
20506629d86SViacheslav Ovsiienko 			.outlen = 2 * sizeof(uint64_t),
20606629d86SViacheslav Ovsiienko 		};
20706629d86SViacheslav Ovsiienko 		int err = mlx5_glue->query_counter_set(&query_cs_attr,
20806629d86SViacheslav Ovsiienko 						       &query_out);
209db48f9dbSViacheslav Ovsiienko #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
210db48f9dbSViacheslav Ovsiienko 		int err = mlx5_glue->query_counters
211db48f9dbSViacheslav Ovsiienko 			       (flow->counter->cs, counters,
212db48f9dbSViacheslav Ovsiienko 				RTE_DIM(counters),
213db48f9dbSViacheslav Ovsiienko 				IBV_READ_COUNTERS_ATTR_PREFER_CACHED);
214db48f9dbSViacheslav Ovsiienko #endif
21506629d86SViacheslav Ovsiienko 		if (err)
21606629d86SViacheslav Ovsiienko 			return rte_flow_error_set
21706629d86SViacheslav Ovsiienko 				(error, err,
21806629d86SViacheslav Ovsiienko 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
21906629d86SViacheslav Ovsiienko 				 NULL,
22006629d86SViacheslav Ovsiienko 				 "cannot read counter");
22106629d86SViacheslav Ovsiienko 		qc->hits_set = 1;
22206629d86SViacheslav Ovsiienko 		qc->bytes_set = 1;
22306629d86SViacheslav Ovsiienko 		qc->hits = counters[0] - flow->counter->hits;
22406629d86SViacheslav Ovsiienko 		qc->bytes = counters[1] - flow->counter->bytes;
22506629d86SViacheslav Ovsiienko 		if (qc->reset) {
22606629d86SViacheslav Ovsiienko 			flow->counter->hits = counters[0];
22706629d86SViacheslav Ovsiienko 			flow->counter->bytes = counters[1];
22806629d86SViacheslav Ovsiienko 		}
22906629d86SViacheslav Ovsiienko 		return 0;
23006629d86SViacheslav Ovsiienko 	}
23106629d86SViacheslav Ovsiienko 	return rte_flow_error_set(error, EINVAL,
23206629d86SViacheslav Ovsiienko 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
23306629d86SViacheslav Ovsiienko 				  NULL,
23406629d86SViacheslav Ovsiienko 				  "flow does not have counter");
23506629d86SViacheslav Ovsiienko #else
236db48f9dbSViacheslav Ovsiienko 	(void)flow;
237db48f9dbSViacheslav Ovsiienko 	(void)data;
23806629d86SViacheslav Ovsiienko 	return rte_flow_error_set(error, ENOTSUP,
23906629d86SViacheslav Ovsiienko 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
24006629d86SViacheslav Ovsiienko 				  NULL,
24106629d86SViacheslav Ovsiienko 				  "counters are not available");
24206629d86SViacheslav Ovsiienko #endif
24306629d86SViacheslav Ovsiienko }
24406629d86SViacheslav Ovsiienko 
24506629d86SViacheslav Ovsiienko /**
2464a78c88eSYongseok Koh  * Add a verbs item specification into @p verbs.
24784c406e7SOri Kam  *
2484a78c88eSYongseok Koh  * @param[out] verbs
2494a78c88eSYongseok Koh  *   Pointer to verbs structure.
25084c406e7SOri Kam  * @param[in] src
25184c406e7SOri Kam  *   Create specification.
25284c406e7SOri Kam  * @param[in] size
25384c406e7SOri Kam  *   Size in bytes of the specification to copy.
25484c406e7SOri Kam  */
25584c406e7SOri Kam static void
256*c42f44bdSBing Zhao flow_verbs_spec_add(struct mlx5_flow_resource_verbs *verbs,
257*c42f44bdSBing Zhao 		    void *src, unsigned int size)
25884c406e7SOri Kam {
25984c406e7SOri Kam 	void *dst;
26084c406e7SOri Kam 
2614a78c88eSYongseok Koh 	if (!verbs)
2624a78c88eSYongseok Koh 		return;
2638e46d4e1SAlexander Kozyrev 	MLX5_ASSERT(verbs->specs);
26484c406e7SOri Kam 	dst = (void *)(verbs->specs + verbs->size);
26584c406e7SOri Kam 	memcpy(dst, src, size);
26684c406e7SOri Kam 	++verbs->attr->num_of_specs;
26784c406e7SOri Kam 	verbs->size += size;
26884c406e7SOri Kam }
26984c406e7SOri Kam 
27084c406e7SOri Kam /**
27184c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
27284c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
27384c406e7SOri Kam  * into the flow.
27484c406e7SOri Kam  *
2754a78c88eSYongseok Koh  * @param[in, out] dev_flow
2764a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
27784c406e7SOri Kam  * @param[in] item
27884c406e7SOri Kam  *   Item specification.
27984c406e7SOri Kam  * @param[in] item_flags
2804a78c88eSYongseok Koh  *   Parsed item flags.
28184c406e7SOri Kam  */
28284c406e7SOri Kam static void
2834a78c88eSYongseok Koh flow_verbs_translate_item_eth(struct mlx5_flow *dev_flow,
2844a78c88eSYongseok Koh 			      const struct rte_flow_item *item,
2854a78c88eSYongseok Koh 			      uint64_t item_flags)
28684c406e7SOri Kam {
28784c406e7SOri Kam 	const struct rte_flow_item_eth *spec = item->spec;
28884c406e7SOri Kam 	const struct rte_flow_item_eth *mask = item->mask;
28984c406e7SOri Kam 	const unsigned int size = sizeof(struct ibv_flow_spec_eth);
29084c406e7SOri Kam 	struct ibv_flow_spec_eth eth = {
2914a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags),
29284c406e7SOri Kam 		.size = size,
29384c406e7SOri Kam 	};
29484c406e7SOri Kam 
29584c406e7SOri Kam 	if (!mask)
29684c406e7SOri Kam 		mask = &rte_flow_item_eth_mask;
29784c406e7SOri Kam 	if (spec) {
29884c406e7SOri Kam 		unsigned int i;
29984c406e7SOri Kam 
30035b2d13fSOlivier Matz 		memcpy(&eth.val.dst_mac, spec->dst.addr_bytes,
30135b2d13fSOlivier Matz 			RTE_ETHER_ADDR_LEN);
30235b2d13fSOlivier Matz 		memcpy(&eth.val.src_mac, spec->src.addr_bytes,
30335b2d13fSOlivier Matz 			RTE_ETHER_ADDR_LEN);
30484c406e7SOri Kam 		eth.val.ether_type = spec->type;
30535b2d13fSOlivier Matz 		memcpy(&eth.mask.dst_mac, mask->dst.addr_bytes,
30635b2d13fSOlivier Matz 			RTE_ETHER_ADDR_LEN);
30735b2d13fSOlivier Matz 		memcpy(&eth.mask.src_mac, mask->src.addr_bytes,
30835b2d13fSOlivier Matz 			RTE_ETHER_ADDR_LEN);
30984c406e7SOri Kam 		eth.mask.ether_type = mask->type;
31084c406e7SOri Kam 		/* Remove unwanted bits from values. */
31135b2d13fSOlivier Matz 		for (i = 0; i < RTE_ETHER_ADDR_LEN; ++i) {
31284c406e7SOri Kam 			eth.val.dst_mac[i] &= eth.mask.dst_mac[i];
31384c406e7SOri Kam 			eth.val.src_mac[i] &= eth.mask.src_mac[i];
31484c406e7SOri Kam 		}
31584c406e7SOri Kam 		eth.val.ether_type &= eth.mask.ether_type;
31684c406e7SOri Kam 	}
3174a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &eth, size);
31884c406e7SOri Kam }
31984c406e7SOri Kam 
32084c406e7SOri Kam /**
32184c406e7SOri Kam  * Update the VLAN tag in the Verbs Ethernet specification.
32284c406e7SOri Kam  * This function assumes that the input is valid and there is space to add
32384c406e7SOri Kam  * the requested item.
32484c406e7SOri Kam  *
32584c406e7SOri Kam  * @param[in, out] attr
32684c406e7SOri Kam  *   Pointer to Verbs attributes structure.
32784c406e7SOri Kam  * @param[in] eth
32884c406e7SOri Kam  *   Verbs structure containing the VLAN information to copy.
32984c406e7SOri Kam  */
33084c406e7SOri Kam static void
33184c406e7SOri Kam flow_verbs_item_vlan_update(struct ibv_flow_attr *attr,
33284c406e7SOri Kam 			    struct ibv_flow_spec_eth *eth)
33384c406e7SOri Kam {
33484c406e7SOri Kam 	unsigned int i;
33584c406e7SOri Kam 	const enum ibv_flow_spec_type search = eth->type;
33684c406e7SOri Kam 	struct ibv_spec_header *hdr = (struct ibv_spec_header *)
33784c406e7SOri Kam 		((uint8_t *)attr + sizeof(struct ibv_flow_attr));
33884c406e7SOri Kam 
33984c406e7SOri Kam 	for (i = 0; i != attr->num_of_specs; ++i) {
34084c406e7SOri Kam 		if (hdr->type == search) {
34184c406e7SOri Kam 			struct ibv_flow_spec_eth *e =
34284c406e7SOri Kam 				(struct ibv_flow_spec_eth *)hdr;
34384c406e7SOri Kam 
34484c406e7SOri Kam 			e->val.vlan_tag = eth->val.vlan_tag;
34584c406e7SOri Kam 			e->mask.vlan_tag = eth->mask.vlan_tag;
34684c406e7SOri Kam 			e->val.ether_type = eth->val.ether_type;
34784c406e7SOri Kam 			e->mask.ether_type = eth->mask.ether_type;
34884c406e7SOri Kam 			break;
34984c406e7SOri Kam 		}
35084c406e7SOri Kam 		hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
35184c406e7SOri Kam 	}
35284c406e7SOri Kam }
35384c406e7SOri Kam 
35484c406e7SOri Kam /**
35584c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
35684c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
35784c406e7SOri Kam  * into the flow.
35884c406e7SOri Kam  *
35984c406e7SOri Kam  * @param[in, out] dev_flow
36084c406e7SOri Kam  *   Pointer to dev_flow structure.
3614a78c88eSYongseok Koh  * @param[in] item
3624a78c88eSYongseok Koh  *   Item specification.
3634a78c88eSYongseok Koh  * @param[in] item_flags
3644a78c88eSYongseok Koh  *   Parsed item flags.
36584c406e7SOri Kam  */
36684c406e7SOri Kam static void
3674a78c88eSYongseok Koh flow_verbs_translate_item_vlan(struct mlx5_flow *dev_flow,
3684a78c88eSYongseok Koh 			       const struct rte_flow_item *item,
3694a78c88eSYongseok Koh 			       uint64_t item_flags)
37084c406e7SOri Kam {
37184c406e7SOri Kam 	const struct rte_flow_item_vlan *spec = item->spec;
37284c406e7SOri Kam 	const struct rte_flow_item_vlan *mask = item->mask;
37384c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_eth);
3744a78c88eSYongseok Koh 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
37584c406e7SOri Kam 	struct ibv_flow_spec_eth eth = {
3764a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_ETH | VERBS_SPEC_INNER(item_flags),
37784c406e7SOri Kam 		.size = size,
37884c406e7SOri Kam 	};
37984c406e7SOri Kam 	const uint32_t l2m = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
38084c406e7SOri Kam 				      MLX5_FLOW_LAYER_OUTER_L2;
38184c406e7SOri Kam 
38284c406e7SOri Kam 	if (!mask)
38384c406e7SOri Kam 		mask = &rte_flow_item_vlan_mask;
38484c406e7SOri Kam 	if (spec) {
38584c406e7SOri Kam 		eth.val.vlan_tag = spec->tci;
38684c406e7SOri Kam 		eth.mask.vlan_tag = mask->tci;
38784c406e7SOri Kam 		eth.val.vlan_tag &= eth.mask.vlan_tag;
38884c406e7SOri Kam 		eth.val.ether_type = spec->inner_type;
38984c406e7SOri Kam 		eth.mask.ether_type = mask->inner_type;
39084c406e7SOri Kam 		eth.val.ether_type &= eth.mask.ether_type;
39184c406e7SOri Kam 	}
3924a78c88eSYongseok Koh 	if (!(item_flags & l2m))
3934a78c88eSYongseok Koh 		flow_verbs_spec_add(&dev_flow->verbs, &eth, size);
3944a78c88eSYongseok Koh 	else
39584c406e7SOri Kam 		flow_verbs_item_vlan_update(dev_flow->verbs.attr, &eth);
396dfedf3e3SViacheslav Ovsiienko 	if (!tunnel)
397*c42f44bdSBing Zhao 		dev_flow->handle.vf_vlan.tag =
398dfedf3e3SViacheslav Ovsiienko 			rte_be_to_cpu_16(spec->tci) & 0x0fff;
39984c406e7SOri Kam }
40084c406e7SOri Kam 
40184c406e7SOri Kam /**
40284c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
40384c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
40484c406e7SOri Kam  * into the flow.
40584c406e7SOri Kam  *
4064a78c88eSYongseok Koh  * @param[in, out] dev_flow
4074a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
40884c406e7SOri Kam  * @param[in] item
40984c406e7SOri Kam  *   Item specification.
4104a78c88eSYongseok Koh  * @param[in] item_flags
4114a78c88eSYongseok Koh  *   Parsed item flags.
41284c406e7SOri Kam  */
41384c406e7SOri Kam static void
4144a78c88eSYongseok Koh flow_verbs_translate_item_ipv4(struct mlx5_flow *dev_flow,
4154a78c88eSYongseok Koh 			       const struct rte_flow_item *item,
4164a78c88eSYongseok Koh 			       uint64_t item_flags)
41784c406e7SOri Kam {
41884c406e7SOri Kam 	const struct rte_flow_item_ipv4 *spec = item->spec;
41984c406e7SOri Kam 	const struct rte_flow_item_ipv4 *mask = item->mask;
42084c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_ipv4_ext);
42184c406e7SOri Kam 	struct ibv_flow_spec_ipv4_ext ipv4 = {
4224a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_IPV4_EXT | VERBS_SPEC_INNER(item_flags),
42384c406e7SOri Kam 		.size = size,
42484c406e7SOri Kam 	};
42584c406e7SOri Kam 
42684c406e7SOri Kam 	if (!mask)
42784c406e7SOri Kam 		mask = &rte_flow_item_ipv4_mask;
42884c406e7SOri Kam 	if (spec) {
42984c406e7SOri Kam 		ipv4.val = (struct ibv_flow_ipv4_ext_filter){
43084c406e7SOri Kam 			.src_ip = spec->hdr.src_addr,
43184c406e7SOri Kam 			.dst_ip = spec->hdr.dst_addr,
43284c406e7SOri Kam 			.proto = spec->hdr.next_proto_id,
43384c406e7SOri Kam 			.tos = spec->hdr.type_of_service,
43484c406e7SOri Kam 		};
43584c406e7SOri Kam 		ipv4.mask = (struct ibv_flow_ipv4_ext_filter){
43684c406e7SOri Kam 			.src_ip = mask->hdr.src_addr,
43784c406e7SOri Kam 			.dst_ip = mask->hdr.dst_addr,
43884c406e7SOri Kam 			.proto = mask->hdr.next_proto_id,
43984c406e7SOri Kam 			.tos = mask->hdr.type_of_service,
44084c406e7SOri Kam 		};
44184c406e7SOri Kam 		/* Remove unwanted bits from values. */
44284c406e7SOri Kam 		ipv4.val.src_ip &= ipv4.mask.src_ip;
44384c406e7SOri Kam 		ipv4.val.dst_ip &= ipv4.mask.dst_ip;
44484c406e7SOri Kam 		ipv4.val.proto &= ipv4.mask.proto;
44584c406e7SOri Kam 		ipv4.val.tos &= ipv4.mask.tos;
44684c406e7SOri Kam 	}
4474a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &ipv4, size);
44884c406e7SOri Kam }
44984c406e7SOri Kam 
45084c406e7SOri Kam /**
45184c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
45284c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
45384c406e7SOri Kam  * into the flow.
45484c406e7SOri Kam  *
4554a78c88eSYongseok Koh  * @param[in, out] dev_flow
4564a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
45784c406e7SOri Kam  * @param[in] item
45884c406e7SOri Kam  *   Item specification.
4594a78c88eSYongseok Koh  * @param[in] item_flags
4604a78c88eSYongseok Koh  *   Parsed item flags.
46184c406e7SOri Kam  */
46284c406e7SOri Kam static void
4634a78c88eSYongseok Koh flow_verbs_translate_item_ipv6(struct mlx5_flow *dev_flow,
4644a78c88eSYongseok Koh 			       const struct rte_flow_item *item,
4654a78c88eSYongseok Koh 			       uint64_t item_flags)
46684c406e7SOri Kam {
46784c406e7SOri Kam 	const struct rte_flow_item_ipv6 *spec = item->spec;
46884c406e7SOri Kam 	const struct rte_flow_item_ipv6 *mask = item->mask;
46984c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_ipv6);
47084c406e7SOri Kam 	struct ibv_flow_spec_ipv6 ipv6 = {
4714a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_IPV6 | VERBS_SPEC_INNER(item_flags),
47284c406e7SOri Kam 		.size = size,
47384c406e7SOri Kam 	};
47484c406e7SOri Kam 
47584c406e7SOri Kam 	if (!mask)
47684c406e7SOri Kam 		mask = &rte_flow_item_ipv6_mask;
47784c406e7SOri Kam 	if (spec) {
47884c406e7SOri Kam 		unsigned int i;
47984c406e7SOri Kam 		uint32_t vtc_flow_val;
48084c406e7SOri Kam 		uint32_t vtc_flow_mask;
48184c406e7SOri Kam 
48284c406e7SOri Kam 		memcpy(&ipv6.val.src_ip, spec->hdr.src_addr,
48384c406e7SOri Kam 		       RTE_DIM(ipv6.val.src_ip));
48484c406e7SOri Kam 		memcpy(&ipv6.val.dst_ip, spec->hdr.dst_addr,
48584c406e7SOri Kam 		       RTE_DIM(ipv6.val.dst_ip));
48684c406e7SOri Kam 		memcpy(&ipv6.mask.src_ip, mask->hdr.src_addr,
48784c406e7SOri Kam 		       RTE_DIM(ipv6.mask.src_ip));
48884c406e7SOri Kam 		memcpy(&ipv6.mask.dst_ip, mask->hdr.dst_addr,
48984c406e7SOri Kam 		       RTE_DIM(ipv6.mask.dst_ip));
49084c406e7SOri Kam 		vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);
49184c406e7SOri Kam 		vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);
49284c406e7SOri Kam 		ipv6.val.flow_label =
49324ac604eSOlivier Matz 			rte_cpu_to_be_32((vtc_flow_val & RTE_IPV6_HDR_FL_MASK) >>
49424ac604eSOlivier Matz 					 RTE_IPV6_HDR_FL_SHIFT);
49524ac604eSOlivier Matz 		ipv6.val.traffic_class = (vtc_flow_val & RTE_IPV6_HDR_TC_MASK) >>
49624ac604eSOlivier Matz 					 RTE_IPV6_HDR_TC_SHIFT;
49784c406e7SOri Kam 		ipv6.val.next_hdr = spec->hdr.proto;
49884c406e7SOri Kam 		ipv6.mask.flow_label =
49924ac604eSOlivier Matz 			rte_cpu_to_be_32((vtc_flow_mask & RTE_IPV6_HDR_FL_MASK) >>
50024ac604eSOlivier Matz 					 RTE_IPV6_HDR_FL_SHIFT);
50124ac604eSOlivier Matz 		ipv6.mask.traffic_class = (vtc_flow_mask & RTE_IPV6_HDR_TC_MASK) >>
50224ac604eSOlivier Matz 					  RTE_IPV6_HDR_TC_SHIFT;
50384c406e7SOri Kam 		ipv6.mask.next_hdr = mask->hdr.proto;
50484c406e7SOri Kam 		/* Remove unwanted bits from values. */
50584c406e7SOri Kam 		for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {
50684c406e7SOri Kam 			ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];
50784c406e7SOri Kam 			ipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];
50884c406e7SOri Kam 		}
50984c406e7SOri Kam 		ipv6.val.flow_label &= ipv6.mask.flow_label;
51084c406e7SOri Kam 		ipv6.val.traffic_class &= ipv6.mask.traffic_class;
51184c406e7SOri Kam 		ipv6.val.next_hdr &= ipv6.mask.next_hdr;
51284c406e7SOri Kam 	}
5134a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &ipv6, size);
51484c406e7SOri Kam }
51584c406e7SOri Kam 
51684c406e7SOri Kam /**
51784c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
51884c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
51984c406e7SOri Kam  * into the flow.
52084c406e7SOri Kam  *
5214a78c88eSYongseok Koh  * @param[in, out] dev_flow
5224a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
52384c406e7SOri Kam  * @param[in] item
52484c406e7SOri Kam  *   Item specification.
5254a78c88eSYongseok Koh  * @param[in] item_flags
5264a78c88eSYongseok Koh  *   Parsed item flags.
52784c406e7SOri Kam  */
52884c406e7SOri Kam static void
5294a78c88eSYongseok Koh flow_verbs_translate_item_tcp(struct mlx5_flow *dev_flow,
5304a78c88eSYongseok Koh 			      const struct rte_flow_item *item,
5314a78c88eSYongseok Koh 			      uint64_t item_flags __rte_unused)
53284c406e7SOri Kam {
53384c406e7SOri Kam 	const struct rte_flow_item_tcp *spec = item->spec;
53484c406e7SOri Kam 	const struct rte_flow_item_tcp *mask = item->mask;
53584c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
53684c406e7SOri Kam 	struct ibv_flow_spec_tcp_udp tcp = {
5374a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_TCP | VERBS_SPEC_INNER(item_flags),
53884c406e7SOri Kam 		.size = size,
53984c406e7SOri Kam 	};
54084c406e7SOri Kam 
54184c406e7SOri Kam 	if (!mask)
54284c406e7SOri Kam 		mask = &rte_flow_item_tcp_mask;
54384c406e7SOri Kam 	if (spec) {
54484c406e7SOri Kam 		tcp.val.dst_port = spec->hdr.dst_port;
54584c406e7SOri Kam 		tcp.val.src_port = spec->hdr.src_port;
54684c406e7SOri Kam 		tcp.mask.dst_port = mask->hdr.dst_port;
54784c406e7SOri Kam 		tcp.mask.src_port = mask->hdr.src_port;
54884c406e7SOri Kam 		/* Remove unwanted bits from values. */
54984c406e7SOri Kam 		tcp.val.src_port &= tcp.mask.src_port;
55084c406e7SOri Kam 		tcp.val.dst_port &= tcp.mask.dst_port;
55184c406e7SOri Kam 	}
5524a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &tcp, size);
55384c406e7SOri Kam }
55484c406e7SOri Kam 
55584c406e7SOri Kam /**
55684c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
55784c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
55884c406e7SOri Kam  * into the flow.
55984c406e7SOri Kam  *
5604a78c88eSYongseok Koh  * @param[in, out] dev_flow
5614a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
56284c406e7SOri Kam  * @param[in] item
56384c406e7SOri Kam  *   Item specification.
5644a78c88eSYongseok Koh  * @param[in] item_flags
5654a78c88eSYongseok Koh  *   Parsed item flags.
56684c406e7SOri Kam  */
56784c406e7SOri Kam static void
5684a78c88eSYongseok Koh flow_verbs_translate_item_udp(struct mlx5_flow *dev_flow,
5694a78c88eSYongseok Koh 			      const struct rte_flow_item *item,
5704a78c88eSYongseok Koh 			      uint64_t item_flags __rte_unused)
5714a78c88eSYongseok Koh {
5724a78c88eSYongseok Koh 	const struct rte_flow_item_udp *spec = item->spec;
5734a78c88eSYongseok Koh 	const struct rte_flow_item_udp *mask = item->mask;
5744a78c88eSYongseok Koh 	unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
5754a78c88eSYongseok Koh 	struct ibv_flow_spec_tcp_udp udp = {
5764a78c88eSYongseok Koh 		.type = IBV_FLOW_SPEC_UDP | VERBS_SPEC_INNER(item_flags),
5774a78c88eSYongseok Koh 		.size = size,
5784a78c88eSYongseok Koh 	};
5794a78c88eSYongseok Koh 
5804a78c88eSYongseok Koh 	if (!mask)
5814a78c88eSYongseok Koh 		mask = &rte_flow_item_udp_mask;
5824a78c88eSYongseok Koh 	if (spec) {
5834a78c88eSYongseok Koh 		udp.val.dst_port = spec->hdr.dst_port;
5844a78c88eSYongseok Koh 		udp.val.src_port = spec->hdr.src_port;
5854a78c88eSYongseok Koh 		udp.mask.dst_port = mask->hdr.dst_port;
5864a78c88eSYongseok Koh 		udp.mask.src_port = mask->hdr.src_port;
5874a78c88eSYongseok Koh 		/* Remove unwanted bits from values. */
5884a78c88eSYongseok Koh 		udp.val.src_port &= udp.mask.src_port;
5894a78c88eSYongseok Koh 		udp.val.dst_port &= udp.mask.dst_port;
5904a78c88eSYongseok Koh 	}
5914a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &udp, size);
5924a78c88eSYongseok Koh }
5934a78c88eSYongseok Koh 
5944a78c88eSYongseok Koh /**
5954a78c88eSYongseok Koh  * Convert the @p item into a Verbs specification. This function assumes that
5964a78c88eSYongseok Koh  * the input is valid and that there is space to insert the requested item
5974a78c88eSYongseok Koh  * into the flow.
5984a78c88eSYongseok Koh  *
5994a78c88eSYongseok Koh  * @param[in, out] dev_flow
6004a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
6014a78c88eSYongseok Koh  * @param[in] item
6024a78c88eSYongseok Koh  *   Item specification.
6034a78c88eSYongseok Koh  * @param[in] item_flags
6044a78c88eSYongseok Koh  *   Parsed item flags.
6054a78c88eSYongseok Koh  */
6064a78c88eSYongseok Koh static void
6074a78c88eSYongseok Koh flow_verbs_translate_item_vxlan(struct mlx5_flow *dev_flow,
6084a78c88eSYongseok Koh 				const struct rte_flow_item *item,
6094a78c88eSYongseok Koh 				uint64_t item_flags __rte_unused)
61084c406e7SOri Kam {
61184c406e7SOri Kam 	const struct rte_flow_item_vxlan *spec = item->spec;
61284c406e7SOri Kam 	const struct rte_flow_item_vxlan *mask = item->mask;
61384c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
61484c406e7SOri Kam 	struct ibv_flow_spec_tunnel vxlan = {
61584c406e7SOri Kam 		.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
61684c406e7SOri Kam 		.size = size,
61784c406e7SOri Kam 	};
61884c406e7SOri Kam 	union vni {
61984c406e7SOri Kam 		uint32_t vlan_id;
62084c406e7SOri Kam 		uint8_t vni[4];
62184c406e7SOri Kam 	} id = { .vlan_id = 0, };
62284c406e7SOri Kam 
62384c406e7SOri Kam 	if (!mask)
62484c406e7SOri Kam 		mask = &rte_flow_item_vxlan_mask;
62584c406e7SOri Kam 	if (spec) {
62684c406e7SOri Kam 		memcpy(&id.vni[1], spec->vni, 3);
62784c406e7SOri Kam 		vxlan.val.tunnel_id = id.vlan_id;
62884c406e7SOri Kam 		memcpy(&id.vni[1], mask->vni, 3);
62984c406e7SOri Kam 		vxlan.mask.tunnel_id = id.vlan_id;
63084c406e7SOri Kam 		/* Remove unwanted bits from values. */
63184c406e7SOri Kam 		vxlan.val.tunnel_id &= vxlan.mask.tunnel_id;
63284c406e7SOri Kam 	}
6334a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &vxlan, size);
63484c406e7SOri Kam }
63584c406e7SOri Kam 
63684c406e7SOri Kam /**
63784c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
63884c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
63984c406e7SOri Kam  * into the flow.
64084c406e7SOri Kam  *
6414a78c88eSYongseok Koh  * @param[in, out] dev_flow
6424a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
64384c406e7SOri Kam  * @param[in] item
64484c406e7SOri Kam  *   Item specification.
6454a78c88eSYongseok Koh  * @param[in] item_flags
6464a78c88eSYongseok Koh  *   Parsed item flags.
64784c406e7SOri Kam  */
64884c406e7SOri Kam static void
6494a78c88eSYongseok Koh flow_verbs_translate_item_vxlan_gpe(struct mlx5_flow *dev_flow,
6504a78c88eSYongseok Koh 				    const struct rte_flow_item *item,
6514a78c88eSYongseok Koh 				    uint64_t item_flags __rte_unused)
65284c406e7SOri Kam {
65384c406e7SOri Kam 	const struct rte_flow_item_vxlan_gpe *spec = item->spec;
65484c406e7SOri Kam 	const struct rte_flow_item_vxlan_gpe *mask = item->mask;
65584c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
65684c406e7SOri Kam 	struct ibv_flow_spec_tunnel vxlan_gpe = {
65784c406e7SOri Kam 		.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
65884c406e7SOri Kam 		.size = size,
65984c406e7SOri Kam 	};
66084c406e7SOri Kam 	union vni {
66184c406e7SOri Kam 		uint32_t vlan_id;
66284c406e7SOri Kam 		uint8_t vni[4];
66384c406e7SOri Kam 	} id = { .vlan_id = 0, };
66484c406e7SOri Kam 
66584c406e7SOri Kam 	if (!mask)
66684c406e7SOri Kam 		mask = &rte_flow_item_vxlan_gpe_mask;
66784c406e7SOri Kam 	if (spec) {
66884c406e7SOri Kam 		memcpy(&id.vni[1], spec->vni, 3);
66984c406e7SOri Kam 		vxlan_gpe.val.tunnel_id = id.vlan_id;
67084c406e7SOri Kam 		memcpy(&id.vni[1], mask->vni, 3);
67184c406e7SOri Kam 		vxlan_gpe.mask.tunnel_id = id.vlan_id;
67284c406e7SOri Kam 		/* Remove unwanted bits from values. */
67384c406e7SOri Kam 		vxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id;
67484c406e7SOri Kam 	}
6754a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &vxlan_gpe, size);
67684c406e7SOri Kam }
67784c406e7SOri Kam 
67884c406e7SOri Kam /**
67984c406e7SOri Kam  * Update the protocol in Verbs IPv4/IPv6 spec.
68084c406e7SOri Kam  *
68184c406e7SOri Kam  * @param[in, out] attr
68284c406e7SOri Kam  *   Pointer to Verbs attributes structure.
68384c406e7SOri Kam  * @param[in] search
68484c406e7SOri Kam  *   Specification type to search in order to update the IP protocol.
68584c406e7SOri Kam  * @param[in] protocol
68684c406e7SOri Kam  *   Protocol value to set if none is present in the specification.
68784c406e7SOri Kam  */
68884c406e7SOri Kam static void
68984c406e7SOri Kam flow_verbs_item_gre_ip_protocol_update(struct ibv_flow_attr *attr,
69084c406e7SOri Kam 				       enum ibv_flow_spec_type search,
69184c406e7SOri Kam 				       uint8_t protocol)
69284c406e7SOri Kam {
69384c406e7SOri Kam 	unsigned int i;
69484c406e7SOri Kam 	struct ibv_spec_header *hdr = (struct ibv_spec_header *)
69584c406e7SOri Kam 		((uint8_t *)attr + sizeof(struct ibv_flow_attr));
69684c406e7SOri Kam 
69784c406e7SOri Kam 	if (!attr)
69884c406e7SOri Kam 		return;
69984c406e7SOri Kam 	for (i = 0; i != attr->num_of_specs; ++i) {
70084c406e7SOri Kam 		if (hdr->type == search) {
70184c406e7SOri Kam 			union {
70284c406e7SOri Kam 				struct ibv_flow_spec_ipv4_ext *ipv4;
70384c406e7SOri Kam 				struct ibv_flow_spec_ipv6 *ipv6;
70484c406e7SOri Kam 			} ip;
70584c406e7SOri Kam 
70684c406e7SOri Kam 			switch (search) {
70784c406e7SOri Kam 			case IBV_FLOW_SPEC_IPV4_EXT:
70884c406e7SOri Kam 				ip.ipv4 = (struct ibv_flow_spec_ipv4_ext *)hdr;
70984c406e7SOri Kam 				if (!ip.ipv4->val.proto) {
71084c406e7SOri Kam 					ip.ipv4->val.proto = protocol;
71184c406e7SOri Kam 					ip.ipv4->mask.proto = 0xff;
71284c406e7SOri Kam 				}
71384c406e7SOri Kam 				break;
71484c406e7SOri Kam 			case IBV_FLOW_SPEC_IPV6:
71584c406e7SOri Kam 				ip.ipv6 = (struct ibv_flow_spec_ipv6 *)hdr;
71684c406e7SOri Kam 				if (!ip.ipv6->val.next_hdr) {
71784c406e7SOri Kam 					ip.ipv6->val.next_hdr = protocol;
71884c406e7SOri Kam 					ip.ipv6->mask.next_hdr = 0xff;
71984c406e7SOri Kam 				}
72084c406e7SOri Kam 				break;
72184c406e7SOri Kam 			default:
72284c406e7SOri Kam 				break;
72384c406e7SOri Kam 			}
72484c406e7SOri Kam 			break;
72584c406e7SOri Kam 		}
72684c406e7SOri Kam 		hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
72784c406e7SOri Kam 	}
72884c406e7SOri Kam }
72984c406e7SOri Kam 
73084c406e7SOri Kam /**
73184c406e7SOri Kam  * Convert the @p item into a Verbs specification. This function assumes that
73284c406e7SOri Kam  * the input is valid and that there is space to insert the requested item
73384c406e7SOri Kam  * into the flow.
73484c406e7SOri Kam  *
7354a78c88eSYongseok Koh  * @param[in, out] dev_flow
7364a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
73784c406e7SOri Kam  * @param[in] item
73884c406e7SOri Kam  *   Item specification.
7394a78c88eSYongseok Koh  * @param[in] item_flags
7404a78c88eSYongseok Koh  *   Parsed item flags.
74184c406e7SOri Kam  */
74284c406e7SOri Kam static void
7434a78c88eSYongseok Koh flow_verbs_translate_item_gre(struct mlx5_flow *dev_flow,
7444a78c88eSYongseok Koh 			      const struct rte_flow_item *item __rte_unused,
7454a78c88eSYongseok Koh 			      uint64_t item_flags)
74684c406e7SOri Kam {
747*c42f44bdSBing Zhao 	struct mlx5_flow_resource_verbs *verbs = &dev_flow->verbs;
74884c406e7SOri Kam #ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT
74984c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
75084c406e7SOri Kam 	struct ibv_flow_spec_tunnel tunnel = {
75184c406e7SOri Kam 		.type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
75284c406e7SOri Kam 		.size = size,
75384c406e7SOri Kam 	};
75484c406e7SOri Kam #else
75584c406e7SOri Kam 	const struct rte_flow_item_gre *spec = item->spec;
75684c406e7SOri Kam 	const struct rte_flow_item_gre *mask = item->mask;
75784c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_gre);
75884c406e7SOri Kam 	struct ibv_flow_spec_gre tunnel = {
75984c406e7SOri Kam 		.type = IBV_FLOW_SPEC_GRE,
76084c406e7SOri Kam 		.size = size,
76184c406e7SOri Kam 	};
76284c406e7SOri Kam 
76384c406e7SOri Kam 	if (!mask)
76484c406e7SOri Kam 		mask = &rte_flow_item_gre_mask;
76584c406e7SOri Kam 	if (spec) {
76684c406e7SOri Kam 		tunnel.val.c_ks_res0_ver = spec->c_rsvd0_ver;
76784c406e7SOri Kam 		tunnel.val.protocol = spec->protocol;
76884c406e7SOri Kam 		tunnel.mask.c_ks_res0_ver = mask->c_rsvd0_ver;
76984c406e7SOri Kam 		tunnel.mask.protocol = mask->protocol;
77084c406e7SOri Kam 		/* Remove unwanted bits from values. */
77184c406e7SOri Kam 		tunnel.val.c_ks_res0_ver &= tunnel.mask.c_ks_res0_ver;
77284c406e7SOri Kam 		tunnel.val.protocol &= tunnel.mask.protocol;
77384c406e7SOri Kam 		tunnel.val.key &= tunnel.mask.key;
77484c406e7SOri Kam 	}
77584c406e7SOri Kam #endif
7764a78c88eSYongseok Koh 	if (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
77784c406e7SOri Kam 		flow_verbs_item_gre_ip_protocol_update(verbs->attr,
77884c406e7SOri Kam 						       IBV_FLOW_SPEC_IPV4_EXT,
77984c406e7SOri Kam 						       IPPROTO_GRE);
78084c406e7SOri Kam 	else
78184c406e7SOri Kam 		flow_verbs_item_gre_ip_protocol_update(verbs->attr,
78284c406e7SOri Kam 						       IBV_FLOW_SPEC_IPV6,
78384c406e7SOri Kam 						       IPPROTO_GRE);
7844a78c88eSYongseok Koh 	flow_verbs_spec_add(verbs, &tunnel, size);
78584c406e7SOri Kam }
78684c406e7SOri Kam 
78784c406e7SOri Kam /**
78884c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
78984c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
79084c406e7SOri Kam  * into the flow. This function also return the action that was added.
79184c406e7SOri Kam  *
7924a78c88eSYongseok Koh  * @param[in, out] dev_flow
7934a78c88eSYongseok Koh  *   Pointer to dev_flow structure.
79484c406e7SOri Kam  * @param[in] item
79584c406e7SOri Kam  *   Item specification.
7964a78c88eSYongseok Koh  * @param[in] item_flags
7974a78c88eSYongseok Koh  *   Parsed item flags.
79884c406e7SOri Kam  */
79984c406e7SOri Kam static void
8004a78c88eSYongseok Koh flow_verbs_translate_item_mpls(struct mlx5_flow *dev_flow __rte_unused,
8014a78c88eSYongseok Koh 			       const struct rte_flow_item *item __rte_unused,
8024a78c88eSYongseok Koh 			       uint64_t item_flags __rte_unused)
80384c406e7SOri Kam {
80484c406e7SOri Kam #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
80584c406e7SOri Kam 	const struct rte_flow_item_mpls *spec = item->spec;
80684c406e7SOri Kam 	const struct rte_flow_item_mpls *mask = item->mask;
80784c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_mpls);
80884c406e7SOri Kam 	struct ibv_flow_spec_mpls mpls = {
80984c406e7SOri Kam 		.type = IBV_FLOW_SPEC_MPLS,
81084c406e7SOri Kam 		.size = size,
81184c406e7SOri Kam 	};
81284c406e7SOri Kam 
81384c406e7SOri Kam 	if (!mask)
81484c406e7SOri Kam 		mask = &rte_flow_item_mpls_mask;
81584c406e7SOri Kam 	if (spec) {
81684c406e7SOri Kam 		memcpy(&mpls.val.label, spec, sizeof(mpls.val.label));
81784c406e7SOri Kam 		memcpy(&mpls.mask.label, mask, sizeof(mpls.mask.label));
81884c406e7SOri Kam 		/* Remove unwanted bits from values.  */
81984c406e7SOri Kam 		mpls.val.label &= mpls.mask.label;
82084c406e7SOri Kam 	}
8214a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &mpls, size);
82284c406e7SOri Kam #endif
82384c406e7SOri Kam }
82484c406e7SOri Kam 
82584c406e7SOri Kam /**
82684c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
82784c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
8284a78c88eSYongseok Koh  * into the flow.
82984c406e7SOri Kam  *
83084c406e7SOri Kam  * @param[in] dev_flow
83184c406e7SOri Kam  *   Pointer to mlx5_flow.
8324a78c88eSYongseok Koh  * @param[in] action
8334a78c88eSYongseok Koh  *   Action configuration.
83484c406e7SOri Kam  */
83584c406e7SOri Kam static void
8364a78c88eSYongseok Koh flow_verbs_translate_action_drop
8374a78c88eSYongseok Koh 	(struct mlx5_flow *dev_flow,
8384a78c88eSYongseok Koh 	 const struct rte_flow_action *action __rte_unused)
83984c406e7SOri Kam {
84084c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_action_drop);
84184c406e7SOri Kam 	struct ibv_flow_spec_action_drop drop = {
84284c406e7SOri Kam 			.type = IBV_FLOW_SPEC_ACTION_DROP,
84384c406e7SOri Kam 			.size = size,
84484c406e7SOri Kam 	};
84584c406e7SOri Kam 
8464a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &drop, size);
84784c406e7SOri Kam }
84884c406e7SOri Kam 
84984c406e7SOri Kam /**
85084c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
85184c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
8524a78c88eSYongseok Koh  * into the flow.
85384c406e7SOri Kam  *
85484c406e7SOri Kam  * @param[in] dev_flow
85584c406e7SOri Kam  *   Pointer to mlx5_flow.
8564a78c88eSYongseok Koh  * @param[in] action
8574a78c88eSYongseok Koh  *   Action configuration.
85884c406e7SOri Kam  */
85984c406e7SOri Kam static void
8604a78c88eSYongseok Koh flow_verbs_translate_action_queue(struct mlx5_flow *dev_flow,
8614a78c88eSYongseok Koh 				  const struct rte_flow_action *action)
86284c406e7SOri Kam {
86384c406e7SOri Kam 	const struct rte_flow_action_queue *queue = action->conf;
86484c406e7SOri Kam 	struct rte_flow *flow = dev_flow->flow;
86584c406e7SOri Kam 
866e205c95fSViacheslav Ovsiienko 	if (flow->rss.queue)
867e205c95fSViacheslav Ovsiienko 		(*flow->rss.queue)[0] = queue->index;
86884c406e7SOri Kam 	flow->rss.queue_num = 1;
86984c406e7SOri Kam }
87084c406e7SOri Kam 
87184c406e7SOri Kam /**
87284c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
87384c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
8744a78c88eSYongseok Koh  * into the flow.
87584c406e7SOri Kam  *
87684c406e7SOri Kam  * @param[in] action
87784c406e7SOri Kam  *   Action configuration.
87884c406e7SOri Kam  * @param[in, out] action_flags
87984c406e7SOri Kam  *   Pointer to the detected actions.
88084c406e7SOri Kam  * @param[in] dev_flow
88184c406e7SOri Kam  *   Pointer to mlx5_flow.
88284c406e7SOri Kam  */
88384c406e7SOri Kam static void
8844a78c88eSYongseok Koh flow_verbs_translate_action_rss(struct mlx5_flow *dev_flow,
8854a78c88eSYongseok Koh 				const struct rte_flow_action *action)
88684c406e7SOri Kam {
88784c406e7SOri Kam 	const struct rte_flow_action_rss *rss = action->conf;
888f1b85a27SOphir Munk 	const uint8_t *rss_key;
88984c406e7SOri Kam 	struct rte_flow *flow = dev_flow->flow;
89084c406e7SOri Kam 
891e205c95fSViacheslav Ovsiienko 	if (flow->rss.queue)
892e205c95fSViacheslav Ovsiienko 		memcpy((*flow->rss.queue), rss->queue,
89384c406e7SOri Kam 		       rss->queue_num * sizeof(uint16_t));
89484c406e7SOri Kam 	flow->rss.queue_num = rss->queue_num;
895f1b85a27SOphir Munk 	/* NULL RSS key indicates default RSS key. */
896f1b85a27SOphir Munk 	rss_key = !rss->key ? rss_hash_default_key : rss->key;
897e205c95fSViacheslav Ovsiienko 	memcpy(flow->rss.key, rss_key, MLX5_RSS_HASH_KEY_LEN);
898e205c95fSViacheslav Ovsiienko 	/*
899e205c95fSViacheslav Ovsiienko 	 * rss->level and rss.types should be set in advance when expanding
900e205c95fSViacheslav Ovsiienko 	 * items for RSS.
901e205c95fSViacheslav Ovsiienko 	 */
90284c406e7SOri Kam }
90384c406e7SOri Kam 
90484c406e7SOri Kam /**
90584c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
90684c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
9074a78c88eSYongseok Koh  * into the flow.
90884c406e7SOri Kam  *
90984c406e7SOri Kam  * @param[in] dev_flow
91084c406e7SOri Kam  *   Pointer to mlx5_flow.
9114a78c88eSYongseok Koh  * @param[in] action
9124a78c88eSYongseok Koh  *   Action configuration.
91384c406e7SOri Kam  */
91484c406e7SOri Kam static void
91584c406e7SOri Kam flow_verbs_translate_action_flag
9164a78c88eSYongseok Koh 	(struct mlx5_flow *dev_flow,
9174a78c88eSYongseok Koh 	 const struct rte_flow_action *action __rte_unused)
91884c406e7SOri Kam {
91984c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
92084c406e7SOri Kam 	struct ibv_flow_spec_action_tag tag = {
92184c406e7SOri Kam 		.type = IBV_FLOW_SPEC_ACTION_TAG,
92284c406e7SOri Kam 		.size = size,
92384c406e7SOri Kam 		.tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT),
92484c406e7SOri Kam 	};
92584c406e7SOri Kam 
9264a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &tag, size);
92784c406e7SOri Kam }
92884c406e7SOri Kam 
92984c406e7SOri Kam /**
93084c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
93184c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
9324a78c88eSYongseok Koh  * into the flow.
93384c406e7SOri Kam  *
93484c406e7SOri Kam  * @param[in] dev_flow
93584c406e7SOri Kam  *   Pointer to mlx5_flow.
9364a78c88eSYongseok Koh  * @param[in] action
9374a78c88eSYongseok Koh  *   Action configuration.
93884c406e7SOri Kam  */
93984c406e7SOri Kam static void
9404a78c88eSYongseok Koh flow_verbs_translate_action_mark(struct mlx5_flow *dev_flow,
9414a78c88eSYongseok Koh 				 const struct rte_flow_action *action)
94284c406e7SOri Kam {
94384c406e7SOri Kam 	const struct rte_flow_action_mark *mark = action->conf;
94484c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
94584c406e7SOri Kam 	struct ibv_flow_spec_action_tag tag = {
94684c406e7SOri Kam 		.type = IBV_FLOW_SPEC_ACTION_TAG,
94784c406e7SOri Kam 		.size = size,
9484a78c88eSYongseok Koh 		.tag_id = mlx5_flow_mark_set(mark->id),
94984c406e7SOri Kam 	};
95084c406e7SOri Kam 
9514a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &tag, size);
95284c406e7SOri Kam }
95384c406e7SOri Kam 
95484c406e7SOri Kam /**
95584c406e7SOri Kam  * Convert the @p action into a Verbs specification. This function assumes that
95684c406e7SOri Kam  * the input is valid and that there is space to insert the requested action
9574a78c88eSYongseok Koh  * into the flow.
95884c406e7SOri Kam  *
95984c406e7SOri Kam  * @param[in] dev
96084c406e7SOri Kam  *   Pointer to the Ethernet device structure.
96184c406e7SOri Kam  * @param[in] action
96284c406e7SOri Kam  *   Action configuration.
96384c406e7SOri Kam  * @param[in] dev_flow
96484c406e7SOri Kam  *   Pointer to mlx5_flow.
96584c406e7SOri Kam  * @param[out] error
96684c406e7SOri Kam  *   Pointer to error structure.
96784c406e7SOri Kam  *
96884c406e7SOri Kam  * @return
96984c406e7SOri Kam  *   0 On success else a negative errno value is returned and rte_errno is set.
97084c406e7SOri Kam  */
97184c406e7SOri Kam static int
9724a78c88eSYongseok Koh flow_verbs_translate_action_count(struct mlx5_flow *dev_flow,
97384c406e7SOri Kam 				  const struct rte_flow_action *action,
9744a78c88eSYongseok Koh 				  struct rte_eth_dev *dev,
97584c406e7SOri Kam 				  struct rte_flow_error *error)
97684c406e7SOri Kam {
97784c406e7SOri Kam 	const struct rte_flow_action_count *count = action->conf;
97884c406e7SOri Kam 	struct rte_flow *flow = dev_flow->flow;
979db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
980db48f9dbSViacheslav Ovsiienko 	defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
98184c406e7SOri Kam 	unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
98284c406e7SOri Kam 	struct ibv_flow_spec_counter_action counter = {
98384c406e7SOri Kam 		.type = IBV_FLOW_SPEC_ACTION_COUNT,
98484c406e7SOri Kam 		.size = size,
98584c406e7SOri Kam 	};
98684c406e7SOri Kam #endif
98784c406e7SOri Kam 
98884c406e7SOri Kam 	if (!flow->counter) {
98984c406e7SOri Kam 		flow->counter = flow_verbs_counter_new(dev, count->shared,
99084c406e7SOri Kam 						       count->id);
99184c406e7SOri Kam 		if (!flow->counter)
99284c406e7SOri Kam 			return rte_flow_error_set(error, rte_errno,
99384c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ACTION,
99484c406e7SOri Kam 						  action,
99584c406e7SOri Kam 						  "cannot get counter"
99684c406e7SOri Kam 						  " context.");
99784c406e7SOri Kam 	}
998db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42)
99984c406e7SOri Kam 	counter.counter_set_handle = flow->counter->cs->handle;
10004a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &counter, size);
1001db48f9dbSViacheslav Ovsiienko #elif defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
1002db48f9dbSViacheslav Ovsiienko 	counter.counters = flow->counter->cs;
10034a78c88eSYongseok Koh 	flow_verbs_spec_add(&dev_flow->verbs, &counter, size);
100484c406e7SOri Kam #endif
100584c406e7SOri Kam 	return 0;
100684c406e7SOri Kam }
100784c406e7SOri Kam 
100884c406e7SOri Kam /**
100984c406e7SOri Kam  * Internal validation function. For validating both actions and items.
101084c406e7SOri Kam  *
101184c406e7SOri Kam  * @param[in] dev
101284c406e7SOri Kam  *   Pointer to the Ethernet device structure.
101384c406e7SOri Kam  * @param[in] attr
101484c406e7SOri Kam  *   Pointer to the flow attributes.
101584c406e7SOri Kam  * @param[in] items
101684c406e7SOri Kam  *   Pointer to the list of items.
101784c406e7SOri Kam  * @param[in] actions
101884c406e7SOri Kam  *   Pointer to the list of actions.
1019b67b4ecbSDekel Peled  * @param[in] external
1020b67b4ecbSDekel Peled  *   This flow rule is created by request external to PMD.
102184c406e7SOri Kam  * @param[out] error
102284c406e7SOri Kam  *   Pointer to the error structure.
102384c406e7SOri Kam  *
102484c406e7SOri Kam  * @return
102584c406e7SOri Kam  *   0 on success, a negative errno value otherwise and rte_errno is set.
102684c406e7SOri Kam  */
102784c406e7SOri Kam static int
102884c406e7SOri Kam flow_verbs_validate(struct rte_eth_dev *dev,
102984c406e7SOri Kam 		    const struct rte_flow_attr *attr,
103084c406e7SOri Kam 		    const struct rte_flow_item items[],
103184c406e7SOri Kam 		    const struct rte_flow_action actions[],
1032b67b4ecbSDekel Peled 		    bool external __rte_unused,
103384c406e7SOri Kam 		    struct rte_flow_error *error)
103484c406e7SOri Kam {
103584c406e7SOri Kam 	int ret;
10360ddd1143SYongseok Koh 	uint64_t action_flags = 0;
10370ddd1143SYongseok Koh 	uint64_t item_flags = 0;
103838f7efaaSDekel Peled 	uint64_t last_item = 0;
103984c406e7SOri Kam 	uint8_t next_protocol = 0xff;
1040fba32130SXiaoyu Min 	uint16_t ether_type = 0;
104184c406e7SOri Kam 
104284c406e7SOri Kam 	if (items == NULL)
104384c406e7SOri Kam 		return -1;
104484c406e7SOri Kam 	ret = mlx5_flow_validate_attributes(dev, attr, error);
104584c406e7SOri Kam 	if (ret < 0)
104684c406e7SOri Kam 		return ret;
104784c406e7SOri Kam 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
10484a78c88eSYongseok Koh 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
104984c406e7SOri Kam 		int ret = 0;
105024663641SYongseok Koh 
105184c406e7SOri Kam 		switch (items->type) {
105284c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VOID:
105384c406e7SOri Kam 			break;
105484c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_ETH:
105584c406e7SOri Kam 			ret = mlx5_flow_validate_item_eth(items, item_flags,
105684c406e7SOri Kam 							  error);
105784c406e7SOri Kam 			if (ret < 0)
105884c406e7SOri Kam 				return ret;
105938f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
106084c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L2;
1061fba32130SXiaoyu Min 			if (items->mask != NULL && items->spec != NULL) {
1062fba32130SXiaoyu Min 				ether_type =
1063fba32130SXiaoyu Min 					((const struct rte_flow_item_eth *)
1064fba32130SXiaoyu Min 					 items->spec)->type;
1065fba32130SXiaoyu Min 				ether_type &=
1066fba32130SXiaoyu Min 					((const struct rte_flow_item_eth *)
1067fba32130SXiaoyu Min 					 items->mask)->type;
1068fba32130SXiaoyu Min 				ether_type = rte_be_to_cpu_16(ether_type);
1069fba32130SXiaoyu Min 			} else {
1070fba32130SXiaoyu Min 				ether_type = 0;
1071fba32130SXiaoyu Min 			}
107284c406e7SOri Kam 			break;
107384c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VLAN:
107484c406e7SOri Kam 			ret = mlx5_flow_validate_item_vlan(items, item_flags,
1075dfedf3e3SViacheslav Ovsiienko 							   dev, error);
107684c406e7SOri Kam 			if (ret < 0)
107784c406e7SOri Kam 				return ret;
107838f7efaaSDekel Peled 			last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
10794a78c88eSYongseok Koh 					      MLX5_FLOW_LAYER_INNER_VLAN) :
10804a78c88eSYongseok Koh 					     (MLX5_FLOW_LAYER_OUTER_L2 |
10814a78c88eSYongseok Koh 					      MLX5_FLOW_LAYER_OUTER_VLAN);
1082fba32130SXiaoyu Min 			if (items->mask != NULL && items->spec != NULL) {
1083fba32130SXiaoyu Min 				ether_type =
1084fba32130SXiaoyu Min 					((const struct rte_flow_item_vlan *)
1085fba32130SXiaoyu Min 					 items->spec)->inner_type;
1086fba32130SXiaoyu Min 				ether_type &=
1087fba32130SXiaoyu Min 					((const struct rte_flow_item_vlan *)
1088fba32130SXiaoyu Min 					 items->mask)->inner_type;
1089fba32130SXiaoyu Min 				ether_type = rte_be_to_cpu_16(ether_type);
1090fba32130SXiaoyu Min 			} else {
1091fba32130SXiaoyu Min 				ether_type = 0;
1092fba32130SXiaoyu Min 			}
109384c406e7SOri Kam 			break;
109484c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV4:
109584c406e7SOri Kam 			ret = mlx5_flow_validate_item_ipv4(items, item_flags,
1096fba32130SXiaoyu Min 							   last_item,
1097fba32130SXiaoyu Min 							   ether_type, NULL,
1098fba32130SXiaoyu Min 							   error);
109984c406e7SOri Kam 			if (ret < 0)
110084c406e7SOri Kam 				return ret;
110138f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
110284c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
110384c406e7SOri Kam 			if (items->mask != NULL &&
110484c406e7SOri Kam 			    ((const struct rte_flow_item_ipv4 *)
11053193c249SYongseok Koh 			     items->mask)->hdr.next_proto_id) {
110684c406e7SOri Kam 				next_protocol =
110784c406e7SOri Kam 					((const struct rte_flow_item_ipv4 *)
110884c406e7SOri Kam 					 (items->spec))->hdr.next_proto_id;
11093193c249SYongseok Koh 				next_protocol &=
11103193c249SYongseok Koh 					((const struct rte_flow_item_ipv4 *)
11113193c249SYongseok Koh 					 (items->mask))->hdr.next_proto_id;
11123193c249SYongseok Koh 			} else {
11133193c249SYongseok Koh 				/* Reset for inner layer. */
11143193c249SYongseok Koh 				next_protocol = 0xff;
11153193c249SYongseok Koh 			}
111684c406e7SOri Kam 			break;
111784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV6:
111884c406e7SOri Kam 			ret = mlx5_flow_validate_item_ipv6(items, item_flags,
1119fba32130SXiaoyu Min 							   last_item,
1120fba32130SXiaoyu Min 							   ether_type, NULL,
1121fba32130SXiaoyu Min 							   error);
112284c406e7SOri Kam 			if (ret < 0)
112384c406e7SOri Kam 				return ret;
112438f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
112584c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
112684c406e7SOri Kam 			if (items->mask != NULL &&
112784c406e7SOri Kam 			    ((const struct rte_flow_item_ipv6 *)
11283193c249SYongseok Koh 			     items->mask)->hdr.proto) {
112984c406e7SOri Kam 				next_protocol =
113084c406e7SOri Kam 					((const struct rte_flow_item_ipv6 *)
113184c406e7SOri Kam 					 items->spec)->hdr.proto;
11323193c249SYongseok Koh 				next_protocol &=
11333193c249SYongseok Koh 					((const struct rte_flow_item_ipv6 *)
11343193c249SYongseok Koh 					 items->mask)->hdr.proto;
11353193c249SYongseok Koh 			} else {
11363193c249SYongseok Koh 				/* Reset for inner layer. */
11373193c249SYongseok Koh 				next_protocol = 0xff;
11383193c249SYongseok Koh 			}
113984c406e7SOri Kam 			break;
114084c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_UDP:
114184c406e7SOri Kam 			ret = mlx5_flow_validate_item_udp(items, item_flags,
114284c406e7SOri Kam 							  next_protocol,
114384c406e7SOri Kam 							  error);
114484c406e7SOri Kam 			if (ret < 0)
114584c406e7SOri Kam 				return ret;
114638f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
114784c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
114884c406e7SOri Kam 			break;
114984c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_TCP:
115092378c2bSMoti Haimovsky 			ret = mlx5_flow_validate_item_tcp
115192378c2bSMoti Haimovsky 						(items, item_flags,
115292378c2bSMoti Haimovsky 						 next_protocol,
115392378c2bSMoti Haimovsky 						 &rte_flow_item_tcp_mask,
115492378c2bSMoti Haimovsky 						 error);
115584c406e7SOri Kam 			if (ret < 0)
115684c406e7SOri Kam 				return ret;
115738f7efaaSDekel Peled 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
115884c406e7SOri Kam 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
115984c406e7SOri Kam 			break;
116084c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN:
116184c406e7SOri Kam 			ret = mlx5_flow_validate_item_vxlan(items, item_flags,
116284c406e7SOri Kam 							    error);
116384c406e7SOri Kam 			if (ret < 0)
116484c406e7SOri Kam 				return ret;
116538f7efaaSDekel Peled 			last_item = MLX5_FLOW_LAYER_VXLAN;
116684c406e7SOri Kam 			break;
116784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
116884c406e7SOri Kam 			ret = mlx5_flow_validate_item_vxlan_gpe(items,
116984c406e7SOri Kam 								item_flags,
117084c406e7SOri Kam 								dev, error);
117184c406e7SOri Kam 			if (ret < 0)
117284c406e7SOri Kam 				return ret;
117338f7efaaSDekel Peled 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
117484c406e7SOri Kam 			break;
117584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_GRE:
117684c406e7SOri Kam 			ret = mlx5_flow_validate_item_gre(items, item_flags,
117784c406e7SOri Kam 							  next_protocol, error);
117884c406e7SOri Kam 			if (ret < 0)
117984c406e7SOri Kam 				return ret;
118038f7efaaSDekel Peled 			last_item = MLX5_FLOW_LAYER_GRE;
118184c406e7SOri Kam 			break;
118284c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_MPLS:
118338f7efaaSDekel Peled 			ret = mlx5_flow_validate_item_mpls(dev, items,
118438f7efaaSDekel Peled 							   item_flags,
118538f7efaaSDekel Peled 							   last_item, error);
118684c406e7SOri Kam 			if (ret < 0)
118784c406e7SOri Kam 				return ret;
118838f7efaaSDekel Peled 			last_item = MLX5_FLOW_LAYER_MPLS;
118984c406e7SOri Kam 			break;
119084c406e7SOri Kam 		default:
119184c406e7SOri Kam 			return rte_flow_error_set(error, ENOTSUP,
119284c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ITEM,
119384c406e7SOri Kam 						  NULL, "item not supported");
119484c406e7SOri Kam 		}
119538f7efaaSDekel Peled 		item_flags |= last_item;
119684c406e7SOri Kam 	}
119784c406e7SOri Kam 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
119884c406e7SOri Kam 		switch (actions->type) {
119984c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_VOID:
120084c406e7SOri Kam 			break;
120184c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_FLAG:
120284c406e7SOri Kam 			ret = mlx5_flow_validate_action_flag(action_flags,
12033e9fa079SDekel Peled 							     attr,
120484c406e7SOri Kam 							     error);
120584c406e7SOri Kam 			if (ret < 0)
120684c406e7SOri Kam 				return ret;
120784c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_FLAG;
120884c406e7SOri Kam 			break;
120984c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_MARK:
121084c406e7SOri Kam 			ret = mlx5_flow_validate_action_mark(actions,
121184c406e7SOri Kam 							     action_flags,
12123e9fa079SDekel Peled 							     attr,
121384c406e7SOri Kam 							     error);
121484c406e7SOri Kam 			if (ret < 0)
121584c406e7SOri Kam 				return ret;
121684c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_MARK;
121784c406e7SOri Kam 			break;
121884c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_DROP:
121984c406e7SOri Kam 			ret = mlx5_flow_validate_action_drop(action_flags,
12203e9fa079SDekel Peled 							     attr,
122184c406e7SOri Kam 							     error);
122284c406e7SOri Kam 			if (ret < 0)
122384c406e7SOri Kam 				return ret;
122484c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_DROP;
122584c406e7SOri Kam 			break;
122684c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_QUEUE:
122784c406e7SOri Kam 			ret = mlx5_flow_validate_action_queue(actions,
122884c406e7SOri Kam 							      action_flags, dev,
12293e9fa079SDekel Peled 							      attr,
123084c406e7SOri Kam 							      error);
123184c406e7SOri Kam 			if (ret < 0)
123284c406e7SOri Kam 				return ret;
123384c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
123484c406e7SOri Kam 			break;
123584c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_RSS:
123684c406e7SOri Kam 			ret = mlx5_flow_validate_action_rss(actions,
123784c406e7SOri Kam 							    action_flags, dev,
12381183f12fSOri Kam 							    attr, item_flags,
123984c406e7SOri Kam 							    error);
124084c406e7SOri Kam 			if (ret < 0)
124184c406e7SOri Kam 				return ret;
124284c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_RSS;
124384c406e7SOri Kam 			break;
124484c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_COUNT:
12453e9fa079SDekel Peled 			ret = mlx5_flow_validate_action_count(dev, attr, error);
124684c406e7SOri Kam 			if (ret < 0)
124784c406e7SOri Kam 				return ret;
124884c406e7SOri Kam 			action_flags |= MLX5_FLOW_ACTION_COUNT;
124984c406e7SOri Kam 			break;
125084c406e7SOri Kam 		default:
125184c406e7SOri Kam 			return rte_flow_error_set(error, ENOTSUP,
125284c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ACTION,
125384c406e7SOri Kam 						  actions,
125484c406e7SOri Kam 						  "action not supported");
125584c406e7SOri Kam 		}
125684c406e7SOri Kam 	}
125770faf9aeSDekel Peled 	/*
125870faf9aeSDekel Peled 	 * Validate the drop action mutual exclusion with other actions.
125970faf9aeSDekel Peled 	 * Drop action is mutually-exclusive with any other action, except for
126070faf9aeSDekel Peled 	 * Count action.
126170faf9aeSDekel Peled 	 */
126270faf9aeSDekel Peled 	if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
126370faf9aeSDekel Peled 	    (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT)))
126470faf9aeSDekel Peled 		return rte_flow_error_set(error, EINVAL,
126570faf9aeSDekel Peled 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
126670faf9aeSDekel Peled 					  "Drop action is mutually-exclusive "
126770faf9aeSDekel Peled 					  "with any other action, except for "
126870faf9aeSDekel Peled 					  "Count action");
126984c406e7SOri Kam 	if (!(action_flags & MLX5_FLOW_FATE_ACTIONS))
127084c406e7SOri Kam 		return rte_flow_error_set(error, EINVAL,
127184c406e7SOri Kam 					  RTE_FLOW_ERROR_TYPE_ACTION, actions,
127284c406e7SOri Kam 					  "no fate action is found");
127384c406e7SOri Kam 	return 0;
127484c406e7SOri Kam }
127584c406e7SOri Kam 
127684c406e7SOri Kam /**
127784c406e7SOri Kam  * Calculate the required bytes that are needed for the action part of the verbs
1278c1cfb132SYongseok Koh  * flow.
127984c406e7SOri Kam  *
128084c406e7SOri Kam  * @param[in] actions
128184c406e7SOri Kam  *   Pointer to the list of actions.
128284c406e7SOri Kam  *
128384c406e7SOri Kam  * @return
128484c406e7SOri Kam  *   The size of the memory needed for all actions.
128584c406e7SOri Kam  */
128684c406e7SOri Kam static int
1287c1cfb132SYongseok Koh flow_verbs_get_actions_size(const struct rte_flow_action actions[])
128884c406e7SOri Kam {
128984c406e7SOri Kam 	int size = 0;
129084c406e7SOri Kam 
129184c406e7SOri Kam 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
129284c406e7SOri Kam 		switch (actions->type) {
129384c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_VOID:
129484c406e7SOri Kam 			break;
129584c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_FLAG:
129684c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_action_tag);
129784c406e7SOri Kam 			break;
129884c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_MARK:
129984c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_action_tag);
130084c406e7SOri Kam 			break;
130184c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_DROP:
130284c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_action_drop);
130384c406e7SOri Kam 			break;
130484c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_QUEUE:
130584c406e7SOri Kam 			break;
130684c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_RSS:
130784c406e7SOri Kam 			break;
130884c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_COUNT:
1309db48f9dbSViacheslav Ovsiienko #if defined(HAVE_IBV_DEVICE_COUNTERS_SET_V42) || \
1310db48f9dbSViacheslav Ovsiienko 	defined(HAVE_IBV_DEVICE_COUNTERS_SET_V45)
131184c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_counter_action);
131284c406e7SOri Kam #endif
131384c406e7SOri Kam 			break;
131484c406e7SOri Kam 		default:
131584c406e7SOri Kam 			break;
131684c406e7SOri Kam 		}
131784c406e7SOri Kam 	}
131884c406e7SOri Kam 	return size;
131984c406e7SOri Kam }
132084c406e7SOri Kam 
132184c406e7SOri Kam /**
132284c406e7SOri Kam  * Calculate the required bytes that are needed for the item part of the verbs
1323c1cfb132SYongseok Koh  * flow.
132484c406e7SOri Kam  *
1325c1cfb132SYongseok Koh  * @param[in] items
132684c406e7SOri Kam  *   Pointer to the list of items.
132784c406e7SOri Kam  *
132884c406e7SOri Kam  * @return
132984c406e7SOri Kam  *   The size of the memory needed for all items.
133084c406e7SOri Kam  */
133184c406e7SOri Kam static int
1332c1cfb132SYongseok Koh flow_verbs_get_items_size(const struct rte_flow_item items[])
133384c406e7SOri Kam {
133484c406e7SOri Kam 	int size = 0;
133584c406e7SOri Kam 
133684c406e7SOri Kam 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
133784c406e7SOri Kam 		switch (items->type) {
133884c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VOID:
133984c406e7SOri Kam 			break;
134084c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_ETH:
134184c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_eth);
134284c406e7SOri Kam 			break;
134384c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VLAN:
134484c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_eth);
134584c406e7SOri Kam 			break;
134684c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV4:
134784c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_ipv4_ext);
134884c406e7SOri Kam 			break;
134984c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV6:
135084c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_ipv6);
135184c406e7SOri Kam 			break;
135284c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_UDP:
135384c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tcp_udp);
135484c406e7SOri Kam 			break;
135584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_TCP:
135684c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tcp_udp);
135784c406e7SOri Kam 			break;
135884c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN:
135984c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tunnel);
136084c406e7SOri Kam 			break;
136184c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
136284c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tunnel);
136384c406e7SOri Kam 			break;
136484c406e7SOri Kam #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
136584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_GRE:
136684c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_gre);
136784c406e7SOri Kam 			break;
136884c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_MPLS:
136984c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_mpls);
137084c406e7SOri Kam 			break;
137184c406e7SOri Kam #else
137284c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_GRE:
137384c406e7SOri Kam 			size += sizeof(struct ibv_flow_spec_tunnel);
137484c406e7SOri Kam 			break;
137584c406e7SOri Kam #endif
137684c406e7SOri Kam 		default:
137784c406e7SOri Kam 			break;
137884c406e7SOri Kam 		}
137984c406e7SOri Kam 	}
138084c406e7SOri Kam 	return size;
138184c406e7SOri Kam }
138284c406e7SOri Kam 
138384c406e7SOri Kam /**
138484c406e7SOri Kam  * Internal preparation function. Allocate mlx5_flow with the required size.
138584c406e7SOri Kam  * The required size is calculate based on the actions and items. This function
138684c406e7SOri Kam  * also returns the detected actions and items for later use.
138784c406e7SOri Kam  *
138884c406e7SOri Kam  * @param[in] attr
138984c406e7SOri Kam  *   Pointer to the flow attributes.
139084c406e7SOri Kam  * @param[in] items
139184c406e7SOri Kam  *   Pointer to the list of items.
139284c406e7SOri Kam  * @param[in] actions
139384c406e7SOri Kam  *   Pointer to the list of actions.
139484c406e7SOri Kam  * @param[out] error
139584c406e7SOri Kam  *   Pointer to the error structure.
139684c406e7SOri Kam  *
139784c406e7SOri Kam  * @return
139884c406e7SOri Kam  *   Pointer to mlx5_flow object on success, otherwise NULL and rte_errno
139984c406e7SOri Kam  *   is set.
140084c406e7SOri Kam  */
140184c406e7SOri Kam static struct mlx5_flow *
140284c406e7SOri Kam flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused,
140384c406e7SOri Kam 		   const struct rte_flow_item items[],
140484c406e7SOri Kam 		   const struct rte_flow_action actions[],
140584c406e7SOri Kam 		   struct rte_flow_error *error)
140684c406e7SOri Kam {
1407e205c95fSViacheslav Ovsiienko 	size_t size = sizeof(struct mlx5_flow) + sizeof(struct ibv_flow_attr);
1408e205c95fSViacheslav Ovsiienko 	struct mlx5_flow *dev_flow;
140984c406e7SOri Kam 
1410c1cfb132SYongseok Koh 	size += flow_verbs_get_actions_size(actions);
1411c1cfb132SYongseok Koh 	size += flow_verbs_get_items_size(items);
1412e205c95fSViacheslav Ovsiienko 	dev_flow = rte_calloc(__func__, 1, size, 0);
1413e205c95fSViacheslav Ovsiienko 	if (!dev_flow) {
141484c406e7SOri Kam 		rte_flow_error_set(error, ENOMEM,
141584c406e7SOri Kam 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
141684c406e7SOri Kam 				   "not enough memory to create flow");
141784c406e7SOri Kam 		return NULL;
141884c406e7SOri Kam 	}
1419e205c95fSViacheslav Ovsiienko 	dev_flow->verbs.attr = (void *)(dev_flow + 1);
1420e205c95fSViacheslav Ovsiienko 	dev_flow->verbs.specs = (void *)(dev_flow->verbs.attr + 1);
1421e205c95fSViacheslav Ovsiienko 	dev_flow->ingress = attr->ingress;
1422*c42f44bdSBing Zhao 	/* Need to set transfer attribute: not supported in Verbs mode. */
1423e205c95fSViacheslav Ovsiienko 	return dev_flow;
142484c406e7SOri Kam }
142584c406e7SOri Kam 
142684c406e7SOri Kam /**
142784c406e7SOri Kam  * Fill the flow with verb spec.
142884c406e7SOri Kam  *
142984c406e7SOri Kam  * @param[in] dev
143084c406e7SOri Kam  *   Pointer to Ethernet device.
143184c406e7SOri Kam  * @param[in, out] dev_flow
143284c406e7SOri Kam  *   Pointer to the mlx5 flow.
143384c406e7SOri Kam  * @param[in] attr
143484c406e7SOri Kam  *   Pointer to the flow attributes.
143584c406e7SOri Kam  * @param[in] items
143684c406e7SOri Kam  *   Pointer to the list of items.
143784c406e7SOri Kam  * @param[in] actions
143884c406e7SOri Kam  *   Pointer to the list of actions.
143984c406e7SOri Kam  * @param[out] error
144084c406e7SOri Kam  *   Pointer to the error structure.
144184c406e7SOri Kam  *
144284c406e7SOri Kam  * @return
1443de90612fSDekel Peled  *   0 on success, else a negative errno value otherwise and rte_errno is set.
144484c406e7SOri Kam  */
144584c406e7SOri Kam static int
144684c406e7SOri Kam flow_verbs_translate(struct rte_eth_dev *dev,
144784c406e7SOri Kam 		     struct mlx5_flow *dev_flow,
144884c406e7SOri Kam 		     const struct rte_flow_attr *attr,
144984c406e7SOri Kam 		     const struct rte_flow_item items[],
145084c406e7SOri Kam 		     const struct rte_flow_action actions[],
145184c406e7SOri Kam 		     struct rte_flow_error *error)
145284c406e7SOri Kam {
145384c406e7SOri Kam 	uint64_t item_flags = 0;
14544a78c88eSYongseok Koh 	uint64_t action_flags = 0;
145584c406e7SOri Kam 	uint64_t priority = attr->priority;
14564a78c88eSYongseok Koh 	uint32_t subpriority = 0;
1457dbeba4cfSThomas Monjalon 	struct mlx5_priv *priv = dev->data->dev_private;
145884c406e7SOri Kam 
145984c406e7SOri Kam 	if (priority == MLX5_FLOW_PRIO_RSVD)
146084c406e7SOri Kam 		priority = priv->config.flow_prio - 1;
146184c406e7SOri Kam 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
146284c406e7SOri Kam 		int ret;
14634a78c88eSYongseok Koh 
146484c406e7SOri Kam 		switch (actions->type) {
146584c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_VOID:
146684c406e7SOri Kam 			break;
146784c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_FLAG:
14684a78c88eSYongseok Koh 			flow_verbs_translate_action_flag(dev_flow, actions);
14694a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_FLAG;
147084c406e7SOri Kam 			break;
147184c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_MARK:
14724a78c88eSYongseok Koh 			flow_verbs_translate_action_mark(dev_flow, actions);
14734a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_MARK;
147484c406e7SOri Kam 			break;
147584c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_DROP:
14764a78c88eSYongseok Koh 			flow_verbs_translate_action_drop(dev_flow, actions);
14774a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_DROP;
147884c406e7SOri Kam 			break;
147984c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_QUEUE:
14804a78c88eSYongseok Koh 			flow_verbs_translate_action_queue(dev_flow, actions);
14814a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
148284c406e7SOri Kam 			break;
148384c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_RSS:
14844a78c88eSYongseok Koh 			flow_verbs_translate_action_rss(dev_flow, actions);
14854a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_RSS;
148684c406e7SOri Kam 			break;
148784c406e7SOri Kam 		case RTE_FLOW_ACTION_TYPE_COUNT:
14884a78c88eSYongseok Koh 			ret = flow_verbs_translate_action_count(dev_flow,
148984c406e7SOri Kam 								actions,
14904a78c88eSYongseok Koh 								dev, error);
149184c406e7SOri Kam 			if (ret < 0)
149284c406e7SOri Kam 				return ret;
14934a78c88eSYongseok Koh 			action_flags |= MLX5_FLOW_ACTION_COUNT;
149484c406e7SOri Kam 			break;
149584c406e7SOri Kam 		default:
149684c406e7SOri Kam 			return rte_flow_error_set(error, ENOTSUP,
149784c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ACTION,
149884c406e7SOri Kam 						  actions,
149984c406e7SOri Kam 						  "action not supported");
150084c406e7SOri Kam 		}
150184c406e7SOri Kam 	}
1502*c42f44bdSBing Zhao 	dev_flow->handle.act_flags = action_flags;
150384c406e7SOri Kam 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
15044a78c88eSYongseok Koh 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
15054a78c88eSYongseok Koh 
150684c406e7SOri Kam 		switch (items->type) {
150784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VOID:
150884c406e7SOri Kam 			break;
150984c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_ETH:
15104a78c88eSYongseok Koh 			flow_verbs_translate_item_eth(dev_flow, items,
15114a78c88eSYongseok Koh 						      item_flags);
15124a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L2;
15134a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
15144a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L2;
151584c406e7SOri Kam 			break;
151684c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VLAN:
15174a78c88eSYongseok Koh 			flow_verbs_translate_item_vlan(dev_flow, items,
15184a78c88eSYongseok Koh 						       item_flags);
15194a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L2;
15204a78c88eSYongseok Koh 			item_flags |= tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
15214a78c88eSYongseok Koh 						MLX5_FLOW_LAYER_INNER_VLAN) :
15224a78c88eSYongseok Koh 					       (MLX5_FLOW_LAYER_OUTER_L2 |
15234a78c88eSYongseok Koh 						MLX5_FLOW_LAYER_OUTER_VLAN);
152484c406e7SOri Kam 			break;
152584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV4:
15264a78c88eSYongseok Koh 			flow_verbs_translate_item_ipv4(dev_flow, items,
15274a78c88eSYongseok Koh 						       item_flags);
15284a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L3;
1529e205c95fSViacheslav Ovsiienko 			dev_flow->hash_fields |=
15304a78c88eSYongseok Koh 				mlx5_flow_hashfields_adjust
15314a78c88eSYongseok Koh 					(dev_flow, tunnel,
15324a78c88eSYongseok Koh 					 MLX5_IPV4_LAYER_TYPES,
15334a78c88eSYongseok Koh 					 MLX5_IPV4_IBV_RX_HASH);
15344a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
15354a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L3_IPV4;
153684c406e7SOri Kam 			break;
153784c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_IPV6:
15384a78c88eSYongseok Koh 			flow_verbs_translate_item_ipv6(dev_flow, items,
15394a78c88eSYongseok Koh 						       item_flags);
15404a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L3;
1541e205c95fSViacheslav Ovsiienko 			dev_flow->hash_fields |=
15424a78c88eSYongseok Koh 				mlx5_flow_hashfields_adjust
15434a78c88eSYongseok Koh 					(dev_flow, tunnel,
15444a78c88eSYongseok Koh 					 MLX5_IPV6_LAYER_TYPES,
15454a78c88eSYongseok Koh 					 MLX5_IPV6_IBV_RX_HASH);
15464a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
15474a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L3_IPV6;
154884c406e7SOri Kam 			break;
154984c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_TCP:
15504a78c88eSYongseok Koh 			flow_verbs_translate_item_tcp(dev_flow, items,
15514a78c88eSYongseok Koh 						      item_flags);
15524a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L4;
1553e205c95fSViacheslav Ovsiienko 			dev_flow->hash_fields |=
15544a78c88eSYongseok Koh 				mlx5_flow_hashfields_adjust
15554a78c88eSYongseok Koh 					(dev_flow, tunnel, ETH_RSS_TCP,
15564a78c88eSYongseok Koh 					 (IBV_RX_HASH_SRC_PORT_TCP |
15574a78c88eSYongseok Koh 					  IBV_RX_HASH_DST_PORT_TCP));
15584a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
15594a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L4_TCP;
15604a78c88eSYongseok Koh 			break;
15614a78c88eSYongseok Koh 		case RTE_FLOW_ITEM_TYPE_UDP:
15624a78c88eSYongseok Koh 			flow_verbs_translate_item_udp(dev_flow, items,
15634a78c88eSYongseok Koh 						      item_flags);
15644a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L4;
1565e205c95fSViacheslav Ovsiienko 			dev_flow->hash_fields |=
15664a78c88eSYongseok Koh 				mlx5_flow_hashfields_adjust
15674a78c88eSYongseok Koh 					(dev_flow, tunnel, ETH_RSS_UDP,
15684a78c88eSYongseok Koh 					 (IBV_RX_HASH_SRC_PORT_UDP |
15694a78c88eSYongseok Koh 					  IBV_RX_HASH_DST_PORT_UDP));
15704a78c88eSYongseok Koh 			item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
15714a78c88eSYongseok Koh 					       MLX5_FLOW_LAYER_OUTER_L4_UDP;
157284c406e7SOri Kam 			break;
157384c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN:
15744a78c88eSYongseok Koh 			flow_verbs_translate_item_vxlan(dev_flow, items,
15754a78c88eSYongseok Koh 							item_flags);
15764a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L2;
15774a78c88eSYongseok Koh 			item_flags |= MLX5_FLOW_LAYER_VXLAN;
157884c406e7SOri Kam 			break;
157984c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
15804a78c88eSYongseok Koh 			flow_verbs_translate_item_vxlan_gpe(dev_flow, items,
15814a78c88eSYongseok Koh 							    item_flags);
15824a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L2;
15834a78c88eSYongseok Koh 			item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE;
158484c406e7SOri Kam 			break;
158584c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_GRE:
15864a78c88eSYongseok Koh 			flow_verbs_translate_item_gre(dev_flow, items,
15874a78c88eSYongseok Koh 						      item_flags);
15884a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L2;
15894a78c88eSYongseok Koh 			item_flags |= MLX5_FLOW_LAYER_GRE;
159084c406e7SOri Kam 			break;
159184c406e7SOri Kam 		case RTE_FLOW_ITEM_TYPE_MPLS:
15924a78c88eSYongseok Koh 			flow_verbs_translate_item_mpls(dev_flow, items,
15934a78c88eSYongseok Koh 						       item_flags);
15944a78c88eSYongseok Koh 			subpriority = MLX5_PRIORITY_MAP_L2;
15954a78c88eSYongseok Koh 			item_flags |= MLX5_FLOW_LAYER_MPLS;
159684c406e7SOri Kam 			break;
159784c406e7SOri Kam 		default:
159884c406e7SOri Kam 			return rte_flow_error_set(error, ENOTSUP,
159984c406e7SOri Kam 						  RTE_FLOW_ERROR_TYPE_ITEM,
160084c406e7SOri Kam 						  NULL,
160184c406e7SOri Kam 						  "item not supported");
160284c406e7SOri Kam 		}
160384c406e7SOri Kam 	}
1604*c42f44bdSBing Zhao 	dev_flow->handle.layers = item_flags;
160584c406e7SOri Kam 	dev_flow->verbs.attr->priority =
16064a78c88eSYongseok Koh 		mlx5_flow_adjust_priority(dev, priority, subpriority);
16071e14090eSViacheslav Ovsiienko 	dev_flow->verbs.attr->port = (uint8_t)priv->ibv_port;
160884c406e7SOri Kam 	return 0;
160984c406e7SOri Kam }
161084c406e7SOri Kam 
161184c406e7SOri Kam /**
161284c406e7SOri Kam  * Remove the flow from the NIC but keeps it in memory.
161384c406e7SOri Kam  *
161484c406e7SOri Kam  * @param[in] dev
161584c406e7SOri Kam  *   Pointer to the Ethernet device structure.
161684c406e7SOri Kam  * @param[in, out] flow
161784c406e7SOri Kam  *   Pointer to flow structure.
161884c406e7SOri Kam  */
161984c406e7SOri Kam static void
162084c406e7SOri Kam flow_verbs_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
162184c406e7SOri Kam {
1622*c42f44bdSBing Zhao 	struct mlx5_flow_handle *dh;
162384c406e7SOri Kam 	struct mlx5_flow *dev_flow;
162484c406e7SOri Kam 
162584c406e7SOri Kam 	if (!flow)
162684c406e7SOri Kam 		return;
162784c406e7SOri Kam 	LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
1628*c42f44bdSBing Zhao 		dh = &dev_flow->handle;
1629*c42f44bdSBing Zhao 		if (dh->ib_flow) {
1630*c42f44bdSBing Zhao 			claim_zero(mlx5_glue->destroy_flow(dh->ib_flow));
1631*c42f44bdSBing Zhao 			dh->ib_flow = NULL;
163284c406e7SOri Kam 		}
1633*c42f44bdSBing Zhao 		if (dh->hrxq) {
1634*c42f44bdSBing Zhao 			if (dev_flow->handle.act_flags & MLX5_FLOW_ACTION_DROP)
163584c406e7SOri Kam 				mlx5_hrxq_drop_release(dev);
163684c406e7SOri Kam 			else
1637*c42f44bdSBing Zhao 				mlx5_hrxq_release(dev, dh->hrxq);
1638*c42f44bdSBing Zhao 			dh->hrxq = NULL;
163984c406e7SOri Kam 		}
1640*c42f44bdSBing Zhao 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
1641*c42f44bdSBing Zhao 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
164284c406e7SOri Kam 	}
164384c406e7SOri Kam }
164484c406e7SOri Kam 
164584c406e7SOri Kam /**
164684c406e7SOri Kam  * Remove the flow from the NIC and the memory.
164784c406e7SOri Kam  *
164884c406e7SOri Kam  * @param[in] dev
164984c406e7SOri Kam  *   Pointer to the Ethernet device structure.
165084c406e7SOri Kam  * @param[in, out] flow
165184c406e7SOri Kam  *   Pointer to flow structure.
165284c406e7SOri Kam  */
165384c406e7SOri Kam static void
165484c406e7SOri Kam flow_verbs_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
165584c406e7SOri Kam {
165684c406e7SOri Kam 	struct mlx5_flow *dev_flow;
165784c406e7SOri Kam 
165884c406e7SOri Kam 	if (!flow)
165984c406e7SOri Kam 		return;
166084c406e7SOri Kam 	flow_verbs_remove(dev, flow);
166184c406e7SOri Kam 	while (!LIST_EMPTY(&flow->dev_flows)) {
166284c406e7SOri Kam 		dev_flow = LIST_FIRST(&flow->dev_flows);
166384c406e7SOri Kam 		LIST_REMOVE(dev_flow, next);
166484c406e7SOri Kam 		rte_free(dev_flow);
166584c406e7SOri Kam 	}
166684be903cSViacheslav Ovsiienko 	if (flow->counter) {
16675382d28cSMatan Azrad 		flow_verbs_counter_release(dev, flow->counter);
166884be903cSViacheslav Ovsiienko 		flow->counter = NULL;
166984be903cSViacheslav Ovsiienko 	}
167084c406e7SOri Kam }
167184c406e7SOri Kam 
167284c406e7SOri Kam /**
167384c406e7SOri Kam  * Apply the flow to the NIC.
167484c406e7SOri Kam  *
167584c406e7SOri Kam  * @param[in] dev
167684c406e7SOri Kam  *   Pointer to the Ethernet device structure.
167784c406e7SOri Kam  * @param[in, out] flow
167884c406e7SOri Kam  *   Pointer to flow structure.
167984c406e7SOri Kam  * @param[out] error
168084c406e7SOri Kam  *   Pointer to error structure.
168184c406e7SOri Kam  *
168284c406e7SOri Kam  * @return
168384c406e7SOri Kam  *   0 on success, a negative errno value otherwise and rte_errno is set.
168484c406e7SOri Kam  */
168584c406e7SOri Kam static int
168684c406e7SOri Kam flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
168784c406e7SOri Kam 		 struct rte_flow_error *error)
168884c406e7SOri Kam {
1689dfedf3e3SViacheslav Ovsiienko 	struct mlx5_priv *priv = dev->data->dev_private;
1690*c42f44bdSBing Zhao 	struct mlx5_flow_handle *dh;
169184c406e7SOri Kam 	struct mlx5_flow *dev_flow;
169284c406e7SOri Kam 	int err;
169384c406e7SOri Kam 
169484c406e7SOri Kam 	LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
1695*c42f44bdSBing Zhao 		dh = &dev_flow->handle;
1696*c42f44bdSBing Zhao 		if (dev_flow->handle.act_flags & MLX5_FLOW_ACTION_DROP) {
1697*c42f44bdSBing Zhao 			dh->hrxq = mlx5_hrxq_drop_new(dev);
1698*c42f44bdSBing Zhao 			if (!dh->hrxq) {
169984c406e7SOri Kam 				rte_flow_error_set
170084c406e7SOri Kam 					(error, errno,
170184c406e7SOri Kam 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
170284c406e7SOri Kam 					 "cannot get drop hash queue");
170384c406e7SOri Kam 				goto error;
170484c406e7SOri Kam 			}
170584c406e7SOri Kam 		} else {
170684c406e7SOri Kam 			struct mlx5_hrxq *hrxq;
170784c406e7SOri Kam 
17088e46d4e1SAlexander Kozyrev 			MLX5_ASSERT(flow->rss.queue);
1709e205c95fSViacheslav Ovsiienko 			hrxq = mlx5_hrxq_get(dev, flow->rss.key,
171084c406e7SOri Kam 					     MLX5_RSS_HASH_KEY_LEN,
1711e205c95fSViacheslav Ovsiienko 					     dev_flow->hash_fields,
1712e205c95fSViacheslav Ovsiienko 					     (*flow->rss.queue),
171384c406e7SOri Kam 					     flow->rss.queue_num);
171484c406e7SOri Kam 			if (!hrxq)
1715e205c95fSViacheslav Ovsiienko 				hrxq = mlx5_hrxq_new(dev, flow->rss.key,
171684c406e7SOri Kam 						MLX5_RSS_HASH_KEY_LEN,
1717e205c95fSViacheslav Ovsiienko 						dev_flow->hash_fields,
1718e205c95fSViacheslav Ovsiienko 						(*flow->rss.queue),
171984c406e7SOri Kam 						flow->rss.queue_num,
1720*c42f44bdSBing Zhao 						!!(dev_flow->handle.layers &
172151582609SMatan Azrad 						MLX5_FLOW_LAYER_TUNNEL));
172284c406e7SOri Kam 			if (!hrxq) {
172384c406e7SOri Kam 				rte_flow_error_set
172484c406e7SOri Kam 					(error, rte_errno,
172584c406e7SOri Kam 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
172684c406e7SOri Kam 					 "cannot get hash queue");
172784c406e7SOri Kam 				goto error;
172884c406e7SOri Kam 			}
1729*c42f44bdSBing Zhao 			dh->hrxq = hrxq;
173084c406e7SOri Kam 		}
1731*c42f44bdSBing Zhao 		dh->ib_flow = mlx5_glue->create_flow(dh->hrxq->qp,
1732*c42f44bdSBing Zhao 						     dev_flow->verbs.attr);
1733*c42f44bdSBing Zhao 		if (!dh->ib_flow) {
173484c406e7SOri Kam 			rte_flow_error_set(error, errno,
173584c406e7SOri Kam 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
173684c406e7SOri Kam 					   NULL,
173784c406e7SOri Kam 					   "hardware refuses to create flow");
173884c406e7SOri Kam 			goto error;
173984c406e7SOri Kam 		}
1740dfedf3e3SViacheslav Ovsiienko 		if (priv->vmwa_context &&
1741*c42f44bdSBing Zhao 		    dev_flow->handle.vf_vlan.tag &&
1742*c42f44bdSBing Zhao 		    !dev_flow->handle.vf_vlan.created) {
1743dfedf3e3SViacheslav Ovsiienko 			/*
1744dfedf3e3SViacheslav Ovsiienko 			 * The rule contains the VLAN pattern.
1745dfedf3e3SViacheslav Ovsiienko 			 * For VF we are going to create VLAN
1746dfedf3e3SViacheslav Ovsiienko 			 * interface to make hypervisor set correct
1747dfedf3e3SViacheslav Ovsiienko 			 * e-Switch vport context.
1748dfedf3e3SViacheslav Ovsiienko 			 */
1749*c42f44bdSBing Zhao 			mlx5_vlan_vmwa_acquire(dev, &dev_flow->handle.vf_vlan);
1750dfedf3e3SViacheslav Ovsiienko 		}
175184c406e7SOri Kam 	}
175284c406e7SOri Kam 	return 0;
175384c406e7SOri Kam error:
175484c406e7SOri Kam 	err = rte_errno; /* Save rte_errno before cleanup. */
175584c406e7SOri Kam 	LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
1756*c42f44bdSBing Zhao 		dh = &dev_flow->handle;
1757*c42f44bdSBing Zhao 		if (dh->hrxq) {
1758*c42f44bdSBing Zhao 			if (dev_flow->handle.act_flags & MLX5_FLOW_ACTION_DROP)
175984c406e7SOri Kam 				mlx5_hrxq_drop_release(dev);
176084c406e7SOri Kam 			else
1761*c42f44bdSBing Zhao 				mlx5_hrxq_release(dev, dh->hrxq);
1762*c42f44bdSBing Zhao 			dh->hrxq = NULL;
176384c406e7SOri Kam 		}
1764*c42f44bdSBing Zhao 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
1765*c42f44bdSBing Zhao 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
176684c406e7SOri Kam 	}
176784c406e7SOri Kam 	rte_errno = err; /* Restore rte_errno. */
176884c406e7SOri Kam 	return -rte_errno;
176984c406e7SOri Kam }
177084c406e7SOri Kam 
1771684dafe7SMoti Haimovsky /**
1772684dafe7SMoti Haimovsky  * Query a flow.
1773684dafe7SMoti Haimovsky  *
1774684dafe7SMoti Haimovsky  * @see rte_flow_query()
1775684dafe7SMoti Haimovsky  * @see rte_flow_ops
1776684dafe7SMoti Haimovsky  */
1777684dafe7SMoti Haimovsky static int
1778684dafe7SMoti Haimovsky flow_verbs_query(struct rte_eth_dev *dev,
1779684dafe7SMoti Haimovsky 		 struct rte_flow *flow,
1780684dafe7SMoti Haimovsky 		 const struct rte_flow_action *actions,
1781684dafe7SMoti Haimovsky 		 void *data,
1782684dafe7SMoti Haimovsky 		 struct rte_flow_error *error)
1783684dafe7SMoti Haimovsky {
1784684dafe7SMoti Haimovsky 	int ret = -EINVAL;
1785684dafe7SMoti Haimovsky 
1786684dafe7SMoti Haimovsky 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1787684dafe7SMoti Haimovsky 		switch (actions->type) {
1788684dafe7SMoti Haimovsky 		case RTE_FLOW_ACTION_TYPE_VOID:
1789684dafe7SMoti Haimovsky 			break;
1790684dafe7SMoti Haimovsky 		case RTE_FLOW_ACTION_TYPE_COUNT:
179106629d86SViacheslav Ovsiienko 			ret = flow_verbs_counter_query(dev, flow, data, error);
1792684dafe7SMoti Haimovsky 			break;
1793684dafe7SMoti Haimovsky 		default:
1794684dafe7SMoti Haimovsky 			return rte_flow_error_set(error, ENOTSUP,
1795684dafe7SMoti Haimovsky 						  RTE_FLOW_ERROR_TYPE_ACTION,
1796684dafe7SMoti Haimovsky 						  actions,
1797684dafe7SMoti Haimovsky 						  "action not supported");
1798684dafe7SMoti Haimovsky 		}
1799684dafe7SMoti Haimovsky 	}
1800684dafe7SMoti Haimovsky 	return ret;
1801684dafe7SMoti Haimovsky }
1802684dafe7SMoti Haimovsky 
18030c76d1c9SYongseok Koh const struct mlx5_flow_driver_ops mlx5_flow_verbs_drv_ops = {
180484c406e7SOri Kam 	.validate = flow_verbs_validate,
180584c406e7SOri Kam 	.prepare = flow_verbs_prepare,
180684c406e7SOri Kam 	.translate = flow_verbs_translate,
180784c406e7SOri Kam 	.apply = flow_verbs_apply,
180884c406e7SOri Kam 	.remove = flow_verbs_remove,
180984c406e7SOri Kam 	.destroy = flow_verbs_destroy,
1810684dafe7SMoti Haimovsky 	.query = flow_verbs_query,
181184c406e7SOri Kam };
1812