xref: /dpdk/drivers/net/mlx5/mlx5_flow_dv.c (revision 3bb3ebb51b789d4ecb417cbdb1dce5c7211f6f18)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2018 Mellanox Technologies, Ltd
3  */
4 
5 #include <sys/queue.h>
6 #include <stdalign.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <unistd.h>
10 
11 #include <rte_common.h>
12 #include <rte_ether.h>
13 #include <ethdev_driver.h>
14 #include <rte_flow.h>
15 #include <rte_flow_driver.h>
16 #include <rte_malloc.h>
17 #include <rte_cycles.h>
18 #include <rte_ip.h>
19 #include <rte_gre.h>
20 #include <rte_vxlan.h>
21 #include <rte_gtp.h>
22 #include <rte_eal_paging.h>
23 #include <rte_mpls.h>
24 
25 #include <mlx5_glue.h>
26 #include <mlx5_devx_cmds.h>
27 #include <mlx5_prm.h>
28 #include <mlx5_malloc.h>
29 
30 #include "mlx5_defs.h"
31 #include "mlx5.h"
32 #include "mlx5_common_os.h"
33 #include "mlx5_flow.h"
34 #include "mlx5_flow_os.h"
35 #include "mlx5_rxtx.h"
36 #include "rte_pmd_mlx5.h"
37 
38 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
39 
40 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS
41 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0
42 #endif
43 
44 #ifndef HAVE_MLX5DV_DR_ESWITCH
45 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB
46 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0
47 #endif
48 #endif
49 
50 #ifndef HAVE_MLX5DV_DR
51 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1
52 #endif
53 
54 /* VLAN header definitions */
55 #define MLX5DV_FLOW_VLAN_PCP_SHIFT 13
56 #define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << MLX5DV_FLOW_VLAN_PCP_SHIFT)
57 #define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff
58 #define MLX5DV_FLOW_VLAN_PCP_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK)
59 #define MLX5DV_FLOW_VLAN_VID_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK)
60 
61 union flow_dv_attr {
62 	struct {
63 		uint32_t valid:1;
64 		uint32_t ipv4:1;
65 		uint32_t ipv6:1;
66 		uint32_t tcp:1;
67 		uint32_t udp:1;
68 		uint32_t reserved:27;
69 	};
70 	uint32_t attr;
71 };
72 
73 static int
74 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
75 			     struct mlx5_flow_tbl_resource *tbl);
76 
77 static int
78 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
79 				     uint32_t encap_decap_idx);
80 
81 static int
82 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
83 					uint32_t port_id);
84 static void
85 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss);
86 
87 static int
88 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
89 				  uint32_t rix_jump);
90 
91 /**
92  * Initialize flow attributes structure according to flow items' types.
93  *
94  * flow_dv_validate() avoids multiple L3/L4 layers cases other than tunnel
95  * mode. For tunnel mode, the items to be modified are the outermost ones.
96  *
97  * @param[in] item
98  *   Pointer to item specification.
99  * @param[out] attr
100  *   Pointer to flow attributes structure.
101  * @param[in] dev_flow
102  *   Pointer to the sub flow.
103  * @param[in] tunnel_decap
104  *   Whether action is after tunnel decapsulation.
105  */
106 static void
107 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
108 		  struct mlx5_flow *dev_flow, bool tunnel_decap)
109 {
110 	uint64_t layers = dev_flow->handle->layers;
111 
112 	/*
113 	 * If layers is already initialized, it means this dev_flow is the
114 	 * suffix flow, the layers flags is set by the prefix flow. Need to
115 	 * use the layer flags from prefix flow as the suffix flow may not
116 	 * have the user defined items as the flow is split.
117 	 */
118 	if (layers) {
119 		if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
120 			attr->ipv4 = 1;
121 		else if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV6)
122 			attr->ipv6 = 1;
123 		if (layers & MLX5_FLOW_LAYER_OUTER_L4_TCP)
124 			attr->tcp = 1;
125 		else if (layers & MLX5_FLOW_LAYER_OUTER_L4_UDP)
126 			attr->udp = 1;
127 		attr->valid = 1;
128 		return;
129 	}
130 	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
131 		uint8_t next_protocol = 0xff;
132 		switch (item->type) {
133 		case RTE_FLOW_ITEM_TYPE_GRE:
134 		case RTE_FLOW_ITEM_TYPE_NVGRE:
135 		case RTE_FLOW_ITEM_TYPE_VXLAN:
136 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
137 		case RTE_FLOW_ITEM_TYPE_GENEVE:
138 		case RTE_FLOW_ITEM_TYPE_MPLS:
139 			if (tunnel_decap)
140 				attr->attr = 0;
141 			break;
142 		case RTE_FLOW_ITEM_TYPE_IPV4:
143 			if (!attr->ipv6)
144 				attr->ipv4 = 1;
145 			if (item->mask != NULL &&
146 			    ((const struct rte_flow_item_ipv4 *)
147 			    item->mask)->hdr.next_proto_id)
148 				next_protocol =
149 				    ((const struct rte_flow_item_ipv4 *)
150 				      (item->spec))->hdr.next_proto_id &
151 				    ((const struct rte_flow_item_ipv4 *)
152 				      (item->mask))->hdr.next_proto_id;
153 			if ((next_protocol == IPPROTO_IPIP ||
154 			    next_protocol == IPPROTO_IPV6) && tunnel_decap)
155 				attr->attr = 0;
156 			break;
157 		case RTE_FLOW_ITEM_TYPE_IPV6:
158 			if (!attr->ipv4)
159 				attr->ipv6 = 1;
160 			if (item->mask != NULL &&
161 			    ((const struct rte_flow_item_ipv6 *)
162 			    item->mask)->hdr.proto)
163 				next_protocol =
164 				    ((const struct rte_flow_item_ipv6 *)
165 				      (item->spec))->hdr.proto &
166 				    ((const struct rte_flow_item_ipv6 *)
167 				      (item->mask))->hdr.proto;
168 			if ((next_protocol == IPPROTO_IPIP ||
169 			    next_protocol == IPPROTO_IPV6) && tunnel_decap)
170 				attr->attr = 0;
171 			break;
172 		case RTE_FLOW_ITEM_TYPE_UDP:
173 			if (!attr->tcp)
174 				attr->udp = 1;
175 			break;
176 		case RTE_FLOW_ITEM_TYPE_TCP:
177 			if (!attr->udp)
178 				attr->tcp = 1;
179 			break;
180 		default:
181 			break;
182 		}
183 	}
184 	attr->valid = 1;
185 }
186 
187 /**
188  * Convert rte_mtr_color to mlx5 color.
189  *
190  * @param[in] rcol
191  *   rte_mtr_color.
192  *
193  * @return
194  *   mlx5 color.
195  */
196 static int
197 rte_col_2_mlx5_col(enum rte_color rcol)
198 {
199 	switch (rcol) {
200 	case RTE_COLOR_GREEN:
201 		return MLX5_FLOW_COLOR_GREEN;
202 	case RTE_COLOR_YELLOW:
203 		return MLX5_FLOW_COLOR_YELLOW;
204 	case RTE_COLOR_RED:
205 		return MLX5_FLOW_COLOR_RED;
206 	default:
207 		break;
208 	}
209 	return MLX5_FLOW_COLOR_UNDEFINED;
210 }
211 
212 struct field_modify_info {
213 	uint32_t size; /* Size of field in protocol header, in bytes. */
214 	uint32_t offset; /* Offset of field in protocol header, in bytes. */
215 	enum mlx5_modification_field id;
216 };
217 
218 struct field_modify_info modify_eth[] = {
219 	{4,  0, MLX5_MODI_OUT_DMAC_47_16},
220 	{2,  4, MLX5_MODI_OUT_DMAC_15_0},
221 	{4,  6, MLX5_MODI_OUT_SMAC_47_16},
222 	{2, 10, MLX5_MODI_OUT_SMAC_15_0},
223 	{0, 0, 0},
224 };
225 
226 struct field_modify_info modify_vlan_out_first_vid[] = {
227 	/* Size in bits !!! */
228 	{12, 0, MLX5_MODI_OUT_FIRST_VID},
229 	{0, 0, 0},
230 };
231 
232 struct field_modify_info modify_ipv4[] = {
233 	{1,  1, MLX5_MODI_OUT_IP_DSCP},
234 	{1,  8, MLX5_MODI_OUT_IPV4_TTL},
235 	{4, 12, MLX5_MODI_OUT_SIPV4},
236 	{4, 16, MLX5_MODI_OUT_DIPV4},
237 	{0, 0, 0},
238 };
239 
240 struct field_modify_info modify_ipv6[] = {
241 	{1,  0, MLX5_MODI_OUT_IP_DSCP},
242 	{1,  7, MLX5_MODI_OUT_IPV6_HOPLIMIT},
243 	{4,  8, MLX5_MODI_OUT_SIPV6_127_96},
244 	{4, 12, MLX5_MODI_OUT_SIPV6_95_64},
245 	{4, 16, MLX5_MODI_OUT_SIPV6_63_32},
246 	{4, 20, MLX5_MODI_OUT_SIPV6_31_0},
247 	{4, 24, MLX5_MODI_OUT_DIPV6_127_96},
248 	{4, 28, MLX5_MODI_OUT_DIPV6_95_64},
249 	{4, 32, MLX5_MODI_OUT_DIPV6_63_32},
250 	{4, 36, MLX5_MODI_OUT_DIPV6_31_0},
251 	{0, 0, 0},
252 };
253 
254 struct field_modify_info modify_udp[] = {
255 	{2, 0, MLX5_MODI_OUT_UDP_SPORT},
256 	{2, 2, MLX5_MODI_OUT_UDP_DPORT},
257 	{0, 0, 0},
258 };
259 
260 struct field_modify_info modify_tcp[] = {
261 	{2, 0, MLX5_MODI_OUT_TCP_SPORT},
262 	{2, 2, MLX5_MODI_OUT_TCP_DPORT},
263 	{4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM},
264 	{4, 8, MLX5_MODI_OUT_TCP_ACK_NUM},
265 	{0, 0, 0},
266 };
267 
268 static void
269 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused,
270 			  uint8_t next_protocol, uint64_t *item_flags,
271 			  int *tunnel)
272 {
273 	MLX5_ASSERT(item->type == RTE_FLOW_ITEM_TYPE_IPV4 ||
274 		    item->type == RTE_FLOW_ITEM_TYPE_IPV6);
275 	if (next_protocol == IPPROTO_IPIP) {
276 		*item_flags |= MLX5_FLOW_LAYER_IPIP;
277 		*tunnel = 1;
278 	}
279 	if (next_protocol == IPPROTO_IPV6) {
280 		*item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP;
281 		*tunnel = 1;
282 	}
283 }
284 
285 /* Update VLAN's VID/PCP based on input rte_flow_action.
286  *
287  * @param[in] action
288  *   Pointer to struct rte_flow_action.
289  * @param[out] vlan
290  *   Pointer to struct rte_vlan_hdr.
291  */
292 static void
293 mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action,
294 			 struct rte_vlan_hdr *vlan)
295 {
296 	uint16_t vlan_tci;
297 	if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) {
298 		vlan_tci =
299 		    ((const struct rte_flow_action_of_set_vlan_pcp *)
300 					       action->conf)->vlan_pcp;
301 		vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT;
302 		vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
303 		vlan->vlan_tci |= vlan_tci;
304 	} else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) {
305 		vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
306 		vlan->vlan_tci |= rte_be_to_cpu_16
307 		    (((const struct rte_flow_action_of_set_vlan_vid *)
308 					     action->conf)->vlan_vid);
309 	}
310 }
311 
312 /**
313  * Fetch 1, 2, 3 or 4 byte field from the byte array
314  * and return as unsigned integer in host-endian format.
315  *
316  * @param[in] data
317  *   Pointer to data array.
318  * @param[in] size
319  *   Size of field to extract.
320  *
321  * @return
322  *   converted field in host endian format.
323  */
324 static inline uint32_t
325 flow_dv_fetch_field(const uint8_t *data, uint32_t size)
326 {
327 	uint32_t ret;
328 
329 	switch (size) {
330 	case 1:
331 		ret = *data;
332 		break;
333 	case 2:
334 		ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);
335 		break;
336 	case 3:
337 		ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);
338 		ret = (ret << 8) | *(data + sizeof(uint16_t));
339 		break;
340 	case 4:
341 		ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data);
342 		break;
343 	default:
344 		MLX5_ASSERT(false);
345 		ret = 0;
346 		break;
347 	}
348 	return ret;
349 }
350 
351 /**
352  * Convert modify-header action to DV specification.
353  *
354  * Data length of each action is determined by provided field description
355  * and the item mask. Data bit offset and width of each action is determined
356  * by provided item mask.
357  *
358  * @param[in] item
359  *   Pointer to item specification.
360  * @param[in] field
361  *   Pointer to field modification information.
362  *     For MLX5_MODIFICATION_TYPE_SET specifies destination field.
363  *     For MLX5_MODIFICATION_TYPE_ADD specifies destination field.
364  *     For MLX5_MODIFICATION_TYPE_COPY specifies source field.
365  * @param[in] dcopy
366  *   Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type.
367  *   Negative offset value sets the same offset as source offset.
368  *   size field is ignored, value is taken from source field.
369  * @param[in,out] resource
370  *   Pointer to the modify-header resource.
371  * @param[in] type
372  *   Type of modification.
373  * @param[out] error
374  *   Pointer to the error structure.
375  *
376  * @return
377  *   0 on success, a negative errno value otherwise and rte_errno is set.
378  */
379 static int
380 flow_dv_convert_modify_action(struct rte_flow_item *item,
381 			      struct field_modify_info *field,
382 			      struct field_modify_info *dcopy,
383 			      struct mlx5_flow_dv_modify_hdr_resource *resource,
384 			      uint32_t type, struct rte_flow_error *error)
385 {
386 	uint32_t i = resource->actions_num;
387 	struct mlx5_modification_cmd *actions = resource->actions;
388 
389 	/*
390 	 * The item and mask are provided in big-endian format.
391 	 * The fields should be presented as in big-endian format either.
392 	 * Mask must be always present, it defines the actual field width.
393 	 */
394 	MLX5_ASSERT(item->mask);
395 	MLX5_ASSERT(field->size);
396 	do {
397 		unsigned int size_b;
398 		unsigned int off_b;
399 		uint32_t mask;
400 		uint32_t data;
401 
402 		if (i >= MLX5_MAX_MODIFY_NUM)
403 			return rte_flow_error_set(error, EINVAL,
404 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
405 				 "too many items to modify");
406 		/* Fetch variable byte size mask from the array. */
407 		mask = flow_dv_fetch_field((const uint8_t *)item->mask +
408 					   field->offset, field->size);
409 		if (!mask) {
410 			++field;
411 			continue;
412 		}
413 		/* Deduce actual data width in bits from mask value. */
414 		off_b = rte_bsf32(mask);
415 		size_b = sizeof(uint32_t) * CHAR_BIT -
416 			 off_b - __builtin_clz(mask);
417 		MLX5_ASSERT(size_b);
418 		size_b = size_b == sizeof(uint32_t) * CHAR_BIT ? 0 : size_b;
419 		actions[i] = (struct mlx5_modification_cmd) {
420 			.action_type = type,
421 			.field = field->id,
422 			.offset = off_b,
423 			.length = size_b,
424 		};
425 		/* Convert entire record to expected big-endian format. */
426 		actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
427 		if (type == MLX5_MODIFICATION_TYPE_COPY) {
428 			MLX5_ASSERT(dcopy);
429 			actions[i].dst_field = dcopy->id;
430 			actions[i].dst_offset =
431 				(int)dcopy->offset < 0 ? off_b : dcopy->offset;
432 			/* Convert entire record to big-endian format. */
433 			actions[i].data1 = rte_cpu_to_be_32(actions[i].data1);
434 			++dcopy;
435 		} else {
436 			MLX5_ASSERT(item->spec);
437 			data = flow_dv_fetch_field((const uint8_t *)item->spec +
438 						   field->offset, field->size);
439 			/* Shift out the trailing masked bits from data. */
440 			data = (data & mask) >> off_b;
441 			actions[i].data1 = rte_cpu_to_be_32(data);
442 		}
443 		++i;
444 		++field;
445 	} while (field->size);
446 	if (resource->actions_num == i)
447 		return rte_flow_error_set(error, EINVAL,
448 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
449 					  "invalid modification flow item");
450 	resource->actions_num = i;
451 	return 0;
452 }
453 
454 /**
455  * Convert modify-header set IPv4 address action to DV specification.
456  *
457  * @param[in,out] resource
458  *   Pointer to the modify-header resource.
459  * @param[in] action
460  *   Pointer to action specification.
461  * @param[out] error
462  *   Pointer to the error structure.
463  *
464  * @return
465  *   0 on success, a negative errno value otherwise and rte_errno is set.
466  */
467 static int
468 flow_dv_convert_action_modify_ipv4
469 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
470 			 const struct rte_flow_action *action,
471 			 struct rte_flow_error *error)
472 {
473 	const struct rte_flow_action_set_ipv4 *conf =
474 		(const struct rte_flow_action_set_ipv4 *)(action->conf);
475 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
476 	struct rte_flow_item_ipv4 ipv4;
477 	struct rte_flow_item_ipv4 ipv4_mask;
478 
479 	memset(&ipv4, 0, sizeof(ipv4));
480 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
481 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) {
482 		ipv4.hdr.src_addr = conf->ipv4_addr;
483 		ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr;
484 	} else {
485 		ipv4.hdr.dst_addr = conf->ipv4_addr;
486 		ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr;
487 	}
488 	item.spec = &ipv4;
489 	item.mask = &ipv4_mask;
490 	return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
491 					     MLX5_MODIFICATION_TYPE_SET, error);
492 }
493 
494 /**
495  * Convert modify-header set IPv6 address action to DV specification.
496  *
497  * @param[in,out] resource
498  *   Pointer to the modify-header resource.
499  * @param[in] action
500  *   Pointer to action specification.
501  * @param[out] error
502  *   Pointer to the error structure.
503  *
504  * @return
505  *   0 on success, a negative errno value otherwise and rte_errno is set.
506  */
507 static int
508 flow_dv_convert_action_modify_ipv6
509 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
510 			 const struct rte_flow_action *action,
511 			 struct rte_flow_error *error)
512 {
513 	const struct rte_flow_action_set_ipv6 *conf =
514 		(const struct rte_flow_action_set_ipv6 *)(action->conf);
515 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
516 	struct rte_flow_item_ipv6 ipv6;
517 	struct rte_flow_item_ipv6 ipv6_mask;
518 
519 	memset(&ipv6, 0, sizeof(ipv6));
520 	memset(&ipv6_mask, 0, sizeof(ipv6_mask));
521 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) {
522 		memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr,
523 		       sizeof(ipv6.hdr.src_addr));
524 		memcpy(&ipv6_mask.hdr.src_addr,
525 		       &rte_flow_item_ipv6_mask.hdr.src_addr,
526 		       sizeof(ipv6.hdr.src_addr));
527 	} else {
528 		memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr,
529 		       sizeof(ipv6.hdr.dst_addr));
530 		memcpy(&ipv6_mask.hdr.dst_addr,
531 		       &rte_flow_item_ipv6_mask.hdr.dst_addr,
532 		       sizeof(ipv6.hdr.dst_addr));
533 	}
534 	item.spec = &ipv6;
535 	item.mask = &ipv6_mask;
536 	return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
537 					     MLX5_MODIFICATION_TYPE_SET, error);
538 }
539 
540 /**
541  * Convert modify-header set MAC address action to DV specification.
542  *
543  * @param[in,out] resource
544  *   Pointer to the modify-header resource.
545  * @param[in] action
546  *   Pointer to action specification.
547  * @param[out] error
548  *   Pointer to the error structure.
549  *
550  * @return
551  *   0 on success, a negative errno value otherwise and rte_errno is set.
552  */
553 static int
554 flow_dv_convert_action_modify_mac
555 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
556 			 const struct rte_flow_action *action,
557 			 struct rte_flow_error *error)
558 {
559 	const struct rte_flow_action_set_mac *conf =
560 		(const struct rte_flow_action_set_mac *)(action->conf);
561 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH };
562 	struct rte_flow_item_eth eth;
563 	struct rte_flow_item_eth eth_mask;
564 
565 	memset(&eth, 0, sizeof(eth));
566 	memset(&eth_mask, 0, sizeof(eth_mask));
567 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) {
568 		memcpy(&eth.src.addr_bytes, &conf->mac_addr,
569 		       sizeof(eth.src.addr_bytes));
570 		memcpy(&eth_mask.src.addr_bytes,
571 		       &rte_flow_item_eth_mask.src.addr_bytes,
572 		       sizeof(eth_mask.src.addr_bytes));
573 	} else {
574 		memcpy(&eth.dst.addr_bytes, &conf->mac_addr,
575 		       sizeof(eth.dst.addr_bytes));
576 		memcpy(&eth_mask.dst.addr_bytes,
577 		       &rte_flow_item_eth_mask.dst.addr_bytes,
578 		       sizeof(eth_mask.dst.addr_bytes));
579 	}
580 	item.spec = &eth;
581 	item.mask = &eth_mask;
582 	return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource,
583 					     MLX5_MODIFICATION_TYPE_SET, error);
584 }
585 
586 /**
587  * Convert modify-header set VLAN VID action to DV specification.
588  *
589  * @param[in,out] resource
590  *   Pointer to the modify-header resource.
591  * @param[in] action
592  *   Pointer to action specification.
593  * @param[out] error
594  *   Pointer to the error structure.
595  *
596  * @return
597  *   0 on success, a negative errno value otherwise and rte_errno is set.
598  */
599 static int
600 flow_dv_convert_action_modify_vlan_vid
601 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
602 			 const struct rte_flow_action *action,
603 			 struct rte_flow_error *error)
604 {
605 	const struct rte_flow_action_of_set_vlan_vid *conf =
606 		(const struct rte_flow_action_of_set_vlan_vid *)(action->conf);
607 	int i = resource->actions_num;
608 	struct mlx5_modification_cmd *actions = resource->actions;
609 	struct field_modify_info *field = modify_vlan_out_first_vid;
610 
611 	if (i >= MLX5_MAX_MODIFY_NUM)
612 		return rte_flow_error_set(error, EINVAL,
613 			 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
614 			 "too many items to modify");
615 	actions[i] = (struct mlx5_modification_cmd) {
616 		.action_type = MLX5_MODIFICATION_TYPE_SET,
617 		.field = field->id,
618 		.length = field->size,
619 		.offset = field->offset,
620 	};
621 	actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
622 	actions[i].data1 = conf->vlan_vid;
623 	actions[i].data1 = actions[i].data1 << 16;
624 	resource->actions_num = ++i;
625 	return 0;
626 }
627 
628 /**
629  * Convert modify-header set TP action to DV specification.
630  *
631  * @param[in,out] resource
632  *   Pointer to the modify-header resource.
633  * @param[in] action
634  *   Pointer to action specification.
635  * @param[in] items
636  *   Pointer to rte_flow_item objects list.
637  * @param[in] attr
638  *   Pointer to flow attributes structure.
639  * @param[in] dev_flow
640  *   Pointer to the sub flow.
641  * @param[in] tunnel_decap
642  *   Whether action is after tunnel decapsulation.
643  * @param[out] error
644  *   Pointer to the error structure.
645  *
646  * @return
647  *   0 on success, a negative errno value otherwise and rte_errno is set.
648  */
649 static int
650 flow_dv_convert_action_modify_tp
651 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
652 			 const struct rte_flow_action *action,
653 			 const struct rte_flow_item *items,
654 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
655 			 bool tunnel_decap, struct rte_flow_error *error)
656 {
657 	const struct rte_flow_action_set_tp *conf =
658 		(const struct rte_flow_action_set_tp *)(action->conf);
659 	struct rte_flow_item item;
660 	struct rte_flow_item_udp udp;
661 	struct rte_flow_item_udp udp_mask;
662 	struct rte_flow_item_tcp tcp;
663 	struct rte_flow_item_tcp tcp_mask;
664 	struct field_modify_info *field;
665 
666 	if (!attr->valid)
667 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
668 	if (attr->udp) {
669 		memset(&udp, 0, sizeof(udp));
670 		memset(&udp_mask, 0, sizeof(udp_mask));
671 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
672 			udp.hdr.src_port = conf->port;
673 			udp_mask.hdr.src_port =
674 					rte_flow_item_udp_mask.hdr.src_port;
675 		} else {
676 			udp.hdr.dst_port = conf->port;
677 			udp_mask.hdr.dst_port =
678 					rte_flow_item_udp_mask.hdr.dst_port;
679 		}
680 		item.type = RTE_FLOW_ITEM_TYPE_UDP;
681 		item.spec = &udp;
682 		item.mask = &udp_mask;
683 		field = modify_udp;
684 	} else {
685 		MLX5_ASSERT(attr->tcp);
686 		memset(&tcp, 0, sizeof(tcp));
687 		memset(&tcp_mask, 0, sizeof(tcp_mask));
688 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
689 			tcp.hdr.src_port = conf->port;
690 			tcp_mask.hdr.src_port =
691 					rte_flow_item_tcp_mask.hdr.src_port;
692 		} else {
693 			tcp.hdr.dst_port = conf->port;
694 			tcp_mask.hdr.dst_port =
695 					rte_flow_item_tcp_mask.hdr.dst_port;
696 		}
697 		item.type = RTE_FLOW_ITEM_TYPE_TCP;
698 		item.spec = &tcp;
699 		item.mask = &tcp_mask;
700 		field = modify_tcp;
701 	}
702 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
703 					     MLX5_MODIFICATION_TYPE_SET, error);
704 }
705 
706 /**
707  * Convert modify-header set TTL action to DV specification.
708  *
709  * @param[in,out] resource
710  *   Pointer to the modify-header resource.
711  * @param[in] action
712  *   Pointer to action specification.
713  * @param[in] items
714  *   Pointer to rte_flow_item objects list.
715  * @param[in] attr
716  *   Pointer to flow attributes structure.
717  * @param[in] dev_flow
718  *   Pointer to the sub flow.
719  * @param[in] tunnel_decap
720  *   Whether action is after tunnel decapsulation.
721  * @param[out] error
722  *   Pointer to the error structure.
723  *
724  * @return
725  *   0 on success, a negative errno value otherwise and rte_errno is set.
726  */
727 static int
728 flow_dv_convert_action_modify_ttl
729 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
730 			 const struct rte_flow_action *action,
731 			 const struct rte_flow_item *items,
732 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
733 			 bool tunnel_decap, struct rte_flow_error *error)
734 {
735 	const struct rte_flow_action_set_ttl *conf =
736 		(const struct rte_flow_action_set_ttl *)(action->conf);
737 	struct rte_flow_item item;
738 	struct rte_flow_item_ipv4 ipv4;
739 	struct rte_flow_item_ipv4 ipv4_mask;
740 	struct rte_flow_item_ipv6 ipv6;
741 	struct rte_flow_item_ipv6 ipv6_mask;
742 	struct field_modify_info *field;
743 
744 	if (!attr->valid)
745 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
746 	if (attr->ipv4) {
747 		memset(&ipv4, 0, sizeof(ipv4));
748 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
749 		ipv4.hdr.time_to_live = conf->ttl_value;
750 		ipv4_mask.hdr.time_to_live = 0xFF;
751 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
752 		item.spec = &ipv4;
753 		item.mask = &ipv4_mask;
754 		field = modify_ipv4;
755 	} else {
756 		MLX5_ASSERT(attr->ipv6);
757 		memset(&ipv6, 0, sizeof(ipv6));
758 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
759 		ipv6.hdr.hop_limits = conf->ttl_value;
760 		ipv6_mask.hdr.hop_limits = 0xFF;
761 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
762 		item.spec = &ipv6;
763 		item.mask = &ipv6_mask;
764 		field = modify_ipv6;
765 	}
766 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
767 					     MLX5_MODIFICATION_TYPE_SET, error);
768 }
769 
770 /**
771  * Convert modify-header decrement TTL action to DV specification.
772  *
773  * @param[in,out] resource
774  *   Pointer to the modify-header resource.
775  * @param[in] action
776  *   Pointer to action specification.
777  * @param[in] items
778  *   Pointer to rte_flow_item objects list.
779  * @param[in] attr
780  *   Pointer to flow attributes structure.
781  * @param[in] dev_flow
782  *   Pointer to the sub flow.
783  * @param[in] tunnel_decap
784  *   Whether action is after tunnel decapsulation.
785  * @param[out] error
786  *   Pointer to the error structure.
787  *
788  * @return
789  *   0 on success, a negative errno value otherwise and rte_errno is set.
790  */
791 static int
792 flow_dv_convert_action_modify_dec_ttl
793 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
794 			 const struct rte_flow_item *items,
795 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
796 			 bool tunnel_decap, struct rte_flow_error *error)
797 {
798 	struct rte_flow_item item;
799 	struct rte_flow_item_ipv4 ipv4;
800 	struct rte_flow_item_ipv4 ipv4_mask;
801 	struct rte_flow_item_ipv6 ipv6;
802 	struct rte_flow_item_ipv6 ipv6_mask;
803 	struct field_modify_info *field;
804 
805 	if (!attr->valid)
806 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
807 	if (attr->ipv4) {
808 		memset(&ipv4, 0, sizeof(ipv4));
809 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
810 		ipv4.hdr.time_to_live = 0xFF;
811 		ipv4_mask.hdr.time_to_live = 0xFF;
812 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
813 		item.spec = &ipv4;
814 		item.mask = &ipv4_mask;
815 		field = modify_ipv4;
816 	} else {
817 		MLX5_ASSERT(attr->ipv6);
818 		memset(&ipv6, 0, sizeof(ipv6));
819 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
820 		ipv6.hdr.hop_limits = 0xFF;
821 		ipv6_mask.hdr.hop_limits = 0xFF;
822 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
823 		item.spec = &ipv6;
824 		item.mask = &ipv6_mask;
825 		field = modify_ipv6;
826 	}
827 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
828 					     MLX5_MODIFICATION_TYPE_ADD, error);
829 }
830 
831 /**
832  * Convert modify-header increment/decrement TCP Sequence number
833  * to DV specification.
834  *
835  * @param[in,out] resource
836  *   Pointer to the modify-header resource.
837  * @param[in] action
838  *   Pointer to action specification.
839  * @param[out] error
840  *   Pointer to the error structure.
841  *
842  * @return
843  *   0 on success, a negative errno value otherwise and rte_errno is set.
844  */
845 static int
846 flow_dv_convert_action_modify_tcp_seq
847 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
848 			 const struct rte_flow_action *action,
849 			 struct rte_flow_error *error)
850 {
851 	const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
852 	uint64_t value = rte_be_to_cpu_32(*conf);
853 	struct rte_flow_item item;
854 	struct rte_flow_item_tcp tcp;
855 	struct rte_flow_item_tcp tcp_mask;
856 
857 	memset(&tcp, 0, sizeof(tcp));
858 	memset(&tcp_mask, 0, sizeof(tcp_mask));
859 	if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ)
860 		/*
861 		 * The HW has no decrement operation, only increment operation.
862 		 * To simulate decrement X from Y using increment operation
863 		 * we need to add UINT32_MAX X times to Y.
864 		 * Each adding of UINT32_MAX decrements Y by 1.
865 		 */
866 		value *= UINT32_MAX;
867 	tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value);
868 	tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX);
869 	item.type = RTE_FLOW_ITEM_TYPE_TCP;
870 	item.spec = &tcp;
871 	item.mask = &tcp_mask;
872 	return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
873 					     MLX5_MODIFICATION_TYPE_ADD, error);
874 }
875 
876 /**
877  * Convert modify-header increment/decrement TCP Acknowledgment number
878  * to DV specification.
879  *
880  * @param[in,out] resource
881  *   Pointer to the modify-header resource.
882  * @param[in] action
883  *   Pointer to action specification.
884  * @param[out] error
885  *   Pointer to the error structure.
886  *
887  * @return
888  *   0 on success, a negative errno value otherwise and rte_errno is set.
889  */
890 static int
891 flow_dv_convert_action_modify_tcp_ack
892 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
893 			 const struct rte_flow_action *action,
894 			 struct rte_flow_error *error)
895 {
896 	const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
897 	uint64_t value = rte_be_to_cpu_32(*conf);
898 	struct rte_flow_item item;
899 	struct rte_flow_item_tcp tcp;
900 	struct rte_flow_item_tcp tcp_mask;
901 
902 	memset(&tcp, 0, sizeof(tcp));
903 	memset(&tcp_mask, 0, sizeof(tcp_mask));
904 	if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK)
905 		/*
906 		 * The HW has no decrement operation, only increment operation.
907 		 * To simulate decrement X from Y using increment operation
908 		 * we need to add UINT32_MAX X times to Y.
909 		 * Each adding of UINT32_MAX decrements Y by 1.
910 		 */
911 		value *= UINT32_MAX;
912 	tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value);
913 	tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX);
914 	item.type = RTE_FLOW_ITEM_TYPE_TCP;
915 	item.spec = &tcp;
916 	item.mask = &tcp_mask;
917 	return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
918 					     MLX5_MODIFICATION_TYPE_ADD, error);
919 }
920 
921 static enum mlx5_modification_field reg_to_field[] = {
922 	[REG_NON] = MLX5_MODI_OUT_NONE,
923 	[REG_A] = MLX5_MODI_META_DATA_REG_A,
924 	[REG_B] = MLX5_MODI_META_DATA_REG_B,
925 	[REG_C_0] = MLX5_MODI_META_REG_C_0,
926 	[REG_C_1] = MLX5_MODI_META_REG_C_1,
927 	[REG_C_2] = MLX5_MODI_META_REG_C_2,
928 	[REG_C_3] = MLX5_MODI_META_REG_C_3,
929 	[REG_C_4] = MLX5_MODI_META_REG_C_4,
930 	[REG_C_5] = MLX5_MODI_META_REG_C_5,
931 	[REG_C_6] = MLX5_MODI_META_REG_C_6,
932 	[REG_C_7] = MLX5_MODI_META_REG_C_7,
933 };
934 
935 /**
936  * Convert register set to DV specification.
937  *
938  * @param[in,out] resource
939  *   Pointer to the modify-header resource.
940  * @param[in] action
941  *   Pointer to action specification.
942  * @param[out] error
943  *   Pointer to the error structure.
944  *
945  * @return
946  *   0 on success, a negative errno value otherwise and rte_errno is set.
947  */
948 static int
949 flow_dv_convert_action_set_reg
950 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
951 			 const struct rte_flow_action *action,
952 			 struct rte_flow_error *error)
953 {
954 	const struct mlx5_rte_flow_action_set_tag *conf = action->conf;
955 	struct mlx5_modification_cmd *actions = resource->actions;
956 	uint32_t i = resource->actions_num;
957 
958 	if (i >= MLX5_MAX_MODIFY_NUM)
959 		return rte_flow_error_set(error, EINVAL,
960 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
961 					  "too many items to modify");
962 	MLX5_ASSERT(conf->id != REG_NON);
963 	MLX5_ASSERT(conf->id < (enum modify_reg)RTE_DIM(reg_to_field));
964 	actions[i] = (struct mlx5_modification_cmd) {
965 		.action_type = MLX5_MODIFICATION_TYPE_SET,
966 		.field = reg_to_field[conf->id],
967 	};
968 	actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
969 	actions[i].data1 = rte_cpu_to_be_32(conf->data);
970 	++i;
971 	resource->actions_num = i;
972 	return 0;
973 }
974 
975 /**
976  * Convert SET_TAG action to DV specification.
977  *
978  * @param[in] dev
979  *   Pointer to the rte_eth_dev structure.
980  * @param[in,out] resource
981  *   Pointer to the modify-header resource.
982  * @param[in] conf
983  *   Pointer to action specification.
984  * @param[out] error
985  *   Pointer to the error structure.
986  *
987  * @return
988  *   0 on success, a negative errno value otherwise and rte_errno is set.
989  */
990 static int
991 flow_dv_convert_action_set_tag
992 			(struct rte_eth_dev *dev,
993 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
994 			 const struct rte_flow_action_set_tag *conf,
995 			 struct rte_flow_error *error)
996 {
997 	rte_be32_t data = rte_cpu_to_be_32(conf->data);
998 	rte_be32_t mask = rte_cpu_to_be_32(conf->mask);
999 	struct rte_flow_item item = {
1000 		.spec = &data,
1001 		.mask = &mask,
1002 	};
1003 	struct field_modify_info reg_c_x[] = {
1004 		[1] = {0, 0, 0},
1005 	};
1006 	enum mlx5_modification_field reg_type;
1007 	int ret;
1008 
1009 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
1010 	if (ret < 0)
1011 		return ret;
1012 	MLX5_ASSERT(ret != REG_NON);
1013 	MLX5_ASSERT((unsigned int)ret < RTE_DIM(reg_to_field));
1014 	reg_type = reg_to_field[ret];
1015 	MLX5_ASSERT(reg_type > 0);
1016 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_type};
1017 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1018 					     MLX5_MODIFICATION_TYPE_SET, error);
1019 }
1020 
1021 /**
1022  * Convert internal COPY_REG action to DV specification.
1023  *
1024  * @param[in] dev
1025  *   Pointer to the rte_eth_dev structure.
1026  * @param[in,out] res
1027  *   Pointer to the modify-header resource.
1028  * @param[in] action
1029  *   Pointer to action specification.
1030  * @param[out] error
1031  *   Pointer to the error structure.
1032  *
1033  * @return
1034  *   0 on success, a negative errno value otherwise and rte_errno is set.
1035  */
1036 static int
1037 flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev,
1038 				 struct mlx5_flow_dv_modify_hdr_resource *res,
1039 				 const struct rte_flow_action *action,
1040 				 struct rte_flow_error *error)
1041 {
1042 	const struct mlx5_flow_action_copy_mreg *conf = action->conf;
1043 	rte_be32_t mask = RTE_BE32(UINT32_MAX);
1044 	struct rte_flow_item item = {
1045 		.spec = NULL,
1046 		.mask = &mask,
1047 	};
1048 	struct field_modify_info reg_src[] = {
1049 		{4, 0, reg_to_field[conf->src]},
1050 		{0, 0, 0},
1051 	};
1052 	struct field_modify_info reg_dst = {
1053 		.offset = 0,
1054 		.id = reg_to_field[conf->dst],
1055 	};
1056 	/* Adjust reg_c[0] usage according to reported mask. */
1057 	if (conf->dst == REG_C_0 || conf->src == REG_C_0) {
1058 		struct mlx5_priv *priv = dev->data->dev_private;
1059 		uint32_t reg_c0 = priv->sh->dv_regc0_mask;
1060 
1061 		MLX5_ASSERT(reg_c0);
1062 		MLX5_ASSERT(priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY);
1063 		if (conf->dst == REG_C_0) {
1064 			/* Copy to reg_c[0], within mask only. */
1065 			reg_dst.offset = rte_bsf32(reg_c0);
1066 			/*
1067 			 * Mask is ignoring the enianness, because
1068 			 * there is no conversion in datapath.
1069 			 */
1070 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
1071 			/* Copy from destination lower bits to reg_c[0]. */
1072 			mask = reg_c0 >> reg_dst.offset;
1073 #else
1074 			/* Copy from destination upper bits to reg_c[0]. */
1075 			mask = reg_c0 << (sizeof(reg_c0) * CHAR_BIT -
1076 					  rte_fls_u32(reg_c0));
1077 #endif
1078 		} else {
1079 			mask = rte_cpu_to_be_32(reg_c0);
1080 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
1081 			/* Copy from reg_c[0] to destination lower bits. */
1082 			reg_dst.offset = 0;
1083 #else
1084 			/* Copy from reg_c[0] to destination upper bits. */
1085 			reg_dst.offset = sizeof(reg_c0) * CHAR_BIT -
1086 					 (rte_fls_u32(reg_c0) -
1087 					  rte_bsf32(reg_c0));
1088 #endif
1089 		}
1090 	}
1091 	return flow_dv_convert_modify_action(&item,
1092 					     reg_src, &reg_dst, res,
1093 					     MLX5_MODIFICATION_TYPE_COPY,
1094 					     error);
1095 }
1096 
1097 /**
1098  * Convert MARK action to DV specification. This routine is used
1099  * in extensive metadata only and requires metadata register to be
1100  * handled. In legacy mode hardware tag resource is engaged.
1101  *
1102  * @param[in] dev
1103  *   Pointer to the rte_eth_dev structure.
1104  * @param[in] conf
1105  *   Pointer to MARK action specification.
1106  * @param[in,out] resource
1107  *   Pointer to the modify-header resource.
1108  * @param[out] error
1109  *   Pointer to the error structure.
1110  *
1111  * @return
1112  *   0 on success, a negative errno value otherwise and rte_errno is set.
1113  */
1114 static int
1115 flow_dv_convert_action_mark(struct rte_eth_dev *dev,
1116 			    const struct rte_flow_action_mark *conf,
1117 			    struct mlx5_flow_dv_modify_hdr_resource *resource,
1118 			    struct rte_flow_error *error)
1119 {
1120 	struct mlx5_priv *priv = dev->data->dev_private;
1121 	rte_be32_t mask = rte_cpu_to_be_32(MLX5_FLOW_MARK_MASK &
1122 					   priv->sh->dv_mark_mask);
1123 	rte_be32_t data = rte_cpu_to_be_32(conf->id) & mask;
1124 	struct rte_flow_item item = {
1125 		.spec = &data,
1126 		.mask = &mask,
1127 	};
1128 	struct field_modify_info reg_c_x[] = {
1129 		[1] = {0, 0, 0},
1130 	};
1131 	int reg;
1132 
1133 	if (!mask)
1134 		return rte_flow_error_set(error, EINVAL,
1135 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1136 					  NULL, "zero mark action mask");
1137 	reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
1138 	if (reg < 0)
1139 		return reg;
1140 	MLX5_ASSERT(reg > 0);
1141 	if (reg == REG_C_0) {
1142 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1143 		uint32_t shl_c0 = rte_bsf32(msk_c0);
1144 
1145 		data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0);
1146 		mask = rte_cpu_to_be_32(mask) & msk_c0;
1147 		mask = rte_cpu_to_be_32(mask << shl_c0);
1148 	}
1149 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1150 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1151 					     MLX5_MODIFICATION_TYPE_SET, error);
1152 }
1153 
1154 /**
1155  * Get metadata register index for specified steering domain.
1156  *
1157  * @param[in] dev
1158  *   Pointer to the rte_eth_dev structure.
1159  * @param[in] attr
1160  *   Attributes of flow to determine steering domain.
1161  * @param[out] error
1162  *   Pointer to the error structure.
1163  *
1164  * @return
1165  *   positive index on success, a negative errno value otherwise
1166  *   and rte_errno is set.
1167  */
1168 static enum modify_reg
1169 flow_dv_get_metadata_reg(struct rte_eth_dev *dev,
1170 			 const struct rte_flow_attr *attr,
1171 			 struct rte_flow_error *error)
1172 {
1173 	int reg =
1174 		mlx5_flow_get_reg_id(dev, attr->transfer ?
1175 					  MLX5_METADATA_FDB :
1176 					    attr->egress ?
1177 					    MLX5_METADATA_TX :
1178 					    MLX5_METADATA_RX, 0, error);
1179 	if (reg < 0)
1180 		return rte_flow_error_set(error,
1181 					  ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
1182 					  NULL, "unavailable "
1183 					  "metadata register");
1184 	return reg;
1185 }
1186 
1187 /**
1188  * Convert SET_META action to DV specification.
1189  *
1190  * @param[in] dev
1191  *   Pointer to the rte_eth_dev structure.
1192  * @param[in,out] resource
1193  *   Pointer to the modify-header resource.
1194  * @param[in] attr
1195  *   Attributes of flow that includes this item.
1196  * @param[in] conf
1197  *   Pointer to action specification.
1198  * @param[out] error
1199  *   Pointer to the error structure.
1200  *
1201  * @return
1202  *   0 on success, a negative errno value otherwise and rte_errno is set.
1203  */
1204 static int
1205 flow_dv_convert_action_set_meta
1206 			(struct rte_eth_dev *dev,
1207 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1208 			 const struct rte_flow_attr *attr,
1209 			 const struct rte_flow_action_set_meta *conf,
1210 			 struct rte_flow_error *error)
1211 {
1212 	uint32_t data = conf->data;
1213 	uint32_t mask = conf->mask;
1214 	struct rte_flow_item item = {
1215 		.spec = &data,
1216 		.mask = &mask,
1217 	};
1218 	struct field_modify_info reg_c_x[] = {
1219 		[1] = {0, 0, 0},
1220 	};
1221 	int reg = flow_dv_get_metadata_reg(dev, attr, error);
1222 
1223 	if (reg < 0)
1224 		return reg;
1225 	MLX5_ASSERT(reg != REG_NON);
1226 	/*
1227 	 * In datapath code there is no endianness
1228 	 * coversions for perfromance reasons, all
1229 	 * pattern conversions are done in rte_flow.
1230 	 */
1231 	if (reg == REG_C_0) {
1232 		struct mlx5_priv *priv = dev->data->dev_private;
1233 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1234 		uint32_t shl_c0;
1235 
1236 		MLX5_ASSERT(msk_c0);
1237 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN
1238 		shl_c0 = rte_bsf32(msk_c0);
1239 #else
1240 		shl_c0 = sizeof(msk_c0) * CHAR_BIT - rte_fls_u32(msk_c0);
1241 #endif
1242 		mask <<= shl_c0;
1243 		data <<= shl_c0;
1244 		MLX5_ASSERT(!(~msk_c0 & rte_cpu_to_be_32(mask)));
1245 	}
1246 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1247 	/* The routine expects parameters in memory as big-endian ones. */
1248 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1249 					     MLX5_MODIFICATION_TYPE_SET, error);
1250 }
1251 
1252 /**
1253  * Convert modify-header set IPv4 DSCP action to DV specification.
1254  *
1255  * @param[in,out] resource
1256  *   Pointer to the modify-header resource.
1257  * @param[in] action
1258  *   Pointer to action specification.
1259  * @param[out] error
1260  *   Pointer to the error structure.
1261  *
1262  * @return
1263  *   0 on success, a negative errno value otherwise and rte_errno is set.
1264  */
1265 static int
1266 flow_dv_convert_action_modify_ipv4_dscp
1267 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1268 			 const struct rte_flow_action *action,
1269 			 struct rte_flow_error *error)
1270 {
1271 	const struct rte_flow_action_set_dscp *conf =
1272 		(const struct rte_flow_action_set_dscp *)(action->conf);
1273 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
1274 	struct rte_flow_item_ipv4 ipv4;
1275 	struct rte_flow_item_ipv4 ipv4_mask;
1276 
1277 	memset(&ipv4, 0, sizeof(ipv4));
1278 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
1279 	ipv4.hdr.type_of_service = conf->dscp;
1280 	ipv4_mask.hdr.type_of_service = RTE_IPV4_HDR_DSCP_MASK >> 2;
1281 	item.spec = &ipv4;
1282 	item.mask = &ipv4_mask;
1283 	return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
1284 					     MLX5_MODIFICATION_TYPE_SET, error);
1285 }
1286 
1287 /**
1288  * Convert modify-header set IPv6 DSCP action to DV specification.
1289  *
1290  * @param[in,out] resource
1291  *   Pointer to the modify-header resource.
1292  * @param[in] action
1293  *   Pointer to action specification.
1294  * @param[out] error
1295  *   Pointer to the error structure.
1296  *
1297  * @return
1298  *   0 on success, a negative errno value otherwise and rte_errno is set.
1299  */
1300 static int
1301 flow_dv_convert_action_modify_ipv6_dscp
1302 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1303 			 const struct rte_flow_action *action,
1304 			 struct rte_flow_error *error)
1305 {
1306 	const struct rte_flow_action_set_dscp *conf =
1307 		(const struct rte_flow_action_set_dscp *)(action->conf);
1308 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
1309 	struct rte_flow_item_ipv6 ipv6;
1310 	struct rte_flow_item_ipv6 ipv6_mask;
1311 
1312 	memset(&ipv6, 0, sizeof(ipv6));
1313 	memset(&ipv6_mask, 0, sizeof(ipv6_mask));
1314 	/*
1315 	 * Even though the DSCP bits offset of IPv6 is not byte aligned,
1316 	 * rdma-core only accept the DSCP bits byte aligned start from
1317 	 * bit 0 to 5 as to be compatible with IPv4. No need to shift the
1318 	 * bits in IPv6 case as rdma-core requires byte aligned value.
1319 	 */
1320 	ipv6.hdr.vtc_flow = conf->dscp;
1321 	ipv6_mask.hdr.vtc_flow = RTE_IPV6_HDR_DSCP_MASK >> 22;
1322 	item.spec = &ipv6;
1323 	item.mask = &ipv6_mask;
1324 	return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
1325 					     MLX5_MODIFICATION_TYPE_SET, error);
1326 }
1327 
1328 static void
1329 mlx5_flow_field_id_to_modify_info
1330 		(const struct rte_flow_action_modify_data *data,
1331 		 struct field_modify_info *info,
1332 		 uint32_t *mask, uint32_t *value, uint32_t width,
1333 		 struct rte_eth_dev *dev,
1334 		 const struct rte_flow_attr *attr,
1335 		 struct rte_flow_error *error)
1336 {
1337 	uint32_t idx = 0;
1338 	switch (data->field) {
1339 	case RTE_FLOW_FIELD_START:
1340 		/* not supported yet */
1341 		MLX5_ASSERT(false);
1342 		break;
1343 	case RTE_FLOW_FIELD_MAC_DST:
1344 		if (mask) {
1345 			if (data->offset < 32) {
1346 				info[idx] = (struct field_modify_info){4, 0,
1347 						MLX5_MODI_OUT_DMAC_47_16};
1348 				mask[idx] = 0xffffffff;
1349 				if (width < 32) {
1350 					mask[idx] = mask[idx] << (32 - width);
1351 					width = 0;
1352 				} else {
1353 					width -= 32;
1354 				}
1355 				if (!width)
1356 					break;
1357 				++idx;
1358 			}
1359 			info[idx] = (struct field_modify_info){2, 4 * idx,
1360 						MLX5_MODI_OUT_DMAC_15_0};
1361 			mask[idx] = (width) ? 0x0000ffff : 0x0;
1362 			if (width < 16)
1363 				mask[idx] = (mask[idx] << (16 - width)) &
1364 						0x0000ffff;
1365 		} else {
1366 			if (data->offset < 32)
1367 				info[idx++] = (struct field_modify_info){4, 0,
1368 						MLX5_MODI_OUT_DMAC_47_16};
1369 			info[idx] = (struct field_modify_info){2, 0,
1370 						MLX5_MODI_OUT_DMAC_15_0};
1371 		}
1372 		break;
1373 	case RTE_FLOW_FIELD_MAC_SRC:
1374 		if (mask) {
1375 			if (data->offset < 32) {
1376 				info[idx] = (struct field_modify_info){4, 0,
1377 						MLX5_MODI_OUT_SMAC_47_16};
1378 				mask[idx] = 0xffffffff;
1379 				if (width < 32) {
1380 					mask[idx] = mask[idx] << (32 - width);
1381 					width = 0;
1382 				} else {
1383 					width -= 32;
1384 				}
1385 				if (!width)
1386 					break;
1387 				++idx;
1388 			}
1389 			info[idx] = (struct field_modify_info){2, 4 * idx,
1390 						MLX5_MODI_OUT_SMAC_15_0};
1391 			mask[idx] = (width) ? 0x0000ffff : 0x0;
1392 			if (width < 16)
1393 				mask[idx] = (mask[idx] << (16 - width)) &
1394 						0x0000ffff;
1395 		} else {
1396 			if (data->offset < 32)
1397 				info[idx++] = (struct field_modify_info){4, 0,
1398 						MLX5_MODI_OUT_SMAC_47_16};
1399 			info[idx] = (struct field_modify_info){2, 0,
1400 						MLX5_MODI_OUT_SMAC_15_0};
1401 		}
1402 		break;
1403 	case RTE_FLOW_FIELD_VLAN_TYPE:
1404 		/* not supported yet */
1405 		break;
1406 	case RTE_FLOW_FIELD_VLAN_ID:
1407 		info[idx] = (struct field_modify_info){2, 0,
1408 					MLX5_MODI_OUT_FIRST_VID};
1409 		if (mask) {
1410 			mask[idx] = 0x00000fff;
1411 			if (width < 12)
1412 				mask[idx] = (mask[idx] << (12 - width)) &
1413 						0x00000fff;
1414 		}
1415 		break;
1416 	case RTE_FLOW_FIELD_MAC_TYPE:
1417 		info[idx] = (struct field_modify_info){2, 0,
1418 					MLX5_MODI_OUT_ETHERTYPE};
1419 		if (mask) {
1420 			mask[idx] = 0x0000ffff;
1421 			if (width < 16)
1422 				mask[idx] = (mask[idx] << (16 - width)) &
1423 						0x0000ffff;
1424 		}
1425 		break;
1426 	case RTE_FLOW_FIELD_IPV4_DSCP:
1427 		info[idx] = (struct field_modify_info){1, 0,
1428 					MLX5_MODI_OUT_IP_DSCP};
1429 		if (mask) {
1430 			mask[idx] = 0x0000003f;
1431 			if (width < 6)
1432 				mask[idx] = (mask[idx] << (6 - width)) &
1433 						0x0000003f;
1434 		}
1435 		break;
1436 	case RTE_FLOW_FIELD_IPV4_TTL:
1437 		info[idx] = (struct field_modify_info){1, 0,
1438 					MLX5_MODI_OUT_IPV4_TTL};
1439 		if (mask) {
1440 			mask[idx] = 0x000000ff;
1441 			if (width < 8)
1442 				mask[idx] = (mask[idx] << (8 - width)) &
1443 						0x000000ff;
1444 		}
1445 		break;
1446 	case RTE_FLOW_FIELD_IPV4_SRC:
1447 		info[idx] = (struct field_modify_info){4, 0,
1448 					MLX5_MODI_OUT_SIPV4};
1449 		if (mask) {
1450 			mask[idx] = 0xffffffff;
1451 			if (width < 32)
1452 				mask[idx] = mask[idx] << (32 - width);
1453 		}
1454 		break;
1455 	case RTE_FLOW_FIELD_IPV4_DST:
1456 		info[idx] = (struct field_modify_info){4, 0,
1457 					MLX5_MODI_OUT_DIPV4};
1458 		if (mask) {
1459 			mask[idx] = 0xffffffff;
1460 			if (width < 32)
1461 				mask[idx] = mask[idx] << (32 - width);
1462 		}
1463 		break;
1464 	case RTE_FLOW_FIELD_IPV6_DSCP:
1465 		info[idx] = (struct field_modify_info){1, 0,
1466 					MLX5_MODI_OUT_IP_DSCP};
1467 		if (mask) {
1468 			mask[idx] = 0x0000003f;
1469 			if (width < 6)
1470 				mask[idx] = (mask[idx] << (6 - width)) &
1471 						0x0000003f;
1472 		}
1473 		break;
1474 	case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
1475 		info[idx] = (struct field_modify_info){1, 0,
1476 					MLX5_MODI_OUT_IPV6_HOPLIMIT};
1477 		if (mask) {
1478 			mask[idx] = 0x000000ff;
1479 			if (width < 8)
1480 				mask[idx] = (mask[idx] << (8 - width)) &
1481 						0x000000ff;
1482 		}
1483 		break;
1484 	case RTE_FLOW_FIELD_IPV6_SRC:
1485 		if (mask) {
1486 			if (data->offset < 32) {
1487 				info[idx] = (struct field_modify_info){4, 0,
1488 						MLX5_MODI_OUT_SIPV6_127_96};
1489 				mask[idx] = 0xffffffff;
1490 				if (width < 32) {
1491 					mask[idx] = mask[idx] << (32 - width);
1492 					width = 0;
1493 				} else {
1494 					width -= 32;
1495 				}
1496 				if (!width)
1497 					break;
1498 				++idx;
1499 			}
1500 			if (data->offset < 64) {
1501 				info[idx] = (struct field_modify_info){4,
1502 						4 * idx,
1503 						MLX5_MODI_OUT_SIPV6_95_64};
1504 				mask[idx] = 0xffffffff;
1505 				if (width < 32) {
1506 					mask[idx] = mask[idx] << (32 - width);
1507 					width = 0;
1508 				} else {
1509 					width -= 32;
1510 				}
1511 				if (!width)
1512 					break;
1513 				++idx;
1514 			}
1515 			if (data->offset < 96) {
1516 				info[idx] = (struct field_modify_info){4,
1517 						8 * idx,
1518 						MLX5_MODI_OUT_SIPV6_63_32};
1519 				mask[idx] = 0xffffffff;
1520 				if (width < 32) {
1521 					mask[idx] = mask[idx] << (32 - width);
1522 					width = 0;
1523 				} else {
1524 					width -= 32;
1525 				}
1526 				if (!width)
1527 					break;
1528 				++idx;
1529 			}
1530 			info[idx] = (struct field_modify_info){4, 12 * idx,
1531 						MLX5_MODI_OUT_SIPV6_31_0};
1532 			mask[idx] = 0xffffffff;
1533 			if (width < 32)
1534 				mask[idx] = mask[idx] << (32 - width);
1535 		} else {
1536 			if (data->offset < 32)
1537 				info[idx++] = (struct field_modify_info){4, 0,
1538 						MLX5_MODI_OUT_SIPV6_127_96};
1539 			if (data->offset < 64)
1540 				info[idx++] = (struct field_modify_info){4, 0,
1541 						MLX5_MODI_OUT_SIPV6_95_64};
1542 			if (data->offset < 96)
1543 				info[idx++] = (struct field_modify_info){4, 0,
1544 						MLX5_MODI_OUT_SIPV6_63_32};
1545 			if (data->offset < 128)
1546 				info[idx++] = (struct field_modify_info){4, 0,
1547 						MLX5_MODI_OUT_SIPV6_31_0};
1548 		}
1549 		break;
1550 	case RTE_FLOW_FIELD_IPV6_DST:
1551 		if (mask) {
1552 			if (data->offset < 32) {
1553 				info[idx] = (struct field_modify_info){4, 0,
1554 						MLX5_MODI_OUT_DIPV6_127_96};
1555 				mask[idx] = 0xffffffff;
1556 				if (width < 32) {
1557 					mask[idx] = mask[idx] << (32 - width);
1558 					width = 0;
1559 				} else {
1560 					width -= 32;
1561 				}
1562 				if (!width)
1563 					break;
1564 				++idx;
1565 			}
1566 			if (data->offset < 64) {
1567 				info[idx] = (struct field_modify_info){4,
1568 						4 * idx,
1569 						MLX5_MODI_OUT_DIPV6_95_64};
1570 				mask[idx] = 0xffffffff;
1571 				if (width < 32) {
1572 					mask[idx] = mask[idx] << (32 - width);
1573 					width = 0;
1574 				} else {
1575 					width -= 32;
1576 				}
1577 				if (!width)
1578 					break;
1579 				++idx;
1580 			}
1581 			if (data->offset < 96) {
1582 				info[idx] = (struct field_modify_info){4,
1583 						8 * idx,
1584 						MLX5_MODI_OUT_DIPV6_63_32};
1585 				mask[idx] = 0xffffffff;
1586 				if (width < 32) {
1587 					mask[idx] = mask[idx] << (32 - width);
1588 					width = 0;
1589 				} else {
1590 					width -= 32;
1591 				}
1592 				if (!width)
1593 					break;
1594 				++idx;
1595 			}
1596 			info[idx] = (struct field_modify_info){4, 12 * idx,
1597 						MLX5_MODI_OUT_DIPV6_31_0};
1598 			mask[idx] = 0xffffffff;
1599 			if (width < 32)
1600 				mask[idx] = mask[idx] << (32 - width);
1601 		} else {
1602 			if (data->offset < 32)
1603 				info[idx++] = (struct field_modify_info){4, 0,
1604 						MLX5_MODI_OUT_DIPV6_127_96};
1605 			if (data->offset < 64)
1606 				info[idx++] = (struct field_modify_info){4, 0,
1607 						MLX5_MODI_OUT_DIPV6_95_64};
1608 			if (data->offset < 96)
1609 				info[idx++] = (struct field_modify_info){4, 0,
1610 						MLX5_MODI_OUT_DIPV6_63_32};
1611 			if (data->offset < 128)
1612 				info[idx++] = (struct field_modify_info){4, 0,
1613 						MLX5_MODI_OUT_DIPV6_31_0};
1614 		}
1615 		break;
1616 	case RTE_FLOW_FIELD_TCP_PORT_SRC:
1617 		info[idx] = (struct field_modify_info){2, 0,
1618 					MLX5_MODI_OUT_TCP_SPORT};
1619 		if (mask) {
1620 			mask[idx] = 0x0000ffff;
1621 			if (width < 16)
1622 				mask[idx] = (mask[idx] << (16 - width)) &
1623 						0x0000ffff;
1624 		}
1625 		break;
1626 	case RTE_FLOW_FIELD_TCP_PORT_DST:
1627 		info[idx] = (struct field_modify_info){2, 0,
1628 					MLX5_MODI_OUT_TCP_DPORT};
1629 		if (mask) {
1630 			mask[idx] = 0x0000ffff;
1631 			if (width < 16)
1632 				mask[idx] = (mask[idx] << (16 - width)) &
1633 						0x0000ffff;
1634 		}
1635 		break;
1636 	case RTE_FLOW_FIELD_TCP_SEQ_NUM:
1637 		info[idx] = (struct field_modify_info){4, 0,
1638 					MLX5_MODI_OUT_TCP_SEQ_NUM};
1639 		if (mask) {
1640 			mask[idx] = 0xffffffff;
1641 			if (width < 32)
1642 				mask[idx] = (mask[idx] << (32 - width));
1643 		}
1644 		break;
1645 	case RTE_FLOW_FIELD_TCP_ACK_NUM:
1646 		info[idx] = (struct field_modify_info){4, 0,
1647 					MLX5_MODI_OUT_TCP_ACK_NUM};
1648 		if (mask) {
1649 			mask[idx] = 0xffffffff;
1650 			if (width < 32)
1651 				mask[idx] = (mask[idx] << (32 - width));
1652 		}
1653 		break;
1654 	case RTE_FLOW_FIELD_TCP_FLAGS:
1655 		info[idx] = (struct field_modify_info){1, 0,
1656 					MLX5_MODI_OUT_TCP_FLAGS};
1657 		if (mask) {
1658 			mask[idx] = 0x0000003f;
1659 			if (width < 6)
1660 				mask[idx] = (mask[idx] << (6 - width)) &
1661 						0x0000003f;
1662 		}
1663 		break;
1664 	case RTE_FLOW_FIELD_UDP_PORT_SRC:
1665 		info[idx] = (struct field_modify_info){2, 0,
1666 					MLX5_MODI_OUT_UDP_SPORT};
1667 		if (mask) {
1668 			mask[idx] = 0x0000ffff;
1669 			if (width < 16)
1670 				mask[idx] = (mask[idx] << (16 - width)) &
1671 						0x0000ffff;
1672 		}
1673 		break;
1674 	case RTE_FLOW_FIELD_UDP_PORT_DST:
1675 		info[idx] = (struct field_modify_info){2, 0,
1676 					MLX5_MODI_OUT_UDP_DPORT};
1677 		if (mask) {
1678 			mask[idx] = 0x0000ffff;
1679 			if (width < 16)
1680 				mask[idx] = (mask[idx] << (16 - width)) &
1681 						0x0000ffff;
1682 		}
1683 		break;
1684 	case RTE_FLOW_FIELD_VXLAN_VNI:
1685 		/* not supported yet */
1686 		break;
1687 	case RTE_FLOW_FIELD_GENEVE_VNI:
1688 		/* not supported yet*/
1689 		break;
1690 	case RTE_FLOW_FIELD_GTP_TEID:
1691 		info[idx] = (struct field_modify_info){4, 0,
1692 					MLX5_MODI_GTP_TEID};
1693 		if (mask) {
1694 			mask[idx] = 0xffffffff;
1695 			if (width < 32)
1696 				mask[idx] = mask[idx] << (32 - width);
1697 		}
1698 		break;
1699 	case RTE_FLOW_FIELD_TAG:
1700 		{
1701 			int reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG,
1702 						   data->level, error);
1703 			if (reg < 0)
1704 				return;
1705 			MLX5_ASSERT(reg != REG_NON);
1706 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1707 			info[idx] = (struct field_modify_info){4, 0,
1708 						reg_to_field[reg]};
1709 			if (mask) {
1710 				mask[idx] = 0xffffffff;
1711 				if (width < 32)
1712 					mask[idx] = mask[idx] << (32 - width);
1713 			}
1714 		}
1715 		break;
1716 	case RTE_FLOW_FIELD_MARK:
1717 		{
1718 			int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK,
1719 						       0, error);
1720 			if (reg < 0)
1721 				return;
1722 			MLX5_ASSERT(reg != REG_NON);
1723 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1724 			info[idx] = (struct field_modify_info){4, 0,
1725 						reg_to_field[reg]};
1726 			if (mask) {
1727 				mask[idx] = 0xffffffff;
1728 				if (width < 32)
1729 					mask[idx] = mask[idx] << (32 - width);
1730 			}
1731 		}
1732 		break;
1733 	case RTE_FLOW_FIELD_META:
1734 		{
1735 			int reg = flow_dv_get_metadata_reg(dev, attr, error);
1736 			if (reg < 0)
1737 				return;
1738 			MLX5_ASSERT(reg != REG_NON);
1739 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1740 			info[idx] = (struct field_modify_info){4, 0,
1741 						reg_to_field[reg]};
1742 			if (mask) {
1743 				mask[idx] = 0xffffffff;
1744 				if (width < 32)
1745 					mask[idx] = mask[idx] << (32 - width);
1746 			}
1747 		}
1748 		break;
1749 	case RTE_FLOW_FIELD_POINTER:
1750 		for (idx = 0; idx < MLX5_ACT_MAX_MOD_FIELDS; idx++) {
1751 			if (mask[idx]) {
1752 				memcpy(&value[idx],
1753 					(void *)(uintptr_t)data->value, 32);
1754 				value[idx] = RTE_BE32(value[idx]);
1755 				break;
1756 			}
1757 		}
1758 		break;
1759 	case RTE_FLOW_FIELD_VALUE:
1760 		for (idx = 0; idx < MLX5_ACT_MAX_MOD_FIELDS; idx++) {
1761 			if (mask[idx]) {
1762 				value[idx] = RTE_BE32((uint32_t)data->value);
1763 				break;
1764 			}
1765 		}
1766 		break;
1767 	default:
1768 		MLX5_ASSERT(false);
1769 		break;
1770 	}
1771 }
1772 
1773 /**
1774  * Convert modify_field action to DV specification.
1775  *
1776  * @param[in] dev
1777  *   Pointer to the rte_eth_dev structure.
1778  * @param[in,out] resource
1779  *   Pointer to the modify-header resource.
1780  * @param[in] action
1781  *   Pointer to action specification.
1782  * @param[in] attr
1783  *   Attributes of flow that includes this item.
1784  * @param[out] error
1785  *   Pointer to the error structure.
1786  *
1787  * @return
1788  *   0 on success, a negative errno value otherwise and rte_errno is set.
1789  */
1790 static int
1791 flow_dv_convert_action_modify_field
1792 			(struct rte_eth_dev *dev,
1793 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1794 			 const struct rte_flow_action *action,
1795 			 const struct rte_flow_attr *attr,
1796 			 struct rte_flow_error *error)
1797 {
1798 	const struct rte_flow_action_modify_field *conf =
1799 		(const struct rte_flow_action_modify_field *)(action->conf);
1800 	struct rte_flow_item item;
1801 	struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = {
1802 								{0, 0, 0} };
1803 	struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = {
1804 								{0, 0, 0} };
1805 	uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0};
1806 	uint32_t value[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0};
1807 	uint32_t type;
1808 
1809 	if (conf->src.field == RTE_FLOW_FIELD_POINTER ||
1810 		conf->src.field == RTE_FLOW_FIELD_VALUE) {
1811 		type = MLX5_MODIFICATION_TYPE_SET;
1812 		/** For SET fill the destination field (field) first. */
1813 		mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask,
1814 					  value, conf->width, dev, attr, error);
1815 		/** Then copy immediate value from source as per mask. */
1816 		mlx5_flow_field_id_to_modify_info(&conf->src, dcopy, mask,
1817 					  value, conf->width, dev, attr, error);
1818 		item.spec = &value;
1819 	} else {
1820 		type = MLX5_MODIFICATION_TYPE_COPY;
1821 		/** For COPY fill the destination field (dcopy) without mask. */
1822 		mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL,
1823 					  value, conf->width, dev, attr, error);
1824 		/** Then construct the source field (field) with mask. */
1825 		mlx5_flow_field_id_to_modify_info(&conf->src, field, mask,
1826 					  value, conf->width, dev, attr, error);
1827 	}
1828 	item.mask = &mask;
1829 	return flow_dv_convert_modify_action(&item,
1830 			field, dcopy, resource, type, error);
1831 }
1832 
1833 /**
1834  * Validate MARK item.
1835  *
1836  * @param[in] dev
1837  *   Pointer to the rte_eth_dev structure.
1838  * @param[in] item
1839  *   Item specification.
1840  * @param[in] attr
1841  *   Attributes of flow that includes this item.
1842  * @param[out] error
1843  *   Pointer to error structure.
1844  *
1845  * @return
1846  *   0 on success, a negative errno value otherwise and rte_errno is set.
1847  */
1848 static int
1849 flow_dv_validate_item_mark(struct rte_eth_dev *dev,
1850 			   const struct rte_flow_item *item,
1851 			   const struct rte_flow_attr *attr __rte_unused,
1852 			   struct rte_flow_error *error)
1853 {
1854 	struct mlx5_priv *priv = dev->data->dev_private;
1855 	struct mlx5_dev_config *config = &priv->config;
1856 	const struct rte_flow_item_mark *spec = item->spec;
1857 	const struct rte_flow_item_mark *mask = item->mask;
1858 	const struct rte_flow_item_mark nic_mask = {
1859 		.id = priv->sh->dv_mark_mask,
1860 	};
1861 	int ret;
1862 
1863 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
1864 		return rte_flow_error_set(error, ENOTSUP,
1865 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1866 					  "extended metadata feature"
1867 					  " isn't enabled");
1868 	if (!mlx5_flow_ext_mreg_supported(dev))
1869 		return rte_flow_error_set(error, ENOTSUP,
1870 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1871 					  "extended metadata register"
1872 					  " isn't supported");
1873 	if (!nic_mask.id)
1874 		return rte_flow_error_set(error, ENOTSUP,
1875 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1876 					  "extended metadata register"
1877 					  " isn't available");
1878 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
1879 	if (ret < 0)
1880 		return ret;
1881 	if (!spec)
1882 		return rte_flow_error_set(error, EINVAL,
1883 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
1884 					  item->spec,
1885 					  "data cannot be empty");
1886 	if (spec->id >= (MLX5_FLOW_MARK_MAX & nic_mask.id))
1887 		return rte_flow_error_set(error, EINVAL,
1888 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1889 					  &spec->id,
1890 					  "mark id exceeds the limit");
1891 	if (!mask)
1892 		mask = &nic_mask;
1893 	if (!mask->id)
1894 		return rte_flow_error_set(error, EINVAL,
1895 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
1896 					"mask cannot be zero");
1897 
1898 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
1899 					(const uint8_t *)&nic_mask,
1900 					sizeof(struct rte_flow_item_mark),
1901 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
1902 	if (ret < 0)
1903 		return ret;
1904 	return 0;
1905 }
1906 
1907 /**
1908  * Validate META item.
1909  *
1910  * @param[in] dev
1911  *   Pointer to the rte_eth_dev structure.
1912  * @param[in] item
1913  *   Item specification.
1914  * @param[in] attr
1915  *   Attributes of flow that includes this item.
1916  * @param[out] error
1917  *   Pointer to error structure.
1918  *
1919  * @return
1920  *   0 on success, a negative errno value otherwise and rte_errno is set.
1921  */
1922 static int
1923 flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused,
1924 			   const struct rte_flow_item *item,
1925 			   const struct rte_flow_attr *attr,
1926 			   struct rte_flow_error *error)
1927 {
1928 	struct mlx5_priv *priv = dev->data->dev_private;
1929 	struct mlx5_dev_config *config = &priv->config;
1930 	const struct rte_flow_item_meta *spec = item->spec;
1931 	const struct rte_flow_item_meta *mask = item->mask;
1932 	struct rte_flow_item_meta nic_mask = {
1933 		.data = UINT32_MAX
1934 	};
1935 	int reg;
1936 	int ret;
1937 
1938 	if (!spec)
1939 		return rte_flow_error_set(error, EINVAL,
1940 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
1941 					  item->spec,
1942 					  "data cannot be empty");
1943 	if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
1944 		if (!mlx5_flow_ext_mreg_supported(dev))
1945 			return rte_flow_error_set(error, ENOTSUP,
1946 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1947 					  "extended metadata register"
1948 					  " isn't supported");
1949 		reg = flow_dv_get_metadata_reg(dev, attr, error);
1950 		if (reg < 0)
1951 			return reg;
1952 		if (reg == REG_NON)
1953 			return rte_flow_error_set(error, ENOTSUP,
1954 					RTE_FLOW_ERROR_TYPE_ITEM, item,
1955 					"unavalable extended metadata register");
1956 		if (reg == REG_B)
1957 			return rte_flow_error_set(error, ENOTSUP,
1958 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1959 					  "match on reg_b "
1960 					  "isn't supported");
1961 		if (reg != REG_A)
1962 			nic_mask.data = priv->sh->dv_meta_mask;
1963 	} else {
1964 		if (attr->transfer)
1965 			return rte_flow_error_set(error, ENOTSUP,
1966 					RTE_FLOW_ERROR_TYPE_ITEM, item,
1967 					"extended metadata feature "
1968 					"should be enabled when "
1969 					"meta item is requested "
1970 					"with e-switch mode ");
1971 		if (attr->ingress)
1972 			return rte_flow_error_set(error, ENOTSUP,
1973 					RTE_FLOW_ERROR_TYPE_ITEM, item,
1974 					"match on metadata for ingress "
1975 					"is not supported in legacy "
1976 					"metadata mode");
1977 	}
1978 	if (!mask)
1979 		mask = &rte_flow_item_meta_mask;
1980 	if (!mask->data)
1981 		return rte_flow_error_set(error, EINVAL,
1982 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
1983 					"mask cannot be zero");
1984 
1985 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
1986 					(const uint8_t *)&nic_mask,
1987 					sizeof(struct rte_flow_item_meta),
1988 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
1989 	return ret;
1990 }
1991 
1992 /**
1993  * Validate TAG item.
1994  *
1995  * @param[in] dev
1996  *   Pointer to the rte_eth_dev structure.
1997  * @param[in] item
1998  *   Item specification.
1999  * @param[in] attr
2000  *   Attributes of flow that includes this item.
2001  * @param[out] error
2002  *   Pointer to error structure.
2003  *
2004  * @return
2005  *   0 on success, a negative errno value otherwise and rte_errno is set.
2006  */
2007 static int
2008 flow_dv_validate_item_tag(struct rte_eth_dev *dev,
2009 			  const struct rte_flow_item *item,
2010 			  const struct rte_flow_attr *attr __rte_unused,
2011 			  struct rte_flow_error *error)
2012 {
2013 	const struct rte_flow_item_tag *spec = item->spec;
2014 	const struct rte_flow_item_tag *mask = item->mask;
2015 	const struct rte_flow_item_tag nic_mask = {
2016 		.data = RTE_BE32(UINT32_MAX),
2017 		.index = 0xff,
2018 	};
2019 	int ret;
2020 
2021 	if (!mlx5_flow_ext_mreg_supported(dev))
2022 		return rte_flow_error_set(error, ENOTSUP,
2023 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2024 					  "extensive metadata register"
2025 					  " isn't supported");
2026 	if (!spec)
2027 		return rte_flow_error_set(error, EINVAL,
2028 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2029 					  item->spec,
2030 					  "data cannot be empty");
2031 	if (!mask)
2032 		mask = &rte_flow_item_tag_mask;
2033 	if (!mask->data)
2034 		return rte_flow_error_set(error, EINVAL,
2035 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2036 					"mask cannot be zero");
2037 
2038 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2039 					(const uint8_t *)&nic_mask,
2040 					sizeof(struct rte_flow_item_tag),
2041 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2042 	if (ret < 0)
2043 		return ret;
2044 	if (mask->index != 0xff)
2045 		return rte_flow_error_set(error, EINVAL,
2046 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2047 					  "partial mask for tag index"
2048 					  " is not supported");
2049 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, spec->index, error);
2050 	if (ret < 0)
2051 		return ret;
2052 	MLX5_ASSERT(ret != REG_NON);
2053 	return 0;
2054 }
2055 
2056 /**
2057  * Validate vport item.
2058  *
2059  * @param[in] dev
2060  *   Pointer to the rte_eth_dev structure.
2061  * @param[in] item
2062  *   Item specification.
2063  * @param[in] attr
2064  *   Attributes of flow that includes this item.
2065  * @param[in] item_flags
2066  *   Bit-fields that holds the items detected until now.
2067  * @param[out] error
2068  *   Pointer to error structure.
2069  *
2070  * @return
2071  *   0 on success, a negative errno value otherwise and rte_errno is set.
2072  */
2073 static int
2074 flow_dv_validate_item_port_id(struct rte_eth_dev *dev,
2075 			      const struct rte_flow_item *item,
2076 			      const struct rte_flow_attr *attr,
2077 			      uint64_t item_flags,
2078 			      struct rte_flow_error *error)
2079 {
2080 	const struct rte_flow_item_port_id *spec = item->spec;
2081 	const struct rte_flow_item_port_id *mask = item->mask;
2082 	const struct rte_flow_item_port_id switch_mask = {
2083 			.id = 0xffffffff,
2084 	};
2085 	struct mlx5_priv *esw_priv;
2086 	struct mlx5_priv *dev_priv;
2087 	int ret;
2088 
2089 	if (!attr->transfer)
2090 		return rte_flow_error_set(error, EINVAL,
2091 					  RTE_FLOW_ERROR_TYPE_ITEM,
2092 					  NULL,
2093 					  "match on port id is valid only"
2094 					  " when transfer flag is enabled");
2095 	if (item_flags & MLX5_FLOW_ITEM_PORT_ID)
2096 		return rte_flow_error_set(error, ENOTSUP,
2097 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2098 					  "multiple source ports are not"
2099 					  " supported");
2100 	if (!mask)
2101 		mask = &switch_mask;
2102 	if (mask->id != 0xffffffff)
2103 		return rte_flow_error_set(error, ENOTSUP,
2104 					   RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2105 					   mask,
2106 					   "no support for partial mask on"
2107 					   " \"id\" field");
2108 	ret = mlx5_flow_item_acceptable
2109 				(item, (const uint8_t *)mask,
2110 				 (const uint8_t *)&rte_flow_item_port_id_mask,
2111 				 sizeof(struct rte_flow_item_port_id),
2112 				 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2113 	if (ret)
2114 		return ret;
2115 	if (!spec)
2116 		return 0;
2117 	esw_priv = mlx5_port_to_eswitch_info(spec->id, false);
2118 	if (!esw_priv)
2119 		return rte_flow_error_set(error, rte_errno,
2120 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2121 					  "failed to obtain E-Switch info for"
2122 					  " port");
2123 	dev_priv = mlx5_dev_to_eswitch_info(dev);
2124 	if (!dev_priv)
2125 		return rte_flow_error_set(error, rte_errno,
2126 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2127 					  NULL,
2128 					  "failed to obtain E-Switch info");
2129 	if (esw_priv->domain_id != dev_priv->domain_id)
2130 		return rte_flow_error_set(error, EINVAL,
2131 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2132 					  "cannot match on a port from a"
2133 					  " different E-Switch");
2134 	return 0;
2135 }
2136 
2137 /**
2138  * Validate VLAN item.
2139  *
2140  * @param[in] item
2141  *   Item specification.
2142  * @param[in] item_flags
2143  *   Bit-fields that holds the items detected until now.
2144  * @param[in] dev
2145  *   Ethernet device flow is being created on.
2146  * @param[out] error
2147  *   Pointer to error structure.
2148  *
2149  * @return
2150  *   0 on success, a negative errno value otherwise and rte_errno is set.
2151  */
2152 static int
2153 flow_dv_validate_item_vlan(const struct rte_flow_item *item,
2154 			   uint64_t item_flags,
2155 			   struct rte_eth_dev *dev,
2156 			   struct rte_flow_error *error)
2157 {
2158 	const struct rte_flow_item_vlan *mask = item->mask;
2159 	const struct rte_flow_item_vlan nic_mask = {
2160 		.tci = RTE_BE16(UINT16_MAX),
2161 		.inner_type = RTE_BE16(UINT16_MAX),
2162 		.has_more_vlan = 1,
2163 	};
2164 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2165 	int ret;
2166 	const uint64_t l34m = tunnel ? (MLX5_FLOW_LAYER_INNER_L3 |
2167 					MLX5_FLOW_LAYER_INNER_L4) :
2168 				       (MLX5_FLOW_LAYER_OUTER_L3 |
2169 					MLX5_FLOW_LAYER_OUTER_L4);
2170 	const uint64_t vlanm = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
2171 					MLX5_FLOW_LAYER_OUTER_VLAN;
2172 
2173 	if (item_flags & vlanm)
2174 		return rte_flow_error_set(error, EINVAL,
2175 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2176 					  "multiple VLAN layers not supported");
2177 	else if ((item_flags & l34m) != 0)
2178 		return rte_flow_error_set(error, EINVAL,
2179 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2180 					  "VLAN cannot follow L3/L4 layer");
2181 	if (!mask)
2182 		mask = &rte_flow_item_vlan_mask;
2183 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2184 					(const uint8_t *)&nic_mask,
2185 					sizeof(struct rte_flow_item_vlan),
2186 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2187 	if (ret)
2188 		return ret;
2189 	if (!tunnel && mask->tci != RTE_BE16(0x0fff)) {
2190 		struct mlx5_priv *priv = dev->data->dev_private;
2191 
2192 		if (priv->vmwa_context) {
2193 			/*
2194 			 * Non-NULL context means we have a virtual machine
2195 			 * and SR-IOV enabled, we have to create VLAN interface
2196 			 * to make hypervisor to setup E-Switch vport
2197 			 * context correctly. We avoid creating the multiple
2198 			 * VLAN interfaces, so we cannot support VLAN tag mask.
2199 			 */
2200 			return rte_flow_error_set(error, EINVAL,
2201 						  RTE_FLOW_ERROR_TYPE_ITEM,
2202 						  item,
2203 						  "VLAN tag mask is not"
2204 						  " supported in virtual"
2205 						  " environment");
2206 		}
2207 	}
2208 	return 0;
2209 }
2210 
2211 /*
2212  * GTP flags are contained in 1 byte of the format:
2213  * -------------------------------------------
2214  * | bit   | 0 - 2   | 3  | 4   | 5 | 6 | 7  |
2215  * |-----------------------------------------|
2216  * | value | Version | PT | Res | E | S | PN |
2217  * -------------------------------------------
2218  *
2219  * Matching is supported only for GTP flags E, S, PN.
2220  */
2221 #define MLX5_GTP_FLAGS_MASK	0x07
2222 
2223 /**
2224  * Validate GTP item.
2225  *
2226  * @param[in] dev
2227  *   Pointer to the rte_eth_dev structure.
2228  * @param[in] item
2229  *   Item specification.
2230  * @param[in] item_flags
2231  *   Bit-fields that holds the items detected until now.
2232  * @param[out] error
2233  *   Pointer to error structure.
2234  *
2235  * @return
2236  *   0 on success, a negative errno value otherwise and rte_errno is set.
2237  */
2238 static int
2239 flow_dv_validate_item_gtp(struct rte_eth_dev *dev,
2240 			  const struct rte_flow_item *item,
2241 			  uint64_t item_flags,
2242 			  struct rte_flow_error *error)
2243 {
2244 	struct mlx5_priv *priv = dev->data->dev_private;
2245 	const struct rte_flow_item_gtp *spec = item->spec;
2246 	const struct rte_flow_item_gtp *mask = item->mask;
2247 	const struct rte_flow_item_gtp nic_mask = {
2248 		.v_pt_rsv_flags = MLX5_GTP_FLAGS_MASK,
2249 		.msg_type = 0xff,
2250 		.teid = RTE_BE32(0xffffffff),
2251 	};
2252 
2253 	if (!priv->config.hca_attr.tunnel_stateless_gtp)
2254 		return rte_flow_error_set(error, ENOTSUP,
2255 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2256 					  "GTP support is not enabled");
2257 	if (item_flags & MLX5_FLOW_LAYER_TUNNEL)
2258 		return rte_flow_error_set(error, ENOTSUP,
2259 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2260 					  "multiple tunnel layers not"
2261 					  " supported");
2262 	if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP))
2263 		return rte_flow_error_set(error, EINVAL,
2264 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2265 					  "no outer UDP layer found");
2266 	if (!mask)
2267 		mask = &rte_flow_item_gtp_mask;
2268 	if (spec && spec->v_pt_rsv_flags & ~MLX5_GTP_FLAGS_MASK)
2269 		return rte_flow_error_set(error, ENOTSUP,
2270 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2271 					  "Match is supported for GTP"
2272 					  " flags only");
2273 	return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2274 					 (const uint8_t *)&nic_mask,
2275 					 sizeof(struct rte_flow_item_gtp),
2276 					 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2277 }
2278 
2279 /**
2280  * Validate GTP PSC item.
2281  *
2282  * @param[in] item
2283  *   Item specification.
2284  * @param[in] last_item
2285  *   Previous validated item in the pattern items.
2286  * @param[in] gtp_item
2287  *   Previous GTP item specification.
2288  * @param[in] attr
2289  *   Pointer to flow attributes.
2290  * @param[out] error
2291  *   Pointer to error structure.
2292  *
2293  * @return
2294  *   0 on success, a negative errno value otherwise and rte_errno is set.
2295  */
2296 static int
2297 flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item,
2298 			      uint64_t last_item,
2299 			      const struct rte_flow_item *gtp_item,
2300 			      const struct rte_flow_attr *attr,
2301 			      struct rte_flow_error *error)
2302 {
2303 	const struct rte_flow_item_gtp *gtp_spec;
2304 	const struct rte_flow_item_gtp *gtp_mask;
2305 	const struct rte_flow_item_gtp_psc *spec;
2306 	const struct rte_flow_item_gtp_psc *mask;
2307 	const struct rte_flow_item_gtp_psc nic_mask = {
2308 		.pdu_type = 0xFF,
2309 		.qfi = 0xFF,
2310 	};
2311 
2312 	if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP))
2313 		return rte_flow_error_set
2314 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2315 			 "GTP PSC item must be preceded with GTP item");
2316 	gtp_spec = gtp_item->spec;
2317 	gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask;
2318 	/* GTP spec and E flag is requested to match zero. */
2319 	if (gtp_spec &&
2320 		(gtp_mask->v_pt_rsv_flags &
2321 		~gtp_spec->v_pt_rsv_flags & MLX5_GTP_EXT_HEADER_FLAG))
2322 		return rte_flow_error_set
2323 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2324 			 "GTP E flag must be 1 to match GTP PSC");
2325 	/* Check the flow is not created in group zero. */
2326 	if (!attr->transfer && !attr->group)
2327 		return rte_flow_error_set
2328 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2329 			 "GTP PSC is not supported for group 0");
2330 	/* GTP spec is here and E flag is requested to match zero. */
2331 	if (!item->spec)
2332 		return 0;
2333 	spec = item->spec;
2334 	mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask;
2335 	if (spec->pdu_type > MLX5_GTP_EXT_MAX_PDU_TYPE)
2336 		return rte_flow_error_set
2337 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2338 			 "PDU type should be smaller than 16");
2339 	return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2340 					 (const uint8_t *)&nic_mask,
2341 					 sizeof(struct rte_flow_item_gtp_psc),
2342 					 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2343 }
2344 
2345 /**
2346  * Validate IPV4 item.
2347  * Use existing validation function mlx5_flow_validate_item_ipv4(), and
2348  * add specific validation of fragment_offset field,
2349  *
2350  * @param[in] item
2351  *   Item specification.
2352  * @param[in] item_flags
2353  *   Bit-fields that holds the items detected until now.
2354  * @param[out] error
2355  *   Pointer to error structure.
2356  *
2357  * @return
2358  *   0 on success, a negative errno value otherwise and rte_errno is set.
2359  */
2360 static int
2361 flow_dv_validate_item_ipv4(const struct rte_flow_item *item,
2362 			   uint64_t item_flags,
2363 			   uint64_t last_item,
2364 			   uint16_t ether_type,
2365 			   struct rte_flow_error *error)
2366 {
2367 	int ret;
2368 	const struct rte_flow_item_ipv4 *spec = item->spec;
2369 	const struct rte_flow_item_ipv4 *last = item->last;
2370 	const struct rte_flow_item_ipv4 *mask = item->mask;
2371 	rte_be16_t fragment_offset_spec = 0;
2372 	rte_be16_t fragment_offset_last = 0;
2373 	const struct rte_flow_item_ipv4 nic_ipv4_mask = {
2374 		.hdr = {
2375 			.src_addr = RTE_BE32(0xffffffff),
2376 			.dst_addr = RTE_BE32(0xffffffff),
2377 			.type_of_service = 0xff,
2378 			.fragment_offset = RTE_BE16(0xffff),
2379 			.next_proto_id = 0xff,
2380 			.time_to_live = 0xff,
2381 		},
2382 	};
2383 
2384 	ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item,
2385 					   ether_type, &nic_ipv4_mask,
2386 					   MLX5_ITEM_RANGE_ACCEPTED, error);
2387 	if (ret < 0)
2388 		return ret;
2389 	if (spec && mask)
2390 		fragment_offset_spec = spec->hdr.fragment_offset &
2391 				       mask->hdr.fragment_offset;
2392 	if (!fragment_offset_spec)
2393 		return 0;
2394 	/*
2395 	 * spec and mask are valid, enforce using full mask to make sure the
2396 	 * complete value is used correctly.
2397 	 */
2398 	if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2399 			!= RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2400 		return rte_flow_error_set(error, EINVAL,
2401 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2402 					  item, "must use full mask for"
2403 					  " fragment_offset");
2404 	/*
2405 	 * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0,
2406 	 * indicating this is 1st fragment of fragmented packet.
2407 	 * This is not yet supported in MLX5, return appropriate error message.
2408 	 */
2409 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG))
2410 		return rte_flow_error_set(error, ENOTSUP,
2411 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2412 					  "match on first fragment not "
2413 					  "supported");
2414 	if (fragment_offset_spec && !last)
2415 		return rte_flow_error_set(error, ENOTSUP,
2416 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2417 					  "specified value not supported");
2418 	/* spec and last are valid, validate the specified range. */
2419 	fragment_offset_last = last->hdr.fragment_offset &
2420 			       mask->hdr.fragment_offset;
2421 	/*
2422 	 * Match on fragment_offset spec 0x2001 and last 0x3fff
2423 	 * means MF is 1 and frag-offset is > 0.
2424 	 * This packet is fragment 2nd and onward, excluding last.
2425 	 * This is not yet supported in MLX5, return appropriate
2426 	 * error message.
2427 	 */
2428 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) &&
2429 	    fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2430 		return rte_flow_error_set(error, ENOTSUP,
2431 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2432 					  last, "match on following "
2433 					  "fragments not supported");
2434 	/*
2435 	 * Match on fragment_offset spec 0x0001 and last 0x1fff
2436 	 * means MF is 0 and frag-offset is > 0.
2437 	 * This packet is last fragment of fragmented packet.
2438 	 * This is not yet supported in MLX5, return appropriate
2439 	 * error message.
2440 	 */
2441 	if (fragment_offset_spec == RTE_BE16(1) &&
2442 	    fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK))
2443 		return rte_flow_error_set(error, ENOTSUP,
2444 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2445 					  last, "match on last "
2446 					  "fragment not supported");
2447 	/*
2448 	 * Match on fragment_offset spec 0x0001 and last 0x3fff
2449 	 * means MF and/or frag-offset is not 0.
2450 	 * This is a fragmented packet.
2451 	 * Other range values are invalid and rejected.
2452 	 */
2453 	if (!(fragment_offset_spec == RTE_BE16(1) &&
2454 	      fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)))
2455 		return rte_flow_error_set(error, ENOTSUP,
2456 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2457 					  "specified range not supported");
2458 	return 0;
2459 }
2460 
2461 /**
2462  * Validate IPV6 fragment extension item.
2463  *
2464  * @param[in] item
2465  *   Item specification.
2466  * @param[in] item_flags
2467  *   Bit-fields that holds the items detected until now.
2468  * @param[out] error
2469  *   Pointer to error structure.
2470  *
2471  * @return
2472  *   0 on success, a negative errno value otherwise and rte_errno is set.
2473  */
2474 static int
2475 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item,
2476 				    uint64_t item_flags,
2477 				    struct rte_flow_error *error)
2478 {
2479 	const struct rte_flow_item_ipv6_frag_ext *spec = item->spec;
2480 	const struct rte_flow_item_ipv6_frag_ext *last = item->last;
2481 	const struct rte_flow_item_ipv6_frag_ext *mask = item->mask;
2482 	rte_be16_t frag_data_spec = 0;
2483 	rte_be16_t frag_data_last = 0;
2484 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2485 	const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 :
2486 				      MLX5_FLOW_LAYER_OUTER_L4;
2487 	int ret = 0;
2488 	struct rte_flow_item_ipv6_frag_ext nic_mask = {
2489 		.hdr = {
2490 			.next_header = 0xff,
2491 			.frag_data = RTE_BE16(0xffff),
2492 		},
2493 	};
2494 
2495 	if (item_flags & l4m)
2496 		return rte_flow_error_set(error, EINVAL,
2497 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2498 					  "ipv6 fragment extension item cannot "
2499 					  "follow L4 item.");
2500 	if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
2501 	    (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6)))
2502 		return rte_flow_error_set(error, EINVAL,
2503 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2504 					  "ipv6 fragment extension item must "
2505 					  "follow ipv6 item");
2506 	if (spec && mask)
2507 		frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data;
2508 	if (!frag_data_spec)
2509 		return 0;
2510 	/*
2511 	 * spec and mask are valid, enforce using full mask to make sure the
2512 	 * complete value is used correctly.
2513 	 */
2514 	if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) !=
2515 				RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2516 		return rte_flow_error_set(error, EINVAL,
2517 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2518 					  item, "must use full mask for"
2519 					  " frag_data");
2520 	/*
2521 	 * Match on frag_data 0x00001 means M is 1 and frag-offset is 0.
2522 	 * This is 1st fragment of fragmented packet.
2523 	 */
2524 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK))
2525 		return rte_flow_error_set(error, ENOTSUP,
2526 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2527 					  "match on first fragment not "
2528 					  "supported");
2529 	if (frag_data_spec && !last)
2530 		return rte_flow_error_set(error, EINVAL,
2531 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2532 					  "specified value not supported");
2533 	ret = mlx5_flow_item_acceptable
2534 				(item, (const uint8_t *)mask,
2535 				 (const uint8_t *)&nic_mask,
2536 				 sizeof(struct rte_flow_item_ipv6_frag_ext),
2537 				 MLX5_ITEM_RANGE_ACCEPTED, error);
2538 	if (ret)
2539 		return ret;
2540 	/* spec and last are valid, validate the specified range. */
2541 	frag_data_last = last->hdr.frag_data & mask->hdr.frag_data;
2542 	/*
2543 	 * Match on frag_data spec 0x0009 and last 0xfff9
2544 	 * means M is 1 and frag-offset is > 0.
2545 	 * This packet is fragment 2nd and onward, excluding last.
2546 	 * This is not yet supported in MLX5, return appropriate
2547 	 * error message.
2548 	 */
2549 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN |
2550 				       RTE_IPV6_EHDR_MF_MASK) &&
2551 	    frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2552 		return rte_flow_error_set(error, ENOTSUP,
2553 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2554 					  last, "match on following "
2555 					  "fragments not supported");
2556 	/*
2557 	 * Match on frag_data spec 0x0008 and last 0xfff8
2558 	 * means M is 0 and frag-offset is > 0.
2559 	 * This packet is last fragment of fragmented packet.
2560 	 * This is not yet supported in MLX5, return appropriate
2561 	 * error message.
2562 	 */
2563 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) &&
2564 	    frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK))
2565 		return rte_flow_error_set(error, ENOTSUP,
2566 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2567 					  last, "match on last "
2568 					  "fragment not supported");
2569 	/* Other range values are invalid and rejected. */
2570 	return rte_flow_error_set(error, EINVAL,
2571 				  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2572 				  "specified range not supported");
2573 }
2574 
2575 /**
2576  * Validate the pop VLAN action.
2577  *
2578  * @param[in] dev
2579  *   Pointer to the rte_eth_dev structure.
2580  * @param[in] action_flags
2581  *   Holds the actions detected until now.
2582  * @param[in] action
2583  *   Pointer to the pop vlan action.
2584  * @param[in] item_flags
2585  *   The items found in this flow rule.
2586  * @param[in] attr
2587  *   Pointer to flow attributes.
2588  * @param[out] error
2589  *   Pointer to error structure.
2590  *
2591  * @return
2592  *   0 on success, a negative errno value otherwise and rte_errno is set.
2593  */
2594 static int
2595 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev,
2596 				 uint64_t action_flags,
2597 				 const struct rte_flow_action *action,
2598 				 uint64_t item_flags,
2599 				 const struct rte_flow_attr *attr,
2600 				 struct rte_flow_error *error)
2601 {
2602 	const struct mlx5_priv *priv = dev->data->dev_private;
2603 
2604 	(void)action;
2605 	(void)attr;
2606 	if (!priv->sh->pop_vlan_action)
2607 		return rte_flow_error_set(error, ENOTSUP,
2608 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2609 					  NULL,
2610 					  "pop vlan action is not supported");
2611 	if (attr->egress)
2612 		return rte_flow_error_set(error, ENOTSUP,
2613 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
2614 					  NULL,
2615 					  "pop vlan action not supported for "
2616 					  "egress");
2617 	if (action_flags & MLX5_FLOW_VLAN_ACTIONS)
2618 		return rte_flow_error_set(error, ENOTSUP,
2619 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2620 					  "no support for multiple VLAN "
2621 					  "actions");
2622 	/* Pop VLAN with preceding Decap requires inner header with VLAN. */
2623 	if ((action_flags & MLX5_FLOW_ACTION_DECAP) &&
2624 	    !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN))
2625 		return rte_flow_error_set(error, ENOTSUP,
2626 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2627 					  NULL,
2628 					  "cannot pop vlan after decap without "
2629 					  "match on inner vlan in the flow");
2630 	/* Pop VLAN without preceding Decap requires outer header with VLAN. */
2631 	if (!(action_flags & MLX5_FLOW_ACTION_DECAP) &&
2632 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
2633 		return rte_flow_error_set(error, ENOTSUP,
2634 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2635 					  NULL,
2636 					  "cannot pop vlan without a "
2637 					  "match on (outer) vlan in the flow");
2638 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2639 		return rte_flow_error_set(error, EINVAL,
2640 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2641 					  "wrong action order, port_id should "
2642 					  "be after pop VLAN action");
2643 	if (!attr->transfer && priv->representor)
2644 		return rte_flow_error_set(error, ENOTSUP,
2645 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2646 					  "pop vlan action for VF representor "
2647 					  "not supported on NIC table");
2648 	return 0;
2649 }
2650 
2651 /**
2652  * Get VLAN default info from vlan match info.
2653  *
2654  * @param[in] items
2655  *   the list of item specifications.
2656  * @param[out] vlan
2657  *   pointer VLAN info to fill to.
2658  *
2659  * @return
2660  *   0 on success, a negative errno value otherwise and rte_errno is set.
2661  */
2662 static void
2663 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items,
2664 				  struct rte_vlan_hdr *vlan)
2665 {
2666 	const struct rte_flow_item_vlan nic_mask = {
2667 		.tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK |
2668 				MLX5DV_FLOW_VLAN_VID_MASK),
2669 		.inner_type = RTE_BE16(0xffff),
2670 	};
2671 
2672 	if (items == NULL)
2673 		return;
2674 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
2675 		int type = items->type;
2676 
2677 		if (type == RTE_FLOW_ITEM_TYPE_VLAN ||
2678 		    type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN)
2679 			break;
2680 	}
2681 	if (items->type != RTE_FLOW_ITEM_TYPE_END) {
2682 		const struct rte_flow_item_vlan *vlan_m = items->mask;
2683 		const struct rte_flow_item_vlan *vlan_v = items->spec;
2684 
2685 		/* If VLAN item in pattern doesn't contain data, return here. */
2686 		if (!vlan_v)
2687 			return;
2688 		if (!vlan_m)
2689 			vlan_m = &nic_mask;
2690 		/* Only full match values are accepted */
2691 		if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) ==
2692 		     MLX5DV_FLOW_VLAN_PCP_MASK_BE) {
2693 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
2694 			vlan->vlan_tci |=
2695 				rte_be_to_cpu_16(vlan_v->tci &
2696 						 MLX5DV_FLOW_VLAN_PCP_MASK_BE);
2697 		}
2698 		if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) ==
2699 		     MLX5DV_FLOW_VLAN_VID_MASK_BE) {
2700 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
2701 			vlan->vlan_tci |=
2702 				rte_be_to_cpu_16(vlan_v->tci &
2703 						 MLX5DV_FLOW_VLAN_VID_MASK_BE);
2704 		}
2705 		if (vlan_m->inner_type == nic_mask.inner_type)
2706 			vlan->eth_proto = rte_be_to_cpu_16(vlan_v->inner_type &
2707 							   vlan_m->inner_type);
2708 	}
2709 }
2710 
2711 /**
2712  * Validate the push VLAN action.
2713  *
2714  * @param[in] dev
2715  *   Pointer to the rte_eth_dev structure.
2716  * @param[in] action_flags
2717  *   Holds the actions detected until now.
2718  * @param[in] item_flags
2719  *   The items found in this flow rule.
2720  * @param[in] action
2721  *   Pointer to the action structure.
2722  * @param[in] attr
2723  *   Pointer to flow attributes
2724  * @param[out] error
2725  *   Pointer to error structure.
2726  *
2727  * @return
2728  *   0 on success, a negative errno value otherwise and rte_errno is set.
2729  */
2730 static int
2731 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev,
2732 				  uint64_t action_flags,
2733 				  const struct rte_flow_item_vlan *vlan_m,
2734 				  const struct rte_flow_action *action,
2735 				  const struct rte_flow_attr *attr,
2736 				  struct rte_flow_error *error)
2737 {
2738 	const struct rte_flow_action_of_push_vlan *push_vlan = action->conf;
2739 	const struct mlx5_priv *priv = dev->data->dev_private;
2740 
2741 	if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) &&
2742 	    push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ))
2743 		return rte_flow_error_set(error, EINVAL,
2744 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2745 					  "invalid vlan ethertype");
2746 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2747 		return rte_flow_error_set(error, EINVAL,
2748 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2749 					  "wrong action order, port_id should "
2750 					  "be after push VLAN");
2751 	if (!attr->transfer && priv->representor)
2752 		return rte_flow_error_set(error, ENOTSUP,
2753 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2754 					  "push vlan action for VF representor "
2755 					  "not supported on NIC table");
2756 	if (vlan_m &&
2757 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) &&
2758 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) !=
2759 		MLX5DV_FLOW_VLAN_PCP_MASK_BE &&
2760 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) &&
2761 	    !(mlx5_flow_find_action
2762 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP)))
2763 		return rte_flow_error_set(error, EINVAL,
2764 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2765 					  "not full match mask on VLAN PCP and "
2766 					  "there is no of_set_vlan_pcp action, "
2767 					  "push VLAN action cannot figure out "
2768 					  "PCP value");
2769 	if (vlan_m &&
2770 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) &&
2771 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) !=
2772 		MLX5DV_FLOW_VLAN_VID_MASK_BE &&
2773 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) &&
2774 	    !(mlx5_flow_find_action
2775 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)))
2776 		return rte_flow_error_set(error, EINVAL,
2777 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2778 					  "not full match mask on VLAN VID and "
2779 					  "there is no of_set_vlan_vid action, "
2780 					  "push VLAN action cannot figure out "
2781 					  "VID value");
2782 	(void)attr;
2783 	return 0;
2784 }
2785 
2786 /**
2787  * Validate the set VLAN PCP.
2788  *
2789  * @param[in] action_flags
2790  *   Holds the actions detected until now.
2791  * @param[in] actions
2792  *   Pointer to the list of actions remaining in the flow rule.
2793  * @param[out] error
2794  *   Pointer to error structure.
2795  *
2796  * @return
2797  *   0 on success, a negative errno value otherwise and rte_errno is set.
2798  */
2799 static int
2800 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags,
2801 				     const struct rte_flow_action actions[],
2802 				     struct rte_flow_error *error)
2803 {
2804 	const struct rte_flow_action *action = actions;
2805 	const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf;
2806 
2807 	if (conf->vlan_pcp > 7)
2808 		return rte_flow_error_set(error, EINVAL,
2809 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2810 					  "VLAN PCP value is too big");
2811 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN))
2812 		return rte_flow_error_set(error, ENOTSUP,
2813 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2814 					  "set VLAN PCP action must follow "
2815 					  "the push VLAN action");
2816 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
2817 		return rte_flow_error_set(error, ENOTSUP,
2818 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2819 					  "Multiple VLAN PCP modification are "
2820 					  "not supported");
2821 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2822 		return rte_flow_error_set(error, EINVAL,
2823 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2824 					  "wrong action order, port_id should "
2825 					  "be after set VLAN PCP");
2826 	return 0;
2827 }
2828 
2829 /**
2830  * Validate the set VLAN VID.
2831  *
2832  * @param[in] item_flags
2833  *   Holds the items detected in this rule.
2834  * @param[in] action_flags
2835  *   Holds the actions detected until now.
2836  * @param[in] actions
2837  *   Pointer to the list of actions remaining in the flow rule.
2838  * @param[out] error
2839  *   Pointer to error structure.
2840  *
2841  * @return
2842  *   0 on success, a negative errno value otherwise and rte_errno is set.
2843  */
2844 static int
2845 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
2846 				     uint64_t action_flags,
2847 				     const struct rte_flow_action actions[],
2848 				     struct rte_flow_error *error)
2849 {
2850 	const struct rte_flow_action *action = actions;
2851 	const struct rte_flow_action_of_set_vlan_vid *conf = action->conf;
2852 
2853 	if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE)
2854 		return rte_flow_error_set(error, EINVAL,
2855 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2856 					  "VLAN VID value is too big");
2857 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) &&
2858 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
2859 		return rte_flow_error_set(error, ENOTSUP,
2860 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2861 					  "set VLAN VID action must follow push"
2862 					  " VLAN action or match on VLAN item");
2863 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID)
2864 		return rte_flow_error_set(error, ENOTSUP,
2865 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2866 					  "Multiple VLAN VID modifications are "
2867 					  "not supported");
2868 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2869 		return rte_flow_error_set(error, EINVAL,
2870 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2871 					  "wrong action order, port_id should "
2872 					  "be after set VLAN VID");
2873 	return 0;
2874 }
2875 
2876 /*
2877  * Validate the FLAG action.
2878  *
2879  * @param[in] dev
2880  *   Pointer to the rte_eth_dev structure.
2881  * @param[in] action_flags
2882  *   Holds the actions detected until now.
2883  * @param[in] attr
2884  *   Pointer to flow attributes
2885  * @param[out] error
2886  *   Pointer to error structure.
2887  *
2888  * @return
2889  *   0 on success, a negative errno value otherwise and rte_errno is set.
2890  */
2891 static int
2892 flow_dv_validate_action_flag(struct rte_eth_dev *dev,
2893 			     uint64_t action_flags,
2894 			     const struct rte_flow_attr *attr,
2895 			     struct rte_flow_error *error)
2896 {
2897 	struct mlx5_priv *priv = dev->data->dev_private;
2898 	struct mlx5_dev_config *config = &priv->config;
2899 	int ret;
2900 
2901 	/* Fall back if no extended metadata register support. */
2902 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
2903 		return mlx5_flow_validate_action_flag(action_flags, attr,
2904 						      error);
2905 	/* Extensive metadata mode requires registers. */
2906 	if (!mlx5_flow_ext_mreg_supported(dev))
2907 		return rte_flow_error_set(error, ENOTSUP,
2908 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2909 					  "no metadata registers "
2910 					  "to support flag action");
2911 	if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT))
2912 		return rte_flow_error_set(error, ENOTSUP,
2913 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2914 					  "extended metadata register"
2915 					  " isn't available");
2916 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
2917 	if (ret < 0)
2918 		return ret;
2919 	MLX5_ASSERT(ret > 0);
2920 	if (action_flags & MLX5_FLOW_ACTION_MARK)
2921 		return rte_flow_error_set(error, EINVAL,
2922 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2923 					  "can't mark and flag in same flow");
2924 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
2925 		return rte_flow_error_set(error, EINVAL,
2926 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2927 					  "can't have 2 flag"
2928 					  " actions in same flow");
2929 	return 0;
2930 }
2931 
2932 /**
2933  * Validate MARK action.
2934  *
2935  * @param[in] dev
2936  *   Pointer to the rte_eth_dev structure.
2937  * @param[in] action
2938  *   Pointer to action.
2939  * @param[in] action_flags
2940  *   Holds the actions detected until now.
2941  * @param[in] attr
2942  *   Pointer to flow attributes
2943  * @param[out] error
2944  *   Pointer to error structure.
2945  *
2946  * @return
2947  *   0 on success, a negative errno value otherwise and rte_errno is set.
2948  */
2949 static int
2950 flow_dv_validate_action_mark(struct rte_eth_dev *dev,
2951 			     const struct rte_flow_action *action,
2952 			     uint64_t action_flags,
2953 			     const struct rte_flow_attr *attr,
2954 			     struct rte_flow_error *error)
2955 {
2956 	struct mlx5_priv *priv = dev->data->dev_private;
2957 	struct mlx5_dev_config *config = &priv->config;
2958 	const struct rte_flow_action_mark *mark = action->conf;
2959 	int ret;
2960 
2961 	if (is_tunnel_offload_active(dev))
2962 		return rte_flow_error_set(error, ENOTSUP,
2963 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2964 					  "no mark action "
2965 					  "if tunnel offload active");
2966 	/* Fall back if no extended metadata register support. */
2967 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
2968 		return mlx5_flow_validate_action_mark(action, action_flags,
2969 						      attr, error);
2970 	/* Extensive metadata mode requires registers. */
2971 	if (!mlx5_flow_ext_mreg_supported(dev))
2972 		return rte_flow_error_set(error, ENOTSUP,
2973 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2974 					  "no metadata registers "
2975 					  "to support mark action");
2976 	if (!priv->sh->dv_mark_mask)
2977 		return rte_flow_error_set(error, ENOTSUP,
2978 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2979 					  "extended metadata register"
2980 					  " isn't available");
2981 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
2982 	if (ret < 0)
2983 		return ret;
2984 	MLX5_ASSERT(ret > 0);
2985 	if (!mark)
2986 		return rte_flow_error_set(error, EINVAL,
2987 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2988 					  "configuration cannot be null");
2989 	if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask))
2990 		return rte_flow_error_set(error, EINVAL,
2991 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
2992 					  &mark->id,
2993 					  "mark id exceeds the limit");
2994 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
2995 		return rte_flow_error_set(error, EINVAL,
2996 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2997 					  "can't flag and mark in same flow");
2998 	if (action_flags & MLX5_FLOW_ACTION_MARK)
2999 		return rte_flow_error_set(error, EINVAL,
3000 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3001 					  "can't have 2 mark actions in same"
3002 					  " flow");
3003 	return 0;
3004 }
3005 
3006 /**
3007  * Validate SET_META action.
3008  *
3009  * @param[in] dev
3010  *   Pointer to the rte_eth_dev structure.
3011  * @param[in] action
3012  *   Pointer to the action structure.
3013  * @param[in] action_flags
3014  *   Holds the actions detected until now.
3015  * @param[in] attr
3016  *   Pointer to flow attributes
3017  * @param[out] error
3018  *   Pointer to error structure.
3019  *
3020  * @return
3021  *   0 on success, a negative errno value otherwise and rte_errno is set.
3022  */
3023 static int
3024 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev,
3025 				 const struct rte_flow_action *action,
3026 				 uint64_t action_flags __rte_unused,
3027 				 const struct rte_flow_attr *attr,
3028 				 struct rte_flow_error *error)
3029 {
3030 	const struct rte_flow_action_set_meta *conf;
3031 	uint32_t nic_mask = UINT32_MAX;
3032 	int reg;
3033 
3034 	if (!mlx5_flow_ext_mreg_supported(dev))
3035 		return rte_flow_error_set(error, ENOTSUP,
3036 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3037 					  "extended metadata register"
3038 					  " isn't supported");
3039 	reg = flow_dv_get_metadata_reg(dev, attr, error);
3040 	if (reg < 0)
3041 		return reg;
3042 	if (reg == REG_NON)
3043 		return rte_flow_error_set(error, ENOTSUP,
3044 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3045 					  "unavalable extended metadata register");
3046 	if (reg != REG_A && reg != REG_B) {
3047 		struct mlx5_priv *priv = dev->data->dev_private;
3048 
3049 		nic_mask = priv->sh->dv_meta_mask;
3050 	}
3051 	if (!(action->conf))
3052 		return rte_flow_error_set(error, EINVAL,
3053 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3054 					  "configuration cannot be null");
3055 	conf = (const struct rte_flow_action_set_meta *)action->conf;
3056 	if (!conf->mask)
3057 		return rte_flow_error_set(error, EINVAL,
3058 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3059 					  "zero mask doesn't have any effect");
3060 	if (conf->mask & ~nic_mask)
3061 		return rte_flow_error_set(error, EINVAL,
3062 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3063 					  "meta data must be within reg C0");
3064 	return 0;
3065 }
3066 
3067 /**
3068  * Validate SET_TAG action.
3069  *
3070  * @param[in] dev
3071  *   Pointer to the rte_eth_dev structure.
3072  * @param[in] action
3073  *   Pointer to the action structure.
3074  * @param[in] action_flags
3075  *   Holds the actions detected until now.
3076  * @param[in] attr
3077  *   Pointer to flow attributes
3078  * @param[out] error
3079  *   Pointer to error structure.
3080  *
3081  * @return
3082  *   0 on success, a negative errno value otherwise and rte_errno is set.
3083  */
3084 static int
3085 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev,
3086 				const struct rte_flow_action *action,
3087 				uint64_t action_flags,
3088 				const struct rte_flow_attr *attr,
3089 				struct rte_flow_error *error)
3090 {
3091 	const struct rte_flow_action_set_tag *conf;
3092 	const uint64_t terminal_action_flags =
3093 		MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE |
3094 		MLX5_FLOW_ACTION_RSS;
3095 	int ret;
3096 
3097 	if (!mlx5_flow_ext_mreg_supported(dev))
3098 		return rte_flow_error_set(error, ENOTSUP,
3099 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3100 					  "extensive metadata register"
3101 					  " isn't supported");
3102 	if (!(action->conf))
3103 		return rte_flow_error_set(error, EINVAL,
3104 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3105 					  "configuration cannot be null");
3106 	conf = (const struct rte_flow_action_set_tag *)action->conf;
3107 	if (!conf->mask)
3108 		return rte_flow_error_set(error, EINVAL,
3109 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3110 					  "zero mask doesn't have any effect");
3111 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
3112 	if (ret < 0)
3113 		return ret;
3114 	if (!attr->transfer && attr->ingress &&
3115 	    (action_flags & terminal_action_flags))
3116 		return rte_flow_error_set(error, EINVAL,
3117 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3118 					  "set_tag has no effect"
3119 					  " with terminal actions");
3120 	return 0;
3121 }
3122 
3123 /**
3124  * Validate count action.
3125  *
3126  * @param[in] dev
3127  *   Pointer to rte_eth_dev structure.
3128  * @param[in] action
3129  *   Pointer to the action structure.
3130  * @param[in] action_flags
3131  *   Holds the actions detected until now.
3132  * @param[out] error
3133  *   Pointer to error structure.
3134  *
3135  * @return
3136  *   0 on success, a negative errno value otherwise and rte_errno is set.
3137  */
3138 static int
3139 flow_dv_validate_action_count(struct rte_eth_dev *dev,
3140 			      const struct rte_flow_action *action,
3141 			      uint64_t action_flags,
3142 			      struct rte_flow_error *error)
3143 {
3144 	struct mlx5_priv *priv = dev->data->dev_private;
3145 	const struct rte_flow_action_count *count;
3146 
3147 	if (!priv->config.devx)
3148 		goto notsup_err;
3149 	if (action_flags & MLX5_FLOW_ACTION_COUNT)
3150 		return rte_flow_error_set(error, EINVAL,
3151 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3152 					  "duplicate count actions set");
3153 	count = (const struct rte_flow_action_count *)action->conf;
3154 	if (count && count->shared && (action_flags & MLX5_FLOW_ACTION_AGE) &&
3155 	    !priv->sh->flow_hit_aso_en)
3156 		return rte_flow_error_set(error, EINVAL,
3157 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3158 					  "old age and shared count combination is not supported");
3159 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
3160 	return 0;
3161 #endif
3162 notsup_err:
3163 	return rte_flow_error_set
3164 		      (error, ENOTSUP,
3165 		       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3166 		       NULL,
3167 		       "count action not supported");
3168 }
3169 
3170 /**
3171  * Validate the L2 encap action.
3172  *
3173  * @param[in] dev
3174  *   Pointer to the rte_eth_dev structure.
3175  * @param[in] action_flags
3176  *   Holds the actions detected until now.
3177  * @param[in] action
3178  *   Pointer to the action structure.
3179  * @param[in] attr
3180  *   Pointer to flow attributes.
3181  * @param[out] error
3182  *   Pointer to error structure.
3183  *
3184  * @return
3185  *   0 on success, a negative errno value otherwise and rte_errno is set.
3186  */
3187 static int
3188 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev,
3189 				 uint64_t action_flags,
3190 				 const struct rte_flow_action *action,
3191 				 const struct rte_flow_attr *attr,
3192 				 struct rte_flow_error *error)
3193 {
3194 	const struct mlx5_priv *priv = dev->data->dev_private;
3195 
3196 	if (!(action->conf))
3197 		return rte_flow_error_set(error, EINVAL,
3198 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3199 					  "configuration cannot be null");
3200 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3201 		return rte_flow_error_set(error, EINVAL,
3202 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3203 					  "can only have a single encap action "
3204 					  "in a flow");
3205 	if (!attr->transfer && priv->representor)
3206 		return rte_flow_error_set(error, ENOTSUP,
3207 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3208 					  "encap action for VF representor "
3209 					  "not supported on NIC table");
3210 	return 0;
3211 }
3212 
3213 /**
3214  * Validate a decap action.
3215  *
3216  * @param[in] dev
3217  *   Pointer to the rte_eth_dev structure.
3218  * @param[in] action_flags
3219  *   Holds the actions detected until now.
3220  * @param[in] action
3221  *   Pointer to the action structure.
3222  * @param[in] item_flags
3223  *   Holds the items detected.
3224  * @param[in] attr
3225  *   Pointer to flow attributes
3226  * @param[out] error
3227  *   Pointer to error structure.
3228  *
3229  * @return
3230  *   0 on success, a negative errno value otherwise and rte_errno is set.
3231  */
3232 static int
3233 flow_dv_validate_action_decap(struct rte_eth_dev *dev,
3234 			      uint64_t action_flags,
3235 			      const struct rte_flow_action *action,
3236 			      const uint64_t item_flags,
3237 			      const struct rte_flow_attr *attr,
3238 			      struct rte_flow_error *error)
3239 {
3240 	const struct mlx5_priv *priv = dev->data->dev_private;
3241 
3242 	if (priv->config.hca_attr.scatter_fcs_w_decap_disable &&
3243 	    !priv->config.decap_en)
3244 		return rte_flow_error_set(error, ENOTSUP,
3245 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3246 					  "decap is not enabled");
3247 	if (action_flags & MLX5_FLOW_XCAP_ACTIONS)
3248 		return rte_flow_error_set(error, ENOTSUP,
3249 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3250 					  action_flags &
3251 					  MLX5_FLOW_ACTION_DECAP ? "can only "
3252 					  "have a single decap action" : "decap "
3253 					  "after encap is not supported");
3254 	if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
3255 		return rte_flow_error_set(error, EINVAL,
3256 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3257 					  "can't have decap action after"
3258 					  " modify action");
3259 	if (attr->egress)
3260 		return rte_flow_error_set(error, ENOTSUP,
3261 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
3262 					  NULL,
3263 					  "decap action not supported for "
3264 					  "egress");
3265 	if (!attr->transfer && priv->representor)
3266 		return rte_flow_error_set(error, ENOTSUP,
3267 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3268 					  "decap action for VF representor "
3269 					  "not supported on NIC table");
3270 	if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP &&
3271 	    !(item_flags & MLX5_FLOW_LAYER_VXLAN))
3272 		return rte_flow_error_set(error, ENOTSUP,
3273 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3274 				"VXLAN item should be present for VXLAN decap");
3275 	return 0;
3276 }
3277 
3278 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,};
3279 
3280 /**
3281  * Validate the raw encap and decap actions.
3282  *
3283  * @param[in] dev
3284  *   Pointer to the rte_eth_dev structure.
3285  * @param[in] decap
3286  *   Pointer to the decap action.
3287  * @param[in] encap
3288  *   Pointer to the encap action.
3289  * @param[in] attr
3290  *   Pointer to flow attributes
3291  * @param[in/out] action_flags
3292  *   Holds the actions detected until now.
3293  * @param[out] actions_n
3294  *   pointer to the number of actions counter.
3295  * @param[in] action
3296  *   Pointer to the action structure.
3297  * @param[in] item_flags
3298  *   Holds the items detected.
3299  * @param[out] error
3300  *   Pointer to error structure.
3301  *
3302  * @return
3303  *   0 on success, a negative errno value otherwise and rte_errno is set.
3304  */
3305 static int
3306 flow_dv_validate_action_raw_encap_decap
3307 	(struct rte_eth_dev *dev,
3308 	 const struct rte_flow_action_raw_decap *decap,
3309 	 const struct rte_flow_action_raw_encap *encap,
3310 	 const struct rte_flow_attr *attr, uint64_t *action_flags,
3311 	 int *actions_n, const struct rte_flow_action *action,
3312 	 uint64_t item_flags, struct rte_flow_error *error)
3313 {
3314 	const struct mlx5_priv *priv = dev->data->dev_private;
3315 	int ret;
3316 
3317 	if (encap && (!encap->size || !encap->data))
3318 		return rte_flow_error_set(error, EINVAL,
3319 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3320 					  "raw encap data cannot be empty");
3321 	if (decap && encap) {
3322 		if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE &&
3323 		    encap->size > MLX5_ENCAPSULATION_DECISION_SIZE)
3324 			/* L3 encap. */
3325 			decap = NULL;
3326 		else if (encap->size <=
3327 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3328 			   decap->size >
3329 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3330 			/* L3 decap. */
3331 			encap = NULL;
3332 		else if (encap->size >
3333 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3334 			   decap->size >
3335 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3336 			/* 2 L2 actions: encap and decap. */
3337 			;
3338 		else
3339 			return rte_flow_error_set(error,
3340 				ENOTSUP,
3341 				RTE_FLOW_ERROR_TYPE_ACTION,
3342 				NULL, "unsupported too small "
3343 				"raw decap and too small raw "
3344 				"encap combination");
3345 	}
3346 	if (decap) {
3347 		ret = flow_dv_validate_action_decap(dev, *action_flags, action,
3348 						    item_flags, attr, error);
3349 		if (ret < 0)
3350 			return ret;
3351 		*action_flags |= MLX5_FLOW_ACTION_DECAP;
3352 		++(*actions_n);
3353 	}
3354 	if (encap) {
3355 		if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE)
3356 			return rte_flow_error_set(error, ENOTSUP,
3357 						  RTE_FLOW_ERROR_TYPE_ACTION,
3358 						  NULL,
3359 						  "small raw encap size");
3360 		if (*action_flags & MLX5_FLOW_ACTION_ENCAP)
3361 			return rte_flow_error_set(error, EINVAL,
3362 						  RTE_FLOW_ERROR_TYPE_ACTION,
3363 						  NULL,
3364 						  "more than one encap action");
3365 		if (!attr->transfer && priv->representor)
3366 			return rte_flow_error_set
3367 					(error, ENOTSUP,
3368 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3369 					 "encap action for VF representor "
3370 					 "not supported on NIC table");
3371 		*action_flags |= MLX5_FLOW_ACTION_ENCAP;
3372 		++(*actions_n);
3373 	}
3374 	return 0;
3375 }
3376 
3377 /**
3378  * Match encap_decap resource.
3379  *
3380  * @param list
3381  *   Pointer to the hash list.
3382  * @param entry
3383  *   Pointer to exist resource entry object.
3384  * @param key
3385  *   Key of the new entry.
3386  * @param ctx_cb
3387  *   Pointer to new encap_decap resource.
3388  *
3389  * @return
3390  *   0 on matching, none-zero otherwise.
3391  */
3392 int
3393 flow_dv_encap_decap_match_cb(struct mlx5_hlist *list __rte_unused,
3394 			     struct mlx5_hlist_entry *entry,
3395 			     uint64_t key __rte_unused, void *cb_ctx)
3396 {
3397 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3398 	struct mlx5_flow_dv_encap_decap_resource *resource = ctx->data;
3399 	struct mlx5_flow_dv_encap_decap_resource *cache_resource;
3400 
3401 	cache_resource = container_of(entry,
3402 				      struct mlx5_flow_dv_encap_decap_resource,
3403 				      entry);
3404 	if (resource->reformat_type == cache_resource->reformat_type &&
3405 	    resource->ft_type == cache_resource->ft_type &&
3406 	    resource->flags == cache_resource->flags &&
3407 	    resource->size == cache_resource->size &&
3408 	    !memcmp((const void *)resource->buf,
3409 		    (const void *)cache_resource->buf,
3410 		    resource->size))
3411 		return 0;
3412 	return -1;
3413 }
3414 
3415 /**
3416  * Allocate encap_decap resource.
3417  *
3418  * @param list
3419  *   Pointer to the hash list.
3420  * @param entry
3421  *   Pointer to exist resource entry object.
3422  * @param ctx_cb
3423  *   Pointer to new encap_decap resource.
3424  *
3425  * @return
3426  *   0 on matching, none-zero otherwise.
3427  */
3428 struct mlx5_hlist_entry *
3429 flow_dv_encap_decap_create_cb(struct mlx5_hlist *list,
3430 			      uint64_t key __rte_unused,
3431 			      void *cb_ctx)
3432 {
3433 	struct mlx5_dev_ctx_shared *sh = list->ctx;
3434 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3435 	struct mlx5dv_dr_domain *domain;
3436 	struct mlx5_flow_dv_encap_decap_resource *resource = ctx->data;
3437 	struct mlx5_flow_dv_encap_decap_resource *cache_resource;
3438 	uint32_t idx;
3439 	int ret;
3440 
3441 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3442 		domain = sh->fdb_domain;
3443 	else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3444 		domain = sh->rx_domain;
3445 	else
3446 		domain = sh->tx_domain;
3447 	/* Register new encap/decap resource. */
3448 	cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
3449 				       &idx);
3450 	if (!cache_resource) {
3451 		rte_flow_error_set(ctx->error, ENOMEM,
3452 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3453 				   "cannot allocate resource memory");
3454 		return NULL;
3455 	}
3456 	*cache_resource = *resource;
3457 	cache_resource->idx = idx;
3458 	ret = mlx5_flow_os_create_flow_action_packet_reformat
3459 					(sh->ctx, domain, cache_resource,
3460 					 &cache_resource->action);
3461 	if (ret) {
3462 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx);
3463 		rte_flow_error_set(ctx->error, ENOMEM,
3464 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3465 				   NULL, "cannot create action");
3466 		return NULL;
3467 	}
3468 
3469 	return &cache_resource->entry;
3470 }
3471 
3472 /**
3473  * Find existing encap/decap resource or create and register a new one.
3474  *
3475  * @param[in, out] dev
3476  *   Pointer to rte_eth_dev structure.
3477  * @param[in, out] resource
3478  *   Pointer to encap/decap resource.
3479  * @parm[in, out] dev_flow
3480  *   Pointer to the dev_flow.
3481  * @param[out] error
3482  *   pointer to error structure.
3483  *
3484  * @return
3485  *   0 on success otherwise -errno and errno is set.
3486  */
3487 static int
3488 flow_dv_encap_decap_resource_register
3489 			(struct rte_eth_dev *dev,
3490 			 struct mlx5_flow_dv_encap_decap_resource *resource,
3491 			 struct mlx5_flow *dev_flow,
3492 			 struct rte_flow_error *error)
3493 {
3494 	struct mlx5_priv *priv = dev->data->dev_private;
3495 	struct mlx5_dev_ctx_shared *sh = priv->sh;
3496 	struct mlx5_hlist_entry *entry;
3497 	union {
3498 		struct {
3499 			uint32_t ft_type:8;
3500 			uint32_t refmt_type:8;
3501 			/*
3502 			 * Header reformat actions can be shared between
3503 			 * non-root tables. One bit to indicate non-root
3504 			 * table or not.
3505 			 */
3506 			uint32_t is_root:1;
3507 			uint32_t reserve:15;
3508 		};
3509 		uint32_t v32;
3510 	} encap_decap_key = {
3511 		{
3512 			.ft_type = resource->ft_type,
3513 			.refmt_type = resource->reformat_type,
3514 			.is_root = !!dev_flow->dv.group,
3515 			.reserve = 0,
3516 		}
3517 	};
3518 	struct mlx5_flow_cb_ctx ctx = {
3519 		.error = error,
3520 		.data = resource,
3521 	};
3522 	uint64_t key64;
3523 
3524 	resource->flags = dev_flow->dv.group ? 0 : 1;
3525 	key64 =  __rte_raw_cksum(&encap_decap_key.v32,
3526 				 sizeof(encap_decap_key.v32), 0);
3527 	if (resource->reformat_type !=
3528 	    MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 &&
3529 	    resource->size)
3530 		key64 = __rte_raw_cksum(resource->buf, resource->size, key64);
3531 	entry = mlx5_hlist_register(sh->encaps_decaps, key64, &ctx);
3532 	if (!entry)
3533 		return -rte_errno;
3534 	resource = container_of(entry, typeof(*resource), entry);
3535 	dev_flow->dv.encap_decap = resource;
3536 	dev_flow->handle->dvh.rix_encap_decap = resource->idx;
3537 	return 0;
3538 }
3539 
3540 /**
3541  * Find existing table jump resource or create and register a new one.
3542  *
3543  * @param[in, out] dev
3544  *   Pointer to rte_eth_dev structure.
3545  * @param[in, out] tbl
3546  *   Pointer to flow table resource.
3547  * @parm[in, out] dev_flow
3548  *   Pointer to the dev_flow.
3549  * @param[out] error
3550  *   pointer to error structure.
3551  *
3552  * @return
3553  *   0 on success otherwise -errno and errno is set.
3554  */
3555 static int
3556 flow_dv_jump_tbl_resource_register
3557 			(struct rte_eth_dev *dev __rte_unused,
3558 			 struct mlx5_flow_tbl_resource *tbl,
3559 			 struct mlx5_flow *dev_flow,
3560 			 struct rte_flow_error *error __rte_unused)
3561 {
3562 	struct mlx5_flow_tbl_data_entry *tbl_data =
3563 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
3564 
3565 	MLX5_ASSERT(tbl);
3566 	MLX5_ASSERT(tbl_data->jump.action);
3567 	dev_flow->handle->rix_jump = tbl_data->idx;
3568 	dev_flow->dv.jump = &tbl_data->jump;
3569 	return 0;
3570 }
3571 
3572 int
3573 flow_dv_port_id_match_cb(struct mlx5_cache_list *list __rte_unused,
3574 			 struct mlx5_cache_entry *entry, void *cb_ctx)
3575 {
3576 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3577 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3578 	struct mlx5_flow_dv_port_id_action_resource *res =
3579 			container_of(entry, typeof(*res), entry);
3580 
3581 	return ref->port_id != res->port_id;
3582 }
3583 
3584 struct mlx5_cache_entry *
3585 flow_dv_port_id_create_cb(struct mlx5_cache_list *list,
3586 			  struct mlx5_cache_entry *entry __rte_unused,
3587 			  void *cb_ctx)
3588 {
3589 	struct mlx5_dev_ctx_shared *sh = list->ctx;
3590 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3591 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3592 	struct mlx5_flow_dv_port_id_action_resource *cache;
3593 	uint32_t idx;
3594 	int ret;
3595 
3596 	/* Register new port id action resource. */
3597 	cache = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3598 	if (!cache) {
3599 		rte_flow_error_set(ctx->error, ENOMEM,
3600 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3601 				   "cannot allocate port_id action cache memory");
3602 		return NULL;
3603 	}
3604 	*cache = *ref;
3605 	ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain,
3606 							ref->port_id,
3607 							&cache->action);
3608 	if (ret) {
3609 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx);
3610 		rte_flow_error_set(ctx->error, ENOMEM,
3611 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3612 				   "cannot create action");
3613 		return NULL;
3614 	}
3615 	return &cache->entry;
3616 }
3617 
3618 /**
3619  * Find existing table port ID resource or create and register a new one.
3620  *
3621  * @param[in, out] dev
3622  *   Pointer to rte_eth_dev structure.
3623  * @param[in, out] resource
3624  *   Pointer to port ID action resource.
3625  * @parm[in, out] dev_flow
3626  *   Pointer to the dev_flow.
3627  * @param[out] error
3628  *   pointer to error structure.
3629  *
3630  * @return
3631  *   0 on success otherwise -errno and errno is set.
3632  */
3633 static int
3634 flow_dv_port_id_action_resource_register
3635 			(struct rte_eth_dev *dev,
3636 			 struct mlx5_flow_dv_port_id_action_resource *resource,
3637 			 struct mlx5_flow *dev_flow,
3638 			 struct rte_flow_error *error)
3639 {
3640 	struct mlx5_priv *priv = dev->data->dev_private;
3641 	struct mlx5_cache_entry *entry;
3642 	struct mlx5_flow_dv_port_id_action_resource *cache;
3643 	struct mlx5_flow_cb_ctx ctx = {
3644 		.error = error,
3645 		.data = resource,
3646 	};
3647 
3648 	entry = mlx5_cache_register(&priv->sh->port_id_action_list, &ctx);
3649 	if (!entry)
3650 		return -rte_errno;
3651 	cache = container_of(entry, typeof(*cache), entry);
3652 	dev_flow->dv.port_id_action = cache;
3653 	dev_flow->handle->rix_port_id_action = cache->idx;
3654 	return 0;
3655 }
3656 
3657 int
3658 flow_dv_push_vlan_match_cb(struct mlx5_cache_list *list __rte_unused,
3659 			 struct mlx5_cache_entry *entry, void *cb_ctx)
3660 {
3661 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3662 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3663 	struct mlx5_flow_dv_push_vlan_action_resource *res =
3664 			container_of(entry, typeof(*res), entry);
3665 
3666 	return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type;
3667 }
3668 
3669 struct mlx5_cache_entry *
3670 flow_dv_push_vlan_create_cb(struct mlx5_cache_list *list,
3671 			  struct mlx5_cache_entry *entry __rte_unused,
3672 			  void *cb_ctx)
3673 {
3674 	struct mlx5_dev_ctx_shared *sh = list->ctx;
3675 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3676 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3677 	struct mlx5_flow_dv_push_vlan_action_resource *cache;
3678 	struct mlx5dv_dr_domain *domain;
3679 	uint32_t idx;
3680 	int ret;
3681 
3682 	/* Register new port id action resource. */
3683 	cache = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
3684 	if (!cache) {
3685 		rte_flow_error_set(ctx->error, ENOMEM,
3686 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3687 				   "cannot allocate push_vlan action cache memory");
3688 		return NULL;
3689 	}
3690 	*cache = *ref;
3691 	if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3692 		domain = sh->fdb_domain;
3693 	else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3694 		domain = sh->rx_domain;
3695 	else
3696 		domain = sh->tx_domain;
3697 	ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag,
3698 							&cache->action);
3699 	if (ret) {
3700 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
3701 		rte_flow_error_set(ctx->error, ENOMEM,
3702 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3703 				   "cannot create push vlan action");
3704 		return NULL;
3705 	}
3706 	return &cache->entry;
3707 }
3708 
3709 /**
3710  * Find existing push vlan resource or create and register a new one.
3711  *
3712  * @param [in, out] dev
3713  *   Pointer to rte_eth_dev structure.
3714  * @param[in, out] resource
3715  *   Pointer to port ID action resource.
3716  * @parm[in, out] dev_flow
3717  *   Pointer to the dev_flow.
3718  * @param[out] error
3719  *   pointer to error structure.
3720  *
3721  * @return
3722  *   0 on success otherwise -errno and errno is set.
3723  */
3724 static int
3725 flow_dv_push_vlan_action_resource_register
3726 		       (struct rte_eth_dev *dev,
3727 			struct mlx5_flow_dv_push_vlan_action_resource *resource,
3728 			struct mlx5_flow *dev_flow,
3729 			struct rte_flow_error *error)
3730 {
3731 	struct mlx5_priv *priv = dev->data->dev_private;
3732 	struct mlx5_flow_dv_push_vlan_action_resource *cache;
3733 	struct mlx5_cache_entry *entry;
3734 	struct mlx5_flow_cb_ctx ctx = {
3735 		.error = error,
3736 		.data = resource,
3737 	};
3738 
3739 	entry = mlx5_cache_register(&priv->sh->push_vlan_action_list, &ctx);
3740 	if (!entry)
3741 		return -rte_errno;
3742 	cache = container_of(entry, typeof(*cache), entry);
3743 
3744 	dev_flow->handle->dvh.rix_push_vlan = cache->idx;
3745 	dev_flow->dv.push_vlan_res = cache;
3746 	return 0;
3747 }
3748 
3749 /**
3750  * Get the size of specific rte_flow_item_type hdr size
3751  *
3752  * @param[in] item_type
3753  *   Tested rte_flow_item_type.
3754  *
3755  * @return
3756  *   sizeof struct item_type, 0 if void or irrelevant.
3757  */
3758 static size_t
3759 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type)
3760 {
3761 	size_t retval;
3762 
3763 	switch (item_type) {
3764 	case RTE_FLOW_ITEM_TYPE_ETH:
3765 		retval = sizeof(struct rte_ether_hdr);
3766 		break;
3767 	case RTE_FLOW_ITEM_TYPE_VLAN:
3768 		retval = sizeof(struct rte_vlan_hdr);
3769 		break;
3770 	case RTE_FLOW_ITEM_TYPE_IPV4:
3771 		retval = sizeof(struct rte_ipv4_hdr);
3772 		break;
3773 	case RTE_FLOW_ITEM_TYPE_IPV6:
3774 		retval = sizeof(struct rte_ipv6_hdr);
3775 		break;
3776 	case RTE_FLOW_ITEM_TYPE_UDP:
3777 		retval = sizeof(struct rte_udp_hdr);
3778 		break;
3779 	case RTE_FLOW_ITEM_TYPE_TCP:
3780 		retval = sizeof(struct rte_tcp_hdr);
3781 		break;
3782 	case RTE_FLOW_ITEM_TYPE_VXLAN:
3783 	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
3784 		retval = sizeof(struct rte_vxlan_hdr);
3785 		break;
3786 	case RTE_FLOW_ITEM_TYPE_GRE:
3787 	case RTE_FLOW_ITEM_TYPE_NVGRE:
3788 		retval = sizeof(struct rte_gre_hdr);
3789 		break;
3790 	case RTE_FLOW_ITEM_TYPE_MPLS:
3791 		retval = sizeof(struct rte_mpls_hdr);
3792 		break;
3793 	case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */
3794 	default:
3795 		retval = 0;
3796 		break;
3797 	}
3798 	return retval;
3799 }
3800 
3801 #define MLX5_ENCAP_IPV4_VERSION		0x40
3802 #define MLX5_ENCAP_IPV4_IHL_MIN		0x05
3803 #define MLX5_ENCAP_IPV4_TTL_DEF		0x40
3804 #define MLX5_ENCAP_IPV6_VTC_FLOW	0x60000000
3805 #define MLX5_ENCAP_IPV6_HOP_LIMIT	0xff
3806 #define MLX5_ENCAP_VXLAN_FLAGS		0x08000000
3807 #define MLX5_ENCAP_VXLAN_GPE_FLAGS	0x04
3808 
3809 /**
3810  * Convert the encap action data from list of rte_flow_item to raw buffer
3811  *
3812  * @param[in] items
3813  *   Pointer to rte_flow_item objects list.
3814  * @param[out] buf
3815  *   Pointer to the output buffer.
3816  * @param[out] size
3817  *   Pointer to the output buffer size.
3818  * @param[out] error
3819  *   Pointer to the error structure.
3820  *
3821  * @return
3822  *   0 on success, a negative errno value otherwise and rte_errno is set.
3823  */
3824 static int
3825 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf,
3826 			   size_t *size, struct rte_flow_error *error)
3827 {
3828 	struct rte_ether_hdr *eth = NULL;
3829 	struct rte_vlan_hdr *vlan = NULL;
3830 	struct rte_ipv4_hdr *ipv4 = NULL;
3831 	struct rte_ipv6_hdr *ipv6 = NULL;
3832 	struct rte_udp_hdr *udp = NULL;
3833 	struct rte_vxlan_hdr *vxlan = NULL;
3834 	struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL;
3835 	struct rte_gre_hdr *gre = NULL;
3836 	size_t len;
3837 	size_t temp_size = 0;
3838 
3839 	if (!items)
3840 		return rte_flow_error_set(error, EINVAL,
3841 					  RTE_FLOW_ERROR_TYPE_ACTION,
3842 					  NULL, "invalid empty data");
3843 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
3844 		len = flow_dv_get_item_hdr_len(items->type);
3845 		if (len + temp_size > MLX5_ENCAP_MAX_LEN)
3846 			return rte_flow_error_set(error, EINVAL,
3847 						  RTE_FLOW_ERROR_TYPE_ACTION,
3848 						  (void *)items->type,
3849 						  "items total size is too big"
3850 						  " for encap action");
3851 		rte_memcpy((void *)&buf[temp_size], items->spec, len);
3852 		switch (items->type) {
3853 		case RTE_FLOW_ITEM_TYPE_ETH:
3854 			eth = (struct rte_ether_hdr *)&buf[temp_size];
3855 			break;
3856 		case RTE_FLOW_ITEM_TYPE_VLAN:
3857 			vlan = (struct rte_vlan_hdr *)&buf[temp_size];
3858 			if (!eth)
3859 				return rte_flow_error_set(error, EINVAL,
3860 						RTE_FLOW_ERROR_TYPE_ACTION,
3861 						(void *)items->type,
3862 						"eth header not found");
3863 			if (!eth->ether_type)
3864 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN);
3865 			break;
3866 		case RTE_FLOW_ITEM_TYPE_IPV4:
3867 			ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size];
3868 			if (!vlan && !eth)
3869 				return rte_flow_error_set(error, EINVAL,
3870 						RTE_FLOW_ERROR_TYPE_ACTION,
3871 						(void *)items->type,
3872 						"neither eth nor vlan"
3873 						" header found");
3874 			if (vlan && !vlan->eth_proto)
3875 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4);
3876 			else if (eth && !eth->ether_type)
3877 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4);
3878 			if (!ipv4->version_ihl)
3879 				ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION |
3880 						    MLX5_ENCAP_IPV4_IHL_MIN;
3881 			if (!ipv4->time_to_live)
3882 				ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF;
3883 			break;
3884 		case RTE_FLOW_ITEM_TYPE_IPV6:
3885 			ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size];
3886 			if (!vlan && !eth)
3887 				return rte_flow_error_set(error, EINVAL,
3888 						RTE_FLOW_ERROR_TYPE_ACTION,
3889 						(void *)items->type,
3890 						"neither eth nor vlan"
3891 						" header found");
3892 			if (vlan && !vlan->eth_proto)
3893 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6);
3894 			else if (eth && !eth->ether_type)
3895 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6);
3896 			if (!ipv6->vtc_flow)
3897 				ipv6->vtc_flow =
3898 					RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW);
3899 			if (!ipv6->hop_limits)
3900 				ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT;
3901 			break;
3902 		case RTE_FLOW_ITEM_TYPE_UDP:
3903 			udp = (struct rte_udp_hdr *)&buf[temp_size];
3904 			if (!ipv4 && !ipv6)
3905 				return rte_flow_error_set(error, EINVAL,
3906 						RTE_FLOW_ERROR_TYPE_ACTION,
3907 						(void *)items->type,
3908 						"ip header not found");
3909 			if (ipv4 && !ipv4->next_proto_id)
3910 				ipv4->next_proto_id = IPPROTO_UDP;
3911 			else if (ipv6 && !ipv6->proto)
3912 				ipv6->proto = IPPROTO_UDP;
3913 			break;
3914 		case RTE_FLOW_ITEM_TYPE_VXLAN:
3915 			vxlan = (struct rte_vxlan_hdr *)&buf[temp_size];
3916 			if (!udp)
3917 				return rte_flow_error_set(error, EINVAL,
3918 						RTE_FLOW_ERROR_TYPE_ACTION,
3919 						(void *)items->type,
3920 						"udp header not found");
3921 			if (!udp->dst_port)
3922 				udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN);
3923 			if (!vxlan->vx_flags)
3924 				vxlan->vx_flags =
3925 					RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS);
3926 			break;
3927 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
3928 			vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size];
3929 			if (!udp)
3930 				return rte_flow_error_set(error, EINVAL,
3931 						RTE_FLOW_ERROR_TYPE_ACTION,
3932 						(void *)items->type,
3933 						"udp header not found");
3934 			if (!vxlan_gpe->proto)
3935 				return rte_flow_error_set(error, EINVAL,
3936 						RTE_FLOW_ERROR_TYPE_ACTION,
3937 						(void *)items->type,
3938 						"next protocol not found");
3939 			if (!udp->dst_port)
3940 				udp->dst_port =
3941 					RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE);
3942 			if (!vxlan_gpe->vx_flags)
3943 				vxlan_gpe->vx_flags =
3944 						MLX5_ENCAP_VXLAN_GPE_FLAGS;
3945 			break;
3946 		case RTE_FLOW_ITEM_TYPE_GRE:
3947 		case RTE_FLOW_ITEM_TYPE_NVGRE:
3948 			gre = (struct rte_gre_hdr *)&buf[temp_size];
3949 			if (!gre->proto)
3950 				return rte_flow_error_set(error, EINVAL,
3951 						RTE_FLOW_ERROR_TYPE_ACTION,
3952 						(void *)items->type,
3953 						"next protocol not found");
3954 			if (!ipv4 && !ipv6)
3955 				return rte_flow_error_set(error, EINVAL,
3956 						RTE_FLOW_ERROR_TYPE_ACTION,
3957 						(void *)items->type,
3958 						"ip header not found");
3959 			if (ipv4 && !ipv4->next_proto_id)
3960 				ipv4->next_proto_id = IPPROTO_GRE;
3961 			else if (ipv6 && !ipv6->proto)
3962 				ipv6->proto = IPPROTO_GRE;
3963 			break;
3964 		case RTE_FLOW_ITEM_TYPE_VOID:
3965 			break;
3966 		default:
3967 			return rte_flow_error_set(error, EINVAL,
3968 						  RTE_FLOW_ERROR_TYPE_ACTION,
3969 						  (void *)items->type,
3970 						  "unsupported item type");
3971 			break;
3972 		}
3973 		temp_size += len;
3974 	}
3975 	*size = temp_size;
3976 	return 0;
3977 }
3978 
3979 static int
3980 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error)
3981 {
3982 	struct rte_ether_hdr *eth = NULL;
3983 	struct rte_vlan_hdr *vlan = NULL;
3984 	struct rte_ipv6_hdr *ipv6 = NULL;
3985 	struct rte_udp_hdr *udp = NULL;
3986 	char *next_hdr;
3987 	uint16_t proto;
3988 
3989 	eth = (struct rte_ether_hdr *)data;
3990 	next_hdr = (char *)(eth + 1);
3991 	proto = RTE_BE16(eth->ether_type);
3992 
3993 	/* VLAN skipping */
3994 	while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) {
3995 		vlan = (struct rte_vlan_hdr *)next_hdr;
3996 		proto = RTE_BE16(vlan->eth_proto);
3997 		next_hdr += sizeof(struct rte_vlan_hdr);
3998 	}
3999 
4000 	/* HW calculates IPv4 csum. no need to proceed */
4001 	if (proto == RTE_ETHER_TYPE_IPV4)
4002 		return 0;
4003 
4004 	/* non IPv4/IPv6 header. not supported */
4005 	if (proto != RTE_ETHER_TYPE_IPV6) {
4006 		return rte_flow_error_set(error, ENOTSUP,
4007 					  RTE_FLOW_ERROR_TYPE_ACTION,
4008 					  NULL, "Cannot offload non IPv4/IPv6");
4009 	}
4010 
4011 	ipv6 = (struct rte_ipv6_hdr *)next_hdr;
4012 
4013 	/* ignore non UDP */
4014 	if (ipv6->proto != IPPROTO_UDP)
4015 		return 0;
4016 
4017 	udp = (struct rte_udp_hdr *)(ipv6 + 1);
4018 	udp->dgram_cksum = 0;
4019 
4020 	return 0;
4021 }
4022 
4023 /**
4024  * Convert L2 encap action to DV specification.
4025  *
4026  * @param[in] dev
4027  *   Pointer to rte_eth_dev structure.
4028  * @param[in] action
4029  *   Pointer to action structure.
4030  * @param[in, out] dev_flow
4031  *   Pointer to the mlx5_flow.
4032  * @param[in] transfer
4033  *   Mark if the flow is E-Switch flow.
4034  * @param[out] error
4035  *   Pointer to the error structure.
4036  *
4037  * @return
4038  *   0 on success, a negative errno value otherwise and rte_errno is set.
4039  */
4040 static int
4041 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev,
4042 			       const struct rte_flow_action *action,
4043 			       struct mlx5_flow *dev_flow,
4044 			       uint8_t transfer,
4045 			       struct rte_flow_error *error)
4046 {
4047 	const struct rte_flow_item *encap_data;
4048 	const struct rte_flow_action_raw_encap *raw_encap_data;
4049 	struct mlx5_flow_dv_encap_decap_resource res = {
4050 		.reformat_type =
4051 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL,
4052 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4053 				      MLX5DV_FLOW_TABLE_TYPE_NIC_TX,
4054 	};
4055 
4056 	if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
4057 		raw_encap_data =
4058 			(const struct rte_flow_action_raw_encap *)action->conf;
4059 		res.size = raw_encap_data->size;
4060 		memcpy(res.buf, raw_encap_data->data, res.size);
4061 	} else {
4062 		if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
4063 			encap_data =
4064 				((const struct rte_flow_action_vxlan_encap *)
4065 						action->conf)->definition;
4066 		else
4067 			encap_data =
4068 				((const struct rte_flow_action_nvgre_encap *)
4069 						action->conf)->definition;
4070 		if (flow_dv_convert_encap_data(encap_data, res.buf,
4071 					       &res.size, error))
4072 			return -rte_errno;
4073 	}
4074 	if (flow_dv_zero_encap_udp_csum(res.buf, error))
4075 		return -rte_errno;
4076 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4077 		return rte_flow_error_set(error, EINVAL,
4078 					  RTE_FLOW_ERROR_TYPE_ACTION,
4079 					  NULL, "can't create L2 encap action");
4080 	return 0;
4081 }
4082 
4083 /**
4084  * Convert L2 decap action to DV specification.
4085  *
4086  * @param[in] dev
4087  *   Pointer to rte_eth_dev structure.
4088  * @param[in, out] dev_flow
4089  *   Pointer to the mlx5_flow.
4090  * @param[in] transfer
4091  *   Mark if the flow is E-Switch flow.
4092  * @param[out] error
4093  *   Pointer to the error structure.
4094  *
4095  * @return
4096  *   0 on success, a negative errno value otherwise and rte_errno is set.
4097  */
4098 static int
4099 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev,
4100 			       struct mlx5_flow *dev_flow,
4101 			       uint8_t transfer,
4102 			       struct rte_flow_error *error)
4103 {
4104 	struct mlx5_flow_dv_encap_decap_resource res = {
4105 		.size = 0,
4106 		.reformat_type =
4107 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2,
4108 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4109 				      MLX5DV_FLOW_TABLE_TYPE_NIC_RX,
4110 	};
4111 
4112 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4113 		return rte_flow_error_set(error, EINVAL,
4114 					  RTE_FLOW_ERROR_TYPE_ACTION,
4115 					  NULL, "can't create L2 decap action");
4116 	return 0;
4117 }
4118 
4119 /**
4120  * Convert raw decap/encap (L3 tunnel) action to DV specification.
4121  *
4122  * @param[in] dev
4123  *   Pointer to rte_eth_dev structure.
4124  * @param[in] action
4125  *   Pointer to action structure.
4126  * @param[in, out] dev_flow
4127  *   Pointer to the mlx5_flow.
4128  * @param[in] attr
4129  *   Pointer to the flow attributes.
4130  * @param[out] error
4131  *   Pointer to the error structure.
4132  *
4133  * @return
4134  *   0 on success, a negative errno value otherwise and rte_errno is set.
4135  */
4136 static int
4137 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
4138 				const struct rte_flow_action *action,
4139 				struct mlx5_flow *dev_flow,
4140 				const struct rte_flow_attr *attr,
4141 				struct rte_flow_error *error)
4142 {
4143 	const struct rte_flow_action_raw_encap *encap_data;
4144 	struct mlx5_flow_dv_encap_decap_resource res;
4145 
4146 	memset(&res, 0, sizeof(res));
4147 	encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
4148 	res.size = encap_data->size;
4149 	memcpy(res.buf, encap_data->data, res.size);
4150 	res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ?
4151 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 :
4152 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
4153 	if (attr->transfer)
4154 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4155 	else
4156 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4157 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4158 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4159 		return rte_flow_error_set(error, EINVAL,
4160 					  RTE_FLOW_ERROR_TYPE_ACTION,
4161 					  NULL, "can't create encap action");
4162 	return 0;
4163 }
4164 
4165 /**
4166  * Create action push VLAN.
4167  *
4168  * @param[in] dev
4169  *   Pointer to rte_eth_dev structure.
4170  * @param[in] attr
4171  *   Pointer to the flow attributes.
4172  * @param[in] vlan
4173  *   Pointer to the vlan to push to the Ethernet header.
4174  * @param[in, out] dev_flow
4175  *   Pointer to the mlx5_flow.
4176  * @param[out] error
4177  *   Pointer to the error structure.
4178  *
4179  * @return
4180  *   0 on success, a negative errno value otherwise and rte_errno is set.
4181  */
4182 static int
4183 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
4184 				const struct rte_flow_attr *attr,
4185 				const struct rte_vlan_hdr *vlan,
4186 				struct mlx5_flow *dev_flow,
4187 				struct rte_flow_error *error)
4188 {
4189 	struct mlx5_flow_dv_push_vlan_action_resource res;
4190 
4191 	memset(&res, 0, sizeof(res));
4192 	res.vlan_tag =
4193 		rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 |
4194 				 vlan->vlan_tci);
4195 	if (attr->transfer)
4196 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4197 	else
4198 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4199 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4200 	return flow_dv_push_vlan_action_resource_register
4201 					    (dev, &res, dev_flow, error);
4202 }
4203 
4204 /**
4205  * Validate the modify-header actions.
4206  *
4207  * @param[in] action_flags
4208  *   Holds the actions detected until now.
4209  * @param[in] action
4210  *   Pointer to the modify action.
4211  * @param[out] error
4212  *   Pointer to error structure.
4213  *
4214  * @return
4215  *   0 on success, a negative errno value otherwise and rte_errno is set.
4216  */
4217 static int
4218 flow_dv_validate_action_modify_hdr(const uint64_t action_flags,
4219 				   const struct rte_flow_action *action,
4220 				   struct rte_flow_error *error)
4221 {
4222 	if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf)
4223 		return rte_flow_error_set(error, EINVAL,
4224 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
4225 					  NULL, "action configuration not set");
4226 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
4227 		return rte_flow_error_set(error, EINVAL,
4228 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4229 					  "can't have encap action before"
4230 					  " modify action");
4231 	return 0;
4232 }
4233 
4234 /**
4235  * Validate the modify-header MAC address actions.
4236  *
4237  * @param[in] action_flags
4238  *   Holds the actions detected until now.
4239  * @param[in] action
4240  *   Pointer to the modify action.
4241  * @param[in] item_flags
4242  *   Holds the items detected.
4243  * @param[out] error
4244  *   Pointer to error structure.
4245  *
4246  * @return
4247  *   0 on success, a negative errno value otherwise and rte_errno is set.
4248  */
4249 static int
4250 flow_dv_validate_action_modify_mac(const uint64_t action_flags,
4251 				   const struct rte_flow_action *action,
4252 				   const uint64_t item_flags,
4253 				   struct rte_flow_error *error)
4254 {
4255 	int ret = 0;
4256 
4257 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4258 	if (!ret) {
4259 		if (!(item_flags & MLX5_FLOW_LAYER_L2))
4260 			return rte_flow_error_set(error, EINVAL,
4261 						  RTE_FLOW_ERROR_TYPE_ACTION,
4262 						  NULL,
4263 						  "no L2 item in pattern");
4264 	}
4265 	return ret;
4266 }
4267 
4268 /**
4269  * Validate the modify-header IPv4 address actions.
4270  *
4271  * @param[in] action_flags
4272  *   Holds the actions detected until now.
4273  * @param[in] action
4274  *   Pointer to the modify action.
4275  * @param[in] item_flags
4276  *   Holds the items detected.
4277  * @param[out] error
4278  *   Pointer to error structure.
4279  *
4280  * @return
4281  *   0 on success, a negative errno value otherwise and rte_errno is set.
4282  */
4283 static int
4284 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags,
4285 				    const struct rte_flow_action *action,
4286 				    const uint64_t item_flags,
4287 				    struct rte_flow_error *error)
4288 {
4289 	int ret = 0;
4290 	uint64_t layer;
4291 
4292 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4293 	if (!ret) {
4294 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4295 				 MLX5_FLOW_LAYER_INNER_L3_IPV4 :
4296 				 MLX5_FLOW_LAYER_OUTER_L3_IPV4;
4297 		if (!(item_flags & layer))
4298 			return rte_flow_error_set(error, EINVAL,
4299 						  RTE_FLOW_ERROR_TYPE_ACTION,
4300 						  NULL,
4301 						  "no ipv4 item in pattern");
4302 	}
4303 	return ret;
4304 }
4305 
4306 /**
4307  * Validate the modify-header IPv6 address actions.
4308  *
4309  * @param[in] action_flags
4310  *   Holds the actions detected until now.
4311  * @param[in] action
4312  *   Pointer to the modify action.
4313  * @param[in] item_flags
4314  *   Holds the items detected.
4315  * @param[out] error
4316  *   Pointer to error structure.
4317  *
4318  * @return
4319  *   0 on success, a negative errno value otherwise and rte_errno is set.
4320  */
4321 static int
4322 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags,
4323 				    const struct rte_flow_action *action,
4324 				    const uint64_t item_flags,
4325 				    struct rte_flow_error *error)
4326 {
4327 	int ret = 0;
4328 	uint64_t layer;
4329 
4330 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4331 	if (!ret) {
4332 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4333 				 MLX5_FLOW_LAYER_INNER_L3_IPV6 :
4334 				 MLX5_FLOW_LAYER_OUTER_L3_IPV6;
4335 		if (!(item_flags & layer))
4336 			return rte_flow_error_set(error, EINVAL,
4337 						  RTE_FLOW_ERROR_TYPE_ACTION,
4338 						  NULL,
4339 						  "no ipv6 item in pattern");
4340 	}
4341 	return ret;
4342 }
4343 
4344 /**
4345  * Validate the modify-header TP actions.
4346  *
4347  * @param[in] action_flags
4348  *   Holds the actions detected until now.
4349  * @param[in] action
4350  *   Pointer to the modify action.
4351  * @param[in] item_flags
4352  *   Holds the items detected.
4353  * @param[out] error
4354  *   Pointer to error structure.
4355  *
4356  * @return
4357  *   0 on success, a negative errno value otherwise and rte_errno is set.
4358  */
4359 static int
4360 flow_dv_validate_action_modify_tp(const uint64_t action_flags,
4361 				  const struct rte_flow_action *action,
4362 				  const uint64_t item_flags,
4363 				  struct rte_flow_error *error)
4364 {
4365 	int ret = 0;
4366 	uint64_t layer;
4367 
4368 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4369 	if (!ret) {
4370 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4371 				 MLX5_FLOW_LAYER_INNER_L4 :
4372 				 MLX5_FLOW_LAYER_OUTER_L4;
4373 		if (!(item_flags & layer))
4374 			return rte_flow_error_set(error, EINVAL,
4375 						  RTE_FLOW_ERROR_TYPE_ACTION,
4376 						  NULL, "no transport layer "
4377 						  "in pattern");
4378 	}
4379 	return ret;
4380 }
4381 
4382 /**
4383  * Validate the modify-header actions of increment/decrement
4384  * TCP Sequence-number.
4385  *
4386  * @param[in] action_flags
4387  *   Holds the actions detected until now.
4388  * @param[in] action
4389  *   Pointer to the modify action.
4390  * @param[in] item_flags
4391  *   Holds the items detected.
4392  * @param[out] error
4393  *   Pointer to error structure.
4394  *
4395  * @return
4396  *   0 on success, a negative errno value otherwise and rte_errno is set.
4397  */
4398 static int
4399 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags,
4400 				       const struct rte_flow_action *action,
4401 				       const uint64_t item_flags,
4402 				       struct rte_flow_error *error)
4403 {
4404 	int ret = 0;
4405 	uint64_t layer;
4406 
4407 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4408 	if (!ret) {
4409 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4410 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4411 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4412 		if (!(item_flags & layer))
4413 			return rte_flow_error_set(error, EINVAL,
4414 						  RTE_FLOW_ERROR_TYPE_ACTION,
4415 						  NULL, "no TCP item in"
4416 						  " pattern");
4417 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ &&
4418 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) ||
4419 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ &&
4420 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ)))
4421 			return rte_flow_error_set(error, EINVAL,
4422 						  RTE_FLOW_ERROR_TYPE_ACTION,
4423 						  NULL,
4424 						  "cannot decrease and increase"
4425 						  " TCP sequence number"
4426 						  " at the same time");
4427 	}
4428 	return ret;
4429 }
4430 
4431 /**
4432  * Validate the modify-header actions of increment/decrement
4433  * TCP Acknowledgment number.
4434  *
4435  * @param[in] action_flags
4436  *   Holds the actions detected until now.
4437  * @param[in] action
4438  *   Pointer to the modify action.
4439  * @param[in] item_flags
4440  *   Holds the items detected.
4441  * @param[out] error
4442  *   Pointer to error structure.
4443  *
4444  * @return
4445  *   0 on success, a negative errno value otherwise and rte_errno is set.
4446  */
4447 static int
4448 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags,
4449 				       const struct rte_flow_action *action,
4450 				       const uint64_t item_flags,
4451 				       struct rte_flow_error *error)
4452 {
4453 	int ret = 0;
4454 	uint64_t layer;
4455 
4456 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4457 	if (!ret) {
4458 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4459 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4460 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4461 		if (!(item_flags & layer))
4462 			return rte_flow_error_set(error, EINVAL,
4463 						  RTE_FLOW_ERROR_TYPE_ACTION,
4464 						  NULL, "no TCP item in"
4465 						  " pattern");
4466 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK &&
4467 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) ||
4468 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK &&
4469 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK)))
4470 			return rte_flow_error_set(error, EINVAL,
4471 						  RTE_FLOW_ERROR_TYPE_ACTION,
4472 						  NULL,
4473 						  "cannot decrease and increase"
4474 						  " TCP acknowledgment number"
4475 						  " at the same time");
4476 	}
4477 	return ret;
4478 }
4479 
4480 /**
4481  * Validate the modify-header TTL actions.
4482  *
4483  * @param[in] action_flags
4484  *   Holds the actions detected until now.
4485  * @param[in] action
4486  *   Pointer to the modify action.
4487  * @param[in] item_flags
4488  *   Holds the items detected.
4489  * @param[out] error
4490  *   Pointer to error structure.
4491  *
4492  * @return
4493  *   0 on success, a negative errno value otherwise and rte_errno is set.
4494  */
4495 static int
4496 flow_dv_validate_action_modify_ttl(const uint64_t action_flags,
4497 				   const struct rte_flow_action *action,
4498 				   const uint64_t item_flags,
4499 				   struct rte_flow_error *error)
4500 {
4501 	int ret = 0;
4502 	uint64_t layer;
4503 
4504 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4505 	if (!ret) {
4506 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4507 				 MLX5_FLOW_LAYER_INNER_L3 :
4508 				 MLX5_FLOW_LAYER_OUTER_L3;
4509 		if (!(item_flags & layer))
4510 			return rte_flow_error_set(error, EINVAL,
4511 						  RTE_FLOW_ERROR_TYPE_ACTION,
4512 						  NULL,
4513 						  "no IP protocol in pattern");
4514 	}
4515 	return ret;
4516 }
4517 
4518 static int
4519 mlx5_flow_item_field_width(enum rte_flow_field_id field)
4520 {
4521 	switch (field) {
4522 	case RTE_FLOW_FIELD_START:
4523 		return 32;
4524 	case RTE_FLOW_FIELD_MAC_DST:
4525 	case RTE_FLOW_FIELD_MAC_SRC:
4526 		return 48;
4527 	case RTE_FLOW_FIELD_VLAN_TYPE:
4528 		return 16;
4529 	case RTE_FLOW_FIELD_VLAN_ID:
4530 		return 12;
4531 	case RTE_FLOW_FIELD_MAC_TYPE:
4532 		return 16;
4533 	case RTE_FLOW_FIELD_IPV4_DSCP:
4534 		return 6;
4535 	case RTE_FLOW_FIELD_IPV4_TTL:
4536 		return 8;
4537 	case RTE_FLOW_FIELD_IPV4_SRC:
4538 	case RTE_FLOW_FIELD_IPV4_DST:
4539 		return 32;
4540 	case RTE_FLOW_FIELD_IPV6_DSCP:
4541 		return 6;
4542 	case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
4543 		return 8;
4544 	case RTE_FLOW_FIELD_IPV6_SRC:
4545 	case RTE_FLOW_FIELD_IPV6_DST:
4546 		return 128;
4547 	case RTE_FLOW_FIELD_TCP_PORT_SRC:
4548 	case RTE_FLOW_FIELD_TCP_PORT_DST:
4549 		return 16;
4550 	case RTE_FLOW_FIELD_TCP_SEQ_NUM:
4551 	case RTE_FLOW_FIELD_TCP_ACK_NUM:
4552 		return 32;
4553 	case RTE_FLOW_FIELD_TCP_FLAGS:
4554 		return 6;
4555 	case RTE_FLOW_FIELD_UDP_PORT_SRC:
4556 	case RTE_FLOW_FIELD_UDP_PORT_DST:
4557 		return 16;
4558 	case RTE_FLOW_FIELD_VXLAN_VNI:
4559 	case RTE_FLOW_FIELD_GENEVE_VNI:
4560 		return 24;
4561 	case RTE_FLOW_FIELD_GTP_TEID:
4562 	case RTE_FLOW_FIELD_TAG:
4563 		return 32;
4564 	case RTE_FLOW_FIELD_MARK:
4565 		return 24;
4566 	case RTE_FLOW_FIELD_META:
4567 	case RTE_FLOW_FIELD_POINTER:
4568 	case RTE_FLOW_FIELD_VALUE:
4569 		return 32;
4570 	default:
4571 		MLX5_ASSERT(false);
4572 	}
4573 	return 0;
4574 }
4575 
4576 /**
4577  * Validate the generic modify field actions.
4578  *
4579  * @param[in] action_flags
4580  *   Holds the actions detected until now.
4581  * @param[in] action
4582  *   Pointer to the modify action.
4583  * @param[in] item_flags
4584  *   Holds the items detected.
4585  * @param[out] error
4586  *   Pointer to error structure.
4587  *
4588  * @return
4589  *   Number of header fields to modify (0 or more) on success,
4590  *   a negative errno value otherwise and rte_errno is set.
4591  */
4592 static int
4593 flow_dv_validate_action_modify_field(const uint64_t action_flags,
4594 				   const struct rte_flow_action *action,
4595 				   struct rte_flow_error *error)
4596 {
4597 	int ret = 0;
4598 	const struct rte_flow_action_modify_field *action_modify_field =
4599 		action->conf;
4600 	uint32_t dst_width =
4601 		mlx5_flow_item_field_width(action_modify_field->dst.field);
4602 	uint32_t src_width =
4603 		mlx5_flow_item_field_width(action_modify_field->src.field);
4604 
4605 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4606 	if (ret)
4607 		return ret;
4608 
4609 	if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE &&
4610 	    action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) {
4611 		if (action_modify_field->dst.offset >= dst_width ||
4612 		    (action_modify_field->dst.offset % 32))
4613 			return rte_flow_error_set(error, EINVAL,
4614 						RTE_FLOW_ERROR_TYPE_ACTION,
4615 						NULL,
4616 						"destination offset is too big"
4617 						" or not aligned to 4 bytes");
4618 		if (action_modify_field->dst.level &&
4619 		    action_modify_field->dst.field != RTE_FLOW_FIELD_TAG)
4620 			return rte_flow_error_set(error, EINVAL,
4621 						RTE_FLOW_ERROR_TYPE_ACTION,
4622 						NULL,
4623 						"cannot modify inner headers");
4624 	}
4625 	if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE &&
4626 	    action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) {
4627 		if (action_modify_field->src.offset >= src_width ||
4628 		    (action_modify_field->src.offset % 32))
4629 			return rte_flow_error_set(error, EINVAL,
4630 						RTE_FLOW_ERROR_TYPE_ACTION,
4631 						NULL,
4632 						"source offset is too big"
4633 						" or not aligned to 4 bytes");
4634 		if (action_modify_field->src.level &&
4635 		    action_modify_field->src.field != RTE_FLOW_FIELD_TAG)
4636 			return rte_flow_error_set(error, EINVAL,
4637 						RTE_FLOW_ERROR_TYPE_ACTION,
4638 						NULL,
4639 						"cannot copy from inner headers");
4640 	}
4641 	if (action_modify_field->width == 0)
4642 		return rte_flow_error_set(error, EINVAL,
4643 						RTE_FLOW_ERROR_TYPE_ACTION,
4644 						NULL,
4645 						"width is required for modify action");
4646 	if (action_modify_field->dst.field ==
4647 	    action_modify_field->src.field)
4648 		return rte_flow_error_set(error, EINVAL,
4649 					RTE_FLOW_ERROR_TYPE_ACTION,
4650 					NULL,
4651 					"source and destination fields"
4652 					" cannot be the same");
4653 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE ||
4654 	    action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER)
4655 		return rte_flow_error_set(error, EINVAL,
4656 					RTE_FLOW_ERROR_TYPE_ACTION,
4657 					NULL,
4658 					"immediate value or a pointer to it"
4659 					" cannot be used as a destination");
4660 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_START ||
4661 	    action_modify_field->src.field == RTE_FLOW_FIELD_START)
4662 		return rte_flow_error_set(error, EINVAL,
4663 				RTE_FLOW_ERROR_TYPE_ACTION,
4664 				NULL,
4665 				"modifications of an arbitrary"
4666 				" place in a packet is not supported");
4667 	if (action_modify_field->operation != RTE_FLOW_MODIFY_SET)
4668 		return rte_flow_error_set(error, EINVAL,
4669 				RTE_FLOW_ERROR_TYPE_ACTION,
4670 				NULL,
4671 				"add and sub operations"
4672 				" are not supported");
4673 	return (action_modify_field->width / 32) +
4674 	       !!(action_modify_field->width % 32);
4675 }
4676 
4677 /**
4678  * Validate jump action.
4679  *
4680  * @param[in] action
4681  *   Pointer to the jump action.
4682  * @param[in] action_flags
4683  *   Holds the actions detected until now.
4684  * @param[in] attributes
4685  *   Pointer to flow attributes
4686  * @param[in] external
4687  *   Action belongs to flow rule created by request external to PMD.
4688  * @param[out] error
4689  *   Pointer to error structure.
4690  *
4691  * @return
4692  *   0 on success, a negative errno value otherwise and rte_errno is set.
4693  */
4694 static int
4695 flow_dv_validate_action_jump(struct rte_eth_dev *dev,
4696 			     const struct mlx5_flow_tunnel *tunnel,
4697 			     const struct rte_flow_action *action,
4698 			     uint64_t action_flags,
4699 			     const struct rte_flow_attr *attributes,
4700 			     bool external, struct rte_flow_error *error)
4701 {
4702 	uint32_t target_group, table;
4703 	int ret = 0;
4704 	struct flow_grp_info grp_info = {
4705 		.external = !!external,
4706 		.transfer = !!attributes->transfer,
4707 		.fdb_def_rule = 1,
4708 		.std_tbl_fix = 0
4709 	};
4710 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
4711 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
4712 		return rte_flow_error_set(error, EINVAL,
4713 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4714 					  "can't have 2 fate actions in"
4715 					  " same flow");
4716 	if (action_flags & MLX5_FLOW_ACTION_METER)
4717 		return rte_flow_error_set(error, ENOTSUP,
4718 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4719 					  "jump with meter not support");
4720 	if (!action->conf)
4721 		return rte_flow_error_set(error, EINVAL,
4722 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
4723 					  NULL, "action configuration not set");
4724 	target_group =
4725 		((const struct rte_flow_action_jump *)action->conf)->group;
4726 	ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table,
4727 				       &grp_info, error);
4728 	if (ret)
4729 		return ret;
4730 	if (attributes->group == target_group &&
4731 	    !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET |
4732 			      MLX5_FLOW_ACTION_TUNNEL_MATCH)))
4733 		return rte_flow_error_set(error, EINVAL,
4734 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4735 					  "target group must be other than"
4736 					  " the current flow group");
4737 	return 0;
4738 }
4739 
4740 /*
4741  * Validate the port_id action.
4742  *
4743  * @param[in] dev
4744  *   Pointer to rte_eth_dev structure.
4745  * @param[in] action_flags
4746  *   Bit-fields that holds the actions detected until now.
4747  * @param[in] action
4748  *   Port_id RTE action structure.
4749  * @param[in] attr
4750  *   Attributes of flow that includes this action.
4751  * @param[out] error
4752  *   Pointer to error structure.
4753  *
4754  * @return
4755  *   0 on success, a negative errno value otherwise and rte_errno is set.
4756  */
4757 static int
4758 flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
4759 				uint64_t action_flags,
4760 				const struct rte_flow_action *action,
4761 				const struct rte_flow_attr *attr,
4762 				struct rte_flow_error *error)
4763 {
4764 	const struct rte_flow_action_port_id *port_id;
4765 	struct mlx5_priv *act_priv;
4766 	struct mlx5_priv *dev_priv;
4767 	uint16_t port;
4768 
4769 	if (!attr->transfer)
4770 		return rte_flow_error_set(error, ENOTSUP,
4771 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4772 					  NULL,
4773 					  "port id action is valid in transfer"
4774 					  " mode only");
4775 	if (!action || !action->conf)
4776 		return rte_flow_error_set(error, ENOTSUP,
4777 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
4778 					  NULL,
4779 					  "port id action parameters must be"
4780 					  " specified");
4781 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
4782 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
4783 		return rte_flow_error_set(error, EINVAL,
4784 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4785 					  "can have only one fate actions in"
4786 					  " a flow");
4787 	dev_priv = mlx5_dev_to_eswitch_info(dev);
4788 	if (!dev_priv)
4789 		return rte_flow_error_set(error, rte_errno,
4790 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4791 					  NULL,
4792 					  "failed to obtain E-Switch info");
4793 	port_id = action->conf;
4794 	port = port_id->original ? dev->data->port_id : port_id->id;
4795 	act_priv = mlx5_port_to_eswitch_info(port, false);
4796 	if (!act_priv)
4797 		return rte_flow_error_set
4798 				(error, rte_errno,
4799 				 RTE_FLOW_ERROR_TYPE_ACTION_CONF, port_id,
4800 				 "failed to obtain E-Switch port id for port");
4801 	if (act_priv->domain_id != dev_priv->domain_id)
4802 		return rte_flow_error_set
4803 				(error, EINVAL,
4804 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4805 				 "port does not belong to"
4806 				 " E-Switch being configured");
4807 	return 0;
4808 }
4809 
4810 /**
4811  * Get the maximum number of modify header actions.
4812  *
4813  * @param dev
4814  *   Pointer to rte_eth_dev structure.
4815  * @param flags
4816  *   Flags bits to check if root level.
4817  *
4818  * @return
4819  *   Max number of modify header actions device can support.
4820  */
4821 static inline unsigned int
4822 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused,
4823 			      uint64_t flags)
4824 {
4825 	/*
4826 	 * There's no way to directly query the max capacity from FW.
4827 	 * The maximal value on root table should be assumed to be supported.
4828 	 */
4829 	if (!(flags & MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL))
4830 		return MLX5_MAX_MODIFY_NUM;
4831 	else
4832 		return MLX5_ROOT_TBL_MODIFY_NUM;
4833 }
4834 
4835 /**
4836  * Validate the meter action.
4837  *
4838  * @param[in] dev
4839  *   Pointer to rte_eth_dev structure.
4840  * @param[in] action_flags
4841  *   Bit-fields that holds the actions detected until now.
4842  * @param[in] action
4843  *   Pointer to the meter action.
4844  * @param[in] attr
4845  *   Attributes of flow that includes this action.
4846  * @param[out] error
4847  *   Pointer to error structure.
4848  *
4849  * @return
4850  *   0 on success, a negative errno value otherwise and rte_ernno is set.
4851  */
4852 static int
4853 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
4854 				uint64_t action_flags,
4855 				const struct rte_flow_action *action,
4856 				const struct rte_flow_attr *attr,
4857 				struct rte_flow_error *error)
4858 {
4859 	struct mlx5_priv *priv = dev->data->dev_private;
4860 	const struct rte_flow_action_meter *am = action->conf;
4861 	struct mlx5_flow_meter *fm;
4862 
4863 	if (!am)
4864 		return rte_flow_error_set(error, EINVAL,
4865 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4866 					  "meter action conf is NULL");
4867 
4868 	if (action_flags & MLX5_FLOW_ACTION_METER)
4869 		return rte_flow_error_set(error, ENOTSUP,
4870 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4871 					  "meter chaining not support");
4872 	if (action_flags & MLX5_FLOW_ACTION_JUMP)
4873 		return rte_flow_error_set(error, ENOTSUP,
4874 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4875 					  "meter with jump not support");
4876 	if (!priv->mtr_en)
4877 		return rte_flow_error_set(error, ENOTSUP,
4878 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4879 					  NULL,
4880 					  "meter action not supported");
4881 	fm = mlx5_flow_meter_find(priv, am->mtr_id);
4882 	if (!fm)
4883 		return rte_flow_error_set(error, EINVAL,
4884 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4885 					  "Meter not found");
4886 	if (fm->ref_cnt && (!(fm->transfer == attr->transfer ||
4887 	      (!fm->ingress && !attr->ingress && attr->egress) ||
4888 	      (!fm->egress && !attr->egress && attr->ingress))))
4889 		return rte_flow_error_set(error, EINVAL,
4890 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4891 					  "Flow attributes are either invalid "
4892 					  "or have a conflict with current "
4893 					  "meter attributes");
4894 	return 0;
4895 }
4896 
4897 /**
4898  * Validate the age action.
4899  *
4900  * @param[in] action_flags
4901  *   Holds the actions detected until now.
4902  * @param[in] action
4903  *   Pointer to the age action.
4904  * @param[in] dev
4905  *   Pointer to the Ethernet device structure.
4906  * @param[out] error
4907  *   Pointer to error structure.
4908  *
4909  * @return
4910  *   0 on success, a negative errno value otherwise and rte_errno is set.
4911  */
4912 static int
4913 flow_dv_validate_action_age(uint64_t action_flags,
4914 			    const struct rte_flow_action *action,
4915 			    struct rte_eth_dev *dev,
4916 			    struct rte_flow_error *error)
4917 {
4918 	struct mlx5_priv *priv = dev->data->dev_private;
4919 	const struct rte_flow_action_age *age = action->conf;
4920 
4921 	if (!priv->config.devx || (priv->sh->cmng.counter_fallback &&
4922 	    !priv->sh->aso_age_mng))
4923 		return rte_flow_error_set(error, ENOTSUP,
4924 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4925 					  NULL,
4926 					  "age action not supported");
4927 	if (!(action->conf))
4928 		return rte_flow_error_set(error, EINVAL,
4929 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
4930 					  "configuration cannot be null");
4931 	if (!(age->timeout))
4932 		return rte_flow_error_set(error, EINVAL,
4933 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
4934 					  "invalid timeout value 0");
4935 	if (action_flags & MLX5_FLOW_ACTION_AGE)
4936 		return rte_flow_error_set(error, EINVAL,
4937 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4938 					  "duplicate age actions set");
4939 	return 0;
4940 }
4941 
4942 /**
4943  * Validate the modify-header IPv4 DSCP actions.
4944  *
4945  * @param[in] action_flags
4946  *   Holds the actions detected until now.
4947  * @param[in] action
4948  *   Pointer to the modify action.
4949  * @param[in] item_flags
4950  *   Holds the items detected.
4951  * @param[out] error
4952  *   Pointer to error structure.
4953  *
4954  * @return
4955  *   0 on success, a negative errno value otherwise and rte_errno is set.
4956  */
4957 static int
4958 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags,
4959 					 const struct rte_flow_action *action,
4960 					 const uint64_t item_flags,
4961 					 struct rte_flow_error *error)
4962 {
4963 	int ret = 0;
4964 
4965 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4966 	if (!ret) {
4967 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4))
4968 			return rte_flow_error_set(error, EINVAL,
4969 						  RTE_FLOW_ERROR_TYPE_ACTION,
4970 						  NULL,
4971 						  "no ipv4 item in pattern");
4972 	}
4973 	return ret;
4974 }
4975 
4976 /**
4977  * Validate the modify-header IPv6 DSCP actions.
4978  *
4979  * @param[in] action_flags
4980  *   Holds the actions detected until now.
4981  * @param[in] action
4982  *   Pointer to the modify action.
4983  * @param[in] item_flags
4984  *   Holds the items detected.
4985  * @param[out] error
4986  *   Pointer to error structure.
4987  *
4988  * @return
4989  *   0 on success, a negative errno value otherwise and rte_errno is set.
4990  */
4991 static int
4992 flow_dv_validate_action_modify_ipv6_dscp(const uint64_t action_flags,
4993 					 const struct rte_flow_action *action,
4994 					 const uint64_t item_flags,
4995 					 struct rte_flow_error *error)
4996 {
4997 	int ret = 0;
4998 
4999 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5000 	if (!ret) {
5001 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6))
5002 			return rte_flow_error_set(error, EINVAL,
5003 						  RTE_FLOW_ERROR_TYPE_ACTION,
5004 						  NULL,
5005 						  "no ipv6 item in pattern");
5006 	}
5007 	return ret;
5008 }
5009 
5010 /**
5011  * Match modify-header resource.
5012  *
5013  * @param list
5014  *   Pointer to the hash list.
5015  * @param entry
5016  *   Pointer to exist resource entry object.
5017  * @param key
5018  *   Key of the new entry.
5019  * @param ctx
5020  *   Pointer to new modify-header resource.
5021  *
5022  * @return
5023  *   0 on matching, non-zero otherwise.
5024  */
5025 int
5026 flow_dv_modify_match_cb(struct mlx5_hlist *list __rte_unused,
5027 			struct mlx5_hlist_entry *entry,
5028 			uint64_t key __rte_unused, void *cb_ctx)
5029 {
5030 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5031 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5032 	struct mlx5_flow_dv_modify_hdr_resource *resource =
5033 			container_of(entry, typeof(*resource), entry);
5034 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5035 
5036 	key_len += ref->actions_num * sizeof(ref->actions[0]);
5037 	return ref->actions_num != resource->actions_num ||
5038 	       memcmp(&ref->ft_type, &resource->ft_type, key_len);
5039 }
5040 
5041 struct mlx5_hlist_entry *
5042 flow_dv_modify_create_cb(struct mlx5_hlist *list, uint64_t key __rte_unused,
5043 			 void *cb_ctx)
5044 {
5045 	struct mlx5_dev_ctx_shared *sh = list->ctx;
5046 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5047 	struct mlx5dv_dr_domain *ns;
5048 	struct mlx5_flow_dv_modify_hdr_resource *entry;
5049 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5050 	int ret;
5051 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5052 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5053 
5054 	entry = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*entry) + data_len, 0,
5055 			    SOCKET_ID_ANY);
5056 	if (!entry) {
5057 		rte_flow_error_set(ctx->error, ENOMEM,
5058 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5059 				   "cannot allocate resource memory");
5060 		return NULL;
5061 	}
5062 	rte_memcpy(&entry->ft_type,
5063 		   RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)),
5064 		   key_len + data_len);
5065 	if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
5066 		ns = sh->fdb_domain;
5067 	else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
5068 		ns = sh->tx_domain;
5069 	else
5070 		ns = sh->rx_domain;
5071 	ret = mlx5_flow_os_create_flow_action_modify_header
5072 					(sh->ctx, ns, entry,
5073 					 data_len, &entry->action);
5074 	if (ret) {
5075 		mlx5_free(entry);
5076 		rte_flow_error_set(ctx->error, ENOMEM,
5077 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5078 				   NULL, "cannot create modification action");
5079 		return NULL;
5080 	}
5081 	return &entry->entry;
5082 }
5083 
5084 /**
5085  * Validate the sample action.
5086  *
5087  * @param[in, out] action_flags
5088  *   Holds the actions detected until now.
5089  * @param[in] action
5090  *   Pointer to the sample action.
5091  * @param[in] dev
5092  *   Pointer to the Ethernet device structure.
5093  * @param[in] attr
5094  *   Attributes of flow that includes this action.
5095  * @param[in] item_flags
5096  *   Holds the items detected.
5097  * @param[in] rss
5098  *   Pointer to the RSS action.
5099  * @param[out] sample_rss
5100  *   Pointer to the RSS action in sample action list.
5101  * @param[out] count
5102  *   Pointer to the COUNT action in sample action list.
5103  * @param[out] fdb_mirror_limit
5104  *   Pointer to the FDB mirror limitation flag.
5105  * @param[out] error
5106  *   Pointer to error structure.
5107  *
5108  * @return
5109  *   0 on success, a negative errno value otherwise and rte_errno is set.
5110  */
5111 static int
5112 flow_dv_validate_action_sample(uint64_t *action_flags,
5113 			       const struct rte_flow_action *action,
5114 			       struct rte_eth_dev *dev,
5115 			       const struct rte_flow_attr *attr,
5116 			       uint64_t item_flags,
5117 			       const struct rte_flow_action_rss *rss,
5118 			       const struct rte_flow_action_rss **sample_rss,
5119 			       const struct rte_flow_action_count **count,
5120 			       int *fdb_mirror_limit,
5121 			       struct rte_flow_error *error)
5122 {
5123 	struct mlx5_priv *priv = dev->data->dev_private;
5124 	struct mlx5_dev_config *dev_conf = &priv->config;
5125 	const struct rte_flow_action_sample *sample = action->conf;
5126 	const struct rte_flow_action *act;
5127 	uint64_t sub_action_flags = 0;
5128 	uint16_t queue_index = 0xFFFF;
5129 	int actions_n = 0;
5130 	int ret;
5131 
5132 	if (!sample)
5133 		return rte_flow_error_set(error, EINVAL,
5134 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5135 					  "configuration cannot be NULL");
5136 	if (sample->ratio == 0)
5137 		return rte_flow_error_set(error, EINVAL,
5138 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5139 					  "ratio value starts from 1");
5140 	if (!priv->config.devx || (sample->ratio > 0 && !priv->sampler_en))
5141 		return rte_flow_error_set(error, ENOTSUP,
5142 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5143 					  NULL,
5144 					  "sample action not supported");
5145 	if (*action_flags & MLX5_FLOW_ACTION_SAMPLE)
5146 		return rte_flow_error_set(error, EINVAL,
5147 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5148 					  "Multiple sample actions not "
5149 					  "supported");
5150 	if (*action_flags & MLX5_FLOW_ACTION_METER)
5151 		return rte_flow_error_set(error, EINVAL,
5152 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5153 					  "wrong action order, meter should "
5154 					  "be after sample action");
5155 	if (*action_flags & MLX5_FLOW_ACTION_JUMP)
5156 		return rte_flow_error_set(error, EINVAL,
5157 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5158 					  "wrong action order, jump should "
5159 					  "be after sample action");
5160 	act = sample->actions;
5161 	for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
5162 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
5163 			return rte_flow_error_set(error, ENOTSUP,
5164 						  RTE_FLOW_ERROR_TYPE_ACTION,
5165 						  act, "too many actions");
5166 		switch (act->type) {
5167 		case RTE_FLOW_ACTION_TYPE_QUEUE:
5168 			ret = mlx5_flow_validate_action_queue(act,
5169 							      sub_action_flags,
5170 							      dev,
5171 							      attr, error);
5172 			if (ret < 0)
5173 				return ret;
5174 			queue_index = ((const struct rte_flow_action_queue *)
5175 							(act->conf))->index;
5176 			sub_action_flags |= MLX5_FLOW_ACTION_QUEUE;
5177 			++actions_n;
5178 			break;
5179 		case RTE_FLOW_ACTION_TYPE_RSS:
5180 			*sample_rss = act->conf;
5181 			ret = mlx5_flow_validate_action_rss(act,
5182 							    sub_action_flags,
5183 							    dev, attr,
5184 							    item_flags,
5185 							    error);
5186 			if (ret < 0)
5187 				return ret;
5188 			if (rss && *sample_rss &&
5189 			    ((*sample_rss)->level != rss->level ||
5190 			    (*sample_rss)->types != rss->types))
5191 				return rte_flow_error_set(error, ENOTSUP,
5192 					RTE_FLOW_ERROR_TYPE_ACTION,
5193 					NULL,
5194 					"Can't use the different RSS types "
5195 					"or level in the same flow");
5196 			if (*sample_rss != NULL && (*sample_rss)->queue_num)
5197 				queue_index = (*sample_rss)->queue[0];
5198 			sub_action_flags |= MLX5_FLOW_ACTION_RSS;
5199 			++actions_n;
5200 			break;
5201 		case RTE_FLOW_ACTION_TYPE_MARK:
5202 			ret = flow_dv_validate_action_mark(dev, act,
5203 							   sub_action_flags,
5204 							   attr, error);
5205 			if (ret < 0)
5206 				return ret;
5207 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)
5208 				sub_action_flags |= MLX5_FLOW_ACTION_MARK |
5209 						MLX5_FLOW_ACTION_MARK_EXT;
5210 			else
5211 				sub_action_flags |= MLX5_FLOW_ACTION_MARK;
5212 			++actions_n;
5213 			break;
5214 		case RTE_FLOW_ACTION_TYPE_COUNT:
5215 			ret = flow_dv_validate_action_count
5216 				(dev, act,
5217 				 *action_flags | sub_action_flags,
5218 				 error);
5219 			if (ret < 0)
5220 				return ret;
5221 			*count = act->conf;
5222 			sub_action_flags |= MLX5_FLOW_ACTION_COUNT;
5223 			*action_flags |= MLX5_FLOW_ACTION_COUNT;
5224 			++actions_n;
5225 			break;
5226 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
5227 			ret = flow_dv_validate_action_port_id(dev,
5228 							      sub_action_flags,
5229 							      act,
5230 							      attr,
5231 							      error);
5232 			if (ret)
5233 				return ret;
5234 			sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID;
5235 			++actions_n;
5236 			break;
5237 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
5238 			ret = flow_dv_validate_action_raw_encap_decap
5239 				(dev, NULL, act->conf, attr, &sub_action_flags,
5240 				 &actions_n, action, item_flags, error);
5241 			if (ret < 0)
5242 				return ret;
5243 			++actions_n;
5244 			break;
5245 		default:
5246 			return rte_flow_error_set(error, ENOTSUP,
5247 						  RTE_FLOW_ERROR_TYPE_ACTION,
5248 						  NULL,
5249 						  "Doesn't support optional "
5250 						  "action");
5251 		}
5252 	}
5253 	if (attr->ingress && !attr->transfer) {
5254 		if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE |
5255 					  MLX5_FLOW_ACTION_RSS)))
5256 			return rte_flow_error_set(error, EINVAL,
5257 						  RTE_FLOW_ERROR_TYPE_ACTION,
5258 						  NULL,
5259 						  "Ingress must has a dest "
5260 						  "QUEUE for Sample");
5261 	} else if (attr->egress && !attr->transfer) {
5262 		return rte_flow_error_set(error, ENOTSUP,
5263 					  RTE_FLOW_ERROR_TYPE_ACTION,
5264 					  NULL,
5265 					  "Sample Only support Ingress "
5266 					  "or E-Switch");
5267 	} else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) {
5268 		MLX5_ASSERT(attr->transfer);
5269 		if (sample->ratio > 1)
5270 			return rte_flow_error_set(error, ENOTSUP,
5271 						  RTE_FLOW_ERROR_TYPE_ACTION,
5272 						  NULL,
5273 						  "E-Switch doesn't support "
5274 						  "any optional action "
5275 						  "for sampling");
5276 		if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE)
5277 			return rte_flow_error_set(error, ENOTSUP,
5278 						  RTE_FLOW_ERROR_TYPE_ACTION,
5279 						  NULL,
5280 						  "unsupported action QUEUE");
5281 		if (sub_action_flags & MLX5_FLOW_ACTION_RSS)
5282 			return rte_flow_error_set(error, ENOTSUP,
5283 						  RTE_FLOW_ERROR_TYPE_ACTION,
5284 						  NULL,
5285 						  "unsupported action QUEUE");
5286 		if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID))
5287 			return rte_flow_error_set(error, EINVAL,
5288 						  RTE_FLOW_ERROR_TYPE_ACTION,
5289 						  NULL,
5290 						  "E-Switch must has a dest "
5291 						  "port for mirroring");
5292 		if (!priv->config.hca_attr.reg_c_preserve &&
5293 		     priv->representor_id != -1)
5294 			*fdb_mirror_limit = 1;
5295 	}
5296 	/* Continue validation for Xcap actions.*/
5297 	if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) &&
5298 	    (queue_index == 0xFFFF ||
5299 	     mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) {
5300 		if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
5301 		     MLX5_FLOW_XCAP_ACTIONS)
5302 			return rte_flow_error_set(error, ENOTSUP,
5303 						  RTE_FLOW_ERROR_TYPE_ACTION,
5304 						  NULL, "encap and decap "
5305 						  "combination aren't "
5306 						  "supported");
5307 		if (!attr->transfer && attr->ingress && (sub_action_flags &
5308 							MLX5_FLOW_ACTION_ENCAP))
5309 			return rte_flow_error_set(error, ENOTSUP,
5310 						  RTE_FLOW_ERROR_TYPE_ACTION,
5311 						  NULL, "encap is not supported"
5312 						  " for ingress traffic");
5313 	}
5314 	return 0;
5315 }
5316 
5317 /**
5318  * Find existing modify-header resource or create and register a new one.
5319  *
5320  * @param dev[in, out]
5321  *   Pointer to rte_eth_dev structure.
5322  * @param[in, out] resource
5323  *   Pointer to modify-header resource.
5324  * @parm[in, out] dev_flow
5325  *   Pointer to the dev_flow.
5326  * @param[out] error
5327  *   pointer to error structure.
5328  *
5329  * @return
5330  *   0 on success otherwise -errno and errno is set.
5331  */
5332 static int
5333 flow_dv_modify_hdr_resource_register
5334 			(struct rte_eth_dev *dev,
5335 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
5336 			 struct mlx5_flow *dev_flow,
5337 			 struct rte_flow_error *error)
5338 {
5339 	struct mlx5_priv *priv = dev->data->dev_private;
5340 	struct mlx5_dev_ctx_shared *sh = priv->sh;
5341 	uint32_t key_len = sizeof(*resource) -
5342 			   offsetof(typeof(*resource), ft_type) +
5343 			   resource->actions_num * sizeof(resource->actions[0]);
5344 	struct mlx5_hlist_entry *entry;
5345 	struct mlx5_flow_cb_ctx ctx = {
5346 		.error = error,
5347 		.data = resource,
5348 	};
5349 	uint64_t key64;
5350 
5351 	resource->flags = dev_flow->dv.group ? 0 :
5352 			  MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
5353 	if (resource->actions_num > flow_dv_modify_hdr_action_max(dev,
5354 				    resource->flags))
5355 		return rte_flow_error_set(error, EOVERFLOW,
5356 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5357 					  "too many modify header items");
5358 	key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0);
5359 	entry = mlx5_hlist_register(sh->modify_cmds, key64, &ctx);
5360 	if (!entry)
5361 		return -rte_errno;
5362 	resource = container_of(entry, typeof(*resource), entry);
5363 	dev_flow->handle->dvh.modify_hdr = resource;
5364 	return 0;
5365 }
5366 
5367 /**
5368  * Get DV flow counter by index.
5369  *
5370  * @param[in] dev
5371  *   Pointer to the Ethernet device structure.
5372  * @param[in] idx
5373  *   mlx5 flow counter index in the container.
5374  * @param[out] ppool
5375  *   mlx5 flow counter pool in the container,
5376  *
5377  * @return
5378  *   Pointer to the counter, NULL otherwise.
5379  */
5380 static struct mlx5_flow_counter *
5381 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev,
5382 			   uint32_t idx,
5383 			   struct mlx5_flow_counter_pool **ppool)
5384 {
5385 	struct mlx5_priv *priv = dev->data->dev_private;
5386 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5387 	struct mlx5_flow_counter_pool *pool;
5388 
5389 	/* Decrease to original index and clear shared bit. */
5390 	idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
5391 	MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < cmng->n);
5392 	pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
5393 	MLX5_ASSERT(pool);
5394 	if (ppool)
5395 		*ppool = pool;
5396 	return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
5397 }
5398 
5399 /**
5400  * Check the devx counter belongs to the pool.
5401  *
5402  * @param[in] pool
5403  *   Pointer to the counter pool.
5404  * @param[in] id
5405  *   The counter devx ID.
5406  *
5407  * @return
5408  *   True if counter belongs to the pool, false otherwise.
5409  */
5410 static bool
5411 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id)
5412 {
5413 	int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) *
5414 		   MLX5_COUNTERS_PER_POOL;
5415 
5416 	if (id >= base && id < base + MLX5_COUNTERS_PER_POOL)
5417 		return true;
5418 	return false;
5419 }
5420 
5421 /**
5422  * Get a pool by devx counter ID.
5423  *
5424  * @param[in] cmng
5425  *   Pointer to the counter management.
5426  * @param[in] id
5427  *   The counter devx ID.
5428  *
5429  * @return
5430  *   The counter pool pointer if exists, NULL otherwise,
5431  */
5432 static struct mlx5_flow_counter_pool *
5433 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id)
5434 {
5435 	uint32_t i;
5436 	struct mlx5_flow_counter_pool *pool = NULL;
5437 
5438 	rte_spinlock_lock(&cmng->pool_update_sl);
5439 	/* Check last used pool. */
5440 	if (cmng->last_pool_idx != POOL_IDX_INVALID &&
5441 	    flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) {
5442 		pool = cmng->pools[cmng->last_pool_idx];
5443 		goto out;
5444 	}
5445 	/* ID out of range means no suitable pool in the container. */
5446 	if (id > cmng->max_id || id < cmng->min_id)
5447 		goto out;
5448 	/*
5449 	 * Find the pool from the end of the container, since mostly counter
5450 	 * ID is sequence increasing, and the last pool should be the needed
5451 	 * one.
5452 	 */
5453 	i = cmng->n_valid;
5454 	while (i--) {
5455 		struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i];
5456 
5457 		if (flow_dv_is_counter_in_pool(pool_tmp, id)) {
5458 			pool = pool_tmp;
5459 			break;
5460 		}
5461 	}
5462 out:
5463 	rte_spinlock_unlock(&cmng->pool_update_sl);
5464 	return pool;
5465 }
5466 
5467 /**
5468  * Resize a counter container.
5469  *
5470  * @param[in] dev
5471  *   Pointer to the Ethernet device structure.
5472  *
5473  * @return
5474  *   0 on success, otherwise negative errno value and rte_errno is set.
5475  */
5476 static int
5477 flow_dv_container_resize(struct rte_eth_dev *dev)
5478 {
5479 	struct mlx5_priv *priv = dev->data->dev_private;
5480 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5481 	void *old_pools = cmng->pools;
5482 	uint32_t resize = cmng->n + MLX5_CNT_CONTAINER_RESIZE;
5483 	uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize;
5484 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
5485 
5486 	if (!pools) {
5487 		rte_errno = ENOMEM;
5488 		return -ENOMEM;
5489 	}
5490 	if (old_pools)
5491 		memcpy(pools, old_pools, cmng->n *
5492 				       sizeof(struct mlx5_flow_counter_pool *));
5493 	cmng->n = resize;
5494 	cmng->pools = pools;
5495 	if (old_pools)
5496 		mlx5_free(old_pools);
5497 	return 0;
5498 }
5499 
5500 /**
5501  * Query a devx flow counter.
5502  *
5503  * @param[in] dev
5504  *   Pointer to the Ethernet device structure.
5505  * @param[in] cnt
5506  *   Index to the flow counter.
5507  * @param[out] pkts
5508  *   The statistics value of packets.
5509  * @param[out] bytes
5510  *   The statistics value of bytes.
5511  *
5512  * @return
5513  *   0 on success, otherwise a negative errno value and rte_errno is set.
5514  */
5515 static inline int
5516 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts,
5517 		     uint64_t *bytes)
5518 {
5519 	struct mlx5_priv *priv = dev->data->dev_private;
5520 	struct mlx5_flow_counter_pool *pool = NULL;
5521 	struct mlx5_flow_counter *cnt;
5522 	int offset;
5523 
5524 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
5525 	MLX5_ASSERT(pool);
5526 	if (priv->sh->cmng.counter_fallback)
5527 		return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0,
5528 					0, pkts, bytes, 0, NULL, NULL, 0);
5529 	rte_spinlock_lock(&pool->sl);
5530 	if (!pool->raw) {
5531 		*pkts = 0;
5532 		*bytes = 0;
5533 	} else {
5534 		offset = MLX5_CNT_ARRAY_IDX(pool, cnt);
5535 		*pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits);
5536 		*bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes);
5537 	}
5538 	rte_spinlock_unlock(&pool->sl);
5539 	return 0;
5540 }
5541 
5542 /**
5543  * Create and initialize a new counter pool.
5544  *
5545  * @param[in] dev
5546  *   Pointer to the Ethernet device structure.
5547  * @param[out] dcs
5548  *   The devX counter handle.
5549  * @param[in] age
5550  *   Whether the pool is for counter that was allocated for aging.
5551  * @param[in/out] cont_cur
5552  *   Pointer to the container pointer, it will be update in pool resize.
5553  *
5554  * @return
5555  *   The pool container pointer on success, NULL otherwise and rte_errno is set.
5556  */
5557 static struct mlx5_flow_counter_pool *
5558 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
5559 		    uint32_t age)
5560 {
5561 	struct mlx5_priv *priv = dev->data->dev_private;
5562 	struct mlx5_flow_counter_pool *pool;
5563 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5564 	bool fallback = priv->sh->cmng.counter_fallback;
5565 	uint32_t size = sizeof(*pool);
5566 
5567 	size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE;
5568 	size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE);
5569 	pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
5570 	if (!pool) {
5571 		rte_errno = ENOMEM;
5572 		return NULL;
5573 	}
5574 	pool->raw = NULL;
5575 	pool->is_aged = !!age;
5576 	pool->query_gen = 0;
5577 	pool->min_dcs = dcs;
5578 	rte_spinlock_init(&pool->sl);
5579 	rte_spinlock_init(&pool->csl);
5580 	TAILQ_INIT(&pool->counters[0]);
5581 	TAILQ_INIT(&pool->counters[1]);
5582 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
5583 	rte_spinlock_lock(&cmng->pool_update_sl);
5584 	pool->index = cmng->n_valid;
5585 	if (pool->index == cmng->n && flow_dv_container_resize(dev)) {
5586 		mlx5_free(pool);
5587 		rte_spinlock_unlock(&cmng->pool_update_sl);
5588 		return NULL;
5589 	}
5590 	cmng->pools[pool->index] = pool;
5591 	cmng->n_valid++;
5592 	if (unlikely(fallback)) {
5593 		int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL);
5594 
5595 		if (base < cmng->min_id)
5596 			cmng->min_id = base;
5597 		if (base > cmng->max_id)
5598 			cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1;
5599 		cmng->last_pool_idx = pool->index;
5600 	}
5601 	rte_spinlock_unlock(&cmng->pool_update_sl);
5602 	return pool;
5603 }
5604 
5605 /**
5606  * Prepare a new counter and/or a new counter pool.
5607  *
5608  * @param[in] dev
5609  *   Pointer to the Ethernet device structure.
5610  * @param[out] cnt_free
5611  *   Where to put the pointer of a new counter.
5612  * @param[in] age
5613  *   Whether the pool is for counter that was allocated for aging.
5614  *
5615  * @return
5616  *   The counter pool pointer and @p cnt_free is set on success,
5617  *   NULL otherwise and rte_errno is set.
5618  */
5619 static struct mlx5_flow_counter_pool *
5620 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev,
5621 			     struct mlx5_flow_counter **cnt_free,
5622 			     uint32_t age)
5623 {
5624 	struct mlx5_priv *priv = dev->data->dev_private;
5625 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5626 	struct mlx5_flow_counter_pool *pool;
5627 	struct mlx5_counters tmp_tq;
5628 	struct mlx5_devx_obj *dcs = NULL;
5629 	struct mlx5_flow_counter *cnt;
5630 	enum mlx5_counter_type cnt_type =
5631 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
5632 	bool fallback = priv->sh->cmng.counter_fallback;
5633 	uint32_t i;
5634 
5635 	if (fallback) {
5636 		/* bulk_bitmap must be 0 for single counter allocation. */
5637 		dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
5638 		if (!dcs)
5639 			return NULL;
5640 		pool = flow_dv_find_pool_by_id(cmng, dcs->id);
5641 		if (!pool) {
5642 			pool = flow_dv_pool_create(dev, dcs, age);
5643 			if (!pool) {
5644 				mlx5_devx_cmd_destroy(dcs);
5645 				return NULL;
5646 			}
5647 		}
5648 		i = dcs->id % MLX5_COUNTERS_PER_POOL;
5649 		cnt = MLX5_POOL_GET_CNT(pool, i);
5650 		cnt->pool = pool;
5651 		cnt->dcs_when_free = dcs;
5652 		*cnt_free = cnt;
5653 		return pool;
5654 	}
5655 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4);
5656 	if (!dcs) {
5657 		rte_errno = ENODATA;
5658 		return NULL;
5659 	}
5660 	pool = flow_dv_pool_create(dev, dcs, age);
5661 	if (!pool) {
5662 		mlx5_devx_cmd_destroy(dcs);
5663 		return NULL;
5664 	}
5665 	TAILQ_INIT(&tmp_tq);
5666 	for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) {
5667 		cnt = MLX5_POOL_GET_CNT(pool, i);
5668 		cnt->pool = pool;
5669 		TAILQ_INSERT_HEAD(&tmp_tq, cnt, next);
5670 	}
5671 	rte_spinlock_lock(&cmng->csl[cnt_type]);
5672 	TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next);
5673 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
5674 	*cnt_free = MLX5_POOL_GET_CNT(pool, 0);
5675 	(*cnt_free)->pool = pool;
5676 	return pool;
5677 }
5678 
5679 /**
5680  * Allocate a flow counter.
5681  *
5682  * @param[in] dev
5683  *   Pointer to the Ethernet device structure.
5684  * @param[in] age
5685  *   Whether the counter was allocated for aging.
5686  *
5687  * @return
5688  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
5689  */
5690 static uint32_t
5691 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age)
5692 {
5693 	struct mlx5_priv *priv = dev->data->dev_private;
5694 	struct mlx5_flow_counter_pool *pool = NULL;
5695 	struct mlx5_flow_counter *cnt_free = NULL;
5696 	bool fallback = priv->sh->cmng.counter_fallback;
5697 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5698 	enum mlx5_counter_type cnt_type =
5699 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
5700 	uint32_t cnt_idx;
5701 
5702 	if (!priv->config.devx) {
5703 		rte_errno = ENOTSUP;
5704 		return 0;
5705 	}
5706 	/* Get free counters from container. */
5707 	rte_spinlock_lock(&cmng->csl[cnt_type]);
5708 	cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]);
5709 	if (cnt_free)
5710 		TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next);
5711 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
5712 	if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age))
5713 		goto err;
5714 	pool = cnt_free->pool;
5715 	if (fallback)
5716 		cnt_free->dcs_when_active = cnt_free->dcs_when_free;
5717 	/* Create a DV counter action only in the first time usage. */
5718 	if (!cnt_free->action) {
5719 		uint16_t offset;
5720 		struct mlx5_devx_obj *dcs;
5721 		int ret;
5722 
5723 		if (!fallback) {
5724 			offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free);
5725 			dcs = pool->min_dcs;
5726 		} else {
5727 			offset = 0;
5728 			dcs = cnt_free->dcs_when_free;
5729 		}
5730 		ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset,
5731 							    &cnt_free->action);
5732 		if (ret) {
5733 			rte_errno = errno;
5734 			goto err;
5735 		}
5736 	}
5737 	cnt_idx = MLX5_MAKE_CNT_IDX(pool->index,
5738 				MLX5_CNT_ARRAY_IDX(pool, cnt_free));
5739 	/* Update the counter reset values. */
5740 	if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits,
5741 				 &cnt_free->bytes))
5742 		goto err;
5743 	if (!fallback && !priv->sh->cmng.query_thread_on)
5744 		/* Start the asynchronous batch query by the host thread. */
5745 		mlx5_set_query_alarm(priv->sh);
5746 	return cnt_idx;
5747 err:
5748 	if (cnt_free) {
5749 		cnt_free->pool = pool;
5750 		if (fallback)
5751 			cnt_free->dcs_when_free = cnt_free->dcs_when_active;
5752 		rte_spinlock_lock(&cmng->csl[cnt_type]);
5753 		TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next);
5754 		rte_spinlock_unlock(&cmng->csl[cnt_type]);
5755 	}
5756 	return 0;
5757 }
5758 
5759 /**
5760  * Allocate a shared flow counter.
5761  *
5762  * @param[in] ctx
5763  *   Pointer to the shared counter configuration.
5764  * @param[in] data
5765  *   Pointer to save the allocated counter index.
5766  *
5767  * @return
5768  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
5769  */
5770 
5771 static int32_t
5772 flow_dv_counter_alloc_shared_cb(void *ctx, union mlx5_l3t_data *data)
5773 {
5774 	struct mlx5_shared_counter_conf *conf = ctx;
5775 	struct rte_eth_dev *dev = conf->dev;
5776 	struct mlx5_flow_counter *cnt;
5777 
5778 	data->dword = flow_dv_counter_alloc(dev, 0);
5779 	data->dword |= MLX5_CNT_SHARED_OFFSET;
5780 	cnt = flow_dv_counter_get_by_idx(dev, data->dword, NULL);
5781 	cnt->shared_info.id = conf->id;
5782 	return 0;
5783 }
5784 
5785 /**
5786  * Get a shared flow counter.
5787  *
5788  * @param[in] dev
5789  *   Pointer to the Ethernet device structure.
5790  * @param[in] id
5791  *   Counter identifier.
5792  *
5793  * @return
5794  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
5795  */
5796 static uint32_t
5797 flow_dv_counter_get_shared(struct rte_eth_dev *dev, uint32_t id)
5798 {
5799 	struct mlx5_priv *priv = dev->data->dev_private;
5800 	struct mlx5_shared_counter_conf conf = {
5801 		.dev = dev,
5802 		.id = id,
5803 	};
5804 	union mlx5_l3t_data data = {
5805 		.dword = 0,
5806 	};
5807 
5808 	mlx5_l3t_prepare_entry(priv->sh->cnt_id_tbl, id, &data,
5809 			       flow_dv_counter_alloc_shared_cb, &conf);
5810 	return data.dword;
5811 }
5812 
5813 /**
5814  * Get age param from counter index.
5815  *
5816  * @param[in] dev
5817  *   Pointer to the Ethernet device structure.
5818  * @param[in] counter
5819  *   Index to the counter handler.
5820  *
5821  * @return
5822  *   The aging parameter specified for the counter index.
5823  */
5824 static struct mlx5_age_param*
5825 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev,
5826 				uint32_t counter)
5827 {
5828 	struct mlx5_flow_counter *cnt;
5829 	struct mlx5_flow_counter_pool *pool = NULL;
5830 
5831 	flow_dv_counter_get_by_idx(dev, counter, &pool);
5832 	counter = (counter - 1) % MLX5_COUNTERS_PER_POOL;
5833 	cnt = MLX5_POOL_GET_CNT(pool, counter);
5834 	return MLX5_CNT_TO_AGE(cnt);
5835 }
5836 
5837 /**
5838  * Remove a flow counter from aged counter list.
5839  *
5840  * @param[in] dev
5841  *   Pointer to the Ethernet device structure.
5842  * @param[in] counter
5843  *   Index to the counter handler.
5844  * @param[in] cnt
5845  *   Pointer to the counter handler.
5846  */
5847 static void
5848 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev,
5849 				uint32_t counter, struct mlx5_flow_counter *cnt)
5850 {
5851 	struct mlx5_age_info *age_info;
5852 	struct mlx5_age_param *age_param;
5853 	struct mlx5_priv *priv = dev->data->dev_private;
5854 	uint16_t expected = AGE_CANDIDATE;
5855 
5856 	age_info = GET_PORT_AGE_INFO(priv);
5857 	age_param = flow_dv_counter_idx_get_age(dev, counter);
5858 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
5859 					 AGE_FREE, false, __ATOMIC_RELAXED,
5860 					 __ATOMIC_RELAXED)) {
5861 		/**
5862 		 * We need the lock even it is age timeout,
5863 		 * since counter may still in process.
5864 		 */
5865 		rte_spinlock_lock(&age_info->aged_sl);
5866 		TAILQ_REMOVE(&age_info->aged_counters, cnt, next);
5867 		rte_spinlock_unlock(&age_info->aged_sl);
5868 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
5869 	}
5870 }
5871 
5872 /**
5873  * Release a flow counter.
5874  *
5875  * @param[in] dev
5876  *   Pointer to the Ethernet device structure.
5877  * @param[in] counter
5878  *   Index to the counter handler.
5879  */
5880 static void
5881 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter)
5882 {
5883 	struct mlx5_priv *priv = dev->data->dev_private;
5884 	struct mlx5_flow_counter_pool *pool = NULL;
5885 	struct mlx5_flow_counter *cnt;
5886 	enum mlx5_counter_type cnt_type;
5887 
5888 	if (!counter)
5889 		return;
5890 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
5891 	MLX5_ASSERT(pool);
5892 	if (IS_SHARED_CNT(counter) &&
5893 	    mlx5_l3t_clear_entry(priv->sh->cnt_id_tbl, cnt->shared_info.id))
5894 		return;
5895 	if (pool->is_aged)
5896 		flow_dv_counter_remove_from_age(dev, counter, cnt);
5897 	cnt->pool = pool;
5898 	/*
5899 	 * Put the counter back to list to be updated in none fallback mode.
5900 	 * Currently, we are using two list alternately, while one is in query,
5901 	 * add the freed counter to the other list based on the pool query_gen
5902 	 * value. After query finishes, add counter the list to the global
5903 	 * container counter list. The list changes while query starts. In
5904 	 * this case, lock will not be needed as query callback and release
5905 	 * function both operate with the different list.
5906 	 *
5907 	 */
5908 	if (!priv->sh->cmng.counter_fallback) {
5909 		rte_spinlock_lock(&pool->csl);
5910 		TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next);
5911 		rte_spinlock_unlock(&pool->csl);
5912 	} else {
5913 		cnt->dcs_when_free = cnt->dcs_when_active;
5914 		cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE :
5915 					   MLX5_COUNTER_TYPE_ORIGIN;
5916 		rte_spinlock_lock(&priv->sh->cmng.csl[cnt_type]);
5917 		TAILQ_INSERT_TAIL(&priv->sh->cmng.counters[cnt_type],
5918 				  cnt, next);
5919 		rte_spinlock_unlock(&priv->sh->cmng.csl[cnt_type]);
5920 	}
5921 }
5922 
5923 /**
5924  * Verify the @p attributes will be correctly understood by the NIC and store
5925  * them in the @p flow if everything is correct.
5926  *
5927  * @param[in] dev
5928  *   Pointer to dev struct.
5929  * @param[in] attributes
5930  *   Pointer to flow attributes
5931  * @param[in] external
5932  *   This flow rule is created by request external to PMD.
5933  * @param[out] error
5934  *   Pointer to error structure.
5935  *
5936  * @return
5937  *   - 0 on success and non root table.
5938  *   - 1 on success and root table.
5939  *   - a negative errno value otherwise and rte_errno is set.
5940  */
5941 static int
5942 flow_dv_validate_attributes(struct rte_eth_dev *dev,
5943 			    const struct mlx5_flow_tunnel *tunnel,
5944 			    const struct rte_flow_attr *attributes,
5945 			    const struct flow_grp_info *grp_info,
5946 			    struct rte_flow_error *error)
5947 {
5948 	struct mlx5_priv *priv = dev->data->dev_private;
5949 	uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes);
5950 	int ret = 0;
5951 
5952 #ifndef HAVE_MLX5DV_DR
5953 	RTE_SET_USED(tunnel);
5954 	RTE_SET_USED(grp_info);
5955 	if (attributes->group)
5956 		return rte_flow_error_set(error, ENOTSUP,
5957 					  RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
5958 					  NULL,
5959 					  "groups are not supported");
5960 #else
5961 	uint32_t table = 0;
5962 
5963 	ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table,
5964 				       grp_info, error);
5965 	if (ret)
5966 		return ret;
5967 	if (!table)
5968 		ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
5969 #endif
5970 	if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR &&
5971 	    attributes->priority > lowest_priority)
5972 		return rte_flow_error_set(error, ENOTSUP,
5973 					  RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
5974 					  NULL,
5975 					  "priority out of range");
5976 	if (attributes->transfer) {
5977 		if (!priv->config.dv_esw_en)
5978 			return rte_flow_error_set
5979 				(error, ENOTSUP,
5980 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5981 				 "E-Switch dr is not supported");
5982 		if (!(priv->representor || priv->master))
5983 			return rte_flow_error_set
5984 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5985 				 NULL, "E-Switch configuration can only be"
5986 				 " done by a master or a representor device");
5987 		if (attributes->egress)
5988 			return rte_flow_error_set
5989 				(error, ENOTSUP,
5990 				 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes,
5991 				 "egress is not supported");
5992 	}
5993 	if (!(attributes->egress ^ attributes->ingress))
5994 		return rte_flow_error_set(error, ENOTSUP,
5995 					  RTE_FLOW_ERROR_TYPE_ATTR, NULL,
5996 					  "must specify exactly one of "
5997 					  "ingress or egress");
5998 	return ret;
5999 }
6000 
6001 /**
6002  * Internal validation function. For validating both actions and items.
6003  *
6004  * @param[in] dev
6005  *   Pointer to the rte_eth_dev structure.
6006  * @param[in] attr
6007  *   Pointer to the flow attributes.
6008  * @param[in] items
6009  *   Pointer to the list of items.
6010  * @param[in] actions
6011  *   Pointer to the list of actions.
6012  * @param[in] external
6013  *   This flow rule is created by request external to PMD.
6014  * @param[in] hairpin
6015  *   Number of hairpin TX actions, 0 means classic flow.
6016  * @param[out] error
6017  *   Pointer to the error structure.
6018  *
6019  * @return
6020  *   0 on success, a negative errno value otherwise and rte_errno is set.
6021  */
6022 static int
6023 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
6024 		 const struct rte_flow_item items[],
6025 		 const struct rte_flow_action actions[],
6026 		 bool external, int hairpin, struct rte_flow_error *error)
6027 {
6028 	int ret;
6029 	uint64_t action_flags = 0;
6030 	uint64_t item_flags = 0;
6031 	uint64_t last_item = 0;
6032 	uint8_t next_protocol = 0xff;
6033 	uint16_t ether_type = 0;
6034 	int actions_n = 0;
6035 	uint8_t item_ipv6_proto = 0;
6036 	int fdb_mirror_limit = 0;
6037 	int modify_after_mirror = 0;
6038 	const struct rte_flow_item *geneve_item = NULL;
6039 	const struct rte_flow_item *gre_item = NULL;
6040 	const struct rte_flow_item *gtp_item = NULL;
6041 	const struct rte_flow_action_raw_decap *decap;
6042 	const struct rte_flow_action_raw_encap *encap;
6043 	const struct rte_flow_action_rss *rss = NULL;
6044 	const struct rte_flow_action_rss *sample_rss = NULL;
6045 	const struct rte_flow_action_count *count = NULL;
6046 	const struct rte_flow_action_count *sample_count = NULL;
6047 	const struct rte_flow_item_tcp nic_tcp_mask = {
6048 		.hdr = {
6049 			.tcp_flags = 0xFF,
6050 			.src_port = RTE_BE16(UINT16_MAX),
6051 			.dst_port = RTE_BE16(UINT16_MAX),
6052 		}
6053 	};
6054 	const struct rte_flow_item_ipv6 nic_ipv6_mask = {
6055 		.hdr = {
6056 			.src_addr =
6057 			"\xff\xff\xff\xff\xff\xff\xff\xff"
6058 			"\xff\xff\xff\xff\xff\xff\xff\xff",
6059 			.dst_addr =
6060 			"\xff\xff\xff\xff\xff\xff\xff\xff"
6061 			"\xff\xff\xff\xff\xff\xff\xff\xff",
6062 			.vtc_flow = RTE_BE32(0xffffffff),
6063 			.proto = 0xff,
6064 			.hop_limits = 0xff,
6065 		},
6066 		.has_frag_ext = 1,
6067 	};
6068 	const struct rte_flow_item_ecpri nic_ecpri_mask = {
6069 		.hdr = {
6070 			.common = {
6071 				.u32 =
6072 				RTE_BE32(((const struct rte_ecpri_common_hdr) {
6073 					.type = 0xFF,
6074 					}).u32),
6075 			},
6076 			.dummy[0] = 0xffffffff,
6077 		},
6078 	};
6079 	struct mlx5_priv *priv = dev->data->dev_private;
6080 	struct mlx5_dev_config *dev_conf = &priv->config;
6081 	uint16_t queue_index = 0xFFFF;
6082 	const struct rte_flow_item_vlan *vlan_m = NULL;
6083 	uint32_t rw_act_num = 0;
6084 	uint64_t is_root;
6085 	const struct mlx5_flow_tunnel *tunnel;
6086 	struct flow_grp_info grp_info = {
6087 		.external = !!external,
6088 		.transfer = !!attr->transfer,
6089 		.fdb_def_rule = !!priv->fdb_def_rule,
6090 	};
6091 	const struct rte_eth_hairpin_conf *conf;
6092 
6093 	if (items == NULL)
6094 		return -1;
6095 	if (is_flow_tunnel_match_rule(dev, attr, items, actions)) {
6096 		tunnel = flow_items_to_tunnel(items);
6097 		action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH |
6098 				MLX5_FLOW_ACTION_DECAP;
6099 	} else if (is_flow_tunnel_steer_rule(dev, attr, items, actions)) {
6100 		tunnel = flow_actions_to_tunnel(actions);
6101 		action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
6102 	} else {
6103 		tunnel = NULL;
6104 	}
6105 	if (tunnel && priv->representor)
6106 		return rte_flow_error_set(error, ENOTSUP,
6107 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
6108 					  "decap not supported "
6109 					  "for VF representor");
6110 	grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
6111 				(dev, tunnel, attr, items, actions);
6112 	ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error);
6113 	if (ret < 0)
6114 		return ret;
6115 	is_root = (uint64_t)ret;
6116 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
6117 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
6118 		int type = items->type;
6119 
6120 		if (!mlx5_flow_os_item_supported(type))
6121 			return rte_flow_error_set(error, ENOTSUP,
6122 						  RTE_FLOW_ERROR_TYPE_ITEM,
6123 						  NULL, "item not supported");
6124 		switch (type) {
6125 		case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL:
6126 			if (items[0].type != (typeof(items[0].type))
6127 						MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL)
6128 				return rte_flow_error_set
6129 						(error, EINVAL,
6130 						RTE_FLOW_ERROR_TYPE_ITEM,
6131 						NULL, "MLX5 private items "
6132 						"must be the first");
6133 			break;
6134 		case RTE_FLOW_ITEM_TYPE_VOID:
6135 			break;
6136 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
6137 			ret = flow_dv_validate_item_port_id
6138 					(dev, items, attr, item_flags, error);
6139 			if (ret < 0)
6140 				return ret;
6141 			last_item = MLX5_FLOW_ITEM_PORT_ID;
6142 			break;
6143 		case RTE_FLOW_ITEM_TYPE_ETH:
6144 			ret = mlx5_flow_validate_item_eth(items, item_flags,
6145 							  true, error);
6146 			if (ret < 0)
6147 				return ret;
6148 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
6149 					     MLX5_FLOW_LAYER_OUTER_L2;
6150 			if (items->mask != NULL && items->spec != NULL) {
6151 				ether_type =
6152 					((const struct rte_flow_item_eth *)
6153 					 items->spec)->type;
6154 				ether_type &=
6155 					((const struct rte_flow_item_eth *)
6156 					 items->mask)->type;
6157 				ether_type = rte_be_to_cpu_16(ether_type);
6158 			} else {
6159 				ether_type = 0;
6160 			}
6161 			break;
6162 		case RTE_FLOW_ITEM_TYPE_VLAN:
6163 			ret = flow_dv_validate_item_vlan(items, item_flags,
6164 							 dev, error);
6165 			if (ret < 0)
6166 				return ret;
6167 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
6168 					     MLX5_FLOW_LAYER_OUTER_VLAN;
6169 			if (items->mask != NULL && items->spec != NULL) {
6170 				ether_type =
6171 					((const struct rte_flow_item_vlan *)
6172 					 items->spec)->inner_type;
6173 				ether_type &=
6174 					((const struct rte_flow_item_vlan *)
6175 					 items->mask)->inner_type;
6176 				ether_type = rte_be_to_cpu_16(ether_type);
6177 			} else {
6178 				ether_type = 0;
6179 			}
6180 			/* Store outer VLAN mask for of_push_vlan action. */
6181 			if (!tunnel)
6182 				vlan_m = items->mask;
6183 			break;
6184 		case RTE_FLOW_ITEM_TYPE_IPV4:
6185 			mlx5_flow_tunnel_ip_check(items, next_protocol,
6186 						  &item_flags, &tunnel);
6187 			ret = flow_dv_validate_item_ipv4(items, item_flags,
6188 							 last_item, ether_type,
6189 							 error);
6190 			if (ret < 0)
6191 				return ret;
6192 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
6193 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
6194 			if (items->mask != NULL &&
6195 			    ((const struct rte_flow_item_ipv4 *)
6196 			     items->mask)->hdr.next_proto_id) {
6197 				next_protocol =
6198 					((const struct rte_flow_item_ipv4 *)
6199 					 (items->spec))->hdr.next_proto_id;
6200 				next_protocol &=
6201 					((const struct rte_flow_item_ipv4 *)
6202 					 (items->mask))->hdr.next_proto_id;
6203 			} else {
6204 				/* Reset for inner layer. */
6205 				next_protocol = 0xff;
6206 			}
6207 			break;
6208 		case RTE_FLOW_ITEM_TYPE_IPV6:
6209 			mlx5_flow_tunnel_ip_check(items, next_protocol,
6210 						  &item_flags, &tunnel);
6211 			ret = mlx5_flow_validate_item_ipv6(items, item_flags,
6212 							   last_item,
6213 							   ether_type,
6214 							   &nic_ipv6_mask,
6215 							   error);
6216 			if (ret < 0)
6217 				return ret;
6218 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
6219 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
6220 			if (items->mask != NULL &&
6221 			    ((const struct rte_flow_item_ipv6 *)
6222 			     items->mask)->hdr.proto) {
6223 				item_ipv6_proto =
6224 					((const struct rte_flow_item_ipv6 *)
6225 					 items->spec)->hdr.proto;
6226 				next_protocol =
6227 					((const struct rte_flow_item_ipv6 *)
6228 					 items->spec)->hdr.proto;
6229 				next_protocol &=
6230 					((const struct rte_flow_item_ipv6 *)
6231 					 items->mask)->hdr.proto;
6232 			} else {
6233 				/* Reset for inner layer. */
6234 				next_protocol = 0xff;
6235 			}
6236 			break;
6237 		case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
6238 			ret = flow_dv_validate_item_ipv6_frag_ext(items,
6239 								  item_flags,
6240 								  error);
6241 			if (ret < 0)
6242 				return ret;
6243 			last_item = tunnel ?
6244 					MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
6245 					MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
6246 			if (items->mask != NULL &&
6247 			    ((const struct rte_flow_item_ipv6_frag_ext *)
6248 			     items->mask)->hdr.next_header) {
6249 				next_protocol =
6250 				((const struct rte_flow_item_ipv6_frag_ext *)
6251 				 items->spec)->hdr.next_header;
6252 				next_protocol &=
6253 				((const struct rte_flow_item_ipv6_frag_ext *)
6254 				 items->mask)->hdr.next_header;
6255 			} else {
6256 				/* Reset for inner layer. */
6257 				next_protocol = 0xff;
6258 			}
6259 			break;
6260 		case RTE_FLOW_ITEM_TYPE_TCP:
6261 			ret = mlx5_flow_validate_item_tcp
6262 						(items, item_flags,
6263 						 next_protocol,
6264 						 &nic_tcp_mask,
6265 						 error);
6266 			if (ret < 0)
6267 				return ret;
6268 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
6269 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
6270 			break;
6271 		case RTE_FLOW_ITEM_TYPE_UDP:
6272 			ret = mlx5_flow_validate_item_udp(items, item_flags,
6273 							  next_protocol,
6274 							  error);
6275 			if (ret < 0)
6276 				return ret;
6277 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
6278 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
6279 			break;
6280 		case RTE_FLOW_ITEM_TYPE_GRE:
6281 			ret = mlx5_flow_validate_item_gre(items, item_flags,
6282 							  next_protocol, error);
6283 			if (ret < 0)
6284 				return ret;
6285 			gre_item = items;
6286 			last_item = MLX5_FLOW_LAYER_GRE;
6287 			break;
6288 		case RTE_FLOW_ITEM_TYPE_NVGRE:
6289 			ret = mlx5_flow_validate_item_nvgre(items, item_flags,
6290 							    next_protocol,
6291 							    error);
6292 			if (ret < 0)
6293 				return ret;
6294 			last_item = MLX5_FLOW_LAYER_NVGRE;
6295 			break;
6296 		case RTE_FLOW_ITEM_TYPE_GRE_KEY:
6297 			ret = mlx5_flow_validate_item_gre_key
6298 				(items, item_flags, gre_item, error);
6299 			if (ret < 0)
6300 				return ret;
6301 			last_item = MLX5_FLOW_LAYER_GRE_KEY;
6302 			break;
6303 		case RTE_FLOW_ITEM_TYPE_VXLAN:
6304 			ret = mlx5_flow_validate_item_vxlan(items, item_flags,
6305 							    error);
6306 			if (ret < 0)
6307 				return ret;
6308 			last_item = MLX5_FLOW_LAYER_VXLAN;
6309 			break;
6310 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
6311 			ret = mlx5_flow_validate_item_vxlan_gpe(items,
6312 								item_flags, dev,
6313 								error);
6314 			if (ret < 0)
6315 				return ret;
6316 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
6317 			break;
6318 		case RTE_FLOW_ITEM_TYPE_GENEVE:
6319 			ret = mlx5_flow_validate_item_geneve(items,
6320 							     item_flags, dev,
6321 							     error);
6322 			if (ret < 0)
6323 				return ret;
6324 			geneve_item = items;
6325 			last_item = MLX5_FLOW_LAYER_GENEVE;
6326 			break;
6327 		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
6328 			ret = mlx5_flow_validate_item_geneve_opt(items,
6329 								 last_item,
6330 								 geneve_item,
6331 								 dev,
6332 								 error);
6333 			if (ret < 0)
6334 				return ret;
6335 			last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
6336 			break;
6337 		case RTE_FLOW_ITEM_TYPE_MPLS:
6338 			ret = mlx5_flow_validate_item_mpls(dev, items,
6339 							   item_flags,
6340 							   last_item, error);
6341 			if (ret < 0)
6342 				return ret;
6343 			last_item = MLX5_FLOW_LAYER_MPLS;
6344 			break;
6345 
6346 		case RTE_FLOW_ITEM_TYPE_MARK:
6347 			ret = flow_dv_validate_item_mark(dev, items, attr,
6348 							 error);
6349 			if (ret < 0)
6350 				return ret;
6351 			last_item = MLX5_FLOW_ITEM_MARK;
6352 			break;
6353 		case RTE_FLOW_ITEM_TYPE_META:
6354 			ret = flow_dv_validate_item_meta(dev, items, attr,
6355 							 error);
6356 			if (ret < 0)
6357 				return ret;
6358 			last_item = MLX5_FLOW_ITEM_METADATA;
6359 			break;
6360 		case RTE_FLOW_ITEM_TYPE_ICMP:
6361 			ret = mlx5_flow_validate_item_icmp(items, item_flags,
6362 							   next_protocol,
6363 							   error);
6364 			if (ret < 0)
6365 				return ret;
6366 			last_item = MLX5_FLOW_LAYER_ICMP;
6367 			break;
6368 		case RTE_FLOW_ITEM_TYPE_ICMP6:
6369 			ret = mlx5_flow_validate_item_icmp6(items, item_flags,
6370 							    next_protocol,
6371 							    error);
6372 			if (ret < 0)
6373 				return ret;
6374 			item_ipv6_proto = IPPROTO_ICMPV6;
6375 			last_item = MLX5_FLOW_LAYER_ICMP6;
6376 			break;
6377 		case RTE_FLOW_ITEM_TYPE_TAG:
6378 			ret = flow_dv_validate_item_tag(dev, items,
6379 							attr, error);
6380 			if (ret < 0)
6381 				return ret;
6382 			last_item = MLX5_FLOW_ITEM_TAG;
6383 			break;
6384 		case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
6385 		case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
6386 			break;
6387 		case RTE_FLOW_ITEM_TYPE_GTP:
6388 			ret = flow_dv_validate_item_gtp(dev, items, item_flags,
6389 							error);
6390 			if (ret < 0)
6391 				return ret;
6392 			gtp_item = items;
6393 			last_item = MLX5_FLOW_LAYER_GTP;
6394 			break;
6395 		case RTE_FLOW_ITEM_TYPE_GTP_PSC:
6396 			ret = flow_dv_validate_item_gtp_psc(items, last_item,
6397 							    gtp_item, attr,
6398 							    error);
6399 			if (ret < 0)
6400 				return ret;
6401 			last_item = MLX5_FLOW_LAYER_GTP_PSC;
6402 			break;
6403 		case RTE_FLOW_ITEM_TYPE_ECPRI:
6404 			/* Capacity will be checked in the translate stage. */
6405 			ret = mlx5_flow_validate_item_ecpri(items, item_flags,
6406 							    last_item,
6407 							    ether_type,
6408 							    &nic_ecpri_mask,
6409 							    error);
6410 			if (ret < 0)
6411 				return ret;
6412 			last_item = MLX5_FLOW_LAYER_ECPRI;
6413 			break;
6414 		default:
6415 			return rte_flow_error_set(error, ENOTSUP,
6416 						  RTE_FLOW_ERROR_TYPE_ITEM,
6417 						  NULL, "item not supported");
6418 		}
6419 		item_flags |= last_item;
6420 	}
6421 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
6422 		int type = actions->type;
6423 
6424 		if (!mlx5_flow_os_action_supported(type))
6425 			return rte_flow_error_set(error, ENOTSUP,
6426 						  RTE_FLOW_ERROR_TYPE_ACTION,
6427 						  actions,
6428 						  "action not supported");
6429 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
6430 			return rte_flow_error_set(error, ENOTSUP,
6431 						  RTE_FLOW_ERROR_TYPE_ACTION,
6432 						  actions, "too many actions");
6433 		switch (type) {
6434 		case RTE_FLOW_ACTION_TYPE_VOID:
6435 			break;
6436 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
6437 			ret = flow_dv_validate_action_port_id(dev,
6438 							      action_flags,
6439 							      actions,
6440 							      attr,
6441 							      error);
6442 			if (ret)
6443 				return ret;
6444 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
6445 			++actions_n;
6446 			break;
6447 		case RTE_FLOW_ACTION_TYPE_FLAG:
6448 			ret = flow_dv_validate_action_flag(dev, action_flags,
6449 							   attr, error);
6450 			if (ret < 0)
6451 				return ret;
6452 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
6453 				/* Count all modify-header actions as one. */
6454 				if (!(action_flags &
6455 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
6456 					++actions_n;
6457 				action_flags |= MLX5_FLOW_ACTION_FLAG |
6458 						MLX5_FLOW_ACTION_MARK_EXT;
6459 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6460 					modify_after_mirror = 1;
6461 
6462 			} else {
6463 				action_flags |= MLX5_FLOW_ACTION_FLAG;
6464 				++actions_n;
6465 			}
6466 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
6467 			break;
6468 		case RTE_FLOW_ACTION_TYPE_MARK:
6469 			ret = flow_dv_validate_action_mark(dev, actions,
6470 							   action_flags,
6471 							   attr, error);
6472 			if (ret < 0)
6473 				return ret;
6474 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
6475 				/* Count all modify-header actions as one. */
6476 				if (!(action_flags &
6477 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
6478 					++actions_n;
6479 				action_flags |= MLX5_FLOW_ACTION_MARK |
6480 						MLX5_FLOW_ACTION_MARK_EXT;
6481 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6482 					modify_after_mirror = 1;
6483 			} else {
6484 				action_flags |= MLX5_FLOW_ACTION_MARK;
6485 				++actions_n;
6486 			}
6487 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
6488 			break;
6489 		case RTE_FLOW_ACTION_TYPE_SET_META:
6490 			ret = flow_dv_validate_action_set_meta(dev, actions,
6491 							       action_flags,
6492 							       attr, error);
6493 			if (ret < 0)
6494 				return ret;
6495 			/* Count all modify-header actions as one action. */
6496 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6497 				++actions_n;
6498 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6499 				modify_after_mirror = 1;
6500 			action_flags |= MLX5_FLOW_ACTION_SET_META;
6501 			rw_act_num += MLX5_ACT_NUM_SET_META;
6502 			break;
6503 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
6504 			ret = flow_dv_validate_action_set_tag(dev, actions,
6505 							      action_flags,
6506 							      attr, error);
6507 			if (ret < 0)
6508 				return ret;
6509 			/* Count all modify-header actions as one action. */
6510 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6511 				++actions_n;
6512 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6513 				modify_after_mirror = 1;
6514 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
6515 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
6516 			break;
6517 		case RTE_FLOW_ACTION_TYPE_DROP:
6518 			ret = mlx5_flow_validate_action_drop(action_flags,
6519 							     attr, error);
6520 			if (ret < 0)
6521 				return ret;
6522 			action_flags |= MLX5_FLOW_ACTION_DROP;
6523 			++actions_n;
6524 			break;
6525 		case RTE_FLOW_ACTION_TYPE_QUEUE:
6526 			ret = mlx5_flow_validate_action_queue(actions,
6527 							      action_flags, dev,
6528 							      attr, error);
6529 			if (ret < 0)
6530 				return ret;
6531 			queue_index = ((const struct rte_flow_action_queue *)
6532 							(actions->conf))->index;
6533 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
6534 			++actions_n;
6535 			break;
6536 		case RTE_FLOW_ACTION_TYPE_RSS:
6537 			rss = actions->conf;
6538 			ret = mlx5_flow_validate_action_rss(actions,
6539 							    action_flags, dev,
6540 							    attr, item_flags,
6541 							    error);
6542 			if (ret < 0)
6543 				return ret;
6544 			if (rss && sample_rss &&
6545 			    (sample_rss->level != rss->level ||
6546 			    sample_rss->types != rss->types))
6547 				return rte_flow_error_set(error, ENOTSUP,
6548 					RTE_FLOW_ERROR_TYPE_ACTION,
6549 					NULL,
6550 					"Can't use the different RSS types "
6551 					"or level in the same flow");
6552 			if (rss != NULL && rss->queue_num)
6553 				queue_index = rss->queue[0];
6554 			action_flags |= MLX5_FLOW_ACTION_RSS;
6555 			++actions_n;
6556 			break;
6557 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
6558 			ret =
6559 			mlx5_flow_validate_action_default_miss(action_flags,
6560 					attr, error);
6561 			if (ret < 0)
6562 				return ret;
6563 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
6564 			++actions_n;
6565 			break;
6566 		case RTE_FLOW_ACTION_TYPE_COUNT:
6567 			ret = flow_dv_validate_action_count(dev, actions,
6568 							    action_flags,
6569 							    error);
6570 			if (ret < 0)
6571 				return ret;
6572 			count = actions->conf;
6573 			action_flags |= MLX5_FLOW_ACTION_COUNT;
6574 			++actions_n;
6575 			break;
6576 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
6577 			if (flow_dv_validate_action_pop_vlan(dev,
6578 							     action_flags,
6579 							     actions,
6580 							     item_flags, attr,
6581 							     error))
6582 				return -rte_errno;
6583 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
6584 			++actions_n;
6585 			break;
6586 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
6587 			ret = flow_dv_validate_action_push_vlan(dev,
6588 								action_flags,
6589 								vlan_m,
6590 								actions, attr,
6591 								error);
6592 			if (ret < 0)
6593 				return ret;
6594 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
6595 			++actions_n;
6596 			break;
6597 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
6598 			ret = flow_dv_validate_action_set_vlan_pcp
6599 						(action_flags, actions, error);
6600 			if (ret < 0)
6601 				return ret;
6602 			/* Count PCP with push_vlan command. */
6603 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP;
6604 			break;
6605 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
6606 			ret = flow_dv_validate_action_set_vlan_vid
6607 						(item_flags, action_flags,
6608 						 actions, error);
6609 			if (ret < 0)
6610 				return ret;
6611 			/* Count VID with push_vlan command. */
6612 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
6613 			rw_act_num += MLX5_ACT_NUM_MDF_VID;
6614 			break;
6615 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
6616 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
6617 			ret = flow_dv_validate_action_l2_encap(dev,
6618 							       action_flags,
6619 							       actions, attr,
6620 							       error);
6621 			if (ret < 0)
6622 				return ret;
6623 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
6624 			++actions_n;
6625 			break;
6626 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
6627 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
6628 			ret = flow_dv_validate_action_decap(dev, action_flags,
6629 							    actions, item_flags,
6630 							    attr, error);
6631 			if (ret < 0)
6632 				return ret;
6633 			action_flags |= MLX5_FLOW_ACTION_DECAP;
6634 			++actions_n;
6635 			break;
6636 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
6637 			ret = flow_dv_validate_action_raw_encap_decap
6638 				(dev, NULL, actions->conf, attr, &action_flags,
6639 				 &actions_n, actions, item_flags, error);
6640 			if (ret < 0)
6641 				return ret;
6642 			break;
6643 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
6644 			decap = actions->conf;
6645 			while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID)
6646 				;
6647 			if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
6648 				encap = NULL;
6649 				actions--;
6650 			} else {
6651 				encap = actions->conf;
6652 			}
6653 			ret = flow_dv_validate_action_raw_encap_decap
6654 					   (dev,
6655 					    decap ? decap : &empty_decap, encap,
6656 					    attr, &action_flags, &actions_n,
6657 					    actions, item_flags, error);
6658 			if (ret < 0)
6659 				return ret;
6660 			break;
6661 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
6662 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
6663 			ret = flow_dv_validate_action_modify_mac(action_flags,
6664 								 actions,
6665 								 item_flags,
6666 								 error);
6667 			if (ret < 0)
6668 				return ret;
6669 			/* Count all modify-header actions as one action. */
6670 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6671 				++actions_n;
6672 			action_flags |= actions->type ==
6673 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
6674 						MLX5_FLOW_ACTION_SET_MAC_SRC :
6675 						MLX5_FLOW_ACTION_SET_MAC_DST;
6676 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6677 				modify_after_mirror = 1;
6678 			/*
6679 			 * Even if the source and destination MAC addresses have
6680 			 * overlap in the header with 4B alignment, the convert
6681 			 * function will handle them separately and 4 SW actions
6682 			 * will be created. And 2 actions will be added each
6683 			 * time no matter how many bytes of address will be set.
6684 			 */
6685 			rw_act_num += MLX5_ACT_NUM_MDF_MAC;
6686 			break;
6687 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
6688 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
6689 			ret = flow_dv_validate_action_modify_ipv4(action_flags,
6690 								  actions,
6691 								  item_flags,
6692 								  error);
6693 			if (ret < 0)
6694 				return ret;
6695 			/* Count all modify-header actions as one action. */
6696 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6697 				++actions_n;
6698 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6699 				modify_after_mirror = 1;
6700 			action_flags |= actions->type ==
6701 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
6702 						MLX5_FLOW_ACTION_SET_IPV4_SRC :
6703 						MLX5_FLOW_ACTION_SET_IPV4_DST;
6704 			rw_act_num += MLX5_ACT_NUM_MDF_IPV4;
6705 			break;
6706 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
6707 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
6708 			ret = flow_dv_validate_action_modify_ipv6(action_flags,
6709 								  actions,
6710 								  item_flags,
6711 								  error);
6712 			if (ret < 0)
6713 				return ret;
6714 			if (item_ipv6_proto == IPPROTO_ICMPV6)
6715 				return rte_flow_error_set(error, ENOTSUP,
6716 					RTE_FLOW_ERROR_TYPE_ACTION,
6717 					actions,
6718 					"Can't change header "
6719 					"with ICMPv6 proto");
6720 			/* Count all modify-header actions as one action. */
6721 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6722 				++actions_n;
6723 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6724 				modify_after_mirror = 1;
6725 			action_flags |= actions->type ==
6726 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
6727 						MLX5_FLOW_ACTION_SET_IPV6_SRC :
6728 						MLX5_FLOW_ACTION_SET_IPV6_DST;
6729 			rw_act_num += MLX5_ACT_NUM_MDF_IPV6;
6730 			break;
6731 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
6732 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
6733 			ret = flow_dv_validate_action_modify_tp(action_flags,
6734 								actions,
6735 								item_flags,
6736 								error);
6737 			if (ret < 0)
6738 				return ret;
6739 			/* Count all modify-header actions as one action. */
6740 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6741 				++actions_n;
6742 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6743 				modify_after_mirror = 1;
6744 			action_flags |= actions->type ==
6745 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
6746 						MLX5_FLOW_ACTION_SET_TP_SRC :
6747 						MLX5_FLOW_ACTION_SET_TP_DST;
6748 			rw_act_num += MLX5_ACT_NUM_MDF_PORT;
6749 			break;
6750 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
6751 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
6752 			ret = flow_dv_validate_action_modify_ttl(action_flags,
6753 								 actions,
6754 								 item_flags,
6755 								 error);
6756 			if (ret < 0)
6757 				return ret;
6758 			/* Count all modify-header actions as one action. */
6759 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6760 				++actions_n;
6761 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6762 				modify_after_mirror = 1;
6763 			action_flags |= actions->type ==
6764 					RTE_FLOW_ACTION_TYPE_SET_TTL ?
6765 						MLX5_FLOW_ACTION_SET_TTL :
6766 						MLX5_FLOW_ACTION_DEC_TTL;
6767 			rw_act_num += MLX5_ACT_NUM_MDF_TTL;
6768 			break;
6769 		case RTE_FLOW_ACTION_TYPE_JUMP:
6770 			ret = flow_dv_validate_action_jump(dev, tunnel, actions,
6771 							   action_flags,
6772 							   attr, external,
6773 							   error);
6774 			if (ret)
6775 				return ret;
6776 			if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
6777 			    fdb_mirror_limit)
6778 				return rte_flow_error_set(error, EINVAL,
6779 						  RTE_FLOW_ERROR_TYPE_ACTION,
6780 						  NULL,
6781 						  "sample and jump action combination is not supported");
6782 			++actions_n;
6783 			action_flags |= MLX5_FLOW_ACTION_JUMP;
6784 			break;
6785 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
6786 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
6787 			ret = flow_dv_validate_action_modify_tcp_seq
6788 								(action_flags,
6789 								 actions,
6790 								 item_flags,
6791 								 error);
6792 			if (ret < 0)
6793 				return ret;
6794 			/* Count all modify-header actions as one action. */
6795 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6796 				++actions_n;
6797 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6798 				modify_after_mirror = 1;
6799 			action_flags |= actions->type ==
6800 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
6801 						MLX5_FLOW_ACTION_INC_TCP_SEQ :
6802 						MLX5_FLOW_ACTION_DEC_TCP_SEQ;
6803 			rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ;
6804 			break;
6805 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
6806 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
6807 			ret = flow_dv_validate_action_modify_tcp_ack
6808 								(action_flags,
6809 								 actions,
6810 								 item_flags,
6811 								 error);
6812 			if (ret < 0)
6813 				return ret;
6814 			/* Count all modify-header actions as one action. */
6815 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6816 				++actions_n;
6817 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6818 				modify_after_mirror = 1;
6819 			action_flags |= actions->type ==
6820 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
6821 						MLX5_FLOW_ACTION_INC_TCP_ACK :
6822 						MLX5_FLOW_ACTION_DEC_TCP_ACK;
6823 			rw_act_num += MLX5_ACT_NUM_MDF_TCPACK;
6824 			break;
6825 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
6826 			break;
6827 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
6828 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
6829 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
6830 			break;
6831 		case RTE_FLOW_ACTION_TYPE_METER:
6832 			ret = mlx5_flow_validate_action_meter(dev,
6833 							      action_flags,
6834 							      actions, attr,
6835 							      error);
6836 			if (ret < 0)
6837 				return ret;
6838 			action_flags |= MLX5_FLOW_ACTION_METER;
6839 			++actions_n;
6840 			/* Meter action will add one more TAG action. */
6841 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
6842 			break;
6843 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
6844 			if (!attr->transfer && !attr->group)
6845 				return rte_flow_error_set(error, ENOTSUP,
6846 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6847 									   NULL,
6848 			  "Shared ASO age action is not supported for group 0");
6849 			action_flags |= MLX5_FLOW_ACTION_AGE;
6850 			++actions_n;
6851 			break;
6852 		case RTE_FLOW_ACTION_TYPE_AGE:
6853 			ret = flow_dv_validate_action_age(action_flags,
6854 							  actions, dev,
6855 							  error);
6856 			if (ret < 0)
6857 				return ret;
6858 			/*
6859 			 * Validate the regular AGE action (using counter)
6860 			 * mutual exclusion with share counter actions.
6861 			 */
6862 			if (!priv->sh->flow_hit_aso_en) {
6863 				if (count && count->shared)
6864 					return rte_flow_error_set
6865 						(error, EINVAL,
6866 						RTE_FLOW_ERROR_TYPE_ACTION,
6867 						NULL,
6868 						"old age and shared count combination is not supported");
6869 				if (sample_count)
6870 					return rte_flow_error_set
6871 						(error, EINVAL,
6872 						RTE_FLOW_ERROR_TYPE_ACTION,
6873 						NULL,
6874 						"old age action and count must be in the same sub flow");
6875 			}
6876 			action_flags |= MLX5_FLOW_ACTION_AGE;
6877 			++actions_n;
6878 			break;
6879 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
6880 			ret = flow_dv_validate_action_modify_ipv4_dscp
6881 							 (action_flags,
6882 							  actions,
6883 							  item_flags,
6884 							  error);
6885 			if (ret < 0)
6886 				return ret;
6887 			/* Count all modify-header actions as one action. */
6888 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6889 				++actions_n;
6890 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6891 				modify_after_mirror = 1;
6892 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
6893 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
6894 			break;
6895 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
6896 			ret = flow_dv_validate_action_modify_ipv6_dscp
6897 								(action_flags,
6898 								 actions,
6899 								 item_flags,
6900 								 error);
6901 			if (ret < 0)
6902 				return ret;
6903 			/* Count all modify-header actions as one action. */
6904 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
6905 				++actions_n;
6906 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
6907 				modify_after_mirror = 1;
6908 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
6909 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
6910 			break;
6911 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
6912 			ret = flow_dv_validate_action_sample(&action_flags,
6913 							     actions, dev,
6914 							     attr, item_flags,
6915 							     rss, &sample_rss,
6916 							     &sample_count,
6917 							     &fdb_mirror_limit,
6918 							     error);
6919 			if (ret < 0)
6920 				return ret;
6921 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
6922 			++actions_n;
6923 			break;
6924 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
6925 			if (actions[0].type != (typeof(actions[0].type))
6926 				MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET)
6927 				return rte_flow_error_set
6928 						(error, EINVAL,
6929 						RTE_FLOW_ERROR_TYPE_ACTION,
6930 						NULL, "MLX5 private action "
6931 						"must be the first");
6932 
6933 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
6934 			break;
6935 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
6936 			if (!attr->transfer && !attr->group)
6937 				return rte_flow_error_set(error, ENOTSUP,
6938 						RTE_FLOW_ERROR_TYPE_ACTION,
6939 						NULL, "modify field action "
6940 						"is not supported for group 0");
6941 			ret = flow_dv_validate_action_modify_field(action_flags,
6942 								 actions,
6943 								 error);
6944 			if (ret < 0)
6945 				return ret;
6946 			/* Count all modify-header actions as one action. */
6947 			if (!(action_flags & MLX5_FLOW_ACTION_MODIFY_FIELD))
6948 				++actions_n;
6949 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
6950 			rw_act_num += ret;
6951 			break;
6952 		default:
6953 			return rte_flow_error_set(error, ENOTSUP,
6954 						  RTE_FLOW_ERROR_TYPE_ACTION,
6955 						  actions,
6956 						  "action not supported");
6957 		}
6958 	}
6959 	/*
6960 	 * Validate actions in flow rules
6961 	 * - Explicit decap action is prohibited by the tunnel offload API.
6962 	 * - Drop action in tunnel steer rule is prohibited by the API.
6963 	 * - Application cannot use MARK action because it's value can mask
6964 	 *   tunnel default miss nitification.
6965 	 * - JUMP in tunnel match rule has no support in current PMD
6966 	 *   implementation.
6967 	 * - TAG & META are reserved for future uses.
6968 	 */
6969 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) {
6970 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP    |
6971 					    MLX5_FLOW_ACTION_MARK     |
6972 					    MLX5_FLOW_ACTION_SET_TAG  |
6973 					    MLX5_FLOW_ACTION_SET_META |
6974 					    MLX5_FLOW_ACTION_DROP;
6975 
6976 		if (action_flags & bad_actions_mask)
6977 			return rte_flow_error_set
6978 					(error, EINVAL,
6979 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
6980 					"Invalid RTE action in tunnel "
6981 					"set decap rule");
6982 		if (!(action_flags & MLX5_FLOW_ACTION_JUMP))
6983 			return rte_flow_error_set
6984 					(error, EINVAL,
6985 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
6986 					"tunnel set decap rule must terminate "
6987 					"with JUMP");
6988 		if (!attr->ingress)
6989 			return rte_flow_error_set
6990 					(error, EINVAL,
6991 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
6992 					"tunnel flows for ingress traffic only");
6993 	}
6994 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) {
6995 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP    |
6996 					    MLX5_FLOW_ACTION_MARK    |
6997 					    MLX5_FLOW_ACTION_SET_TAG |
6998 					    MLX5_FLOW_ACTION_SET_META;
6999 
7000 		if (action_flags & bad_actions_mask)
7001 			return rte_flow_error_set
7002 					(error, EINVAL,
7003 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7004 					"Invalid RTE action in tunnel "
7005 					"set match rule");
7006 	}
7007 	/*
7008 	 * Validate the drop action mutual exclusion with other actions.
7009 	 * Drop action is mutually-exclusive with any other action, except for
7010 	 * Count action.
7011 	 * Drop action compatibility with tunnel offload was already validated.
7012 	 */
7013 	if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH |
7014 			    MLX5_FLOW_ACTION_TUNNEL_MATCH));
7015 	else if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
7016 	    (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT)))
7017 		return rte_flow_error_set(error, EINVAL,
7018 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7019 					  "Drop action is mutually-exclusive "
7020 					  "with any other action, except for "
7021 					  "Count action");
7022 	/* Eswitch has few restrictions on using items and actions */
7023 	if (attr->transfer) {
7024 		if (!mlx5_flow_ext_mreg_supported(dev) &&
7025 		    action_flags & MLX5_FLOW_ACTION_FLAG)
7026 			return rte_flow_error_set(error, ENOTSUP,
7027 						  RTE_FLOW_ERROR_TYPE_ACTION,
7028 						  NULL,
7029 						  "unsupported action FLAG");
7030 		if (!mlx5_flow_ext_mreg_supported(dev) &&
7031 		    action_flags & MLX5_FLOW_ACTION_MARK)
7032 			return rte_flow_error_set(error, ENOTSUP,
7033 						  RTE_FLOW_ERROR_TYPE_ACTION,
7034 						  NULL,
7035 						  "unsupported action MARK");
7036 		if (action_flags & MLX5_FLOW_ACTION_QUEUE)
7037 			return rte_flow_error_set(error, ENOTSUP,
7038 						  RTE_FLOW_ERROR_TYPE_ACTION,
7039 						  NULL,
7040 						  "unsupported action QUEUE");
7041 		if (action_flags & MLX5_FLOW_ACTION_RSS)
7042 			return rte_flow_error_set(error, ENOTSUP,
7043 						  RTE_FLOW_ERROR_TYPE_ACTION,
7044 						  NULL,
7045 						  "unsupported action RSS");
7046 		if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
7047 			return rte_flow_error_set(error, EINVAL,
7048 						  RTE_FLOW_ERROR_TYPE_ACTION,
7049 						  actions,
7050 						  "no fate action is found");
7051 	} else {
7052 		if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress)
7053 			return rte_flow_error_set(error, EINVAL,
7054 						  RTE_FLOW_ERROR_TYPE_ACTION,
7055 						  actions,
7056 						  "no fate action is found");
7057 	}
7058 	/*
7059 	 * Continue validation for Xcap and VLAN actions.
7060 	 * If hairpin is working in explicit TX rule mode, there is no actions
7061 	 * splitting and the validation of hairpin ingress flow should be the
7062 	 * same as other standard flows.
7063 	 */
7064 	if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS |
7065 			     MLX5_FLOW_VLAN_ACTIONS)) &&
7066 	    (queue_index == 0xFFFF ||
7067 	     mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN ||
7068 	     ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL &&
7069 	     conf->tx_explicit != 0))) {
7070 		if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
7071 		    MLX5_FLOW_XCAP_ACTIONS)
7072 			return rte_flow_error_set(error, ENOTSUP,
7073 						  RTE_FLOW_ERROR_TYPE_ACTION,
7074 						  NULL, "encap and decap "
7075 						  "combination aren't supported");
7076 		if (!attr->transfer && attr->ingress) {
7077 			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
7078 				return rte_flow_error_set
7079 						(error, ENOTSUP,
7080 						 RTE_FLOW_ERROR_TYPE_ACTION,
7081 						 NULL, "encap is not supported"
7082 						 " for ingress traffic");
7083 			else if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
7084 				return rte_flow_error_set
7085 						(error, ENOTSUP,
7086 						 RTE_FLOW_ERROR_TYPE_ACTION,
7087 						 NULL, "push VLAN action not "
7088 						 "supported for ingress");
7089 			else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) ==
7090 					MLX5_FLOW_VLAN_ACTIONS)
7091 				return rte_flow_error_set
7092 						(error, ENOTSUP,
7093 						 RTE_FLOW_ERROR_TYPE_ACTION,
7094 						 NULL, "no support for "
7095 						 "multiple VLAN actions");
7096 		}
7097 	}
7098 	/*
7099 	 * Hairpin flow will add one more TAG action in TX implicit mode.
7100 	 * In TX explicit mode, there will be no hairpin flow ID.
7101 	 */
7102 	if (hairpin > 0)
7103 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
7104 	/* extra metadata enabled: one more TAG action will be add. */
7105 	if (dev_conf->dv_flow_en &&
7106 	    dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
7107 	    mlx5_flow_ext_mreg_supported(dev))
7108 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
7109 	if (rw_act_num >
7110 			flow_dv_modify_hdr_action_max(dev, is_root)) {
7111 		return rte_flow_error_set(error, ENOTSUP,
7112 					  RTE_FLOW_ERROR_TYPE_ACTION,
7113 					  NULL, "too many header modify"
7114 					  " actions to support");
7115 	}
7116 	/* Eswitch egress mirror and modify flow has limitation on CX5 */
7117 	if (fdb_mirror_limit && modify_after_mirror)
7118 		return rte_flow_error_set(error, EINVAL,
7119 				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7120 				"sample before modify action is not supported");
7121 	return 0;
7122 }
7123 
7124 /**
7125  * Internal preparation function. Allocates the DV flow size,
7126  * this size is constant.
7127  *
7128  * @param[in] dev
7129  *   Pointer to the rte_eth_dev structure.
7130  * @param[in] attr
7131  *   Pointer to the flow attributes.
7132  * @param[in] items
7133  *   Pointer to the list of items.
7134  * @param[in] actions
7135  *   Pointer to the list of actions.
7136  * @param[out] error
7137  *   Pointer to the error structure.
7138  *
7139  * @return
7140  *   Pointer to mlx5_flow object on success,
7141  *   otherwise NULL and rte_errno is set.
7142  */
7143 static struct mlx5_flow *
7144 flow_dv_prepare(struct rte_eth_dev *dev,
7145 		const struct rte_flow_attr *attr __rte_unused,
7146 		const struct rte_flow_item items[] __rte_unused,
7147 		const struct rte_flow_action actions[] __rte_unused,
7148 		struct rte_flow_error *error)
7149 {
7150 	uint32_t handle_idx = 0;
7151 	struct mlx5_flow *dev_flow;
7152 	struct mlx5_flow_handle *dev_handle;
7153 	struct mlx5_priv *priv = dev->data->dev_private;
7154 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
7155 
7156 	MLX5_ASSERT(wks);
7157 	/* In case of corrupting the memory. */
7158 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
7159 		rte_flow_error_set(error, ENOSPC,
7160 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
7161 				   "not free temporary device flow");
7162 		return NULL;
7163 	}
7164 	dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
7165 				   &handle_idx);
7166 	if (!dev_handle) {
7167 		rte_flow_error_set(error, ENOMEM,
7168 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
7169 				   "not enough memory to create flow handle");
7170 		return NULL;
7171 	}
7172 	MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows));
7173 	dev_flow = &wks->flows[wks->flow_idx++];
7174 	memset(dev_flow, 0, sizeof(*dev_flow));
7175 	dev_flow->handle = dev_handle;
7176 	dev_flow->handle_idx = handle_idx;
7177 	/*
7178 	 * In some old rdma-core releases, before continuing, a check of the
7179 	 * length of matching parameter will be done at first. It needs to use
7180 	 * the length without misc4 param. If the flow has misc4 support, then
7181 	 * the length needs to be adjusted accordingly. Each param member is
7182 	 * aligned with a 64B boundary naturally.
7183 	 */
7184 	dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param) -
7185 				  MLX5_ST_SZ_BYTES(fte_match_set_misc4);
7186 	dev_flow->ingress = attr->ingress;
7187 	dev_flow->dv.transfer = attr->transfer;
7188 	return dev_flow;
7189 }
7190 
7191 #ifdef RTE_LIBRTE_MLX5_DEBUG
7192 /**
7193  * Sanity check for match mask and value. Similar to check_valid_spec() in
7194  * kernel driver. If unmasked bit is present in value, it returns failure.
7195  *
7196  * @param match_mask
7197  *   pointer to match mask buffer.
7198  * @param match_value
7199  *   pointer to match value buffer.
7200  *
7201  * @return
7202  *   0 if valid, -EINVAL otherwise.
7203  */
7204 static int
7205 flow_dv_check_valid_spec(void *match_mask, void *match_value)
7206 {
7207 	uint8_t *m = match_mask;
7208 	uint8_t *v = match_value;
7209 	unsigned int i;
7210 
7211 	for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) {
7212 		if (v[i] & ~m[i]) {
7213 			DRV_LOG(ERR,
7214 				"match_value differs from match_criteria"
7215 				" %p[%u] != %p[%u]",
7216 				match_value, i, match_mask, i);
7217 			return -EINVAL;
7218 		}
7219 	}
7220 	return 0;
7221 }
7222 #endif
7223 
7224 /**
7225  * Add match of ip_version.
7226  *
7227  * @param[in] group
7228  *   Flow group.
7229  * @param[in] headers_v
7230  *   Values header pointer.
7231  * @param[in] headers_m
7232  *   Masks header pointer.
7233  * @param[in] ip_version
7234  *   The IP version to set.
7235  */
7236 static inline void
7237 flow_dv_set_match_ip_version(uint32_t group,
7238 			     void *headers_v,
7239 			     void *headers_m,
7240 			     uint8_t ip_version)
7241 {
7242 	if (group == 0)
7243 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
7244 	else
7245 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version,
7246 			 ip_version);
7247 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, ip_version);
7248 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0);
7249 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype, 0);
7250 }
7251 
7252 /**
7253  * Add Ethernet item to matcher and to the value.
7254  *
7255  * @param[in, out] matcher
7256  *   Flow matcher.
7257  * @param[in, out] key
7258  *   Flow matcher value.
7259  * @param[in] item
7260  *   Flow pattern to translate.
7261  * @param[in] inner
7262  *   Item is inner pattern.
7263  */
7264 static void
7265 flow_dv_translate_item_eth(void *matcher, void *key,
7266 			   const struct rte_flow_item *item, int inner,
7267 			   uint32_t group)
7268 {
7269 	const struct rte_flow_item_eth *eth_m = item->mask;
7270 	const struct rte_flow_item_eth *eth_v = item->spec;
7271 	const struct rte_flow_item_eth nic_mask = {
7272 		.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
7273 		.src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
7274 		.type = RTE_BE16(0xffff),
7275 		.has_vlan = 0,
7276 	};
7277 	void *hdrs_m;
7278 	void *hdrs_v;
7279 	char *l24_v;
7280 	unsigned int i;
7281 
7282 	if (!eth_v)
7283 		return;
7284 	if (!eth_m)
7285 		eth_m = &nic_mask;
7286 	if (inner) {
7287 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
7288 					 inner_headers);
7289 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
7290 	} else {
7291 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
7292 					 outer_headers);
7293 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
7294 	}
7295 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, dmac_47_16),
7296 	       &eth_m->dst, sizeof(eth_m->dst));
7297 	/* The value must be in the range of the mask. */
7298 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16);
7299 	for (i = 0; i < sizeof(eth_m->dst); ++i)
7300 		l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i];
7301 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, smac_47_16),
7302 	       &eth_m->src, sizeof(eth_m->src));
7303 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16);
7304 	/* The value must be in the range of the mask. */
7305 	for (i = 0; i < sizeof(eth_m->dst); ++i)
7306 		l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i];
7307 	/*
7308 	 * HW supports match on one Ethertype, the Ethertype following the last
7309 	 * VLAN tag of the packet (see PRM).
7310 	 * Set match on ethertype only if ETH header is not followed by VLAN.
7311 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
7312 	 * ethertype, and use ip_version field instead.
7313 	 * eCPRI over Ether layer will use type value 0xAEFE.
7314 	 */
7315 	if (eth_m->type == 0xFFFF) {
7316 		/* Set cvlan_tag mask for any single\multi\un-tagged case. */
7317 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
7318 		switch (eth_v->type) {
7319 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
7320 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
7321 			return;
7322 		case RTE_BE16(RTE_ETHER_TYPE_QINQ):
7323 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
7324 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
7325 			return;
7326 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
7327 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
7328 			return;
7329 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
7330 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
7331 			return;
7332 		default:
7333 			break;
7334 		}
7335 	}
7336 	if (eth_m->has_vlan) {
7337 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
7338 		if (eth_v->has_vlan) {
7339 			/*
7340 			 * Here, when also has_more_vlan field in VLAN item is
7341 			 * not set, only single-tagged packets will be matched.
7342 			 */
7343 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
7344 			return;
7345 		}
7346 	}
7347 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
7348 		 rte_be_to_cpu_16(eth_m->type));
7349 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
7350 	*(uint16_t *)(l24_v) = eth_m->type & eth_v->type;
7351 }
7352 
7353 /**
7354  * Add VLAN item to matcher and to the value.
7355  *
7356  * @param[in, out] dev_flow
7357  *   Flow descriptor.
7358  * @param[in, out] matcher
7359  *   Flow matcher.
7360  * @param[in, out] key
7361  *   Flow matcher value.
7362  * @param[in] item
7363  *   Flow pattern to translate.
7364  * @param[in] inner
7365  *   Item is inner pattern.
7366  */
7367 static void
7368 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow,
7369 			    void *matcher, void *key,
7370 			    const struct rte_flow_item *item,
7371 			    int inner, uint32_t group)
7372 {
7373 	const struct rte_flow_item_vlan *vlan_m = item->mask;
7374 	const struct rte_flow_item_vlan *vlan_v = item->spec;
7375 	void *hdrs_m;
7376 	void *hdrs_v;
7377 	uint16_t tci_m;
7378 	uint16_t tci_v;
7379 
7380 	if (inner) {
7381 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
7382 					 inner_headers);
7383 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
7384 	} else {
7385 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
7386 					 outer_headers);
7387 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
7388 		/*
7389 		 * This is workaround, masks are not supported,
7390 		 * and pre-validated.
7391 		 */
7392 		if (vlan_v)
7393 			dev_flow->handle->vf_vlan.tag =
7394 					rte_be_to_cpu_16(vlan_v->tci) & 0x0fff;
7395 	}
7396 	/*
7397 	 * When VLAN item exists in flow, mark packet as tagged,
7398 	 * even if TCI is not specified.
7399 	 */
7400 	if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag)) {
7401 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
7402 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
7403 	}
7404 	if (!vlan_v)
7405 		return;
7406 	if (!vlan_m)
7407 		vlan_m = &rte_flow_item_vlan_mask;
7408 	tci_m = rte_be_to_cpu_16(vlan_m->tci);
7409 	tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci);
7410 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_vid, tci_m);
7411 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v);
7412 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_cfi, tci_m >> 12);
7413 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12);
7414 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_prio, tci_m >> 13);
7415 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13);
7416 	/*
7417 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
7418 	 * ethertype, and use ip_version field instead.
7419 	 */
7420 	if (vlan_m->inner_type == 0xFFFF) {
7421 		switch (vlan_v->inner_type) {
7422 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
7423 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
7424 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
7425 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
7426 			return;
7427 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
7428 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
7429 			return;
7430 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
7431 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
7432 			return;
7433 		default:
7434 			break;
7435 		}
7436 	}
7437 	if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) {
7438 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
7439 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
7440 		/* Only one vlan_tag bit can be set. */
7441 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
7442 		return;
7443 	}
7444 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
7445 		 rte_be_to_cpu_16(vlan_m->inner_type));
7446 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype,
7447 		 rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type));
7448 }
7449 
7450 /**
7451  * Add IPV4 item to matcher and to the value.
7452  *
7453  * @param[in, out] matcher
7454  *   Flow matcher.
7455  * @param[in, out] key
7456  *   Flow matcher value.
7457  * @param[in] item
7458  *   Flow pattern to translate.
7459  * @param[in] inner
7460  *   Item is inner pattern.
7461  * @param[in] group
7462  *   The group to insert the rule.
7463  */
7464 static void
7465 flow_dv_translate_item_ipv4(void *matcher, void *key,
7466 			    const struct rte_flow_item *item,
7467 			    int inner, uint32_t group)
7468 {
7469 	const struct rte_flow_item_ipv4 *ipv4_m = item->mask;
7470 	const struct rte_flow_item_ipv4 *ipv4_v = item->spec;
7471 	const struct rte_flow_item_ipv4 nic_mask = {
7472 		.hdr = {
7473 			.src_addr = RTE_BE32(0xffffffff),
7474 			.dst_addr = RTE_BE32(0xffffffff),
7475 			.type_of_service = 0xff,
7476 			.next_proto_id = 0xff,
7477 			.time_to_live = 0xff,
7478 		},
7479 	};
7480 	void *headers_m;
7481 	void *headers_v;
7482 	char *l24_m;
7483 	char *l24_v;
7484 	uint8_t tos;
7485 
7486 	if (inner) {
7487 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7488 					 inner_headers);
7489 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
7490 	} else {
7491 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7492 					 outer_headers);
7493 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
7494 	}
7495 	flow_dv_set_match_ip_version(group, headers_v, headers_m, 4);
7496 	if (!ipv4_v)
7497 		return;
7498 	if (!ipv4_m)
7499 		ipv4_m = &nic_mask;
7500 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
7501 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
7502 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
7503 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
7504 	*(uint32_t *)l24_m = ipv4_m->hdr.dst_addr;
7505 	*(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr;
7506 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
7507 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
7508 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
7509 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
7510 	*(uint32_t *)l24_m = ipv4_m->hdr.src_addr;
7511 	*(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr;
7512 	tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service;
7513 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn,
7514 		 ipv4_m->hdr.type_of_service);
7515 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos);
7516 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp,
7517 		 ipv4_m->hdr.type_of_service >> 2);
7518 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2);
7519 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
7520 		 ipv4_m->hdr.next_proto_id);
7521 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
7522 		 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id);
7523 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
7524 		 ipv4_m->hdr.time_to_live);
7525 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
7526 		 ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live);
7527 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
7528 		 !!(ipv4_m->hdr.fragment_offset));
7529 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
7530 		 !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset));
7531 }
7532 
7533 /**
7534  * Add IPV6 item to matcher and to the value.
7535  *
7536  * @param[in, out] matcher
7537  *   Flow matcher.
7538  * @param[in, out] key
7539  *   Flow matcher value.
7540  * @param[in] item
7541  *   Flow pattern to translate.
7542  * @param[in] inner
7543  *   Item is inner pattern.
7544  * @param[in] group
7545  *   The group to insert the rule.
7546  */
7547 static void
7548 flow_dv_translate_item_ipv6(void *matcher, void *key,
7549 			    const struct rte_flow_item *item,
7550 			    int inner, uint32_t group)
7551 {
7552 	const struct rte_flow_item_ipv6 *ipv6_m = item->mask;
7553 	const struct rte_flow_item_ipv6 *ipv6_v = item->spec;
7554 	const struct rte_flow_item_ipv6 nic_mask = {
7555 		.hdr = {
7556 			.src_addr =
7557 				"\xff\xff\xff\xff\xff\xff\xff\xff"
7558 				"\xff\xff\xff\xff\xff\xff\xff\xff",
7559 			.dst_addr =
7560 				"\xff\xff\xff\xff\xff\xff\xff\xff"
7561 				"\xff\xff\xff\xff\xff\xff\xff\xff",
7562 			.vtc_flow = RTE_BE32(0xffffffff),
7563 			.proto = 0xff,
7564 			.hop_limits = 0xff,
7565 		},
7566 	};
7567 	void *headers_m;
7568 	void *headers_v;
7569 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
7570 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
7571 	char *l24_m;
7572 	char *l24_v;
7573 	uint32_t vtc_m;
7574 	uint32_t vtc_v;
7575 	int i;
7576 	int size;
7577 
7578 	if (inner) {
7579 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7580 					 inner_headers);
7581 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
7582 	} else {
7583 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7584 					 outer_headers);
7585 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
7586 	}
7587 	flow_dv_set_match_ip_version(group, headers_v, headers_m, 6);
7588 	if (!ipv6_v)
7589 		return;
7590 	if (!ipv6_m)
7591 		ipv6_m = &nic_mask;
7592 	size = sizeof(ipv6_m->hdr.dst_addr);
7593 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
7594 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
7595 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
7596 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
7597 	memcpy(l24_m, ipv6_m->hdr.dst_addr, size);
7598 	for (i = 0; i < size; ++i)
7599 		l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i];
7600 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
7601 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
7602 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
7603 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
7604 	memcpy(l24_m, ipv6_m->hdr.src_addr, size);
7605 	for (i = 0; i < size; ++i)
7606 		l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i];
7607 	/* TOS. */
7608 	vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow);
7609 	vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow);
7610 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20);
7611 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20);
7612 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22);
7613 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22);
7614 	/* Label. */
7615 	if (inner) {
7616 		MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label,
7617 			 vtc_m);
7618 		MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label,
7619 			 vtc_v);
7620 	} else {
7621 		MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label,
7622 			 vtc_m);
7623 		MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label,
7624 			 vtc_v);
7625 	}
7626 	/* Protocol. */
7627 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
7628 		 ipv6_m->hdr.proto);
7629 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
7630 		 ipv6_v->hdr.proto & ipv6_m->hdr.proto);
7631 	/* Hop limit. */
7632 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
7633 		 ipv6_m->hdr.hop_limits);
7634 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
7635 		 ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits);
7636 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
7637 		 !!(ipv6_m->has_frag_ext));
7638 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
7639 		 !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext));
7640 }
7641 
7642 /**
7643  * Add IPV6 fragment extension item to matcher and to the value.
7644  *
7645  * @param[in, out] matcher
7646  *   Flow matcher.
7647  * @param[in, out] key
7648  *   Flow matcher value.
7649  * @param[in] item
7650  *   Flow pattern to translate.
7651  * @param[in] inner
7652  *   Item is inner pattern.
7653  */
7654 static void
7655 flow_dv_translate_item_ipv6_frag_ext(void *matcher, void *key,
7656 				     const struct rte_flow_item *item,
7657 				     int inner)
7658 {
7659 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m = item->mask;
7660 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v = item->spec;
7661 	const struct rte_flow_item_ipv6_frag_ext nic_mask = {
7662 		.hdr = {
7663 			.next_header = 0xff,
7664 			.frag_data = RTE_BE16(0xffff),
7665 		},
7666 	};
7667 	void *headers_m;
7668 	void *headers_v;
7669 
7670 	if (inner) {
7671 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7672 					 inner_headers);
7673 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
7674 	} else {
7675 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7676 					 outer_headers);
7677 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
7678 	}
7679 	/* IPv6 fragment extension item exists, so packet is IP fragment. */
7680 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 1);
7681 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1);
7682 	if (!ipv6_frag_ext_v)
7683 		return;
7684 	if (!ipv6_frag_ext_m)
7685 		ipv6_frag_ext_m = &nic_mask;
7686 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
7687 		 ipv6_frag_ext_m->hdr.next_header);
7688 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
7689 		 ipv6_frag_ext_v->hdr.next_header &
7690 		 ipv6_frag_ext_m->hdr.next_header);
7691 }
7692 
7693 /**
7694  * Add TCP item to matcher and to the value.
7695  *
7696  * @param[in, out] matcher
7697  *   Flow matcher.
7698  * @param[in, out] key
7699  *   Flow matcher value.
7700  * @param[in] item
7701  *   Flow pattern to translate.
7702  * @param[in] inner
7703  *   Item is inner pattern.
7704  */
7705 static void
7706 flow_dv_translate_item_tcp(void *matcher, void *key,
7707 			   const struct rte_flow_item *item,
7708 			   int inner)
7709 {
7710 	const struct rte_flow_item_tcp *tcp_m = item->mask;
7711 	const struct rte_flow_item_tcp *tcp_v = item->spec;
7712 	void *headers_m;
7713 	void *headers_v;
7714 
7715 	if (inner) {
7716 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7717 					 inner_headers);
7718 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
7719 	} else {
7720 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7721 					 outer_headers);
7722 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
7723 	}
7724 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
7725 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP);
7726 	if (!tcp_v)
7727 		return;
7728 	if (!tcp_m)
7729 		tcp_m = &rte_flow_item_tcp_mask;
7730 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport,
7731 		 rte_be_to_cpu_16(tcp_m->hdr.src_port));
7732 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
7733 		 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port));
7734 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport,
7735 		 rte_be_to_cpu_16(tcp_m->hdr.dst_port));
7736 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
7737 		 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port));
7738 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags,
7739 		 tcp_m->hdr.tcp_flags);
7740 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
7741 		 (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags));
7742 }
7743 
7744 /**
7745  * Add UDP item to matcher and to the value.
7746  *
7747  * @param[in, out] matcher
7748  *   Flow matcher.
7749  * @param[in, out] key
7750  *   Flow matcher value.
7751  * @param[in] item
7752  *   Flow pattern to translate.
7753  * @param[in] inner
7754  *   Item is inner pattern.
7755  */
7756 static void
7757 flow_dv_translate_item_udp(void *matcher, void *key,
7758 			   const struct rte_flow_item *item,
7759 			   int inner)
7760 {
7761 	const struct rte_flow_item_udp *udp_m = item->mask;
7762 	const struct rte_flow_item_udp *udp_v = item->spec;
7763 	void *headers_m;
7764 	void *headers_v;
7765 
7766 	if (inner) {
7767 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7768 					 inner_headers);
7769 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
7770 	} else {
7771 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7772 					 outer_headers);
7773 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
7774 	}
7775 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
7776 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
7777 	if (!udp_v)
7778 		return;
7779 	if (!udp_m)
7780 		udp_m = &rte_flow_item_udp_mask;
7781 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport,
7782 		 rte_be_to_cpu_16(udp_m->hdr.src_port));
7783 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
7784 		 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port));
7785 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport,
7786 		 rte_be_to_cpu_16(udp_m->hdr.dst_port));
7787 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
7788 		 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port));
7789 }
7790 
7791 /**
7792  * Add GRE optional Key item to matcher and to the value.
7793  *
7794  * @param[in, out] matcher
7795  *   Flow matcher.
7796  * @param[in, out] key
7797  *   Flow matcher value.
7798  * @param[in] item
7799  *   Flow pattern to translate.
7800  * @param[in] inner
7801  *   Item is inner pattern.
7802  */
7803 static void
7804 flow_dv_translate_item_gre_key(void *matcher, void *key,
7805 				   const struct rte_flow_item *item)
7806 {
7807 	const rte_be32_t *key_m = item->mask;
7808 	const rte_be32_t *key_v = item->spec;
7809 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
7810 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
7811 	rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX);
7812 
7813 	/* GRE K bit must be on and should already be validated */
7814 	MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1);
7815 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1);
7816 	if (!key_v)
7817 		return;
7818 	if (!key_m)
7819 		key_m = &gre_key_default_mask;
7820 	MLX5_SET(fte_match_set_misc, misc_m, gre_key_h,
7821 		 rte_be_to_cpu_32(*key_m) >> 8);
7822 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_h,
7823 		 rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8);
7824 	MLX5_SET(fte_match_set_misc, misc_m, gre_key_l,
7825 		 rte_be_to_cpu_32(*key_m) & 0xFF);
7826 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_l,
7827 		 rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF);
7828 }
7829 
7830 /**
7831  * Add GRE item to matcher and to the value.
7832  *
7833  * @param[in, out] matcher
7834  *   Flow matcher.
7835  * @param[in, out] key
7836  *   Flow matcher value.
7837  * @param[in] item
7838  *   Flow pattern to translate.
7839  * @param[in] inner
7840  *   Item is inner pattern.
7841  */
7842 static void
7843 flow_dv_translate_item_gre(void *matcher, void *key,
7844 			   const struct rte_flow_item *item,
7845 			   int inner)
7846 {
7847 	const struct rte_flow_item_gre *gre_m = item->mask;
7848 	const struct rte_flow_item_gre *gre_v = item->spec;
7849 	void *headers_m;
7850 	void *headers_v;
7851 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
7852 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
7853 	struct {
7854 		union {
7855 			__extension__
7856 			struct {
7857 				uint16_t version:3;
7858 				uint16_t rsvd0:9;
7859 				uint16_t s_present:1;
7860 				uint16_t k_present:1;
7861 				uint16_t rsvd_bit1:1;
7862 				uint16_t c_present:1;
7863 			};
7864 			uint16_t value;
7865 		};
7866 	} gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v;
7867 
7868 	if (inner) {
7869 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7870 					 inner_headers);
7871 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
7872 	} else {
7873 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7874 					 outer_headers);
7875 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
7876 	}
7877 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
7878 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
7879 	if (!gre_v)
7880 		return;
7881 	if (!gre_m)
7882 		gre_m = &rte_flow_item_gre_mask;
7883 	MLX5_SET(fte_match_set_misc, misc_m, gre_protocol,
7884 		 rte_be_to_cpu_16(gre_m->protocol));
7885 	MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
7886 		 rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol));
7887 	gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver);
7888 	gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver);
7889 	MLX5_SET(fte_match_set_misc, misc_m, gre_c_present,
7890 		 gre_crks_rsvd0_ver_m.c_present);
7891 	MLX5_SET(fte_match_set_misc, misc_v, gre_c_present,
7892 		 gre_crks_rsvd0_ver_v.c_present &
7893 		 gre_crks_rsvd0_ver_m.c_present);
7894 	MLX5_SET(fte_match_set_misc, misc_m, gre_k_present,
7895 		 gre_crks_rsvd0_ver_m.k_present);
7896 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present,
7897 		 gre_crks_rsvd0_ver_v.k_present &
7898 		 gre_crks_rsvd0_ver_m.k_present);
7899 	MLX5_SET(fte_match_set_misc, misc_m, gre_s_present,
7900 		 gre_crks_rsvd0_ver_m.s_present);
7901 	MLX5_SET(fte_match_set_misc, misc_v, gre_s_present,
7902 		 gre_crks_rsvd0_ver_v.s_present &
7903 		 gre_crks_rsvd0_ver_m.s_present);
7904 }
7905 
7906 /**
7907  * Add NVGRE item to matcher and to the value.
7908  *
7909  * @param[in, out] matcher
7910  *   Flow matcher.
7911  * @param[in, out] key
7912  *   Flow matcher value.
7913  * @param[in] item
7914  *   Flow pattern to translate.
7915  * @param[in] inner
7916  *   Item is inner pattern.
7917  */
7918 static void
7919 flow_dv_translate_item_nvgre(void *matcher, void *key,
7920 			     const struct rte_flow_item *item,
7921 			     int inner)
7922 {
7923 	const struct rte_flow_item_nvgre *nvgre_m = item->mask;
7924 	const struct rte_flow_item_nvgre *nvgre_v = item->spec;
7925 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
7926 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
7927 	const char *tni_flow_id_m;
7928 	const char *tni_flow_id_v;
7929 	char *gre_key_m;
7930 	char *gre_key_v;
7931 	int size;
7932 	int i;
7933 
7934 	/* For NVGRE, GRE header fields must be set with defined values. */
7935 	const struct rte_flow_item_gre gre_spec = {
7936 		.c_rsvd0_ver = RTE_BE16(0x2000),
7937 		.protocol = RTE_BE16(RTE_ETHER_TYPE_TEB)
7938 	};
7939 	const struct rte_flow_item_gre gre_mask = {
7940 		.c_rsvd0_ver = RTE_BE16(0xB000),
7941 		.protocol = RTE_BE16(UINT16_MAX),
7942 	};
7943 	const struct rte_flow_item gre_item = {
7944 		.spec = &gre_spec,
7945 		.mask = &gre_mask,
7946 		.last = NULL,
7947 	};
7948 	flow_dv_translate_item_gre(matcher, key, &gre_item, inner);
7949 	if (!nvgre_v)
7950 		return;
7951 	if (!nvgre_m)
7952 		nvgre_m = &rte_flow_item_nvgre_mask;
7953 	tni_flow_id_m = (const char *)nvgre_m->tni;
7954 	tni_flow_id_v = (const char *)nvgre_v->tni;
7955 	size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
7956 	gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h);
7957 	gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
7958 	memcpy(gre_key_m, tni_flow_id_m, size);
7959 	for (i = 0; i < size; ++i)
7960 		gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i];
7961 }
7962 
7963 /**
7964  * Add VXLAN item to matcher and to the value.
7965  *
7966  * @param[in, out] matcher
7967  *   Flow matcher.
7968  * @param[in, out] key
7969  *   Flow matcher value.
7970  * @param[in] item
7971  *   Flow pattern to translate.
7972  * @param[in] inner
7973  *   Item is inner pattern.
7974  */
7975 static void
7976 flow_dv_translate_item_vxlan(void *matcher, void *key,
7977 			     const struct rte_flow_item *item,
7978 			     int inner)
7979 {
7980 	const struct rte_flow_item_vxlan *vxlan_m = item->mask;
7981 	const struct rte_flow_item_vxlan *vxlan_v = item->spec;
7982 	void *headers_m;
7983 	void *headers_v;
7984 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
7985 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
7986 	char *vni_m;
7987 	char *vni_v;
7988 	uint16_t dport;
7989 	int size;
7990 	int i;
7991 
7992 	if (inner) {
7993 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7994 					 inner_headers);
7995 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
7996 	} else {
7997 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
7998 					 outer_headers);
7999 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8000 	}
8001 	dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
8002 		MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
8003 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8004 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8005 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8006 	}
8007 	if (!vxlan_v)
8008 		return;
8009 	if (!vxlan_m)
8010 		vxlan_m = &rte_flow_item_vxlan_mask;
8011 	size = sizeof(vxlan_m->vni);
8012 	vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni);
8013 	vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni);
8014 	memcpy(vni_m, vxlan_m->vni, size);
8015 	for (i = 0; i < size; ++i)
8016 		vni_v[i] = vni_m[i] & vxlan_v->vni[i];
8017 }
8018 
8019 /**
8020  * Add VXLAN-GPE item to matcher and to the value.
8021  *
8022  * @param[in, out] matcher
8023  *   Flow matcher.
8024  * @param[in, out] key
8025  *   Flow matcher value.
8026  * @param[in] item
8027  *   Flow pattern to translate.
8028  * @param[in] inner
8029  *   Item is inner pattern.
8030  */
8031 
8032 static void
8033 flow_dv_translate_item_vxlan_gpe(void *matcher, void *key,
8034 				 const struct rte_flow_item *item, int inner)
8035 {
8036 	const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask;
8037 	const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec;
8038 	void *headers_m;
8039 	void *headers_v;
8040 	void *misc_m =
8041 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_3);
8042 	void *misc_v =
8043 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
8044 	char *vni_m;
8045 	char *vni_v;
8046 	uint16_t dport;
8047 	int size;
8048 	int i;
8049 	uint8_t flags_m = 0xff;
8050 	uint8_t flags_v = 0xc;
8051 
8052 	if (inner) {
8053 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8054 					 inner_headers);
8055 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8056 	} else {
8057 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8058 					 outer_headers);
8059 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8060 	}
8061 	dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
8062 		MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
8063 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8064 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8065 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8066 	}
8067 	if (!vxlan_v)
8068 		return;
8069 	if (!vxlan_m)
8070 		vxlan_m = &rte_flow_item_vxlan_gpe_mask;
8071 	size = sizeof(vxlan_m->vni);
8072 	vni_m = MLX5_ADDR_OF(fte_match_set_misc3, misc_m, outer_vxlan_gpe_vni);
8073 	vni_v = MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni);
8074 	memcpy(vni_m, vxlan_m->vni, size);
8075 	for (i = 0; i < size; ++i)
8076 		vni_v[i] = vni_m[i] & vxlan_v->vni[i];
8077 	if (vxlan_m->flags) {
8078 		flags_m = vxlan_m->flags;
8079 		flags_v = vxlan_v->flags;
8080 	}
8081 	MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_flags, flags_m);
8082 	MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_flags, flags_v);
8083 	MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_next_protocol,
8084 		 vxlan_m->protocol);
8085 	MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_next_protocol,
8086 		 vxlan_v->protocol);
8087 }
8088 
8089 /**
8090  * Add Geneve item to matcher and to the value.
8091  *
8092  * @param[in, out] matcher
8093  *   Flow matcher.
8094  * @param[in, out] key
8095  *   Flow matcher value.
8096  * @param[in] item
8097  *   Flow pattern to translate.
8098  * @param[in] inner
8099  *   Item is inner pattern.
8100  */
8101 
8102 static void
8103 flow_dv_translate_item_geneve(void *matcher, void *key,
8104 			      const struct rte_flow_item *item, int inner)
8105 {
8106 	const struct rte_flow_item_geneve *geneve_m = item->mask;
8107 	const struct rte_flow_item_geneve *geneve_v = item->spec;
8108 	void *headers_m;
8109 	void *headers_v;
8110 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8111 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8112 	uint16_t dport;
8113 	uint16_t gbhdr_m;
8114 	uint16_t gbhdr_v;
8115 	char *vni_m;
8116 	char *vni_v;
8117 	size_t size, i;
8118 
8119 	if (inner) {
8120 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8121 					 inner_headers);
8122 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8123 	} else {
8124 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8125 					 outer_headers);
8126 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8127 	}
8128 	dport = MLX5_UDP_PORT_GENEVE;
8129 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8130 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8131 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8132 	}
8133 	if (!geneve_v)
8134 		return;
8135 	if (!geneve_m)
8136 		geneve_m = &rte_flow_item_geneve_mask;
8137 	size = sizeof(geneve_m->vni);
8138 	vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, geneve_vni);
8139 	vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni);
8140 	memcpy(vni_m, geneve_m->vni, size);
8141 	for (i = 0; i < size; ++i)
8142 		vni_v[i] = vni_m[i] & geneve_v->vni[i];
8143 	MLX5_SET(fte_match_set_misc, misc_m, geneve_protocol_type,
8144 		 rte_be_to_cpu_16(geneve_m->protocol));
8145 	MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type,
8146 		 rte_be_to_cpu_16(geneve_v->protocol & geneve_m->protocol));
8147 	gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0);
8148 	gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0);
8149 	MLX5_SET(fte_match_set_misc, misc_m, geneve_oam,
8150 		 MLX5_GENEVE_OAMF_VAL(gbhdr_m));
8151 	MLX5_SET(fte_match_set_misc, misc_v, geneve_oam,
8152 		 MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m));
8153 	MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
8154 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
8155 	MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
8156 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) &
8157 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
8158 }
8159 
8160 /**
8161  * Create Geneve TLV option resource.
8162  *
8163  * @param dev[in, out]
8164  *   Pointer to rte_eth_dev structure.
8165  * @param[in, out] tag_be24
8166  *   Tag value in big endian then R-shift 8.
8167  * @parm[in, out] dev_flow
8168  *   Pointer to the dev_flow.
8169  * @param[out] error
8170  *   pointer to error structure.
8171  *
8172  * @return
8173  *   0 on success otherwise -errno and errno is set.
8174  */
8175 
8176 int
8177 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev,
8178 					     const struct rte_flow_item *item,
8179 					     struct rte_flow_error *error)
8180 {
8181 	struct mlx5_priv *priv = dev->data->dev_private;
8182 	struct mlx5_dev_ctx_shared *sh = priv->sh;
8183 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
8184 			sh->geneve_tlv_option_resource;
8185 	struct mlx5_devx_obj *obj;
8186 	const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
8187 	int ret = 0;
8188 
8189 	if (!geneve_opt_v)
8190 		return -1;
8191 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
8192 	if (geneve_opt_resource != NULL) {
8193 		if (geneve_opt_resource->option_class ==
8194 			geneve_opt_v->option_class &&
8195 			geneve_opt_resource->option_type ==
8196 			geneve_opt_v->option_type &&
8197 			geneve_opt_resource->length ==
8198 			geneve_opt_v->option_len) {
8199 			/* We already have GENVE TLV option obj allocated. */
8200 			__atomic_fetch_add(&geneve_opt_resource->refcnt, 1,
8201 					   __ATOMIC_RELAXED);
8202 		} else {
8203 			ret = rte_flow_error_set(error, ENOMEM,
8204 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8205 				"Only one GENEVE TLV option supported");
8206 			goto exit;
8207 		}
8208 	} else {
8209 		/* Create a GENEVE TLV object and resource. */
8210 		obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->ctx,
8211 				geneve_opt_v->option_class,
8212 				geneve_opt_v->option_type,
8213 				geneve_opt_v->option_len);
8214 		if (!obj) {
8215 			ret = rte_flow_error_set(error, ENODATA,
8216 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8217 				"Failed to create GENEVE TLV Devx object");
8218 			goto exit;
8219 		}
8220 		sh->geneve_tlv_option_resource =
8221 				mlx5_malloc(MLX5_MEM_ZERO,
8222 						sizeof(*geneve_opt_resource),
8223 						0, SOCKET_ID_ANY);
8224 		if (!sh->geneve_tlv_option_resource) {
8225 			claim_zero(mlx5_devx_cmd_destroy(obj));
8226 			ret = rte_flow_error_set(error, ENOMEM,
8227 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8228 				"GENEVE TLV object memory allocation failed");
8229 			goto exit;
8230 		}
8231 		geneve_opt_resource = sh->geneve_tlv_option_resource;
8232 		geneve_opt_resource->obj = obj;
8233 		geneve_opt_resource->option_class = geneve_opt_v->option_class;
8234 		geneve_opt_resource->option_type = geneve_opt_v->option_type;
8235 		geneve_opt_resource->length = geneve_opt_v->option_len;
8236 		__atomic_store_n(&geneve_opt_resource->refcnt, 1,
8237 				__ATOMIC_RELAXED);
8238 	}
8239 exit:
8240 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
8241 	return ret;
8242 }
8243 
8244 /**
8245  * Add Geneve TLV option item to matcher.
8246  *
8247  * @param[in, out] dev
8248  *   Pointer to rte_eth_dev structure.
8249  * @param[in, out] matcher
8250  *   Flow matcher.
8251  * @param[in, out] key
8252  *   Flow matcher value.
8253  * @param[in] item
8254  *   Flow pattern to translate.
8255  * @param[out] error
8256  *   Pointer to error structure.
8257  */
8258 static int
8259 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *matcher,
8260 				  void *key, const struct rte_flow_item *item,
8261 				  struct rte_flow_error *error)
8262 {
8263 	const struct rte_flow_item_geneve_opt *geneve_opt_m = item->mask;
8264 	const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
8265 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8266 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8267 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
8268 			misc_parameters_3);
8269 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
8270 	rte_be32_t opt_data_key = 0, opt_data_mask = 0;
8271 	int ret = 0;
8272 
8273 	if (!geneve_opt_v)
8274 		return -1;
8275 	if (!geneve_opt_m)
8276 		geneve_opt_m = &rte_flow_item_geneve_opt_mask;
8277 	ret = flow_dev_geneve_tlv_option_resource_register(dev, item,
8278 							   error);
8279 	if (ret) {
8280 		DRV_LOG(ERR, "Failed to create geneve_tlv_obj");
8281 		return ret;
8282 	}
8283 	/*
8284 	 * Set the option length in GENEVE header if not requested.
8285 	 * The GENEVE TLV option length is expressed by the option length field
8286 	 * in the GENEVE header.
8287 	 * If the option length was not requested but the GENEVE TLV option item
8288 	 * is present we set the option length field implicitly.
8289 	 */
8290 	if (!MLX5_GET16(fte_match_set_misc, misc_m, geneve_opt_len)) {
8291 		MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
8292 			 MLX5_GENEVE_OPTLEN_MASK);
8293 		MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
8294 			 geneve_opt_v->option_len + 1);
8295 	}
8296 	/* Set the data. */
8297 	if (geneve_opt_v->data) {
8298 		memcpy(&opt_data_key, geneve_opt_v->data,
8299 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
8300 				sizeof(opt_data_key)));
8301 		MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
8302 				sizeof(opt_data_key));
8303 		memcpy(&opt_data_mask, geneve_opt_m->data,
8304 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
8305 				sizeof(opt_data_mask)));
8306 		MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
8307 				sizeof(opt_data_mask));
8308 		MLX5_SET(fte_match_set_misc3, misc3_m,
8309 				geneve_tlv_option_0_data,
8310 				rte_be_to_cpu_32(opt_data_mask));
8311 		MLX5_SET(fte_match_set_misc3, misc3_v,
8312 				geneve_tlv_option_0_data,
8313 			rte_be_to_cpu_32(opt_data_key & opt_data_mask));
8314 	}
8315 	return ret;
8316 }
8317 
8318 /**
8319  * Add MPLS item to matcher and to the value.
8320  *
8321  * @param[in, out] matcher
8322  *   Flow matcher.
8323  * @param[in, out] key
8324  *   Flow matcher value.
8325  * @param[in] item
8326  *   Flow pattern to translate.
8327  * @param[in] prev_layer
8328  *   The protocol layer indicated in previous item.
8329  * @param[in] inner
8330  *   Item is inner pattern.
8331  */
8332 static void
8333 flow_dv_translate_item_mpls(void *matcher, void *key,
8334 			    const struct rte_flow_item *item,
8335 			    uint64_t prev_layer,
8336 			    int inner)
8337 {
8338 	const uint32_t *in_mpls_m = item->mask;
8339 	const uint32_t *in_mpls_v = item->spec;
8340 	uint32_t *out_mpls_m = 0;
8341 	uint32_t *out_mpls_v = 0;
8342 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8343 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8344 	void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher,
8345 				     misc_parameters_2);
8346 	void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
8347 	void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
8348 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8349 
8350 	switch (prev_layer) {
8351 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
8352 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff);
8353 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
8354 			 MLX5_UDP_PORT_MPLS);
8355 		break;
8356 	case MLX5_FLOW_LAYER_GRE:
8357 		MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff);
8358 		MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
8359 			 RTE_ETHER_TYPE_MPLS);
8360 		break;
8361 	default:
8362 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8363 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8364 			 IPPROTO_MPLS);
8365 		break;
8366 	}
8367 	if (!in_mpls_v)
8368 		return;
8369 	if (!in_mpls_m)
8370 		in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask;
8371 	switch (prev_layer) {
8372 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
8373 		out_mpls_m =
8374 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
8375 						 outer_first_mpls_over_udp);
8376 		out_mpls_v =
8377 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
8378 						 outer_first_mpls_over_udp);
8379 		break;
8380 	case MLX5_FLOW_LAYER_GRE:
8381 		out_mpls_m =
8382 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
8383 						 outer_first_mpls_over_gre);
8384 		out_mpls_v =
8385 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
8386 						 outer_first_mpls_over_gre);
8387 		break;
8388 	default:
8389 		/* Inner MPLS not over GRE is not supported. */
8390 		if (!inner) {
8391 			out_mpls_m =
8392 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
8393 							 misc2_m,
8394 							 outer_first_mpls);
8395 			out_mpls_v =
8396 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
8397 							 misc2_v,
8398 							 outer_first_mpls);
8399 		}
8400 		break;
8401 	}
8402 	if (out_mpls_m && out_mpls_v) {
8403 		*out_mpls_m = *in_mpls_m;
8404 		*out_mpls_v = *in_mpls_v & *in_mpls_m;
8405 	}
8406 }
8407 
8408 /**
8409  * Add metadata register item to matcher
8410  *
8411  * @param[in, out] matcher
8412  *   Flow matcher.
8413  * @param[in, out] key
8414  *   Flow matcher value.
8415  * @param[in] reg_type
8416  *   Type of device metadata register
8417  * @param[in] value
8418  *   Register value
8419  * @param[in] mask
8420  *   Register mask
8421  */
8422 static void
8423 flow_dv_match_meta_reg(void *matcher, void *key,
8424 		       enum modify_reg reg_type,
8425 		       uint32_t data, uint32_t mask)
8426 {
8427 	void *misc2_m =
8428 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2);
8429 	void *misc2_v =
8430 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
8431 	uint32_t temp;
8432 
8433 	data &= mask;
8434 	switch (reg_type) {
8435 	case REG_A:
8436 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a, mask);
8437 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data);
8438 		break;
8439 	case REG_B:
8440 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_b, mask);
8441 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data);
8442 		break;
8443 	case REG_C_0:
8444 		/*
8445 		 * The metadata register C0 field might be divided into
8446 		 * source vport index and META item value, we should set
8447 		 * this field according to specified mask, not as whole one.
8448 		 */
8449 		temp = MLX5_GET(fte_match_set_misc2, misc2_m, metadata_reg_c_0);
8450 		temp |= mask;
8451 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_0, temp);
8452 		temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0);
8453 		temp &= ~mask;
8454 		temp |= data;
8455 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp);
8456 		break;
8457 	case REG_C_1:
8458 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_1, mask);
8459 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data);
8460 		break;
8461 	case REG_C_2:
8462 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_2, mask);
8463 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data);
8464 		break;
8465 	case REG_C_3:
8466 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_3, mask);
8467 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data);
8468 		break;
8469 	case REG_C_4:
8470 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_4, mask);
8471 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data);
8472 		break;
8473 	case REG_C_5:
8474 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_5, mask);
8475 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data);
8476 		break;
8477 	case REG_C_6:
8478 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_6, mask);
8479 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data);
8480 		break;
8481 	case REG_C_7:
8482 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_7, mask);
8483 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data);
8484 		break;
8485 	default:
8486 		MLX5_ASSERT(false);
8487 		break;
8488 	}
8489 }
8490 
8491 /**
8492  * Add MARK item to matcher
8493  *
8494  * @param[in] dev
8495  *   The device to configure through.
8496  * @param[in, out] matcher
8497  *   Flow matcher.
8498  * @param[in, out] key
8499  *   Flow matcher value.
8500  * @param[in] item
8501  *   Flow pattern to translate.
8502  */
8503 static void
8504 flow_dv_translate_item_mark(struct rte_eth_dev *dev,
8505 			    void *matcher, void *key,
8506 			    const struct rte_flow_item *item)
8507 {
8508 	struct mlx5_priv *priv = dev->data->dev_private;
8509 	const struct rte_flow_item_mark *mark;
8510 	uint32_t value;
8511 	uint32_t mask;
8512 
8513 	mark = item->mask ? (const void *)item->mask :
8514 			    &rte_flow_item_mark_mask;
8515 	mask = mark->id & priv->sh->dv_mark_mask;
8516 	mark = (const void *)item->spec;
8517 	MLX5_ASSERT(mark);
8518 	value = mark->id & priv->sh->dv_mark_mask & mask;
8519 	if (mask) {
8520 		enum modify_reg reg;
8521 
8522 		/* Get the metadata register index for the mark. */
8523 		reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL);
8524 		MLX5_ASSERT(reg > 0);
8525 		if (reg == REG_C_0) {
8526 			struct mlx5_priv *priv = dev->data->dev_private;
8527 			uint32_t msk_c0 = priv->sh->dv_regc0_mask;
8528 			uint32_t shl_c0 = rte_bsf32(msk_c0);
8529 
8530 			mask &= msk_c0;
8531 			mask <<= shl_c0;
8532 			value <<= shl_c0;
8533 		}
8534 		flow_dv_match_meta_reg(matcher, key, reg, value, mask);
8535 	}
8536 }
8537 
8538 /**
8539  * Add META item to matcher
8540  *
8541  * @param[in] dev
8542  *   The devich to configure through.
8543  * @param[in, out] matcher
8544  *   Flow matcher.
8545  * @param[in, out] key
8546  *   Flow matcher value.
8547  * @param[in] attr
8548  *   Attributes of flow that includes this item.
8549  * @param[in] item
8550  *   Flow pattern to translate.
8551  */
8552 static void
8553 flow_dv_translate_item_meta(struct rte_eth_dev *dev,
8554 			    void *matcher, void *key,
8555 			    const struct rte_flow_attr *attr,
8556 			    const struct rte_flow_item *item)
8557 {
8558 	const struct rte_flow_item_meta *meta_m;
8559 	const struct rte_flow_item_meta *meta_v;
8560 
8561 	meta_m = (const void *)item->mask;
8562 	if (!meta_m)
8563 		meta_m = &rte_flow_item_meta_mask;
8564 	meta_v = (const void *)item->spec;
8565 	if (meta_v) {
8566 		int reg;
8567 		uint32_t value = meta_v->data;
8568 		uint32_t mask = meta_m->data;
8569 
8570 		reg = flow_dv_get_metadata_reg(dev, attr, NULL);
8571 		if (reg < 0)
8572 			return;
8573 		MLX5_ASSERT(reg != REG_NON);
8574 		/*
8575 		 * In datapath code there is no endianness
8576 		 * coversions for perfromance reasons, all
8577 		 * pattern conversions are done in rte_flow.
8578 		 */
8579 		value = rte_cpu_to_be_32(value);
8580 		mask = rte_cpu_to_be_32(mask);
8581 		if (reg == REG_C_0) {
8582 			struct mlx5_priv *priv = dev->data->dev_private;
8583 			uint32_t msk_c0 = priv->sh->dv_regc0_mask;
8584 			uint32_t shl_c0 = rte_bsf32(msk_c0);
8585 #if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
8586 			uint32_t shr_c0 = __builtin_clz(priv->sh->dv_meta_mask);
8587 
8588 			value >>= shr_c0;
8589 			mask >>= shr_c0;
8590 #endif
8591 			value <<= shl_c0;
8592 			mask <<= shl_c0;
8593 			MLX5_ASSERT(msk_c0);
8594 			MLX5_ASSERT(!(~msk_c0 & mask));
8595 		}
8596 		flow_dv_match_meta_reg(matcher, key, reg, value, mask);
8597 	}
8598 }
8599 
8600 /**
8601  * Add vport metadata Reg C0 item to matcher
8602  *
8603  * @param[in, out] matcher
8604  *   Flow matcher.
8605  * @param[in, out] key
8606  *   Flow matcher value.
8607  * @param[in] reg
8608  *   Flow pattern to translate.
8609  */
8610 static void
8611 flow_dv_translate_item_meta_vport(void *matcher, void *key,
8612 				  uint32_t value, uint32_t mask)
8613 {
8614 	flow_dv_match_meta_reg(matcher, key, REG_C_0, value, mask);
8615 }
8616 
8617 /**
8618  * Add tag item to matcher
8619  *
8620  * @param[in] dev
8621  *   The devich to configure through.
8622  * @param[in, out] matcher
8623  *   Flow matcher.
8624  * @param[in, out] key
8625  *   Flow matcher value.
8626  * @param[in] item
8627  *   Flow pattern to translate.
8628  */
8629 static void
8630 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev,
8631 				void *matcher, void *key,
8632 				const struct rte_flow_item *item)
8633 {
8634 	const struct mlx5_rte_flow_item_tag *tag_v = item->spec;
8635 	const struct mlx5_rte_flow_item_tag *tag_m = item->mask;
8636 	uint32_t mask, value;
8637 
8638 	MLX5_ASSERT(tag_v);
8639 	value = tag_v->data;
8640 	mask = tag_m ? tag_m->data : UINT32_MAX;
8641 	if (tag_v->id == REG_C_0) {
8642 		struct mlx5_priv *priv = dev->data->dev_private;
8643 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
8644 		uint32_t shl_c0 = rte_bsf32(msk_c0);
8645 
8646 		mask &= msk_c0;
8647 		mask <<= shl_c0;
8648 		value <<= shl_c0;
8649 	}
8650 	flow_dv_match_meta_reg(matcher, key, tag_v->id, value, mask);
8651 }
8652 
8653 /**
8654  * Add TAG item to matcher
8655  *
8656  * @param[in] dev
8657  *   The devich to configure through.
8658  * @param[in, out] matcher
8659  *   Flow matcher.
8660  * @param[in, out] key
8661  *   Flow matcher value.
8662  * @param[in] item
8663  *   Flow pattern to translate.
8664  */
8665 static void
8666 flow_dv_translate_item_tag(struct rte_eth_dev *dev,
8667 			   void *matcher, void *key,
8668 			   const struct rte_flow_item *item)
8669 {
8670 	const struct rte_flow_item_tag *tag_v = item->spec;
8671 	const struct rte_flow_item_tag *tag_m = item->mask;
8672 	enum modify_reg reg;
8673 
8674 	MLX5_ASSERT(tag_v);
8675 	tag_m = tag_m ? tag_m : &rte_flow_item_tag_mask;
8676 	/* Get the metadata register index for the tag. */
8677 	reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, tag_v->index, NULL);
8678 	MLX5_ASSERT(reg > 0);
8679 	flow_dv_match_meta_reg(matcher, key, reg, tag_v->data, tag_m->data);
8680 }
8681 
8682 /**
8683  * Add source vport match to the specified matcher.
8684  *
8685  * @param[in, out] matcher
8686  *   Flow matcher.
8687  * @param[in, out] key
8688  *   Flow matcher value.
8689  * @param[in] port
8690  *   Source vport value to match
8691  * @param[in] mask
8692  *   Mask
8693  */
8694 static void
8695 flow_dv_translate_item_source_vport(void *matcher, void *key,
8696 				    int16_t port, uint16_t mask)
8697 {
8698 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8699 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8700 
8701 	MLX5_SET(fte_match_set_misc, misc_m, source_port, mask);
8702 	MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
8703 }
8704 
8705 /**
8706  * Translate port-id item to eswitch match on  port-id.
8707  *
8708  * @param[in] dev
8709  *   The devich to configure through.
8710  * @param[in, out] matcher
8711  *   Flow matcher.
8712  * @param[in, out] key
8713  *   Flow matcher value.
8714  * @param[in] item
8715  *   Flow pattern to translate.
8716  * @param[in]
8717  *   Flow attributes.
8718  *
8719  * @return
8720  *   0 on success, a negative errno value otherwise.
8721  */
8722 static int
8723 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher,
8724 			       void *key, const struct rte_flow_item *item,
8725 			       const struct rte_flow_attr *attr)
8726 {
8727 	const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL;
8728 	const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL;
8729 	struct mlx5_priv *priv;
8730 	uint16_t mask, id;
8731 
8732 	mask = pid_m ? pid_m->id : 0xffff;
8733 	id = pid_v ? pid_v->id : dev->data->port_id;
8734 	priv = mlx5_port_to_eswitch_info(id, item == NULL);
8735 	if (!priv)
8736 		return -rte_errno;
8737 	/*
8738 	 * Translate to vport field or to metadata, depending on mode.
8739 	 * Kernel can use either misc.source_port or half of C0 metadata
8740 	 * register.
8741 	 */
8742 	if (priv->vport_meta_mask) {
8743 		/*
8744 		 * Provide the hint for SW steering library
8745 		 * to insert the flow into ingress domain and
8746 		 * save the extra vport match.
8747 		 */
8748 		if (mask == 0xffff && priv->vport_id == 0xffff &&
8749 		    priv->pf_bond < 0 && attr->transfer)
8750 			flow_dv_translate_item_source_vport
8751 				(matcher, key, priv->vport_id, mask);
8752 		/*
8753 		 * We should always set the vport metadata register,
8754 		 * otherwise the SW steering library can drop
8755 		 * the rule if wire vport metadata value is not zero,
8756 		 * it depends on kernel configuration.
8757 		 */
8758 		flow_dv_translate_item_meta_vport(matcher, key,
8759 						  priv->vport_meta_tag,
8760 						  priv->vport_meta_mask);
8761 	} else {
8762 		flow_dv_translate_item_source_vport(matcher, key,
8763 						    priv->vport_id, mask);
8764 	}
8765 	return 0;
8766 }
8767 
8768 /**
8769  * Add ICMP6 item to matcher and to the value.
8770  *
8771  * @param[in, out] matcher
8772  *   Flow matcher.
8773  * @param[in, out] key
8774  *   Flow matcher value.
8775  * @param[in] item
8776  *   Flow pattern to translate.
8777  * @param[in] inner
8778  *   Item is inner pattern.
8779  */
8780 static void
8781 flow_dv_translate_item_icmp6(void *matcher, void *key,
8782 			      const struct rte_flow_item *item,
8783 			      int inner)
8784 {
8785 	const struct rte_flow_item_icmp6 *icmp6_m = item->mask;
8786 	const struct rte_flow_item_icmp6 *icmp6_v = item->spec;
8787 	void *headers_m;
8788 	void *headers_v;
8789 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
8790 				     misc_parameters_3);
8791 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
8792 	if (inner) {
8793 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8794 					 inner_headers);
8795 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8796 	} else {
8797 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8798 					 outer_headers);
8799 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8800 	}
8801 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
8802 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6);
8803 	if (!icmp6_v)
8804 		return;
8805 	if (!icmp6_m)
8806 		icmp6_m = &rte_flow_item_icmp6_mask;
8807 	MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type);
8808 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type,
8809 		 icmp6_v->type & icmp6_m->type);
8810 	MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code);
8811 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code,
8812 		 icmp6_v->code & icmp6_m->code);
8813 }
8814 
8815 /**
8816  * Add ICMP item to matcher and to the value.
8817  *
8818  * @param[in, out] matcher
8819  *   Flow matcher.
8820  * @param[in, out] key
8821  *   Flow matcher value.
8822  * @param[in] item
8823  *   Flow pattern to translate.
8824  * @param[in] inner
8825  *   Item is inner pattern.
8826  */
8827 static void
8828 flow_dv_translate_item_icmp(void *matcher, void *key,
8829 			    const struct rte_flow_item *item,
8830 			    int inner)
8831 {
8832 	const struct rte_flow_item_icmp *icmp_m = item->mask;
8833 	const struct rte_flow_item_icmp *icmp_v = item->spec;
8834 	uint32_t icmp_header_data_m = 0;
8835 	uint32_t icmp_header_data_v = 0;
8836 	void *headers_m;
8837 	void *headers_v;
8838 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
8839 				     misc_parameters_3);
8840 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
8841 	if (inner) {
8842 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8843 					 inner_headers);
8844 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8845 	} else {
8846 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8847 					 outer_headers);
8848 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8849 	}
8850 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
8851 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP);
8852 	if (!icmp_v)
8853 		return;
8854 	if (!icmp_m)
8855 		icmp_m = &rte_flow_item_icmp_mask;
8856 	MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type,
8857 		 icmp_m->hdr.icmp_type);
8858 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type,
8859 		 icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type);
8860 	MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code,
8861 		 icmp_m->hdr.icmp_code);
8862 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code,
8863 		 icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code);
8864 	icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb);
8865 	icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16;
8866 	if (icmp_header_data_m) {
8867 		icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb);
8868 		icmp_header_data_v |=
8869 			 rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16;
8870 		MLX5_SET(fte_match_set_misc3, misc3_m, icmp_header_data,
8871 			 icmp_header_data_m);
8872 		MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data,
8873 			 icmp_header_data_v & icmp_header_data_m);
8874 	}
8875 }
8876 
8877 /**
8878  * Add GTP item to matcher and to the value.
8879  *
8880  * @param[in, out] matcher
8881  *   Flow matcher.
8882  * @param[in, out] key
8883  *   Flow matcher value.
8884  * @param[in] item
8885  *   Flow pattern to translate.
8886  * @param[in] inner
8887  *   Item is inner pattern.
8888  */
8889 static void
8890 flow_dv_translate_item_gtp(void *matcher, void *key,
8891 			   const struct rte_flow_item *item, int inner)
8892 {
8893 	const struct rte_flow_item_gtp *gtp_m = item->mask;
8894 	const struct rte_flow_item_gtp *gtp_v = item->spec;
8895 	void *headers_m;
8896 	void *headers_v;
8897 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
8898 				     misc_parameters_3);
8899 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
8900 	uint16_t dport = RTE_GTPU_UDP_PORT;
8901 
8902 	if (inner) {
8903 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8904 					 inner_headers);
8905 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8906 	} else {
8907 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8908 					 outer_headers);
8909 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8910 	}
8911 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8912 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8913 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8914 	}
8915 	if (!gtp_v)
8916 		return;
8917 	if (!gtp_m)
8918 		gtp_m = &rte_flow_item_gtp_mask;
8919 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags,
8920 		 gtp_m->v_pt_rsv_flags);
8921 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags,
8922 		 gtp_v->v_pt_rsv_flags & gtp_m->v_pt_rsv_flags);
8923 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_type, gtp_m->msg_type);
8924 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type,
8925 		 gtp_v->msg_type & gtp_m->msg_type);
8926 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_teid,
8927 		 rte_be_to_cpu_32(gtp_m->teid));
8928 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid,
8929 		 rte_be_to_cpu_32(gtp_v->teid & gtp_m->teid));
8930 }
8931 
8932 /**
8933  * Add GTP PSC item to matcher.
8934  *
8935  * @param[in, out] matcher
8936  *   Flow matcher.
8937  * @param[in, out] key
8938  *   Flow matcher value.
8939  * @param[in] item
8940  *   Flow pattern to translate.
8941  */
8942 static int
8943 flow_dv_translate_item_gtp_psc(void *matcher, void *key,
8944 			       const struct rte_flow_item *item)
8945 {
8946 	const struct rte_flow_item_gtp_psc *gtp_psc_m = item->mask;
8947 	const struct rte_flow_item_gtp_psc *gtp_psc_v = item->spec;
8948 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
8949 			misc_parameters_3);
8950 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
8951 	union {
8952 		uint32_t w32;
8953 		struct {
8954 			uint16_t seq_num;
8955 			uint8_t npdu_num;
8956 			uint8_t next_ext_header_type;
8957 		};
8958 	} dw_2;
8959 	uint8_t gtp_flags;
8960 
8961 	/* Always set E-flag match on one, regardless of GTP item settings. */
8962 	gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_m, gtpu_msg_flags);
8963 	gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
8964 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, gtp_flags);
8965 	gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags);
8966 	gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
8967 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags);
8968 	/*Set next extension header type. */
8969 	dw_2.seq_num = 0;
8970 	dw_2.npdu_num = 0;
8971 	dw_2.next_ext_header_type = 0xff;
8972 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_dw_2,
8973 		 rte_cpu_to_be_32(dw_2.w32));
8974 	dw_2.seq_num = 0;
8975 	dw_2.npdu_num = 0;
8976 	dw_2.next_ext_header_type = 0x85;
8977 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2,
8978 		 rte_cpu_to_be_32(dw_2.w32));
8979 	if (gtp_psc_v) {
8980 		union {
8981 			uint32_t w32;
8982 			struct {
8983 				uint8_t len;
8984 				uint8_t type_flags;
8985 				uint8_t qfi;
8986 				uint8_t reserved;
8987 			};
8988 		} dw_0;
8989 
8990 		/*Set extension header PDU type and Qos. */
8991 		if (!gtp_psc_m)
8992 			gtp_psc_m = &rte_flow_item_gtp_psc_mask;
8993 		dw_0.w32 = 0;
8994 		dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->pdu_type);
8995 		dw_0.qfi = gtp_psc_m->qfi;
8996 		MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_first_ext_dw_0,
8997 			 rte_cpu_to_be_32(dw_0.w32));
8998 		dw_0.w32 = 0;
8999 		dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->pdu_type &
9000 							gtp_psc_m->pdu_type);
9001 		dw_0.qfi = gtp_psc_v->qfi & gtp_psc_m->qfi;
9002 		MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0,
9003 			 rte_cpu_to_be_32(dw_0.w32));
9004 	}
9005 	return 0;
9006 }
9007 
9008 /**
9009  * Add eCPRI item to matcher and to the value.
9010  *
9011  * @param[in] dev
9012  *   The devich to configure through.
9013  * @param[in, out] matcher
9014  *   Flow matcher.
9015  * @param[in, out] key
9016  *   Flow matcher value.
9017  * @param[in] item
9018  *   Flow pattern to translate.
9019  * @param[in] samples
9020  *   Sample IDs to be used in the matching.
9021  */
9022 static void
9023 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher,
9024 			     void *key, const struct rte_flow_item *item)
9025 {
9026 	struct mlx5_priv *priv = dev->data->dev_private;
9027 	const struct rte_flow_item_ecpri *ecpri_m = item->mask;
9028 	const struct rte_flow_item_ecpri *ecpri_v = item->spec;
9029 	struct rte_ecpri_common_hdr common;
9030 	void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher,
9031 				     misc_parameters_4);
9032 	void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4);
9033 	uint32_t *samples;
9034 	void *dw_m;
9035 	void *dw_v;
9036 
9037 	if (!ecpri_v)
9038 		return;
9039 	if (!ecpri_m)
9040 		ecpri_m = &rte_flow_item_ecpri_mask;
9041 	/*
9042 	 * Maximal four DW samples are supported in a single matching now.
9043 	 * Two are used now for a eCPRI matching:
9044 	 * 1. Type: one byte, mask should be 0x00ff0000 in network order
9045 	 * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000
9046 	 *    if any.
9047 	 */
9048 	if (!ecpri_m->hdr.common.u32)
9049 		return;
9050 	samples = priv->sh->fp[MLX5_FLEX_PARSER_ECPRI_0].ids;
9051 	/* Need to take the whole DW as the mask to fill the entry. */
9052 	dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
9053 			    prog_sample_field_value_0);
9054 	dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
9055 			    prog_sample_field_value_0);
9056 	/* Already big endian (network order) in the header. */
9057 	*(uint32_t *)dw_m = ecpri_m->hdr.common.u32;
9058 	*(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32;
9059 	/* Sample#0, used for matching type, offset 0. */
9060 	MLX5_SET(fte_match_set_misc4, misc4_m,
9061 		 prog_sample_field_id_0, samples[0]);
9062 	/* It makes no sense to set the sample ID in the mask field. */
9063 	MLX5_SET(fte_match_set_misc4, misc4_v,
9064 		 prog_sample_field_id_0, samples[0]);
9065 	/*
9066 	 * Checking if message body part needs to be matched.
9067 	 * Some wildcard rules only matching type field should be supported.
9068 	 */
9069 	if (ecpri_m->hdr.dummy[0]) {
9070 		common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32);
9071 		switch (common.type) {
9072 		case RTE_ECPRI_MSG_TYPE_IQ_DATA:
9073 		case RTE_ECPRI_MSG_TYPE_RTC_CTRL:
9074 		case RTE_ECPRI_MSG_TYPE_DLY_MSR:
9075 			dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
9076 					    prog_sample_field_value_1);
9077 			dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
9078 					    prog_sample_field_value_1);
9079 			*(uint32_t *)dw_m = ecpri_m->hdr.dummy[0];
9080 			*(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] &
9081 					    ecpri_m->hdr.dummy[0];
9082 			/* Sample#1, to match message body, offset 4. */
9083 			MLX5_SET(fte_match_set_misc4, misc4_m,
9084 				 prog_sample_field_id_1, samples[1]);
9085 			MLX5_SET(fte_match_set_misc4, misc4_v,
9086 				 prog_sample_field_id_1, samples[1]);
9087 			break;
9088 		default:
9089 			/* Others, do not match any sample ID. */
9090 			break;
9091 		}
9092 	}
9093 }
9094 
9095 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
9096 
9097 #define HEADER_IS_ZERO(match_criteria, headers)				     \
9098 	!(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
9099 		 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
9100 
9101 /**
9102  * Calculate flow matcher enable bitmap.
9103  *
9104  * @param match_criteria
9105  *   Pointer to flow matcher criteria.
9106  *
9107  * @return
9108  *   Bitmap of enabled fields.
9109  */
9110 static uint8_t
9111 flow_dv_matcher_enable(uint32_t *match_criteria)
9112 {
9113 	uint8_t match_criteria_enable;
9114 
9115 	match_criteria_enable =
9116 		(!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
9117 		MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
9118 	match_criteria_enable |=
9119 		(!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
9120 		MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
9121 	match_criteria_enable |=
9122 		(!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
9123 		MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
9124 	match_criteria_enable |=
9125 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
9126 		MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
9127 	match_criteria_enable |=
9128 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
9129 		MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
9130 	match_criteria_enable |=
9131 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) <<
9132 		MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT;
9133 	return match_criteria_enable;
9134 }
9135 
9136 struct mlx5_hlist_entry *
9137 flow_dv_tbl_create_cb(struct mlx5_hlist *list, uint64_t key64, void *cb_ctx)
9138 {
9139 	struct mlx5_dev_ctx_shared *sh = list->ctx;
9140 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
9141 	struct rte_eth_dev *dev = ctx->dev;
9142 	struct mlx5_flow_tbl_data_entry *tbl_data;
9143 	struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data;
9144 	struct rte_flow_error *error = ctx->error;
9145 	union mlx5_flow_tbl_key key = { .v64 = key64 };
9146 	struct mlx5_flow_tbl_resource *tbl;
9147 	void *domain;
9148 	uint32_t idx = 0;
9149 	int ret;
9150 
9151 	tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
9152 	if (!tbl_data) {
9153 		rte_flow_error_set(error, ENOMEM,
9154 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9155 				   NULL,
9156 				   "cannot allocate flow table data entry");
9157 		return NULL;
9158 	}
9159 	tbl_data->idx = idx;
9160 	tbl_data->tunnel = tt_prm->tunnel;
9161 	tbl_data->group_id = tt_prm->group_id;
9162 	tbl_data->external = !!tt_prm->external;
9163 	tbl_data->tunnel_offload = is_tunnel_offload_active(dev);
9164 	tbl_data->is_egress = !!key.direction;
9165 	tbl_data->is_transfer = !!key.domain;
9166 	tbl_data->dummy = !!key.dummy;
9167 	tbl_data->table_id = key.table_id;
9168 	tbl = &tbl_data->tbl;
9169 	if (key.dummy)
9170 		return &tbl_data->entry;
9171 	if (key.domain)
9172 		domain = sh->fdb_domain;
9173 	else if (key.direction)
9174 		domain = sh->tx_domain;
9175 	else
9176 		domain = sh->rx_domain;
9177 	ret = mlx5_flow_os_create_flow_tbl(domain, key.table_id, &tbl->obj);
9178 	if (ret) {
9179 		rte_flow_error_set(error, ENOMEM,
9180 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9181 				   NULL, "cannot create flow table object");
9182 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
9183 		return NULL;
9184 	}
9185 	if (key.table_id) {
9186 		ret = mlx5_flow_os_create_flow_action_dest_flow_tbl
9187 					(tbl->obj, &tbl_data->jump.action);
9188 		if (ret) {
9189 			rte_flow_error_set(error, ENOMEM,
9190 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9191 					   NULL,
9192 					   "cannot create flow jump action");
9193 			mlx5_flow_os_destroy_flow_tbl(tbl->obj);
9194 			mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
9195 			return NULL;
9196 		}
9197 	}
9198 	MKSTR(matcher_name, "%s_%s_%u_matcher_cache",
9199 	      key.domain ? "FDB" : "NIC", key.direction ? "egress" : "ingress",
9200 	      key.table_id);
9201 	mlx5_cache_list_init(&tbl_data->matchers, matcher_name, 0, sh,
9202 			     flow_dv_matcher_create_cb,
9203 			     flow_dv_matcher_match_cb,
9204 			     flow_dv_matcher_remove_cb);
9205 	return &tbl_data->entry;
9206 }
9207 
9208 int
9209 flow_dv_tbl_match_cb(struct mlx5_hlist *list __rte_unused,
9210 		     struct mlx5_hlist_entry *entry, uint64_t key64,
9211 		     void *cb_ctx __rte_unused)
9212 {
9213 	struct mlx5_flow_tbl_data_entry *tbl_data =
9214 		container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
9215 	union mlx5_flow_tbl_key key = { .v64 = key64 };
9216 
9217 	return tbl_data->table_id != key.table_id ||
9218 	       tbl_data->dummy != key.dummy ||
9219 	       tbl_data->is_transfer != key.domain ||
9220 	       tbl_data->is_egress != key.direction;
9221 }
9222 
9223 /**
9224  * Get a flow table.
9225  *
9226  * @param[in, out] dev
9227  *   Pointer to rte_eth_dev structure.
9228  * @param[in] table_id
9229  *   Table id to use.
9230  * @param[in] egress
9231  *   Direction of the table.
9232  * @param[in] transfer
9233  *   E-Switch or NIC flow.
9234  * @param[in] dummy
9235  *   Dummy entry for dv API.
9236  * @param[out] error
9237  *   pointer to error structure.
9238  *
9239  * @return
9240  *   Returns tables resource based on the index, NULL in case of failed.
9241  */
9242 struct mlx5_flow_tbl_resource *
9243 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
9244 			 uint32_t table_id, uint8_t egress,
9245 			 uint8_t transfer,
9246 			 bool external,
9247 			 const struct mlx5_flow_tunnel *tunnel,
9248 			 uint32_t group_id, uint8_t dummy,
9249 			 struct rte_flow_error *error)
9250 {
9251 	struct mlx5_priv *priv = dev->data->dev_private;
9252 	union mlx5_flow_tbl_key table_key = {
9253 		{
9254 			.table_id = table_id,
9255 			.dummy = dummy,
9256 			.domain = !!transfer,
9257 			.direction = !!egress,
9258 		}
9259 	};
9260 	struct mlx5_flow_tbl_tunnel_prm tt_prm = {
9261 		.tunnel = tunnel,
9262 		.group_id = group_id,
9263 		.external = external,
9264 	};
9265 	struct mlx5_flow_cb_ctx ctx = {
9266 		.dev = dev,
9267 		.error = error,
9268 		.data = &tt_prm,
9269 	};
9270 	struct mlx5_hlist_entry *entry;
9271 	struct mlx5_flow_tbl_data_entry *tbl_data;
9272 
9273 	entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx);
9274 	if (!entry) {
9275 		rte_flow_error_set(error, ENOMEM,
9276 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9277 				   "cannot get table");
9278 		return NULL;
9279 	}
9280 	DRV_LOG(DEBUG, "Table_id %u tunnel %u group %u registered.",
9281 		table_id, tunnel ? tunnel->tunnel_id : 0, group_id);
9282 	tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
9283 	return &tbl_data->tbl;
9284 }
9285 
9286 void
9287 flow_dv_tbl_remove_cb(struct mlx5_hlist *list,
9288 		      struct mlx5_hlist_entry *entry)
9289 {
9290 	struct mlx5_dev_ctx_shared *sh = list->ctx;
9291 	struct mlx5_flow_tbl_data_entry *tbl_data =
9292 		container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
9293 
9294 	MLX5_ASSERT(entry && sh);
9295 	if (tbl_data->jump.action)
9296 		mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
9297 	if (tbl_data->tbl.obj)
9298 		mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj);
9299 	if (tbl_data->tunnel_offload && tbl_data->external) {
9300 		struct mlx5_hlist_entry *he;
9301 		struct mlx5_hlist *tunnel_grp_hash;
9302 		struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;
9303 		union tunnel_tbl_key tunnel_key = {
9304 			.tunnel_id = tbl_data->tunnel ?
9305 					tbl_data->tunnel->tunnel_id : 0,
9306 			.group = tbl_data->group_id
9307 		};
9308 		uint32_t table_id = tbl_data->table_id;
9309 
9310 		tunnel_grp_hash = tbl_data->tunnel ?
9311 					tbl_data->tunnel->groups :
9312 					thub->groups;
9313 		he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, NULL);
9314 		if (he)
9315 			mlx5_hlist_unregister(tunnel_grp_hash, he);
9316 		DRV_LOG(DEBUG,
9317 			"Table_id %u tunnel %u group %u released.",
9318 			table_id,
9319 			tbl_data->tunnel ?
9320 			tbl_data->tunnel->tunnel_id : 0,
9321 			tbl_data->group_id);
9322 	}
9323 	mlx5_cache_list_destroy(&tbl_data->matchers);
9324 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
9325 }
9326 
9327 /**
9328  * Release a flow table.
9329  *
9330  * @param[in] sh
9331  *   Pointer to device shared structure.
9332  * @param[in] tbl
9333  *   Table resource to be released.
9334  *
9335  * @return
9336  *   Returns 0 if table was released, else return 1;
9337  */
9338 static int
9339 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
9340 			     struct mlx5_flow_tbl_resource *tbl)
9341 {
9342 	struct mlx5_flow_tbl_data_entry *tbl_data =
9343 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
9344 
9345 	if (!tbl)
9346 		return 0;
9347 	return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry);
9348 }
9349 
9350 int
9351 flow_dv_matcher_match_cb(struct mlx5_cache_list *list __rte_unused,
9352 			 struct mlx5_cache_entry *entry, void *cb_ctx)
9353 {
9354 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
9355 	struct mlx5_flow_dv_matcher *ref = ctx->data;
9356 	struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur),
9357 							entry);
9358 
9359 	return cur->crc != ref->crc ||
9360 	       cur->priority != ref->priority ||
9361 	       memcmp((const void *)cur->mask.buf,
9362 		      (const void *)ref->mask.buf, ref->mask.size);
9363 }
9364 
9365 struct mlx5_cache_entry *
9366 flow_dv_matcher_create_cb(struct mlx5_cache_list *list,
9367 			  struct mlx5_cache_entry *entry __rte_unused,
9368 			  void *cb_ctx)
9369 {
9370 	struct mlx5_dev_ctx_shared *sh = list->ctx;
9371 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
9372 	struct mlx5_flow_dv_matcher *ref = ctx->data;
9373 	struct mlx5_flow_dv_matcher *cache;
9374 	struct mlx5dv_flow_matcher_attr dv_attr = {
9375 		.type = IBV_FLOW_ATTR_NORMAL,
9376 		.match_mask = (void *)&ref->mask,
9377 	};
9378 	struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
9379 							    typeof(*tbl), tbl);
9380 	int ret;
9381 
9382 	cache = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*cache), 0, SOCKET_ID_ANY);
9383 	if (!cache) {
9384 		rte_flow_error_set(ctx->error, ENOMEM,
9385 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9386 				   "cannot create matcher");
9387 		return NULL;
9388 	}
9389 	*cache = *ref;
9390 	dv_attr.match_criteria_enable =
9391 		flow_dv_matcher_enable(cache->mask.buf);
9392 	dv_attr.priority = ref->priority;
9393 	if (tbl->is_egress)
9394 		dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
9395 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->tbl.obj,
9396 					       &cache->matcher_object);
9397 	if (ret) {
9398 		mlx5_free(cache);
9399 		rte_flow_error_set(ctx->error, ENOMEM,
9400 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9401 				   "cannot create matcher");
9402 		return NULL;
9403 	}
9404 	return &cache->entry;
9405 }
9406 
9407 /**
9408  * Register the flow matcher.
9409  *
9410  * @param[in, out] dev
9411  *   Pointer to rte_eth_dev structure.
9412  * @param[in, out] matcher
9413  *   Pointer to flow matcher.
9414  * @param[in, out] key
9415  *   Pointer to flow table key.
9416  * @parm[in, out] dev_flow
9417  *   Pointer to the dev_flow.
9418  * @param[out] error
9419  *   pointer to error structure.
9420  *
9421  * @return
9422  *   0 on success otherwise -errno and errno is set.
9423  */
9424 static int
9425 flow_dv_matcher_register(struct rte_eth_dev *dev,
9426 			 struct mlx5_flow_dv_matcher *ref,
9427 			 union mlx5_flow_tbl_key *key,
9428 			 struct mlx5_flow *dev_flow,
9429 			 const struct mlx5_flow_tunnel *tunnel,
9430 			 uint32_t group_id,
9431 			 struct rte_flow_error *error)
9432 {
9433 	struct mlx5_cache_entry *entry;
9434 	struct mlx5_flow_dv_matcher *cache;
9435 	struct mlx5_flow_tbl_resource *tbl;
9436 	struct mlx5_flow_tbl_data_entry *tbl_data;
9437 	struct mlx5_flow_cb_ctx ctx = {
9438 		.error = error,
9439 		.data = ref,
9440 	};
9441 
9442 	/**
9443 	 * tunnel offload API requires this registration for cases when
9444 	 * tunnel match rule was inserted before tunnel set rule.
9445 	 */
9446 	tbl = flow_dv_tbl_resource_get(dev, key->table_id,
9447 				       key->direction, key->domain,
9448 				       dev_flow->external, tunnel,
9449 				       group_id, 0, error);
9450 	if (!tbl)
9451 		return -rte_errno;	/* No need to refill the error info */
9452 	tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
9453 	ref->tbl = tbl;
9454 	entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
9455 	if (!entry) {
9456 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
9457 		return rte_flow_error_set(error, ENOMEM,
9458 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9459 					  "cannot allocate ref memory");
9460 	}
9461 	cache = container_of(entry, typeof(*cache), entry);
9462 	dev_flow->handle->dvh.matcher = cache;
9463 	return 0;
9464 }
9465 
9466 struct mlx5_hlist_entry *
9467 flow_dv_tag_create_cb(struct mlx5_hlist *list, uint64_t key, void *ctx)
9468 {
9469 	struct mlx5_dev_ctx_shared *sh = list->ctx;
9470 	struct rte_flow_error *error = ctx;
9471 	struct mlx5_flow_dv_tag_resource *entry;
9472 	uint32_t idx = 0;
9473 	int ret;
9474 
9475 	entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
9476 	if (!entry) {
9477 		rte_flow_error_set(error, ENOMEM,
9478 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9479 				   "cannot allocate resource memory");
9480 		return NULL;
9481 	}
9482 	entry->idx = idx;
9483 	entry->tag_id = key;
9484 	ret = mlx5_flow_os_create_flow_action_tag(key,
9485 						  &entry->action);
9486 	if (ret) {
9487 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx);
9488 		rte_flow_error_set(error, ENOMEM,
9489 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9490 				   NULL, "cannot create action");
9491 		return NULL;
9492 	}
9493 	return &entry->entry;
9494 }
9495 
9496 int
9497 flow_dv_tag_match_cb(struct mlx5_hlist *list __rte_unused,
9498 		     struct mlx5_hlist_entry *entry, uint64_t key,
9499 		     void *cb_ctx __rte_unused)
9500 {
9501 	struct mlx5_flow_dv_tag_resource *tag =
9502 		container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
9503 
9504 	return key != tag->tag_id;
9505 }
9506 
9507 /**
9508  * Find existing tag resource or create and register a new one.
9509  *
9510  * @param dev[in, out]
9511  *   Pointer to rte_eth_dev structure.
9512  * @param[in, out] tag_be24
9513  *   Tag value in big endian then R-shift 8.
9514  * @parm[in, out] dev_flow
9515  *   Pointer to the dev_flow.
9516  * @param[out] error
9517  *   pointer to error structure.
9518  *
9519  * @return
9520  *   0 on success otherwise -errno and errno is set.
9521  */
9522 static int
9523 flow_dv_tag_resource_register
9524 			(struct rte_eth_dev *dev,
9525 			 uint32_t tag_be24,
9526 			 struct mlx5_flow *dev_flow,
9527 			 struct rte_flow_error *error)
9528 {
9529 	struct mlx5_priv *priv = dev->data->dev_private;
9530 	struct mlx5_flow_dv_tag_resource *cache_resource;
9531 	struct mlx5_hlist_entry *entry;
9532 
9533 	entry = mlx5_hlist_register(priv->sh->tag_table, tag_be24, error);
9534 	if (entry) {
9535 		cache_resource = container_of
9536 			(entry, struct mlx5_flow_dv_tag_resource, entry);
9537 		dev_flow->handle->dvh.rix_tag = cache_resource->idx;
9538 		dev_flow->dv.tag_resource = cache_resource;
9539 		return 0;
9540 	}
9541 	return -rte_errno;
9542 }
9543 
9544 void
9545 flow_dv_tag_remove_cb(struct mlx5_hlist *list,
9546 		      struct mlx5_hlist_entry *entry)
9547 {
9548 	struct mlx5_dev_ctx_shared *sh = list->ctx;
9549 	struct mlx5_flow_dv_tag_resource *tag =
9550 		container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
9551 
9552 	MLX5_ASSERT(tag && sh && tag->action);
9553 	claim_zero(mlx5_flow_os_destroy_flow_action(tag->action));
9554 	DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag);
9555 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
9556 }
9557 
9558 /**
9559  * Release the tag.
9560  *
9561  * @param dev
9562  *   Pointer to Ethernet device.
9563  * @param tag_idx
9564  *   Tag index.
9565  *
9566  * @return
9567  *   1 while a reference on it exists, 0 when freed.
9568  */
9569 static int
9570 flow_dv_tag_release(struct rte_eth_dev *dev,
9571 		    uint32_t tag_idx)
9572 {
9573 	struct mlx5_priv *priv = dev->data->dev_private;
9574 	struct mlx5_flow_dv_tag_resource *tag;
9575 
9576 	tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx);
9577 	if (!tag)
9578 		return 0;
9579 	DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
9580 		dev->data->port_id, (void *)tag, tag->entry.ref_cnt);
9581 	return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry);
9582 }
9583 
9584 /**
9585  * Translate port ID action to vport.
9586  *
9587  * @param[in] dev
9588  *   Pointer to rte_eth_dev structure.
9589  * @param[in] action
9590  *   Pointer to the port ID action.
9591  * @param[out] dst_port_id
9592  *   The target port ID.
9593  * @param[out] error
9594  *   Pointer to the error structure.
9595  *
9596  * @return
9597  *   0 on success, a negative errno value otherwise and rte_errno is set.
9598  */
9599 static int
9600 flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
9601 				 const struct rte_flow_action *action,
9602 				 uint32_t *dst_port_id,
9603 				 struct rte_flow_error *error)
9604 {
9605 	uint32_t port;
9606 	struct mlx5_priv *priv;
9607 	const struct rte_flow_action_port_id *conf =
9608 			(const struct rte_flow_action_port_id *)action->conf;
9609 
9610 	port = conf->original ? dev->data->port_id : conf->id;
9611 	priv = mlx5_port_to_eswitch_info(port, false);
9612 	if (!priv)
9613 		return rte_flow_error_set(error, -rte_errno,
9614 					  RTE_FLOW_ERROR_TYPE_ACTION,
9615 					  NULL,
9616 					  "No eswitch info was found for port");
9617 #ifdef HAVE_MLX5DV_DR_DEVX_PORT
9618 	/*
9619 	 * This parameter is transferred to
9620 	 * mlx5dv_dr_action_create_dest_ib_port().
9621 	 */
9622 	*dst_port_id = priv->dev_port;
9623 #else
9624 	/*
9625 	 * Legacy mode, no LAG configurations is supported.
9626 	 * This parameter is transferred to
9627 	 * mlx5dv_dr_action_create_dest_vport().
9628 	 */
9629 	*dst_port_id = priv->vport_id;
9630 #endif
9631 	return 0;
9632 }
9633 
9634 /**
9635  * Create a counter with aging configuration.
9636  *
9637  * @param[in] dev
9638  *   Pointer to rte_eth_dev structure.
9639  * @param[out] count
9640  *   Pointer to the counter action configuration.
9641  * @param[in] age
9642  *   Pointer to the aging action configuration.
9643  *
9644  * @return
9645  *   Index to flow counter on success, 0 otherwise.
9646  */
9647 static uint32_t
9648 flow_dv_translate_create_counter(struct rte_eth_dev *dev,
9649 				struct mlx5_flow *dev_flow,
9650 				const struct rte_flow_action_count *count,
9651 				const struct rte_flow_action_age *age)
9652 {
9653 	uint32_t counter;
9654 	struct mlx5_age_param *age_param;
9655 
9656 	if (count && count->shared)
9657 		counter = flow_dv_counter_get_shared(dev, count->id);
9658 	else
9659 		counter = flow_dv_counter_alloc(dev, !!age);
9660 	if (!counter || age == NULL)
9661 		return counter;
9662 	age_param  = flow_dv_counter_idx_get_age(dev, counter);
9663 	age_param->context = age->context ? age->context :
9664 		(void *)(uintptr_t)(dev_flow->flow_idx);
9665 	age_param->timeout = age->timeout;
9666 	age_param->port_id = dev->data->port_id;
9667 	__atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED);
9668 	__atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED);
9669 	return counter;
9670 }
9671 
9672 /**
9673  * Add Tx queue matcher
9674  *
9675  * @param[in] dev
9676  *   Pointer to the dev struct.
9677  * @param[in, out] matcher
9678  *   Flow matcher.
9679  * @param[in, out] key
9680  *   Flow matcher value.
9681  * @param[in] item
9682  *   Flow pattern to translate.
9683  * @param[in] inner
9684  *   Item is inner pattern.
9685  */
9686 static void
9687 flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev,
9688 				void *matcher, void *key,
9689 				const struct rte_flow_item *item)
9690 {
9691 	const struct mlx5_rte_flow_item_tx_queue *queue_m;
9692 	const struct mlx5_rte_flow_item_tx_queue *queue_v;
9693 	void *misc_m =
9694 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9695 	void *misc_v =
9696 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9697 	struct mlx5_txq_ctrl *txq;
9698 	uint32_t queue;
9699 
9700 
9701 	queue_m = (const void *)item->mask;
9702 	if (!queue_m)
9703 		return;
9704 	queue_v = (const void *)item->spec;
9705 	if (!queue_v)
9706 		return;
9707 	txq = mlx5_txq_get(dev, queue_v->queue);
9708 	if (!txq)
9709 		return;
9710 	queue = txq->obj->sq->id;
9711 	MLX5_SET(fte_match_set_misc, misc_m, source_sqn, queue_m->queue);
9712 	MLX5_SET(fte_match_set_misc, misc_v, source_sqn,
9713 		 queue & queue_m->queue);
9714 	mlx5_txq_release(dev, queue_v->queue);
9715 }
9716 
9717 /**
9718  * Set the hash fields according to the @p flow information.
9719  *
9720  * @param[in] dev_flow
9721  *   Pointer to the mlx5_flow.
9722  * @param[in] rss_desc
9723  *   Pointer to the mlx5_flow_rss_desc.
9724  */
9725 static void
9726 flow_dv_hashfields_set(struct mlx5_flow *dev_flow,
9727 		       struct mlx5_flow_rss_desc *rss_desc)
9728 {
9729 	uint64_t items = dev_flow->handle->layers;
9730 	int rss_inner = 0;
9731 	uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types);
9732 
9733 	dev_flow->hash_fields = 0;
9734 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
9735 	if (rss_desc->level >= 2) {
9736 		dev_flow->hash_fields |= IBV_RX_HASH_INNER;
9737 		rss_inner = 1;
9738 	}
9739 #endif
9740 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) ||
9741 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) {
9742 		if (rss_types & MLX5_IPV4_LAYER_TYPES) {
9743 			if (rss_types & ETH_RSS_L3_SRC_ONLY)
9744 				dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV4;
9745 			else if (rss_types & ETH_RSS_L3_DST_ONLY)
9746 				dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV4;
9747 			else
9748 				dev_flow->hash_fields |= MLX5_IPV4_IBV_RX_HASH;
9749 		}
9750 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
9751 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) {
9752 		if (rss_types & MLX5_IPV6_LAYER_TYPES) {
9753 			if (rss_types & ETH_RSS_L3_SRC_ONLY)
9754 				dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV6;
9755 			else if (rss_types & ETH_RSS_L3_DST_ONLY)
9756 				dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV6;
9757 			else
9758 				dev_flow->hash_fields |= MLX5_IPV6_IBV_RX_HASH;
9759 		}
9760 	}
9761 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) ||
9762 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) {
9763 		if (rss_types & ETH_RSS_UDP) {
9764 			if (rss_types & ETH_RSS_L4_SRC_ONLY)
9765 				dev_flow->hash_fields |=
9766 						IBV_RX_HASH_SRC_PORT_UDP;
9767 			else if (rss_types & ETH_RSS_L4_DST_ONLY)
9768 				dev_flow->hash_fields |=
9769 						IBV_RX_HASH_DST_PORT_UDP;
9770 			else
9771 				dev_flow->hash_fields |= MLX5_UDP_IBV_RX_HASH;
9772 		}
9773 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) ||
9774 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) {
9775 		if (rss_types & ETH_RSS_TCP) {
9776 			if (rss_types & ETH_RSS_L4_SRC_ONLY)
9777 				dev_flow->hash_fields |=
9778 						IBV_RX_HASH_SRC_PORT_TCP;
9779 			else if (rss_types & ETH_RSS_L4_DST_ONLY)
9780 				dev_flow->hash_fields |=
9781 						IBV_RX_HASH_DST_PORT_TCP;
9782 			else
9783 				dev_flow->hash_fields |= MLX5_TCP_IBV_RX_HASH;
9784 		}
9785 	}
9786 }
9787 
9788 /**
9789  * Prepare an Rx Hash queue.
9790  *
9791  * @param dev
9792  *   Pointer to Ethernet device.
9793  * @param[in] dev_flow
9794  *   Pointer to the mlx5_flow.
9795  * @param[in] rss_desc
9796  *   Pointer to the mlx5_flow_rss_desc.
9797  * @param[out] hrxq_idx
9798  *   Hash Rx queue index.
9799  *
9800  * @return
9801  *   The Verbs/DevX object initialised, NULL otherwise and rte_errno is set.
9802  */
9803 static struct mlx5_hrxq *
9804 flow_dv_hrxq_prepare(struct rte_eth_dev *dev,
9805 		     struct mlx5_flow *dev_flow,
9806 		     struct mlx5_flow_rss_desc *rss_desc,
9807 		     uint32_t *hrxq_idx)
9808 {
9809 	struct mlx5_priv *priv = dev->data->dev_private;
9810 	struct mlx5_flow_handle *dh = dev_flow->handle;
9811 	struct mlx5_hrxq *hrxq;
9812 
9813 	MLX5_ASSERT(rss_desc->queue_num);
9814 	rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN;
9815 	rss_desc->hash_fields = dev_flow->hash_fields;
9816 	rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL);
9817 	rss_desc->shared_rss = 0;
9818 	*hrxq_idx = mlx5_hrxq_get(dev, rss_desc);
9819 	if (!*hrxq_idx)
9820 		return NULL;
9821 	hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
9822 			      *hrxq_idx);
9823 	return hrxq;
9824 }
9825 
9826 /**
9827  * Release sample sub action resource.
9828  *
9829  * @param[in, out] dev
9830  *   Pointer to rte_eth_dev structure.
9831  * @param[in] act_res
9832  *   Pointer to sample sub action resource.
9833  */
9834 static void
9835 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev,
9836 				   struct mlx5_flow_sub_actions_idx *act_res)
9837 {
9838 	if (act_res->rix_hrxq) {
9839 		mlx5_hrxq_release(dev, act_res->rix_hrxq);
9840 		act_res->rix_hrxq = 0;
9841 	}
9842 	if (act_res->rix_encap_decap) {
9843 		flow_dv_encap_decap_resource_release(dev,
9844 						     act_res->rix_encap_decap);
9845 		act_res->rix_encap_decap = 0;
9846 	}
9847 	if (act_res->rix_port_id_action) {
9848 		flow_dv_port_id_action_resource_release(dev,
9849 						act_res->rix_port_id_action);
9850 		act_res->rix_port_id_action = 0;
9851 	}
9852 	if (act_res->rix_tag) {
9853 		flow_dv_tag_release(dev, act_res->rix_tag);
9854 		act_res->rix_tag = 0;
9855 	}
9856 	if (act_res->rix_jump) {
9857 		flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump);
9858 		act_res->rix_jump = 0;
9859 	}
9860 }
9861 
9862 int
9863 flow_dv_sample_match_cb(struct mlx5_cache_list *list __rte_unused,
9864 			struct mlx5_cache_entry *entry, void *cb_ctx)
9865 {
9866 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
9867 	struct rte_eth_dev *dev = ctx->dev;
9868 	struct mlx5_flow_dv_sample_resource *resource = ctx->data;
9869 	struct mlx5_flow_dv_sample_resource *cache_resource =
9870 			container_of(entry, typeof(*cache_resource), entry);
9871 
9872 	if (resource->ratio == cache_resource->ratio &&
9873 	    resource->ft_type == cache_resource->ft_type &&
9874 	    resource->ft_id == cache_resource->ft_id &&
9875 	    resource->set_action == cache_resource->set_action &&
9876 	    !memcmp((void *)&resource->sample_act,
9877 		    (void *)&cache_resource->sample_act,
9878 		    sizeof(struct mlx5_flow_sub_actions_list))) {
9879 		/*
9880 		 * Existing sample action should release the prepared
9881 		 * sub-actions reference counter.
9882 		 */
9883 		flow_dv_sample_sub_actions_release(dev,
9884 						&resource->sample_idx);
9885 		return 0;
9886 	}
9887 	return 1;
9888 }
9889 
9890 struct mlx5_cache_entry *
9891 flow_dv_sample_create_cb(struct mlx5_cache_list *list __rte_unused,
9892 			 struct mlx5_cache_entry *entry __rte_unused,
9893 			 void *cb_ctx)
9894 {
9895 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
9896 	struct rte_eth_dev *dev = ctx->dev;
9897 	struct mlx5_flow_dv_sample_resource *resource = ctx->data;
9898 	void **sample_dv_actions = resource->sub_actions;
9899 	struct mlx5_flow_dv_sample_resource *cache_resource;
9900 	struct mlx5dv_dr_flow_sampler_attr sampler_attr;
9901 	struct mlx5_priv *priv = dev->data->dev_private;
9902 	struct mlx5_dev_ctx_shared *sh = priv->sh;
9903 	struct mlx5_flow_tbl_resource *tbl;
9904 	uint32_t idx = 0;
9905 	const uint32_t next_ft_step = 1;
9906 	uint32_t next_ft_id = resource->ft_id +	next_ft_step;
9907 	uint8_t is_egress = 0;
9908 	uint8_t is_transfer = 0;
9909 	struct rte_flow_error *error = ctx->error;
9910 
9911 	/* Register new sample resource. */
9912 	cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
9913 	if (!cache_resource) {
9914 		rte_flow_error_set(error, ENOMEM,
9915 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9916 					  NULL,
9917 					  "cannot allocate resource memory");
9918 		return NULL;
9919 	}
9920 	*cache_resource = *resource;
9921 	/* Create normal path table level */
9922 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
9923 		is_transfer = 1;
9924 	else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
9925 		is_egress = 1;
9926 	tbl = flow_dv_tbl_resource_get(dev, next_ft_id,
9927 					is_egress, is_transfer,
9928 					true, NULL, 0, 0, error);
9929 	if (!tbl) {
9930 		rte_flow_error_set(error, ENOMEM,
9931 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9932 					  NULL,
9933 					  "fail to create normal path table "
9934 					  "for sample");
9935 		goto error;
9936 	}
9937 	cache_resource->normal_path_tbl = tbl;
9938 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) {
9939 		if (!sh->default_miss_action) {
9940 			rte_flow_error_set(error, ENOMEM,
9941 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9942 						NULL,
9943 						"default miss action was not "
9944 						"created");
9945 			goto error;
9946 		}
9947 		sample_dv_actions[resource->sample_act.actions_num++] =
9948 						sh->default_miss_action;
9949 	}
9950 	/* Create a DR sample action */
9951 	sampler_attr.sample_ratio = cache_resource->ratio;
9952 	sampler_attr.default_next_table = tbl->obj;
9953 	sampler_attr.num_sample_actions = resource->sample_act.actions_num;
9954 	sampler_attr.sample_actions = (struct mlx5dv_dr_action **)
9955 							&sample_dv_actions[0];
9956 	sampler_attr.action = cache_resource->set_action;
9957 	if (mlx5_os_flow_dr_create_flow_action_sampler
9958 			(&sampler_attr, &cache_resource->verbs_action)) {
9959 		rte_flow_error_set(error, ENOMEM,
9960 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9961 					NULL, "cannot create sample action");
9962 		goto error;
9963 	}
9964 	cache_resource->idx = idx;
9965 	cache_resource->dev = dev;
9966 	return &cache_resource->entry;
9967 error:
9968 	if (cache_resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB)
9969 		flow_dv_sample_sub_actions_release(dev,
9970 						   &cache_resource->sample_idx);
9971 	if (cache_resource->normal_path_tbl)
9972 		flow_dv_tbl_resource_release(MLX5_SH(dev),
9973 				cache_resource->normal_path_tbl);
9974 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx);
9975 	return NULL;
9976 
9977 }
9978 
9979 /**
9980  * Find existing sample resource or create and register a new one.
9981  *
9982  * @param[in, out] dev
9983  *   Pointer to rte_eth_dev structure.
9984  * @param[in] resource
9985  *   Pointer to sample resource.
9986  * @parm[in, out] dev_flow
9987  *   Pointer to the dev_flow.
9988  * @param[out] error
9989  *   pointer to error structure.
9990  *
9991  * @return
9992  *   0 on success otherwise -errno and errno is set.
9993  */
9994 static int
9995 flow_dv_sample_resource_register(struct rte_eth_dev *dev,
9996 			 struct mlx5_flow_dv_sample_resource *resource,
9997 			 struct mlx5_flow *dev_flow,
9998 			 struct rte_flow_error *error)
9999 {
10000 	struct mlx5_flow_dv_sample_resource *cache_resource;
10001 	struct mlx5_cache_entry *entry;
10002 	struct mlx5_priv *priv = dev->data->dev_private;
10003 	struct mlx5_flow_cb_ctx ctx = {
10004 		.dev = dev,
10005 		.error = error,
10006 		.data = resource,
10007 	};
10008 
10009 	entry = mlx5_cache_register(&priv->sh->sample_action_list, &ctx);
10010 	if (!entry)
10011 		return -rte_errno;
10012 	cache_resource = container_of(entry, typeof(*cache_resource), entry);
10013 	dev_flow->handle->dvh.rix_sample = cache_resource->idx;
10014 	dev_flow->dv.sample_res = cache_resource;
10015 	return 0;
10016 }
10017 
10018 int
10019 flow_dv_dest_array_match_cb(struct mlx5_cache_list *list __rte_unused,
10020 			    struct mlx5_cache_entry *entry, void *cb_ctx)
10021 {
10022 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10023 	struct mlx5_flow_dv_dest_array_resource *resource = ctx->data;
10024 	struct rte_eth_dev *dev = ctx->dev;
10025 	struct mlx5_flow_dv_dest_array_resource *cache_resource =
10026 			container_of(entry, typeof(*cache_resource), entry);
10027 	uint32_t idx = 0;
10028 
10029 	if (resource->num_of_dest == cache_resource->num_of_dest &&
10030 	    resource->ft_type == cache_resource->ft_type &&
10031 	    !memcmp((void *)cache_resource->sample_act,
10032 		    (void *)resource->sample_act,
10033 		   (resource->num_of_dest *
10034 		   sizeof(struct mlx5_flow_sub_actions_list)))) {
10035 		/*
10036 		 * Existing sample action should release the prepared
10037 		 * sub-actions reference counter.
10038 		 */
10039 		for (idx = 0; idx < resource->num_of_dest; idx++)
10040 			flow_dv_sample_sub_actions_release(dev,
10041 					&resource->sample_idx[idx]);
10042 		return 0;
10043 	}
10044 	return 1;
10045 }
10046 
10047 struct mlx5_cache_entry *
10048 flow_dv_dest_array_create_cb(struct mlx5_cache_list *list __rte_unused,
10049 			 struct mlx5_cache_entry *entry __rte_unused,
10050 			 void *cb_ctx)
10051 {
10052 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10053 	struct rte_eth_dev *dev = ctx->dev;
10054 	struct mlx5_flow_dv_dest_array_resource *cache_resource;
10055 	struct mlx5_flow_dv_dest_array_resource *resource = ctx->data;
10056 	struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 };
10057 	struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM];
10058 	struct mlx5_priv *priv = dev->data->dev_private;
10059 	struct mlx5_dev_ctx_shared *sh = priv->sh;
10060 	struct mlx5_flow_sub_actions_list *sample_act;
10061 	struct mlx5dv_dr_domain *domain;
10062 	uint32_t idx = 0, res_idx = 0;
10063 	struct rte_flow_error *error = ctx->error;
10064 	uint64_t action_flags;
10065 	int ret;
10066 
10067 	/* Register new destination array resource. */
10068 	cache_resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
10069 					    &res_idx);
10070 	if (!cache_resource) {
10071 		rte_flow_error_set(error, ENOMEM,
10072 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10073 					  NULL,
10074 					  "cannot allocate resource memory");
10075 		return NULL;
10076 	}
10077 	*cache_resource = *resource;
10078 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
10079 		domain = sh->fdb_domain;
10080 	else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
10081 		domain = sh->rx_domain;
10082 	else
10083 		domain = sh->tx_domain;
10084 	for (idx = 0; idx < resource->num_of_dest; idx++) {
10085 		dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *)
10086 				 mlx5_malloc(MLX5_MEM_ZERO,
10087 				 sizeof(struct mlx5dv_dr_action_dest_attr),
10088 				 0, SOCKET_ID_ANY);
10089 		if (!dest_attr[idx]) {
10090 			rte_flow_error_set(error, ENOMEM,
10091 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10092 					   NULL,
10093 					   "cannot allocate resource memory");
10094 			goto error;
10095 		}
10096 		dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST;
10097 		sample_act = &resource->sample_act[idx];
10098 		action_flags = sample_act->action_flags;
10099 		switch (action_flags) {
10100 		case MLX5_FLOW_ACTION_QUEUE:
10101 			dest_attr[idx]->dest = sample_act->dr_queue_action;
10102 			break;
10103 		case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP):
10104 			dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT;
10105 			dest_attr[idx]->dest_reformat = &dest_reformat[idx];
10106 			dest_attr[idx]->dest_reformat->reformat =
10107 					sample_act->dr_encap_action;
10108 			dest_attr[idx]->dest_reformat->dest =
10109 					sample_act->dr_port_id_action;
10110 			break;
10111 		case MLX5_FLOW_ACTION_PORT_ID:
10112 			dest_attr[idx]->dest = sample_act->dr_port_id_action;
10113 			break;
10114 		case MLX5_FLOW_ACTION_JUMP:
10115 			dest_attr[idx]->dest = sample_act->dr_jump_action;
10116 			break;
10117 		default:
10118 			rte_flow_error_set(error, EINVAL,
10119 					   RTE_FLOW_ERROR_TYPE_ACTION,
10120 					   NULL,
10121 					   "unsupported actions type");
10122 			goto error;
10123 		}
10124 	}
10125 	/* create a dest array actioin */
10126 	ret = mlx5_os_flow_dr_create_flow_action_dest_array
10127 						(domain,
10128 						 cache_resource->num_of_dest,
10129 						 dest_attr,
10130 						 &cache_resource->action);
10131 	if (ret) {
10132 		rte_flow_error_set(error, ENOMEM,
10133 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10134 				   NULL,
10135 				   "cannot create destination array action");
10136 		goto error;
10137 	}
10138 	cache_resource->idx = res_idx;
10139 	cache_resource->dev = dev;
10140 	for (idx = 0; idx < resource->num_of_dest; idx++)
10141 		mlx5_free(dest_attr[idx]);
10142 	return &cache_resource->entry;
10143 error:
10144 	for (idx = 0; idx < resource->num_of_dest; idx++) {
10145 		struct mlx5_flow_sub_actions_idx *act_res =
10146 					&cache_resource->sample_idx[idx];
10147 		if (act_res->rix_hrxq &&
10148 		    !mlx5_hrxq_release(dev,
10149 				act_res->rix_hrxq))
10150 			act_res->rix_hrxq = 0;
10151 		if (act_res->rix_encap_decap &&
10152 			!flow_dv_encap_decap_resource_release(dev,
10153 				act_res->rix_encap_decap))
10154 			act_res->rix_encap_decap = 0;
10155 		if (act_res->rix_port_id_action &&
10156 			!flow_dv_port_id_action_resource_release(dev,
10157 				act_res->rix_port_id_action))
10158 			act_res->rix_port_id_action = 0;
10159 		if (act_res->rix_jump &&
10160 			!flow_dv_jump_tbl_resource_release(dev,
10161 				act_res->rix_jump))
10162 			act_res->rix_jump = 0;
10163 		if (dest_attr[idx])
10164 			mlx5_free(dest_attr[idx]);
10165 	}
10166 
10167 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx);
10168 	return NULL;
10169 }
10170 
10171 /**
10172  * Find existing destination array resource or create and register a new one.
10173  *
10174  * @param[in, out] dev
10175  *   Pointer to rte_eth_dev structure.
10176  * @param[in] resource
10177  *   Pointer to destination array resource.
10178  * @parm[in, out] dev_flow
10179  *   Pointer to the dev_flow.
10180  * @param[out] error
10181  *   pointer to error structure.
10182  *
10183  * @return
10184  *   0 on success otherwise -errno and errno is set.
10185  */
10186 static int
10187 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev,
10188 			 struct mlx5_flow_dv_dest_array_resource *resource,
10189 			 struct mlx5_flow *dev_flow,
10190 			 struct rte_flow_error *error)
10191 {
10192 	struct mlx5_flow_dv_dest_array_resource *cache_resource;
10193 	struct mlx5_priv *priv = dev->data->dev_private;
10194 	struct mlx5_cache_entry *entry;
10195 	struct mlx5_flow_cb_ctx ctx = {
10196 		.dev = dev,
10197 		.error = error,
10198 		.data = resource,
10199 	};
10200 
10201 	entry = mlx5_cache_register(&priv->sh->dest_array_list, &ctx);
10202 	if (!entry)
10203 		return -rte_errno;
10204 	cache_resource = container_of(entry, typeof(*cache_resource), entry);
10205 	dev_flow->handle->dvh.rix_dest_array = cache_resource->idx;
10206 	dev_flow->dv.dest_array_res = cache_resource;
10207 	return 0;
10208 }
10209 
10210 /**
10211  * Convert Sample action to DV specification.
10212  *
10213  * @param[in] dev
10214  *   Pointer to rte_eth_dev structure.
10215  * @param[in] action
10216  *   Pointer to sample action structure.
10217  * @param[in, out] dev_flow
10218  *   Pointer to the mlx5_flow.
10219  * @param[in] attr
10220  *   Pointer to the flow attributes.
10221  * @param[in, out] num_of_dest
10222  *   Pointer to the num of destination.
10223  * @param[in, out] sample_actions
10224  *   Pointer to sample actions list.
10225  * @param[in, out] res
10226  *   Pointer to sample resource.
10227  * @param[out] error
10228  *   Pointer to the error structure.
10229  *
10230  * @return
10231  *   0 on success, a negative errno value otherwise and rte_errno is set.
10232  */
10233 static int
10234 flow_dv_translate_action_sample(struct rte_eth_dev *dev,
10235 				const struct rte_flow_action_sample *action,
10236 				struct mlx5_flow *dev_flow,
10237 				const struct rte_flow_attr *attr,
10238 				uint32_t *num_of_dest,
10239 				void **sample_actions,
10240 				struct mlx5_flow_dv_sample_resource *res,
10241 				struct rte_flow_error *error)
10242 {
10243 	struct mlx5_priv *priv = dev->data->dev_private;
10244 	const struct rte_flow_action *sub_actions;
10245 	struct mlx5_flow_sub_actions_list *sample_act;
10246 	struct mlx5_flow_sub_actions_idx *sample_idx;
10247 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
10248 	struct rte_flow *flow = dev_flow->flow;
10249 	struct mlx5_flow_rss_desc *rss_desc;
10250 	uint64_t action_flags = 0;
10251 
10252 	MLX5_ASSERT(wks);
10253 	rss_desc = &wks->rss_desc;
10254 	sample_act = &res->sample_act;
10255 	sample_idx = &res->sample_idx;
10256 	res->ratio = action->ratio;
10257 	sub_actions = action->actions;
10258 	for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) {
10259 		int type = sub_actions->type;
10260 		uint32_t pre_rix = 0;
10261 		void *pre_r;
10262 		switch (type) {
10263 		case RTE_FLOW_ACTION_TYPE_QUEUE:
10264 		{
10265 			const struct rte_flow_action_queue *queue;
10266 			struct mlx5_hrxq *hrxq;
10267 			uint32_t hrxq_idx;
10268 
10269 			queue = sub_actions->conf;
10270 			rss_desc->queue_num = 1;
10271 			rss_desc->queue[0] = queue->index;
10272 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
10273 						    rss_desc, &hrxq_idx);
10274 			if (!hrxq)
10275 				return rte_flow_error_set
10276 					(error, rte_errno,
10277 					 RTE_FLOW_ERROR_TYPE_ACTION,
10278 					 NULL,
10279 					 "cannot create fate queue");
10280 			sample_act->dr_queue_action = hrxq->action;
10281 			sample_idx->rix_hrxq = hrxq_idx;
10282 			sample_actions[sample_act->actions_num++] =
10283 						hrxq->action;
10284 			(*num_of_dest)++;
10285 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
10286 			if (action_flags & MLX5_FLOW_ACTION_MARK)
10287 				dev_flow->handle->rix_hrxq = hrxq_idx;
10288 			dev_flow->handle->fate_action =
10289 					MLX5_FLOW_FATE_QUEUE;
10290 			break;
10291 		}
10292 		case RTE_FLOW_ACTION_TYPE_RSS:
10293 		{
10294 			struct mlx5_hrxq *hrxq;
10295 			uint32_t hrxq_idx;
10296 			const struct rte_flow_action_rss *rss;
10297 			const uint8_t *rss_key;
10298 
10299 			rss = sub_actions->conf;
10300 			memcpy(rss_desc->queue, rss->queue,
10301 			       rss->queue_num * sizeof(uint16_t));
10302 			rss_desc->queue_num = rss->queue_num;
10303 			/* NULL RSS key indicates default RSS key. */
10304 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
10305 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
10306 			/*
10307 			 * rss->level and rss.types should be set in advance
10308 			 * when expanding items for RSS.
10309 			 */
10310 			flow_dv_hashfields_set(dev_flow, rss_desc);
10311 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
10312 						    rss_desc, &hrxq_idx);
10313 			if (!hrxq)
10314 				return rte_flow_error_set
10315 					(error, rte_errno,
10316 					 RTE_FLOW_ERROR_TYPE_ACTION,
10317 					 NULL,
10318 					 "cannot create fate queue");
10319 			sample_act->dr_queue_action = hrxq->action;
10320 			sample_idx->rix_hrxq = hrxq_idx;
10321 			sample_actions[sample_act->actions_num++] =
10322 						hrxq->action;
10323 			(*num_of_dest)++;
10324 			action_flags |= MLX5_FLOW_ACTION_RSS;
10325 			if (action_flags & MLX5_FLOW_ACTION_MARK)
10326 				dev_flow->handle->rix_hrxq = hrxq_idx;
10327 			dev_flow->handle->fate_action =
10328 					MLX5_FLOW_FATE_QUEUE;
10329 			break;
10330 		}
10331 		case RTE_FLOW_ACTION_TYPE_MARK:
10332 		{
10333 			uint32_t tag_be = mlx5_flow_mark_set
10334 				(((const struct rte_flow_action_mark *)
10335 				(sub_actions->conf))->id);
10336 
10337 			dev_flow->handle->mark = 1;
10338 			pre_rix = dev_flow->handle->dvh.rix_tag;
10339 			/* Save the mark resource before sample */
10340 			pre_r = dev_flow->dv.tag_resource;
10341 			if (flow_dv_tag_resource_register(dev, tag_be,
10342 						  dev_flow, error))
10343 				return -rte_errno;
10344 			MLX5_ASSERT(dev_flow->dv.tag_resource);
10345 			sample_act->dr_tag_action =
10346 				dev_flow->dv.tag_resource->action;
10347 			sample_idx->rix_tag =
10348 				dev_flow->handle->dvh.rix_tag;
10349 			sample_actions[sample_act->actions_num++] =
10350 						sample_act->dr_tag_action;
10351 			/* Recover the mark resource after sample */
10352 			dev_flow->dv.tag_resource = pre_r;
10353 			dev_flow->handle->dvh.rix_tag = pre_rix;
10354 			action_flags |= MLX5_FLOW_ACTION_MARK;
10355 			break;
10356 		}
10357 		case RTE_FLOW_ACTION_TYPE_COUNT:
10358 		{
10359 			if (!flow->counter) {
10360 				flow->counter =
10361 					flow_dv_translate_create_counter(dev,
10362 						dev_flow, sub_actions->conf,
10363 						0);
10364 				if (!flow->counter)
10365 					return rte_flow_error_set
10366 						(error, rte_errno,
10367 						RTE_FLOW_ERROR_TYPE_ACTION,
10368 						NULL,
10369 						"cannot create counter"
10370 						" object.");
10371 			}
10372 			sample_act->dr_cnt_action =
10373 				  (flow_dv_counter_get_by_idx(dev,
10374 				  flow->counter, NULL))->action;
10375 			sample_actions[sample_act->actions_num++] =
10376 						sample_act->dr_cnt_action;
10377 			action_flags |= MLX5_FLOW_ACTION_COUNT;
10378 			break;
10379 		}
10380 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
10381 		{
10382 			struct mlx5_flow_dv_port_id_action_resource
10383 					port_id_resource;
10384 			uint32_t port_id = 0;
10385 
10386 			memset(&port_id_resource, 0, sizeof(port_id_resource));
10387 			/* Save the port id resource before sample */
10388 			pre_rix = dev_flow->handle->rix_port_id_action;
10389 			pre_r = dev_flow->dv.port_id_action;
10390 			if (flow_dv_translate_action_port_id(dev, sub_actions,
10391 							     &port_id, error))
10392 				return -rte_errno;
10393 			port_id_resource.port_id = port_id;
10394 			if (flow_dv_port_id_action_resource_register
10395 			    (dev, &port_id_resource, dev_flow, error))
10396 				return -rte_errno;
10397 			sample_act->dr_port_id_action =
10398 				dev_flow->dv.port_id_action->action;
10399 			sample_idx->rix_port_id_action =
10400 				dev_flow->handle->rix_port_id_action;
10401 			sample_actions[sample_act->actions_num++] =
10402 						sample_act->dr_port_id_action;
10403 			/* Recover the port id resource after sample */
10404 			dev_flow->dv.port_id_action = pre_r;
10405 			dev_flow->handle->rix_port_id_action = pre_rix;
10406 			(*num_of_dest)++;
10407 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
10408 			break;
10409 		}
10410 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
10411 			/* Save the encap resource before sample */
10412 			pre_rix = dev_flow->handle->dvh.rix_encap_decap;
10413 			pre_r = dev_flow->dv.encap_decap;
10414 			if (flow_dv_create_action_l2_encap(dev, sub_actions,
10415 							   dev_flow,
10416 							   attr->transfer,
10417 							   error))
10418 				return -rte_errno;
10419 			sample_act->dr_encap_action =
10420 				dev_flow->dv.encap_decap->action;
10421 			sample_idx->rix_encap_decap =
10422 				dev_flow->handle->dvh.rix_encap_decap;
10423 			sample_actions[sample_act->actions_num++] =
10424 						sample_act->dr_encap_action;
10425 			/* Recover the encap resource after sample */
10426 			dev_flow->dv.encap_decap = pre_r;
10427 			dev_flow->handle->dvh.rix_encap_decap = pre_rix;
10428 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
10429 			break;
10430 		default:
10431 			return rte_flow_error_set(error, EINVAL,
10432 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10433 				NULL,
10434 				"Not support for sampler action");
10435 		}
10436 	}
10437 	sample_act->action_flags = action_flags;
10438 	res->ft_id = dev_flow->dv.group;
10439 	if (attr->transfer) {
10440 		union {
10441 			uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)];
10442 			uint64_t set_action;
10443 		} action_ctx = { .set_action = 0 };
10444 
10445 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
10446 		MLX5_SET(set_action_in, action_ctx.action_in, action_type,
10447 			 MLX5_MODIFICATION_TYPE_SET);
10448 		MLX5_SET(set_action_in, action_ctx.action_in, field,
10449 			 MLX5_MODI_META_REG_C_0);
10450 		MLX5_SET(set_action_in, action_ctx.action_in, data,
10451 			 priv->vport_meta_tag);
10452 		res->set_action = action_ctx.set_action;
10453 	} else if (attr->ingress) {
10454 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
10455 	} else {
10456 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
10457 	}
10458 	return 0;
10459 }
10460 
10461 /**
10462  * Convert Sample action to DV specification.
10463  *
10464  * @param[in] dev
10465  *   Pointer to rte_eth_dev structure.
10466  * @param[in, out] dev_flow
10467  *   Pointer to the mlx5_flow.
10468  * @param[in] num_of_dest
10469  *   The num of destination.
10470  * @param[in, out] res
10471  *   Pointer to sample resource.
10472  * @param[in, out] mdest_res
10473  *   Pointer to destination array resource.
10474  * @param[in] sample_actions
10475  *   Pointer to sample path actions list.
10476  * @param[in] action_flags
10477  *   Holds the actions detected until now.
10478  * @param[out] error
10479  *   Pointer to the error structure.
10480  *
10481  * @return
10482  *   0 on success, a negative errno value otherwise and rte_errno is set.
10483  */
10484 static int
10485 flow_dv_create_action_sample(struct rte_eth_dev *dev,
10486 			     struct mlx5_flow *dev_flow,
10487 			     uint32_t num_of_dest,
10488 			     struct mlx5_flow_dv_sample_resource *res,
10489 			     struct mlx5_flow_dv_dest_array_resource *mdest_res,
10490 			     void **sample_actions,
10491 			     uint64_t action_flags,
10492 			     struct rte_flow_error *error)
10493 {
10494 	/* update normal path action resource into last index of array */
10495 	uint32_t dest_index = MLX5_MAX_DEST_NUM - 1;
10496 	struct mlx5_flow_sub_actions_list *sample_act =
10497 					&mdest_res->sample_act[dest_index];
10498 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
10499 	struct mlx5_flow_rss_desc *rss_desc;
10500 	uint32_t normal_idx = 0;
10501 	struct mlx5_hrxq *hrxq;
10502 	uint32_t hrxq_idx;
10503 
10504 	MLX5_ASSERT(wks);
10505 	rss_desc = &wks->rss_desc;
10506 	if (num_of_dest > 1) {
10507 		if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) {
10508 			/* Handle QP action for mirroring */
10509 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
10510 						    rss_desc, &hrxq_idx);
10511 			if (!hrxq)
10512 				return rte_flow_error_set
10513 				     (error, rte_errno,
10514 				      RTE_FLOW_ERROR_TYPE_ACTION,
10515 				      NULL,
10516 				      "cannot create rx queue");
10517 			normal_idx++;
10518 			mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx;
10519 			sample_act->dr_queue_action = hrxq->action;
10520 			if (action_flags & MLX5_FLOW_ACTION_MARK)
10521 				dev_flow->handle->rix_hrxq = hrxq_idx;
10522 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
10523 		}
10524 		if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) {
10525 			normal_idx++;
10526 			mdest_res->sample_idx[dest_index].rix_encap_decap =
10527 				dev_flow->handle->dvh.rix_encap_decap;
10528 			sample_act->dr_encap_action =
10529 				dev_flow->dv.encap_decap->action;
10530 		}
10531 		if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) {
10532 			normal_idx++;
10533 			mdest_res->sample_idx[dest_index].rix_port_id_action =
10534 				dev_flow->handle->rix_port_id_action;
10535 			sample_act->dr_port_id_action =
10536 				dev_flow->dv.port_id_action->action;
10537 		}
10538 		if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) {
10539 			normal_idx++;
10540 			mdest_res->sample_idx[dest_index].rix_jump =
10541 				dev_flow->handle->rix_jump;
10542 			sample_act->dr_jump_action =
10543 				dev_flow->dv.jump->action;
10544 			dev_flow->handle->rix_jump = 0;
10545 		}
10546 		sample_act->actions_num = normal_idx;
10547 		/* update sample action resource into first index of array */
10548 		mdest_res->ft_type = res->ft_type;
10549 		memcpy(&mdest_res->sample_idx[0], &res->sample_idx,
10550 				sizeof(struct mlx5_flow_sub_actions_idx));
10551 		memcpy(&mdest_res->sample_act[0], &res->sample_act,
10552 				sizeof(struct mlx5_flow_sub_actions_list));
10553 		mdest_res->num_of_dest = num_of_dest;
10554 		if (flow_dv_dest_array_resource_register(dev, mdest_res,
10555 							 dev_flow, error))
10556 			return rte_flow_error_set(error, EINVAL,
10557 						  RTE_FLOW_ERROR_TYPE_ACTION,
10558 						  NULL, "can't create sample "
10559 						  "action");
10560 	} else {
10561 		res->sub_actions = sample_actions;
10562 		if (flow_dv_sample_resource_register(dev, res, dev_flow, error))
10563 			return rte_flow_error_set(error, EINVAL,
10564 						  RTE_FLOW_ERROR_TYPE_ACTION,
10565 						  NULL,
10566 						  "can't create sample action");
10567 	}
10568 	return 0;
10569 }
10570 
10571 /**
10572  * Remove an ASO age action from age actions list.
10573  *
10574  * @param[in] dev
10575  *   Pointer to the Ethernet device structure.
10576  * @param[in] age
10577  *   Pointer to the aso age action handler.
10578  */
10579 static void
10580 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev,
10581 				struct mlx5_aso_age_action *age)
10582 {
10583 	struct mlx5_age_info *age_info;
10584 	struct mlx5_age_param *age_param = &age->age_params;
10585 	struct mlx5_priv *priv = dev->data->dev_private;
10586 	uint16_t expected = AGE_CANDIDATE;
10587 
10588 	age_info = GET_PORT_AGE_INFO(priv);
10589 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
10590 					 AGE_FREE, false, __ATOMIC_RELAXED,
10591 					 __ATOMIC_RELAXED)) {
10592 		/**
10593 		 * We need the lock even it is age timeout,
10594 		 * since age action may still in process.
10595 		 */
10596 		rte_spinlock_lock(&age_info->aged_sl);
10597 		LIST_REMOVE(age, next);
10598 		rte_spinlock_unlock(&age_info->aged_sl);
10599 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
10600 	}
10601 }
10602 
10603 /**
10604  * Release an ASO age action.
10605  *
10606  * @param[in] dev
10607  *   Pointer to the Ethernet device structure.
10608  * @param[in] age_idx
10609  *   Index of ASO age action to release.
10610  * @param[in] flow
10611  *   True if the release operation is during flow destroy operation.
10612  *   False if the release operation is during action destroy operation.
10613  *
10614  * @return
10615  *   0 when age action was removed, otherwise the number of references.
10616  */
10617 static int
10618 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx)
10619 {
10620 	struct mlx5_priv *priv = dev->data->dev_private;
10621 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
10622 	struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx);
10623 	uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED);
10624 
10625 	if (!ret) {
10626 		flow_dv_aso_age_remove_from_age(dev, age);
10627 		rte_spinlock_lock(&mng->free_sl);
10628 		LIST_INSERT_HEAD(&mng->free, age, next);
10629 		rte_spinlock_unlock(&mng->free_sl);
10630 	}
10631 	return ret;
10632 }
10633 
10634 /**
10635  * Resize the ASO age pools array by MLX5_CNT_CONTAINER_RESIZE pools.
10636  *
10637  * @param[in] dev
10638  *   Pointer to the Ethernet device structure.
10639  *
10640  * @return
10641  *   0 on success, otherwise negative errno value and rte_errno is set.
10642  */
10643 static int
10644 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev)
10645 {
10646 	struct mlx5_priv *priv = dev->data->dev_private;
10647 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
10648 	void *old_pools = mng->pools;
10649 	uint32_t resize = mng->n + MLX5_CNT_CONTAINER_RESIZE;
10650 	uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize;
10651 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
10652 
10653 	if (!pools) {
10654 		rte_errno = ENOMEM;
10655 		return -ENOMEM;
10656 	}
10657 	if (old_pools) {
10658 		memcpy(pools, old_pools,
10659 		       mng->n * sizeof(struct mlx5_flow_counter_pool *));
10660 		mlx5_free(old_pools);
10661 	} else {
10662 		/* First ASO flow hit allocation - starting ASO data-path. */
10663 		int ret = mlx5_aso_queue_start(priv->sh);
10664 
10665 		if (ret) {
10666 			mlx5_free(pools);
10667 			return ret;
10668 		}
10669 	}
10670 	mng->n = resize;
10671 	mng->pools = pools;
10672 	return 0;
10673 }
10674 
10675 /**
10676  * Create and initialize a new ASO aging pool.
10677  *
10678  * @param[in] dev
10679  *   Pointer to the Ethernet device structure.
10680  * @param[out] age_free
10681  *   Where to put the pointer of a new age action.
10682  *
10683  * @return
10684  *   The age actions pool pointer and @p age_free is set on success,
10685  *   NULL otherwise and rte_errno is set.
10686  */
10687 static struct mlx5_aso_age_pool *
10688 flow_dv_age_pool_create(struct rte_eth_dev *dev,
10689 			struct mlx5_aso_age_action **age_free)
10690 {
10691 	struct mlx5_priv *priv = dev->data->dev_private;
10692 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
10693 	struct mlx5_aso_age_pool *pool = NULL;
10694 	struct mlx5_devx_obj *obj = NULL;
10695 	uint32_t i;
10696 
10697 	obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->ctx,
10698 						    priv->sh->pdn);
10699 	if (!obj) {
10700 		rte_errno = ENODATA;
10701 		DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX.");
10702 		return NULL;
10703 	}
10704 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
10705 	if (!pool) {
10706 		claim_zero(mlx5_devx_cmd_destroy(obj));
10707 		rte_errno = ENOMEM;
10708 		return NULL;
10709 	}
10710 	pool->flow_hit_aso_obj = obj;
10711 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
10712 	rte_spinlock_lock(&mng->resize_sl);
10713 	pool->index = mng->next;
10714 	/* Resize pools array if there is no room for the new pool in it. */
10715 	if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) {
10716 		claim_zero(mlx5_devx_cmd_destroy(obj));
10717 		mlx5_free(pool);
10718 		rte_spinlock_unlock(&mng->resize_sl);
10719 		return NULL;
10720 	}
10721 	mng->pools[pool->index] = pool;
10722 	mng->next++;
10723 	rte_spinlock_unlock(&mng->resize_sl);
10724 	/* Assign the first action in the new pool, the rest go to free list. */
10725 	*age_free = &pool->actions[0];
10726 	for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) {
10727 		pool->actions[i].offset = i;
10728 		LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next);
10729 	}
10730 	return pool;
10731 }
10732 
10733 /**
10734  * Allocate a ASO aging bit.
10735  *
10736  * @param[in] dev
10737  *   Pointer to the Ethernet device structure.
10738  * @param[out] error
10739  *   Pointer to the error structure.
10740  *
10741  * @return
10742  *   Index to ASO age action on success, 0 otherwise and rte_errno is set.
10743  */
10744 static uint32_t
10745 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
10746 {
10747 	struct mlx5_priv *priv = dev->data->dev_private;
10748 	const struct mlx5_aso_age_pool *pool;
10749 	struct mlx5_aso_age_action *age_free = NULL;
10750 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
10751 
10752 	MLX5_ASSERT(mng);
10753 	/* Try to get the next free age action bit. */
10754 	rte_spinlock_lock(&mng->free_sl);
10755 	age_free = LIST_FIRST(&mng->free);
10756 	if (age_free) {
10757 		LIST_REMOVE(age_free, next);
10758 	} else if (!flow_dv_age_pool_create(dev, &age_free)) {
10759 		rte_spinlock_unlock(&mng->free_sl);
10760 		rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
10761 				   NULL, "failed to create ASO age pool");
10762 		return 0; /* 0 is an error. */
10763 	}
10764 	rte_spinlock_unlock(&mng->free_sl);
10765 	pool = container_of
10766 	  ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL])
10767 		  (age_free - age_free->offset), const struct mlx5_aso_age_pool,
10768 								       actions);
10769 	if (!age_free->dr_action) {
10770 		int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0,
10771 						 error);
10772 
10773 		if (reg_c < 0) {
10774 			rte_flow_error_set(error, rte_errno,
10775 					   RTE_FLOW_ERROR_TYPE_ACTION,
10776 					   NULL, "failed to get reg_c "
10777 					   "for ASO flow hit");
10778 			return 0; /* 0 is an error. */
10779 		}
10780 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
10781 		age_free->dr_action = mlx5_glue->dv_create_flow_action_aso
10782 				(priv->sh->rx_domain,
10783 				 pool->flow_hit_aso_obj->obj, age_free->offset,
10784 				 MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET,
10785 				 (reg_c - REG_C_0));
10786 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
10787 		if (!age_free->dr_action) {
10788 			rte_errno = errno;
10789 			rte_spinlock_lock(&mng->free_sl);
10790 			LIST_INSERT_HEAD(&mng->free, age_free, next);
10791 			rte_spinlock_unlock(&mng->free_sl);
10792 			rte_flow_error_set(error, rte_errno,
10793 					   RTE_FLOW_ERROR_TYPE_ACTION,
10794 					   NULL, "failed to create ASO "
10795 					   "flow hit action");
10796 			return 0; /* 0 is an error. */
10797 		}
10798 	}
10799 	__atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED);
10800 	return pool->index | ((age_free->offset + 1) << 16);
10801 }
10802 
10803 /**
10804  * Create a age action using ASO mechanism.
10805  *
10806  * @param[in] dev
10807  *   Pointer to rte_eth_dev structure.
10808  * @param[in] age
10809  *   Pointer to the aging action configuration.
10810  * @param[out] error
10811  *   Pointer to the error structure.
10812  *
10813  * @return
10814  *   Index to flow counter on success, 0 otherwise.
10815  */
10816 static uint32_t
10817 flow_dv_translate_create_aso_age(struct rte_eth_dev *dev,
10818 				 const struct rte_flow_action_age *age,
10819 				 struct rte_flow_error *error)
10820 {
10821 	uint32_t age_idx = 0;
10822 	struct mlx5_aso_age_action *aso_age;
10823 
10824 	age_idx = flow_dv_aso_age_alloc(dev, error);
10825 	if (!age_idx)
10826 		return 0;
10827 	aso_age = flow_aso_age_get_by_idx(dev, age_idx);
10828 	aso_age->age_params.context = age->context;
10829 	aso_age->age_params.timeout = age->timeout;
10830 	aso_age->age_params.port_id = dev->data->port_id;
10831 	__atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0,
10832 			 __ATOMIC_RELAXED);
10833 	__atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE,
10834 			 __ATOMIC_RELAXED);
10835 	return age_idx;
10836 }
10837 
10838 /**
10839  * Fill the flow with DV spec, lock free
10840  * (mutex should be acquired by caller).
10841  *
10842  * @param[in] dev
10843  *   Pointer to rte_eth_dev structure.
10844  * @param[in, out] dev_flow
10845  *   Pointer to the sub flow.
10846  * @param[in] attr
10847  *   Pointer to the flow attributes.
10848  * @param[in] items
10849  *   Pointer to the list of items.
10850  * @param[in] actions
10851  *   Pointer to the list of actions.
10852  * @param[out] error
10853  *   Pointer to the error structure.
10854  *
10855  * @return
10856  *   0 on success, a negative errno value otherwise and rte_errno is set.
10857  */
10858 static int
10859 flow_dv_translate(struct rte_eth_dev *dev,
10860 		  struct mlx5_flow *dev_flow,
10861 		  const struct rte_flow_attr *attr,
10862 		  const struct rte_flow_item items[],
10863 		  const struct rte_flow_action actions[],
10864 		  struct rte_flow_error *error)
10865 {
10866 	struct mlx5_priv *priv = dev->data->dev_private;
10867 	struct mlx5_dev_config *dev_conf = &priv->config;
10868 	struct rte_flow *flow = dev_flow->flow;
10869 	struct mlx5_flow_handle *handle = dev_flow->handle;
10870 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
10871 	struct mlx5_flow_rss_desc *rss_desc;
10872 	uint64_t item_flags = 0;
10873 	uint64_t last_item = 0;
10874 	uint64_t action_flags = 0;
10875 	struct mlx5_flow_dv_matcher matcher = {
10876 		.mask = {
10877 			.size = sizeof(matcher.mask.buf) -
10878 				MLX5_ST_SZ_BYTES(fte_match_set_misc4),
10879 		},
10880 	};
10881 	int actions_n = 0;
10882 	bool actions_end = false;
10883 	union {
10884 		struct mlx5_flow_dv_modify_hdr_resource res;
10885 		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
10886 			    sizeof(struct mlx5_modification_cmd) *
10887 			    (MLX5_MAX_MODIFY_NUM + 1)];
10888 	} mhdr_dummy;
10889 	struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
10890 	const struct rte_flow_action_count *count = NULL;
10891 	const struct rte_flow_action_age *age = NULL;
10892 	union flow_dv_attr flow_attr = { .attr = 0 };
10893 	uint32_t tag_be;
10894 	union mlx5_flow_tbl_key tbl_key;
10895 	uint32_t modify_action_position = UINT32_MAX;
10896 	void *match_mask = matcher.mask.buf;
10897 	void *match_value = dev_flow->dv.value.buf;
10898 	uint8_t next_protocol = 0xff;
10899 	struct rte_vlan_hdr vlan = { 0 };
10900 	struct mlx5_flow_dv_dest_array_resource mdest_res;
10901 	struct mlx5_flow_dv_sample_resource sample_res;
10902 	void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
10903 	const struct rte_flow_action_sample *sample = NULL;
10904 	struct mlx5_flow_sub_actions_list *sample_act;
10905 	uint32_t sample_act_pos = UINT32_MAX;
10906 	uint32_t num_of_dest = 0;
10907 	int tmp_actions_n = 0;
10908 	uint32_t table;
10909 	int ret = 0;
10910 	const struct mlx5_flow_tunnel *tunnel;
10911 	struct flow_grp_info grp_info = {
10912 		.external = !!dev_flow->external,
10913 		.transfer = !!attr->transfer,
10914 		.fdb_def_rule = !!priv->fdb_def_rule,
10915 		.skip_scale = dev_flow->skip_scale &
10916 			(1 << MLX5_SCALE_FLOW_GROUP_BIT),
10917 	};
10918 
10919 	if (!wks)
10920 		return rte_flow_error_set(error, ENOMEM,
10921 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10922 					  NULL,
10923 					  "failed to push flow workspace");
10924 	rss_desc = &wks->rss_desc;
10925 	memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource));
10926 	memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource));
10927 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
10928 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
10929 	/* update normal path action resource into last index of array */
10930 	sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1];
10931 	tunnel = is_flow_tunnel_match_rule(dev, attr, items, actions) ?
10932 		 flow_items_to_tunnel(items) :
10933 		 is_flow_tunnel_steer_rule(dev, attr, items, actions) ?
10934 		 flow_actions_to_tunnel(actions) :
10935 		 dev_flow->tunnel ? dev_flow->tunnel : NULL;
10936 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
10937 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
10938 	grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
10939 				(dev, tunnel, attr, items, actions);
10940 	ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table,
10941 				       &grp_info, error);
10942 	if (ret)
10943 		return ret;
10944 	dev_flow->dv.group = table;
10945 	if (attr->transfer)
10946 		mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
10947 	/* number of actions must be set to 0 in case of dirty stack. */
10948 	mhdr_res->actions_num = 0;
10949 	if (is_flow_tunnel_match_rule(dev, attr, items, actions)) {
10950 		/*
10951 		 * do not add decap action if match rule drops packet
10952 		 * HW rejects rules with decap & drop
10953 		 *
10954 		 * if tunnel match rule was inserted before matching tunnel set
10955 		 * rule flow table used in the match rule must be registered.
10956 		 * current implementation handles that in the
10957 		 * flow_dv_match_register() at the function end.
10958 		 */
10959 		bool add_decap = true;
10960 		const struct rte_flow_action *ptr = actions;
10961 
10962 		for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) {
10963 			if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) {
10964 				add_decap = false;
10965 				break;
10966 			}
10967 		}
10968 		if (add_decap) {
10969 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
10970 							   attr->transfer,
10971 							   error))
10972 				return -rte_errno;
10973 			dev_flow->dv.actions[actions_n++] =
10974 					dev_flow->dv.encap_decap->action;
10975 			action_flags |= MLX5_FLOW_ACTION_DECAP;
10976 		}
10977 	}
10978 	for (; !actions_end ; actions++) {
10979 		const struct rte_flow_action_queue *queue;
10980 		const struct rte_flow_action_rss *rss;
10981 		const struct rte_flow_action *action = actions;
10982 		const uint8_t *rss_key;
10983 		const struct rte_flow_action_meter *mtr;
10984 		struct mlx5_flow_tbl_resource *tbl;
10985 		struct mlx5_aso_age_action *age_act;
10986 		uint32_t port_id = 0;
10987 		struct mlx5_flow_dv_port_id_action_resource port_id_resource;
10988 		int action_type = actions->type;
10989 		const struct rte_flow_action *found_action = NULL;
10990 		struct mlx5_flow_meter *fm = NULL;
10991 		uint32_t jump_group = 0;
10992 
10993 		if (!mlx5_flow_os_action_supported(action_type))
10994 			return rte_flow_error_set(error, ENOTSUP,
10995 						  RTE_FLOW_ERROR_TYPE_ACTION,
10996 						  actions,
10997 						  "action not supported");
10998 		switch (action_type) {
10999 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
11000 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
11001 			break;
11002 		case RTE_FLOW_ACTION_TYPE_VOID:
11003 			break;
11004 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
11005 			if (flow_dv_translate_action_port_id(dev, action,
11006 							     &port_id, error))
11007 				return -rte_errno;
11008 			port_id_resource.port_id = port_id;
11009 			MLX5_ASSERT(!handle->rix_port_id_action);
11010 			if (flow_dv_port_id_action_resource_register
11011 			    (dev, &port_id_resource, dev_flow, error))
11012 				return -rte_errno;
11013 			dev_flow->dv.actions[actions_n++] =
11014 					dev_flow->dv.port_id_action->action;
11015 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
11016 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID;
11017 			sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID;
11018 			num_of_dest++;
11019 			break;
11020 		case RTE_FLOW_ACTION_TYPE_FLAG:
11021 			action_flags |= MLX5_FLOW_ACTION_FLAG;
11022 			dev_flow->handle->mark = 1;
11023 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
11024 				struct rte_flow_action_mark mark = {
11025 					.id = MLX5_FLOW_MARK_DEFAULT,
11026 				};
11027 
11028 				if (flow_dv_convert_action_mark(dev, &mark,
11029 								mhdr_res,
11030 								error))
11031 					return -rte_errno;
11032 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
11033 				break;
11034 			}
11035 			tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
11036 			/*
11037 			 * Only one FLAG or MARK is supported per device flow
11038 			 * right now. So the pointer to the tag resource must be
11039 			 * zero before the register process.
11040 			 */
11041 			MLX5_ASSERT(!handle->dvh.rix_tag);
11042 			if (flow_dv_tag_resource_register(dev, tag_be,
11043 							  dev_flow, error))
11044 				return -rte_errno;
11045 			MLX5_ASSERT(dev_flow->dv.tag_resource);
11046 			dev_flow->dv.actions[actions_n++] =
11047 					dev_flow->dv.tag_resource->action;
11048 			break;
11049 		case RTE_FLOW_ACTION_TYPE_MARK:
11050 			action_flags |= MLX5_FLOW_ACTION_MARK;
11051 			dev_flow->handle->mark = 1;
11052 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
11053 				const struct rte_flow_action_mark *mark =
11054 					(const struct rte_flow_action_mark *)
11055 						actions->conf;
11056 
11057 				if (flow_dv_convert_action_mark(dev, mark,
11058 								mhdr_res,
11059 								error))
11060 					return -rte_errno;
11061 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
11062 				break;
11063 			}
11064 			/* Fall-through */
11065 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
11066 			/* Legacy (non-extensive) MARK action. */
11067 			tag_be = mlx5_flow_mark_set
11068 			      (((const struct rte_flow_action_mark *)
11069 			       (actions->conf))->id);
11070 			MLX5_ASSERT(!handle->dvh.rix_tag);
11071 			if (flow_dv_tag_resource_register(dev, tag_be,
11072 							  dev_flow, error))
11073 				return -rte_errno;
11074 			MLX5_ASSERT(dev_flow->dv.tag_resource);
11075 			dev_flow->dv.actions[actions_n++] =
11076 					dev_flow->dv.tag_resource->action;
11077 			break;
11078 		case RTE_FLOW_ACTION_TYPE_SET_META:
11079 			if (flow_dv_convert_action_set_meta
11080 				(dev, mhdr_res, attr,
11081 				 (const struct rte_flow_action_set_meta *)
11082 				  actions->conf, error))
11083 				return -rte_errno;
11084 			action_flags |= MLX5_FLOW_ACTION_SET_META;
11085 			break;
11086 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
11087 			if (flow_dv_convert_action_set_tag
11088 				(dev, mhdr_res,
11089 				 (const struct rte_flow_action_set_tag *)
11090 				  actions->conf, error))
11091 				return -rte_errno;
11092 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
11093 			break;
11094 		case RTE_FLOW_ACTION_TYPE_DROP:
11095 			action_flags |= MLX5_FLOW_ACTION_DROP;
11096 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
11097 			break;
11098 		case RTE_FLOW_ACTION_TYPE_QUEUE:
11099 			queue = actions->conf;
11100 			rss_desc->queue_num = 1;
11101 			rss_desc->queue[0] = queue->index;
11102 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
11103 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
11104 			sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE;
11105 			num_of_dest++;
11106 			break;
11107 		case RTE_FLOW_ACTION_TYPE_RSS:
11108 			rss = actions->conf;
11109 			memcpy(rss_desc->queue, rss->queue,
11110 			       rss->queue_num * sizeof(uint16_t));
11111 			rss_desc->queue_num = rss->queue_num;
11112 			/* NULL RSS key indicates default RSS key. */
11113 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
11114 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
11115 			/*
11116 			 * rss->level and rss.types should be set in advance
11117 			 * when expanding items for RSS.
11118 			 */
11119 			action_flags |= MLX5_FLOW_ACTION_RSS;
11120 			dev_flow->handle->fate_action = rss_desc->shared_rss ?
11121 				MLX5_FLOW_FATE_SHARED_RSS :
11122 				MLX5_FLOW_FATE_QUEUE;
11123 			break;
11124 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
11125 			flow->age = (uint32_t)(uintptr_t)(action->conf);
11126 			age_act = flow_aso_age_get_by_idx(dev, flow->age);
11127 			__atomic_fetch_add(&age_act->refcnt, 1,
11128 					   __ATOMIC_RELAXED);
11129 			dev_flow->dv.actions[actions_n++] = age_act->dr_action;
11130 			action_flags |= MLX5_FLOW_ACTION_AGE;
11131 			break;
11132 		case RTE_FLOW_ACTION_TYPE_AGE:
11133 			if (priv->sh->flow_hit_aso_en && attr->group) {
11134 				/*
11135 				 * Create one shared age action, to be used
11136 				 * by all sub-flows.
11137 				 */
11138 				if (!flow->age) {
11139 					flow->age =
11140 						flow_dv_translate_create_aso_age
11141 							(dev, action->conf,
11142 							 error);
11143 					if (!flow->age)
11144 						return rte_flow_error_set
11145 						(error, rte_errno,
11146 						 RTE_FLOW_ERROR_TYPE_ACTION,
11147 						 NULL,
11148 						 "can't create ASO age action");
11149 				}
11150 				dev_flow->dv.actions[actions_n++] =
11151 					  (flow_aso_age_get_by_idx
11152 						(dev, flow->age))->dr_action;
11153 				action_flags |= MLX5_FLOW_ACTION_AGE;
11154 				break;
11155 			}
11156 			/* Fall-through */
11157 		case RTE_FLOW_ACTION_TYPE_COUNT:
11158 			if (!dev_conf->devx) {
11159 				return rte_flow_error_set
11160 					      (error, ENOTSUP,
11161 					       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11162 					       NULL,
11163 					       "count action not supported");
11164 			}
11165 			/* Save information first, will apply later. */
11166 			if (actions->type == RTE_FLOW_ACTION_TYPE_COUNT)
11167 				count = action->conf;
11168 			else
11169 				age = action->conf;
11170 			action_flags |= MLX5_FLOW_ACTION_COUNT;
11171 			break;
11172 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
11173 			dev_flow->dv.actions[actions_n++] =
11174 						priv->sh->pop_vlan_action;
11175 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
11176 			break;
11177 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
11178 			if (!(action_flags &
11179 			      MLX5_FLOW_ACTION_OF_SET_VLAN_VID))
11180 				flow_dev_get_vlan_info_from_items(items, &vlan);
11181 			vlan.eth_proto = rte_be_to_cpu_16
11182 			     ((((const struct rte_flow_action_of_push_vlan *)
11183 						   actions->conf)->ethertype));
11184 			found_action = mlx5_flow_find_action
11185 					(actions + 1,
11186 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID);
11187 			if (found_action)
11188 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
11189 			found_action = mlx5_flow_find_action
11190 					(actions + 1,
11191 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP);
11192 			if (found_action)
11193 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
11194 			if (flow_dv_create_action_push_vlan
11195 					    (dev, attr, &vlan, dev_flow, error))
11196 				return -rte_errno;
11197 			dev_flow->dv.actions[actions_n++] =
11198 					dev_flow->dv.push_vlan_res->action;
11199 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
11200 			break;
11201 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
11202 			/* of_vlan_push action handled this action */
11203 			MLX5_ASSERT(action_flags &
11204 				    MLX5_FLOW_ACTION_OF_PUSH_VLAN);
11205 			break;
11206 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
11207 			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
11208 				break;
11209 			flow_dev_get_vlan_info_from_items(items, &vlan);
11210 			mlx5_update_vlan_vid_pcp(actions, &vlan);
11211 			/* If no VLAN push - this is a modify header action */
11212 			if (flow_dv_convert_action_modify_vlan_vid
11213 						(mhdr_res, actions, error))
11214 				return -rte_errno;
11215 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
11216 			break;
11217 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
11218 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
11219 			if (flow_dv_create_action_l2_encap(dev, actions,
11220 							   dev_flow,
11221 							   attr->transfer,
11222 							   error))
11223 				return -rte_errno;
11224 			dev_flow->dv.actions[actions_n++] =
11225 					dev_flow->dv.encap_decap->action;
11226 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
11227 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
11228 				sample_act->action_flags |=
11229 							MLX5_FLOW_ACTION_ENCAP;
11230 			break;
11231 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
11232 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
11233 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
11234 							   attr->transfer,
11235 							   error))
11236 				return -rte_errno;
11237 			dev_flow->dv.actions[actions_n++] =
11238 					dev_flow->dv.encap_decap->action;
11239 			action_flags |= MLX5_FLOW_ACTION_DECAP;
11240 			break;
11241 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
11242 			/* Handle encap with preceding decap. */
11243 			if (action_flags & MLX5_FLOW_ACTION_DECAP) {
11244 				if (flow_dv_create_action_raw_encap
11245 					(dev, actions, dev_flow, attr, error))
11246 					return -rte_errno;
11247 				dev_flow->dv.actions[actions_n++] =
11248 					dev_flow->dv.encap_decap->action;
11249 			} else {
11250 				/* Handle encap without preceding decap. */
11251 				if (flow_dv_create_action_l2_encap
11252 				    (dev, actions, dev_flow, attr->transfer,
11253 				     error))
11254 					return -rte_errno;
11255 				dev_flow->dv.actions[actions_n++] =
11256 					dev_flow->dv.encap_decap->action;
11257 			}
11258 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
11259 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
11260 				sample_act->action_flags |=
11261 							MLX5_FLOW_ACTION_ENCAP;
11262 			break;
11263 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
11264 			while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID)
11265 				;
11266 			if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
11267 				if (flow_dv_create_action_l2_decap
11268 				    (dev, dev_flow, attr->transfer, error))
11269 					return -rte_errno;
11270 				dev_flow->dv.actions[actions_n++] =
11271 					dev_flow->dv.encap_decap->action;
11272 			}
11273 			/* If decap is followed by encap, handle it at encap. */
11274 			action_flags |= MLX5_FLOW_ACTION_DECAP;
11275 			break;
11276 		case RTE_FLOW_ACTION_TYPE_JUMP:
11277 			jump_group = ((const struct rte_flow_action_jump *)
11278 							action->conf)->group;
11279 			grp_info.std_tbl_fix = 0;
11280 			if (dev_flow->skip_scale &
11281 				(1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT))
11282 				grp_info.skip_scale = 1;
11283 			else
11284 				grp_info.skip_scale = 0;
11285 			ret = mlx5_flow_group_to_table(dev, tunnel,
11286 						       jump_group,
11287 						       &table,
11288 						       &grp_info, error);
11289 			if (ret)
11290 				return ret;
11291 			tbl = flow_dv_tbl_resource_get(dev, table, attr->egress,
11292 						       attr->transfer,
11293 						       !!dev_flow->external,
11294 						       tunnel, jump_group, 0,
11295 						       error);
11296 			if (!tbl)
11297 				return rte_flow_error_set
11298 						(error, errno,
11299 						 RTE_FLOW_ERROR_TYPE_ACTION,
11300 						 NULL,
11301 						 "cannot create jump action.");
11302 			if (flow_dv_jump_tbl_resource_register
11303 			    (dev, tbl, dev_flow, error)) {
11304 				flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
11305 				return rte_flow_error_set
11306 						(error, errno,
11307 						 RTE_FLOW_ERROR_TYPE_ACTION,
11308 						 NULL,
11309 						 "cannot create jump action.");
11310 			}
11311 			dev_flow->dv.actions[actions_n++] =
11312 					dev_flow->dv.jump->action;
11313 			action_flags |= MLX5_FLOW_ACTION_JUMP;
11314 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP;
11315 			sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP;
11316 			num_of_dest++;
11317 			break;
11318 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
11319 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
11320 			if (flow_dv_convert_action_modify_mac
11321 					(mhdr_res, actions, error))
11322 				return -rte_errno;
11323 			action_flags |= actions->type ==
11324 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
11325 					MLX5_FLOW_ACTION_SET_MAC_SRC :
11326 					MLX5_FLOW_ACTION_SET_MAC_DST;
11327 			break;
11328 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
11329 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
11330 			if (flow_dv_convert_action_modify_ipv4
11331 					(mhdr_res, actions, error))
11332 				return -rte_errno;
11333 			action_flags |= actions->type ==
11334 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
11335 					MLX5_FLOW_ACTION_SET_IPV4_SRC :
11336 					MLX5_FLOW_ACTION_SET_IPV4_DST;
11337 			break;
11338 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
11339 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
11340 			if (flow_dv_convert_action_modify_ipv6
11341 					(mhdr_res, actions, error))
11342 				return -rte_errno;
11343 			action_flags |= actions->type ==
11344 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
11345 					MLX5_FLOW_ACTION_SET_IPV6_SRC :
11346 					MLX5_FLOW_ACTION_SET_IPV6_DST;
11347 			break;
11348 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
11349 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
11350 			if (flow_dv_convert_action_modify_tp
11351 					(mhdr_res, actions, items,
11352 					 &flow_attr, dev_flow, !!(action_flags &
11353 					 MLX5_FLOW_ACTION_DECAP), error))
11354 				return -rte_errno;
11355 			action_flags |= actions->type ==
11356 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
11357 					MLX5_FLOW_ACTION_SET_TP_SRC :
11358 					MLX5_FLOW_ACTION_SET_TP_DST;
11359 			break;
11360 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
11361 			if (flow_dv_convert_action_modify_dec_ttl
11362 					(mhdr_res, items, &flow_attr, dev_flow,
11363 					 !!(action_flags &
11364 					 MLX5_FLOW_ACTION_DECAP), error))
11365 				return -rte_errno;
11366 			action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
11367 			break;
11368 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
11369 			if (flow_dv_convert_action_modify_ttl
11370 					(mhdr_res, actions, items, &flow_attr,
11371 					 dev_flow, !!(action_flags &
11372 					 MLX5_FLOW_ACTION_DECAP), error))
11373 				return -rte_errno;
11374 			action_flags |= MLX5_FLOW_ACTION_SET_TTL;
11375 			break;
11376 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
11377 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
11378 			if (flow_dv_convert_action_modify_tcp_seq
11379 					(mhdr_res, actions, error))
11380 				return -rte_errno;
11381 			action_flags |= actions->type ==
11382 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
11383 					MLX5_FLOW_ACTION_INC_TCP_SEQ :
11384 					MLX5_FLOW_ACTION_DEC_TCP_SEQ;
11385 			break;
11386 
11387 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
11388 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
11389 			if (flow_dv_convert_action_modify_tcp_ack
11390 					(mhdr_res, actions, error))
11391 				return -rte_errno;
11392 			action_flags |= actions->type ==
11393 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
11394 					MLX5_FLOW_ACTION_INC_TCP_ACK :
11395 					MLX5_FLOW_ACTION_DEC_TCP_ACK;
11396 			break;
11397 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
11398 			if (flow_dv_convert_action_set_reg
11399 					(mhdr_res, actions, error))
11400 				return -rte_errno;
11401 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
11402 			break;
11403 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
11404 			if (flow_dv_convert_action_copy_mreg
11405 					(dev, mhdr_res, actions, error))
11406 				return -rte_errno;
11407 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
11408 			break;
11409 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
11410 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
11411 			dev_flow->handle->fate_action =
11412 					MLX5_FLOW_FATE_DEFAULT_MISS;
11413 			break;
11414 		case RTE_FLOW_ACTION_TYPE_METER:
11415 			mtr = actions->conf;
11416 			if (!flow->meter) {
11417 				fm = mlx5_flow_meter_attach(priv, mtr->mtr_id,
11418 							    attr, error);
11419 				if (!fm)
11420 					return rte_flow_error_set(error,
11421 						rte_errno,
11422 						RTE_FLOW_ERROR_TYPE_ACTION,
11423 						NULL,
11424 						"meter not found "
11425 						"or invalid parameters");
11426 				flow->meter = fm->idx;
11427 			}
11428 			/* Set the meter action. */
11429 			if (!fm) {
11430 				fm = mlx5_ipool_get(priv->sh->ipool
11431 						[MLX5_IPOOL_MTR], flow->meter);
11432 				if (!fm)
11433 					return rte_flow_error_set(error,
11434 						rte_errno,
11435 						RTE_FLOW_ERROR_TYPE_ACTION,
11436 						NULL,
11437 						"meter not found "
11438 						"or invalid parameters");
11439 			}
11440 			dev_flow->dv.actions[actions_n++] =
11441 				fm->mfts->meter_action;
11442 			action_flags |= MLX5_FLOW_ACTION_METER;
11443 			break;
11444 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
11445 			if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res,
11446 							      actions, error))
11447 				return -rte_errno;
11448 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
11449 			break;
11450 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
11451 			if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res,
11452 							      actions, error))
11453 				return -rte_errno;
11454 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
11455 			break;
11456 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
11457 			sample_act_pos = actions_n;
11458 			sample = (const struct rte_flow_action_sample *)
11459 				 action->conf;
11460 			actions_n++;
11461 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
11462 			/* put encap action into group if work with port id */
11463 			if ((action_flags & MLX5_FLOW_ACTION_ENCAP) &&
11464 			    (action_flags & MLX5_FLOW_ACTION_PORT_ID))
11465 				sample_act->action_flags |=
11466 							MLX5_FLOW_ACTION_ENCAP;
11467 			break;
11468 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
11469 			if (flow_dv_convert_action_modify_field
11470 					(dev, mhdr_res, actions, attr, error))
11471 				return -rte_errno;
11472 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
11473 			break;
11474 		case RTE_FLOW_ACTION_TYPE_END:
11475 			actions_end = true;
11476 			if (mhdr_res->actions_num) {
11477 				/* create modify action if needed. */
11478 				if (flow_dv_modify_hdr_resource_register
11479 					(dev, mhdr_res, dev_flow, error))
11480 					return -rte_errno;
11481 				dev_flow->dv.actions[modify_action_position] =
11482 					handle->dvh.modify_hdr->action;
11483 			}
11484 			if (action_flags & MLX5_FLOW_ACTION_COUNT) {
11485 				/*
11486 				 * Create one count action, to be used
11487 				 * by all sub-flows.
11488 				 */
11489 				if (!flow->counter) {
11490 					flow->counter =
11491 						flow_dv_translate_create_counter
11492 							(dev, dev_flow, count,
11493 							 age);
11494 					if (!flow->counter)
11495 						return rte_flow_error_set
11496 						(error, rte_errno,
11497 						 RTE_FLOW_ERROR_TYPE_ACTION,
11498 						 NULL, "cannot create counter"
11499 						 " object.");
11500 				}
11501 				dev_flow->dv.actions[actions_n] =
11502 					  (flow_dv_counter_get_by_idx(dev,
11503 					  flow->counter, NULL))->action;
11504 				actions_n++;
11505 			}
11506 		default:
11507 			break;
11508 		}
11509 		if (mhdr_res->actions_num &&
11510 		    modify_action_position == UINT32_MAX)
11511 			modify_action_position = actions_n++;
11512 	}
11513 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
11514 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
11515 		int item_type = items->type;
11516 
11517 		if (!mlx5_flow_os_item_supported(item_type))
11518 			return rte_flow_error_set(error, ENOTSUP,
11519 						  RTE_FLOW_ERROR_TYPE_ITEM,
11520 						  NULL, "item not supported");
11521 		switch (item_type) {
11522 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
11523 			flow_dv_translate_item_port_id
11524 				(dev, match_mask, match_value, items, attr);
11525 			last_item = MLX5_FLOW_ITEM_PORT_ID;
11526 			break;
11527 		case RTE_FLOW_ITEM_TYPE_ETH:
11528 			flow_dv_translate_item_eth(match_mask, match_value,
11529 						   items, tunnel,
11530 						   dev_flow->dv.group);
11531 			matcher.priority = action_flags &
11532 					MLX5_FLOW_ACTION_DEFAULT_MISS &&
11533 					!dev_flow->external ?
11534 					MLX5_PRIORITY_MAP_L3 :
11535 					MLX5_PRIORITY_MAP_L2;
11536 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
11537 					     MLX5_FLOW_LAYER_OUTER_L2;
11538 			break;
11539 		case RTE_FLOW_ITEM_TYPE_VLAN:
11540 			flow_dv_translate_item_vlan(dev_flow,
11541 						    match_mask, match_value,
11542 						    items, tunnel,
11543 						    dev_flow->dv.group);
11544 			matcher.priority = MLX5_PRIORITY_MAP_L2;
11545 			last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
11546 					      MLX5_FLOW_LAYER_INNER_VLAN) :
11547 					     (MLX5_FLOW_LAYER_OUTER_L2 |
11548 					      MLX5_FLOW_LAYER_OUTER_VLAN);
11549 			break;
11550 		case RTE_FLOW_ITEM_TYPE_IPV4:
11551 			mlx5_flow_tunnel_ip_check(items, next_protocol,
11552 						  &item_flags, &tunnel);
11553 			flow_dv_translate_item_ipv4(match_mask, match_value,
11554 						    items, tunnel,
11555 						    dev_flow->dv.group);
11556 			matcher.priority = MLX5_PRIORITY_MAP_L3;
11557 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
11558 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
11559 			if (items->mask != NULL &&
11560 			    ((const struct rte_flow_item_ipv4 *)
11561 			     items->mask)->hdr.next_proto_id) {
11562 				next_protocol =
11563 					((const struct rte_flow_item_ipv4 *)
11564 					 (items->spec))->hdr.next_proto_id;
11565 				next_protocol &=
11566 					((const struct rte_flow_item_ipv4 *)
11567 					 (items->mask))->hdr.next_proto_id;
11568 			} else {
11569 				/* Reset for inner layer. */
11570 				next_protocol = 0xff;
11571 			}
11572 			break;
11573 		case RTE_FLOW_ITEM_TYPE_IPV6:
11574 			mlx5_flow_tunnel_ip_check(items, next_protocol,
11575 						  &item_flags, &tunnel);
11576 			flow_dv_translate_item_ipv6(match_mask, match_value,
11577 						    items, tunnel,
11578 						    dev_flow->dv.group);
11579 			matcher.priority = MLX5_PRIORITY_MAP_L3;
11580 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
11581 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
11582 			if (items->mask != NULL &&
11583 			    ((const struct rte_flow_item_ipv6 *)
11584 			     items->mask)->hdr.proto) {
11585 				next_protocol =
11586 					((const struct rte_flow_item_ipv6 *)
11587 					 items->spec)->hdr.proto;
11588 				next_protocol &=
11589 					((const struct rte_flow_item_ipv6 *)
11590 					 items->mask)->hdr.proto;
11591 			} else {
11592 				/* Reset for inner layer. */
11593 				next_protocol = 0xff;
11594 			}
11595 			break;
11596 		case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
11597 			flow_dv_translate_item_ipv6_frag_ext(match_mask,
11598 							     match_value,
11599 							     items, tunnel);
11600 			last_item = tunnel ?
11601 					MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
11602 					MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
11603 			if (items->mask != NULL &&
11604 			    ((const struct rte_flow_item_ipv6_frag_ext *)
11605 			     items->mask)->hdr.next_header) {
11606 				next_protocol =
11607 				((const struct rte_flow_item_ipv6_frag_ext *)
11608 				 items->spec)->hdr.next_header;
11609 				next_protocol &=
11610 				((const struct rte_flow_item_ipv6_frag_ext *)
11611 				 items->mask)->hdr.next_header;
11612 			} else {
11613 				/* Reset for inner layer. */
11614 				next_protocol = 0xff;
11615 			}
11616 			break;
11617 		case RTE_FLOW_ITEM_TYPE_TCP:
11618 			flow_dv_translate_item_tcp(match_mask, match_value,
11619 						   items, tunnel);
11620 			matcher.priority = MLX5_PRIORITY_MAP_L4;
11621 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
11622 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
11623 			break;
11624 		case RTE_FLOW_ITEM_TYPE_UDP:
11625 			flow_dv_translate_item_udp(match_mask, match_value,
11626 						   items, tunnel);
11627 			matcher.priority = MLX5_PRIORITY_MAP_L4;
11628 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
11629 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
11630 			break;
11631 		case RTE_FLOW_ITEM_TYPE_GRE:
11632 			flow_dv_translate_item_gre(match_mask, match_value,
11633 						   items, tunnel);
11634 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
11635 			last_item = MLX5_FLOW_LAYER_GRE;
11636 			break;
11637 		case RTE_FLOW_ITEM_TYPE_GRE_KEY:
11638 			flow_dv_translate_item_gre_key(match_mask,
11639 						       match_value, items);
11640 			last_item = MLX5_FLOW_LAYER_GRE_KEY;
11641 			break;
11642 		case RTE_FLOW_ITEM_TYPE_NVGRE:
11643 			flow_dv_translate_item_nvgre(match_mask, match_value,
11644 						     items, tunnel);
11645 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
11646 			last_item = MLX5_FLOW_LAYER_GRE;
11647 			break;
11648 		case RTE_FLOW_ITEM_TYPE_VXLAN:
11649 			flow_dv_translate_item_vxlan(match_mask, match_value,
11650 						     items, tunnel);
11651 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
11652 			last_item = MLX5_FLOW_LAYER_VXLAN;
11653 			break;
11654 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
11655 			flow_dv_translate_item_vxlan_gpe(match_mask,
11656 							 match_value, items,
11657 							 tunnel);
11658 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
11659 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
11660 			break;
11661 		case RTE_FLOW_ITEM_TYPE_GENEVE:
11662 			flow_dv_translate_item_geneve(match_mask, match_value,
11663 						      items, tunnel);
11664 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
11665 			last_item = MLX5_FLOW_LAYER_GENEVE;
11666 			break;
11667 		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
11668 			ret = flow_dv_translate_item_geneve_opt(dev, match_mask,
11669 							  match_value,
11670 							  items, error);
11671 			if (ret)
11672 				return rte_flow_error_set(error, -ret,
11673 					RTE_FLOW_ERROR_TYPE_ITEM, NULL,
11674 					"cannot create GENEVE TLV option");
11675 			flow->geneve_tlv_option = 1;
11676 			last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
11677 			break;
11678 		case RTE_FLOW_ITEM_TYPE_MPLS:
11679 			flow_dv_translate_item_mpls(match_mask, match_value,
11680 						    items, last_item, tunnel);
11681 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
11682 			last_item = MLX5_FLOW_LAYER_MPLS;
11683 			break;
11684 		case RTE_FLOW_ITEM_TYPE_MARK:
11685 			flow_dv_translate_item_mark(dev, match_mask,
11686 						    match_value, items);
11687 			last_item = MLX5_FLOW_ITEM_MARK;
11688 			break;
11689 		case RTE_FLOW_ITEM_TYPE_META:
11690 			flow_dv_translate_item_meta(dev, match_mask,
11691 						    match_value, attr, items);
11692 			last_item = MLX5_FLOW_ITEM_METADATA;
11693 			break;
11694 		case RTE_FLOW_ITEM_TYPE_ICMP:
11695 			flow_dv_translate_item_icmp(match_mask, match_value,
11696 						    items, tunnel);
11697 			last_item = MLX5_FLOW_LAYER_ICMP;
11698 			break;
11699 		case RTE_FLOW_ITEM_TYPE_ICMP6:
11700 			flow_dv_translate_item_icmp6(match_mask, match_value,
11701 						      items, tunnel);
11702 			last_item = MLX5_FLOW_LAYER_ICMP6;
11703 			break;
11704 		case RTE_FLOW_ITEM_TYPE_TAG:
11705 			flow_dv_translate_item_tag(dev, match_mask,
11706 						   match_value, items);
11707 			last_item = MLX5_FLOW_ITEM_TAG;
11708 			break;
11709 		case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
11710 			flow_dv_translate_mlx5_item_tag(dev, match_mask,
11711 							match_value, items);
11712 			last_item = MLX5_FLOW_ITEM_TAG;
11713 			break;
11714 		case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
11715 			flow_dv_translate_item_tx_queue(dev, match_mask,
11716 							match_value,
11717 							items);
11718 			last_item = MLX5_FLOW_ITEM_TX_QUEUE;
11719 			break;
11720 		case RTE_FLOW_ITEM_TYPE_GTP:
11721 			flow_dv_translate_item_gtp(match_mask, match_value,
11722 						   items, tunnel);
11723 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
11724 			last_item = MLX5_FLOW_LAYER_GTP;
11725 			break;
11726 		case RTE_FLOW_ITEM_TYPE_GTP_PSC:
11727 			ret = flow_dv_translate_item_gtp_psc(match_mask,
11728 							  match_value,
11729 							  items);
11730 			if (ret)
11731 				return rte_flow_error_set(error, -ret,
11732 					RTE_FLOW_ERROR_TYPE_ITEM, NULL,
11733 					"cannot create GTP PSC item");
11734 			last_item = MLX5_FLOW_LAYER_GTP_PSC;
11735 			break;
11736 		case RTE_FLOW_ITEM_TYPE_ECPRI:
11737 			if (!mlx5_flex_parser_ecpri_exist(dev)) {
11738 				/* Create it only the first time to be used. */
11739 				ret = mlx5_flex_parser_ecpri_alloc(dev);
11740 				if (ret)
11741 					return rte_flow_error_set
11742 						(error, -ret,
11743 						RTE_FLOW_ERROR_TYPE_ITEM,
11744 						NULL,
11745 						"cannot create eCPRI parser");
11746 			}
11747 			/* Adjust the length matcher and device flow value. */
11748 			matcher.mask.size = MLX5_ST_SZ_BYTES(fte_match_param);
11749 			dev_flow->dv.value.size =
11750 					MLX5_ST_SZ_BYTES(fte_match_param);
11751 			flow_dv_translate_item_ecpri(dev, match_mask,
11752 						     match_value, items);
11753 			/* No other protocol should follow eCPRI layer. */
11754 			last_item = MLX5_FLOW_LAYER_ECPRI;
11755 			break;
11756 		default:
11757 			break;
11758 		}
11759 		item_flags |= last_item;
11760 	}
11761 	/*
11762 	 * When E-Switch mode is enabled, we have two cases where we need to
11763 	 * set the source port manually.
11764 	 * The first one, is in case of Nic steering rule, and the second is
11765 	 * E-Switch rule where no port_id item was found. In both cases
11766 	 * the source port is set according the current port in use.
11767 	 */
11768 	if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) &&
11769 	    (priv->representor || priv->master)) {
11770 		if (flow_dv_translate_item_port_id(dev, match_mask,
11771 						   match_value, NULL, attr))
11772 			return -rte_errno;
11773 	}
11774 #ifdef RTE_LIBRTE_MLX5_DEBUG
11775 	MLX5_ASSERT(!flow_dv_check_valid_spec(matcher.mask.buf,
11776 					      dev_flow->dv.value.buf));
11777 #endif
11778 	/*
11779 	 * Layers may be already initialized from prefix flow if this dev_flow
11780 	 * is the suffix flow.
11781 	 */
11782 	handle->layers |= item_flags;
11783 	if (action_flags & MLX5_FLOW_ACTION_RSS)
11784 		flow_dv_hashfields_set(dev_flow, rss_desc);
11785 	/* If has RSS action in the sample action, the Sample/Mirror resource
11786 	 * should be registered after the hash filed be update.
11787 	 */
11788 	if (action_flags & MLX5_FLOW_ACTION_SAMPLE) {
11789 		ret = flow_dv_translate_action_sample(dev,
11790 						      sample,
11791 						      dev_flow, attr,
11792 						      &num_of_dest,
11793 						      sample_actions,
11794 						      &sample_res,
11795 						      error);
11796 		if (ret < 0)
11797 			return ret;
11798 		ret = flow_dv_create_action_sample(dev,
11799 						   dev_flow,
11800 						   num_of_dest,
11801 						   &sample_res,
11802 						   &mdest_res,
11803 						   sample_actions,
11804 						   action_flags,
11805 						   error);
11806 		if (ret < 0)
11807 			return rte_flow_error_set
11808 						(error, rte_errno,
11809 						RTE_FLOW_ERROR_TYPE_ACTION,
11810 						NULL,
11811 						"cannot create sample action");
11812 		if (num_of_dest > 1) {
11813 			dev_flow->dv.actions[sample_act_pos] =
11814 			dev_flow->dv.dest_array_res->action;
11815 		} else {
11816 			dev_flow->dv.actions[sample_act_pos] =
11817 			dev_flow->dv.sample_res->verbs_action;
11818 		}
11819 	}
11820 	/*
11821 	 * For multiple destination (sample action with ratio=1), the encap
11822 	 * action and port id action will be combined into group action.
11823 	 * So need remove the original these actions in the flow and only
11824 	 * use the sample action instead of.
11825 	 */
11826 	if (num_of_dest > 1 &&
11827 	    (sample_act->dr_port_id_action || sample_act->dr_jump_action)) {
11828 		int i;
11829 		void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
11830 
11831 		for (i = 0; i < actions_n; i++) {
11832 			if ((sample_act->dr_encap_action &&
11833 				sample_act->dr_encap_action ==
11834 				dev_flow->dv.actions[i]) ||
11835 				(sample_act->dr_port_id_action &&
11836 				sample_act->dr_port_id_action ==
11837 				dev_flow->dv.actions[i]) ||
11838 				(sample_act->dr_jump_action &&
11839 				sample_act->dr_jump_action ==
11840 				dev_flow->dv.actions[i]))
11841 				continue;
11842 			temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];
11843 		}
11844 		memcpy((void *)dev_flow->dv.actions,
11845 				(void *)temp_actions,
11846 				tmp_actions_n * sizeof(void *));
11847 		actions_n = tmp_actions_n;
11848 	}
11849 	dev_flow->dv.actions_n = actions_n;
11850 	dev_flow->act_flags = action_flags;
11851 	/* Register matcher. */
11852 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
11853 				    matcher.mask.size);
11854 	matcher.priority = mlx5_get_matcher_priority(dev, attr,
11855 					matcher.priority);
11856 	/* reserved field no needs to be set to 0 here. */
11857 	tbl_key.domain = attr->transfer;
11858 	tbl_key.direction = attr->egress;
11859 	tbl_key.table_id = dev_flow->dv.group;
11860 	if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow,
11861 				     tunnel, attr->group, error))
11862 		return -rte_errno;
11863 	return 0;
11864 }
11865 
11866 /**
11867  * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields)
11868  * and tunnel.
11869  *
11870  * @param[in, out] action
11871  *   Shred RSS action holding hash RX queue objects.
11872  * @param[in] hash_fields
11873  *   Defines combination of packet fields to participate in RX hash.
11874  * @param[in] tunnel
11875  *   Tunnel type
11876  * @param[in] hrxq_idx
11877  *   Hash RX queue index to set.
11878  *
11879  * @return
11880  *   0 on success, otherwise negative errno value.
11881  */
11882 static int
11883 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action,
11884 			      const uint64_t hash_fields,
11885 			      const int tunnel,
11886 			      uint32_t hrxq_idx)
11887 {
11888 	uint32_t *hrxqs = tunnel ? action->hrxq : action->hrxq_tunnel;
11889 
11890 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
11891 	case MLX5_RSS_HASH_IPV4:
11892 		hrxqs[0] = hrxq_idx;
11893 		return 0;
11894 	case MLX5_RSS_HASH_IPV4_TCP:
11895 		hrxqs[1] = hrxq_idx;
11896 		return 0;
11897 	case MLX5_RSS_HASH_IPV4_UDP:
11898 		hrxqs[2] = hrxq_idx;
11899 		return 0;
11900 	case MLX5_RSS_HASH_IPV6:
11901 		hrxqs[3] = hrxq_idx;
11902 		return 0;
11903 	case MLX5_RSS_HASH_IPV6_TCP:
11904 		hrxqs[4] = hrxq_idx;
11905 		return 0;
11906 	case MLX5_RSS_HASH_IPV6_UDP:
11907 		hrxqs[5] = hrxq_idx;
11908 		return 0;
11909 	case MLX5_RSS_HASH_NONE:
11910 		hrxqs[6] = hrxq_idx;
11911 		return 0;
11912 	default:
11913 		return -1;
11914 	}
11915 }
11916 
11917 /**
11918  * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields)
11919  * and tunnel.
11920  *
11921  * @param[in] dev
11922  *   Pointer to the Ethernet device structure.
11923  * @param[in] idx
11924  *   Shared RSS action ID holding hash RX queue objects.
11925  * @param[in] hash_fields
11926  *   Defines combination of packet fields to participate in RX hash.
11927  * @param[in] tunnel
11928  *   Tunnel type
11929  *
11930  * @return
11931  *   Valid hash RX queue index, otherwise 0.
11932  */
11933 static uint32_t
11934 __flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx,
11935 				 const uint64_t hash_fields,
11936 				 const int tunnel)
11937 {
11938 	struct mlx5_priv *priv = dev->data->dev_private;
11939 	struct mlx5_shared_action_rss *shared_rss =
11940 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
11941 	const uint32_t *hrxqs = tunnel ? shared_rss->hrxq :
11942 							shared_rss->hrxq_tunnel;
11943 
11944 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
11945 	case MLX5_RSS_HASH_IPV4:
11946 		return hrxqs[0];
11947 	case MLX5_RSS_HASH_IPV4_TCP:
11948 		return hrxqs[1];
11949 	case MLX5_RSS_HASH_IPV4_UDP:
11950 		return hrxqs[2];
11951 	case MLX5_RSS_HASH_IPV6:
11952 		return hrxqs[3];
11953 	case MLX5_RSS_HASH_IPV6_TCP:
11954 		return hrxqs[4];
11955 	case MLX5_RSS_HASH_IPV6_UDP:
11956 		return hrxqs[5];
11957 	case MLX5_RSS_HASH_NONE:
11958 		return hrxqs[6];
11959 	default:
11960 		return 0;
11961 	}
11962 }
11963 
11964 /**
11965  * Apply the flow to the NIC, lock free,
11966  * (mutex should be acquired by caller).
11967  *
11968  * @param[in] dev
11969  *   Pointer to the Ethernet device structure.
11970  * @param[in, out] flow
11971  *   Pointer to flow structure.
11972  * @param[out] error
11973  *   Pointer to error structure.
11974  *
11975  * @return
11976  *   0 on success, a negative errno value otherwise and rte_errno is set.
11977  */
11978 static int
11979 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
11980 	      struct rte_flow_error *error)
11981 {
11982 	struct mlx5_flow_dv_workspace *dv;
11983 	struct mlx5_flow_handle *dh;
11984 	struct mlx5_flow_handle_dv *dv_h;
11985 	struct mlx5_flow *dev_flow;
11986 	struct mlx5_priv *priv = dev->data->dev_private;
11987 	uint32_t handle_idx;
11988 	int n;
11989 	int err;
11990 	int idx;
11991 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
11992 	struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc;
11993 
11994 	MLX5_ASSERT(wks);
11995 	for (idx = wks->flow_idx - 1; idx >= 0; idx--) {
11996 		dev_flow = &wks->flows[idx];
11997 		dv = &dev_flow->dv;
11998 		dh = dev_flow->handle;
11999 		dv_h = &dh->dvh;
12000 		n = dv->actions_n;
12001 		if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
12002 			if (dv->transfer) {
12003 				dv->actions[n++] = priv->sh->esw_drop_action;
12004 			} else {
12005 				MLX5_ASSERT(priv->drop_queue.hrxq);
12006 				dv->actions[n++] =
12007 						priv->drop_queue.hrxq->action;
12008 			}
12009 		} else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE &&
12010 			   !dv_h->rix_sample && !dv_h->rix_dest_array)) {
12011 			struct mlx5_hrxq *hrxq;
12012 			uint32_t hrxq_idx;
12013 
12014 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc,
12015 						    &hrxq_idx);
12016 			if (!hrxq) {
12017 				rte_flow_error_set
12018 					(error, rte_errno,
12019 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12020 					 "cannot get hash queue");
12021 				goto error;
12022 			}
12023 			dh->rix_hrxq = hrxq_idx;
12024 			dv->actions[n++] = hrxq->action;
12025 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
12026 			struct mlx5_hrxq *hrxq = NULL;
12027 			uint32_t hrxq_idx;
12028 
12029 			hrxq_idx = __flow_dv_action_rss_hrxq_lookup(dev,
12030 						rss_desc->shared_rss,
12031 						dev_flow->hash_fields,
12032 						!!(dh->layers &
12033 						MLX5_FLOW_LAYER_TUNNEL));
12034 			if (hrxq_idx)
12035 				hrxq = mlx5_ipool_get
12036 					(priv->sh->ipool[MLX5_IPOOL_HRXQ],
12037 					 hrxq_idx);
12038 			if (!hrxq) {
12039 				rte_flow_error_set
12040 					(error, rte_errno,
12041 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12042 					 "cannot get hash queue");
12043 				goto error;
12044 			}
12045 			dh->rix_srss = rss_desc->shared_rss;
12046 			dv->actions[n++] = hrxq->action;
12047 		} else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) {
12048 			if (!priv->sh->default_miss_action) {
12049 				rte_flow_error_set
12050 					(error, rte_errno,
12051 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12052 					 "default miss action not be created.");
12053 				goto error;
12054 			}
12055 			dv->actions[n++] = priv->sh->default_miss_action;
12056 		}
12057 		err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object,
12058 					       (void *)&dv->value, n,
12059 					       dv->actions, &dh->drv_flow);
12060 		if (err) {
12061 			rte_flow_error_set(error, errno,
12062 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12063 					   NULL,
12064 					   "hardware refuses to create flow");
12065 			goto error;
12066 		}
12067 		if (priv->vmwa_context &&
12068 		    dh->vf_vlan.tag && !dh->vf_vlan.created) {
12069 			/*
12070 			 * The rule contains the VLAN pattern.
12071 			 * For VF we are going to create VLAN
12072 			 * interface to make hypervisor set correct
12073 			 * e-Switch vport context.
12074 			 */
12075 			mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan);
12076 		}
12077 	}
12078 	return 0;
12079 error:
12080 	err = rte_errno; /* Save rte_errno before cleanup. */
12081 	SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
12082 		       handle_idx, dh, next) {
12083 		/* hrxq is union, don't clear it if the flag is not set. */
12084 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) {
12085 			mlx5_hrxq_release(dev, dh->rix_hrxq);
12086 			dh->rix_hrxq = 0;
12087 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
12088 			dh->rix_srss = 0;
12089 		}
12090 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
12091 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
12092 	}
12093 	rte_errno = err; /* Restore rte_errno. */
12094 	return -rte_errno;
12095 }
12096 
12097 void
12098 flow_dv_matcher_remove_cb(struct mlx5_cache_list *list __rte_unused,
12099 			  struct mlx5_cache_entry *entry)
12100 {
12101 	struct mlx5_flow_dv_matcher *cache = container_of(entry, typeof(*cache),
12102 							  entry);
12103 
12104 	claim_zero(mlx5_flow_os_destroy_flow_matcher(cache->matcher_object));
12105 	mlx5_free(cache);
12106 }
12107 
12108 /**
12109  * Release the flow matcher.
12110  *
12111  * @param dev
12112  *   Pointer to Ethernet device.
12113  * @param port_id
12114  *   Index to port ID action resource.
12115  *
12116  * @return
12117  *   1 while a reference on it exists, 0 when freed.
12118  */
12119 static int
12120 flow_dv_matcher_release(struct rte_eth_dev *dev,
12121 			struct mlx5_flow_handle *handle)
12122 {
12123 	struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher;
12124 	struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl,
12125 							    typeof(*tbl), tbl);
12126 	int ret;
12127 
12128 	MLX5_ASSERT(matcher->matcher_object);
12129 	ret = mlx5_cache_unregister(&tbl->matchers, &matcher->entry);
12130 	flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl);
12131 	return ret;
12132 }
12133 
12134 /**
12135  * Release encap_decap resource.
12136  *
12137  * @param list
12138  *   Pointer to the hash list.
12139  * @param entry
12140  *   Pointer to exist resource entry object.
12141  */
12142 void
12143 flow_dv_encap_decap_remove_cb(struct mlx5_hlist *list,
12144 			      struct mlx5_hlist_entry *entry)
12145 {
12146 	struct mlx5_dev_ctx_shared *sh = list->ctx;
12147 	struct mlx5_flow_dv_encap_decap_resource *res =
12148 		container_of(entry, typeof(*res), entry);
12149 
12150 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
12151 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
12152 }
12153 
12154 /**
12155  * Release an encap/decap resource.
12156  *
12157  * @param dev
12158  *   Pointer to Ethernet device.
12159  * @param encap_decap_idx
12160  *   Index of encap decap resource.
12161  *
12162  * @return
12163  *   1 while a reference on it exists, 0 when freed.
12164  */
12165 static int
12166 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
12167 				     uint32_t encap_decap_idx)
12168 {
12169 	struct mlx5_priv *priv = dev->data->dev_private;
12170 	struct mlx5_flow_dv_encap_decap_resource *cache_resource;
12171 
12172 	cache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
12173 					encap_decap_idx);
12174 	if (!cache_resource)
12175 		return 0;
12176 	MLX5_ASSERT(cache_resource->action);
12177 	return mlx5_hlist_unregister(priv->sh->encaps_decaps,
12178 				     &cache_resource->entry);
12179 }
12180 
12181 /**
12182  * Release an jump to table action resource.
12183  *
12184  * @param dev
12185  *   Pointer to Ethernet device.
12186  * @param rix_jump
12187  *   Index to the jump action resource.
12188  *
12189  * @return
12190  *   1 while a reference on it exists, 0 when freed.
12191  */
12192 static int
12193 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
12194 				  uint32_t rix_jump)
12195 {
12196 	struct mlx5_priv *priv = dev->data->dev_private;
12197 	struct mlx5_flow_tbl_data_entry *tbl_data;
12198 
12199 	tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP],
12200 				  rix_jump);
12201 	if (!tbl_data)
12202 		return 0;
12203 	return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl);
12204 }
12205 
12206 void
12207 flow_dv_modify_remove_cb(struct mlx5_hlist *list __rte_unused,
12208 			 struct mlx5_hlist_entry *entry)
12209 {
12210 	struct mlx5_flow_dv_modify_hdr_resource *res =
12211 		container_of(entry, typeof(*res), entry);
12212 
12213 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
12214 	mlx5_free(entry);
12215 }
12216 
12217 /**
12218  * Release a modify-header resource.
12219  *
12220  * @param dev
12221  *   Pointer to Ethernet device.
12222  * @param handle
12223  *   Pointer to mlx5_flow_handle.
12224  *
12225  * @return
12226  *   1 while a reference on it exists, 0 when freed.
12227  */
12228 static int
12229 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev,
12230 				    struct mlx5_flow_handle *handle)
12231 {
12232 	struct mlx5_priv *priv = dev->data->dev_private;
12233 	struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr;
12234 
12235 	MLX5_ASSERT(entry->action);
12236 	return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry);
12237 }
12238 
12239 void
12240 flow_dv_port_id_remove_cb(struct mlx5_cache_list *list,
12241 			  struct mlx5_cache_entry *entry)
12242 {
12243 	struct mlx5_dev_ctx_shared *sh = list->ctx;
12244 	struct mlx5_flow_dv_port_id_action_resource *cache =
12245 			container_of(entry, typeof(*cache), entry);
12246 
12247 	claim_zero(mlx5_flow_os_destroy_flow_action(cache->action));
12248 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], cache->idx);
12249 }
12250 
12251 /**
12252  * Release port ID action resource.
12253  *
12254  * @param dev
12255  *   Pointer to Ethernet device.
12256  * @param handle
12257  *   Pointer to mlx5_flow_handle.
12258  *
12259  * @return
12260  *   1 while a reference on it exists, 0 when freed.
12261  */
12262 static int
12263 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
12264 					uint32_t port_id)
12265 {
12266 	struct mlx5_priv *priv = dev->data->dev_private;
12267 	struct mlx5_flow_dv_port_id_action_resource *cache;
12268 
12269 	cache = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id);
12270 	if (!cache)
12271 		return 0;
12272 	MLX5_ASSERT(cache->action);
12273 	return mlx5_cache_unregister(&priv->sh->port_id_action_list,
12274 				     &cache->entry);
12275 }
12276 
12277 /**
12278  * Release shared RSS action resource.
12279  *
12280  * @param dev
12281  *   Pointer to Ethernet device.
12282  * @param srss
12283  *   Shared RSS action index.
12284  */
12285 static void
12286 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss)
12287 {
12288 	struct mlx5_priv *priv = dev->data->dev_private;
12289 	struct mlx5_shared_action_rss *shared_rss;
12290 
12291 	shared_rss = mlx5_ipool_get
12292 			(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss);
12293 	__atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
12294 }
12295 
12296 void
12297 flow_dv_push_vlan_remove_cb(struct mlx5_cache_list *list,
12298 			    struct mlx5_cache_entry *entry)
12299 {
12300 	struct mlx5_dev_ctx_shared *sh = list->ctx;
12301 	struct mlx5_flow_dv_push_vlan_action_resource *cache =
12302 			container_of(entry, typeof(*cache), entry);
12303 
12304 	claim_zero(mlx5_flow_os_destroy_flow_action(cache->action));
12305 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], cache->idx);
12306 }
12307 
12308 /**
12309  * Release push vlan action resource.
12310  *
12311  * @param dev
12312  *   Pointer to Ethernet device.
12313  * @param handle
12314  *   Pointer to mlx5_flow_handle.
12315  *
12316  * @return
12317  *   1 while a reference on it exists, 0 when freed.
12318  */
12319 static int
12320 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev,
12321 					  struct mlx5_flow_handle *handle)
12322 {
12323 	struct mlx5_priv *priv = dev->data->dev_private;
12324 	struct mlx5_flow_dv_push_vlan_action_resource *cache;
12325 	uint32_t idx = handle->dvh.rix_push_vlan;
12326 
12327 	cache = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
12328 	if (!cache)
12329 		return 0;
12330 	MLX5_ASSERT(cache->action);
12331 	return mlx5_cache_unregister(&priv->sh->push_vlan_action_list,
12332 				     &cache->entry);
12333 }
12334 
12335 /**
12336  * Release the fate resource.
12337  *
12338  * @param dev
12339  *   Pointer to Ethernet device.
12340  * @param handle
12341  *   Pointer to mlx5_flow_handle.
12342  */
12343 static void
12344 flow_dv_fate_resource_release(struct rte_eth_dev *dev,
12345 			       struct mlx5_flow_handle *handle)
12346 {
12347 	if (!handle->rix_fate)
12348 		return;
12349 	switch (handle->fate_action) {
12350 	case MLX5_FLOW_FATE_QUEUE:
12351 		mlx5_hrxq_release(dev, handle->rix_hrxq);
12352 		break;
12353 	case MLX5_FLOW_FATE_JUMP:
12354 		flow_dv_jump_tbl_resource_release(dev, handle->rix_jump);
12355 		break;
12356 	case MLX5_FLOW_FATE_PORT_ID:
12357 		flow_dv_port_id_action_resource_release(dev,
12358 				handle->rix_port_id_action);
12359 		break;
12360 	default:
12361 		DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action);
12362 		break;
12363 	}
12364 	handle->rix_fate = 0;
12365 }
12366 
12367 void
12368 flow_dv_sample_remove_cb(struct mlx5_cache_list *list __rte_unused,
12369 			 struct mlx5_cache_entry *entry)
12370 {
12371 	struct mlx5_flow_dv_sample_resource *cache_resource =
12372 			container_of(entry, typeof(*cache_resource), entry);
12373 	struct rte_eth_dev *dev = cache_resource->dev;
12374 	struct mlx5_priv *priv = dev->data->dev_private;
12375 
12376 	if (cache_resource->verbs_action)
12377 		claim_zero(mlx5_flow_os_destroy_flow_action
12378 				(cache_resource->verbs_action));
12379 	if (cache_resource->normal_path_tbl)
12380 		flow_dv_tbl_resource_release(MLX5_SH(dev),
12381 			cache_resource->normal_path_tbl);
12382 	flow_dv_sample_sub_actions_release(dev,
12383 				&cache_resource->sample_idx);
12384 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE],
12385 			cache_resource->idx);
12386 	DRV_LOG(DEBUG, "sample resource %p: removed",
12387 		(void *)cache_resource);
12388 }
12389 
12390 /**
12391  * Release an sample resource.
12392  *
12393  * @param dev
12394  *   Pointer to Ethernet device.
12395  * @param handle
12396  *   Pointer to mlx5_flow_handle.
12397  *
12398  * @return
12399  *   1 while a reference on it exists, 0 when freed.
12400  */
12401 static int
12402 flow_dv_sample_resource_release(struct rte_eth_dev *dev,
12403 				     struct mlx5_flow_handle *handle)
12404 {
12405 	struct mlx5_priv *priv = dev->data->dev_private;
12406 	struct mlx5_flow_dv_sample_resource *cache_resource;
12407 
12408 	cache_resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE],
12409 			 handle->dvh.rix_sample);
12410 	if (!cache_resource)
12411 		return 0;
12412 	MLX5_ASSERT(cache_resource->verbs_action);
12413 	return mlx5_cache_unregister(&priv->sh->sample_action_list,
12414 				     &cache_resource->entry);
12415 }
12416 
12417 void
12418 flow_dv_dest_array_remove_cb(struct mlx5_cache_list *list __rte_unused,
12419 			     struct mlx5_cache_entry *entry)
12420 {
12421 	struct mlx5_flow_dv_dest_array_resource *cache_resource =
12422 			container_of(entry, typeof(*cache_resource), entry);
12423 	struct rte_eth_dev *dev = cache_resource->dev;
12424 	struct mlx5_priv *priv = dev->data->dev_private;
12425 	uint32_t i = 0;
12426 
12427 	MLX5_ASSERT(cache_resource->action);
12428 	if (cache_resource->action)
12429 		claim_zero(mlx5_flow_os_destroy_flow_action
12430 					(cache_resource->action));
12431 	for (; i < cache_resource->num_of_dest; i++)
12432 		flow_dv_sample_sub_actions_release(dev,
12433 				&cache_resource->sample_idx[i]);
12434 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY],
12435 			cache_resource->idx);
12436 	DRV_LOG(DEBUG, "destination array resource %p: removed",
12437 		(void *)cache_resource);
12438 }
12439 
12440 /**
12441  * Release an destination array resource.
12442  *
12443  * @param dev
12444  *   Pointer to Ethernet device.
12445  * @param handle
12446  *   Pointer to mlx5_flow_handle.
12447  *
12448  * @return
12449  *   1 while a reference on it exists, 0 when freed.
12450  */
12451 static int
12452 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev,
12453 				    struct mlx5_flow_handle *handle)
12454 {
12455 	struct mlx5_priv *priv = dev->data->dev_private;
12456 	struct mlx5_flow_dv_dest_array_resource *cache;
12457 
12458 	cache = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY],
12459 			       handle->dvh.rix_dest_array);
12460 	if (!cache)
12461 		return 0;
12462 	MLX5_ASSERT(cache->action);
12463 	return mlx5_cache_unregister(&priv->sh->dest_array_list,
12464 				     &cache->entry);
12465 }
12466 
12467 static void
12468 flow_dv_geneve_tlv_option_resource_release(struct rte_eth_dev *dev)
12469 {
12470 	struct mlx5_priv *priv = dev->data->dev_private;
12471 	struct mlx5_dev_ctx_shared *sh = priv->sh;
12472 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
12473 				sh->geneve_tlv_option_resource;
12474 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
12475 	if (geneve_opt_resource) {
12476 		if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1,
12477 					 __ATOMIC_RELAXED))) {
12478 			claim_zero(mlx5_devx_cmd_destroy
12479 					(geneve_opt_resource->obj));
12480 			mlx5_free(sh->geneve_tlv_option_resource);
12481 			sh->geneve_tlv_option_resource = NULL;
12482 		}
12483 	}
12484 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
12485 }
12486 
12487 /**
12488  * Remove the flow from the NIC but keeps it in memory.
12489  * Lock free, (mutex should be acquired by caller).
12490  *
12491  * @param[in] dev
12492  *   Pointer to Ethernet device.
12493  * @param[in, out] flow
12494  *   Pointer to flow structure.
12495  */
12496 static void
12497 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
12498 {
12499 	struct mlx5_flow_handle *dh;
12500 	uint32_t handle_idx;
12501 	struct mlx5_priv *priv = dev->data->dev_private;
12502 
12503 	if (!flow)
12504 		return;
12505 	handle_idx = flow->dev_handles;
12506 	while (handle_idx) {
12507 		dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
12508 				    handle_idx);
12509 		if (!dh)
12510 			return;
12511 		if (dh->drv_flow) {
12512 			claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow));
12513 			dh->drv_flow = NULL;
12514 		}
12515 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE)
12516 			flow_dv_fate_resource_release(dev, dh);
12517 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
12518 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
12519 		handle_idx = dh->next.next;
12520 	}
12521 }
12522 
12523 /**
12524  * Remove the flow from the NIC and the memory.
12525  * Lock free, (mutex should be acquired by caller).
12526  *
12527  * @param[in] dev
12528  *   Pointer to the Ethernet device structure.
12529  * @param[in, out] flow
12530  *   Pointer to flow structure.
12531  */
12532 static void
12533 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
12534 {
12535 	struct mlx5_flow_handle *dev_handle;
12536 	struct mlx5_priv *priv = dev->data->dev_private;
12537 	uint32_t srss = 0;
12538 
12539 	if (!flow)
12540 		return;
12541 	flow_dv_remove(dev, flow);
12542 	if (flow->counter) {
12543 		flow_dv_counter_free(dev, flow->counter);
12544 		flow->counter = 0;
12545 	}
12546 	if (flow->meter) {
12547 		struct mlx5_flow_meter *fm;
12548 
12549 		fm = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR],
12550 				    flow->meter);
12551 		if (fm)
12552 			mlx5_flow_meter_detach(fm);
12553 		flow->meter = 0;
12554 	}
12555 	if (flow->age)
12556 		flow_dv_aso_age_release(dev, flow->age);
12557 	if (flow->geneve_tlv_option) {
12558 		flow_dv_geneve_tlv_option_resource_release(dev);
12559 		flow->geneve_tlv_option = 0;
12560 	}
12561 	while (flow->dev_handles) {
12562 		uint32_t tmp_idx = flow->dev_handles;
12563 
12564 		dev_handle = mlx5_ipool_get(priv->sh->ipool
12565 					    [MLX5_IPOOL_MLX5_FLOW], tmp_idx);
12566 		if (!dev_handle)
12567 			return;
12568 		flow->dev_handles = dev_handle->next.next;
12569 		if (dev_handle->dvh.matcher)
12570 			flow_dv_matcher_release(dev, dev_handle);
12571 		if (dev_handle->dvh.rix_sample)
12572 			flow_dv_sample_resource_release(dev, dev_handle);
12573 		if (dev_handle->dvh.rix_dest_array)
12574 			flow_dv_dest_array_resource_release(dev, dev_handle);
12575 		if (dev_handle->dvh.rix_encap_decap)
12576 			flow_dv_encap_decap_resource_release(dev,
12577 				dev_handle->dvh.rix_encap_decap);
12578 		if (dev_handle->dvh.modify_hdr)
12579 			flow_dv_modify_hdr_resource_release(dev, dev_handle);
12580 		if (dev_handle->dvh.rix_push_vlan)
12581 			flow_dv_push_vlan_action_resource_release(dev,
12582 								  dev_handle);
12583 		if (dev_handle->dvh.rix_tag)
12584 			flow_dv_tag_release(dev,
12585 					    dev_handle->dvh.rix_tag);
12586 		if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS)
12587 			flow_dv_fate_resource_release(dev, dev_handle);
12588 		else if (!srss)
12589 			srss = dev_handle->rix_srss;
12590 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
12591 			   tmp_idx);
12592 	}
12593 	if (srss)
12594 		flow_dv_shared_rss_action_release(dev, srss);
12595 }
12596 
12597 /**
12598  * Release array of hash RX queue objects.
12599  * Helper function.
12600  *
12601  * @param[in] dev
12602  *   Pointer to the Ethernet device structure.
12603  * @param[in, out] hrxqs
12604  *   Array of hash RX queue objects.
12605  *
12606  * @return
12607  *   Total number of references to hash RX queue objects in *hrxqs* array
12608  *   after this operation.
12609  */
12610 static int
12611 __flow_dv_hrxqs_release(struct rte_eth_dev *dev,
12612 			uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN])
12613 {
12614 	size_t i;
12615 	int remaining = 0;
12616 
12617 	for (i = 0; i < RTE_DIM(*hrxqs); i++) {
12618 		int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]);
12619 
12620 		if (!ret)
12621 			(*hrxqs)[i] = 0;
12622 		remaining += ret;
12623 	}
12624 	return remaining;
12625 }
12626 
12627 /**
12628  * Release all hash RX queue objects representing shared RSS action.
12629  *
12630  * @param[in] dev
12631  *   Pointer to the Ethernet device structure.
12632  * @param[in, out] action
12633  *   Shared RSS action to remove hash RX queue objects from.
12634  *
12635  * @return
12636  *   Total number of references to hash RX queue objects stored in *action*
12637  *   after this operation.
12638  *   Expected to be 0 if no external references held.
12639  */
12640 static int
12641 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev,
12642 				 struct mlx5_shared_action_rss *shared_rss)
12643 {
12644 	return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq) +
12645 		__flow_dv_hrxqs_release(dev, &shared_rss->hrxq_tunnel);
12646 }
12647 
12648 /**
12649  * Setup shared RSS action.
12650  * Prepare set of hash RX queue objects sufficient to handle all valid
12651  * hash_fields combinations (see enum ibv_rx_hash_fields).
12652  *
12653  * @param[in] dev
12654  *   Pointer to the Ethernet device structure.
12655  * @param[in] action_idx
12656  *   Shared RSS action ipool index.
12657  * @param[in, out] action
12658  *   Partially initialized shared RSS action.
12659  * @param[out] error
12660  *   Perform verbose error reporting if not NULL. Initialized in case of
12661  *   error only.
12662  *
12663  * @return
12664  *   0 on success, otherwise negative errno value.
12665  */
12666 static int
12667 __flow_dv_action_rss_setup(struct rte_eth_dev *dev,
12668 			   uint32_t action_idx,
12669 			   struct mlx5_shared_action_rss *shared_rss,
12670 			   struct rte_flow_error *error)
12671 {
12672 	struct mlx5_flow_rss_desc rss_desc = { 0 };
12673 	size_t i;
12674 	int err;
12675 
12676 	if (mlx5_ind_table_obj_setup(dev, shared_rss->ind_tbl)) {
12677 		return rte_flow_error_set(error, rte_errno,
12678 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12679 					  "cannot setup indirection table");
12680 	}
12681 	memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN);
12682 	rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN;
12683 	rss_desc.const_q = shared_rss->origin.queue;
12684 	rss_desc.queue_num = shared_rss->origin.queue_num;
12685 	/* Set non-zero value to indicate a shared RSS. */
12686 	rss_desc.shared_rss = action_idx;
12687 	rss_desc.ind_tbl = shared_rss->ind_tbl;
12688 	for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) {
12689 		uint32_t hrxq_idx;
12690 		uint64_t hash_fields = mlx5_rss_hash_fields[i];
12691 		int tunnel;
12692 
12693 		for (tunnel = 0; tunnel < 2; tunnel++) {
12694 			rss_desc.tunnel = tunnel;
12695 			rss_desc.hash_fields = hash_fields;
12696 			hrxq_idx = mlx5_hrxq_get(dev, &rss_desc);
12697 			if (!hrxq_idx) {
12698 				rte_flow_error_set
12699 					(error, rte_errno,
12700 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12701 					 "cannot get hash queue");
12702 				goto error_hrxq_new;
12703 			}
12704 			err = __flow_dv_action_rss_hrxq_set
12705 				(shared_rss, hash_fields, tunnel, hrxq_idx);
12706 			MLX5_ASSERT(!err);
12707 		}
12708 	}
12709 	return 0;
12710 error_hrxq_new:
12711 	err = rte_errno;
12712 	__flow_dv_action_rss_hrxqs_release(dev, shared_rss);
12713 	if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true))
12714 		shared_rss->ind_tbl = NULL;
12715 	rte_errno = err;
12716 	return -rte_errno;
12717 }
12718 
12719 /**
12720  * Create shared RSS action.
12721  *
12722  * @param[in] dev
12723  *   Pointer to the Ethernet device structure.
12724  * @param[in] conf
12725  *   Shared action configuration.
12726  * @param[in] rss
12727  *   RSS action specification used to create shared action.
12728  * @param[out] error
12729  *   Perform verbose error reporting if not NULL. Initialized in case of
12730  *   error only.
12731  *
12732  * @return
12733  *   A valid shared action ID in case of success, 0 otherwise and
12734  *   rte_errno is set.
12735  */
12736 static uint32_t
12737 __flow_dv_action_rss_create(struct rte_eth_dev *dev,
12738 			    const struct rte_flow_shared_action_conf *conf,
12739 			    const struct rte_flow_action_rss *rss,
12740 			    struct rte_flow_error *error)
12741 {
12742 	struct mlx5_priv *priv = dev->data->dev_private;
12743 	struct mlx5_shared_action_rss *shared_rss = NULL;
12744 	void *queue = NULL;
12745 	struct rte_flow_action_rss *origin;
12746 	const uint8_t *rss_key;
12747 	uint32_t queue_size = rss->queue_num * sizeof(uint16_t);
12748 	uint32_t idx;
12749 
12750 	RTE_SET_USED(conf);
12751 	queue = mlx5_malloc(0, RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
12752 			    0, SOCKET_ID_ANY);
12753 	shared_rss = mlx5_ipool_zmalloc
12754 			 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx);
12755 	if (!shared_rss || !queue) {
12756 		rte_flow_error_set(error, ENOMEM,
12757 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12758 				   "cannot allocate resource memory");
12759 		goto error_rss_init;
12760 	}
12761 	if (idx > (1u << MLX5_SHARED_ACTION_TYPE_OFFSET)) {
12762 		rte_flow_error_set(error, E2BIG,
12763 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12764 				   "rss action number out of range");
12765 		goto error_rss_init;
12766 	}
12767 	shared_rss->ind_tbl = mlx5_malloc(MLX5_MEM_ZERO,
12768 					  sizeof(*shared_rss->ind_tbl),
12769 					  0, SOCKET_ID_ANY);
12770 	if (!shared_rss->ind_tbl) {
12771 		rte_flow_error_set(error, ENOMEM,
12772 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12773 				   "cannot allocate resource memory");
12774 		goto error_rss_init;
12775 	}
12776 	memcpy(queue, rss->queue, queue_size);
12777 	shared_rss->ind_tbl->queues = queue;
12778 	shared_rss->ind_tbl->queues_n = rss->queue_num;
12779 	origin = &shared_rss->origin;
12780 	origin->func = rss->func;
12781 	origin->level = rss->level;
12782 	/* RSS type 0 indicates default RSS type (ETH_RSS_IP). */
12783 	origin->types = !rss->types ? ETH_RSS_IP : rss->types;
12784 	/* NULL RSS key indicates default RSS key. */
12785 	rss_key = !rss->key ? rss_hash_default_key : rss->key;
12786 	memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
12787 	origin->key = &shared_rss->key[0];
12788 	origin->key_len = MLX5_RSS_HASH_KEY_LEN;
12789 	origin->queue = queue;
12790 	origin->queue_num = rss->queue_num;
12791 	if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error))
12792 		goto error_rss_init;
12793 	rte_spinlock_init(&shared_rss->action_rss_sl);
12794 	__atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
12795 	rte_spinlock_lock(&priv->shared_act_sl);
12796 	ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
12797 		     &priv->rss_shared_actions, idx, shared_rss, next);
12798 	rte_spinlock_unlock(&priv->shared_act_sl);
12799 	return idx;
12800 error_rss_init:
12801 	if (shared_rss) {
12802 		if (shared_rss->ind_tbl)
12803 			mlx5_free(shared_rss->ind_tbl);
12804 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
12805 				idx);
12806 	}
12807 	if (queue)
12808 		mlx5_free(queue);
12809 	return 0;
12810 }
12811 
12812 /**
12813  * Destroy the shared RSS action.
12814  * Release related hash RX queue objects.
12815  *
12816  * @param[in] dev
12817  *   Pointer to the Ethernet device structure.
12818  * @param[in] idx
12819  *   The shared RSS action object ID to be removed.
12820  * @param[out] error
12821  *   Perform verbose error reporting if not NULL. Initialized in case of
12822  *   error only.
12823  *
12824  * @return
12825  *   0 on success, otherwise negative errno value.
12826  */
12827 static int
12828 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx,
12829 			     struct rte_flow_error *error)
12830 {
12831 	struct mlx5_priv *priv = dev->data->dev_private;
12832 	struct mlx5_shared_action_rss *shared_rss =
12833 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
12834 	uint32_t old_refcnt = 1;
12835 	int remaining;
12836 	uint16_t *queue = NULL;
12837 
12838 	if (!shared_rss)
12839 		return rte_flow_error_set(error, EINVAL,
12840 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12841 					  "invalid shared action");
12842 	remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss);
12843 	if (remaining)
12844 		return rte_flow_error_set(error, EBUSY,
12845 					  RTE_FLOW_ERROR_TYPE_ACTION,
12846 					  NULL,
12847 					  "shared rss hrxq has references");
12848 	if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt,
12849 					 0, 0, __ATOMIC_ACQUIRE,
12850 					 __ATOMIC_RELAXED))
12851 		return rte_flow_error_set(error, EBUSY,
12852 					  RTE_FLOW_ERROR_TYPE_ACTION,
12853 					  NULL,
12854 					  "shared rss has references");
12855 	queue = shared_rss->ind_tbl->queues;
12856 	remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true);
12857 	if (remaining)
12858 		return rte_flow_error_set(error, EBUSY,
12859 					  RTE_FLOW_ERROR_TYPE_ACTION,
12860 					  NULL,
12861 					  "shared rss indirection table has"
12862 					  " references");
12863 	mlx5_free(queue);
12864 	rte_spinlock_lock(&priv->shared_act_sl);
12865 	ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
12866 		     &priv->rss_shared_actions, idx, shared_rss, next);
12867 	rte_spinlock_unlock(&priv->shared_act_sl);
12868 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
12869 			idx);
12870 	return 0;
12871 }
12872 
12873 /**
12874  * Create shared action, lock free,
12875  * (mutex should be acquired by caller).
12876  * Dispatcher for action type specific call.
12877  *
12878  * @param[in] dev
12879  *   Pointer to the Ethernet device structure.
12880  * @param[in] conf
12881  *   Shared action configuration.
12882  * @param[in] action
12883  *   Action specification used to create shared action.
12884  * @param[out] error
12885  *   Perform verbose error reporting if not NULL. Initialized in case of
12886  *   error only.
12887  *
12888  * @return
12889  *   A valid shared action handle in case of success, NULL otherwise and
12890  *   rte_errno is set.
12891  */
12892 static struct rte_flow_shared_action *
12893 flow_dv_action_create(struct rte_eth_dev *dev,
12894 		      const struct rte_flow_shared_action_conf *conf,
12895 		      const struct rte_flow_action *action,
12896 		      struct rte_flow_error *err)
12897 {
12898 	uint32_t idx = 0;
12899 	uint32_t ret = 0;
12900 
12901 	switch (action->type) {
12902 	case RTE_FLOW_ACTION_TYPE_RSS:
12903 		ret = __flow_dv_action_rss_create(dev, conf, action->conf, err);
12904 		idx = (MLX5_SHARED_ACTION_TYPE_RSS <<
12905 		       MLX5_SHARED_ACTION_TYPE_OFFSET) | ret;
12906 		break;
12907 	case RTE_FLOW_ACTION_TYPE_AGE:
12908 		ret = flow_dv_translate_create_aso_age(dev, action->conf, err);
12909 		idx = (MLX5_SHARED_ACTION_TYPE_AGE <<
12910 		       MLX5_SHARED_ACTION_TYPE_OFFSET) | ret;
12911 		if (ret) {
12912 			struct mlx5_aso_age_action *aso_age =
12913 					      flow_aso_age_get_by_idx(dev, ret);
12914 
12915 			if (!aso_age->age_params.context)
12916 				aso_age->age_params.context =
12917 							 (void *)(uintptr_t)idx;
12918 		}
12919 		break;
12920 	default:
12921 		rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
12922 				   NULL, "action type not supported");
12923 		break;
12924 	}
12925 	return ret ? (struct rte_flow_shared_action *)(uintptr_t)idx : NULL;
12926 }
12927 
12928 /**
12929  * Destroy the shared action.
12930  * Release action related resources on the NIC and the memory.
12931  * Lock free, (mutex should be acquired by caller).
12932  * Dispatcher for action type specific call.
12933  *
12934  * @param[in] dev
12935  *   Pointer to the Ethernet device structure.
12936  * @param[in] action
12937  *   The shared action object to be removed.
12938  * @param[out] error
12939  *   Perform verbose error reporting if not NULL. Initialized in case of
12940  *   error only.
12941  *
12942  * @return
12943  *   0 on success, otherwise negative errno value.
12944  */
12945 static int
12946 flow_dv_action_destroy(struct rte_eth_dev *dev,
12947 		       struct rte_flow_shared_action *action,
12948 		       struct rte_flow_error *error)
12949 {
12950 	uint32_t act_idx = (uint32_t)(uintptr_t)action;
12951 	uint32_t type = act_idx >> MLX5_SHARED_ACTION_TYPE_OFFSET;
12952 	uint32_t idx = act_idx & ((1u << MLX5_SHARED_ACTION_TYPE_OFFSET) - 1);
12953 	int ret;
12954 
12955 	switch (type) {
12956 	case MLX5_SHARED_ACTION_TYPE_RSS:
12957 		return __flow_dv_action_rss_release(dev, idx, error);
12958 	case MLX5_SHARED_ACTION_TYPE_AGE:
12959 		ret = flow_dv_aso_age_release(dev, idx);
12960 		if (ret)
12961 			/*
12962 			 * In this case, the last flow has a reference will
12963 			 * actually release the age action.
12964 			 */
12965 			DRV_LOG(DEBUG, "Shared age action %" PRIu32 " was"
12966 				" released with references %d.", idx, ret);
12967 		return 0;
12968 	default:
12969 		return rte_flow_error_set(error, ENOTSUP,
12970 					  RTE_FLOW_ERROR_TYPE_ACTION,
12971 					  NULL,
12972 					  "action type not supported");
12973 	}
12974 }
12975 
12976 /**
12977  * Updates in place shared RSS action configuration.
12978  *
12979  * @param[in] dev
12980  *   Pointer to the Ethernet device structure.
12981  * @param[in] idx
12982  *   The shared RSS action object ID to be updated.
12983  * @param[in] action_conf
12984  *   RSS action specification used to modify *shared_rss*.
12985  * @param[out] error
12986  *   Perform verbose error reporting if not NULL. Initialized in case of
12987  *   error only.
12988  *
12989  * @return
12990  *   0 on success, otherwise negative errno value.
12991  * @note: currently only support update of RSS queues.
12992  */
12993 static int
12994 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx,
12995 			    const struct rte_flow_action_rss *action_conf,
12996 			    struct rte_flow_error *error)
12997 {
12998 	struct mlx5_priv *priv = dev->data->dev_private;
12999 	struct mlx5_shared_action_rss *shared_rss =
13000 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
13001 	int ret = 0;
13002 	void *queue = NULL;
13003 	uint16_t *queue_old = NULL;
13004 	uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t);
13005 
13006 	if (!shared_rss)
13007 		return rte_flow_error_set(error, EINVAL,
13008 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
13009 					  "invalid shared action to update");
13010 	if (priv->obj_ops.ind_table_modify == NULL)
13011 		return rte_flow_error_set(error, ENOTSUP,
13012 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
13013 					  "cannot modify indirection table");
13014 	queue = mlx5_malloc(MLX5_MEM_ZERO,
13015 			    RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
13016 			    0, SOCKET_ID_ANY);
13017 	if (!queue)
13018 		return rte_flow_error_set(error, ENOMEM,
13019 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13020 					  NULL,
13021 					  "cannot allocate resource memory");
13022 	memcpy(queue, action_conf->queue, queue_size);
13023 	MLX5_ASSERT(shared_rss->ind_tbl);
13024 	rte_spinlock_lock(&shared_rss->action_rss_sl);
13025 	queue_old = shared_rss->ind_tbl->queues;
13026 	ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl,
13027 					queue, action_conf->queue_num, true);
13028 	if (ret) {
13029 		mlx5_free(queue);
13030 		ret = rte_flow_error_set(error, rte_errno,
13031 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
13032 					  "cannot update indirection table");
13033 	} else {
13034 		mlx5_free(queue_old);
13035 		shared_rss->origin.queue = queue;
13036 		shared_rss->origin.queue_num = action_conf->queue_num;
13037 	}
13038 	rte_spinlock_unlock(&shared_rss->action_rss_sl);
13039 	return ret;
13040 }
13041 
13042 /**
13043  * Updates in place shared action configuration, lock free,
13044  * (mutex should be acquired by caller).
13045  *
13046  * @param[in] dev
13047  *   Pointer to the Ethernet device structure.
13048  * @param[in] action
13049  *   The shared action object to be updated.
13050  * @param[in] action_conf
13051  *   Action specification used to modify *action*.
13052  *   *action_conf* should be of type correlating with type of the *action*,
13053  *   otherwise considered as invalid.
13054  * @param[out] error
13055  *   Perform verbose error reporting if not NULL. Initialized in case of
13056  *   error only.
13057  *
13058  * @return
13059  *   0 on success, otherwise negative errno value.
13060  */
13061 static int
13062 flow_dv_action_update(struct rte_eth_dev *dev,
13063 			struct rte_flow_shared_action *action,
13064 			const void *action_conf,
13065 			struct rte_flow_error *err)
13066 {
13067 	uint32_t act_idx = (uint32_t)(uintptr_t)action;
13068 	uint32_t type = act_idx >> MLX5_SHARED_ACTION_TYPE_OFFSET;
13069 	uint32_t idx = act_idx & ((1u << MLX5_SHARED_ACTION_TYPE_OFFSET) - 1);
13070 
13071 	switch (type) {
13072 	case MLX5_SHARED_ACTION_TYPE_RSS:
13073 		return __flow_dv_action_rss_update(dev, idx, action_conf, err);
13074 	default:
13075 		return rte_flow_error_set(err, ENOTSUP,
13076 					  RTE_FLOW_ERROR_TYPE_ACTION,
13077 					  NULL,
13078 					  "action type update not supported");
13079 	}
13080 }
13081 
13082 static int
13083 flow_dv_action_query(struct rte_eth_dev *dev,
13084 		     const struct rte_flow_shared_action *action, void *data,
13085 		     struct rte_flow_error *error)
13086 {
13087 	struct mlx5_age_param *age_param;
13088 	struct rte_flow_query_age *resp;
13089 	uint32_t act_idx = (uint32_t)(uintptr_t)action;
13090 	uint32_t type = act_idx >> MLX5_SHARED_ACTION_TYPE_OFFSET;
13091 	uint32_t idx = act_idx & ((1u << MLX5_SHARED_ACTION_TYPE_OFFSET) - 1);
13092 
13093 	switch (type) {
13094 	case MLX5_SHARED_ACTION_TYPE_AGE:
13095 		age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params;
13096 		resp = data;
13097 		resp->aged = __atomic_load_n(&age_param->state,
13098 					      __ATOMIC_RELAXED) == AGE_TMOUT ?
13099 									  1 : 0;
13100 		resp->sec_since_last_hit_valid = !resp->aged;
13101 		if (resp->sec_since_last_hit_valid)
13102 			resp->sec_since_last_hit = __atomic_load_n
13103 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
13104 		return 0;
13105 	default:
13106 		return rte_flow_error_set(error, ENOTSUP,
13107 					  RTE_FLOW_ERROR_TYPE_ACTION,
13108 					  NULL,
13109 					  "action type query not supported");
13110 	}
13111 }
13112 
13113 /**
13114  * Query a dv flow  rule for its statistics via devx.
13115  *
13116  * @param[in] dev
13117  *   Pointer to Ethernet device.
13118  * @param[in] flow
13119  *   Pointer to the sub flow.
13120  * @param[out] data
13121  *   data retrieved by the query.
13122  * @param[out] error
13123  *   Perform verbose error reporting if not NULL.
13124  *
13125  * @return
13126  *   0 on success, a negative errno value otherwise and rte_errno is set.
13127  */
13128 static int
13129 flow_dv_query_count(struct rte_eth_dev *dev, struct rte_flow *flow,
13130 		    void *data, struct rte_flow_error *error)
13131 {
13132 	struct mlx5_priv *priv = dev->data->dev_private;
13133 	struct rte_flow_query_count *qc = data;
13134 
13135 	if (!priv->config.devx)
13136 		return rte_flow_error_set(error, ENOTSUP,
13137 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13138 					  NULL,
13139 					  "counters are not supported");
13140 	if (flow->counter) {
13141 		uint64_t pkts, bytes;
13142 		struct mlx5_flow_counter *cnt;
13143 
13144 		cnt = flow_dv_counter_get_by_idx(dev, flow->counter,
13145 						 NULL);
13146 		int err = _flow_dv_query_count(dev, flow->counter, &pkts,
13147 					       &bytes);
13148 
13149 		if (err)
13150 			return rte_flow_error_set(error, -err,
13151 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13152 					NULL, "cannot read counters");
13153 		qc->hits_set = 1;
13154 		qc->bytes_set = 1;
13155 		qc->hits = pkts - cnt->hits;
13156 		qc->bytes = bytes - cnt->bytes;
13157 		if (qc->reset) {
13158 			cnt->hits = pkts;
13159 			cnt->bytes = bytes;
13160 		}
13161 		return 0;
13162 	}
13163 	return rte_flow_error_set(error, EINVAL,
13164 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13165 				  NULL,
13166 				  "counters are not available");
13167 }
13168 
13169 /**
13170  * Query a flow rule AGE action for aging information.
13171  *
13172  * @param[in] dev
13173  *   Pointer to Ethernet device.
13174  * @param[in] flow
13175  *   Pointer to the sub flow.
13176  * @param[out] data
13177  *   data retrieved by the query.
13178  * @param[out] error
13179  *   Perform verbose error reporting if not NULL.
13180  *
13181  * @return
13182  *   0 on success, a negative errno value otherwise and rte_errno is set.
13183  */
13184 static int
13185 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow,
13186 		  void *data, struct rte_flow_error *error)
13187 {
13188 	struct rte_flow_query_age *resp = data;
13189 	struct mlx5_age_param *age_param;
13190 
13191 	if (flow->age) {
13192 		struct mlx5_aso_age_action *act =
13193 				     flow_aso_age_get_by_idx(dev, flow->age);
13194 
13195 		age_param = &act->age_params;
13196 	} else if (flow->counter) {
13197 		age_param = flow_dv_counter_idx_get_age(dev, flow->counter);
13198 
13199 		if (!age_param || !age_param->timeout)
13200 			return rte_flow_error_set
13201 					(error, EINVAL,
13202 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13203 					 NULL, "cannot read age data");
13204 	} else {
13205 		return rte_flow_error_set(error, EINVAL,
13206 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13207 					  NULL, "age data not available");
13208 	}
13209 	resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) ==
13210 				     AGE_TMOUT ? 1 : 0;
13211 	resp->sec_since_last_hit_valid = !resp->aged;
13212 	if (resp->sec_since_last_hit_valid)
13213 		resp->sec_since_last_hit = __atomic_load_n
13214 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
13215 	return 0;
13216 }
13217 
13218 /**
13219  * Query a flow.
13220  *
13221  * @see rte_flow_query()
13222  * @see rte_flow_ops
13223  */
13224 static int
13225 flow_dv_query(struct rte_eth_dev *dev,
13226 	      struct rte_flow *flow __rte_unused,
13227 	      const struct rte_flow_action *actions __rte_unused,
13228 	      void *data __rte_unused,
13229 	      struct rte_flow_error *error __rte_unused)
13230 {
13231 	int ret = -EINVAL;
13232 
13233 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
13234 		switch (actions->type) {
13235 		case RTE_FLOW_ACTION_TYPE_VOID:
13236 			break;
13237 		case RTE_FLOW_ACTION_TYPE_COUNT:
13238 			ret = flow_dv_query_count(dev, flow, data, error);
13239 			break;
13240 		case RTE_FLOW_ACTION_TYPE_AGE:
13241 			ret = flow_dv_query_age(dev, flow, data, error);
13242 			break;
13243 		default:
13244 			return rte_flow_error_set(error, ENOTSUP,
13245 						  RTE_FLOW_ERROR_TYPE_ACTION,
13246 						  actions,
13247 						  "action not supported");
13248 		}
13249 	}
13250 	return ret;
13251 }
13252 
13253 /**
13254  * Destroy the meter table set.
13255  * Lock free, (mutex should be acquired by caller).
13256  *
13257  * @param[in] dev
13258  *   Pointer to Ethernet device.
13259  * @param[in] tbl
13260  *   Pointer to the meter table set.
13261  *
13262  * @return
13263  *   Always 0.
13264  */
13265 static int
13266 flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
13267 			struct mlx5_meter_domains_infos *tbl)
13268 {
13269 	struct mlx5_priv *priv = dev->data->dev_private;
13270 	struct mlx5_meter_domains_infos *mtd =
13271 				(struct mlx5_meter_domains_infos *)tbl;
13272 
13273 	if (!mtd || !priv->config.dv_flow_en)
13274 		return 0;
13275 	if (mtd->ingress.policer_rules[RTE_MTR_DROPPED])
13276 		claim_zero(mlx5_flow_os_destroy_flow
13277 			   (mtd->ingress.policer_rules[RTE_MTR_DROPPED]));
13278 	if (mtd->egress.policer_rules[RTE_MTR_DROPPED])
13279 		claim_zero(mlx5_flow_os_destroy_flow
13280 			   (mtd->egress.policer_rules[RTE_MTR_DROPPED]));
13281 	if (mtd->transfer.policer_rules[RTE_MTR_DROPPED])
13282 		claim_zero(mlx5_flow_os_destroy_flow
13283 			   (mtd->transfer.policer_rules[RTE_MTR_DROPPED]));
13284 	if (mtd->egress.color_matcher)
13285 		claim_zero(mlx5_flow_os_destroy_flow_matcher
13286 			   (mtd->egress.color_matcher));
13287 	if (mtd->egress.any_matcher)
13288 		claim_zero(mlx5_flow_os_destroy_flow_matcher
13289 			   (mtd->egress.any_matcher));
13290 	if (mtd->egress.tbl)
13291 		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.tbl);
13292 	if (mtd->egress.sfx_tbl)
13293 		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.sfx_tbl);
13294 	if (mtd->ingress.color_matcher)
13295 		claim_zero(mlx5_flow_os_destroy_flow_matcher
13296 			   (mtd->ingress.color_matcher));
13297 	if (mtd->ingress.any_matcher)
13298 		claim_zero(mlx5_flow_os_destroy_flow_matcher
13299 			   (mtd->ingress.any_matcher));
13300 	if (mtd->ingress.tbl)
13301 		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->ingress.tbl);
13302 	if (mtd->ingress.sfx_tbl)
13303 		flow_dv_tbl_resource_release(MLX5_SH(dev),
13304 					     mtd->ingress.sfx_tbl);
13305 	if (mtd->transfer.color_matcher)
13306 		claim_zero(mlx5_flow_os_destroy_flow_matcher
13307 			   (mtd->transfer.color_matcher));
13308 	if (mtd->transfer.any_matcher)
13309 		claim_zero(mlx5_flow_os_destroy_flow_matcher
13310 			   (mtd->transfer.any_matcher));
13311 	if (mtd->transfer.tbl)
13312 		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->transfer.tbl);
13313 	if (mtd->transfer.sfx_tbl)
13314 		flow_dv_tbl_resource_release(MLX5_SH(dev),
13315 					     mtd->transfer.sfx_tbl);
13316 	if (mtd->drop_actn)
13317 		claim_zero(mlx5_flow_os_destroy_flow_action(mtd->drop_actn));
13318 	mlx5_free(mtd);
13319 	return 0;
13320 }
13321 
13322 /* Number of meter flow actions, count and jump or count and drop. */
13323 #define METER_ACTIONS 2
13324 
13325 /**
13326  * Create specify domain meter table and suffix table.
13327  *
13328  * @param[in] dev
13329  *   Pointer to Ethernet device.
13330  * @param[in,out] mtb
13331  *   Pointer to DV meter table set.
13332  * @param[in] egress
13333  *   Table attribute.
13334  * @param[in] transfer
13335  *   Table attribute.
13336  * @param[in] color_reg_c_idx
13337  *   Reg C index for color match.
13338  *
13339  * @return
13340  *   0 on success, -1 otherwise and rte_errno is set.
13341  */
13342 static int
13343 flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
13344 			   struct mlx5_meter_domains_infos *mtb,
13345 			   uint8_t egress, uint8_t transfer,
13346 			   uint32_t color_reg_c_idx)
13347 {
13348 	struct mlx5_priv *priv = dev->data->dev_private;
13349 	struct mlx5_dev_ctx_shared *sh = priv->sh;
13350 	struct mlx5_flow_dv_match_params mask = {
13351 		.size = sizeof(mask.buf),
13352 	};
13353 	struct mlx5_flow_dv_match_params value = {
13354 		.size = sizeof(value.buf),
13355 	};
13356 	struct mlx5dv_flow_matcher_attr dv_attr = {
13357 		.type = IBV_FLOW_ATTR_NORMAL,
13358 		.priority = 0,
13359 		.match_criteria_enable = 0,
13360 		.match_mask = (void *)&mask,
13361 	};
13362 	void *actions[METER_ACTIONS];
13363 	struct mlx5_meter_domain_info *dtb;
13364 	struct rte_flow_error error;
13365 	int i = 0;
13366 	int ret;
13367 
13368 	if (transfer)
13369 		dtb = &mtb->transfer;
13370 	else if (egress)
13371 		dtb = &mtb->egress;
13372 	else
13373 		dtb = &mtb->ingress;
13374 	/* Create the meter table with METER level. */
13375 	dtb->tbl = flow_dv_tbl_resource_get(dev, MLX5_FLOW_TABLE_LEVEL_METER,
13376 					    egress, transfer, false, NULL, 0,
13377 					    0, &error);
13378 	if (!dtb->tbl) {
13379 		DRV_LOG(ERR, "Failed to create meter policer table.");
13380 		return -1;
13381 	}
13382 	/* Create the meter suffix table with SUFFIX level. */
13383 	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
13384 					    MLX5_FLOW_TABLE_LEVEL_SUFFIX,
13385 					    egress, transfer, false, NULL, 0,
13386 					    0, &error);
13387 	if (!dtb->sfx_tbl) {
13388 		DRV_LOG(ERR, "Failed to create meter suffix table.");
13389 		return -1;
13390 	}
13391 	/* Create matchers, Any and Color. */
13392 	dv_attr.priority = 3;
13393 	dv_attr.match_criteria_enable = 0;
13394 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, dtb->tbl->obj,
13395 					       &dtb->any_matcher);
13396 	if (ret) {
13397 		DRV_LOG(ERR, "Failed to create meter"
13398 			     " policer default matcher.");
13399 		goto error_exit;
13400 	}
13401 	dv_attr.priority = 0;
13402 	dv_attr.match_criteria_enable =
13403 				1 << MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
13404 	flow_dv_match_meta_reg(mask.buf, value.buf, color_reg_c_idx,
13405 			       rte_col_2_mlx5_col(RTE_COLORS), UINT8_MAX);
13406 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, dtb->tbl->obj,
13407 					       &dtb->color_matcher);
13408 	if (ret) {
13409 		DRV_LOG(ERR, "Failed to create meter policer color matcher.");
13410 		goto error_exit;
13411 	}
13412 	if (mtb->count_actns[RTE_MTR_DROPPED])
13413 		actions[i++] = mtb->count_actns[RTE_MTR_DROPPED];
13414 	actions[i++] = mtb->drop_actn;
13415 	/* Default rule: lowest priority, match any, actions: drop. */
13416 	ret = mlx5_flow_os_create_flow(dtb->any_matcher, (void *)&value, i,
13417 				       actions,
13418 				       &dtb->policer_rules[RTE_MTR_DROPPED]);
13419 	if (ret) {
13420 		DRV_LOG(ERR, "Failed to create meter policer drop rule.");
13421 		goto error_exit;
13422 	}
13423 	return 0;
13424 error_exit:
13425 	return -1;
13426 }
13427 
13428 /**
13429  * Create the needed meter and suffix tables.
13430  * Lock free, (mutex should be acquired by caller).
13431  *
13432  * @param[in] dev
13433  *   Pointer to Ethernet device.
13434  * @param[in] fm
13435  *   Pointer to the flow meter.
13436  *
13437  * @return
13438  *   Pointer to table set on success, NULL otherwise and rte_errno is set.
13439  */
13440 static struct mlx5_meter_domains_infos *
13441 flow_dv_create_mtr_tbl(struct rte_eth_dev *dev,
13442 		       const struct mlx5_flow_meter *fm)
13443 {
13444 	struct mlx5_priv *priv = dev->data->dev_private;
13445 	struct mlx5_meter_domains_infos *mtb;
13446 	int ret;
13447 	int i;
13448 
13449 	if (!priv->mtr_en) {
13450 		rte_errno = ENOTSUP;
13451 		return NULL;
13452 	}
13453 	mtb = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*mtb), 0, SOCKET_ID_ANY);
13454 	if (!mtb) {
13455 		DRV_LOG(ERR, "Failed to allocate memory for meter.");
13456 		return NULL;
13457 	}
13458 	/* Create meter count actions */
13459 	for (i = 0; i <= RTE_MTR_DROPPED; i++) {
13460 		struct mlx5_flow_counter *cnt;
13461 		if (!fm->policer_stats.cnt[i])
13462 			continue;
13463 		cnt = flow_dv_counter_get_by_idx(dev,
13464 		      fm->policer_stats.cnt[i], NULL);
13465 		mtb->count_actns[i] = cnt->action;
13466 	}
13467 	/* Create drop action. */
13468 	ret = mlx5_flow_os_create_flow_action_drop(&mtb->drop_actn);
13469 	if (ret) {
13470 		DRV_LOG(ERR, "Failed to create drop action.");
13471 		goto error_exit;
13472 	}
13473 	/* Egress meter table. */
13474 	ret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0, priv->mtr_color_reg);
13475 	if (ret) {
13476 		DRV_LOG(ERR, "Failed to prepare egress meter table.");
13477 		goto error_exit;
13478 	}
13479 	/* Ingress meter table. */
13480 	ret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 0, priv->mtr_color_reg);
13481 	if (ret) {
13482 		DRV_LOG(ERR, "Failed to prepare ingress meter table.");
13483 		goto error_exit;
13484 	}
13485 	/* FDB meter table. */
13486 	if (priv->config.dv_esw_en) {
13487 		ret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 1,
13488 						 priv->mtr_color_reg);
13489 		if (ret) {
13490 			DRV_LOG(ERR, "Failed to prepare fdb meter table.");
13491 			goto error_exit;
13492 		}
13493 	}
13494 	return mtb;
13495 error_exit:
13496 	flow_dv_destroy_mtr_tbl(dev, mtb);
13497 	return NULL;
13498 }
13499 
13500 /**
13501  * Destroy domain policer rule.
13502  *
13503  * @param[in] dt
13504  *   Pointer to domain table.
13505  */
13506 static void
13507 flow_dv_destroy_domain_policer_rule(struct mlx5_meter_domain_info *dt)
13508 {
13509 	int i;
13510 
13511 	for (i = 0; i < RTE_MTR_DROPPED; i++) {
13512 		if (dt->policer_rules[i]) {
13513 			claim_zero(mlx5_flow_os_destroy_flow
13514 				   (dt->policer_rules[i]));
13515 			dt->policer_rules[i] = NULL;
13516 		}
13517 	}
13518 	if (dt->jump_actn) {
13519 		claim_zero(mlx5_flow_os_destroy_flow_action(dt->jump_actn));
13520 		dt->jump_actn = NULL;
13521 	}
13522 }
13523 
13524 /**
13525  * Destroy policer rules.
13526  *
13527  * @param[in] dev
13528  *   Pointer to Ethernet device.
13529  * @param[in] fm
13530  *   Pointer to flow meter structure.
13531  * @param[in] attr
13532  *   Pointer to flow attributes.
13533  *
13534  * @return
13535  *   Always 0.
13536  */
13537 static int
13538 flow_dv_destroy_policer_rules(struct rte_eth_dev *dev __rte_unused,
13539 			      const struct mlx5_flow_meter *fm,
13540 			      const struct rte_flow_attr *attr)
13541 {
13542 	struct mlx5_meter_domains_infos *mtb = fm ? fm->mfts : NULL;
13543 
13544 	if (!mtb)
13545 		return 0;
13546 	if (attr->egress)
13547 		flow_dv_destroy_domain_policer_rule(&mtb->egress);
13548 	if (attr->ingress)
13549 		flow_dv_destroy_domain_policer_rule(&mtb->ingress);
13550 	if (attr->transfer)
13551 		flow_dv_destroy_domain_policer_rule(&mtb->transfer);
13552 	return 0;
13553 }
13554 
13555 /**
13556  * Create specify domain meter policer rule.
13557  *
13558  * @param[in] fm
13559  *   Pointer to flow meter structure.
13560  * @param[in] mtb
13561  *   Pointer to DV meter table set.
13562  * @param[in] mtr_reg_c
13563  *   Color match REG_C.
13564  *
13565  * @return
13566  *   0 on success, -1 otherwise.
13567  */
13568 static int
13569 flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,
13570 				    struct mlx5_meter_domain_info *dtb,
13571 				    uint8_t mtr_reg_c)
13572 {
13573 	struct mlx5_flow_dv_match_params matcher = {
13574 		.size = sizeof(matcher.buf),
13575 	};
13576 	struct mlx5_flow_dv_match_params value = {
13577 		.size = sizeof(value.buf),
13578 	};
13579 	struct mlx5_meter_domains_infos *mtb = fm->mfts;
13580 	void *actions[METER_ACTIONS];
13581 	int i;
13582 	int ret = 0;
13583 
13584 	/* Create jump action. */
13585 	if (!dtb->jump_actn)
13586 		ret = mlx5_flow_os_create_flow_action_dest_flow_tbl
13587 				(dtb->sfx_tbl->obj, &dtb->jump_actn);
13588 	if (ret) {
13589 		DRV_LOG(ERR, "Failed to create policer jump action.");
13590 		goto error;
13591 	}
13592 	for (i = 0; i < RTE_MTR_DROPPED; i++) {
13593 		int j = 0;
13594 
13595 		flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_reg_c,
13596 				       rte_col_2_mlx5_col(i), UINT8_MAX);
13597 		if (mtb->count_actns[i])
13598 			actions[j++] = mtb->count_actns[i];
13599 		if (fm->action[i] == MTR_POLICER_ACTION_DROP)
13600 			actions[j++] = mtb->drop_actn;
13601 		else
13602 			actions[j++] = dtb->jump_actn;
13603 		ret = mlx5_flow_os_create_flow(dtb->color_matcher,
13604 					       (void *)&value, j, actions,
13605 					       &dtb->policer_rules[i]);
13606 		if (ret) {
13607 			DRV_LOG(ERR, "Failed to create policer rule.");
13608 			goto error;
13609 		}
13610 	}
13611 	return 0;
13612 error:
13613 	rte_errno = errno;
13614 	return -1;
13615 }
13616 
13617 /**
13618  * Create policer rules.
13619  *
13620  * @param[in] dev
13621  *   Pointer to Ethernet device.
13622  * @param[in] fm
13623  *   Pointer to flow meter structure.
13624  * @param[in] attr
13625  *   Pointer to flow attributes.
13626  *
13627  * @return
13628  *   0 on success, -1 otherwise.
13629  */
13630 static int
13631 flow_dv_create_policer_rules(struct rte_eth_dev *dev,
13632 			     struct mlx5_flow_meter *fm,
13633 			     const struct rte_flow_attr *attr)
13634 {
13635 	struct mlx5_priv *priv = dev->data->dev_private;
13636 	struct mlx5_meter_domains_infos *mtb = fm->mfts;
13637 	int ret;
13638 
13639 	if (attr->egress) {
13640 		ret = flow_dv_create_policer_forward_rule(fm, &mtb->egress,
13641 						priv->mtr_color_reg);
13642 		if (ret) {
13643 			DRV_LOG(ERR, "Failed to create egress policer.");
13644 			goto error;
13645 		}
13646 	}
13647 	if (attr->ingress) {
13648 		ret = flow_dv_create_policer_forward_rule(fm, &mtb->ingress,
13649 						priv->mtr_color_reg);
13650 		if (ret) {
13651 			DRV_LOG(ERR, "Failed to create ingress policer.");
13652 			goto error;
13653 		}
13654 	}
13655 	if (attr->transfer) {
13656 		ret = flow_dv_create_policer_forward_rule(fm, &mtb->transfer,
13657 						priv->mtr_color_reg);
13658 		if (ret) {
13659 			DRV_LOG(ERR, "Failed to create transfer policer.");
13660 			goto error;
13661 		}
13662 	}
13663 	return 0;
13664 error:
13665 	flow_dv_destroy_policer_rules(dev, fm, attr);
13666 	return -1;
13667 }
13668 
13669 /**
13670  * Validate the batch counter support in root table.
13671  *
13672  * Create a simple flow with invalid counter and drop action on root table to
13673  * validate if batch counter with offset on root table is supported or not.
13674  *
13675  * @param[in] dev
13676  *   Pointer to rte_eth_dev structure.
13677  *
13678  * @return
13679  *   0 on success, a negative errno value otherwise and rte_errno is set.
13680  */
13681 int
13682 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev)
13683 {
13684 	struct mlx5_priv *priv = dev->data->dev_private;
13685 	struct mlx5_dev_ctx_shared *sh = priv->sh;
13686 	struct mlx5_flow_dv_match_params mask = {
13687 		.size = sizeof(mask.buf),
13688 	};
13689 	struct mlx5_flow_dv_match_params value = {
13690 		.size = sizeof(value.buf),
13691 	};
13692 	struct mlx5dv_flow_matcher_attr dv_attr = {
13693 		.type = IBV_FLOW_ATTR_NORMAL,
13694 		.priority = 0,
13695 		.match_criteria_enable = 0,
13696 		.match_mask = (void *)&mask,
13697 	};
13698 	void *actions[2] = { 0 };
13699 	struct mlx5_flow_tbl_resource *tbl = NULL;
13700 	struct mlx5_devx_obj *dcs = NULL;
13701 	void *matcher = NULL;
13702 	void *flow = NULL;
13703 	int ret = -1;
13704 
13705 	tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL, 0, 0, NULL);
13706 	if (!tbl)
13707 		goto err;
13708 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4);
13709 	if (!dcs)
13710 		goto err;
13711 	ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX,
13712 						    &actions[0]);
13713 	if (ret)
13714 		goto err;
13715 	actions[1] = priv->drop_queue.hrxq->action;
13716 	dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
13717 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj,
13718 					       &matcher);
13719 	if (ret)
13720 		goto err;
13721 	ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 2,
13722 				       actions, &flow);
13723 err:
13724 	/*
13725 	 * If batch counter with offset is not supported, the driver will not
13726 	 * validate the invalid offset value, flow create should success.
13727 	 * In this case, it means batch counter is not supported in root table.
13728 	 *
13729 	 * Otherwise, if flow create is failed, counter offset is supported.
13730 	 */
13731 	if (flow) {
13732 		DRV_LOG(INFO, "Batch counter is not supported in root "
13733 			      "table. Switch to fallback mode.");
13734 		rte_errno = ENOTSUP;
13735 		ret = -rte_errno;
13736 		claim_zero(mlx5_flow_os_destroy_flow(flow));
13737 	} else {
13738 		/* Check matcher to make sure validate fail at flow create. */
13739 		if (!matcher || (matcher && errno != EINVAL))
13740 			DRV_LOG(ERR, "Unexpected error in counter offset "
13741 				     "support detection");
13742 		ret = 0;
13743 	}
13744 	if (actions[0])
13745 		claim_zero(mlx5_flow_os_destroy_flow_action(actions[0]));
13746 	if (matcher)
13747 		claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
13748 	if (tbl)
13749 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
13750 	if (dcs)
13751 		claim_zero(mlx5_devx_cmd_destroy(dcs));
13752 	return ret;
13753 }
13754 
13755 /**
13756  * Query a devx counter.
13757  *
13758  * @param[in] dev
13759  *   Pointer to the Ethernet device structure.
13760  * @param[in] cnt
13761  *   Index to the flow counter.
13762  * @param[in] clear
13763  *   Set to clear the counter statistics.
13764  * @param[out] pkts
13765  *   The statistics value of packets.
13766  * @param[out] bytes
13767  *   The statistics value of bytes.
13768  *
13769  * @return
13770  *   0 on success, otherwise return -1.
13771  */
13772 static int
13773 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear,
13774 		      uint64_t *pkts, uint64_t *bytes)
13775 {
13776 	struct mlx5_priv *priv = dev->data->dev_private;
13777 	struct mlx5_flow_counter *cnt;
13778 	uint64_t inn_pkts, inn_bytes;
13779 	int ret;
13780 
13781 	if (!priv->config.devx)
13782 		return -1;
13783 
13784 	ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes);
13785 	if (ret)
13786 		return -1;
13787 	cnt = flow_dv_counter_get_by_idx(dev, counter, NULL);
13788 	*pkts = inn_pkts - cnt->hits;
13789 	*bytes = inn_bytes - cnt->bytes;
13790 	if (clear) {
13791 		cnt->hits = inn_pkts;
13792 		cnt->bytes = inn_bytes;
13793 	}
13794 	return 0;
13795 }
13796 
13797 /**
13798  * Get aged-out flows.
13799  *
13800  * @param[in] dev
13801  *   Pointer to the Ethernet device structure.
13802  * @param[in] context
13803  *   The address of an array of pointers to the aged-out flows contexts.
13804  * @param[in] nb_contexts
13805  *   The length of context array pointers.
13806  * @param[out] error
13807  *   Perform verbose error reporting if not NULL. Initialized in case of
13808  *   error only.
13809  *
13810  * @return
13811  *   how many contexts get in success, otherwise negative errno value.
13812  *   if nb_contexts is 0, return the amount of all aged contexts.
13813  *   if nb_contexts is not 0 , return the amount of aged flows reported
13814  *   in the context array.
13815  * @note: only stub for now
13816  */
13817 static int
13818 flow_get_aged_flows(struct rte_eth_dev *dev,
13819 		    void **context,
13820 		    uint32_t nb_contexts,
13821 		    struct rte_flow_error *error)
13822 {
13823 	struct mlx5_priv *priv = dev->data->dev_private;
13824 	struct mlx5_age_info *age_info;
13825 	struct mlx5_age_param *age_param;
13826 	struct mlx5_flow_counter *counter;
13827 	struct mlx5_aso_age_action *act;
13828 	int nb_flows = 0;
13829 
13830 	if (nb_contexts && !context)
13831 		return rte_flow_error_set(error, EINVAL,
13832 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13833 					  NULL, "empty context");
13834 	age_info = GET_PORT_AGE_INFO(priv);
13835 	rte_spinlock_lock(&age_info->aged_sl);
13836 	LIST_FOREACH(act, &age_info->aged_aso, next) {
13837 		nb_flows++;
13838 		if (nb_contexts) {
13839 			context[nb_flows - 1] =
13840 						act->age_params.context;
13841 			if (!(--nb_contexts))
13842 				break;
13843 		}
13844 	}
13845 	TAILQ_FOREACH(counter, &age_info->aged_counters, next) {
13846 		nb_flows++;
13847 		if (nb_contexts) {
13848 			age_param = MLX5_CNT_TO_AGE(counter);
13849 			context[nb_flows - 1] = age_param->context;
13850 			if (!(--nb_contexts))
13851 				break;
13852 		}
13853 	}
13854 	rte_spinlock_unlock(&age_info->aged_sl);
13855 	MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER);
13856 	return nb_flows;
13857 }
13858 
13859 /*
13860  * Mutex-protected thunk to lock-free flow_dv_counter_alloc().
13861  */
13862 static uint32_t
13863 flow_dv_counter_allocate(struct rte_eth_dev *dev)
13864 {
13865 	return flow_dv_counter_alloc(dev, 0);
13866 }
13867 
13868 /**
13869  * Validate shared action.
13870  * Dispatcher for action type specific validation.
13871  *
13872  * @param[in] dev
13873  *   Pointer to the Ethernet device structure.
13874  * @param[in] conf
13875  *   Shared action configuration.
13876  * @param[in] action
13877  *   The shared action object to validate.
13878  * @param[out] error
13879  *   Perform verbose error reporting if not NULL. Initialized in case of
13880  *   error only.
13881  *
13882  * @return
13883  *   0 on success, otherwise negative errno value.
13884  */
13885 static int
13886 flow_dv_action_validate(struct rte_eth_dev *dev,
13887 			const struct rte_flow_shared_action_conf *conf,
13888 			const struct rte_flow_action *action,
13889 			struct rte_flow_error *err)
13890 {
13891 	struct mlx5_priv *priv = dev->data->dev_private;
13892 
13893 	RTE_SET_USED(conf);
13894 	switch (action->type) {
13895 	case RTE_FLOW_ACTION_TYPE_RSS:
13896 		/*
13897 		 * priv->obj_ops is set according to driver capabilities.
13898 		 * When DevX capabilities are
13899 		 * sufficient, it is set to devx_obj_ops.
13900 		 * Otherwise, it is set to ibv_obj_ops.
13901 		 * ibv_obj_ops doesn't support ind_table_modify operation.
13902 		 * In this case the shared RSS action can't be used.
13903 		 */
13904 		if (priv->obj_ops.ind_table_modify == NULL)
13905 			return rte_flow_error_set
13906 					(err, ENOTSUP,
13907 					 RTE_FLOW_ERROR_TYPE_ACTION,
13908 					 NULL,
13909 					 "shared RSS action not supported");
13910 		return mlx5_validate_action_rss(dev, action, err);
13911 	case RTE_FLOW_ACTION_TYPE_AGE:
13912 		if (!priv->sh->aso_age_mng)
13913 			return rte_flow_error_set(err, ENOTSUP,
13914 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13915 						NULL,
13916 					     "shared age action not supported");
13917 		return flow_dv_validate_action_age(0, action, dev, err);
13918 	default:
13919 		return rte_flow_error_set(err, ENOTSUP,
13920 					  RTE_FLOW_ERROR_TYPE_ACTION,
13921 					  NULL,
13922 					  "action type not supported");
13923 	}
13924 }
13925 
13926 static int
13927 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
13928 {
13929 	struct mlx5_priv *priv = dev->data->dev_private;
13930 	int ret = 0;
13931 
13932 	if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) {
13933 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain,
13934 						flags);
13935 		if (ret != 0)
13936 			return ret;
13937 	}
13938 	if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) {
13939 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags);
13940 		if (ret != 0)
13941 			return ret;
13942 	}
13943 	if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) {
13944 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags);
13945 		if (ret != 0)
13946 			return ret;
13947 	}
13948 	return 0;
13949 }
13950 
13951 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
13952 	.validate = flow_dv_validate,
13953 	.prepare = flow_dv_prepare,
13954 	.translate = flow_dv_translate,
13955 	.apply = flow_dv_apply,
13956 	.remove = flow_dv_remove,
13957 	.destroy = flow_dv_destroy,
13958 	.query = flow_dv_query,
13959 	.create_mtr_tbls = flow_dv_create_mtr_tbl,
13960 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
13961 	.create_policer_rules = flow_dv_create_policer_rules,
13962 	.destroy_policer_rules = flow_dv_destroy_policer_rules,
13963 	.counter_alloc = flow_dv_counter_allocate,
13964 	.counter_free = flow_dv_counter_free,
13965 	.counter_query = flow_dv_counter_query,
13966 	.get_aged_flows = flow_get_aged_flows,
13967 	.action_validate = flow_dv_action_validate,
13968 	.action_create = flow_dv_action_create,
13969 	.action_destroy = flow_dv_action_destroy,
13970 	.action_update = flow_dv_action_update,
13971 	.action_query = flow_dv_action_query,
13972 	.sync_domain = flow_dv_sync_domain,
13973 };
13974 
13975 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
13976 
13977