xref: /dpdk/drivers/net/mlx5/mlx5_flow_dv.c (revision 081e42dab11d1add2d038fdf2bd4c86b20043d08)
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 #include <rte_mtr.h>
25 #include <rte_mtr_driver.h>
26 #include <rte_tailq.h>
27 
28 #include <mlx5_glue.h>
29 #include <mlx5_devx_cmds.h>
30 #include <mlx5_prm.h>
31 #include <mlx5_malloc.h>
32 
33 #include "mlx5_defs.h"
34 #include "mlx5.h"
35 #include "mlx5_common_os.h"
36 #include "mlx5_flow.h"
37 #include "mlx5_flow_os.h"
38 #include "mlx5_rx.h"
39 #include "mlx5_tx.h"
40 #include "rte_pmd_mlx5.h"
41 
42 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
43 
44 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS
45 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0
46 #endif
47 
48 #ifndef HAVE_MLX5DV_DR_ESWITCH
49 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB
50 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0
51 #endif
52 #endif
53 
54 #ifndef HAVE_MLX5DV_DR
55 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1
56 #endif
57 
58 /* VLAN header definitions */
59 #define MLX5DV_FLOW_VLAN_PCP_SHIFT 13
60 #define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << MLX5DV_FLOW_VLAN_PCP_SHIFT)
61 #define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff
62 #define MLX5DV_FLOW_VLAN_PCP_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK)
63 #define MLX5DV_FLOW_VLAN_VID_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK)
64 
65 union flow_dv_attr {
66 	struct {
67 		uint32_t valid:1;
68 		uint32_t ipv4:1;
69 		uint32_t ipv6:1;
70 		uint32_t tcp:1;
71 		uint32_t udp:1;
72 		uint32_t reserved:27;
73 	};
74 	uint32_t attr;
75 };
76 
77 static int
78 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
79 			     struct mlx5_flow_tbl_resource *tbl);
80 
81 static int
82 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
83 				     uint32_t encap_decap_idx);
84 
85 static int
86 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
87 					uint32_t port_id);
88 static void
89 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss);
90 
91 static int
92 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
93 				  uint32_t rix_jump);
94 
95 /**
96  * Initialize flow attributes structure according to flow items' types.
97  *
98  * flow_dv_validate() avoids multiple L3/L4 layers cases other than tunnel
99  * mode. For tunnel mode, the items to be modified are the outermost ones.
100  *
101  * @param[in] item
102  *   Pointer to item specification.
103  * @param[out] attr
104  *   Pointer to flow attributes structure.
105  * @param[in] dev_flow
106  *   Pointer to the sub flow.
107  * @param[in] tunnel_decap
108  *   Whether action is after tunnel decapsulation.
109  */
110 static void
111 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
112 		  struct mlx5_flow *dev_flow, bool tunnel_decap)
113 {
114 	uint64_t layers = dev_flow->handle->layers;
115 
116 	/*
117 	 * If layers is already initialized, it means this dev_flow is the
118 	 * suffix flow, the layers flags is set by the prefix flow. Need to
119 	 * use the layer flags from prefix flow as the suffix flow may not
120 	 * have the user defined items as the flow is split.
121 	 */
122 	if (layers) {
123 		if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
124 			attr->ipv4 = 1;
125 		else if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV6)
126 			attr->ipv6 = 1;
127 		if (layers & MLX5_FLOW_LAYER_OUTER_L4_TCP)
128 			attr->tcp = 1;
129 		else if (layers & MLX5_FLOW_LAYER_OUTER_L4_UDP)
130 			attr->udp = 1;
131 		attr->valid = 1;
132 		return;
133 	}
134 	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
135 		uint8_t next_protocol = 0xff;
136 		switch (item->type) {
137 		case RTE_FLOW_ITEM_TYPE_GRE:
138 		case RTE_FLOW_ITEM_TYPE_NVGRE:
139 		case RTE_FLOW_ITEM_TYPE_VXLAN:
140 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
141 		case RTE_FLOW_ITEM_TYPE_GENEVE:
142 		case RTE_FLOW_ITEM_TYPE_MPLS:
143 			if (tunnel_decap)
144 				attr->attr = 0;
145 			break;
146 		case RTE_FLOW_ITEM_TYPE_IPV4:
147 			if (!attr->ipv6)
148 				attr->ipv4 = 1;
149 			if (item->mask != NULL &&
150 			    ((const struct rte_flow_item_ipv4 *)
151 			    item->mask)->hdr.next_proto_id)
152 				next_protocol =
153 				    ((const struct rte_flow_item_ipv4 *)
154 				      (item->spec))->hdr.next_proto_id &
155 				    ((const struct rte_flow_item_ipv4 *)
156 				      (item->mask))->hdr.next_proto_id;
157 			if ((next_protocol == IPPROTO_IPIP ||
158 			    next_protocol == IPPROTO_IPV6) && tunnel_decap)
159 				attr->attr = 0;
160 			break;
161 		case RTE_FLOW_ITEM_TYPE_IPV6:
162 			if (!attr->ipv4)
163 				attr->ipv6 = 1;
164 			if (item->mask != NULL &&
165 			    ((const struct rte_flow_item_ipv6 *)
166 			    item->mask)->hdr.proto)
167 				next_protocol =
168 				    ((const struct rte_flow_item_ipv6 *)
169 				      (item->spec))->hdr.proto &
170 				    ((const struct rte_flow_item_ipv6 *)
171 				      (item->mask))->hdr.proto;
172 			if ((next_protocol == IPPROTO_IPIP ||
173 			    next_protocol == IPPROTO_IPV6) && tunnel_decap)
174 				attr->attr = 0;
175 			break;
176 		case RTE_FLOW_ITEM_TYPE_UDP:
177 			if (!attr->tcp)
178 				attr->udp = 1;
179 			break;
180 		case RTE_FLOW_ITEM_TYPE_TCP:
181 			if (!attr->udp)
182 				attr->tcp = 1;
183 			break;
184 		default:
185 			break;
186 		}
187 	}
188 	attr->valid = 1;
189 }
190 
191 /*
192  * Convert rte_mtr_color to mlx5 color.
193  *
194  * @param[in] rcol
195  *   rte_mtr_color.
196  *
197  * @return
198  *   mlx5 color.
199  */
200 static inline int
201 rte_col_2_mlx5_col(enum rte_color rcol)
202 {
203 	switch (rcol) {
204 	case RTE_COLOR_GREEN:
205 		return MLX5_FLOW_COLOR_GREEN;
206 	case RTE_COLOR_YELLOW:
207 		return MLX5_FLOW_COLOR_YELLOW;
208 	case RTE_COLOR_RED:
209 		return MLX5_FLOW_COLOR_RED;
210 	default:
211 		break;
212 	}
213 	return MLX5_FLOW_COLOR_UNDEFINED;
214 }
215 
216 struct field_modify_info {
217 	uint32_t size; /* Size of field in protocol header, in bytes. */
218 	uint32_t offset; /* Offset of field in protocol header, in bytes. */
219 	enum mlx5_modification_field id;
220 };
221 
222 struct field_modify_info modify_eth[] = {
223 	{4,  0, MLX5_MODI_OUT_DMAC_47_16},
224 	{2,  4, MLX5_MODI_OUT_DMAC_15_0},
225 	{4,  6, MLX5_MODI_OUT_SMAC_47_16},
226 	{2, 10, MLX5_MODI_OUT_SMAC_15_0},
227 	{0, 0, 0},
228 };
229 
230 struct field_modify_info modify_vlan_out_first_vid[] = {
231 	/* Size in bits !!! */
232 	{12, 0, MLX5_MODI_OUT_FIRST_VID},
233 	{0, 0, 0},
234 };
235 
236 struct field_modify_info modify_ipv4[] = {
237 	{1,  1, MLX5_MODI_OUT_IP_DSCP},
238 	{1,  8, MLX5_MODI_OUT_IPV4_TTL},
239 	{4, 12, MLX5_MODI_OUT_SIPV4},
240 	{4, 16, MLX5_MODI_OUT_DIPV4},
241 	{0, 0, 0},
242 };
243 
244 struct field_modify_info modify_ipv6[] = {
245 	{1,  0, MLX5_MODI_OUT_IP_DSCP},
246 	{1,  7, MLX5_MODI_OUT_IPV6_HOPLIMIT},
247 	{4,  8, MLX5_MODI_OUT_SIPV6_127_96},
248 	{4, 12, MLX5_MODI_OUT_SIPV6_95_64},
249 	{4, 16, MLX5_MODI_OUT_SIPV6_63_32},
250 	{4, 20, MLX5_MODI_OUT_SIPV6_31_0},
251 	{4, 24, MLX5_MODI_OUT_DIPV6_127_96},
252 	{4, 28, MLX5_MODI_OUT_DIPV6_95_64},
253 	{4, 32, MLX5_MODI_OUT_DIPV6_63_32},
254 	{4, 36, MLX5_MODI_OUT_DIPV6_31_0},
255 	{0, 0, 0},
256 };
257 
258 struct field_modify_info modify_udp[] = {
259 	{2, 0, MLX5_MODI_OUT_UDP_SPORT},
260 	{2, 2, MLX5_MODI_OUT_UDP_DPORT},
261 	{0, 0, 0},
262 };
263 
264 struct field_modify_info modify_tcp[] = {
265 	{2, 0, MLX5_MODI_OUT_TCP_SPORT},
266 	{2, 2, MLX5_MODI_OUT_TCP_DPORT},
267 	{4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM},
268 	{4, 8, MLX5_MODI_OUT_TCP_ACK_NUM},
269 	{0, 0, 0},
270 };
271 
272 static const struct rte_flow_item *
273 mlx5_flow_find_tunnel_item(const struct rte_flow_item *item)
274 {
275 	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
276 		switch (item->type) {
277 		default:
278 			break;
279 		case RTE_FLOW_ITEM_TYPE_VXLAN:
280 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
281 		case RTE_FLOW_ITEM_TYPE_GRE:
282 		case RTE_FLOW_ITEM_TYPE_MPLS:
283 		case RTE_FLOW_ITEM_TYPE_NVGRE:
284 		case RTE_FLOW_ITEM_TYPE_GENEVE:
285 			return item;
286 		case RTE_FLOW_ITEM_TYPE_IPV4:
287 		case RTE_FLOW_ITEM_TYPE_IPV6:
288 			if (item[1].type == RTE_FLOW_ITEM_TYPE_IPV4 ||
289 			    item[1].type == RTE_FLOW_ITEM_TYPE_IPV6)
290 				return item;
291 			break;
292 		}
293 	}
294 	return NULL;
295 }
296 
297 static void
298 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused,
299 			  uint8_t next_protocol, uint64_t *item_flags,
300 			  int *tunnel)
301 {
302 	MLX5_ASSERT(item->type == RTE_FLOW_ITEM_TYPE_IPV4 ||
303 		    item->type == RTE_FLOW_ITEM_TYPE_IPV6);
304 	if (next_protocol == IPPROTO_IPIP) {
305 		*item_flags |= MLX5_FLOW_LAYER_IPIP;
306 		*tunnel = 1;
307 	}
308 	if (next_protocol == IPPROTO_IPV6) {
309 		*item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP;
310 		*tunnel = 1;
311 	}
312 }
313 
314 static inline struct mlx5_hlist *
315 flow_dv_hlist_prepare(struct mlx5_dev_ctx_shared *sh, struct mlx5_hlist **phl,
316 		     const char *name, uint32_t size, bool direct_key,
317 		     bool lcores_share, void *ctx,
318 		     mlx5_list_create_cb cb_create,
319 		     mlx5_list_match_cb cb_match,
320 		     mlx5_list_remove_cb cb_remove,
321 		     mlx5_list_clone_cb cb_clone,
322 		     mlx5_list_clone_free_cb cb_clone_free)
323 {
324 	struct mlx5_hlist *hl;
325 	struct mlx5_hlist *expected = NULL;
326 	char s[MLX5_NAME_SIZE];
327 
328 	hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST);
329 	if (likely(hl))
330 		return hl;
331 	snprintf(s, sizeof(s), "%s_%s", sh->ibdev_name, name);
332 	hl = mlx5_hlist_create(s, size, direct_key, lcores_share,
333 			ctx, cb_create, cb_match, cb_remove, cb_clone,
334 			cb_clone_free);
335 	if (!hl) {
336 		DRV_LOG(ERR, "%s hash creation failed", name);
337 		rte_errno = ENOMEM;
338 		return NULL;
339 	}
340 	if (!__atomic_compare_exchange_n(phl, &expected, hl, false,
341 					 __ATOMIC_SEQ_CST,
342 					 __ATOMIC_SEQ_CST)) {
343 		mlx5_hlist_destroy(hl);
344 		hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST);
345 	}
346 	return hl;
347 }
348 
349 /* Update VLAN's VID/PCP based on input rte_flow_action.
350  *
351  * @param[in] action
352  *   Pointer to struct rte_flow_action.
353  * @param[out] vlan
354  *   Pointer to struct rte_vlan_hdr.
355  */
356 static void
357 mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action,
358 			 struct rte_vlan_hdr *vlan)
359 {
360 	uint16_t vlan_tci;
361 	if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) {
362 		vlan_tci =
363 		    ((const struct rte_flow_action_of_set_vlan_pcp *)
364 					       action->conf)->vlan_pcp;
365 		vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT;
366 		vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
367 		vlan->vlan_tci |= vlan_tci;
368 	} else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) {
369 		vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
370 		vlan->vlan_tci |= rte_be_to_cpu_16
371 		    (((const struct rte_flow_action_of_set_vlan_vid *)
372 					     action->conf)->vlan_vid);
373 	}
374 }
375 
376 /**
377  * Fetch 1, 2, 3 or 4 byte field from the byte array
378  * and return as unsigned integer in host-endian format.
379  *
380  * @param[in] data
381  *   Pointer to data array.
382  * @param[in] size
383  *   Size of field to extract.
384  *
385  * @return
386  *   converted field in host endian format.
387  */
388 static inline uint32_t
389 flow_dv_fetch_field(const uint8_t *data, uint32_t size)
390 {
391 	uint32_t ret;
392 
393 	switch (size) {
394 	case 1:
395 		ret = *data;
396 		break;
397 	case 2:
398 		ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);
399 		break;
400 	case 3:
401 		ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);
402 		ret = (ret << 8) | *(data + sizeof(uint16_t));
403 		break;
404 	case 4:
405 		ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data);
406 		break;
407 	default:
408 		MLX5_ASSERT(false);
409 		ret = 0;
410 		break;
411 	}
412 	return ret;
413 }
414 
415 /**
416  * Convert modify-header action to DV specification.
417  *
418  * Data length of each action is determined by provided field description
419  * and the item mask. Data bit offset and width of each action is determined
420  * by provided item mask.
421  *
422  * @param[in] item
423  *   Pointer to item specification.
424  * @param[in] field
425  *   Pointer to field modification information.
426  *     For MLX5_MODIFICATION_TYPE_SET specifies destination field.
427  *     For MLX5_MODIFICATION_TYPE_ADD specifies destination field.
428  *     For MLX5_MODIFICATION_TYPE_COPY specifies source field.
429  * @param[in] dcopy
430  *   Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type.
431  *   Negative offset value sets the same offset as source offset.
432  *   size field is ignored, value is taken from source field.
433  * @param[in,out] resource
434  *   Pointer to the modify-header resource.
435  * @param[in] type
436  *   Type of modification.
437  * @param[out] error
438  *   Pointer to the error structure.
439  *
440  * @return
441  *   0 on success, a negative errno value otherwise and rte_errno is set.
442  */
443 static int
444 flow_dv_convert_modify_action(struct rte_flow_item *item,
445 			      struct field_modify_info *field,
446 			      struct field_modify_info *dcopy,
447 			      struct mlx5_flow_dv_modify_hdr_resource *resource,
448 			      uint32_t type, struct rte_flow_error *error)
449 {
450 	uint32_t i = resource->actions_num;
451 	struct mlx5_modification_cmd *actions = resource->actions;
452 	uint32_t carry_b = 0;
453 
454 	/*
455 	 * The item and mask are provided in big-endian format.
456 	 * The fields should be presented as in big-endian format either.
457 	 * Mask must be always present, it defines the actual field width.
458 	 */
459 	MLX5_ASSERT(item->mask);
460 	MLX5_ASSERT(field->size);
461 	do {
462 		uint32_t size_b;
463 		uint32_t off_b;
464 		uint32_t mask;
465 		uint32_t data;
466 		bool next_field = true;
467 		bool next_dcopy = true;
468 
469 		if (i >= MLX5_MAX_MODIFY_NUM)
470 			return rte_flow_error_set(error, EINVAL,
471 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
472 				 "too many items to modify");
473 		/* Fetch variable byte size mask from the array. */
474 		mask = flow_dv_fetch_field((const uint8_t *)item->mask +
475 					   field->offset, field->size);
476 		if (!mask) {
477 			++field;
478 			continue;
479 		}
480 		/* Deduce actual data width in bits from mask value. */
481 		off_b = rte_bsf32(mask) + carry_b;
482 		size_b = sizeof(uint32_t) * CHAR_BIT -
483 			 off_b - __builtin_clz(mask);
484 		MLX5_ASSERT(size_b);
485 		actions[i] = (struct mlx5_modification_cmd) {
486 			.action_type = type,
487 			.field = field->id,
488 			.offset = off_b,
489 			.length = (size_b == sizeof(uint32_t) * CHAR_BIT) ?
490 				0 : size_b,
491 		};
492 		if (type == MLX5_MODIFICATION_TYPE_COPY) {
493 			MLX5_ASSERT(dcopy);
494 			actions[i].dst_field = dcopy->id;
495 			actions[i].dst_offset =
496 				(int)dcopy->offset < 0 ? off_b : dcopy->offset;
497 			/* Convert entire record to big-endian format. */
498 			actions[i].data1 = rte_cpu_to_be_32(actions[i].data1);
499 			/*
500 			 * Destination field overflow. Copy leftovers of
501 			 * a source field to the next destination field.
502 			 */
503 			carry_b = 0;
504 			if ((size_b > dcopy->size * CHAR_BIT - dcopy->offset) &&
505 			    dcopy->size != 0) {
506 				actions[i].length =
507 					dcopy->size * CHAR_BIT - dcopy->offset;
508 				carry_b = actions[i].length;
509 				next_field = false;
510 			}
511 			/*
512 			 * Not enough bits in a source filed to fill a
513 			 * destination field. Switch to the next source.
514 			 */
515 			if ((size_b < dcopy->size * CHAR_BIT - dcopy->offset) &&
516 			    (size_b == field->size * CHAR_BIT - off_b)) {
517 				actions[i].length =
518 					field->size * CHAR_BIT - off_b;
519 				dcopy->offset += actions[i].length;
520 				next_dcopy = false;
521 			}
522 			if (next_dcopy)
523 				++dcopy;
524 		} else {
525 			MLX5_ASSERT(item->spec);
526 			data = flow_dv_fetch_field((const uint8_t *)item->spec +
527 						   field->offset, field->size);
528 			/* Shift out the trailing masked bits from data. */
529 			data = (data & mask) >> off_b;
530 			actions[i].data1 = rte_cpu_to_be_32(data);
531 		}
532 		/* Convert entire record to expected big-endian format. */
533 		actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
534 		if (next_field)
535 			++field;
536 		++i;
537 	} while (field->size);
538 	if (resource->actions_num == i)
539 		return rte_flow_error_set(error, EINVAL,
540 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
541 					  "invalid modification flow item");
542 	resource->actions_num = i;
543 	return 0;
544 }
545 
546 /**
547  * Convert modify-header set IPv4 address action to DV specification.
548  *
549  * @param[in,out] resource
550  *   Pointer to the modify-header resource.
551  * @param[in] action
552  *   Pointer to action specification.
553  * @param[out] error
554  *   Pointer to the error structure.
555  *
556  * @return
557  *   0 on success, a negative errno value otherwise and rte_errno is set.
558  */
559 static int
560 flow_dv_convert_action_modify_ipv4
561 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
562 			 const struct rte_flow_action *action,
563 			 struct rte_flow_error *error)
564 {
565 	const struct rte_flow_action_set_ipv4 *conf =
566 		(const struct rte_flow_action_set_ipv4 *)(action->conf);
567 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
568 	struct rte_flow_item_ipv4 ipv4;
569 	struct rte_flow_item_ipv4 ipv4_mask;
570 
571 	memset(&ipv4, 0, sizeof(ipv4));
572 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
573 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) {
574 		ipv4.hdr.src_addr = conf->ipv4_addr;
575 		ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr;
576 	} else {
577 		ipv4.hdr.dst_addr = conf->ipv4_addr;
578 		ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr;
579 	}
580 	item.spec = &ipv4;
581 	item.mask = &ipv4_mask;
582 	return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
583 					     MLX5_MODIFICATION_TYPE_SET, error);
584 }
585 
586 /**
587  * Convert modify-header set IPv6 address 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_ipv6
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_set_ipv6 *conf =
606 		(const struct rte_flow_action_set_ipv6 *)(action->conf);
607 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
608 	struct rte_flow_item_ipv6 ipv6;
609 	struct rte_flow_item_ipv6 ipv6_mask;
610 
611 	memset(&ipv6, 0, sizeof(ipv6));
612 	memset(&ipv6_mask, 0, sizeof(ipv6_mask));
613 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) {
614 		memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr,
615 		       sizeof(ipv6.hdr.src_addr));
616 		memcpy(&ipv6_mask.hdr.src_addr,
617 		       &rte_flow_item_ipv6_mask.hdr.src_addr,
618 		       sizeof(ipv6.hdr.src_addr));
619 	} else {
620 		memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr,
621 		       sizeof(ipv6.hdr.dst_addr));
622 		memcpy(&ipv6_mask.hdr.dst_addr,
623 		       &rte_flow_item_ipv6_mask.hdr.dst_addr,
624 		       sizeof(ipv6.hdr.dst_addr));
625 	}
626 	item.spec = &ipv6;
627 	item.mask = &ipv6_mask;
628 	return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
629 					     MLX5_MODIFICATION_TYPE_SET, error);
630 }
631 
632 /**
633  * Convert modify-header set MAC address action to DV specification.
634  *
635  * @param[in,out] resource
636  *   Pointer to the modify-header resource.
637  * @param[in] action
638  *   Pointer to action specification.
639  * @param[out] error
640  *   Pointer to the error structure.
641  *
642  * @return
643  *   0 on success, a negative errno value otherwise and rte_errno is set.
644  */
645 static int
646 flow_dv_convert_action_modify_mac
647 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
648 			 const struct rte_flow_action *action,
649 			 struct rte_flow_error *error)
650 {
651 	const struct rte_flow_action_set_mac *conf =
652 		(const struct rte_flow_action_set_mac *)(action->conf);
653 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH };
654 	struct rte_flow_item_eth eth;
655 	struct rte_flow_item_eth eth_mask;
656 
657 	memset(&eth, 0, sizeof(eth));
658 	memset(&eth_mask, 0, sizeof(eth_mask));
659 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) {
660 		memcpy(&eth.src.addr_bytes, &conf->mac_addr,
661 		       sizeof(eth.src.addr_bytes));
662 		memcpy(&eth_mask.src.addr_bytes,
663 		       &rte_flow_item_eth_mask.src.addr_bytes,
664 		       sizeof(eth_mask.src.addr_bytes));
665 	} else {
666 		memcpy(&eth.dst.addr_bytes, &conf->mac_addr,
667 		       sizeof(eth.dst.addr_bytes));
668 		memcpy(&eth_mask.dst.addr_bytes,
669 		       &rte_flow_item_eth_mask.dst.addr_bytes,
670 		       sizeof(eth_mask.dst.addr_bytes));
671 	}
672 	item.spec = &eth;
673 	item.mask = &eth_mask;
674 	return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource,
675 					     MLX5_MODIFICATION_TYPE_SET, error);
676 }
677 
678 /**
679  * Convert modify-header set VLAN VID action to DV specification.
680  *
681  * @param[in,out] resource
682  *   Pointer to the modify-header resource.
683  * @param[in] action
684  *   Pointer to action specification.
685  * @param[out] error
686  *   Pointer to the error structure.
687  *
688  * @return
689  *   0 on success, a negative errno value otherwise and rte_errno is set.
690  */
691 static int
692 flow_dv_convert_action_modify_vlan_vid
693 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
694 			 const struct rte_flow_action *action,
695 			 struct rte_flow_error *error)
696 {
697 	const struct rte_flow_action_of_set_vlan_vid *conf =
698 		(const struct rte_flow_action_of_set_vlan_vid *)(action->conf);
699 	int i = resource->actions_num;
700 	struct mlx5_modification_cmd *actions = resource->actions;
701 	struct field_modify_info *field = modify_vlan_out_first_vid;
702 
703 	if (i >= MLX5_MAX_MODIFY_NUM)
704 		return rte_flow_error_set(error, EINVAL,
705 			 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
706 			 "too many items to modify");
707 	actions[i] = (struct mlx5_modification_cmd) {
708 		.action_type = MLX5_MODIFICATION_TYPE_SET,
709 		.field = field->id,
710 		.length = field->size,
711 		.offset = field->offset,
712 	};
713 	actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
714 	actions[i].data1 = conf->vlan_vid;
715 	actions[i].data1 = actions[i].data1 << 16;
716 	resource->actions_num = ++i;
717 	return 0;
718 }
719 
720 /**
721  * Convert modify-header set TP action to DV specification.
722  *
723  * @param[in,out] resource
724  *   Pointer to the modify-header resource.
725  * @param[in] action
726  *   Pointer to action specification.
727  * @param[in] items
728  *   Pointer to rte_flow_item objects list.
729  * @param[in] attr
730  *   Pointer to flow attributes structure.
731  * @param[in] dev_flow
732  *   Pointer to the sub flow.
733  * @param[in] tunnel_decap
734  *   Whether action is after tunnel decapsulation.
735  * @param[out] error
736  *   Pointer to the error structure.
737  *
738  * @return
739  *   0 on success, a negative errno value otherwise and rte_errno is set.
740  */
741 static int
742 flow_dv_convert_action_modify_tp
743 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
744 			 const struct rte_flow_action *action,
745 			 const struct rte_flow_item *items,
746 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
747 			 bool tunnel_decap, struct rte_flow_error *error)
748 {
749 	const struct rte_flow_action_set_tp *conf =
750 		(const struct rte_flow_action_set_tp *)(action->conf);
751 	struct rte_flow_item item;
752 	struct rte_flow_item_udp udp;
753 	struct rte_flow_item_udp udp_mask;
754 	struct rte_flow_item_tcp tcp;
755 	struct rte_flow_item_tcp tcp_mask;
756 	struct field_modify_info *field;
757 
758 	if (!attr->valid)
759 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
760 	if (attr->udp) {
761 		memset(&udp, 0, sizeof(udp));
762 		memset(&udp_mask, 0, sizeof(udp_mask));
763 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
764 			udp.hdr.src_port = conf->port;
765 			udp_mask.hdr.src_port =
766 					rte_flow_item_udp_mask.hdr.src_port;
767 		} else {
768 			udp.hdr.dst_port = conf->port;
769 			udp_mask.hdr.dst_port =
770 					rte_flow_item_udp_mask.hdr.dst_port;
771 		}
772 		item.type = RTE_FLOW_ITEM_TYPE_UDP;
773 		item.spec = &udp;
774 		item.mask = &udp_mask;
775 		field = modify_udp;
776 	} else {
777 		MLX5_ASSERT(attr->tcp);
778 		memset(&tcp, 0, sizeof(tcp));
779 		memset(&tcp_mask, 0, sizeof(tcp_mask));
780 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
781 			tcp.hdr.src_port = conf->port;
782 			tcp_mask.hdr.src_port =
783 					rte_flow_item_tcp_mask.hdr.src_port;
784 		} else {
785 			tcp.hdr.dst_port = conf->port;
786 			tcp_mask.hdr.dst_port =
787 					rte_flow_item_tcp_mask.hdr.dst_port;
788 		}
789 		item.type = RTE_FLOW_ITEM_TYPE_TCP;
790 		item.spec = &tcp;
791 		item.mask = &tcp_mask;
792 		field = modify_tcp;
793 	}
794 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
795 					     MLX5_MODIFICATION_TYPE_SET, error);
796 }
797 
798 /**
799  * Convert modify-header set TTL action to DV specification.
800  *
801  * @param[in,out] resource
802  *   Pointer to the modify-header resource.
803  * @param[in] action
804  *   Pointer to action specification.
805  * @param[in] items
806  *   Pointer to rte_flow_item objects list.
807  * @param[in] attr
808  *   Pointer to flow attributes structure.
809  * @param[in] dev_flow
810  *   Pointer to the sub flow.
811  * @param[in] tunnel_decap
812  *   Whether action is after tunnel decapsulation.
813  * @param[out] error
814  *   Pointer to the error structure.
815  *
816  * @return
817  *   0 on success, a negative errno value otherwise and rte_errno is set.
818  */
819 static int
820 flow_dv_convert_action_modify_ttl
821 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
822 			 const struct rte_flow_action *action,
823 			 const struct rte_flow_item *items,
824 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
825 			 bool tunnel_decap, struct rte_flow_error *error)
826 {
827 	const struct rte_flow_action_set_ttl *conf =
828 		(const struct rte_flow_action_set_ttl *)(action->conf);
829 	struct rte_flow_item item;
830 	struct rte_flow_item_ipv4 ipv4;
831 	struct rte_flow_item_ipv4 ipv4_mask;
832 	struct rte_flow_item_ipv6 ipv6;
833 	struct rte_flow_item_ipv6 ipv6_mask;
834 	struct field_modify_info *field;
835 
836 	if (!attr->valid)
837 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
838 	if (attr->ipv4) {
839 		memset(&ipv4, 0, sizeof(ipv4));
840 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
841 		ipv4.hdr.time_to_live = conf->ttl_value;
842 		ipv4_mask.hdr.time_to_live = 0xFF;
843 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
844 		item.spec = &ipv4;
845 		item.mask = &ipv4_mask;
846 		field = modify_ipv4;
847 	} else {
848 		MLX5_ASSERT(attr->ipv6);
849 		memset(&ipv6, 0, sizeof(ipv6));
850 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
851 		ipv6.hdr.hop_limits = conf->ttl_value;
852 		ipv6_mask.hdr.hop_limits = 0xFF;
853 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
854 		item.spec = &ipv6;
855 		item.mask = &ipv6_mask;
856 		field = modify_ipv6;
857 	}
858 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
859 					     MLX5_MODIFICATION_TYPE_SET, error);
860 }
861 
862 /**
863  * Convert modify-header decrement TTL action to DV specification.
864  *
865  * @param[in,out] resource
866  *   Pointer to the modify-header resource.
867  * @param[in] action
868  *   Pointer to action specification.
869  * @param[in] items
870  *   Pointer to rte_flow_item objects list.
871  * @param[in] attr
872  *   Pointer to flow attributes structure.
873  * @param[in] dev_flow
874  *   Pointer to the sub flow.
875  * @param[in] tunnel_decap
876  *   Whether action is after tunnel decapsulation.
877  * @param[out] error
878  *   Pointer to the error structure.
879  *
880  * @return
881  *   0 on success, a negative errno value otherwise and rte_errno is set.
882  */
883 static int
884 flow_dv_convert_action_modify_dec_ttl
885 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
886 			 const struct rte_flow_item *items,
887 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
888 			 bool tunnel_decap, struct rte_flow_error *error)
889 {
890 	struct rte_flow_item item;
891 	struct rte_flow_item_ipv4 ipv4;
892 	struct rte_flow_item_ipv4 ipv4_mask;
893 	struct rte_flow_item_ipv6 ipv6;
894 	struct rte_flow_item_ipv6 ipv6_mask;
895 	struct field_modify_info *field;
896 
897 	if (!attr->valid)
898 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
899 	if (attr->ipv4) {
900 		memset(&ipv4, 0, sizeof(ipv4));
901 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
902 		ipv4.hdr.time_to_live = 0xFF;
903 		ipv4_mask.hdr.time_to_live = 0xFF;
904 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
905 		item.spec = &ipv4;
906 		item.mask = &ipv4_mask;
907 		field = modify_ipv4;
908 	} else {
909 		MLX5_ASSERT(attr->ipv6);
910 		memset(&ipv6, 0, sizeof(ipv6));
911 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
912 		ipv6.hdr.hop_limits = 0xFF;
913 		ipv6_mask.hdr.hop_limits = 0xFF;
914 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
915 		item.spec = &ipv6;
916 		item.mask = &ipv6_mask;
917 		field = modify_ipv6;
918 	}
919 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
920 					     MLX5_MODIFICATION_TYPE_ADD, error);
921 }
922 
923 /**
924  * Convert modify-header increment/decrement TCP Sequence number
925  * to DV specification.
926  *
927  * @param[in,out] resource
928  *   Pointer to the modify-header resource.
929  * @param[in] action
930  *   Pointer to action specification.
931  * @param[out] error
932  *   Pointer to the error structure.
933  *
934  * @return
935  *   0 on success, a negative errno value otherwise and rte_errno is set.
936  */
937 static int
938 flow_dv_convert_action_modify_tcp_seq
939 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
940 			 const struct rte_flow_action *action,
941 			 struct rte_flow_error *error)
942 {
943 	const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
944 	uint64_t value = rte_be_to_cpu_32(*conf);
945 	struct rte_flow_item item;
946 	struct rte_flow_item_tcp tcp;
947 	struct rte_flow_item_tcp tcp_mask;
948 
949 	memset(&tcp, 0, sizeof(tcp));
950 	memset(&tcp_mask, 0, sizeof(tcp_mask));
951 	if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ)
952 		/*
953 		 * The HW has no decrement operation, only increment operation.
954 		 * To simulate decrement X from Y using increment operation
955 		 * we need to add UINT32_MAX X times to Y.
956 		 * Each adding of UINT32_MAX decrements Y by 1.
957 		 */
958 		value *= UINT32_MAX;
959 	tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value);
960 	tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX);
961 	item.type = RTE_FLOW_ITEM_TYPE_TCP;
962 	item.spec = &tcp;
963 	item.mask = &tcp_mask;
964 	return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
965 					     MLX5_MODIFICATION_TYPE_ADD, error);
966 }
967 
968 /**
969  * Convert modify-header increment/decrement TCP Acknowledgment number
970  * to DV specification.
971  *
972  * @param[in,out] resource
973  *   Pointer to the modify-header resource.
974  * @param[in] action
975  *   Pointer to action specification.
976  * @param[out] error
977  *   Pointer to the error structure.
978  *
979  * @return
980  *   0 on success, a negative errno value otherwise and rte_errno is set.
981  */
982 static int
983 flow_dv_convert_action_modify_tcp_ack
984 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
985 			 const struct rte_flow_action *action,
986 			 struct rte_flow_error *error)
987 {
988 	const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
989 	uint64_t value = rte_be_to_cpu_32(*conf);
990 	struct rte_flow_item item;
991 	struct rte_flow_item_tcp tcp;
992 	struct rte_flow_item_tcp tcp_mask;
993 
994 	memset(&tcp, 0, sizeof(tcp));
995 	memset(&tcp_mask, 0, sizeof(tcp_mask));
996 	if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK)
997 		/*
998 		 * The HW has no decrement operation, only increment operation.
999 		 * To simulate decrement X from Y using increment operation
1000 		 * we need to add UINT32_MAX X times to Y.
1001 		 * Each adding of UINT32_MAX decrements Y by 1.
1002 		 */
1003 		value *= UINT32_MAX;
1004 	tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value);
1005 	tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX);
1006 	item.type = RTE_FLOW_ITEM_TYPE_TCP;
1007 	item.spec = &tcp;
1008 	item.mask = &tcp_mask;
1009 	return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
1010 					     MLX5_MODIFICATION_TYPE_ADD, error);
1011 }
1012 
1013 static enum mlx5_modification_field reg_to_field[] = {
1014 	[REG_NON] = MLX5_MODI_OUT_NONE,
1015 	[REG_A] = MLX5_MODI_META_DATA_REG_A,
1016 	[REG_B] = MLX5_MODI_META_DATA_REG_B,
1017 	[REG_C_0] = MLX5_MODI_META_REG_C_0,
1018 	[REG_C_1] = MLX5_MODI_META_REG_C_1,
1019 	[REG_C_2] = MLX5_MODI_META_REG_C_2,
1020 	[REG_C_3] = MLX5_MODI_META_REG_C_3,
1021 	[REG_C_4] = MLX5_MODI_META_REG_C_4,
1022 	[REG_C_5] = MLX5_MODI_META_REG_C_5,
1023 	[REG_C_6] = MLX5_MODI_META_REG_C_6,
1024 	[REG_C_7] = MLX5_MODI_META_REG_C_7,
1025 };
1026 
1027 /**
1028  * Convert register set to DV specification.
1029  *
1030  * @param[in,out] resource
1031  *   Pointer to the modify-header resource.
1032  * @param[in] action
1033  *   Pointer to action specification.
1034  * @param[out] error
1035  *   Pointer to the error structure.
1036  *
1037  * @return
1038  *   0 on success, a negative errno value otherwise and rte_errno is set.
1039  */
1040 static int
1041 flow_dv_convert_action_set_reg
1042 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1043 			 const struct rte_flow_action *action,
1044 			 struct rte_flow_error *error)
1045 {
1046 	const struct mlx5_rte_flow_action_set_tag *conf = action->conf;
1047 	struct mlx5_modification_cmd *actions = resource->actions;
1048 	uint32_t i = resource->actions_num;
1049 
1050 	if (i >= MLX5_MAX_MODIFY_NUM)
1051 		return rte_flow_error_set(error, EINVAL,
1052 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1053 					  "too many items to modify");
1054 	MLX5_ASSERT(conf->id != REG_NON);
1055 	MLX5_ASSERT(conf->id < (enum modify_reg)RTE_DIM(reg_to_field));
1056 	actions[i] = (struct mlx5_modification_cmd) {
1057 		.action_type = MLX5_MODIFICATION_TYPE_SET,
1058 		.field = reg_to_field[conf->id],
1059 		.offset = conf->offset,
1060 		.length = conf->length,
1061 	};
1062 	actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
1063 	actions[i].data1 = rte_cpu_to_be_32(conf->data);
1064 	++i;
1065 	resource->actions_num = i;
1066 	return 0;
1067 }
1068 
1069 /**
1070  * Convert SET_TAG action to DV specification.
1071  *
1072  * @param[in] dev
1073  *   Pointer to the rte_eth_dev structure.
1074  * @param[in,out] resource
1075  *   Pointer to the modify-header resource.
1076  * @param[in] conf
1077  *   Pointer to action specification.
1078  * @param[out] error
1079  *   Pointer to the error structure.
1080  *
1081  * @return
1082  *   0 on success, a negative errno value otherwise and rte_errno is set.
1083  */
1084 static int
1085 flow_dv_convert_action_set_tag
1086 			(struct rte_eth_dev *dev,
1087 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1088 			 const struct rte_flow_action_set_tag *conf,
1089 			 struct rte_flow_error *error)
1090 {
1091 	rte_be32_t data = rte_cpu_to_be_32(conf->data);
1092 	rte_be32_t mask = rte_cpu_to_be_32(conf->mask);
1093 	struct rte_flow_item item = {
1094 		.spec = &data,
1095 		.mask = &mask,
1096 	};
1097 	struct field_modify_info reg_c_x[] = {
1098 		[1] = {0, 0, 0},
1099 	};
1100 	enum mlx5_modification_field reg_type;
1101 	int ret;
1102 
1103 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
1104 	if (ret < 0)
1105 		return ret;
1106 	MLX5_ASSERT(ret != REG_NON);
1107 	MLX5_ASSERT((unsigned int)ret < RTE_DIM(reg_to_field));
1108 	reg_type = reg_to_field[ret];
1109 	MLX5_ASSERT(reg_type > 0);
1110 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_type};
1111 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1112 					     MLX5_MODIFICATION_TYPE_SET, error);
1113 }
1114 
1115 /**
1116  * Convert internal COPY_REG action to DV specification.
1117  *
1118  * @param[in] dev
1119  *   Pointer to the rte_eth_dev structure.
1120  * @param[in,out] res
1121  *   Pointer to the modify-header resource.
1122  * @param[in] action
1123  *   Pointer to action specification.
1124  * @param[out] error
1125  *   Pointer to the error structure.
1126  *
1127  * @return
1128  *   0 on success, a negative errno value otherwise and rte_errno is set.
1129  */
1130 static int
1131 flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev,
1132 				 struct mlx5_flow_dv_modify_hdr_resource *res,
1133 				 const struct rte_flow_action *action,
1134 				 struct rte_flow_error *error)
1135 {
1136 	const struct mlx5_flow_action_copy_mreg *conf = action->conf;
1137 	rte_be32_t mask = RTE_BE32(UINT32_MAX);
1138 	struct rte_flow_item item = {
1139 		.spec = NULL,
1140 		.mask = &mask,
1141 	};
1142 	struct field_modify_info reg_src[] = {
1143 		{4, 0, reg_to_field[conf->src]},
1144 		{0, 0, 0},
1145 	};
1146 	struct field_modify_info reg_dst = {
1147 		.offset = 0,
1148 		.id = reg_to_field[conf->dst],
1149 	};
1150 	/* Adjust reg_c[0] usage according to reported mask. */
1151 	if (conf->dst == REG_C_0 || conf->src == REG_C_0) {
1152 		struct mlx5_priv *priv = dev->data->dev_private;
1153 		uint32_t reg_c0 = priv->sh->dv_regc0_mask;
1154 
1155 		MLX5_ASSERT(reg_c0);
1156 		MLX5_ASSERT(priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY);
1157 		if (conf->dst == REG_C_0) {
1158 			/* Copy to reg_c[0], within mask only. */
1159 			reg_dst.offset = rte_bsf32(reg_c0);
1160 			mask = rte_cpu_to_be_32(reg_c0 >> reg_dst.offset);
1161 		} else {
1162 			reg_dst.offset = 0;
1163 			mask = rte_cpu_to_be_32(reg_c0);
1164 		}
1165 	}
1166 	return flow_dv_convert_modify_action(&item,
1167 					     reg_src, &reg_dst, res,
1168 					     MLX5_MODIFICATION_TYPE_COPY,
1169 					     error);
1170 }
1171 
1172 /**
1173  * Convert MARK action to DV specification. This routine is used
1174  * in extensive metadata only and requires metadata register to be
1175  * handled. In legacy mode hardware tag resource is engaged.
1176  *
1177  * @param[in] dev
1178  *   Pointer to the rte_eth_dev structure.
1179  * @param[in] conf
1180  *   Pointer to MARK action specification.
1181  * @param[in,out] resource
1182  *   Pointer to the modify-header resource.
1183  * @param[out] error
1184  *   Pointer to the error structure.
1185  *
1186  * @return
1187  *   0 on success, a negative errno value otherwise and rte_errno is set.
1188  */
1189 static int
1190 flow_dv_convert_action_mark(struct rte_eth_dev *dev,
1191 			    const struct rte_flow_action_mark *conf,
1192 			    struct mlx5_flow_dv_modify_hdr_resource *resource,
1193 			    struct rte_flow_error *error)
1194 {
1195 	struct mlx5_priv *priv = dev->data->dev_private;
1196 	rte_be32_t mask = rte_cpu_to_be_32(MLX5_FLOW_MARK_MASK &
1197 					   priv->sh->dv_mark_mask);
1198 	rte_be32_t data = rte_cpu_to_be_32(conf->id) & mask;
1199 	struct rte_flow_item item = {
1200 		.spec = &data,
1201 		.mask = &mask,
1202 	};
1203 	struct field_modify_info reg_c_x[] = {
1204 		[1] = {0, 0, 0},
1205 	};
1206 	int reg;
1207 
1208 	if (!mask)
1209 		return rte_flow_error_set(error, EINVAL,
1210 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1211 					  NULL, "zero mark action mask");
1212 	reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
1213 	if (reg < 0)
1214 		return reg;
1215 	MLX5_ASSERT(reg > 0);
1216 	if (reg == REG_C_0) {
1217 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1218 		uint32_t shl_c0 = rte_bsf32(msk_c0);
1219 
1220 		data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0);
1221 		mask = rte_cpu_to_be_32(mask) & msk_c0;
1222 		mask = rte_cpu_to_be_32(mask << shl_c0);
1223 	}
1224 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1225 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1226 					     MLX5_MODIFICATION_TYPE_SET, error);
1227 }
1228 
1229 /**
1230  * Get metadata register index for specified steering domain.
1231  *
1232  * @param[in] dev
1233  *   Pointer to the rte_eth_dev structure.
1234  * @param[in] attr
1235  *   Attributes of flow to determine steering domain.
1236  * @param[out] error
1237  *   Pointer to the error structure.
1238  *
1239  * @return
1240  *   positive index on success, a negative errno value otherwise
1241  *   and rte_errno is set.
1242  */
1243 static enum modify_reg
1244 flow_dv_get_metadata_reg(struct rte_eth_dev *dev,
1245 			 const struct rte_flow_attr *attr,
1246 			 struct rte_flow_error *error)
1247 {
1248 	int reg =
1249 		mlx5_flow_get_reg_id(dev, attr->transfer ?
1250 					  MLX5_METADATA_FDB :
1251 					    attr->egress ?
1252 					    MLX5_METADATA_TX :
1253 					    MLX5_METADATA_RX, 0, error);
1254 	if (reg < 0)
1255 		return rte_flow_error_set(error,
1256 					  ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
1257 					  NULL, "unavailable "
1258 					  "metadata register");
1259 	return reg;
1260 }
1261 
1262 /**
1263  * Convert SET_META action to DV specification.
1264  *
1265  * @param[in] dev
1266  *   Pointer to the rte_eth_dev structure.
1267  * @param[in,out] resource
1268  *   Pointer to the modify-header resource.
1269  * @param[in] attr
1270  *   Attributes of flow that includes this item.
1271  * @param[in] conf
1272  *   Pointer to action specification.
1273  * @param[out] error
1274  *   Pointer to the error structure.
1275  *
1276  * @return
1277  *   0 on success, a negative errno value otherwise and rte_errno is set.
1278  */
1279 static int
1280 flow_dv_convert_action_set_meta
1281 			(struct rte_eth_dev *dev,
1282 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1283 			 const struct rte_flow_attr *attr,
1284 			 const struct rte_flow_action_set_meta *conf,
1285 			 struct rte_flow_error *error)
1286 {
1287 	uint32_t mask = rte_cpu_to_be_32(conf->mask);
1288 	uint32_t data = rte_cpu_to_be_32(conf->data) & mask;
1289 	struct rte_flow_item item = {
1290 		.spec = &data,
1291 		.mask = &mask,
1292 	};
1293 	struct field_modify_info reg_c_x[] = {
1294 		[1] = {0, 0, 0},
1295 	};
1296 	int reg = flow_dv_get_metadata_reg(dev, attr, error);
1297 
1298 	if (reg < 0)
1299 		return reg;
1300 	MLX5_ASSERT(reg != REG_NON);
1301 	if (reg == REG_C_0) {
1302 		struct mlx5_priv *priv = dev->data->dev_private;
1303 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1304 		uint32_t shl_c0 = rte_bsf32(msk_c0);
1305 
1306 		data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0);
1307 		mask = rte_cpu_to_be_32(mask) & msk_c0;
1308 		mask = rte_cpu_to_be_32(mask << shl_c0);
1309 	}
1310 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1311 	/* The routine expects parameters in memory as big-endian ones. */
1312 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1313 					     MLX5_MODIFICATION_TYPE_SET, error);
1314 }
1315 
1316 /**
1317  * Convert modify-header set IPv4 DSCP action to DV specification.
1318  *
1319  * @param[in,out] resource
1320  *   Pointer to the modify-header resource.
1321  * @param[in] action
1322  *   Pointer to action specification.
1323  * @param[out] error
1324  *   Pointer to the error structure.
1325  *
1326  * @return
1327  *   0 on success, a negative errno value otherwise and rte_errno is set.
1328  */
1329 static int
1330 flow_dv_convert_action_modify_ipv4_dscp
1331 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1332 			 const struct rte_flow_action *action,
1333 			 struct rte_flow_error *error)
1334 {
1335 	const struct rte_flow_action_set_dscp *conf =
1336 		(const struct rte_flow_action_set_dscp *)(action->conf);
1337 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
1338 	struct rte_flow_item_ipv4 ipv4;
1339 	struct rte_flow_item_ipv4 ipv4_mask;
1340 
1341 	memset(&ipv4, 0, sizeof(ipv4));
1342 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
1343 	ipv4.hdr.type_of_service = conf->dscp;
1344 	ipv4_mask.hdr.type_of_service = RTE_IPV4_HDR_DSCP_MASK >> 2;
1345 	item.spec = &ipv4;
1346 	item.mask = &ipv4_mask;
1347 	return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
1348 					     MLX5_MODIFICATION_TYPE_SET, error);
1349 }
1350 
1351 /**
1352  * Convert modify-header set IPv6 DSCP action to DV specification.
1353  *
1354  * @param[in,out] resource
1355  *   Pointer to the modify-header resource.
1356  * @param[in] action
1357  *   Pointer to action specification.
1358  * @param[out] error
1359  *   Pointer to the error structure.
1360  *
1361  * @return
1362  *   0 on success, a negative errno value otherwise and rte_errno is set.
1363  */
1364 static int
1365 flow_dv_convert_action_modify_ipv6_dscp
1366 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1367 			 const struct rte_flow_action *action,
1368 			 struct rte_flow_error *error)
1369 {
1370 	const struct rte_flow_action_set_dscp *conf =
1371 		(const struct rte_flow_action_set_dscp *)(action->conf);
1372 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
1373 	struct rte_flow_item_ipv6 ipv6;
1374 	struct rte_flow_item_ipv6 ipv6_mask;
1375 
1376 	memset(&ipv6, 0, sizeof(ipv6));
1377 	memset(&ipv6_mask, 0, sizeof(ipv6_mask));
1378 	/*
1379 	 * Even though the DSCP bits offset of IPv6 is not byte aligned,
1380 	 * rdma-core only accept the DSCP bits byte aligned start from
1381 	 * bit 0 to 5 as to be compatible with IPv4. No need to shift the
1382 	 * bits in IPv6 case as rdma-core requires byte aligned value.
1383 	 */
1384 	ipv6.hdr.vtc_flow = conf->dscp;
1385 	ipv6_mask.hdr.vtc_flow = RTE_IPV6_HDR_DSCP_MASK >> 22;
1386 	item.spec = &ipv6;
1387 	item.mask = &ipv6_mask;
1388 	return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
1389 					     MLX5_MODIFICATION_TYPE_SET, error);
1390 }
1391 
1392 static int
1393 mlx5_flow_item_field_width(struct mlx5_priv *priv,
1394 			   enum rte_flow_field_id field)
1395 {
1396 	switch (field) {
1397 	case RTE_FLOW_FIELD_START:
1398 		return 32;
1399 	case RTE_FLOW_FIELD_MAC_DST:
1400 	case RTE_FLOW_FIELD_MAC_SRC:
1401 		return 48;
1402 	case RTE_FLOW_FIELD_VLAN_TYPE:
1403 		return 16;
1404 	case RTE_FLOW_FIELD_VLAN_ID:
1405 		return 12;
1406 	case RTE_FLOW_FIELD_MAC_TYPE:
1407 		return 16;
1408 	case RTE_FLOW_FIELD_IPV4_DSCP:
1409 		return 6;
1410 	case RTE_FLOW_FIELD_IPV4_TTL:
1411 		return 8;
1412 	case RTE_FLOW_FIELD_IPV4_SRC:
1413 	case RTE_FLOW_FIELD_IPV4_DST:
1414 		return 32;
1415 	case RTE_FLOW_FIELD_IPV6_DSCP:
1416 		return 6;
1417 	case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
1418 		return 8;
1419 	case RTE_FLOW_FIELD_IPV6_SRC:
1420 	case RTE_FLOW_FIELD_IPV6_DST:
1421 		return 128;
1422 	case RTE_FLOW_FIELD_TCP_PORT_SRC:
1423 	case RTE_FLOW_FIELD_TCP_PORT_DST:
1424 		return 16;
1425 	case RTE_FLOW_FIELD_TCP_SEQ_NUM:
1426 	case RTE_FLOW_FIELD_TCP_ACK_NUM:
1427 		return 32;
1428 	case RTE_FLOW_FIELD_TCP_FLAGS:
1429 		return 9;
1430 	case RTE_FLOW_FIELD_UDP_PORT_SRC:
1431 	case RTE_FLOW_FIELD_UDP_PORT_DST:
1432 		return 16;
1433 	case RTE_FLOW_FIELD_VXLAN_VNI:
1434 	case RTE_FLOW_FIELD_GENEVE_VNI:
1435 		return 24;
1436 	case RTE_FLOW_FIELD_GTP_TEID:
1437 	case RTE_FLOW_FIELD_TAG:
1438 		return 32;
1439 	case RTE_FLOW_FIELD_MARK:
1440 		return __builtin_popcount(priv->sh->dv_mark_mask);
1441 	case RTE_FLOW_FIELD_META:
1442 		return __builtin_popcount(priv->sh->dv_meta_mask);
1443 	case RTE_FLOW_FIELD_POINTER:
1444 	case RTE_FLOW_FIELD_VALUE:
1445 		return 64;
1446 	default:
1447 		MLX5_ASSERT(false);
1448 	}
1449 	return 0;
1450 }
1451 
1452 static void
1453 mlx5_flow_field_id_to_modify_info
1454 		(const struct rte_flow_action_modify_data *data,
1455 		 struct field_modify_info *info,
1456 		 uint32_t *mask, uint32_t *value,
1457 		 uint32_t width, uint32_t dst_width,
1458 		 uint32_t *shift, struct rte_eth_dev *dev,
1459 		 const struct rte_flow_attr *attr,
1460 		 struct rte_flow_error *error)
1461 {
1462 	struct mlx5_priv *priv = dev->data->dev_private;
1463 	uint32_t idx = 0;
1464 	uint32_t off = 0;
1465 	uint64_t val = 0;
1466 	switch (data->field) {
1467 	case RTE_FLOW_FIELD_START:
1468 		/* not supported yet */
1469 		MLX5_ASSERT(false);
1470 		break;
1471 	case RTE_FLOW_FIELD_MAC_DST:
1472 		off = data->offset > 16 ? data->offset - 16 : 0;
1473 		if (mask) {
1474 			if (data->offset < 16) {
1475 				info[idx] = (struct field_modify_info){2, 0,
1476 						MLX5_MODI_OUT_DMAC_15_0};
1477 				if (width < 16) {
1478 					mask[idx] = rte_cpu_to_be_16(0xffff >>
1479 								 (16 - width));
1480 					width = 0;
1481 				} else {
1482 					mask[idx] = RTE_BE16(0xffff);
1483 					width -= 16;
1484 				}
1485 				if (!width)
1486 					break;
1487 				++idx;
1488 			}
1489 			info[idx] = (struct field_modify_info){4, 4 * idx,
1490 						MLX5_MODI_OUT_DMAC_47_16};
1491 			mask[idx] = rte_cpu_to_be_32((0xffffffff >>
1492 						      (32 - width)) << off);
1493 		} else {
1494 			if (data->offset < 16)
1495 				info[idx++] = (struct field_modify_info){2, 0,
1496 						MLX5_MODI_OUT_DMAC_15_0};
1497 			info[idx] = (struct field_modify_info){4, off,
1498 						MLX5_MODI_OUT_DMAC_47_16};
1499 		}
1500 		break;
1501 	case RTE_FLOW_FIELD_MAC_SRC:
1502 		off = data->offset > 16 ? data->offset - 16 : 0;
1503 		if (mask) {
1504 			if (data->offset < 16) {
1505 				info[idx] = (struct field_modify_info){2, 0,
1506 						MLX5_MODI_OUT_SMAC_15_0};
1507 				if (width < 16) {
1508 					mask[idx] = rte_cpu_to_be_16(0xffff >>
1509 								 (16 - width));
1510 					width = 0;
1511 				} else {
1512 					mask[idx] = RTE_BE16(0xffff);
1513 					width -= 16;
1514 				}
1515 				if (!width)
1516 					break;
1517 				++idx;
1518 			}
1519 			info[idx] = (struct field_modify_info){4, 4 * idx,
1520 						MLX5_MODI_OUT_SMAC_47_16};
1521 			mask[idx] = rte_cpu_to_be_32((0xffffffff >>
1522 						      (32 - width)) << off);
1523 		} else {
1524 			if (data->offset < 16)
1525 				info[idx++] = (struct field_modify_info){2, 0,
1526 						MLX5_MODI_OUT_SMAC_15_0};
1527 			info[idx] = (struct field_modify_info){4, off,
1528 						MLX5_MODI_OUT_SMAC_47_16};
1529 		}
1530 		break;
1531 	case RTE_FLOW_FIELD_VLAN_TYPE:
1532 		/* not supported yet */
1533 		break;
1534 	case RTE_FLOW_FIELD_VLAN_ID:
1535 		info[idx] = (struct field_modify_info){2, 0,
1536 					MLX5_MODI_OUT_FIRST_VID};
1537 		if (mask)
1538 			mask[idx] = rte_cpu_to_be_16(0x0fff >> (12 - width));
1539 		break;
1540 	case RTE_FLOW_FIELD_MAC_TYPE:
1541 		info[idx] = (struct field_modify_info){2, 0,
1542 					MLX5_MODI_OUT_ETHERTYPE};
1543 		if (mask)
1544 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1545 		break;
1546 	case RTE_FLOW_FIELD_IPV4_DSCP:
1547 		info[idx] = (struct field_modify_info){1, 0,
1548 					MLX5_MODI_OUT_IP_DSCP};
1549 		if (mask)
1550 			mask[idx] = 0x3f >> (6 - width);
1551 		break;
1552 	case RTE_FLOW_FIELD_IPV4_TTL:
1553 		info[idx] = (struct field_modify_info){1, 0,
1554 					MLX5_MODI_OUT_IPV4_TTL};
1555 		if (mask)
1556 			mask[idx] = 0xff >> (8 - width);
1557 		break;
1558 	case RTE_FLOW_FIELD_IPV4_SRC:
1559 		info[idx] = (struct field_modify_info){4, 0,
1560 					MLX5_MODI_OUT_SIPV4};
1561 		if (mask)
1562 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1563 						     (32 - width));
1564 		break;
1565 	case RTE_FLOW_FIELD_IPV4_DST:
1566 		info[idx] = (struct field_modify_info){4, 0,
1567 					MLX5_MODI_OUT_DIPV4};
1568 		if (mask)
1569 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1570 						     (32 - width));
1571 		break;
1572 	case RTE_FLOW_FIELD_IPV6_DSCP:
1573 		info[idx] = (struct field_modify_info){1, 0,
1574 					MLX5_MODI_OUT_IP_DSCP};
1575 		if (mask)
1576 			mask[idx] = 0x3f >> (6 - width);
1577 		break;
1578 	case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
1579 		info[idx] = (struct field_modify_info){1, 0,
1580 					MLX5_MODI_OUT_IPV6_HOPLIMIT};
1581 		if (mask)
1582 			mask[idx] = 0xff >> (8 - width);
1583 		break;
1584 	case RTE_FLOW_FIELD_IPV6_SRC:
1585 		if (mask) {
1586 			if (data->offset < 32) {
1587 				info[idx] = (struct field_modify_info){4,
1588 						4 * idx,
1589 						MLX5_MODI_OUT_SIPV6_31_0};
1590 				if (width < 32) {
1591 					mask[idx] =
1592 						rte_cpu_to_be_32(0xffffffff >>
1593 								 (32 - width));
1594 					width = 0;
1595 				} else {
1596 					mask[idx] = RTE_BE32(0xffffffff);
1597 					width -= 32;
1598 				}
1599 				if (!width)
1600 					break;
1601 				++idx;
1602 			}
1603 			if (data->offset < 64) {
1604 				info[idx] = (struct field_modify_info){4,
1605 						4 * idx,
1606 						MLX5_MODI_OUT_SIPV6_63_32};
1607 				if (width < 32) {
1608 					mask[idx] =
1609 						rte_cpu_to_be_32(0xffffffff >>
1610 								 (32 - width));
1611 					width = 0;
1612 				} else {
1613 					mask[idx] = RTE_BE32(0xffffffff);
1614 					width -= 32;
1615 				}
1616 				if (!width)
1617 					break;
1618 				++idx;
1619 			}
1620 			if (data->offset < 96) {
1621 				info[idx] = (struct field_modify_info){4,
1622 						4 * idx,
1623 						MLX5_MODI_OUT_SIPV6_95_64};
1624 				if (width < 32) {
1625 					mask[idx] =
1626 						rte_cpu_to_be_32(0xffffffff >>
1627 								 (32 - width));
1628 					width = 0;
1629 				} else {
1630 					mask[idx] = RTE_BE32(0xffffffff);
1631 					width -= 32;
1632 				}
1633 				if (!width)
1634 					break;
1635 				++idx;
1636 			}
1637 			info[idx] = (struct field_modify_info){4, 4 * idx,
1638 						MLX5_MODI_OUT_SIPV6_127_96};
1639 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1640 						     (32 - width));
1641 		} else {
1642 			if (data->offset < 32)
1643 				info[idx++] = (struct field_modify_info){4, 0,
1644 						MLX5_MODI_OUT_SIPV6_31_0};
1645 			if (data->offset < 64)
1646 				info[idx++] = (struct field_modify_info){4, 0,
1647 						MLX5_MODI_OUT_SIPV6_63_32};
1648 			if (data->offset < 96)
1649 				info[idx++] = (struct field_modify_info){4, 0,
1650 						MLX5_MODI_OUT_SIPV6_95_64};
1651 			if (data->offset < 128)
1652 				info[idx++] = (struct field_modify_info){4, 0,
1653 						MLX5_MODI_OUT_SIPV6_127_96};
1654 		}
1655 		break;
1656 	case RTE_FLOW_FIELD_IPV6_DST:
1657 		if (mask) {
1658 			if (data->offset < 32) {
1659 				info[idx] = (struct field_modify_info){4,
1660 						4 * idx,
1661 						MLX5_MODI_OUT_DIPV6_31_0};
1662 				if (width < 32) {
1663 					mask[idx] =
1664 						rte_cpu_to_be_32(0xffffffff >>
1665 								 (32 - width));
1666 					width = 0;
1667 				} else {
1668 					mask[idx] = RTE_BE32(0xffffffff);
1669 					width -= 32;
1670 				}
1671 				if (!width)
1672 					break;
1673 				++idx;
1674 			}
1675 			if (data->offset < 64) {
1676 				info[idx] = (struct field_modify_info){4,
1677 						4 * idx,
1678 						MLX5_MODI_OUT_DIPV6_63_32};
1679 				if (width < 32) {
1680 					mask[idx] =
1681 						rte_cpu_to_be_32(0xffffffff >>
1682 								 (32 - width));
1683 					width = 0;
1684 				} else {
1685 					mask[idx] = RTE_BE32(0xffffffff);
1686 					width -= 32;
1687 				}
1688 				if (!width)
1689 					break;
1690 				++idx;
1691 			}
1692 			if (data->offset < 96) {
1693 				info[idx] = (struct field_modify_info){4,
1694 						4 * idx,
1695 						MLX5_MODI_OUT_DIPV6_95_64};
1696 				if (width < 32) {
1697 					mask[idx] =
1698 						rte_cpu_to_be_32(0xffffffff >>
1699 								 (32 - width));
1700 					width = 0;
1701 				} else {
1702 					mask[idx] = RTE_BE32(0xffffffff);
1703 					width -= 32;
1704 				}
1705 				if (!width)
1706 					break;
1707 				++idx;
1708 			}
1709 			info[idx] = (struct field_modify_info){4, 4 * idx,
1710 						MLX5_MODI_OUT_DIPV6_127_96};
1711 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1712 						     (32 - width));
1713 		} else {
1714 			if (data->offset < 32)
1715 				info[idx++] = (struct field_modify_info){4, 0,
1716 						MLX5_MODI_OUT_DIPV6_31_0};
1717 			if (data->offset < 64)
1718 				info[idx++] = (struct field_modify_info){4, 0,
1719 						MLX5_MODI_OUT_DIPV6_63_32};
1720 			if (data->offset < 96)
1721 				info[idx++] = (struct field_modify_info){4, 0,
1722 						MLX5_MODI_OUT_DIPV6_95_64};
1723 			if (data->offset < 128)
1724 				info[idx++] = (struct field_modify_info){4, 0,
1725 						MLX5_MODI_OUT_DIPV6_127_96};
1726 		}
1727 		break;
1728 	case RTE_FLOW_FIELD_TCP_PORT_SRC:
1729 		info[idx] = (struct field_modify_info){2, 0,
1730 					MLX5_MODI_OUT_TCP_SPORT};
1731 		if (mask)
1732 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1733 		break;
1734 	case RTE_FLOW_FIELD_TCP_PORT_DST:
1735 		info[idx] = (struct field_modify_info){2, 0,
1736 					MLX5_MODI_OUT_TCP_DPORT};
1737 		if (mask)
1738 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1739 		break;
1740 	case RTE_FLOW_FIELD_TCP_SEQ_NUM:
1741 		info[idx] = (struct field_modify_info){4, 0,
1742 					MLX5_MODI_OUT_TCP_SEQ_NUM};
1743 		if (mask)
1744 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1745 						     (32 - width));
1746 		break;
1747 	case RTE_FLOW_FIELD_TCP_ACK_NUM:
1748 		info[idx] = (struct field_modify_info){4, 0,
1749 					MLX5_MODI_OUT_TCP_ACK_NUM};
1750 		if (mask)
1751 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1752 						     (32 - width));
1753 		break;
1754 	case RTE_FLOW_FIELD_TCP_FLAGS:
1755 		info[idx] = (struct field_modify_info){2, 0,
1756 					MLX5_MODI_OUT_TCP_FLAGS};
1757 		if (mask)
1758 			mask[idx] = rte_cpu_to_be_16(0x1ff >> (9 - width));
1759 		break;
1760 	case RTE_FLOW_FIELD_UDP_PORT_SRC:
1761 		info[idx] = (struct field_modify_info){2, 0,
1762 					MLX5_MODI_OUT_UDP_SPORT};
1763 		if (mask)
1764 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1765 		break;
1766 	case RTE_FLOW_FIELD_UDP_PORT_DST:
1767 		info[idx] = (struct field_modify_info){2, 0,
1768 					MLX5_MODI_OUT_UDP_DPORT};
1769 		if (mask)
1770 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1771 		break;
1772 	case RTE_FLOW_FIELD_VXLAN_VNI:
1773 		/* not supported yet */
1774 		break;
1775 	case RTE_FLOW_FIELD_GENEVE_VNI:
1776 		/* not supported yet*/
1777 		break;
1778 	case RTE_FLOW_FIELD_GTP_TEID:
1779 		info[idx] = (struct field_modify_info){4, 0,
1780 					MLX5_MODI_GTP_TEID};
1781 		if (mask)
1782 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1783 						     (32 - width));
1784 		break;
1785 	case RTE_FLOW_FIELD_TAG:
1786 		{
1787 			int reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG,
1788 						   data->level, error);
1789 			if (reg < 0)
1790 				return;
1791 			MLX5_ASSERT(reg != REG_NON);
1792 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1793 			info[idx] = (struct field_modify_info){4, 0,
1794 						reg_to_field[reg]};
1795 			if (mask)
1796 				mask[idx] =
1797 					rte_cpu_to_be_32(0xffffffff >>
1798 							 (32 - width));
1799 		}
1800 		break;
1801 	case RTE_FLOW_FIELD_MARK:
1802 		{
1803 			uint32_t mark_mask = priv->sh->dv_mark_mask;
1804 			uint32_t mark_count = __builtin_popcount(mark_mask);
1805 			int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK,
1806 						       0, error);
1807 			if (reg < 0)
1808 				return;
1809 			MLX5_ASSERT(reg != REG_NON);
1810 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1811 			info[idx] = (struct field_modify_info){4, 0,
1812 						reg_to_field[reg]};
1813 			if (mask)
1814 				mask[idx] = rte_cpu_to_be_32((mark_mask >>
1815 					 (mark_count - width)) & mark_mask);
1816 		}
1817 		break;
1818 	case RTE_FLOW_FIELD_META:
1819 		{
1820 			uint32_t meta_mask = priv->sh->dv_meta_mask;
1821 			uint32_t meta_count = __builtin_popcount(meta_mask);
1822 			uint32_t msk_c0 =
1823 				rte_cpu_to_be_32(priv->sh->dv_regc0_mask);
1824 			uint32_t shl_c0 = rte_bsf32(msk_c0);
1825 			int reg = flow_dv_get_metadata_reg(dev, attr, error);
1826 			if (reg < 0)
1827 				return;
1828 			MLX5_ASSERT(reg != REG_NON);
1829 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1830 			if (reg == REG_C_0)
1831 				*shift = shl_c0;
1832 			info[idx] = (struct field_modify_info){4, 0,
1833 						reg_to_field[reg]};
1834 			if (mask)
1835 				mask[idx] = rte_cpu_to_be_32((meta_mask >>
1836 					(meta_count - width)) & meta_mask);
1837 		}
1838 		break;
1839 	case RTE_FLOW_FIELD_POINTER:
1840 	case RTE_FLOW_FIELD_VALUE:
1841 		if (data->field == RTE_FLOW_FIELD_POINTER)
1842 			memcpy(&val, (void *)(uintptr_t)data->value,
1843 			       sizeof(uint64_t));
1844 		else
1845 			val = data->value;
1846 		for (idx = 0; idx < MLX5_ACT_MAX_MOD_FIELDS; idx++) {
1847 			if (mask[idx]) {
1848 				if (dst_width == 48) {
1849 					/*special case for MAC addresses */
1850 					value[idx] = rte_cpu_to_be_16(val);
1851 					val >>= 16;
1852 					dst_width -= 16;
1853 				} else if (dst_width > 16) {
1854 					value[idx] = rte_cpu_to_be_32(val);
1855 					val >>= 32;
1856 				} else if (dst_width > 8) {
1857 					value[idx] = rte_cpu_to_be_16(val);
1858 					val >>= 16;
1859 				} else {
1860 					value[idx] = (uint8_t)val;
1861 					val >>= 8;
1862 				}
1863 				if (*shift)
1864 					value[idx] <<= *shift;
1865 				if (!val)
1866 					break;
1867 			}
1868 		}
1869 		break;
1870 	default:
1871 		MLX5_ASSERT(false);
1872 		break;
1873 	}
1874 }
1875 
1876 /**
1877  * Convert modify_field action to DV specification.
1878  *
1879  * @param[in] dev
1880  *   Pointer to the rte_eth_dev structure.
1881  * @param[in,out] resource
1882  *   Pointer to the modify-header resource.
1883  * @param[in] action
1884  *   Pointer to action specification.
1885  * @param[in] attr
1886  *   Attributes of flow that includes this item.
1887  * @param[out] error
1888  *   Pointer to the error structure.
1889  *
1890  * @return
1891  *   0 on success, a negative errno value otherwise and rte_errno is set.
1892  */
1893 static int
1894 flow_dv_convert_action_modify_field
1895 			(struct rte_eth_dev *dev,
1896 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1897 			 const struct rte_flow_action *action,
1898 			 const struct rte_flow_attr *attr,
1899 			 struct rte_flow_error *error)
1900 {
1901 	struct mlx5_priv *priv = dev->data->dev_private;
1902 	const struct rte_flow_action_modify_field *conf =
1903 		(const struct rte_flow_action_modify_field *)(action->conf);
1904 	struct rte_flow_item item;
1905 	struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = {
1906 								{0, 0, 0} };
1907 	struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = {
1908 								{0, 0, 0} };
1909 	uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0};
1910 	uint32_t value[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0};
1911 	uint32_t type;
1912 	uint32_t shift = 0;
1913 	uint32_t dst_width = mlx5_flow_item_field_width(priv, conf->dst.field);
1914 
1915 	if (conf->src.field == RTE_FLOW_FIELD_POINTER ||
1916 		conf->src.field == RTE_FLOW_FIELD_VALUE) {
1917 		type = MLX5_MODIFICATION_TYPE_SET;
1918 		/** For SET fill the destination field (field) first. */
1919 		mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask,
1920 						  value, conf->width, dst_width,
1921 						  &shift, dev, attr, error);
1922 		/** Then copy immediate value from source as per mask. */
1923 		mlx5_flow_field_id_to_modify_info(&conf->src, dcopy, mask,
1924 						  value, conf->width, dst_width,
1925 						  &shift, dev, attr, error);
1926 		item.spec = &value;
1927 	} else {
1928 		type = MLX5_MODIFICATION_TYPE_COPY;
1929 		/** For COPY fill the destination field (dcopy) without mask. */
1930 		mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL,
1931 						  value, conf->width, dst_width,
1932 						  &shift, dev, attr, error);
1933 		/** Then construct the source field (field) with mask. */
1934 		mlx5_flow_field_id_to_modify_info(&conf->src, field, mask,
1935 						  value, conf->width, dst_width,
1936 						  &shift, dev, attr, error);
1937 	}
1938 	item.mask = &mask;
1939 	return flow_dv_convert_modify_action(&item,
1940 			field, dcopy, resource, type, error);
1941 }
1942 
1943 /**
1944  * Validate MARK item.
1945  *
1946  * @param[in] dev
1947  *   Pointer to the rte_eth_dev structure.
1948  * @param[in] item
1949  *   Item specification.
1950  * @param[in] attr
1951  *   Attributes of flow that includes this item.
1952  * @param[out] error
1953  *   Pointer to error structure.
1954  *
1955  * @return
1956  *   0 on success, a negative errno value otherwise and rte_errno is set.
1957  */
1958 static int
1959 flow_dv_validate_item_mark(struct rte_eth_dev *dev,
1960 			   const struct rte_flow_item *item,
1961 			   const struct rte_flow_attr *attr __rte_unused,
1962 			   struct rte_flow_error *error)
1963 {
1964 	struct mlx5_priv *priv = dev->data->dev_private;
1965 	struct mlx5_dev_config *config = &priv->config;
1966 	const struct rte_flow_item_mark *spec = item->spec;
1967 	const struct rte_flow_item_mark *mask = item->mask;
1968 	const struct rte_flow_item_mark nic_mask = {
1969 		.id = priv->sh->dv_mark_mask,
1970 	};
1971 	int ret;
1972 
1973 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
1974 		return rte_flow_error_set(error, ENOTSUP,
1975 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1976 					  "extended metadata feature"
1977 					  " isn't enabled");
1978 	if (!mlx5_flow_ext_mreg_supported(dev))
1979 		return rte_flow_error_set(error, ENOTSUP,
1980 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1981 					  "extended metadata register"
1982 					  " isn't supported");
1983 	if (!nic_mask.id)
1984 		return rte_flow_error_set(error, ENOTSUP,
1985 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1986 					  "extended metadata register"
1987 					  " isn't available");
1988 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
1989 	if (ret < 0)
1990 		return ret;
1991 	if (!spec)
1992 		return rte_flow_error_set(error, EINVAL,
1993 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
1994 					  item->spec,
1995 					  "data cannot be empty");
1996 	if (spec->id >= (MLX5_FLOW_MARK_MAX & nic_mask.id))
1997 		return rte_flow_error_set(error, EINVAL,
1998 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1999 					  &spec->id,
2000 					  "mark id exceeds the limit");
2001 	if (!mask)
2002 		mask = &nic_mask;
2003 	if (!mask->id)
2004 		return rte_flow_error_set(error, EINVAL,
2005 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2006 					"mask cannot be zero");
2007 
2008 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2009 					(const uint8_t *)&nic_mask,
2010 					sizeof(struct rte_flow_item_mark),
2011 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2012 	if (ret < 0)
2013 		return ret;
2014 	return 0;
2015 }
2016 
2017 /**
2018  * Validate META item.
2019  *
2020  * @param[in] dev
2021  *   Pointer to the rte_eth_dev structure.
2022  * @param[in] item
2023  *   Item specification.
2024  * @param[in] attr
2025  *   Attributes of flow that includes this item.
2026  * @param[out] error
2027  *   Pointer to error structure.
2028  *
2029  * @return
2030  *   0 on success, a negative errno value otherwise and rte_errno is set.
2031  */
2032 static int
2033 flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused,
2034 			   const struct rte_flow_item *item,
2035 			   const struct rte_flow_attr *attr,
2036 			   struct rte_flow_error *error)
2037 {
2038 	struct mlx5_priv *priv = dev->data->dev_private;
2039 	struct mlx5_dev_config *config = &priv->config;
2040 	const struct rte_flow_item_meta *spec = item->spec;
2041 	const struct rte_flow_item_meta *mask = item->mask;
2042 	struct rte_flow_item_meta nic_mask = {
2043 		.data = UINT32_MAX
2044 	};
2045 	int reg;
2046 	int ret;
2047 
2048 	if (!spec)
2049 		return rte_flow_error_set(error, EINVAL,
2050 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2051 					  item->spec,
2052 					  "data cannot be empty");
2053 	if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
2054 		if (!mlx5_flow_ext_mreg_supported(dev))
2055 			return rte_flow_error_set(error, ENOTSUP,
2056 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2057 					  "extended metadata register"
2058 					  " isn't supported");
2059 		reg = flow_dv_get_metadata_reg(dev, attr, error);
2060 		if (reg < 0)
2061 			return reg;
2062 		if (reg == REG_NON)
2063 			return rte_flow_error_set(error, ENOTSUP,
2064 					RTE_FLOW_ERROR_TYPE_ITEM, item,
2065 					"unavalable extended metadata register");
2066 		if (reg == REG_B)
2067 			return rte_flow_error_set(error, ENOTSUP,
2068 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2069 					  "match on reg_b "
2070 					  "isn't supported");
2071 		if (reg != REG_A)
2072 			nic_mask.data = priv->sh->dv_meta_mask;
2073 	} else {
2074 		if (attr->transfer)
2075 			return rte_flow_error_set(error, ENOTSUP,
2076 					RTE_FLOW_ERROR_TYPE_ITEM, item,
2077 					"extended metadata feature "
2078 					"should be enabled when "
2079 					"meta item is requested "
2080 					"with e-switch mode ");
2081 		if (attr->ingress)
2082 			return rte_flow_error_set(error, ENOTSUP,
2083 					RTE_FLOW_ERROR_TYPE_ITEM, item,
2084 					"match on metadata for ingress "
2085 					"is not supported in legacy "
2086 					"metadata mode");
2087 	}
2088 	if (!mask)
2089 		mask = &rte_flow_item_meta_mask;
2090 	if (!mask->data)
2091 		return rte_flow_error_set(error, EINVAL,
2092 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2093 					"mask cannot be zero");
2094 
2095 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2096 					(const uint8_t *)&nic_mask,
2097 					sizeof(struct rte_flow_item_meta),
2098 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2099 	return ret;
2100 }
2101 
2102 /**
2103  * Validate TAG item.
2104  *
2105  * @param[in] dev
2106  *   Pointer to the rte_eth_dev structure.
2107  * @param[in] item
2108  *   Item specification.
2109  * @param[in] attr
2110  *   Attributes of flow that includes this item.
2111  * @param[out] error
2112  *   Pointer to error structure.
2113  *
2114  * @return
2115  *   0 on success, a negative errno value otherwise and rte_errno is set.
2116  */
2117 static int
2118 flow_dv_validate_item_tag(struct rte_eth_dev *dev,
2119 			  const struct rte_flow_item *item,
2120 			  const struct rte_flow_attr *attr __rte_unused,
2121 			  struct rte_flow_error *error)
2122 {
2123 	const struct rte_flow_item_tag *spec = item->spec;
2124 	const struct rte_flow_item_tag *mask = item->mask;
2125 	const struct rte_flow_item_tag nic_mask = {
2126 		.data = RTE_BE32(UINT32_MAX),
2127 		.index = 0xff,
2128 	};
2129 	int ret;
2130 
2131 	if (!mlx5_flow_ext_mreg_supported(dev))
2132 		return rte_flow_error_set(error, ENOTSUP,
2133 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2134 					  "extensive metadata register"
2135 					  " isn't supported");
2136 	if (!spec)
2137 		return rte_flow_error_set(error, EINVAL,
2138 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2139 					  item->spec,
2140 					  "data cannot be empty");
2141 	if (!mask)
2142 		mask = &rte_flow_item_tag_mask;
2143 	if (!mask->data)
2144 		return rte_flow_error_set(error, EINVAL,
2145 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2146 					"mask cannot be zero");
2147 
2148 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2149 					(const uint8_t *)&nic_mask,
2150 					sizeof(struct rte_flow_item_tag),
2151 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2152 	if (ret < 0)
2153 		return ret;
2154 	if (mask->index != 0xff)
2155 		return rte_flow_error_set(error, EINVAL,
2156 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2157 					  "partial mask for tag index"
2158 					  " is not supported");
2159 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, spec->index, error);
2160 	if (ret < 0)
2161 		return ret;
2162 	MLX5_ASSERT(ret != REG_NON);
2163 	return 0;
2164 }
2165 
2166 /**
2167  * Validate vport item.
2168  *
2169  * @param[in] dev
2170  *   Pointer to the rte_eth_dev structure.
2171  * @param[in] item
2172  *   Item specification.
2173  * @param[in] attr
2174  *   Attributes of flow that includes this item.
2175  * @param[in] item_flags
2176  *   Bit-fields that holds the items detected until now.
2177  * @param[out] error
2178  *   Pointer to error structure.
2179  *
2180  * @return
2181  *   0 on success, a negative errno value otherwise and rte_errno is set.
2182  */
2183 static int
2184 flow_dv_validate_item_port_id(struct rte_eth_dev *dev,
2185 			      const struct rte_flow_item *item,
2186 			      const struct rte_flow_attr *attr,
2187 			      uint64_t item_flags,
2188 			      struct rte_flow_error *error)
2189 {
2190 	const struct rte_flow_item_port_id *spec = item->spec;
2191 	const struct rte_flow_item_port_id *mask = item->mask;
2192 	const struct rte_flow_item_port_id switch_mask = {
2193 			.id = 0xffffffff,
2194 	};
2195 	struct mlx5_priv *esw_priv;
2196 	struct mlx5_priv *dev_priv;
2197 	int ret;
2198 
2199 	if (!attr->transfer)
2200 		return rte_flow_error_set(error, EINVAL,
2201 					  RTE_FLOW_ERROR_TYPE_ITEM,
2202 					  NULL,
2203 					  "match on port id is valid only"
2204 					  " when transfer flag is enabled");
2205 	if (item_flags & MLX5_FLOW_ITEM_PORT_ID)
2206 		return rte_flow_error_set(error, ENOTSUP,
2207 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2208 					  "multiple source ports are not"
2209 					  " supported");
2210 	if (!mask)
2211 		mask = &switch_mask;
2212 	if (mask->id != 0xffffffff)
2213 		return rte_flow_error_set(error, ENOTSUP,
2214 					   RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2215 					   mask,
2216 					   "no support for partial mask on"
2217 					   " \"id\" field");
2218 	ret = mlx5_flow_item_acceptable
2219 				(item, (const uint8_t *)mask,
2220 				 (const uint8_t *)&rte_flow_item_port_id_mask,
2221 				 sizeof(struct rte_flow_item_port_id),
2222 				 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2223 	if (ret)
2224 		return ret;
2225 	if (!spec)
2226 		return 0;
2227 	esw_priv = mlx5_port_to_eswitch_info(spec->id, false);
2228 	if (!esw_priv)
2229 		return rte_flow_error_set(error, rte_errno,
2230 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2231 					  "failed to obtain E-Switch info for"
2232 					  " port");
2233 	dev_priv = mlx5_dev_to_eswitch_info(dev);
2234 	if (!dev_priv)
2235 		return rte_flow_error_set(error, rte_errno,
2236 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2237 					  NULL,
2238 					  "failed to obtain E-Switch info");
2239 	if (esw_priv->domain_id != dev_priv->domain_id)
2240 		return rte_flow_error_set(error, EINVAL,
2241 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2242 					  "cannot match on a port from a"
2243 					  " different E-Switch");
2244 	return 0;
2245 }
2246 
2247 /**
2248  * Validate VLAN item.
2249  *
2250  * @param[in] item
2251  *   Item specification.
2252  * @param[in] item_flags
2253  *   Bit-fields that holds the items detected until now.
2254  * @param[in] dev
2255  *   Ethernet device flow is being created on.
2256  * @param[out] error
2257  *   Pointer to error structure.
2258  *
2259  * @return
2260  *   0 on success, a negative errno value otherwise and rte_errno is set.
2261  */
2262 static int
2263 flow_dv_validate_item_vlan(const struct rte_flow_item *item,
2264 			   uint64_t item_flags,
2265 			   struct rte_eth_dev *dev,
2266 			   struct rte_flow_error *error)
2267 {
2268 	const struct rte_flow_item_vlan *mask = item->mask;
2269 	const struct rte_flow_item_vlan nic_mask = {
2270 		.tci = RTE_BE16(UINT16_MAX),
2271 		.inner_type = RTE_BE16(UINT16_MAX),
2272 		.has_more_vlan = 1,
2273 	};
2274 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2275 	int ret;
2276 	const uint64_t l34m = tunnel ? (MLX5_FLOW_LAYER_INNER_L3 |
2277 					MLX5_FLOW_LAYER_INNER_L4) :
2278 				       (MLX5_FLOW_LAYER_OUTER_L3 |
2279 					MLX5_FLOW_LAYER_OUTER_L4);
2280 	const uint64_t vlanm = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
2281 					MLX5_FLOW_LAYER_OUTER_VLAN;
2282 
2283 	if (item_flags & vlanm)
2284 		return rte_flow_error_set(error, EINVAL,
2285 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2286 					  "multiple VLAN layers not supported");
2287 	else if ((item_flags & l34m) != 0)
2288 		return rte_flow_error_set(error, EINVAL,
2289 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2290 					  "VLAN cannot follow L3/L4 layer");
2291 	if (!mask)
2292 		mask = &rte_flow_item_vlan_mask;
2293 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2294 					(const uint8_t *)&nic_mask,
2295 					sizeof(struct rte_flow_item_vlan),
2296 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2297 	if (ret)
2298 		return ret;
2299 	if (!tunnel && mask->tci != RTE_BE16(0x0fff)) {
2300 		struct mlx5_priv *priv = dev->data->dev_private;
2301 
2302 		if (priv->vmwa_context) {
2303 			/*
2304 			 * Non-NULL context means we have a virtual machine
2305 			 * and SR-IOV enabled, we have to create VLAN interface
2306 			 * to make hypervisor to setup E-Switch vport
2307 			 * context correctly. We avoid creating the multiple
2308 			 * VLAN interfaces, so we cannot support VLAN tag mask.
2309 			 */
2310 			return rte_flow_error_set(error, EINVAL,
2311 						  RTE_FLOW_ERROR_TYPE_ITEM,
2312 						  item,
2313 						  "VLAN tag mask is not"
2314 						  " supported in virtual"
2315 						  " environment");
2316 		}
2317 	}
2318 	return 0;
2319 }
2320 
2321 /*
2322  * GTP flags are contained in 1 byte of the format:
2323  * -------------------------------------------
2324  * | bit   | 0 - 2   | 3  | 4   | 5 | 6 | 7  |
2325  * |-----------------------------------------|
2326  * | value | Version | PT | Res | E | S | PN |
2327  * -------------------------------------------
2328  *
2329  * Matching is supported only for GTP flags E, S, PN.
2330  */
2331 #define MLX5_GTP_FLAGS_MASK	0x07
2332 
2333 /**
2334  * Validate GTP item.
2335  *
2336  * @param[in] dev
2337  *   Pointer to the rte_eth_dev structure.
2338  * @param[in] item
2339  *   Item specification.
2340  * @param[in] item_flags
2341  *   Bit-fields that holds the items detected until now.
2342  * @param[out] error
2343  *   Pointer to error structure.
2344  *
2345  * @return
2346  *   0 on success, a negative errno value otherwise and rte_errno is set.
2347  */
2348 static int
2349 flow_dv_validate_item_gtp(struct rte_eth_dev *dev,
2350 			  const struct rte_flow_item *item,
2351 			  uint64_t item_flags,
2352 			  struct rte_flow_error *error)
2353 {
2354 	struct mlx5_priv *priv = dev->data->dev_private;
2355 	const struct rte_flow_item_gtp *spec = item->spec;
2356 	const struct rte_flow_item_gtp *mask = item->mask;
2357 	const struct rte_flow_item_gtp nic_mask = {
2358 		.v_pt_rsv_flags = MLX5_GTP_FLAGS_MASK,
2359 		.msg_type = 0xff,
2360 		.teid = RTE_BE32(0xffffffff),
2361 	};
2362 
2363 	if (!priv->config.hca_attr.tunnel_stateless_gtp)
2364 		return rte_flow_error_set(error, ENOTSUP,
2365 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2366 					  "GTP support is not enabled");
2367 	if (item_flags & MLX5_FLOW_LAYER_TUNNEL)
2368 		return rte_flow_error_set(error, ENOTSUP,
2369 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2370 					  "multiple tunnel layers not"
2371 					  " supported");
2372 	if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP))
2373 		return rte_flow_error_set(error, EINVAL,
2374 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2375 					  "no outer UDP layer found");
2376 	if (!mask)
2377 		mask = &rte_flow_item_gtp_mask;
2378 	if (spec && spec->v_pt_rsv_flags & ~MLX5_GTP_FLAGS_MASK)
2379 		return rte_flow_error_set(error, ENOTSUP,
2380 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2381 					  "Match is supported for GTP"
2382 					  " flags only");
2383 	return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2384 					 (const uint8_t *)&nic_mask,
2385 					 sizeof(struct rte_flow_item_gtp),
2386 					 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2387 }
2388 
2389 /**
2390  * Validate GTP PSC item.
2391  *
2392  * @param[in] item
2393  *   Item specification.
2394  * @param[in] last_item
2395  *   Previous validated item in the pattern items.
2396  * @param[in] gtp_item
2397  *   Previous GTP item specification.
2398  * @param[in] attr
2399  *   Pointer to flow attributes.
2400  * @param[out] error
2401  *   Pointer to error structure.
2402  *
2403  * @return
2404  *   0 on success, a negative errno value otherwise and rte_errno is set.
2405  */
2406 static int
2407 flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item,
2408 			      uint64_t last_item,
2409 			      const struct rte_flow_item *gtp_item,
2410 			      const struct rte_flow_attr *attr,
2411 			      struct rte_flow_error *error)
2412 {
2413 	const struct rte_flow_item_gtp *gtp_spec;
2414 	const struct rte_flow_item_gtp *gtp_mask;
2415 	const struct rte_flow_item_gtp_psc *mask;
2416 	const struct rte_flow_item_gtp_psc nic_mask = {
2417 		.hdr.type = 0xF,
2418 		.hdr.qfi = 0x3F,
2419 	};
2420 
2421 	if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP))
2422 		return rte_flow_error_set
2423 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2424 			 "GTP PSC item must be preceded with GTP item");
2425 	gtp_spec = gtp_item->spec;
2426 	gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask;
2427 	/* GTP spec and E flag is requested to match zero. */
2428 	if (gtp_spec &&
2429 		(gtp_mask->v_pt_rsv_flags &
2430 		~gtp_spec->v_pt_rsv_flags & MLX5_GTP_EXT_HEADER_FLAG))
2431 		return rte_flow_error_set
2432 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2433 			 "GTP E flag must be 1 to match GTP PSC");
2434 	/* Check the flow is not created in group zero. */
2435 	if (!attr->transfer && !attr->group)
2436 		return rte_flow_error_set
2437 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2438 			 "GTP PSC is not supported for group 0");
2439 	/* GTP spec is here and E flag is requested to match zero. */
2440 	if (!item->spec)
2441 		return 0;
2442 	mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask;
2443 	return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2444 					 (const uint8_t *)&nic_mask,
2445 					 sizeof(struct rte_flow_item_gtp_psc),
2446 					 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2447 }
2448 
2449 /**
2450  * Validate IPV4 item.
2451  * Use existing validation function mlx5_flow_validate_item_ipv4(), and
2452  * add specific validation of fragment_offset field,
2453  *
2454  * @param[in] item
2455  *   Item specification.
2456  * @param[in] item_flags
2457  *   Bit-fields that holds the items detected until now.
2458  * @param[out] error
2459  *   Pointer to error structure.
2460  *
2461  * @return
2462  *   0 on success, a negative errno value otherwise and rte_errno is set.
2463  */
2464 static int
2465 flow_dv_validate_item_ipv4(struct rte_eth_dev *dev,
2466 			   const struct rte_flow_item *item,
2467 			   uint64_t item_flags, uint64_t last_item,
2468 			   uint16_t ether_type, struct rte_flow_error *error)
2469 {
2470 	int ret;
2471 	struct mlx5_priv *priv = dev->data->dev_private;
2472 	const struct rte_flow_item_ipv4 *spec = item->spec;
2473 	const struct rte_flow_item_ipv4 *last = item->last;
2474 	const struct rte_flow_item_ipv4 *mask = item->mask;
2475 	rte_be16_t fragment_offset_spec = 0;
2476 	rte_be16_t fragment_offset_last = 0;
2477 	struct rte_flow_item_ipv4 nic_ipv4_mask = {
2478 		.hdr = {
2479 			.src_addr = RTE_BE32(0xffffffff),
2480 			.dst_addr = RTE_BE32(0xffffffff),
2481 			.type_of_service = 0xff,
2482 			.fragment_offset = RTE_BE16(0xffff),
2483 			.next_proto_id = 0xff,
2484 			.time_to_live = 0xff,
2485 		},
2486 	};
2487 
2488 	if (mask && (mask->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK)) {
2489 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2490 		bool ihl_cap = !tunnel ? priv->config.hca_attr.outer_ipv4_ihl :
2491 			       priv->config.hca_attr.inner_ipv4_ihl;
2492 		if (!ihl_cap)
2493 			return rte_flow_error_set(error, ENOTSUP,
2494 						  RTE_FLOW_ERROR_TYPE_ITEM,
2495 						  item,
2496 						  "IPV4 ihl offload not supported");
2497 		nic_ipv4_mask.hdr.version_ihl = mask->hdr.version_ihl;
2498 	}
2499 	ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item,
2500 					   ether_type, &nic_ipv4_mask,
2501 					   MLX5_ITEM_RANGE_ACCEPTED, error);
2502 	if (ret < 0)
2503 		return ret;
2504 	if (spec && mask)
2505 		fragment_offset_spec = spec->hdr.fragment_offset &
2506 				       mask->hdr.fragment_offset;
2507 	if (!fragment_offset_spec)
2508 		return 0;
2509 	/*
2510 	 * spec and mask are valid, enforce using full mask to make sure the
2511 	 * complete value is used correctly.
2512 	 */
2513 	if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2514 			!= RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2515 		return rte_flow_error_set(error, EINVAL,
2516 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2517 					  item, "must use full mask for"
2518 					  " fragment_offset");
2519 	/*
2520 	 * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0,
2521 	 * indicating this is 1st fragment of fragmented packet.
2522 	 * This is not yet supported in MLX5, return appropriate error message.
2523 	 */
2524 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG))
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 (fragment_offset_spec && !last)
2530 		return rte_flow_error_set(error, ENOTSUP,
2531 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2532 					  "specified value not supported");
2533 	/* spec and last are valid, validate the specified range. */
2534 	fragment_offset_last = last->hdr.fragment_offset &
2535 			       mask->hdr.fragment_offset;
2536 	/*
2537 	 * Match on fragment_offset spec 0x2001 and last 0x3fff
2538 	 * means MF is 1 and frag-offset is > 0.
2539 	 * This packet is fragment 2nd and onward, excluding last.
2540 	 * This is not yet supported in MLX5, return appropriate
2541 	 * error message.
2542 	 */
2543 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) &&
2544 	    fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2545 		return rte_flow_error_set(error, ENOTSUP,
2546 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2547 					  last, "match on following "
2548 					  "fragments not supported");
2549 	/*
2550 	 * Match on fragment_offset spec 0x0001 and last 0x1fff
2551 	 * means MF is 0 and frag-offset is > 0.
2552 	 * This packet is last fragment of fragmented packet.
2553 	 * This is not yet supported in MLX5, return appropriate
2554 	 * error message.
2555 	 */
2556 	if (fragment_offset_spec == RTE_BE16(1) &&
2557 	    fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK))
2558 		return rte_flow_error_set(error, ENOTSUP,
2559 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2560 					  last, "match on last "
2561 					  "fragment not supported");
2562 	/*
2563 	 * Match on fragment_offset spec 0x0001 and last 0x3fff
2564 	 * means MF and/or frag-offset is not 0.
2565 	 * This is a fragmented packet.
2566 	 * Other range values are invalid and rejected.
2567 	 */
2568 	if (!(fragment_offset_spec == RTE_BE16(1) &&
2569 	      fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)))
2570 		return rte_flow_error_set(error, ENOTSUP,
2571 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2572 					  "specified range not supported");
2573 	return 0;
2574 }
2575 
2576 /**
2577  * Validate IPV6 fragment extension item.
2578  *
2579  * @param[in] item
2580  *   Item specification.
2581  * @param[in] item_flags
2582  *   Bit-fields that holds the items detected until now.
2583  * @param[out] error
2584  *   Pointer to error structure.
2585  *
2586  * @return
2587  *   0 on success, a negative errno value otherwise and rte_errno is set.
2588  */
2589 static int
2590 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item,
2591 				    uint64_t item_flags,
2592 				    struct rte_flow_error *error)
2593 {
2594 	const struct rte_flow_item_ipv6_frag_ext *spec = item->spec;
2595 	const struct rte_flow_item_ipv6_frag_ext *last = item->last;
2596 	const struct rte_flow_item_ipv6_frag_ext *mask = item->mask;
2597 	rte_be16_t frag_data_spec = 0;
2598 	rte_be16_t frag_data_last = 0;
2599 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2600 	const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 :
2601 				      MLX5_FLOW_LAYER_OUTER_L4;
2602 	int ret = 0;
2603 	struct rte_flow_item_ipv6_frag_ext nic_mask = {
2604 		.hdr = {
2605 			.next_header = 0xff,
2606 			.frag_data = RTE_BE16(0xffff),
2607 		},
2608 	};
2609 
2610 	if (item_flags & l4m)
2611 		return rte_flow_error_set(error, EINVAL,
2612 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2613 					  "ipv6 fragment extension item cannot "
2614 					  "follow L4 item.");
2615 	if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
2616 	    (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6)))
2617 		return rte_flow_error_set(error, EINVAL,
2618 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2619 					  "ipv6 fragment extension item must "
2620 					  "follow ipv6 item");
2621 	if (spec && mask)
2622 		frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data;
2623 	if (!frag_data_spec)
2624 		return 0;
2625 	/*
2626 	 * spec and mask are valid, enforce using full mask to make sure the
2627 	 * complete value is used correctly.
2628 	 */
2629 	if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) !=
2630 				RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2631 		return rte_flow_error_set(error, EINVAL,
2632 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2633 					  item, "must use full mask for"
2634 					  " frag_data");
2635 	/*
2636 	 * Match on frag_data 0x00001 means M is 1 and frag-offset is 0.
2637 	 * This is 1st fragment of fragmented packet.
2638 	 */
2639 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK))
2640 		return rte_flow_error_set(error, ENOTSUP,
2641 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2642 					  "match on first fragment not "
2643 					  "supported");
2644 	if (frag_data_spec && !last)
2645 		return rte_flow_error_set(error, EINVAL,
2646 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2647 					  "specified value not supported");
2648 	ret = mlx5_flow_item_acceptable
2649 				(item, (const uint8_t *)mask,
2650 				 (const uint8_t *)&nic_mask,
2651 				 sizeof(struct rte_flow_item_ipv6_frag_ext),
2652 				 MLX5_ITEM_RANGE_ACCEPTED, error);
2653 	if (ret)
2654 		return ret;
2655 	/* spec and last are valid, validate the specified range. */
2656 	frag_data_last = last->hdr.frag_data & mask->hdr.frag_data;
2657 	/*
2658 	 * Match on frag_data spec 0x0009 and last 0xfff9
2659 	 * means M is 1 and frag-offset is > 0.
2660 	 * This packet is fragment 2nd and onward, excluding last.
2661 	 * This is not yet supported in MLX5, return appropriate
2662 	 * error message.
2663 	 */
2664 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN |
2665 				       RTE_IPV6_EHDR_MF_MASK) &&
2666 	    frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2667 		return rte_flow_error_set(error, ENOTSUP,
2668 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2669 					  last, "match on following "
2670 					  "fragments not supported");
2671 	/*
2672 	 * Match on frag_data spec 0x0008 and last 0xfff8
2673 	 * means M is 0 and frag-offset is > 0.
2674 	 * This packet is last fragment of fragmented packet.
2675 	 * This is not yet supported in MLX5, return appropriate
2676 	 * error message.
2677 	 */
2678 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) &&
2679 	    frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK))
2680 		return rte_flow_error_set(error, ENOTSUP,
2681 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2682 					  last, "match on last "
2683 					  "fragment not supported");
2684 	/* Other range values are invalid and rejected. */
2685 	return rte_flow_error_set(error, EINVAL,
2686 				  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2687 				  "specified range not supported");
2688 }
2689 
2690 /*
2691  * Validate ASO CT item.
2692  *
2693  * @param[in] dev
2694  *   Pointer to the rte_eth_dev structure.
2695  * @param[in] item
2696  *   Item specification.
2697  * @param[in] item_flags
2698  *   Pointer to bit-fields that holds the items detected until now.
2699  * @param[out] error
2700  *   Pointer to error structure.
2701  *
2702  * @return
2703  *   0 on success, a negative errno value otherwise and rte_errno is set.
2704  */
2705 static int
2706 flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev,
2707 			     const struct rte_flow_item *item,
2708 			     uint64_t *item_flags,
2709 			     struct rte_flow_error *error)
2710 {
2711 	const struct rte_flow_item_conntrack *spec = item->spec;
2712 	const struct rte_flow_item_conntrack *mask = item->mask;
2713 	RTE_SET_USED(dev);
2714 	uint32_t flags;
2715 
2716 	if (*item_flags & MLX5_FLOW_LAYER_ASO_CT)
2717 		return rte_flow_error_set(error, EINVAL,
2718 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2719 					  "Only one CT is supported");
2720 	if (!mask)
2721 		mask = &rte_flow_item_conntrack_mask;
2722 	flags = spec->flags & mask->flags;
2723 	if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) &&
2724 	    ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) ||
2725 	     (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) ||
2726 	     (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)))
2727 		return rte_flow_error_set(error, EINVAL,
2728 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2729 					  "Conflict status bits");
2730 	/* State change also needs to be considered. */
2731 	*item_flags |= MLX5_FLOW_LAYER_ASO_CT;
2732 	return 0;
2733 }
2734 
2735 /**
2736  * Validate the pop VLAN action.
2737  *
2738  * @param[in] dev
2739  *   Pointer to the rte_eth_dev structure.
2740  * @param[in] action_flags
2741  *   Holds the actions detected until now.
2742  * @param[in] action
2743  *   Pointer to the pop vlan action.
2744  * @param[in] item_flags
2745  *   The items found in this flow rule.
2746  * @param[in] attr
2747  *   Pointer to flow attributes.
2748  * @param[out] error
2749  *   Pointer to error structure.
2750  *
2751  * @return
2752  *   0 on success, a negative errno value otherwise and rte_errno is set.
2753  */
2754 static int
2755 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev,
2756 				 uint64_t action_flags,
2757 				 const struct rte_flow_action *action,
2758 				 uint64_t item_flags,
2759 				 const struct rte_flow_attr *attr,
2760 				 struct rte_flow_error *error)
2761 {
2762 	const struct mlx5_priv *priv = dev->data->dev_private;
2763 	struct mlx5_dev_ctx_shared *sh = priv->sh;
2764 	bool direction_error = false;
2765 
2766 	if (!priv->sh->pop_vlan_action)
2767 		return rte_flow_error_set(error, ENOTSUP,
2768 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2769 					  NULL,
2770 					  "pop vlan action is not supported");
2771 	/* Pop VLAN is not supported in egress except for CX6 FDB mode. */
2772 	if (attr->transfer) {
2773 		bool fdb_tx = priv->representor_id != UINT16_MAX;
2774 		bool is_cx5 = sh->steering_format_version ==
2775 		    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
2776 
2777 		if (fdb_tx && is_cx5)
2778 			direction_error = true;
2779 	} else if (attr->egress) {
2780 		direction_error = true;
2781 	}
2782 	if (direction_error)
2783 		return rte_flow_error_set(error, ENOTSUP,
2784 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
2785 					  NULL,
2786 					  "pop vlan action not supported for egress");
2787 	if (action_flags & MLX5_FLOW_VLAN_ACTIONS)
2788 		return rte_flow_error_set(error, ENOTSUP,
2789 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2790 					  "no support for multiple VLAN "
2791 					  "actions");
2792 	/* Pop VLAN with preceding Decap requires inner header with VLAN. */
2793 	if ((action_flags & MLX5_FLOW_ACTION_DECAP) &&
2794 	    !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN))
2795 		return rte_flow_error_set(error, ENOTSUP,
2796 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2797 					  NULL,
2798 					  "cannot pop vlan after decap without "
2799 					  "match on inner vlan in the flow");
2800 	/* Pop VLAN without preceding Decap requires outer header with VLAN. */
2801 	if (!(action_flags & MLX5_FLOW_ACTION_DECAP) &&
2802 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
2803 		return rte_flow_error_set(error, ENOTSUP,
2804 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2805 					  NULL,
2806 					  "cannot pop vlan without a "
2807 					  "match on (outer) vlan in the flow");
2808 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2809 		return rte_flow_error_set(error, EINVAL,
2810 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2811 					  "wrong action order, port_id should "
2812 					  "be after pop VLAN action");
2813 	if (!attr->transfer && priv->representor)
2814 		return rte_flow_error_set(error, ENOTSUP,
2815 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2816 					  "pop vlan action for VF representor "
2817 					  "not supported on NIC table");
2818 	return 0;
2819 }
2820 
2821 /**
2822  * Get VLAN default info from vlan match info.
2823  *
2824  * @param[in] items
2825  *   the list of item specifications.
2826  * @param[out] vlan
2827  *   pointer VLAN info to fill to.
2828  *
2829  * @return
2830  *   0 on success, a negative errno value otherwise and rte_errno is set.
2831  */
2832 static void
2833 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items,
2834 				  struct rte_vlan_hdr *vlan)
2835 {
2836 	const struct rte_flow_item_vlan nic_mask = {
2837 		.tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK |
2838 				MLX5DV_FLOW_VLAN_VID_MASK),
2839 		.inner_type = RTE_BE16(0xffff),
2840 	};
2841 
2842 	if (items == NULL)
2843 		return;
2844 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
2845 		int type = items->type;
2846 
2847 		if (type == RTE_FLOW_ITEM_TYPE_VLAN ||
2848 		    type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN)
2849 			break;
2850 	}
2851 	if (items->type != RTE_FLOW_ITEM_TYPE_END) {
2852 		const struct rte_flow_item_vlan *vlan_m = items->mask;
2853 		const struct rte_flow_item_vlan *vlan_v = items->spec;
2854 
2855 		/* If VLAN item in pattern doesn't contain data, return here. */
2856 		if (!vlan_v)
2857 			return;
2858 		if (!vlan_m)
2859 			vlan_m = &nic_mask;
2860 		/* Only full match values are accepted */
2861 		if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) ==
2862 		     MLX5DV_FLOW_VLAN_PCP_MASK_BE) {
2863 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
2864 			vlan->vlan_tci |=
2865 				rte_be_to_cpu_16(vlan_v->tci &
2866 						 MLX5DV_FLOW_VLAN_PCP_MASK_BE);
2867 		}
2868 		if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) ==
2869 		     MLX5DV_FLOW_VLAN_VID_MASK_BE) {
2870 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
2871 			vlan->vlan_tci |=
2872 				rte_be_to_cpu_16(vlan_v->tci &
2873 						 MLX5DV_FLOW_VLAN_VID_MASK_BE);
2874 		}
2875 		if (vlan_m->inner_type == nic_mask.inner_type)
2876 			vlan->eth_proto = rte_be_to_cpu_16(vlan_v->inner_type &
2877 							   vlan_m->inner_type);
2878 	}
2879 }
2880 
2881 /**
2882  * Validate the push VLAN action.
2883  *
2884  * @param[in] dev
2885  *   Pointer to the rte_eth_dev structure.
2886  * @param[in] action_flags
2887  *   Holds the actions detected until now.
2888  * @param[in] item_flags
2889  *   The items found in this flow rule.
2890  * @param[in] action
2891  *   Pointer to the action structure.
2892  * @param[in] attr
2893  *   Pointer to flow attributes
2894  * @param[out] error
2895  *   Pointer to error structure.
2896  *
2897  * @return
2898  *   0 on success, a negative errno value otherwise and rte_errno is set.
2899  */
2900 static int
2901 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev,
2902 				  uint64_t action_flags,
2903 				  const struct rte_flow_item_vlan *vlan_m,
2904 				  const struct rte_flow_action *action,
2905 				  const struct rte_flow_attr *attr,
2906 				  struct rte_flow_error *error)
2907 {
2908 	const struct rte_flow_action_of_push_vlan *push_vlan = action->conf;
2909 	const struct mlx5_priv *priv = dev->data->dev_private;
2910 	struct mlx5_dev_ctx_shared *sh = priv->sh;
2911 	bool direction_error = false;
2912 
2913 	if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) &&
2914 	    push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ))
2915 		return rte_flow_error_set(error, EINVAL,
2916 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2917 					  "invalid vlan ethertype");
2918 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2919 		return rte_flow_error_set(error, EINVAL,
2920 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2921 					  "wrong action order, port_id should "
2922 					  "be after push VLAN");
2923 	/* Push VLAN is not supported in ingress except for CX6 FDB mode. */
2924 	if (attr->transfer) {
2925 		bool fdb_tx = priv->representor_id != UINT16_MAX;
2926 		bool is_cx5 = sh->steering_format_version ==
2927 		    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
2928 
2929 		if (!fdb_tx && is_cx5)
2930 			direction_error = true;
2931 	} else if (attr->ingress) {
2932 		direction_error = true;
2933 	}
2934 	if (direction_error)
2935 		return rte_flow_error_set(error, ENOTSUP,
2936 					  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
2937 					  NULL,
2938 					  "push vlan action not supported for ingress");
2939 	if (!attr->transfer && priv->representor)
2940 		return rte_flow_error_set(error, ENOTSUP,
2941 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2942 					  "push vlan action for VF representor "
2943 					  "not supported on NIC table");
2944 	if (vlan_m &&
2945 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) &&
2946 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) !=
2947 		MLX5DV_FLOW_VLAN_PCP_MASK_BE &&
2948 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) &&
2949 	    !(mlx5_flow_find_action
2950 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP)))
2951 		return rte_flow_error_set(error, EINVAL,
2952 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2953 					  "not full match mask on VLAN PCP and "
2954 					  "there is no of_set_vlan_pcp action, "
2955 					  "push VLAN action cannot figure out "
2956 					  "PCP value");
2957 	if (vlan_m &&
2958 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) &&
2959 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) !=
2960 		MLX5DV_FLOW_VLAN_VID_MASK_BE &&
2961 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) &&
2962 	    !(mlx5_flow_find_action
2963 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)))
2964 		return rte_flow_error_set(error, EINVAL,
2965 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2966 					  "not full match mask on VLAN VID and "
2967 					  "there is no of_set_vlan_vid action, "
2968 					  "push VLAN action cannot figure out "
2969 					  "VID value");
2970 	(void)attr;
2971 	return 0;
2972 }
2973 
2974 /**
2975  * Validate the set VLAN PCP.
2976  *
2977  * @param[in] action_flags
2978  *   Holds the actions detected until now.
2979  * @param[in] actions
2980  *   Pointer to the list of actions remaining in the flow rule.
2981  * @param[out] error
2982  *   Pointer to error structure.
2983  *
2984  * @return
2985  *   0 on success, a negative errno value otherwise and rte_errno is set.
2986  */
2987 static int
2988 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags,
2989 				     const struct rte_flow_action actions[],
2990 				     struct rte_flow_error *error)
2991 {
2992 	const struct rte_flow_action *action = actions;
2993 	const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf;
2994 
2995 	if (conf->vlan_pcp > 7)
2996 		return rte_flow_error_set(error, EINVAL,
2997 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2998 					  "VLAN PCP value is too big");
2999 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN))
3000 		return rte_flow_error_set(error, ENOTSUP,
3001 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3002 					  "set VLAN PCP action must follow "
3003 					  "the push VLAN action");
3004 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
3005 		return rte_flow_error_set(error, ENOTSUP,
3006 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3007 					  "Multiple VLAN PCP modification are "
3008 					  "not supported");
3009 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
3010 		return rte_flow_error_set(error, EINVAL,
3011 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3012 					  "wrong action order, port_id should "
3013 					  "be after set VLAN PCP");
3014 	return 0;
3015 }
3016 
3017 /**
3018  * Validate the set VLAN VID.
3019  *
3020  * @param[in] item_flags
3021  *   Holds the items detected in this rule.
3022  * @param[in] action_flags
3023  *   Holds the actions detected until now.
3024  * @param[in] actions
3025  *   Pointer to the list of actions remaining in the flow rule.
3026  * @param[out] error
3027  *   Pointer to error structure.
3028  *
3029  * @return
3030  *   0 on success, a negative errno value otherwise and rte_errno is set.
3031  */
3032 static int
3033 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
3034 				     uint64_t action_flags,
3035 				     const struct rte_flow_action actions[],
3036 				     struct rte_flow_error *error)
3037 {
3038 	const struct rte_flow_action *action = actions;
3039 	const struct rte_flow_action_of_set_vlan_vid *conf = action->conf;
3040 
3041 	if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE)
3042 		return rte_flow_error_set(error, EINVAL,
3043 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3044 					  "VLAN VID value is too big");
3045 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) &&
3046 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
3047 		return rte_flow_error_set(error, ENOTSUP,
3048 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3049 					  "set VLAN VID action must follow push"
3050 					  " VLAN action or match on VLAN item");
3051 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID)
3052 		return rte_flow_error_set(error, ENOTSUP,
3053 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3054 					  "Multiple VLAN VID modifications are "
3055 					  "not supported");
3056 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
3057 		return rte_flow_error_set(error, EINVAL,
3058 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3059 					  "wrong action order, port_id should "
3060 					  "be after set VLAN VID");
3061 	return 0;
3062 }
3063 
3064 /*
3065  * Validate the FLAG action.
3066  *
3067  * @param[in] dev
3068  *   Pointer to the rte_eth_dev structure.
3069  * @param[in] action_flags
3070  *   Holds the actions detected until now.
3071  * @param[in] attr
3072  *   Pointer to flow attributes
3073  * @param[out] error
3074  *   Pointer to error structure.
3075  *
3076  * @return
3077  *   0 on success, a negative errno value otherwise and rte_errno is set.
3078  */
3079 static int
3080 flow_dv_validate_action_flag(struct rte_eth_dev *dev,
3081 			     uint64_t action_flags,
3082 			     const struct rte_flow_attr *attr,
3083 			     struct rte_flow_error *error)
3084 {
3085 	struct mlx5_priv *priv = dev->data->dev_private;
3086 	struct mlx5_dev_config *config = &priv->config;
3087 	int ret;
3088 
3089 	/* Fall back if no extended metadata register support. */
3090 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3091 		return mlx5_flow_validate_action_flag(action_flags, attr,
3092 						      error);
3093 	/* Extensive metadata mode requires registers. */
3094 	if (!mlx5_flow_ext_mreg_supported(dev))
3095 		return rte_flow_error_set(error, ENOTSUP,
3096 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3097 					  "no metadata registers "
3098 					  "to support flag action");
3099 	if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT))
3100 		return rte_flow_error_set(error, ENOTSUP,
3101 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3102 					  "extended metadata register"
3103 					  " isn't available");
3104 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3105 	if (ret < 0)
3106 		return ret;
3107 	MLX5_ASSERT(ret > 0);
3108 	if (action_flags & MLX5_FLOW_ACTION_MARK)
3109 		return rte_flow_error_set(error, EINVAL,
3110 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3111 					  "can't mark and flag in same flow");
3112 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
3113 		return rte_flow_error_set(error, EINVAL,
3114 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3115 					  "can't have 2 flag"
3116 					  " actions in same flow");
3117 	return 0;
3118 }
3119 
3120 /**
3121  * Validate MARK action.
3122  *
3123  * @param[in] dev
3124  *   Pointer to the rte_eth_dev structure.
3125  * @param[in] action
3126  *   Pointer to action.
3127  * @param[in] action_flags
3128  *   Holds the actions detected until now.
3129  * @param[in] attr
3130  *   Pointer to flow attributes
3131  * @param[out] error
3132  *   Pointer to error structure.
3133  *
3134  * @return
3135  *   0 on success, a negative errno value otherwise and rte_errno is set.
3136  */
3137 static int
3138 flow_dv_validate_action_mark(struct rte_eth_dev *dev,
3139 			     const struct rte_flow_action *action,
3140 			     uint64_t action_flags,
3141 			     const struct rte_flow_attr *attr,
3142 			     struct rte_flow_error *error)
3143 {
3144 	struct mlx5_priv *priv = dev->data->dev_private;
3145 	struct mlx5_dev_config *config = &priv->config;
3146 	const struct rte_flow_action_mark *mark = action->conf;
3147 	int ret;
3148 
3149 	if (is_tunnel_offload_active(dev))
3150 		return rte_flow_error_set(error, ENOTSUP,
3151 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3152 					  "no mark action "
3153 					  "if tunnel offload active");
3154 	/* Fall back if no extended metadata register support. */
3155 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3156 		return mlx5_flow_validate_action_mark(action, action_flags,
3157 						      attr, error);
3158 	/* Extensive metadata mode requires registers. */
3159 	if (!mlx5_flow_ext_mreg_supported(dev))
3160 		return rte_flow_error_set(error, ENOTSUP,
3161 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3162 					  "no metadata registers "
3163 					  "to support mark action");
3164 	if (!priv->sh->dv_mark_mask)
3165 		return rte_flow_error_set(error, ENOTSUP,
3166 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3167 					  "extended metadata register"
3168 					  " isn't available");
3169 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3170 	if (ret < 0)
3171 		return ret;
3172 	MLX5_ASSERT(ret > 0);
3173 	if (!mark)
3174 		return rte_flow_error_set(error, EINVAL,
3175 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3176 					  "configuration cannot be null");
3177 	if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask))
3178 		return rte_flow_error_set(error, EINVAL,
3179 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
3180 					  &mark->id,
3181 					  "mark id exceeds the limit");
3182 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
3183 		return rte_flow_error_set(error, EINVAL,
3184 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3185 					  "can't flag and mark in same flow");
3186 	if (action_flags & MLX5_FLOW_ACTION_MARK)
3187 		return rte_flow_error_set(error, EINVAL,
3188 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3189 					  "can't have 2 mark actions in same"
3190 					  " flow");
3191 	return 0;
3192 }
3193 
3194 /**
3195  * Validate SET_META action.
3196  *
3197  * @param[in] dev
3198  *   Pointer to the rte_eth_dev structure.
3199  * @param[in] action
3200  *   Pointer to the action structure.
3201  * @param[in] action_flags
3202  *   Holds the actions detected until now.
3203  * @param[in] attr
3204  *   Pointer to flow attributes
3205  * @param[out] error
3206  *   Pointer to error structure.
3207  *
3208  * @return
3209  *   0 on success, a negative errno value otherwise and rte_errno is set.
3210  */
3211 static int
3212 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev,
3213 				 const struct rte_flow_action *action,
3214 				 uint64_t action_flags __rte_unused,
3215 				 const struct rte_flow_attr *attr,
3216 				 struct rte_flow_error *error)
3217 {
3218 	const struct rte_flow_action_set_meta *conf;
3219 	uint32_t nic_mask = UINT32_MAX;
3220 	int reg;
3221 
3222 	if (!mlx5_flow_ext_mreg_supported(dev))
3223 		return rte_flow_error_set(error, ENOTSUP,
3224 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3225 					  "extended metadata register"
3226 					  " isn't supported");
3227 	reg = flow_dv_get_metadata_reg(dev, attr, error);
3228 	if (reg < 0)
3229 		return reg;
3230 	if (reg == REG_NON)
3231 		return rte_flow_error_set(error, ENOTSUP,
3232 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3233 					  "unavalable extended metadata register");
3234 	if (reg != REG_A && reg != REG_B) {
3235 		struct mlx5_priv *priv = dev->data->dev_private;
3236 
3237 		nic_mask = priv->sh->dv_meta_mask;
3238 	}
3239 	if (!(action->conf))
3240 		return rte_flow_error_set(error, EINVAL,
3241 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3242 					  "configuration cannot be null");
3243 	conf = (const struct rte_flow_action_set_meta *)action->conf;
3244 	if (!conf->mask)
3245 		return rte_flow_error_set(error, EINVAL,
3246 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3247 					  "zero mask doesn't have any effect");
3248 	if (conf->mask & ~nic_mask)
3249 		return rte_flow_error_set(error, EINVAL,
3250 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3251 					  "meta data must be within reg C0");
3252 	return 0;
3253 }
3254 
3255 /**
3256  * Validate SET_TAG action.
3257  *
3258  * @param[in] dev
3259  *   Pointer to the rte_eth_dev structure.
3260  * @param[in] action
3261  *   Pointer to the action structure.
3262  * @param[in] action_flags
3263  *   Holds the actions detected until now.
3264  * @param[in] attr
3265  *   Pointer to flow attributes
3266  * @param[out] error
3267  *   Pointer to error structure.
3268  *
3269  * @return
3270  *   0 on success, a negative errno value otherwise and rte_errno is set.
3271  */
3272 static int
3273 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev,
3274 				const struct rte_flow_action *action,
3275 				uint64_t action_flags,
3276 				const struct rte_flow_attr *attr,
3277 				struct rte_flow_error *error)
3278 {
3279 	const struct rte_flow_action_set_tag *conf;
3280 	const uint64_t terminal_action_flags =
3281 		MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE |
3282 		MLX5_FLOW_ACTION_RSS;
3283 	int ret;
3284 
3285 	if (!mlx5_flow_ext_mreg_supported(dev))
3286 		return rte_flow_error_set(error, ENOTSUP,
3287 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3288 					  "extensive metadata register"
3289 					  " isn't supported");
3290 	if (!(action->conf))
3291 		return rte_flow_error_set(error, EINVAL,
3292 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3293 					  "configuration cannot be null");
3294 	conf = (const struct rte_flow_action_set_tag *)action->conf;
3295 	if (!conf->mask)
3296 		return rte_flow_error_set(error, EINVAL,
3297 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3298 					  "zero mask doesn't have any effect");
3299 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
3300 	if (ret < 0)
3301 		return ret;
3302 	if (!attr->transfer && attr->ingress &&
3303 	    (action_flags & terminal_action_flags))
3304 		return rte_flow_error_set(error, EINVAL,
3305 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3306 					  "set_tag has no effect"
3307 					  " with terminal actions");
3308 	return 0;
3309 }
3310 
3311 /**
3312  * Validate count action.
3313  *
3314  * @param[in] dev
3315  *   Pointer to rte_eth_dev structure.
3316  * @param[in] shared
3317  *   Indicator if action is shared.
3318  * @param[in] action_flags
3319  *   Holds the actions detected until now.
3320  * @param[out] error
3321  *   Pointer to error structure.
3322  *
3323  * @return
3324  *   0 on success, a negative errno value otherwise and rte_errno is set.
3325  */
3326 static int
3327 flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared,
3328 			      uint64_t action_flags,
3329 			      struct rte_flow_error *error)
3330 {
3331 	struct mlx5_priv *priv = dev->data->dev_private;
3332 
3333 	if (!priv->config.devx)
3334 		goto notsup_err;
3335 	if (action_flags & MLX5_FLOW_ACTION_COUNT)
3336 		return rte_flow_error_set(error, EINVAL,
3337 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3338 					  "duplicate count actions set");
3339 	if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) &&
3340 	    !priv->sh->flow_hit_aso_en)
3341 		return rte_flow_error_set(error, EINVAL,
3342 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3343 					  "old age and shared count combination is not supported");
3344 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
3345 	return 0;
3346 #endif
3347 notsup_err:
3348 	return rte_flow_error_set
3349 		      (error, ENOTSUP,
3350 		       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3351 		       NULL,
3352 		       "count action not supported");
3353 }
3354 
3355 /**
3356  * Validate the L2 encap action.
3357  *
3358  * @param[in] dev
3359  *   Pointer to the rte_eth_dev structure.
3360  * @param[in] action_flags
3361  *   Holds the actions detected until now.
3362  * @param[in] action
3363  *   Pointer to the action structure.
3364  * @param[in] attr
3365  *   Pointer to flow attributes.
3366  * @param[out] error
3367  *   Pointer to error structure.
3368  *
3369  * @return
3370  *   0 on success, a negative errno value otherwise and rte_errno is set.
3371  */
3372 static int
3373 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev,
3374 				 uint64_t action_flags,
3375 				 const struct rte_flow_action *action,
3376 				 const struct rte_flow_attr *attr,
3377 				 struct rte_flow_error *error)
3378 {
3379 	const struct mlx5_priv *priv = dev->data->dev_private;
3380 
3381 	if (!(action->conf))
3382 		return rte_flow_error_set(error, EINVAL,
3383 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3384 					  "configuration cannot be null");
3385 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3386 		return rte_flow_error_set(error, EINVAL,
3387 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3388 					  "can only have a single encap action "
3389 					  "in a flow");
3390 	if (!attr->transfer && priv->representor)
3391 		return rte_flow_error_set(error, ENOTSUP,
3392 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3393 					  "encap action for VF representor "
3394 					  "not supported on NIC table");
3395 	return 0;
3396 }
3397 
3398 /**
3399  * Validate a decap action.
3400  *
3401  * @param[in] dev
3402  *   Pointer to the rte_eth_dev structure.
3403  * @param[in] action_flags
3404  *   Holds the actions detected until now.
3405  * @param[in] action
3406  *   Pointer to the action structure.
3407  * @param[in] item_flags
3408  *   Holds the items detected.
3409  * @param[in] attr
3410  *   Pointer to flow attributes
3411  * @param[out] error
3412  *   Pointer to error structure.
3413  *
3414  * @return
3415  *   0 on success, a negative errno value otherwise and rte_errno is set.
3416  */
3417 static int
3418 flow_dv_validate_action_decap(struct rte_eth_dev *dev,
3419 			      uint64_t action_flags,
3420 			      const struct rte_flow_action *action,
3421 			      const uint64_t item_flags,
3422 			      const struct rte_flow_attr *attr,
3423 			      struct rte_flow_error *error)
3424 {
3425 	const struct mlx5_priv *priv = dev->data->dev_private;
3426 
3427 	if (priv->config.hca_attr.scatter_fcs_w_decap_disable &&
3428 	    !priv->config.decap_en)
3429 		return rte_flow_error_set(error, ENOTSUP,
3430 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3431 					  "decap is not enabled");
3432 	if (action_flags & MLX5_FLOW_XCAP_ACTIONS)
3433 		return rte_flow_error_set(error, ENOTSUP,
3434 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3435 					  action_flags &
3436 					  MLX5_FLOW_ACTION_DECAP ? "can only "
3437 					  "have a single decap action" : "decap "
3438 					  "after encap is not supported");
3439 	if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
3440 		return rte_flow_error_set(error, EINVAL,
3441 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3442 					  "can't have decap action after"
3443 					  " modify action");
3444 	if (attr->egress)
3445 		return rte_flow_error_set(error, ENOTSUP,
3446 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
3447 					  NULL,
3448 					  "decap action not supported for "
3449 					  "egress");
3450 	if (!attr->transfer && priv->representor)
3451 		return rte_flow_error_set(error, ENOTSUP,
3452 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3453 					  "decap action for VF representor "
3454 					  "not supported on NIC table");
3455 	if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP &&
3456 	    !(item_flags & MLX5_FLOW_LAYER_VXLAN))
3457 		return rte_flow_error_set(error, ENOTSUP,
3458 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3459 				"VXLAN item should be present for VXLAN decap");
3460 	return 0;
3461 }
3462 
3463 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,};
3464 
3465 /**
3466  * Validate the raw encap and decap actions.
3467  *
3468  * @param[in] dev
3469  *   Pointer to the rte_eth_dev structure.
3470  * @param[in] decap
3471  *   Pointer to the decap action.
3472  * @param[in] encap
3473  *   Pointer to the encap action.
3474  * @param[in] attr
3475  *   Pointer to flow attributes
3476  * @param[in/out] action_flags
3477  *   Holds the actions detected until now.
3478  * @param[out] actions_n
3479  *   pointer to the number of actions counter.
3480  * @param[in] action
3481  *   Pointer to the action structure.
3482  * @param[in] item_flags
3483  *   Holds the items detected.
3484  * @param[out] error
3485  *   Pointer to error structure.
3486  *
3487  * @return
3488  *   0 on success, a negative errno value otherwise and rte_errno is set.
3489  */
3490 static int
3491 flow_dv_validate_action_raw_encap_decap
3492 	(struct rte_eth_dev *dev,
3493 	 const struct rte_flow_action_raw_decap *decap,
3494 	 const struct rte_flow_action_raw_encap *encap,
3495 	 const struct rte_flow_attr *attr, uint64_t *action_flags,
3496 	 int *actions_n, const struct rte_flow_action *action,
3497 	 uint64_t item_flags, struct rte_flow_error *error)
3498 {
3499 	const struct mlx5_priv *priv = dev->data->dev_private;
3500 	int ret;
3501 
3502 	if (encap && (!encap->size || !encap->data))
3503 		return rte_flow_error_set(error, EINVAL,
3504 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3505 					  "raw encap data cannot be empty");
3506 	if (decap && encap) {
3507 		if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE &&
3508 		    encap->size > MLX5_ENCAPSULATION_DECISION_SIZE)
3509 			/* L3 encap. */
3510 			decap = NULL;
3511 		else if (encap->size <=
3512 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3513 			   decap->size >
3514 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3515 			/* L3 decap. */
3516 			encap = NULL;
3517 		else if (encap->size >
3518 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3519 			   decap->size >
3520 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3521 			/* 2 L2 actions: encap and decap. */
3522 			;
3523 		else
3524 			return rte_flow_error_set(error,
3525 				ENOTSUP,
3526 				RTE_FLOW_ERROR_TYPE_ACTION,
3527 				NULL, "unsupported too small "
3528 				"raw decap and too small raw "
3529 				"encap combination");
3530 	}
3531 	if (decap) {
3532 		ret = flow_dv_validate_action_decap(dev, *action_flags, action,
3533 						    item_flags, attr, error);
3534 		if (ret < 0)
3535 			return ret;
3536 		*action_flags |= MLX5_FLOW_ACTION_DECAP;
3537 		++(*actions_n);
3538 	}
3539 	if (encap) {
3540 		if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE)
3541 			return rte_flow_error_set(error, ENOTSUP,
3542 						  RTE_FLOW_ERROR_TYPE_ACTION,
3543 						  NULL,
3544 						  "small raw encap size");
3545 		if (*action_flags & MLX5_FLOW_ACTION_ENCAP)
3546 			return rte_flow_error_set(error, EINVAL,
3547 						  RTE_FLOW_ERROR_TYPE_ACTION,
3548 						  NULL,
3549 						  "more than one encap action");
3550 		if (!attr->transfer && priv->representor)
3551 			return rte_flow_error_set
3552 					(error, ENOTSUP,
3553 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3554 					 "encap action for VF representor "
3555 					 "not supported on NIC table");
3556 		*action_flags |= MLX5_FLOW_ACTION_ENCAP;
3557 		++(*actions_n);
3558 	}
3559 	return 0;
3560 }
3561 
3562 /*
3563  * Validate the ASO CT action.
3564  *
3565  * @param[in] dev
3566  *   Pointer to the rte_eth_dev structure.
3567  * @param[in] action_flags
3568  *   Holds the actions detected until now.
3569  * @param[in] item_flags
3570  *   The items found in this flow rule.
3571  * @param[in] attr
3572  *   Pointer to flow attributes.
3573  * @param[out] error
3574  *   Pointer to error structure.
3575  *
3576  * @return
3577  *   0 on success, a negative errno value otherwise and rte_errno is set.
3578  */
3579 static int
3580 flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev,
3581 			       uint64_t action_flags,
3582 			       uint64_t item_flags,
3583 			       const struct rte_flow_attr *attr,
3584 			       struct rte_flow_error *error)
3585 {
3586 	RTE_SET_USED(dev);
3587 
3588 	if (attr->group == 0 && !attr->transfer)
3589 		return rte_flow_error_set(error, ENOTSUP,
3590 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3591 					  NULL,
3592 					  "Only support non-root table");
3593 	if (action_flags & MLX5_FLOW_FATE_ACTIONS)
3594 		return rte_flow_error_set(error, ENOTSUP,
3595 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3596 					  "CT cannot follow a fate action");
3597 	if ((action_flags & MLX5_FLOW_ACTION_METER) ||
3598 	    (action_flags & MLX5_FLOW_ACTION_AGE))
3599 		return rte_flow_error_set(error, EINVAL,
3600 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3601 					  "Only one ASO action is supported");
3602 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3603 		return rte_flow_error_set(error, EINVAL,
3604 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3605 					  "Encap cannot exist before CT");
3606 	if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP))
3607 		return rte_flow_error_set(error, EINVAL,
3608 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3609 					  "Not a outer TCP packet");
3610 	return 0;
3611 }
3612 
3613 int
3614 flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused,
3615 			     struct mlx5_list_entry *entry, void *cb_ctx)
3616 {
3617 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3618 	struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3619 	struct mlx5_flow_dv_encap_decap_resource *resource;
3620 
3621 	resource = container_of(entry, struct mlx5_flow_dv_encap_decap_resource,
3622 				entry);
3623 	if (resource->reformat_type == ctx_resource->reformat_type &&
3624 	    resource->ft_type == ctx_resource->ft_type &&
3625 	    resource->flags == ctx_resource->flags &&
3626 	    resource->size == ctx_resource->size &&
3627 	    !memcmp((const void *)resource->buf,
3628 		    (const void *)ctx_resource->buf,
3629 		    resource->size))
3630 		return 0;
3631 	return -1;
3632 }
3633 
3634 struct mlx5_list_entry *
3635 flow_dv_encap_decap_create_cb(void *tool_ctx, void *cb_ctx)
3636 {
3637 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3638 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3639 	struct mlx5dv_dr_domain *domain;
3640 	struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3641 	struct mlx5_flow_dv_encap_decap_resource *resource;
3642 	uint32_t idx;
3643 	int ret;
3644 
3645 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3646 		domain = sh->fdb_domain;
3647 	else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3648 		domain = sh->rx_domain;
3649 	else
3650 		domain = sh->tx_domain;
3651 	/* Register new encap/decap resource. */
3652 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &idx);
3653 	if (!resource) {
3654 		rte_flow_error_set(ctx->error, ENOMEM,
3655 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3656 				   "cannot allocate resource memory");
3657 		return NULL;
3658 	}
3659 	*resource = *ctx_resource;
3660 	resource->idx = idx;
3661 	ret = mlx5_flow_os_create_flow_action_packet_reformat(sh->ctx, domain,
3662 							      resource,
3663 							     &resource->action);
3664 	if (ret) {
3665 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx);
3666 		rte_flow_error_set(ctx->error, ENOMEM,
3667 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3668 				   NULL, "cannot create action");
3669 		return NULL;
3670 	}
3671 
3672 	return &resource->entry;
3673 }
3674 
3675 struct mlx5_list_entry *
3676 flow_dv_encap_decap_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
3677 			     void *cb_ctx)
3678 {
3679 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3680 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3681 	struct mlx5_flow_dv_encap_decap_resource *cache_resource;
3682 	uint32_t idx;
3683 
3684 	cache_resource = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
3685 					   &idx);
3686 	if (!cache_resource) {
3687 		rte_flow_error_set(ctx->error, ENOMEM,
3688 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3689 				   "cannot allocate resource memory");
3690 		return NULL;
3691 	}
3692 	memcpy(cache_resource, oentry, sizeof(*cache_resource));
3693 	cache_resource->idx = idx;
3694 	return &cache_resource->entry;
3695 }
3696 
3697 void
3698 flow_dv_encap_decap_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3699 {
3700 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3701 	struct mlx5_flow_dv_encap_decap_resource *res =
3702 				       container_of(entry, typeof(*res), entry);
3703 
3704 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
3705 }
3706 
3707 /**
3708  * Find existing encap/decap resource or create and register a new one.
3709  *
3710  * @param[in, out] dev
3711  *   Pointer to rte_eth_dev structure.
3712  * @param[in, out] resource
3713  *   Pointer to encap/decap resource.
3714  * @parm[in, out] dev_flow
3715  *   Pointer to the dev_flow.
3716  * @param[out] error
3717  *   pointer to error structure.
3718  *
3719  * @return
3720  *   0 on success otherwise -errno and errno is set.
3721  */
3722 static int
3723 flow_dv_encap_decap_resource_register
3724 			(struct rte_eth_dev *dev,
3725 			 struct mlx5_flow_dv_encap_decap_resource *resource,
3726 			 struct mlx5_flow *dev_flow,
3727 			 struct rte_flow_error *error)
3728 {
3729 	struct mlx5_priv *priv = dev->data->dev_private;
3730 	struct mlx5_dev_ctx_shared *sh = priv->sh;
3731 	struct mlx5_list_entry *entry;
3732 	union {
3733 		struct {
3734 			uint32_t ft_type:8;
3735 			uint32_t refmt_type:8;
3736 			/*
3737 			 * Header reformat actions can be shared between
3738 			 * non-root tables. One bit to indicate non-root
3739 			 * table or not.
3740 			 */
3741 			uint32_t is_root:1;
3742 			uint32_t reserve:15;
3743 		};
3744 		uint32_t v32;
3745 	} encap_decap_key = {
3746 		{
3747 			.ft_type = resource->ft_type,
3748 			.refmt_type = resource->reformat_type,
3749 			.is_root = !!dev_flow->dv.group,
3750 			.reserve = 0,
3751 		}
3752 	};
3753 	struct mlx5_flow_cb_ctx ctx = {
3754 		.error = error,
3755 		.data = resource,
3756 	};
3757 	struct mlx5_hlist *encaps_decaps;
3758 	uint64_t key64;
3759 
3760 	encaps_decaps = flow_dv_hlist_prepare(sh, &sh->encaps_decaps,
3761 				"encaps_decaps",
3762 				MLX5_FLOW_ENCAP_DECAP_HTABLE_SZ,
3763 				true, true, sh,
3764 				flow_dv_encap_decap_create_cb,
3765 				flow_dv_encap_decap_match_cb,
3766 				flow_dv_encap_decap_remove_cb,
3767 				flow_dv_encap_decap_clone_cb,
3768 				flow_dv_encap_decap_clone_free_cb);
3769 	if (unlikely(!encaps_decaps))
3770 		return -rte_errno;
3771 	resource->flags = dev_flow->dv.group ? 0 : 1;
3772 	key64 =  __rte_raw_cksum(&encap_decap_key.v32,
3773 				 sizeof(encap_decap_key.v32), 0);
3774 	if (resource->reformat_type !=
3775 	    MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 &&
3776 	    resource->size)
3777 		key64 = __rte_raw_cksum(resource->buf, resource->size, key64);
3778 	entry = mlx5_hlist_register(encaps_decaps, key64, &ctx);
3779 	if (!entry)
3780 		return -rte_errno;
3781 	resource = container_of(entry, typeof(*resource), entry);
3782 	dev_flow->dv.encap_decap = resource;
3783 	dev_flow->handle->dvh.rix_encap_decap = resource->idx;
3784 	return 0;
3785 }
3786 
3787 /**
3788  * Find existing table jump resource or create and register a new one.
3789  *
3790  * @param[in, out] dev
3791  *   Pointer to rte_eth_dev structure.
3792  * @param[in, out] tbl
3793  *   Pointer to flow table resource.
3794  * @parm[in, out] dev_flow
3795  *   Pointer to the dev_flow.
3796  * @param[out] error
3797  *   pointer to error structure.
3798  *
3799  * @return
3800  *   0 on success otherwise -errno and errno is set.
3801  */
3802 static int
3803 flow_dv_jump_tbl_resource_register
3804 			(struct rte_eth_dev *dev __rte_unused,
3805 			 struct mlx5_flow_tbl_resource *tbl,
3806 			 struct mlx5_flow *dev_flow,
3807 			 struct rte_flow_error *error __rte_unused)
3808 {
3809 	struct mlx5_flow_tbl_data_entry *tbl_data =
3810 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
3811 
3812 	MLX5_ASSERT(tbl);
3813 	MLX5_ASSERT(tbl_data->jump.action);
3814 	dev_flow->handle->rix_jump = tbl_data->idx;
3815 	dev_flow->dv.jump = &tbl_data->jump;
3816 	return 0;
3817 }
3818 
3819 int
3820 flow_dv_port_id_match_cb(void *tool_ctx __rte_unused,
3821 			 struct mlx5_list_entry *entry, void *cb_ctx)
3822 {
3823 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3824 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3825 	struct mlx5_flow_dv_port_id_action_resource *res =
3826 				       container_of(entry, typeof(*res), entry);
3827 
3828 	return ref->port_id != res->port_id;
3829 }
3830 
3831 struct mlx5_list_entry *
3832 flow_dv_port_id_create_cb(void *tool_ctx, void *cb_ctx)
3833 {
3834 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3835 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3836 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3837 	struct mlx5_flow_dv_port_id_action_resource *resource;
3838 	uint32_t idx;
3839 	int ret;
3840 
3841 	/* Register new port id action resource. */
3842 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3843 	if (!resource) {
3844 		rte_flow_error_set(ctx->error, ENOMEM,
3845 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3846 				   "cannot allocate port_id action memory");
3847 		return NULL;
3848 	}
3849 	*resource = *ref;
3850 	ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain,
3851 							ref->port_id,
3852 							&resource->action);
3853 	if (ret) {
3854 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx);
3855 		rte_flow_error_set(ctx->error, ENOMEM,
3856 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3857 				   "cannot create action");
3858 		return NULL;
3859 	}
3860 	resource->idx = idx;
3861 	return &resource->entry;
3862 }
3863 
3864 struct mlx5_list_entry *
3865 flow_dv_port_id_clone_cb(void *tool_ctx,
3866 			 struct mlx5_list_entry *entry __rte_unused,
3867 			 void *cb_ctx)
3868 {
3869 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3870 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3871 	struct mlx5_flow_dv_port_id_action_resource *resource;
3872 	uint32_t idx;
3873 
3874 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3875 	if (!resource) {
3876 		rte_flow_error_set(ctx->error, ENOMEM,
3877 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3878 				   "cannot allocate port_id action memory");
3879 		return NULL;
3880 	}
3881 	memcpy(resource, entry, sizeof(*resource));
3882 	resource->idx = idx;
3883 	return &resource->entry;
3884 }
3885 
3886 void
3887 flow_dv_port_id_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3888 {
3889 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3890 	struct mlx5_flow_dv_port_id_action_resource *resource =
3891 				  container_of(entry, typeof(*resource), entry);
3892 
3893 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
3894 }
3895 
3896 /**
3897  * Find existing table port ID resource or create and register a new one.
3898  *
3899  * @param[in, out] dev
3900  *   Pointer to rte_eth_dev structure.
3901  * @param[in, out] ref
3902  *   Pointer to port ID action resource reference.
3903  * @parm[in, out] dev_flow
3904  *   Pointer to the dev_flow.
3905  * @param[out] error
3906  *   pointer to error structure.
3907  *
3908  * @return
3909  *   0 on success otherwise -errno and errno is set.
3910  */
3911 static int
3912 flow_dv_port_id_action_resource_register
3913 			(struct rte_eth_dev *dev,
3914 			 struct mlx5_flow_dv_port_id_action_resource *ref,
3915 			 struct mlx5_flow *dev_flow,
3916 			 struct rte_flow_error *error)
3917 {
3918 	struct mlx5_priv *priv = dev->data->dev_private;
3919 	struct mlx5_list_entry *entry;
3920 	struct mlx5_flow_dv_port_id_action_resource *resource;
3921 	struct mlx5_flow_cb_ctx ctx = {
3922 		.error = error,
3923 		.data = ref,
3924 	};
3925 
3926 	entry = mlx5_list_register(priv->sh->port_id_action_list, &ctx);
3927 	if (!entry)
3928 		return -rte_errno;
3929 	resource = container_of(entry, typeof(*resource), entry);
3930 	dev_flow->dv.port_id_action = resource;
3931 	dev_flow->handle->rix_port_id_action = resource->idx;
3932 	return 0;
3933 }
3934 
3935 int
3936 flow_dv_push_vlan_match_cb(void *tool_ctx __rte_unused,
3937 			   struct mlx5_list_entry *entry, void *cb_ctx)
3938 {
3939 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3940 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3941 	struct mlx5_flow_dv_push_vlan_action_resource *res =
3942 				       container_of(entry, typeof(*res), entry);
3943 
3944 	return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type;
3945 }
3946 
3947 struct mlx5_list_entry *
3948 flow_dv_push_vlan_create_cb(void *tool_ctx, void *cb_ctx)
3949 {
3950 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3951 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3952 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3953 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
3954 	struct mlx5dv_dr_domain *domain;
3955 	uint32_t idx;
3956 	int ret;
3957 
3958 	/* Register new port id action resource. */
3959 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
3960 	if (!resource) {
3961 		rte_flow_error_set(ctx->error, ENOMEM,
3962 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3963 				   "cannot allocate push_vlan action memory");
3964 		return NULL;
3965 	}
3966 	*resource = *ref;
3967 	if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3968 		domain = sh->fdb_domain;
3969 	else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3970 		domain = sh->rx_domain;
3971 	else
3972 		domain = sh->tx_domain;
3973 	ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag,
3974 							&resource->action);
3975 	if (ret) {
3976 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
3977 		rte_flow_error_set(ctx->error, ENOMEM,
3978 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3979 				   "cannot create push vlan action");
3980 		return NULL;
3981 	}
3982 	resource->idx = idx;
3983 	return &resource->entry;
3984 }
3985 
3986 struct mlx5_list_entry *
3987 flow_dv_push_vlan_clone_cb(void *tool_ctx,
3988 			   struct mlx5_list_entry *entry __rte_unused,
3989 			   void *cb_ctx)
3990 {
3991 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3992 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3993 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
3994 	uint32_t idx;
3995 
3996 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
3997 	if (!resource) {
3998 		rte_flow_error_set(ctx->error, ENOMEM,
3999 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4000 				   "cannot allocate push_vlan action memory");
4001 		return NULL;
4002 	}
4003 	memcpy(resource, entry, sizeof(*resource));
4004 	resource->idx = idx;
4005 	return &resource->entry;
4006 }
4007 
4008 void
4009 flow_dv_push_vlan_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
4010 {
4011 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
4012 	struct mlx5_flow_dv_push_vlan_action_resource *resource =
4013 				  container_of(entry, typeof(*resource), entry);
4014 
4015 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
4016 }
4017 
4018 /**
4019  * Find existing push vlan resource or create and register a new one.
4020  *
4021  * @param [in, out] dev
4022  *   Pointer to rte_eth_dev structure.
4023  * @param[in, out] ref
4024  *   Pointer to port ID action resource reference.
4025  * @parm[in, out] dev_flow
4026  *   Pointer to the dev_flow.
4027  * @param[out] error
4028  *   pointer to error structure.
4029  *
4030  * @return
4031  *   0 on success otherwise -errno and errno is set.
4032  */
4033 static int
4034 flow_dv_push_vlan_action_resource_register
4035 		       (struct rte_eth_dev *dev,
4036 			struct mlx5_flow_dv_push_vlan_action_resource *ref,
4037 			struct mlx5_flow *dev_flow,
4038 			struct rte_flow_error *error)
4039 {
4040 	struct mlx5_priv *priv = dev->data->dev_private;
4041 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
4042 	struct mlx5_list_entry *entry;
4043 	struct mlx5_flow_cb_ctx ctx = {
4044 		.error = error,
4045 		.data = ref,
4046 	};
4047 
4048 	entry = mlx5_list_register(priv->sh->push_vlan_action_list, &ctx);
4049 	if (!entry)
4050 		return -rte_errno;
4051 	resource = container_of(entry, typeof(*resource), entry);
4052 
4053 	dev_flow->handle->dvh.rix_push_vlan = resource->idx;
4054 	dev_flow->dv.push_vlan_res = resource;
4055 	return 0;
4056 }
4057 
4058 /**
4059  * Get the size of specific rte_flow_item_type hdr size
4060  *
4061  * @param[in] item_type
4062  *   Tested rte_flow_item_type.
4063  *
4064  * @return
4065  *   sizeof struct item_type, 0 if void or irrelevant.
4066  */
4067 static size_t
4068 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type)
4069 {
4070 	size_t retval;
4071 
4072 	switch (item_type) {
4073 	case RTE_FLOW_ITEM_TYPE_ETH:
4074 		retval = sizeof(struct rte_ether_hdr);
4075 		break;
4076 	case RTE_FLOW_ITEM_TYPE_VLAN:
4077 		retval = sizeof(struct rte_vlan_hdr);
4078 		break;
4079 	case RTE_FLOW_ITEM_TYPE_IPV4:
4080 		retval = sizeof(struct rte_ipv4_hdr);
4081 		break;
4082 	case RTE_FLOW_ITEM_TYPE_IPV6:
4083 		retval = sizeof(struct rte_ipv6_hdr);
4084 		break;
4085 	case RTE_FLOW_ITEM_TYPE_UDP:
4086 		retval = sizeof(struct rte_udp_hdr);
4087 		break;
4088 	case RTE_FLOW_ITEM_TYPE_TCP:
4089 		retval = sizeof(struct rte_tcp_hdr);
4090 		break;
4091 	case RTE_FLOW_ITEM_TYPE_VXLAN:
4092 	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4093 		retval = sizeof(struct rte_vxlan_hdr);
4094 		break;
4095 	case RTE_FLOW_ITEM_TYPE_GRE:
4096 	case RTE_FLOW_ITEM_TYPE_NVGRE:
4097 		retval = sizeof(struct rte_gre_hdr);
4098 		break;
4099 	case RTE_FLOW_ITEM_TYPE_MPLS:
4100 		retval = sizeof(struct rte_mpls_hdr);
4101 		break;
4102 	case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */
4103 	default:
4104 		retval = 0;
4105 		break;
4106 	}
4107 	return retval;
4108 }
4109 
4110 #define MLX5_ENCAP_IPV4_VERSION		0x40
4111 #define MLX5_ENCAP_IPV4_IHL_MIN		0x05
4112 #define MLX5_ENCAP_IPV4_TTL_DEF		0x40
4113 #define MLX5_ENCAP_IPV6_VTC_FLOW	0x60000000
4114 #define MLX5_ENCAP_IPV6_HOP_LIMIT	0xff
4115 #define MLX5_ENCAP_VXLAN_FLAGS		0x08000000
4116 #define MLX5_ENCAP_VXLAN_GPE_FLAGS	0x04
4117 
4118 /**
4119  * Convert the encap action data from list of rte_flow_item to raw buffer
4120  *
4121  * @param[in] items
4122  *   Pointer to rte_flow_item objects list.
4123  * @param[out] buf
4124  *   Pointer to the output buffer.
4125  * @param[out] size
4126  *   Pointer to the output buffer size.
4127  * @param[out] error
4128  *   Pointer to the error structure.
4129  *
4130  * @return
4131  *   0 on success, a negative errno value otherwise and rte_errno is set.
4132  */
4133 static int
4134 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf,
4135 			   size_t *size, struct rte_flow_error *error)
4136 {
4137 	struct rte_ether_hdr *eth = NULL;
4138 	struct rte_vlan_hdr *vlan = NULL;
4139 	struct rte_ipv4_hdr *ipv4 = NULL;
4140 	struct rte_ipv6_hdr *ipv6 = NULL;
4141 	struct rte_udp_hdr *udp = NULL;
4142 	struct rte_vxlan_hdr *vxlan = NULL;
4143 	struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL;
4144 	struct rte_gre_hdr *gre = NULL;
4145 	size_t len;
4146 	size_t temp_size = 0;
4147 
4148 	if (!items)
4149 		return rte_flow_error_set(error, EINVAL,
4150 					  RTE_FLOW_ERROR_TYPE_ACTION,
4151 					  NULL, "invalid empty data");
4152 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
4153 		len = flow_dv_get_item_hdr_len(items->type);
4154 		if (len + temp_size > MLX5_ENCAP_MAX_LEN)
4155 			return rte_flow_error_set(error, EINVAL,
4156 						  RTE_FLOW_ERROR_TYPE_ACTION,
4157 						  (void *)items->type,
4158 						  "items total size is too big"
4159 						  " for encap action");
4160 		rte_memcpy((void *)&buf[temp_size], items->spec, len);
4161 		switch (items->type) {
4162 		case RTE_FLOW_ITEM_TYPE_ETH:
4163 			eth = (struct rte_ether_hdr *)&buf[temp_size];
4164 			break;
4165 		case RTE_FLOW_ITEM_TYPE_VLAN:
4166 			vlan = (struct rte_vlan_hdr *)&buf[temp_size];
4167 			if (!eth)
4168 				return rte_flow_error_set(error, EINVAL,
4169 						RTE_FLOW_ERROR_TYPE_ACTION,
4170 						(void *)items->type,
4171 						"eth header not found");
4172 			if (!eth->ether_type)
4173 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN);
4174 			break;
4175 		case RTE_FLOW_ITEM_TYPE_IPV4:
4176 			ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size];
4177 			if (!vlan && !eth)
4178 				return rte_flow_error_set(error, EINVAL,
4179 						RTE_FLOW_ERROR_TYPE_ACTION,
4180 						(void *)items->type,
4181 						"neither eth nor vlan"
4182 						" header found");
4183 			if (vlan && !vlan->eth_proto)
4184 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4185 			else if (eth && !eth->ether_type)
4186 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4187 			if (!ipv4->version_ihl)
4188 				ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION |
4189 						    MLX5_ENCAP_IPV4_IHL_MIN;
4190 			if (!ipv4->time_to_live)
4191 				ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF;
4192 			break;
4193 		case RTE_FLOW_ITEM_TYPE_IPV6:
4194 			ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size];
4195 			if (!vlan && !eth)
4196 				return rte_flow_error_set(error, EINVAL,
4197 						RTE_FLOW_ERROR_TYPE_ACTION,
4198 						(void *)items->type,
4199 						"neither eth nor vlan"
4200 						" header found");
4201 			if (vlan && !vlan->eth_proto)
4202 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4203 			else if (eth && !eth->ether_type)
4204 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4205 			if (!ipv6->vtc_flow)
4206 				ipv6->vtc_flow =
4207 					RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW);
4208 			if (!ipv6->hop_limits)
4209 				ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT;
4210 			break;
4211 		case RTE_FLOW_ITEM_TYPE_UDP:
4212 			udp = (struct rte_udp_hdr *)&buf[temp_size];
4213 			if (!ipv4 && !ipv6)
4214 				return rte_flow_error_set(error, EINVAL,
4215 						RTE_FLOW_ERROR_TYPE_ACTION,
4216 						(void *)items->type,
4217 						"ip header not found");
4218 			if (ipv4 && !ipv4->next_proto_id)
4219 				ipv4->next_proto_id = IPPROTO_UDP;
4220 			else if (ipv6 && !ipv6->proto)
4221 				ipv6->proto = IPPROTO_UDP;
4222 			break;
4223 		case RTE_FLOW_ITEM_TYPE_VXLAN:
4224 			vxlan = (struct rte_vxlan_hdr *)&buf[temp_size];
4225 			if (!udp)
4226 				return rte_flow_error_set(error, EINVAL,
4227 						RTE_FLOW_ERROR_TYPE_ACTION,
4228 						(void *)items->type,
4229 						"udp header not found");
4230 			if (!udp->dst_port)
4231 				udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN);
4232 			if (!vxlan->vx_flags)
4233 				vxlan->vx_flags =
4234 					RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS);
4235 			break;
4236 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4237 			vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size];
4238 			if (!udp)
4239 				return rte_flow_error_set(error, EINVAL,
4240 						RTE_FLOW_ERROR_TYPE_ACTION,
4241 						(void *)items->type,
4242 						"udp header not found");
4243 			if (!vxlan_gpe->proto)
4244 				return rte_flow_error_set(error, EINVAL,
4245 						RTE_FLOW_ERROR_TYPE_ACTION,
4246 						(void *)items->type,
4247 						"next protocol not found");
4248 			if (!udp->dst_port)
4249 				udp->dst_port =
4250 					RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE);
4251 			if (!vxlan_gpe->vx_flags)
4252 				vxlan_gpe->vx_flags =
4253 						MLX5_ENCAP_VXLAN_GPE_FLAGS;
4254 			break;
4255 		case RTE_FLOW_ITEM_TYPE_GRE:
4256 		case RTE_FLOW_ITEM_TYPE_NVGRE:
4257 			gre = (struct rte_gre_hdr *)&buf[temp_size];
4258 			if (!gre->proto)
4259 				return rte_flow_error_set(error, EINVAL,
4260 						RTE_FLOW_ERROR_TYPE_ACTION,
4261 						(void *)items->type,
4262 						"next protocol not found");
4263 			if (!ipv4 && !ipv6)
4264 				return rte_flow_error_set(error, EINVAL,
4265 						RTE_FLOW_ERROR_TYPE_ACTION,
4266 						(void *)items->type,
4267 						"ip header not found");
4268 			if (ipv4 && !ipv4->next_proto_id)
4269 				ipv4->next_proto_id = IPPROTO_GRE;
4270 			else if (ipv6 && !ipv6->proto)
4271 				ipv6->proto = IPPROTO_GRE;
4272 			break;
4273 		case RTE_FLOW_ITEM_TYPE_VOID:
4274 			break;
4275 		default:
4276 			return rte_flow_error_set(error, EINVAL,
4277 						  RTE_FLOW_ERROR_TYPE_ACTION,
4278 						  (void *)items->type,
4279 						  "unsupported item type");
4280 			break;
4281 		}
4282 		temp_size += len;
4283 	}
4284 	*size = temp_size;
4285 	return 0;
4286 }
4287 
4288 static int
4289 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error)
4290 {
4291 	struct rte_ether_hdr *eth = NULL;
4292 	struct rte_vlan_hdr *vlan = NULL;
4293 	struct rte_ipv6_hdr *ipv6 = NULL;
4294 	struct rte_udp_hdr *udp = NULL;
4295 	char *next_hdr;
4296 	uint16_t proto;
4297 
4298 	eth = (struct rte_ether_hdr *)data;
4299 	next_hdr = (char *)(eth + 1);
4300 	proto = RTE_BE16(eth->ether_type);
4301 
4302 	/* VLAN skipping */
4303 	while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) {
4304 		vlan = (struct rte_vlan_hdr *)next_hdr;
4305 		proto = RTE_BE16(vlan->eth_proto);
4306 		next_hdr += sizeof(struct rte_vlan_hdr);
4307 	}
4308 
4309 	/* HW calculates IPv4 csum. no need to proceed */
4310 	if (proto == RTE_ETHER_TYPE_IPV4)
4311 		return 0;
4312 
4313 	/* non IPv4/IPv6 header. not supported */
4314 	if (proto != RTE_ETHER_TYPE_IPV6) {
4315 		return rte_flow_error_set(error, ENOTSUP,
4316 					  RTE_FLOW_ERROR_TYPE_ACTION,
4317 					  NULL, "Cannot offload non IPv4/IPv6");
4318 	}
4319 
4320 	ipv6 = (struct rte_ipv6_hdr *)next_hdr;
4321 
4322 	/* ignore non UDP */
4323 	if (ipv6->proto != IPPROTO_UDP)
4324 		return 0;
4325 
4326 	udp = (struct rte_udp_hdr *)(ipv6 + 1);
4327 	udp->dgram_cksum = 0;
4328 
4329 	return 0;
4330 }
4331 
4332 /**
4333  * Convert L2 encap action to DV specification.
4334  *
4335  * @param[in] dev
4336  *   Pointer to rte_eth_dev structure.
4337  * @param[in] action
4338  *   Pointer to action structure.
4339  * @param[in, out] dev_flow
4340  *   Pointer to the mlx5_flow.
4341  * @param[in] transfer
4342  *   Mark if the flow is E-Switch flow.
4343  * @param[out] error
4344  *   Pointer to the error structure.
4345  *
4346  * @return
4347  *   0 on success, a negative errno value otherwise and rte_errno is set.
4348  */
4349 static int
4350 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev,
4351 			       const struct rte_flow_action *action,
4352 			       struct mlx5_flow *dev_flow,
4353 			       uint8_t transfer,
4354 			       struct rte_flow_error *error)
4355 {
4356 	const struct rte_flow_item *encap_data;
4357 	const struct rte_flow_action_raw_encap *raw_encap_data;
4358 	struct mlx5_flow_dv_encap_decap_resource res = {
4359 		.reformat_type =
4360 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL,
4361 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4362 				      MLX5DV_FLOW_TABLE_TYPE_NIC_TX,
4363 	};
4364 
4365 	if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
4366 		raw_encap_data =
4367 			(const struct rte_flow_action_raw_encap *)action->conf;
4368 		res.size = raw_encap_data->size;
4369 		memcpy(res.buf, raw_encap_data->data, res.size);
4370 	} else {
4371 		if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
4372 			encap_data =
4373 				((const struct rte_flow_action_vxlan_encap *)
4374 						action->conf)->definition;
4375 		else
4376 			encap_data =
4377 				((const struct rte_flow_action_nvgre_encap *)
4378 						action->conf)->definition;
4379 		if (flow_dv_convert_encap_data(encap_data, res.buf,
4380 					       &res.size, error))
4381 			return -rte_errno;
4382 	}
4383 	if (flow_dv_zero_encap_udp_csum(res.buf, error))
4384 		return -rte_errno;
4385 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4386 		return rte_flow_error_set(error, EINVAL,
4387 					  RTE_FLOW_ERROR_TYPE_ACTION,
4388 					  NULL, "can't create L2 encap action");
4389 	return 0;
4390 }
4391 
4392 /**
4393  * Convert L2 decap action to DV specification.
4394  *
4395  * @param[in] dev
4396  *   Pointer to rte_eth_dev structure.
4397  * @param[in, out] dev_flow
4398  *   Pointer to the mlx5_flow.
4399  * @param[in] transfer
4400  *   Mark if the flow is E-Switch flow.
4401  * @param[out] error
4402  *   Pointer to the error structure.
4403  *
4404  * @return
4405  *   0 on success, a negative errno value otherwise and rte_errno is set.
4406  */
4407 static int
4408 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev,
4409 			       struct mlx5_flow *dev_flow,
4410 			       uint8_t transfer,
4411 			       struct rte_flow_error *error)
4412 {
4413 	struct mlx5_flow_dv_encap_decap_resource res = {
4414 		.size = 0,
4415 		.reformat_type =
4416 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2,
4417 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4418 				      MLX5DV_FLOW_TABLE_TYPE_NIC_RX,
4419 	};
4420 
4421 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4422 		return rte_flow_error_set(error, EINVAL,
4423 					  RTE_FLOW_ERROR_TYPE_ACTION,
4424 					  NULL, "can't create L2 decap action");
4425 	return 0;
4426 }
4427 
4428 /**
4429  * Convert raw decap/encap (L3 tunnel) action to DV specification.
4430  *
4431  * @param[in] dev
4432  *   Pointer to rte_eth_dev structure.
4433  * @param[in] action
4434  *   Pointer to action structure.
4435  * @param[in, out] dev_flow
4436  *   Pointer to the mlx5_flow.
4437  * @param[in] attr
4438  *   Pointer to the flow attributes.
4439  * @param[out] error
4440  *   Pointer to the error structure.
4441  *
4442  * @return
4443  *   0 on success, a negative errno value otherwise and rte_errno is set.
4444  */
4445 static int
4446 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
4447 				const struct rte_flow_action *action,
4448 				struct mlx5_flow *dev_flow,
4449 				const struct rte_flow_attr *attr,
4450 				struct rte_flow_error *error)
4451 {
4452 	const struct rte_flow_action_raw_encap *encap_data;
4453 	struct mlx5_flow_dv_encap_decap_resource res;
4454 
4455 	memset(&res, 0, sizeof(res));
4456 	encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
4457 	res.size = encap_data->size;
4458 	memcpy(res.buf, encap_data->data, res.size);
4459 	res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ?
4460 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 :
4461 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
4462 	if (attr->transfer)
4463 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4464 	else
4465 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4466 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4467 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4468 		return rte_flow_error_set(error, EINVAL,
4469 					  RTE_FLOW_ERROR_TYPE_ACTION,
4470 					  NULL, "can't create encap action");
4471 	return 0;
4472 }
4473 
4474 /**
4475  * Create action push VLAN.
4476  *
4477  * @param[in] dev
4478  *   Pointer to rte_eth_dev structure.
4479  * @param[in] attr
4480  *   Pointer to the flow attributes.
4481  * @param[in] vlan
4482  *   Pointer to the vlan to push to the Ethernet header.
4483  * @param[in, out] dev_flow
4484  *   Pointer to the mlx5_flow.
4485  * @param[out] error
4486  *   Pointer to the error structure.
4487  *
4488  * @return
4489  *   0 on success, a negative errno value otherwise and rte_errno is set.
4490  */
4491 static int
4492 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
4493 				const struct rte_flow_attr *attr,
4494 				const struct rte_vlan_hdr *vlan,
4495 				struct mlx5_flow *dev_flow,
4496 				struct rte_flow_error *error)
4497 {
4498 	struct mlx5_flow_dv_push_vlan_action_resource res;
4499 
4500 	memset(&res, 0, sizeof(res));
4501 	res.vlan_tag =
4502 		rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 |
4503 				 vlan->vlan_tci);
4504 	if (attr->transfer)
4505 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4506 	else
4507 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4508 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4509 	return flow_dv_push_vlan_action_resource_register
4510 					    (dev, &res, dev_flow, error);
4511 }
4512 
4513 /**
4514  * Validate the modify-header actions.
4515  *
4516  * @param[in] action_flags
4517  *   Holds the actions detected until now.
4518  * @param[in] action
4519  *   Pointer to the modify action.
4520  * @param[out] error
4521  *   Pointer to error structure.
4522  *
4523  * @return
4524  *   0 on success, a negative errno value otherwise and rte_errno is set.
4525  */
4526 static int
4527 flow_dv_validate_action_modify_hdr(const uint64_t action_flags,
4528 				   const struct rte_flow_action *action,
4529 				   struct rte_flow_error *error)
4530 {
4531 	if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf)
4532 		return rte_flow_error_set(error, EINVAL,
4533 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
4534 					  NULL, "action configuration not set");
4535 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
4536 		return rte_flow_error_set(error, EINVAL,
4537 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4538 					  "can't have encap action before"
4539 					  " modify action");
4540 	return 0;
4541 }
4542 
4543 /**
4544  * Validate the modify-header MAC address actions.
4545  *
4546  * @param[in] action_flags
4547  *   Holds the actions detected until now.
4548  * @param[in] action
4549  *   Pointer to the modify action.
4550  * @param[in] item_flags
4551  *   Holds the items detected.
4552  * @param[out] error
4553  *   Pointer to error structure.
4554  *
4555  * @return
4556  *   0 on success, a negative errno value otherwise and rte_errno is set.
4557  */
4558 static int
4559 flow_dv_validate_action_modify_mac(const uint64_t action_flags,
4560 				   const struct rte_flow_action *action,
4561 				   const uint64_t item_flags,
4562 				   struct rte_flow_error *error)
4563 {
4564 	int ret = 0;
4565 
4566 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4567 	if (!ret) {
4568 		if (!(item_flags & MLX5_FLOW_LAYER_L2))
4569 			return rte_flow_error_set(error, EINVAL,
4570 						  RTE_FLOW_ERROR_TYPE_ACTION,
4571 						  NULL,
4572 						  "no L2 item in pattern");
4573 	}
4574 	return ret;
4575 }
4576 
4577 /**
4578  * Validate the modify-header IPv4 address actions.
4579  *
4580  * @param[in] action_flags
4581  *   Holds the actions detected until now.
4582  * @param[in] action
4583  *   Pointer to the modify action.
4584  * @param[in] item_flags
4585  *   Holds the items detected.
4586  * @param[out] error
4587  *   Pointer to error structure.
4588  *
4589  * @return
4590  *   0 on success, a negative errno value otherwise and rte_errno is set.
4591  */
4592 static int
4593 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags,
4594 				    const struct rte_flow_action *action,
4595 				    const uint64_t item_flags,
4596 				    struct rte_flow_error *error)
4597 {
4598 	int ret = 0;
4599 	uint64_t layer;
4600 
4601 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4602 	if (!ret) {
4603 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4604 				 MLX5_FLOW_LAYER_INNER_L3_IPV4 :
4605 				 MLX5_FLOW_LAYER_OUTER_L3_IPV4;
4606 		if (!(item_flags & layer))
4607 			return rte_flow_error_set(error, EINVAL,
4608 						  RTE_FLOW_ERROR_TYPE_ACTION,
4609 						  NULL,
4610 						  "no ipv4 item in pattern");
4611 	}
4612 	return ret;
4613 }
4614 
4615 /**
4616  * Validate the modify-header IPv6 address actions.
4617  *
4618  * @param[in] action_flags
4619  *   Holds the actions detected until now.
4620  * @param[in] action
4621  *   Pointer to the modify action.
4622  * @param[in] item_flags
4623  *   Holds the items detected.
4624  * @param[out] error
4625  *   Pointer to error structure.
4626  *
4627  * @return
4628  *   0 on success, a negative errno value otherwise and rte_errno is set.
4629  */
4630 static int
4631 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags,
4632 				    const struct rte_flow_action *action,
4633 				    const uint64_t item_flags,
4634 				    struct rte_flow_error *error)
4635 {
4636 	int ret = 0;
4637 	uint64_t layer;
4638 
4639 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4640 	if (!ret) {
4641 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4642 				 MLX5_FLOW_LAYER_INNER_L3_IPV6 :
4643 				 MLX5_FLOW_LAYER_OUTER_L3_IPV6;
4644 		if (!(item_flags & layer))
4645 			return rte_flow_error_set(error, EINVAL,
4646 						  RTE_FLOW_ERROR_TYPE_ACTION,
4647 						  NULL,
4648 						  "no ipv6 item in pattern");
4649 	}
4650 	return ret;
4651 }
4652 
4653 /**
4654  * Validate the modify-header TP actions.
4655  *
4656  * @param[in] action_flags
4657  *   Holds the actions detected until now.
4658  * @param[in] action
4659  *   Pointer to the modify action.
4660  * @param[in] item_flags
4661  *   Holds the items detected.
4662  * @param[out] error
4663  *   Pointer to error structure.
4664  *
4665  * @return
4666  *   0 on success, a negative errno value otherwise and rte_errno is set.
4667  */
4668 static int
4669 flow_dv_validate_action_modify_tp(const uint64_t action_flags,
4670 				  const struct rte_flow_action *action,
4671 				  const uint64_t item_flags,
4672 				  struct rte_flow_error *error)
4673 {
4674 	int ret = 0;
4675 	uint64_t layer;
4676 
4677 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4678 	if (!ret) {
4679 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4680 				 MLX5_FLOW_LAYER_INNER_L4 :
4681 				 MLX5_FLOW_LAYER_OUTER_L4;
4682 		if (!(item_flags & layer))
4683 			return rte_flow_error_set(error, EINVAL,
4684 						  RTE_FLOW_ERROR_TYPE_ACTION,
4685 						  NULL, "no transport layer "
4686 						  "in pattern");
4687 	}
4688 	return ret;
4689 }
4690 
4691 /**
4692  * Validate the modify-header actions of increment/decrement
4693  * TCP Sequence-number.
4694  *
4695  * @param[in] action_flags
4696  *   Holds the actions detected until now.
4697  * @param[in] action
4698  *   Pointer to the modify action.
4699  * @param[in] item_flags
4700  *   Holds the items detected.
4701  * @param[out] error
4702  *   Pointer to error structure.
4703  *
4704  * @return
4705  *   0 on success, a negative errno value otherwise and rte_errno is set.
4706  */
4707 static int
4708 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags,
4709 				       const struct rte_flow_action *action,
4710 				       const uint64_t item_flags,
4711 				       struct rte_flow_error *error)
4712 {
4713 	int ret = 0;
4714 	uint64_t layer;
4715 
4716 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4717 	if (!ret) {
4718 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4719 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4720 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4721 		if (!(item_flags & layer))
4722 			return rte_flow_error_set(error, EINVAL,
4723 						  RTE_FLOW_ERROR_TYPE_ACTION,
4724 						  NULL, "no TCP item in"
4725 						  " pattern");
4726 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ &&
4727 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) ||
4728 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ &&
4729 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ)))
4730 			return rte_flow_error_set(error, EINVAL,
4731 						  RTE_FLOW_ERROR_TYPE_ACTION,
4732 						  NULL,
4733 						  "cannot decrease and increase"
4734 						  " TCP sequence number"
4735 						  " at the same time");
4736 	}
4737 	return ret;
4738 }
4739 
4740 /**
4741  * Validate the modify-header actions of increment/decrement
4742  * TCP Acknowledgment number.
4743  *
4744  * @param[in] action_flags
4745  *   Holds the actions detected until now.
4746  * @param[in] action
4747  *   Pointer to the modify action.
4748  * @param[in] item_flags
4749  *   Holds the items detected.
4750  * @param[out] error
4751  *   Pointer to error structure.
4752  *
4753  * @return
4754  *   0 on success, a negative errno value otherwise and rte_errno is set.
4755  */
4756 static int
4757 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags,
4758 				       const struct rte_flow_action *action,
4759 				       const uint64_t item_flags,
4760 				       struct rte_flow_error *error)
4761 {
4762 	int ret = 0;
4763 	uint64_t layer;
4764 
4765 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4766 	if (!ret) {
4767 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4768 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4769 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4770 		if (!(item_flags & layer))
4771 			return rte_flow_error_set(error, EINVAL,
4772 						  RTE_FLOW_ERROR_TYPE_ACTION,
4773 						  NULL, "no TCP item in"
4774 						  " pattern");
4775 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK &&
4776 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) ||
4777 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK &&
4778 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK)))
4779 			return rte_flow_error_set(error, EINVAL,
4780 						  RTE_FLOW_ERROR_TYPE_ACTION,
4781 						  NULL,
4782 						  "cannot decrease and increase"
4783 						  " TCP acknowledgment number"
4784 						  " at the same time");
4785 	}
4786 	return ret;
4787 }
4788 
4789 /**
4790  * Validate the modify-header TTL actions.
4791  *
4792  * @param[in] action_flags
4793  *   Holds the actions detected until now.
4794  * @param[in] action
4795  *   Pointer to the modify action.
4796  * @param[in] item_flags
4797  *   Holds the items detected.
4798  * @param[out] error
4799  *   Pointer to error structure.
4800  *
4801  * @return
4802  *   0 on success, a negative errno value otherwise and rte_errno is set.
4803  */
4804 static int
4805 flow_dv_validate_action_modify_ttl(const uint64_t action_flags,
4806 				   const struct rte_flow_action *action,
4807 				   const uint64_t item_flags,
4808 				   struct rte_flow_error *error)
4809 {
4810 	int ret = 0;
4811 	uint64_t layer;
4812 
4813 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4814 	if (!ret) {
4815 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4816 				 MLX5_FLOW_LAYER_INNER_L3 :
4817 				 MLX5_FLOW_LAYER_OUTER_L3;
4818 		if (!(item_flags & layer))
4819 			return rte_flow_error_set(error, EINVAL,
4820 						  RTE_FLOW_ERROR_TYPE_ACTION,
4821 						  NULL,
4822 						  "no IP protocol in pattern");
4823 	}
4824 	return ret;
4825 }
4826 
4827 /**
4828  * Validate the generic modify field actions.
4829  * @param[in] dev
4830  *   Pointer to the rte_eth_dev structure.
4831  * @param[in] action_flags
4832  *   Holds the actions detected until now.
4833  * @param[in] action
4834  *   Pointer to the modify action.
4835  * @param[in] attr
4836  *   Pointer to the flow attributes.
4837  * @param[out] error
4838  *   Pointer to error structure.
4839  *
4840  * @return
4841  *   Number of header fields to modify (0 or more) on success,
4842  *   a negative errno value otherwise and rte_errno is set.
4843  */
4844 static int
4845 flow_dv_validate_action_modify_field(struct rte_eth_dev *dev,
4846 				   const uint64_t action_flags,
4847 				   const struct rte_flow_action *action,
4848 				   const struct rte_flow_attr *attr,
4849 				   struct rte_flow_error *error)
4850 {
4851 	int ret = 0;
4852 	struct mlx5_priv *priv = dev->data->dev_private;
4853 	struct mlx5_dev_config *config = &priv->config;
4854 	const struct rte_flow_action_modify_field *action_modify_field =
4855 		action->conf;
4856 	uint32_t dst_width = mlx5_flow_item_field_width(priv,
4857 				action_modify_field->dst.field);
4858 	uint32_t src_width = mlx5_flow_item_field_width(priv,
4859 				action_modify_field->src.field);
4860 
4861 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4862 	if (ret)
4863 		return ret;
4864 
4865 	if (action_modify_field->width == 0)
4866 		return rte_flow_error_set(error, EINVAL,
4867 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4868 				"no bits are requested to be modified");
4869 	else if (action_modify_field->width > dst_width ||
4870 		 action_modify_field->width > src_width)
4871 		return rte_flow_error_set(error, EINVAL,
4872 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4873 				"cannot modify more bits than"
4874 				" the width of a field");
4875 	if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE &&
4876 	    action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) {
4877 		if ((action_modify_field->dst.offset +
4878 		     action_modify_field->width > dst_width) ||
4879 		    (action_modify_field->dst.offset % 32))
4880 			return rte_flow_error_set(error, EINVAL,
4881 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4882 					"destination offset is too big"
4883 					" or not aligned to 4 bytes");
4884 		if (action_modify_field->dst.level &&
4885 		    action_modify_field->dst.field != RTE_FLOW_FIELD_TAG)
4886 			return rte_flow_error_set(error, ENOTSUP,
4887 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4888 					"inner header fields modification"
4889 					" is not supported");
4890 	}
4891 	if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE &&
4892 	    action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) {
4893 		if (!attr->transfer && !attr->group)
4894 			return rte_flow_error_set(error, ENOTSUP,
4895 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4896 					"modify field action is not"
4897 					" supported for group 0");
4898 		if ((action_modify_field->src.offset +
4899 		     action_modify_field->width > src_width) ||
4900 		    (action_modify_field->src.offset % 32))
4901 			return rte_flow_error_set(error, EINVAL,
4902 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4903 					"source offset is too big"
4904 					" or not aligned to 4 bytes");
4905 		if (action_modify_field->src.level &&
4906 		    action_modify_field->src.field != RTE_FLOW_FIELD_TAG)
4907 			return rte_flow_error_set(error, ENOTSUP,
4908 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4909 					"inner header fields modification"
4910 					" is not supported");
4911 	}
4912 	if ((action_modify_field->dst.field ==
4913 	     action_modify_field->src.field) &&
4914 	    (action_modify_field->dst.level ==
4915 	     action_modify_field->src.level))
4916 		return rte_flow_error_set(error, EINVAL,
4917 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4918 				"source and destination fields"
4919 				" cannot be the same");
4920 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE ||
4921 	    action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER ||
4922 	    action_modify_field->dst.field == RTE_FLOW_FIELD_MARK)
4923 		return rte_flow_error_set(error, EINVAL,
4924 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4925 				"mark, immediate value or a pointer to it"
4926 				" cannot be used as a destination");
4927 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_START ||
4928 	    action_modify_field->src.field == RTE_FLOW_FIELD_START)
4929 		return rte_flow_error_set(error, ENOTSUP,
4930 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4931 				"modifications of an arbitrary"
4932 				" place in a packet is not supported");
4933 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VLAN_TYPE ||
4934 	    action_modify_field->src.field == RTE_FLOW_FIELD_VLAN_TYPE)
4935 		return rte_flow_error_set(error, ENOTSUP,
4936 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4937 				"modifications of the 802.1Q Tag"
4938 				" Identifier is not supported");
4939 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VXLAN_VNI ||
4940 	    action_modify_field->src.field == RTE_FLOW_FIELD_VXLAN_VNI)
4941 		return rte_flow_error_set(error, ENOTSUP,
4942 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4943 				"modifications of the VXLAN Network"
4944 				" Identifier is not supported");
4945 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_GENEVE_VNI ||
4946 	    action_modify_field->src.field == RTE_FLOW_FIELD_GENEVE_VNI)
4947 		return rte_flow_error_set(error, ENOTSUP,
4948 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4949 				"modifications of the GENEVE Network"
4950 				" Identifier is not supported");
4951 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_MARK ||
4952 	    action_modify_field->src.field == RTE_FLOW_FIELD_MARK ||
4953 	    action_modify_field->dst.field == RTE_FLOW_FIELD_META ||
4954 	    action_modify_field->src.field == RTE_FLOW_FIELD_META) {
4955 		if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||
4956 		    !mlx5_flow_ext_mreg_supported(dev))
4957 			return rte_flow_error_set(error, ENOTSUP,
4958 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4959 					"cannot modify mark or metadata without"
4960 					" extended metadata register support");
4961 	}
4962 	if (action_modify_field->operation != RTE_FLOW_MODIFY_SET)
4963 		return rte_flow_error_set(error, ENOTSUP,
4964 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4965 				"add and sub operations"
4966 				" are not supported");
4967 	return (action_modify_field->width / 32) +
4968 	       !!(action_modify_field->width % 32);
4969 }
4970 
4971 /**
4972  * Validate jump action.
4973  *
4974  * @param[in] action
4975  *   Pointer to the jump action.
4976  * @param[in] action_flags
4977  *   Holds the actions detected until now.
4978  * @param[in] attributes
4979  *   Pointer to flow attributes
4980  * @param[in] external
4981  *   Action belongs to flow rule created by request external to PMD.
4982  * @param[out] error
4983  *   Pointer to error structure.
4984  *
4985  * @return
4986  *   0 on success, a negative errno value otherwise and rte_errno is set.
4987  */
4988 static int
4989 flow_dv_validate_action_jump(struct rte_eth_dev *dev,
4990 			     const struct mlx5_flow_tunnel *tunnel,
4991 			     const struct rte_flow_action *action,
4992 			     uint64_t action_flags,
4993 			     const struct rte_flow_attr *attributes,
4994 			     bool external, struct rte_flow_error *error)
4995 {
4996 	uint32_t target_group, table;
4997 	int ret = 0;
4998 	struct flow_grp_info grp_info = {
4999 		.external = !!external,
5000 		.transfer = !!attributes->transfer,
5001 		.fdb_def_rule = 1,
5002 		.std_tbl_fix = 0
5003 	};
5004 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
5005 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
5006 		return rte_flow_error_set(error, EINVAL,
5007 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5008 					  "can't have 2 fate actions in"
5009 					  " same flow");
5010 	if (!action->conf)
5011 		return rte_flow_error_set(error, EINVAL,
5012 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5013 					  NULL, "action configuration not set");
5014 	target_group =
5015 		((const struct rte_flow_action_jump *)action->conf)->group;
5016 	ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table,
5017 				       &grp_info, error);
5018 	if (ret)
5019 		return ret;
5020 	if (attributes->group == target_group &&
5021 	    !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET |
5022 			      MLX5_FLOW_ACTION_TUNNEL_MATCH)))
5023 		return rte_flow_error_set(error, EINVAL,
5024 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5025 					  "target group must be other than"
5026 					  " the current flow group");
5027 	return 0;
5028 }
5029 
5030 /*
5031  * Validate the port_id action.
5032  *
5033  * @param[in] dev
5034  *   Pointer to rte_eth_dev structure.
5035  * @param[in] action_flags
5036  *   Bit-fields that holds the actions detected until now.
5037  * @param[in] action
5038  *   Port_id RTE action structure.
5039  * @param[in] attr
5040  *   Attributes of flow that includes this action.
5041  * @param[out] error
5042  *   Pointer to error structure.
5043  *
5044  * @return
5045  *   0 on success, a negative errno value otherwise and rte_errno is set.
5046  */
5047 static int
5048 flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
5049 				uint64_t action_flags,
5050 				const struct rte_flow_action *action,
5051 				const struct rte_flow_attr *attr,
5052 				struct rte_flow_error *error)
5053 {
5054 	const struct rte_flow_action_port_id *port_id;
5055 	struct mlx5_priv *act_priv;
5056 	struct mlx5_priv *dev_priv;
5057 	uint16_t port;
5058 
5059 	if (!attr->transfer)
5060 		return rte_flow_error_set(error, ENOTSUP,
5061 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5062 					  NULL,
5063 					  "port id action is valid in transfer"
5064 					  " mode only");
5065 	if (!action || !action->conf)
5066 		return rte_flow_error_set(error, ENOTSUP,
5067 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5068 					  NULL,
5069 					  "port id action parameters must be"
5070 					  " specified");
5071 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
5072 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
5073 		return rte_flow_error_set(error, EINVAL,
5074 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5075 					  "can have only one fate actions in"
5076 					  " a flow");
5077 	dev_priv = mlx5_dev_to_eswitch_info(dev);
5078 	if (!dev_priv)
5079 		return rte_flow_error_set(error, rte_errno,
5080 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5081 					  NULL,
5082 					  "failed to obtain E-Switch info");
5083 	port_id = action->conf;
5084 	port = port_id->original ? dev->data->port_id : port_id->id;
5085 	act_priv = mlx5_port_to_eswitch_info(port, false);
5086 	if (!act_priv)
5087 		return rte_flow_error_set
5088 				(error, rte_errno,
5089 				 RTE_FLOW_ERROR_TYPE_ACTION_CONF, port_id,
5090 				 "failed to obtain E-Switch port id for port");
5091 	if (act_priv->domain_id != dev_priv->domain_id)
5092 		return rte_flow_error_set
5093 				(error, EINVAL,
5094 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5095 				 "port does not belong to"
5096 				 " E-Switch being configured");
5097 	return 0;
5098 }
5099 
5100 /**
5101  * Get the maximum number of modify header actions.
5102  *
5103  * @param dev
5104  *   Pointer to rte_eth_dev structure.
5105  * @param root
5106  *   Whether action is on root table.
5107  *
5108  * @return
5109  *   Max number of modify header actions device can support.
5110  */
5111 static inline unsigned int
5112 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused,
5113 			      bool root)
5114 {
5115 	/*
5116 	 * There's no way to directly query the max capacity from FW.
5117 	 * The maximal value on root table should be assumed to be supported.
5118 	 */
5119 	if (!root)
5120 		return MLX5_MAX_MODIFY_NUM;
5121 	else
5122 		return MLX5_ROOT_TBL_MODIFY_NUM;
5123 }
5124 
5125 /**
5126  * Validate the meter action.
5127  *
5128  * @param[in] dev
5129  *   Pointer to rte_eth_dev structure.
5130  * @param[in] action_flags
5131  *   Bit-fields that holds the actions detected until now.
5132  * @param[in] action
5133  *   Pointer to the meter action.
5134  * @param[in] attr
5135  *   Attributes of flow that includes this action.
5136  * @param[in] port_id_item
5137  *   Pointer to item indicating port id.
5138  * @param[out] error
5139  *   Pointer to error structure.
5140  *
5141  * @return
5142  *   0 on success, a negative errno value otherwise and rte_ernno is set.
5143  */
5144 static int
5145 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
5146 				uint64_t action_flags,
5147 				const struct rte_flow_action *action,
5148 				const struct rte_flow_attr *attr,
5149 				const struct rte_flow_item *port_id_item,
5150 				bool *def_policy,
5151 				struct rte_flow_error *error)
5152 {
5153 	struct mlx5_priv *priv = dev->data->dev_private;
5154 	const struct rte_flow_action_meter *am = action->conf;
5155 	struct mlx5_flow_meter_info *fm;
5156 	struct mlx5_flow_meter_policy *mtr_policy;
5157 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
5158 
5159 	if (!am)
5160 		return rte_flow_error_set(error, EINVAL,
5161 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5162 					  "meter action conf is NULL");
5163 
5164 	if (action_flags & MLX5_FLOW_ACTION_METER)
5165 		return rte_flow_error_set(error, ENOTSUP,
5166 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5167 					  "meter chaining not support");
5168 	if (action_flags & MLX5_FLOW_ACTION_JUMP)
5169 		return rte_flow_error_set(error, ENOTSUP,
5170 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5171 					  "meter with jump not support");
5172 	if (!priv->mtr_en)
5173 		return rte_flow_error_set(error, ENOTSUP,
5174 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5175 					  NULL,
5176 					  "meter action not supported");
5177 	fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL);
5178 	if (!fm)
5179 		return rte_flow_error_set(error, EINVAL,
5180 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5181 					  "Meter not found");
5182 	/* aso meter can always be shared by different domains */
5183 	if (fm->ref_cnt && !priv->sh->meter_aso_en &&
5184 	    !(fm->transfer == attr->transfer ||
5185 	      (!fm->ingress && !attr->ingress && attr->egress) ||
5186 	      (!fm->egress && !attr->egress && attr->ingress)))
5187 		return rte_flow_error_set(error, EINVAL,
5188 			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5189 			"Flow attributes domain are either invalid "
5190 			"or have a domain conflict with current "
5191 			"meter attributes");
5192 	if (fm->def_policy) {
5193 		if (!((attr->transfer &&
5194 			mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
5195 			(attr->egress &&
5196 			mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
5197 			(attr->ingress &&
5198 			mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
5199 			return rte_flow_error_set(error, EINVAL,
5200 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5201 					  "Flow attributes domain "
5202 					  "have a conflict with current "
5203 					  "meter domain attributes");
5204 		*def_policy = true;
5205 	} else {
5206 		mtr_policy = mlx5_flow_meter_policy_find(dev,
5207 						fm->policy_id, NULL);
5208 		if (!mtr_policy)
5209 			return rte_flow_error_set(error, EINVAL,
5210 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5211 					  "Invalid policy id for meter ");
5212 		if (!((attr->transfer && mtr_policy->transfer) ||
5213 			(attr->egress && mtr_policy->egress) ||
5214 			(attr->ingress && mtr_policy->ingress)))
5215 			return rte_flow_error_set(error, EINVAL,
5216 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5217 					  "Flow attributes domain "
5218 					  "have a conflict with current "
5219 					  "meter domain attributes");
5220 		if (attr->transfer && mtr_policy->dev) {
5221 			/**
5222 			 * When policy has fate action of port_id,
5223 			 * the flow should have the same src port as policy.
5224 			 */
5225 			struct mlx5_priv *policy_port_priv =
5226 					mtr_policy->dev->data->dev_private;
5227 			int32_t flow_src_port = priv->representor_id;
5228 
5229 			if (port_id_item) {
5230 				const struct rte_flow_item_port_id *spec =
5231 							port_id_item->spec;
5232 				struct mlx5_priv *port_priv =
5233 					mlx5_port_to_eswitch_info(spec->id,
5234 								  false);
5235 				if (!port_priv)
5236 					return rte_flow_error_set(error,
5237 						rte_errno,
5238 						RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
5239 						spec,
5240 						"Failed to get port info.");
5241 				flow_src_port = port_priv->representor_id;
5242 			}
5243 			if (flow_src_port != policy_port_priv->representor_id)
5244 				return rte_flow_error_set(error,
5245 						rte_errno,
5246 						RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
5247 						NULL,
5248 						"Flow and meter policy "
5249 						"have different src port.");
5250 		}
5251 		*def_policy = false;
5252 	}
5253 	return 0;
5254 }
5255 
5256 /**
5257  * Validate the age action.
5258  *
5259  * @param[in] action_flags
5260  *   Holds the actions detected until now.
5261  * @param[in] action
5262  *   Pointer to the age action.
5263  * @param[in] dev
5264  *   Pointer to the Ethernet device structure.
5265  * @param[out] error
5266  *   Pointer to error structure.
5267  *
5268  * @return
5269  *   0 on success, a negative errno value otherwise and rte_errno is set.
5270  */
5271 static int
5272 flow_dv_validate_action_age(uint64_t action_flags,
5273 			    const struct rte_flow_action *action,
5274 			    struct rte_eth_dev *dev,
5275 			    struct rte_flow_error *error)
5276 {
5277 	struct mlx5_priv *priv = dev->data->dev_private;
5278 	const struct rte_flow_action_age *age = action->conf;
5279 
5280 	if (!priv->config.devx || (priv->sh->cmng.counter_fallback &&
5281 	    !priv->sh->aso_age_mng))
5282 		return rte_flow_error_set(error, ENOTSUP,
5283 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5284 					  NULL,
5285 					  "age action not supported");
5286 	if (!(action->conf))
5287 		return rte_flow_error_set(error, EINVAL,
5288 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5289 					  "configuration cannot be null");
5290 	if (!(age->timeout))
5291 		return rte_flow_error_set(error, EINVAL,
5292 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5293 					  "invalid timeout value 0");
5294 	if (action_flags & MLX5_FLOW_ACTION_AGE)
5295 		return rte_flow_error_set(error, EINVAL,
5296 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5297 					  "duplicate age actions set");
5298 	return 0;
5299 }
5300 
5301 /**
5302  * Validate the modify-header IPv4 DSCP actions.
5303  *
5304  * @param[in] action_flags
5305  *   Holds the actions detected until now.
5306  * @param[in] action
5307  *   Pointer to the modify action.
5308  * @param[in] item_flags
5309  *   Holds the items detected.
5310  * @param[out] error
5311  *   Pointer to error structure.
5312  *
5313  * @return
5314  *   0 on success, a negative errno value otherwise and rte_errno is set.
5315  */
5316 static int
5317 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags,
5318 					 const struct rte_flow_action *action,
5319 					 const uint64_t item_flags,
5320 					 struct rte_flow_error *error)
5321 {
5322 	int ret = 0;
5323 
5324 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5325 	if (!ret) {
5326 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4))
5327 			return rte_flow_error_set(error, EINVAL,
5328 						  RTE_FLOW_ERROR_TYPE_ACTION,
5329 						  NULL,
5330 						  "no ipv4 item in pattern");
5331 	}
5332 	return ret;
5333 }
5334 
5335 /**
5336  * Validate the modify-header IPv6 DSCP actions.
5337  *
5338  * @param[in] action_flags
5339  *   Holds the actions detected until now.
5340  * @param[in] action
5341  *   Pointer to the modify action.
5342  * @param[in] item_flags
5343  *   Holds the items detected.
5344  * @param[out] error
5345  *   Pointer to error structure.
5346  *
5347  * @return
5348  *   0 on success, a negative errno value otherwise and rte_errno is set.
5349  */
5350 static int
5351 flow_dv_validate_action_modify_ipv6_dscp(const uint64_t action_flags,
5352 					 const struct rte_flow_action *action,
5353 					 const uint64_t item_flags,
5354 					 struct rte_flow_error *error)
5355 {
5356 	int ret = 0;
5357 
5358 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5359 	if (!ret) {
5360 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6))
5361 			return rte_flow_error_set(error, EINVAL,
5362 						  RTE_FLOW_ERROR_TYPE_ACTION,
5363 						  NULL,
5364 						  "no ipv6 item in pattern");
5365 	}
5366 	return ret;
5367 }
5368 
5369 int
5370 flow_dv_modify_match_cb(void *tool_ctx __rte_unused,
5371 			struct mlx5_list_entry *entry, void *cb_ctx)
5372 {
5373 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5374 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5375 	struct mlx5_flow_dv_modify_hdr_resource *resource =
5376 				  container_of(entry, typeof(*resource), entry);
5377 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5378 
5379 	key_len += ref->actions_num * sizeof(ref->actions[0]);
5380 	return ref->actions_num != resource->actions_num ||
5381 	       memcmp(&ref->ft_type, &resource->ft_type, key_len);
5382 }
5383 
5384 static struct mlx5_indexed_pool *
5385 flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index)
5386 {
5387 	struct mlx5_indexed_pool *ipool = __atomic_load_n
5388 				     (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST);
5389 
5390 	if (!ipool) {
5391 		struct mlx5_indexed_pool *expected = NULL;
5392 		struct mlx5_indexed_pool_config cfg =
5393 		    (struct mlx5_indexed_pool_config) {
5394 		       .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
5395 								   (index + 1) *
5396 					   sizeof(struct mlx5_modification_cmd),
5397 		       .trunk_size = 64,
5398 		       .grow_trunk = 3,
5399 		       .grow_shift = 2,
5400 		       .need_lock = 1,
5401 		       .release_mem_en = !!sh->reclaim_mode,
5402 		       .per_core_cache = sh->reclaim_mode ? 0 : (1 << 16),
5403 		       .malloc = mlx5_malloc,
5404 		       .free = mlx5_free,
5405 		       .type = "mlx5_modify_action_resource",
5406 		};
5407 
5408 		cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool));
5409 		ipool = mlx5_ipool_create(&cfg);
5410 		if (!ipool)
5411 			return NULL;
5412 		if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index],
5413 						 &expected, ipool, false,
5414 						 __ATOMIC_SEQ_CST,
5415 						 __ATOMIC_SEQ_CST)) {
5416 			mlx5_ipool_destroy(ipool);
5417 			ipool = __atomic_load_n(&sh->mdh_ipools[index],
5418 						__ATOMIC_SEQ_CST);
5419 		}
5420 	}
5421 	return ipool;
5422 }
5423 
5424 struct mlx5_list_entry *
5425 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx)
5426 {
5427 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5428 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5429 	struct mlx5dv_dr_domain *ns;
5430 	struct mlx5_flow_dv_modify_hdr_resource *entry;
5431 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5432 	struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh,
5433 							  ref->actions_num - 1);
5434 	int ret;
5435 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5436 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5437 	uint32_t idx;
5438 
5439 	if (unlikely(!ipool)) {
5440 		rte_flow_error_set(ctx->error, ENOMEM,
5441 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5442 				   NULL, "cannot allocate modify ipool");
5443 		return NULL;
5444 	}
5445 	entry = mlx5_ipool_zmalloc(ipool, &idx);
5446 	if (!entry) {
5447 		rte_flow_error_set(ctx->error, ENOMEM,
5448 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5449 				   "cannot allocate resource memory");
5450 		return NULL;
5451 	}
5452 	rte_memcpy(&entry->ft_type,
5453 		   RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)),
5454 		   key_len + data_len);
5455 	if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
5456 		ns = sh->fdb_domain;
5457 	else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
5458 		ns = sh->tx_domain;
5459 	else
5460 		ns = sh->rx_domain;
5461 	ret = mlx5_flow_os_create_flow_action_modify_header
5462 					(sh->ctx, ns, entry,
5463 					 data_len, &entry->action);
5464 	if (ret) {
5465 		mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx);
5466 		rte_flow_error_set(ctx->error, ENOMEM,
5467 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5468 				   NULL, "cannot create modification action");
5469 		return NULL;
5470 	}
5471 	entry->idx = idx;
5472 	return &entry->entry;
5473 }
5474 
5475 struct mlx5_list_entry *
5476 flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
5477 			void *cb_ctx)
5478 {
5479 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5480 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5481 	struct mlx5_flow_dv_modify_hdr_resource *entry;
5482 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5483 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5484 	uint32_t idx;
5485 
5486 	entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1],
5487 				  &idx);
5488 	if (!entry) {
5489 		rte_flow_error_set(ctx->error, ENOMEM,
5490 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5491 				   "cannot allocate resource memory");
5492 		return NULL;
5493 	}
5494 	memcpy(entry, oentry, sizeof(*entry) + data_len);
5495 	entry->idx = idx;
5496 	return &entry->entry;
5497 }
5498 
5499 void
5500 flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
5501 {
5502 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5503 	struct mlx5_flow_dv_modify_hdr_resource *res =
5504 		container_of(entry, typeof(*res), entry);
5505 
5506 	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
5507 }
5508 
5509 /**
5510  * Validate the sample action.
5511  *
5512  * @param[in, out] action_flags
5513  *   Holds the actions detected until now.
5514  * @param[in] action
5515  *   Pointer to the sample action.
5516  * @param[in] dev
5517  *   Pointer to the Ethernet device structure.
5518  * @param[in] attr
5519  *   Attributes of flow that includes this action.
5520  * @param[in] item_flags
5521  *   Holds the items detected.
5522  * @param[in] rss
5523  *   Pointer to the RSS action.
5524  * @param[out] sample_rss
5525  *   Pointer to the RSS action in sample action list.
5526  * @param[out] count
5527  *   Pointer to the COUNT action in sample action list.
5528  * @param[out] fdb_mirror_limit
5529  *   Pointer to the FDB mirror limitation flag.
5530  * @param[out] error
5531  *   Pointer to error structure.
5532  *
5533  * @return
5534  *   0 on success, a negative errno value otherwise and rte_errno is set.
5535  */
5536 static int
5537 flow_dv_validate_action_sample(uint64_t *action_flags,
5538 			       const struct rte_flow_action *action,
5539 			       struct rte_eth_dev *dev,
5540 			       const struct rte_flow_attr *attr,
5541 			       uint64_t item_flags,
5542 			       const struct rte_flow_action_rss *rss,
5543 			       const struct rte_flow_action_rss **sample_rss,
5544 			       const struct rte_flow_action_count **count,
5545 			       int *fdb_mirror_limit,
5546 			       struct rte_flow_error *error)
5547 {
5548 	struct mlx5_priv *priv = dev->data->dev_private;
5549 	struct mlx5_dev_config *dev_conf = &priv->config;
5550 	const struct rte_flow_action_sample *sample = action->conf;
5551 	const struct rte_flow_action *act;
5552 	uint64_t sub_action_flags = 0;
5553 	uint16_t queue_index = 0xFFFF;
5554 	int actions_n = 0;
5555 	int ret;
5556 
5557 	if (!sample)
5558 		return rte_flow_error_set(error, EINVAL,
5559 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5560 					  "configuration cannot be NULL");
5561 	if (sample->ratio == 0)
5562 		return rte_flow_error_set(error, EINVAL,
5563 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5564 					  "ratio value starts from 1");
5565 	if (!priv->config.devx || (sample->ratio > 0 && !priv->sampler_en))
5566 		return rte_flow_error_set(error, ENOTSUP,
5567 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5568 					  NULL,
5569 					  "sample action not supported");
5570 	if (*action_flags & MLX5_FLOW_ACTION_SAMPLE)
5571 		return rte_flow_error_set(error, EINVAL,
5572 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5573 					  "Multiple sample actions not "
5574 					  "supported");
5575 	if (*action_flags & MLX5_FLOW_ACTION_METER)
5576 		return rte_flow_error_set(error, EINVAL,
5577 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5578 					  "wrong action order, meter should "
5579 					  "be after sample action");
5580 	if (*action_flags & MLX5_FLOW_ACTION_JUMP)
5581 		return rte_flow_error_set(error, EINVAL,
5582 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5583 					  "wrong action order, jump should "
5584 					  "be after sample action");
5585 	act = sample->actions;
5586 	for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
5587 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
5588 			return rte_flow_error_set(error, ENOTSUP,
5589 						  RTE_FLOW_ERROR_TYPE_ACTION,
5590 						  act, "too many actions");
5591 		switch (act->type) {
5592 		case RTE_FLOW_ACTION_TYPE_QUEUE:
5593 			ret = mlx5_flow_validate_action_queue(act,
5594 							      sub_action_flags,
5595 							      dev,
5596 							      attr, error);
5597 			if (ret < 0)
5598 				return ret;
5599 			queue_index = ((const struct rte_flow_action_queue *)
5600 							(act->conf))->index;
5601 			sub_action_flags |= MLX5_FLOW_ACTION_QUEUE;
5602 			++actions_n;
5603 			break;
5604 		case RTE_FLOW_ACTION_TYPE_RSS:
5605 			*sample_rss = act->conf;
5606 			ret = mlx5_flow_validate_action_rss(act,
5607 							    sub_action_flags,
5608 							    dev, attr,
5609 							    item_flags,
5610 							    error);
5611 			if (ret < 0)
5612 				return ret;
5613 			if (rss && *sample_rss &&
5614 			    ((*sample_rss)->level != rss->level ||
5615 			    (*sample_rss)->types != rss->types))
5616 				return rte_flow_error_set(error, ENOTSUP,
5617 					RTE_FLOW_ERROR_TYPE_ACTION,
5618 					NULL,
5619 					"Can't use the different RSS types "
5620 					"or level in the same flow");
5621 			if (*sample_rss != NULL && (*sample_rss)->queue_num)
5622 				queue_index = (*sample_rss)->queue[0];
5623 			sub_action_flags |= MLX5_FLOW_ACTION_RSS;
5624 			++actions_n;
5625 			break;
5626 		case RTE_FLOW_ACTION_TYPE_MARK:
5627 			ret = flow_dv_validate_action_mark(dev, act,
5628 							   sub_action_flags,
5629 							   attr, error);
5630 			if (ret < 0)
5631 				return ret;
5632 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)
5633 				sub_action_flags |= MLX5_FLOW_ACTION_MARK |
5634 						MLX5_FLOW_ACTION_MARK_EXT;
5635 			else
5636 				sub_action_flags |= MLX5_FLOW_ACTION_MARK;
5637 			++actions_n;
5638 			break;
5639 		case RTE_FLOW_ACTION_TYPE_COUNT:
5640 			ret = flow_dv_validate_action_count
5641 				(dev, false, *action_flags | sub_action_flags,
5642 				 error);
5643 			if (ret < 0)
5644 				return ret;
5645 			*count = act->conf;
5646 			sub_action_flags |= MLX5_FLOW_ACTION_COUNT;
5647 			*action_flags |= MLX5_FLOW_ACTION_COUNT;
5648 			++actions_n;
5649 			break;
5650 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
5651 			ret = flow_dv_validate_action_port_id(dev,
5652 							      sub_action_flags,
5653 							      act,
5654 							      attr,
5655 							      error);
5656 			if (ret)
5657 				return ret;
5658 			sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID;
5659 			++actions_n;
5660 			break;
5661 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
5662 			ret = flow_dv_validate_action_raw_encap_decap
5663 				(dev, NULL, act->conf, attr, &sub_action_flags,
5664 				 &actions_n, action, item_flags, error);
5665 			if (ret < 0)
5666 				return ret;
5667 			++actions_n;
5668 			break;
5669 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5670 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
5671 			ret = flow_dv_validate_action_l2_encap(dev,
5672 							       sub_action_flags,
5673 							       act, attr,
5674 							       error);
5675 			if (ret < 0)
5676 				return ret;
5677 			sub_action_flags |= MLX5_FLOW_ACTION_ENCAP;
5678 			++actions_n;
5679 			break;
5680 		default:
5681 			return rte_flow_error_set(error, ENOTSUP,
5682 						  RTE_FLOW_ERROR_TYPE_ACTION,
5683 						  NULL,
5684 						  "Doesn't support optional "
5685 						  "action");
5686 		}
5687 	}
5688 	if (attr->ingress && !attr->transfer) {
5689 		if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE |
5690 					  MLX5_FLOW_ACTION_RSS)))
5691 			return rte_flow_error_set(error, EINVAL,
5692 						  RTE_FLOW_ERROR_TYPE_ACTION,
5693 						  NULL,
5694 						  "Ingress must has a dest "
5695 						  "QUEUE for Sample");
5696 	} else if (attr->egress && !attr->transfer) {
5697 		return rte_flow_error_set(error, ENOTSUP,
5698 					  RTE_FLOW_ERROR_TYPE_ACTION,
5699 					  NULL,
5700 					  "Sample Only support Ingress "
5701 					  "or E-Switch");
5702 	} else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) {
5703 		MLX5_ASSERT(attr->transfer);
5704 		if (sample->ratio > 1)
5705 			return rte_flow_error_set(error, ENOTSUP,
5706 						  RTE_FLOW_ERROR_TYPE_ACTION,
5707 						  NULL,
5708 						  "E-Switch doesn't support "
5709 						  "any optional action "
5710 						  "for sampling");
5711 		if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE)
5712 			return rte_flow_error_set(error, ENOTSUP,
5713 						  RTE_FLOW_ERROR_TYPE_ACTION,
5714 						  NULL,
5715 						  "unsupported action QUEUE");
5716 		if (sub_action_flags & MLX5_FLOW_ACTION_RSS)
5717 			return rte_flow_error_set(error, ENOTSUP,
5718 						  RTE_FLOW_ERROR_TYPE_ACTION,
5719 						  NULL,
5720 						  "unsupported action QUEUE");
5721 		if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID))
5722 			return rte_flow_error_set(error, EINVAL,
5723 						  RTE_FLOW_ERROR_TYPE_ACTION,
5724 						  NULL,
5725 						  "E-Switch must has a dest "
5726 						  "port for mirroring");
5727 		if (!priv->config.hca_attr.reg_c_preserve &&
5728 		     priv->representor_id != UINT16_MAX)
5729 			*fdb_mirror_limit = 1;
5730 	}
5731 	/* Continue validation for Xcap actions.*/
5732 	if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) &&
5733 	    (queue_index == 0xFFFF ||
5734 	     mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) {
5735 		if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
5736 		     MLX5_FLOW_XCAP_ACTIONS)
5737 			return rte_flow_error_set(error, ENOTSUP,
5738 						  RTE_FLOW_ERROR_TYPE_ACTION,
5739 						  NULL, "encap and decap "
5740 						  "combination aren't "
5741 						  "supported");
5742 		if (!attr->transfer && attr->ingress && (sub_action_flags &
5743 							MLX5_FLOW_ACTION_ENCAP))
5744 			return rte_flow_error_set(error, ENOTSUP,
5745 						  RTE_FLOW_ERROR_TYPE_ACTION,
5746 						  NULL, "encap is not supported"
5747 						  " for ingress traffic");
5748 	}
5749 	return 0;
5750 }
5751 
5752 /**
5753  * Find existing modify-header resource or create and register a new one.
5754  *
5755  * @param dev[in, out]
5756  *   Pointer to rte_eth_dev structure.
5757  * @param[in, out] resource
5758  *   Pointer to modify-header resource.
5759  * @parm[in, out] dev_flow
5760  *   Pointer to the dev_flow.
5761  * @param[out] error
5762  *   pointer to error structure.
5763  *
5764  * @return
5765  *   0 on success otherwise -errno and errno is set.
5766  */
5767 static int
5768 flow_dv_modify_hdr_resource_register
5769 			(struct rte_eth_dev *dev,
5770 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
5771 			 struct mlx5_flow *dev_flow,
5772 			 struct rte_flow_error *error)
5773 {
5774 	struct mlx5_priv *priv = dev->data->dev_private;
5775 	struct mlx5_dev_ctx_shared *sh = priv->sh;
5776 	uint32_t key_len = sizeof(*resource) -
5777 			   offsetof(typeof(*resource), ft_type) +
5778 			   resource->actions_num * sizeof(resource->actions[0]);
5779 	struct mlx5_list_entry *entry;
5780 	struct mlx5_flow_cb_ctx ctx = {
5781 		.error = error,
5782 		.data = resource,
5783 	};
5784 	struct mlx5_hlist *modify_cmds;
5785 	uint64_t key64;
5786 
5787 	modify_cmds = flow_dv_hlist_prepare(sh, &sh->modify_cmds,
5788 				"hdr_modify",
5789 				MLX5_FLOW_HDR_MODIFY_HTABLE_SZ,
5790 				true, false, sh,
5791 				flow_dv_modify_create_cb,
5792 				flow_dv_modify_match_cb,
5793 				flow_dv_modify_remove_cb,
5794 				flow_dv_modify_clone_cb,
5795 				flow_dv_modify_clone_free_cb);
5796 	if (unlikely(!modify_cmds))
5797 		return -rte_errno;
5798 	resource->root = !dev_flow->dv.group;
5799 	if (resource->actions_num > flow_dv_modify_hdr_action_max(dev,
5800 								resource->root))
5801 		return rte_flow_error_set(error, EOVERFLOW,
5802 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5803 					  "too many modify header items");
5804 	key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0);
5805 	entry = mlx5_hlist_register(modify_cmds, key64, &ctx);
5806 	if (!entry)
5807 		return -rte_errno;
5808 	resource = container_of(entry, typeof(*resource), entry);
5809 	dev_flow->handle->dvh.modify_hdr = resource;
5810 	return 0;
5811 }
5812 
5813 /**
5814  * Get DV flow counter by index.
5815  *
5816  * @param[in] dev
5817  *   Pointer to the Ethernet device structure.
5818  * @param[in] idx
5819  *   mlx5 flow counter index in the container.
5820  * @param[out] ppool
5821  *   mlx5 flow counter pool in the container.
5822  *
5823  * @return
5824  *   Pointer to the counter, NULL otherwise.
5825  */
5826 static struct mlx5_flow_counter *
5827 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev,
5828 			   uint32_t idx,
5829 			   struct mlx5_flow_counter_pool **ppool)
5830 {
5831 	struct mlx5_priv *priv = dev->data->dev_private;
5832 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5833 	struct mlx5_flow_counter_pool *pool;
5834 
5835 	/* Decrease to original index and clear shared bit. */
5836 	idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
5837 	MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < cmng->n);
5838 	pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
5839 	MLX5_ASSERT(pool);
5840 	if (ppool)
5841 		*ppool = pool;
5842 	return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
5843 }
5844 
5845 /**
5846  * Check the devx counter belongs to the pool.
5847  *
5848  * @param[in] pool
5849  *   Pointer to the counter pool.
5850  * @param[in] id
5851  *   The counter devx ID.
5852  *
5853  * @return
5854  *   True if counter belongs to the pool, false otherwise.
5855  */
5856 static bool
5857 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id)
5858 {
5859 	int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) *
5860 		   MLX5_COUNTERS_PER_POOL;
5861 
5862 	if (id >= base && id < base + MLX5_COUNTERS_PER_POOL)
5863 		return true;
5864 	return false;
5865 }
5866 
5867 /**
5868  * Get a pool by devx counter ID.
5869  *
5870  * @param[in] cmng
5871  *   Pointer to the counter management.
5872  * @param[in] id
5873  *   The counter devx ID.
5874  *
5875  * @return
5876  *   The counter pool pointer if exists, NULL otherwise,
5877  */
5878 static struct mlx5_flow_counter_pool *
5879 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id)
5880 {
5881 	uint32_t i;
5882 	struct mlx5_flow_counter_pool *pool = NULL;
5883 
5884 	rte_spinlock_lock(&cmng->pool_update_sl);
5885 	/* Check last used pool. */
5886 	if (cmng->last_pool_idx != POOL_IDX_INVALID &&
5887 	    flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) {
5888 		pool = cmng->pools[cmng->last_pool_idx];
5889 		goto out;
5890 	}
5891 	/* ID out of range means no suitable pool in the container. */
5892 	if (id > cmng->max_id || id < cmng->min_id)
5893 		goto out;
5894 	/*
5895 	 * Find the pool from the end of the container, since mostly counter
5896 	 * ID is sequence increasing, and the last pool should be the needed
5897 	 * one.
5898 	 */
5899 	i = cmng->n_valid;
5900 	while (i--) {
5901 		struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i];
5902 
5903 		if (flow_dv_is_counter_in_pool(pool_tmp, id)) {
5904 			pool = pool_tmp;
5905 			break;
5906 		}
5907 	}
5908 out:
5909 	rte_spinlock_unlock(&cmng->pool_update_sl);
5910 	return pool;
5911 }
5912 
5913 /**
5914  * Resize a counter container.
5915  *
5916  * @param[in] dev
5917  *   Pointer to the Ethernet device structure.
5918  *
5919  * @return
5920  *   0 on success, otherwise negative errno value and rte_errno is set.
5921  */
5922 static int
5923 flow_dv_container_resize(struct rte_eth_dev *dev)
5924 {
5925 	struct mlx5_priv *priv = dev->data->dev_private;
5926 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5927 	void *old_pools = cmng->pools;
5928 	uint32_t resize = cmng->n + MLX5_CNT_CONTAINER_RESIZE;
5929 	uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize;
5930 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
5931 
5932 	if (!pools) {
5933 		rte_errno = ENOMEM;
5934 		return -ENOMEM;
5935 	}
5936 	if (old_pools)
5937 		memcpy(pools, old_pools, cmng->n *
5938 				       sizeof(struct mlx5_flow_counter_pool *));
5939 	cmng->n = resize;
5940 	cmng->pools = pools;
5941 	if (old_pools)
5942 		mlx5_free(old_pools);
5943 	return 0;
5944 }
5945 
5946 /**
5947  * Query a devx flow counter.
5948  *
5949  * @param[in] dev
5950  *   Pointer to the Ethernet device structure.
5951  * @param[in] counter
5952  *   Index to the flow counter.
5953  * @param[out] pkts
5954  *   The statistics value of packets.
5955  * @param[out] bytes
5956  *   The statistics value of bytes.
5957  *
5958  * @return
5959  *   0 on success, otherwise a negative errno value and rte_errno is set.
5960  */
5961 static inline int
5962 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts,
5963 		     uint64_t *bytes)
5964 {
5965 	struct mlx5_priv *priv = dev->data->dev_private;
5966 	struct mlx5_flow_counter_pool *pool = NULL;
5967 	struct mlx5_flow_counter *cnt;
5968 	int offset;
5969 
5970 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
5971 	MLX5_ASSERT(pool);
5972 	if (priv->sh->cmng.counter_fallback)
5973 		return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0,
5974 					0, pkts, bytes, 0, NULL, NULL, 0);
5975 	rte_spinlock_lock(&pool->sl);
5976 	if (!pool->raw) {
5977 		*pkts = 0;
5978 		*bytes = 0;
5979 	} else {
5980 		offset = MLX5_CNT_ARRAY_IDX(pool, cnt);
5981 		*pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits);
5982 		*bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes);
5983 	}
5984 	rte_spinlock_unlock(&pool->sl);
5985 	return 0;
5986 }
5987 
5988 /**
5989  * Create and initialize a new counter pool.
5990  *
5991  * @param[in] dev
5992  *   Pointer to the Ethernet device structure.
5993  * @param[out] dcs
5994  *   The devX counter handle.
5995  * @param[in] age
5996  *   Whether the pool is for counter that was allocated for aging.
5997  * @param[in/out] cont_cur
5998  *   Pointer to the container pointer, it will be update in pool resize.
5999  *
6000  * @return
6001  *   The pool container pointer on success, NULL otherwise and rte_errno is set.
6002  */
6003 static struct mlx5_flow_counter_pool *
6004 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
6005 		    uint32_t age)
6006 {
6007 	struct mlx5_priv *priv = dev->data->dev_private;
6008 	struct mlx5_flow_counter_pool *pool;
6009 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6010 	bool fallback = priv->sh->cmng.counter_fallback;
6011 	uint32_t size = sizeof(*pool);
6012 
6013 	size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE;
6014 	size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE);
6015 	pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
6016 	if (!pool) {
6017 		rte_errno = ENOMEM;
6018 		return NULL;
6019 	}
6020 	pool->raw = NULL;
6021 	pool->is_aged = !!age;
6022 	pool->query_gen = 0;
6023 	pool->min_dcs = dcs;
6024 	rte_spinlock_init(&pool->sl);
6025 	rte_spinlock_init(&pool->csl);
6026 	TAILQ_INIT(&pool->counters[0]);
6027 	TAILQ_INIT(&pool->counters[1]);
6028 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
6029 	rte_spinlock_lock(&cmng->pool_update_sl);
6030 	pool->index = cmng->n_valid;
6031 	if (pool->index == cmng->n && flow_dv_container_resize(dev)) {
6032 		mlx5_free(pool);
6033 		rte_spinlock_unlock(&cmng->pool_update_sl);
6034 		return NULL;
6035 	}
6036 	cmng->pools[pool->index] = pool;
6037 	cmng->n_valid++;
6038 	if (unlikely(fallback)) {
6039 		int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL);
6040 
6041 		if (base < cmng->min_id)
6042 			cmng->min_id = base;
6043 		if (base > cmng->max_id)
6044 			cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1;
6045 		cmng->last_pool_idx = pool->index;
6046 	}
6047 	rte_spinlock_unlock(&cmng->pool_update_sl);
6048 	return pool;
6049 }
6050 
6051 /**
6052  * Prepare a new counter and/or a new counter pool.
6053  *
6054  * @param[in] dev
6055  *   Pointer to the Ethernet device structure.
6056  * @param[out] cnt_free
6057  *   Where to put the pointer of a new counter.
6058  * @param[in] age
6059  *   Whether the pool is for counter that was allocated for aging.
6060  *
6061  * @return
6062  *   The counter pool pointer and @p cnt_free is set on success,
6063  *   NULL otherwise and rte_errno is set.
6064  */
6065 static struct mlx5_flow_counter_pool *
6066 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev,
6067 			     struct mlx5_flow_counter **cnt_free,
6068 			     uint32_t age)
6069 {
6070 	struct mlx5_priv *priv = dev->data->dev_private;
6071 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6072 	struct mlx5_flow_counter_pool *pool;
6073 	struct mlx5_counters tmp_tq;
6074 	struct mlx5_devx_obj *dcs = NULL;
6075 	struct mlx5_flow_counter *cnt;
6076 	enum mlx5_counter_type cnt_type =
6077 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6078 	bool fallback = priv->sh->cmng.counter_fallback;
6079 	uint32_t i;
6080 
6081 	if (fallback) {
6082 		/* bulk_bitmap must be 0 for single counter allocation. */
6083 		dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
6084 		if (!dcs)
6085 			return NULL;
6086 		pool = flow_dv_find_pool_by_id(cmng, dcs->id);
6087 		if (!pool) {
6088 			pool = flow_dv_pool_create(dev, dcs, age);
6089 			if (!pool) {
6090 				mlx5_devx_cmd_destroy(dcs);
6091 				return NULL;
6092 			}
6093 		}
6094 		i = dcs->id % MLX5_COUNTERS_PER_POOL;
6095 		cnt = MLX5_POOL_GET_CNT(pool, i);
6096 		cnt->pool = pool;
6097 		cnt->dcs_when_free = dcs;
6098 		*cnt_free = cnt;
6099 		return pool;
6100 	}
6101 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4);
6102 	if (!dcs) {
6103 		rte_errno = ENODATA;
6104 		return NULL;
6105 	}
6106 	pool = flow_dv_pool_create(dev, dcs, age);
6107 	if (!pool) {
6108 		mlx5_devx_cmd_destroy(dcs);
6109 		return NULL;
6110 	}
6111 	TAILQ_INIT(&tmp_tq);
6112 	for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) {
6113 		cnt = MLX5_POOL_GET_CNT(pool, i);
6114 		cnt->pool = pool;
6115 		TAILQ_INSERT_HEAD(&tmp_tq, cnt, next);
6116 	}
6117 	rte_spinlock_lock(&cmng->csl[cnt_type]);
6118 	TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next);
6119 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
6120 	*cnt_free = MLX5_POOL_GET_CNT(pool, 0);
6121 	(*cnt_free)->pool = pool;
6122 	return pool;
6123 }
6124 
6125 /**
6126  * Allocate a flow counter.
6127  *
6128  * @param[in] dev
6129  *   Pointer to the Ethernet device structure.
6130  * @param[in] age
6131  *   Whether the counter was allocated for aging.
6132  *
6133  * @return
6134  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
6135  */
6136 static uint32_t
6137 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age)
6138 {
6139 	struct mlx5_priv *priv = dev->data->dev_private;
6140 	struct mlx5_flow_counter_pool *pool = NULL;
6141 	struct mlx5_flow_counter *cnt_free = NULL;
6142 	bool fallback = priv->sh->cmng.counter_fallback;
6143 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6144 	enum mlx5_counter_type cnt_type =
6145 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6146 	uint32_t cnt_idx;
6147 
6148 	if (!priv->config.devx) {
6149 		rte_errno = ENOTSUP;
6150 		return 0;
6151 	}
6152 	/* Get free counters from container. */
6153 	rte_spinlock_lock(&cmng->csl[cnt_type]);
6154 	cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]);
6155 	if (cnt_free)
6156 		TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next);
6157 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
6158 	if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age))
6159 		goto err;
6160 	pool = cnt_free->pool;
6161 	if (fallback)
6162 		cnt_free->dcs_when_active = cnt_free->dcs_when_free;
6163 	/* Create a DV counter action only in the first time usage. */
6164 	if (!cnt_free->action) {
6165 		uint16_t offset;
6166 		struct mlx5_devx_obj *dcs;
6167 		int ret;
6168 
6169 		if (!fallback) {
6170 			offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free);
6171 			dcs = pool->min_dcs;
6172 		} else {
6173 			offset = 0;
6174 			dcs = cnt_free->dcs_when_free;
6175 		}
6176 		ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset,
6177 							    &cnt_free->action);
6178 		if (ret) {
6179 			rte_errno = errno;
6180 			goto err;
6181 		}
6182 	}
6183 	cnt_idx = MLX5_MAKE_CNT_IDX(pool->index,
6184 				MLX5_CNT_ARRAY_IDX(pool, cnt_free));
6185 	/* Update the counter reset values. */
6186 	if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits,
6187 				 &cnt_free->bytes))
6188 		goto err;
6189 	if (!fallback && !priv->sh->cmng.query_thread_on)
6190 		/* Start the asynchronous batch query by the host thread. */
6191 		mlx5_set_query_alarm(priv->sh);
6192 	/*
6193 	 * When the count action isn't shared (by ID), shared_info field is
6194 	 * used for indirect action API's refcnt.
6195 	 * When the counter action is not shared neither by ID nor by indirect
6196 	 * action API, shared info must be 1.
6197 	 */
6198 	cnt_free->shared_info.refcnt = 1;
6199 	return cnt_idx;
6200 err:
6201 	if (cnt_free) {
6202 		cnt_free->pool = pool;
6203 		if (fallback)
6204 			cnt_free->dcs_when_free = cnt_free->dcs_when_active;
6205 		rte_spinlock_lock(&cmng->csl[cnt_type]);
6206 		TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next);
6207 		rte_spinlock_unlock(&cmng->csl[cnt_type]);
6208 	}
6209 	return 0;
6210 }
6211 
6212 /**
6213  * Get age param from counter index.
6214  *
6215  * @param[in] dev
6216  *   Pointer to the Ethernet device structure.
6217  * @param[in] counter
6218  *   Index to the counter handler.
6219  *
6220  * @return
6221  *   The aging parameter specified for the counter index.
6222  */
6223 static struct mlx5_age_param*
6224 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev,
6225 				uint32_t counter)
6226 {
6227 	struct mlx5_flow_counter *cnt;
6228 	struct mlx5_flow_counter_pool *pool = NULL;
6229 
6230 	flow_dv_counter_get_by_idx(dev, counter, &pool);
6231 	counter = (counter - 1) % MLX5_COUNTERS_PER_POOL;
6232 	cnt = MLX5_POOL_GET_CNT(pool, counter);
6233 	return MLX5_CNT_TO_AGE(cnt);
6234 }
6235 
6236 /**
6237  * Remove a flow counter from aged counter list.
6238  *
6239  * @param[in] dev
6240  *   Pointer to the Ethernet device structure.
6241  * @param[in] counter
6242  *   Index to the counter handler.
6243  * @param[in] cnt
6244  *   Pointer to the counter handler.
6245  */
6246 static void
6247 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev,
6248 				uint32_t counter, struct mlx5_flow_counter *cnt)
6249 {
6250 	struct mlx5_age_info *age_info;
6251 	struct mlx5_age_param *age_param;
6252 	struct mlx5_priv *priv = dev->data->dev_private;
6253 	uint16_t expected = AGE_CANDIDATE;
6254 
6255 	age_info = GET_PORT_AGE_INFO(priv);
6256 	age_param = flow_dv_counter_idx_get_age(dev, counter);
6257 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
6258 					 AGE_FREE, false, __ATOMIC_RELAXED,
6259 					 __ATOMIC_RELAXED)) {
6260 		/**
6261 		 * We need the lock even it is age timeout,
6262 		 * since counter may still in process.
6263 		 */
6264 		rte_spinlock_lock(&age_info->aged_sl);
6265 		TAILQ_REMOVE(&age_info->aged_counters, cnt, next);
6266 		rte_spinlock_unlock(&age_info->aged_sl);
6267 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
6268 	}
6269 }
6270 
6271 /**
6272  * Release a flow counter.
6273  *
6274  * @param[in] dev
6275  *   Pointer to the Ethernet device structure.
6276  * @param[in] counter
6277  *   Index to the counter handler.
6278  */
6279 static void
6280 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter)
6281 {
6282 	struct mlx5_priv *priv = dev->data->dev_private;
6283 	struct mlx5_flow_counter_pool *pool = NULL;
6284 	struct mlx5_flow_counter *cnt;
6285 	enum mlx5_counter_type cnt_type;
6286 
6287 	if (!counter)
6288 		return;
6289 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
6290 	MLX5_ASSERT(pool);
6291 	if (pool->is_aged) {
6292 		flow_dv_counter_remove_from_age(dev, counter, cnt);
6293 	} else {
6294 		/*
6295 		 * If the counter action is shared by indirect action API,
6296 		 * the atomic function reduces its references counter.
6297 		 * If after the reduction the action is still referenced, the
6298 		 * function returns here and does not release it.
6299 		 * When the counter action is not shared by
6300 		 * indirect action API, shared info is 1 before the reduction,
6301 		 * so this condition is failed and function doesn't return here.
6302 		 */
6303 		if (__atomic_sub_fetch(&cnt->shared_info.refcnt, 1,
6304 				       __ATOMIC_RELAXED))
6305 			return;
6306 	}
6307 	cnt->pool = pool;
6308 	/*
6309 	 * Put the counter back to list to be updated in none fallback mode.
6310 	 * Currently, we are using two list alternately, while one is in query,
6311 	 * add the freed counter to the other list based on the pool query_gen
6312 	 * value. After query finishes, add counter the list to the global
6313 	 * container counter list. The list changes while query starts. In
6314 	 * this case, lock will not be needed as query callback and release
6315 	 * function both operate with the different list.
6316 	 */
6317 	if (!priv->sh->cmng.counter_fallback) {
6318 		rte_spinlock_lock(&pool->csl);
6319 		TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next);
6320 		rte_spinlock_unlock(&pool->csl);
6321 	} else {
6322 		cnt->dcs_when_free = cnt->dcs_when_active;
6323 		cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE :
6324 					   MLX5_COUNTER_TYPE_ORIGIN;
6325 		rte_spinlock_lock(&priv->sh->cmng.csl[cnt_type]);
6326 		TAILQ_INSERT_TAIL(&priv->sh->cmng.counters[cnt_type],
6327 				  cnt, next);
6328 		rte_spinlock_unlock(&priv->sh->cmng.csl[cnt_type]);
6329 	}
6330 }
6331 
6332 /**
6333  * Resize a meter id container.
6334  *
6335  * @param[in] dev
6336  *   Pointer to the Ethernet device structure.
6337  *
6338  * @return
6339  *   0 on success, otherwise negative errno value and rte_errno is set.
6340  */
6341 static int
6342 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
6343 {
6344 	struct mlx5_priv *priv = dev->data->dev_private;
6345 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6346 				&priv->sh->mtrmng->pools_mng;
6347 	void *old_pools = pools_mng->pools;
6348 	uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
6349 	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
6350 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
6351 
6352 	if (!pools) {
6353 		rte_errno = ENOMEM;
6354 		return -ENOMEM;
6355 	}
6356 	if (!pools_mng->n)
6357 		if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {
6358 			mlx5_free(pools);
6359 			return -ENOMEM;
6360 		}
6361 	if (old_pools)
6362 		memcpy(pools, old_pools, pools_mng->n *
6363 				       sizeof(struct mlx5_aso_mtr_pool *));
6364 	pools_mng->n = resize;
6365 	pools_mng->pools = pools;
6366 	if (old_pools)
6367 		mlx5_free(old_pools);
6368 	return 0;
6369 }
6370 
6371 /**
6372  * Prepare a new meter and/or a new meter pool.
6373  *
6374  * @param[in] dev
6375  *   Pointer to the Ethernet device structure.
6376  * @param[out] mtr_free
6377  *   Where to put the pointer of a new meter.g.
6378  *
6379  * @return
6380  *   The meter pool pointer and @mtr_free is set on success,
6381  *   NULL otherwise and rte_errno is set.
6382  */
6383 static struct mlx5_aso_mtr_pool *
6384 flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
6385 			     struct mlx5_aso_mtr **mtr_free)
6386 {
6387 	struct mlx5_priv *priv = dev->data->dev_private;
6388 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6389 				&priv->sh->mtrmng->pools_mng;
6390 	struct mlx5_aso_mtr_pool *pool = NULL;
6391 	struct mlx5_devx_obj *dcs = NULL;
6392 	uint32_t i;
6393 	uint32_t log_obj_size;
6394 
6395 	log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1);
6396 	dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->ctx,
6397 			priv->sh->pdn, log_obj_size);
6398 	if (!dcs) {
6399 		rte_errno = ENODATA;
6400 		return NULL;
6401 	}
6402 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
6403 	if (!pool) {
6404 		rte_errno = ENOMEM;
6405 		claim_zero(mlx5_devx_cmd_destroy(dcs));
6406 		return NULL;
6407 	}
6408 	pool->devx_obj = dcs;
6409 	pool->index = pools_mng->n_valid;
6410 	if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
6411 		mlx5_free(pool);
6412 		claim_zero(mlx5_devx_cmd_destroy(dcs));
6413 		return NULL;
6414 	}
6415 	pools_mng->pools[pool->index] = pool;
6416 	pools_mng->n_valid++;
6417 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
6418 		pool->mtrs[i].offset = i;
6419 		LIST_INSERT_HEAD(&pools_mng->meters,
6420 						&pool->mtrs[i], next);
6421 	}
6422 	pool->mtrs[0].offset = 0;
6423 	*mtr_free = &pool->mtrs[0];
6424 	return pool;
6425 }
6426 
6427 /**
6428  * Release a flow meter into pool.
6429  *
6430  * @param[in] dev
6431  *   Pointer to the Ethernet device structure.
6432  * @param[in] mtr_idx
6433  *   Index to aso flow meter.
6434  */
6435 static void
6436 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
6437 {
6438 	struct mlx5_priv *priv = dev->data->dev_private;
6439 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6440 				&priv->sh->mtrmng->pools_mng;
6441 	struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
6442 
6443 	MLX5_ASSERT(aso_mtr);
6444 	rte_spinlock_lock(&pools_mng->mtrsl);
6445 	memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
6446 	aso_mtr->state = ASO_METER_FREE;
6447 	LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
6448 	rte_spinlock_unlock(&pools_mng->mtrsl);
6449 }
6450 
6451 /**
6452  * Allocate a aso flow meter.
6453  *
6454  * @param[in] dev
6455  *   Pointer to the Ethernet device structure.
6456  *
6457  * @return
6458  *   Index to aso flow meter on success, 0 otherwise and rte_errno is set.
6459  */
6460 static uint32_t
6461 flow_dv_mtr_alloc(struct rte_eth_dev *dev)
6462 {
6463 	struct mlx5_priv *priv = dev->data->dev_private;
6464 	struct mlx5_aso_mtr *mtr_free = NULL;
6465 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6466 				&priv->sh->mtrmng->pools_mng;
6467 	struct mlx5_aso_mtr_pool *pool;
6468 	uint32_t mtr_idx = 0;
6469 
6470 	if (!priv->config.devx) {
6471 		rte_errno = ENOTSUP;
6472 		return 0;
6473 	}
6474 	/* Allocate the flow meter memory. */
6475 	/* Get free meters from management. */
6476 	rte_spinlock_lock(&pools_mng->mtrsl);
6477 	mtr_free = LIST_FIRST(&pools_mng->meters);
6478 	if (mtr_free)
6479 		LIST_REMOVE(mtr_free, next);
6480 	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
6481 		rte_spinlock_unlock(&pools_mng->mtrsl);
6482 		return 0;
6483 	}
6484 	mtr_free->state = ASO_METER_WAIT;
6485 	rte_spinlock_unlock(&pools_mng->mtrsl);
6486 	pool = container_of(mtr_free,
6487 			struct mlx5_aso_mtr_pool,
6488 			mtrs[mtr_free->offset]);
6489 	mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
6490 	if (!mtr_free->fm.meter_action) {
6491 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
6492 		struct rte_flow_error error;
6493 		uint8_t reg_id;
6494 
6495 		reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error);
6496 		mtr_free->fm.meter_action =
6497 			mlx5_glue->dv_create_flow_action_aso
6498 						(priv->sh->rx_domain,
6499 						 pool->devx_obj->obj,
6500 						 mtr_free->offset,
6501 						 (1 << MLX5_FLOW_COLOR_GREEN),
6502 						 reg_id - REG_C_0);
6503 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
6504 		if (!mtr_free->fm.meter_action) {
6505 			flow_dv_aso_mtr_release_to_pool(dev, mtr_idx);
6506 			return 0;
6507 		}
6508 	}
6509 	return mtr_idx;
6510 }
6511 
6512 /**
6513  * Verify the @p attributes will be correctly understood by the NIC and store
6514  * them in the @p flow if everything is correct.
6515  *
6516  * @param[in] dev
6517  *   Pointer to dev struct.
6518  * @param[in] attributes
6519  *   Pointer to flow attributes
6520  * @param[in] external
6521  *   This flow rule is created by request external to PMD.
6522  * @param[out] error
6523  *   Pointer to error structure.
6524  *
6525  * @return
6526  *   - 0 on success and non root table.
6527  *   - 1 on success and root table.
6528  *   - a negative errno value otherwise and rte_errno is set.
6529  */
6530 static int
6531 flow_dv_validate_attributes(struct rte_eth_dev *dev,
6532 			    const struct mlx5_flow_tunnel *tunnel,
6533 			    const struct rte_flow_attr *attributes,
6534 			    const struct flow_grp_info *grp_info,
6535 			    struct rte_flow_error *error)
6536 {
6537 	struct mlx5_priv *priv = dev->data->dev_private;
6538 	uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes);
6539 	int ret = 0;
6540 
6541 #ifndef HAVE_MLX5DV_DR
6542 	RTE_SET_USED(tunnel);
6543 	RTE_SET_USED(grp_info);
6544 	if (attributes->group)
6545 		return rte_flow_error_set(error, ENOTSUP,
6546 					  RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
6547 					  NULL,
6548 					  "groups are not supported");
6549 #else
6550 	uint32_t table = 0;
6551 
6552 	ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table,
6553 				       grp_info, error);
6554 	if (ret)
6555 		return ret;
6556 	if (!table)
6557 		ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
6558 #endif
6559 	if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR &&
6560 	    attributes->priority > lowest_priority)
6561 		return rte_flow_error_set(error, ENOTSUP,
6562 					  RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
6563 					  NULL,
6564 					  "priority out of range");
6565 	if (attributes->transfer) {
6566 		if (!priv->config.dv_esw_en)
6567 			return rte_flow_error_set
6568 				(error, ENOTSUP,
6569 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
6570 				 "E-Switch dr is not supported");
6571 		if (!(priv->representor || priv->master))
6572 			return rte_flow_error_set
6573 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6574 				 NULL, "E-Switch configuration can only be"
6575 				 " done by a master or a representor device");
6576 		if (attributes->egress)
6577 			return rte_flow_error_set
6578 				(error, ENOTSUP,
6579 				 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes,
6580 				 "egress is not supported");
6581 	}
6582 	if (!(attributes->egress ^ attributes->ingress))
6583 		return rte_flow_error_set(error, ENOTSUP,
6584 					  RTE_FLOW_ERROR_TYPE_ATTR, NULL,
6585 					  "must specify exactly one of "
6586 					  "ingress or egress");
6587 	return ret;
6588 }
6589 
6590 static uint16_t
6591 mlx5_flow_locate_proto_l3(const struct rte_flow_item **head,
6592 			  const struct rte_flow_item *end)
6593 {
6594 	const struct rte_flow_item *item = *head;
6595 	uint16_t l3_protocol;
6596 
6597 	for (; item != end; item++) {
6598 		switch (item->type) {
6599 		default:
6600 			break;
6601 		case RTE_FLOW_ITEM_TYPE_IPV4:
6602 			l3_protocol = RTE_ETHER_TYPE_IPV4;
6603 			goto l3_ok;
6604 		case RTE_FLOW_ITEM_TYPE_IPV6:
6605 			l3_protocol = RTE_ETHER_TYPE_IPV6;
6606 			goto l3_ok;
6607 		case RTE_FLOW_ITEM_TYPE_ETH:
6608 			if (item->mask && item->spec) {
6609 				MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_eth,
6610 							    type, item,
6611 							    l3_protocol);
6612 				if (l3_protocol == RTE_ETHER_TYPE_IPV4 ||
6613 				    l3_protocol == RTE_ETHER_TYPE_IPV6)
6614 					goto l3_ok;
6615 			}
6616 			break;
6617 		case RTE_FLOW_ITEM_TYPE_VLAN:
6618 			if (item->mask && item->spec) {
6619 				MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_vlan,
6620 							    inner_type, item,
6621 							    l3_protocol);
6622 				if (l3_protocol == RTE_ETHER_TYPE_IPV4 ||
6623 				    l3_protocol == RTE_ETHER_TYPE_IPV6)
6624 					goto l3_ok;
6625 			}
6626 			break;
6627 		}
6628 	}
6629 	return 0;
6630 l3_ok:
6631 	*head = item;
6632 	return l3_protocol;
6633 }
6634 
6635 static uint8_t
6636 mlx5_flow_locate_proto_l4(const struct rte_flow_item **head,
6637 			  const struct rte_flow_item *end)
6638 {
6639 	const struct rte_flow_item *item = *head;
6640 	uint8_t l4_protocol;
6641 
6642 	for (; item != end; item++) {
6643 		switch (item->type) {
6644 		default:
6645 			break;
6646 		case RTE_FLOW_ITEM_TYPE_TCP:
6647 			l4_protocol = IPPROTO_TCP;
6648 			goto l4_ok;
6649 		case RTE_FLOW_ITEM_TYPE_UDP:
6650 			l4_protocol = IPPROTO_UDP;
6651 			goto l4_ok;
6652 		case RTE_FLOW_ITEM_TYPE_IPV4:
6653 			if (item->mask && item->spec) {
6654 				const struct rte_flow_item_ipv4 *mask, *spec;
6655 
6656 				mask = (typeof(mask))item->mask;
6657 				spec = (typeof(spec))item->spec;
6658 				l4_protocol = mask->hdr.next_proto_id &
6659 					      spec->hdr.next_proto_id;
6660 				if (l4_protocol == IPPROTO_TCP ||
6661 				    l4_protocol == IPPROTO_UDP)
6662 					goto l4_ok;
6663 			}
6664 			break;
6665 		case RTE_FLOW_ITEM_TYPE_IPV6:
6666 			if (item->mask && item->spec) {
6667 				const struct rte_flow_item_ipv6 *mask, *spec;
6668 				mask = (typeof(mask))item->mask;
6669 				spec = (typeof(spec))item->spec;
6670 				l4_protocol = mask->hdr.proto & spec->hdr.proto;
6671 				if (l4_protocol == IPPROTO_TCP ||
6672 				    l4_protocol == IPPROTO_UDP)
6673 					goto l4_ok;
6674 			}
6675 			break;
6676 		}
6677 	}
6678 	return 0;
6679 l4_ok:
6680 	*head = item;
6681 	return l4_protocol;
6682 }
6683 
6684 static int
6685 flow_dv_validate_item_integrity(struct rte_eth_dev *dev,
6686 				const struct rte_flow_item *rule_items,
6687 				const struct rte_flow_item *integrity_item,
6688 				struct rte_flow_error *error)
6689 {
6690 	struct mlx5_priv *priv = dev->data->dev_private;
6691 	const struct rte_flow_item *tunnel_item, *end_item, *item = rule_items;
6692 	const struct rte_flow_item_integrity *mask = (typeof(mask))
6693 						     integrity_item->mask;
6694 	const struct rte_flow_item_integrity *spec = (typeof(spec))
6695 						     integrity_item->spec;
6696 	uint32_t protocol;
6697 
6698 	if (!priv->config.hca_attr.pkt_integrity_match)
6699 		return rte_flow_error_set(error, ENOTSUP,
6700 					  RTE_FLOW_ERROR_TYPE_ITEM,
6701 					  integrity_item,
6702 					  "packet integrity integrity_item not supported");
6703 	if (!mask)
6704 		mask = &rte_flow_item_integrity_mask;
6705 	if (!mlx5_validate_integrity_item(mask))
6706 		return rte_flow_error_set(error, ENOTSUP,
6707 					  RTE_FLOW_ERROR_TYPE_ITEM,
6708 					  integrity_item,
6709 					  "unsupported integrity filter");
6710 	tunnel_item = mlx5_flow_find_tunnel_item(rule_items);
6711 	if (spec->level > 1) {
6712 		if (!tunnel_item)
6713 			return rte_flow_error_set(error, ENOTSUP,
6714 						  RTE_FLOW_ERROR_TYPE_ITEM,
6715 						  integrity_item,
6716 						  "missing tunnel item");
6717 		item = tunnel_item;
6718 		end_item = mlx5_find_end_item(tunnel_item);
6719 	} else {
6720 		end_item = tunnel_item ? tunnel_item :
6721 			   mlx5_find_end_item(integrity_item);
6722 	}
6723 	if (mask->l3_ok || mask->ipv4_csum_ok) {
6724 		protocol = mlx5_flow_locate_proto_l3(&item, end_item);
6725 		if (!protocol)
6726 			return rte_flow_error_set(error, EINVAL,
6727 						  RTE_FLOW_ERROR_TYPE_ITEM,
6728 						  integrity_item,
6729 						  "missing L3 protocol");
6730 	}
6731 	if (mask->l4_ok || mask->l4_csum_ok) {
6732 		protocol = mlx5_flow_locate_proto_l4(&item, end_item);
6733 		if (!protocol)
6734 			return rte_flow_error_set(error, EINVAL,
6735 						  RTE_FLOW_ERROR_TYPE_ITEM,
6736 						  integrity_item,
6737 						  "missing L4 protocol");
6738 	}
6739 	return 0;
6740 }
6741 
6742 /**
6743  * Internal validation function. For validating both actions and items.
6744  *
6745  * @param[in] dev
6746  *   Pointer to the rte_eth_dev structure.
6747  * @param[in] attr
6748  *   Pointer to the flow attributes.
6749  * @param[in] items
6750  *   Pointer to the list of items.
6751  * @param[in] actions
6752  *   Pointer to the list of actions.
6753  * @param[in] external
6754  *   This flow rule is created by request external to PMD.
6755  * @param[in] hairpin
6756  *   Number of hairpin TX actions, 0 means classic flow.
6757  * @param[out] error
6758  *   Pointer to the error structure.
6759  *
6760  * @return
6761  *   0 on success, a negative errno value otherwise and rte_errno is set.
6762  */
6763 static int
6764 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
6765 		 const struct rte_flow_item items[],
6766 		 const struct rte_flow_action actions[],
6767 		 bool external, int hairpin, struct rte_flow_error *error)
6768 {
6769 	int ret;
6770 	uint64_t action_flags = 0;
6771 	uint64_t item_flags = 0;
6772 	uint64_t last_item = 0;
6773 	uint8_t next_protocol = 0xff;
6774 	uint16_t ether_type = 0;
6775 	int actions_n = 0;
6776 	uint8_t item_ipv6_proto = 0;
6777 	int fdb_mirror_limit = 0;
6778 	int modify_after_mirror = 0;
6779 	const struct rte_flow_item *geneve_item = NULL;
6780 	const struct rte_flow_item *gre_item = NULL;
6781 	const struct rte_flow_item *gtp_item = NULL;
6782 	const struct rte_flow_action_raw_decap *decap;
6783 	const struct rte_flow_action_raw_encap *encap;
6784 	const struct rte_flow_action_rss *rss = NULL;
6785 	const struct rte_flow_action_rss *sample_rss = NULL;
6786 	const struct rte_flow_action_count *sample_count = NULL;
6787 	const struct rte_flow_item_tcp nic_tcp_mask = {
6788 		.hdr = {
6789 			.tcp_flags = 0xFF,
6790 			.src_port = RTE_BE16(UINT16_MAX),
6791 			.dst_port = RTE_BE16(UINT16_MAX),
6792 		}
6793 	};
6794 	const struct rte_flow_item_ipv6 nic_ipv6_mask = {
6795 		.hdr = {
6796 			.src_addr =
6797 			"\xff\xff\xff\xff\xff\xff\xff\xff"
6798 			"\xff\xff\xff\xff\xff\xff\xff\xff",
6799 			.dst_addr =
6800 			"\xff\xff\xff\xff\xff\xff\xff\xff"
6801 			"\xff\xff\xff\xff\xff\xff\xff\xff",
6802 			.vtc_flow = RTE_BE32(0xffffffff),
6803 			.proto = 0xff,
6804 			.hop_limits = 0xff,
6805 		},
6806 		.has_frag_ext = 1,
6807 	};
6808 	const struct rte_flow_item_ecpri nic_ecpri_mask = {
6809 		.hdr = {
6810 			.common = {
6811 				.u32 =
6812 				RTE_BE32(((const struct rte_ecpri_common_hdr) {
6813 					.type = 0xFF,
6814 					}).u32),
6815 			},
6816 			.dummy[0] = 0xffffffff,
6817 		},
6818 	};
6819 	struct mlx5_priv *priv = dev->data->dev_private;
6820 	struct mlx5_dev_config *dev_conf = &priv->config;
6821 	uint16_t queue_index = 0xFFFF;
6822 	const struct rte_flow_item_vlan *vlan_m = NULL;
6823 	uint32_t rw_act_num = 0;
6824 	uint64_t is_root;
6825 	const struct mlx5_flow_tunnel *tunnel;
6826 	enum mlx5_tof_rule_type tof_rule_type;
6827 	struct flow_grp_info grp_info = {
6828 		.external = !!external,
6829 		.transfer = !!attr->transfer,
6830 		.fdb_def_rule = !!priv->fdb_def_rule,
6831 		.std_tbl_fix = true,
6832 	};
6833 	const struct rte_eth_hairpin_conf *conf;
6834 	const struct rte_flow_item *rule_items = items;
6835 	const struct rte_flow_item *port_id_item = NULL;
6836 	bool def_policy = false;
6837 	uint16_t udp_dport = 0;
6838 
6839 	if (items == NULL)
6840 		return -1;
6841 	tunnel = is_tunnel_offload_active(dev) ?
6842 		 mlx5_get_tof(items, actions, &tof_rule_type) : NULL;
6843 	if (tunnel) {
6844 		if (priv->representor)
6845 			return rte_flow_error_set
6846 				(error, ENOTSUP,
6847 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6848 				 NULL, "decap not supported for VF representor");
6849 		if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE)
6850 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
6851 		else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE)
6852 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH |
6853 					MLX5_FLOW_ACTION_DECAP;
6854 		grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
6855 					(dev, attr, tunnel, tof_rule_type);
6856 	}
6857 	ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error);
6858 	if (ret < 0)
6859 		return ret;
6860 	is_root = (uint64_t)ret;
6861 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
6862 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
6863 		int type = items->type;
6864 
6865 		if (!mlx5_flow_os_item_supported(type))
6866 			return rte_flow_error_set(error, ENOTSUP,
6867 						  RTE_FLOW_ERROR_TYPE_ITEM,
6868 						  NULL, "item not supported");
6869 		switch (type) {
6870 		case RTE_FLOW_ITEM_TYPE_VOID:
6871 			break;
6872 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
6873 			ret = flow_dv_validate_item_port_id
6874 					(dev, items, attr, item_flags, error);
6875 			if (ret < 0)
6876 				return ret;
6877 			last_item = MLX5_FLOW_ITEM_PORT_ID;
6878 			port_id_item = items;
6879 			break;
6880 		case RTE_FLOW_ITEM_TYPE_ETH:
6881 			ret = mlx5_flow_validate_item_eth(items, item_flags,
6882 							  true, error);
6883 			if (ret < 0)
6884 				return ret;
6885 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
6886 					     MLX5_FLOW_LAYER_OUTER_L2;
6887 			if (items->mask != NULL && items->spec != NULL) {
6888 				ether_type =
6889 					((const struct rte_flow_item_eth *)
6890 					 items->spec)->type;
6891 				ether_type &=
6892 					((const struct rte_flow_item_eth *)
6893 					 items->mask)->type;
6894 				ether_type = rte_be_to_cpu_16(ether_type);
6895 			} else {
6896 				ether_type = 0;
6897 			}
6898 			break;
6899 		case RTE_FLOW_ITEM_TYPE_VLAN:
6900 			ret = flow_dv_validate_item_vlan(items, item_flags,
6901 							 dev, error);
6902 			if (ret < 0)
6903 				return ret;
6904 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
6905 					     MLX5_FLOW_LAYER_OUTER_VLAN;
6906 			if (items->mask != NULL && items->spec != NULL) {
6907 				ether_type =
6908 					((const struct rte_flow_item_vlan *)
6909 					 items->spec)->inner_type;
6910 				ether_type &=
6911 					((const struct rte_flow_item_vlan *)
6912 					 items->mask)->inner_type;
6913 				ether_type = rte_be_to_cpu_16(ether_type);
6914 			} else {
6915 				ether_type = 0;
6916 			}
6917 			/* Store outer VLAN mask for of_push_vlan action. */
6918 			if (!tunnel)
6919 				vlan_m = items->mask;
6920 			break;
6921 		case RTE_FLOW_ITEM_TYPE_IPV4:
6922 			mlx5_flow_tunnel_ip_check(items, next_protocol,
6923 						  &item_flags, &tunnel);
6924 			ret = flow_dv_validate_item_ipv4(dev, items, item_flags,
6925 							 last_item, ether_type,
6926 							 error);
6927 			if (ret < 0)
6928 				return ret;
6929 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
6930 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
6931 			if (items->mask != NULL &&
6932 			    ((const struct rte_flow_item_ipv4 *)
6933 			     items->mask)->hdr.next_proto_id) {
6934 				next_protocol =
6935 					((const struct rte_flow_item_ipv4 *)
6936 					 (items->spec))->hdr.next_proto_id;
6937 				next_protocol &=
6938 					((const struct rte_flow_item_ipv4 *)
6939 					 (items->mask))->hdr.next_proto_id;
6940 			} else {
6941 				/* Reset for inner layer. */
6942 				next_protocol = 0xff;
6943 			}
6944 			break;
6945 		case RTE_FLOW_ITEM_TYPE_IPV6:
6946 			mlx5_flow_tunnel_ip_check(items, next_protocol,
6947 						  &item_flags, &tunnel);
6948 			ret = mlx5_flow_validate_item_ipv6(items, item_flags,
6949 							   last_item,
6950 							   ether_type,
6951 							   &nic_ipv6_mask,
6952 							   error);
6953 			if (ret < 0)
6954 				return ret;
6955 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
6956 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
6957 			if (items->mask != NULL &&
6958 			    ((const struct rte_flow_item_ipv6 *)
6959 			     items->mask)->hdr.proto) {
6960 				item_ipv6_proto =
6961 					((const struct rte_flow_item_ipv6 *)
6962 					 items->spec)->hdr.proto;
6963 				next_protocol =
6964 					((const struct rte_flow_item_ipv6 *)
6965 					 items->spec)->hdr.proto;
6966 				next_protocol &=
6967 					((const struct rte_flow_item_ipv6 *)
6968 					 items->mask)->hdr.proto;
6969 			} else {
6970 				/* Reset for inner layer. */
6971 				next_protocol = 0xff;
6972 			}
6973 			break;
6974 		case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
6975 			ret = flow_dv_validate_item_ipv6_frag_ext(items,
6976 								  item_flags,
6977 								  error);
6978 			if (ret < 0)
6979 				return ret;
6980 			last_item = tunnel ?
6981 					MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
6982 					MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
6983 			if (items->mask != NULL &&
6984 			    ((const struct rte_flow_item_ipv6_frag_ext *)
6985 			     items->mask)->hdr.next_header) {
6986 				next_protocol =
6987 				((const struct rte_flow_item_ipv6_frag_ext *)
6988 				 items->spec)->hdr.next_header;
6989 				next_protocol &=
6990 				((const struct rte_flow_item_ipv6_frag_ext *)
6991 				 items->mask)->hdr.next_header;
6992 			} else {
6993 				/* Reset for inner layer. */
6994 				next_protocol = 0xff;
6995 			}
6996 			break;
6997 		case RTE_FLOW_ITEM_TYPE_TCP:
6998 			ret = mlx5_flow_validate_item_tcp
6999 						(items, item_flags,
7000 						 next_protocol,
7001 						 &nic_tcp_mask,
7002 						 error);
7003 			if (ret < 0)
7004 				return ret;
7005 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
7006 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
7007 			break;
7008 		case RTE_FLOW_ITEM_TYPE_UDP:
7009 			ret = mlx5_flow_validate_item_udp(items, item_flags,
7010 							  next_protocol,
7011 							  error);
7012 			const struct rte_flow_item_udp *spec = items->spec;
7013 			const struct rte_flow_item_udp *mask = items->mask;
7014 			if (!mask)
7015 				mask = &rte_flow_item_udp_mask;
7016 			if (spec != NULL)
7017 				udp_dport = rte_be_to_cpu_16
7018 						(spec->hdr.dst_port &
7019 						 mask->hdr.dst_port);
7020 			if (ret < 0)
7021 				return ret;
7022 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
7023 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
7024 			break;
7025 		case RTE_FLOW_ITEM_TYPE_GRE:
7026 			ret = mlx5_flow_validate_item_gre(items, item_flags,
7027 							  next_protocol, error);
7028 			if (ret < 0)
7029 				return ret;
7030 			gre_item = items;
7031 			last_item = MLX5_FLOW_LAYER_GRE;
7032 			break;
7033 		case RTE_FLOW_ITEM_TYPE_NVGRE:
7034 			ret = mlx5_flow_validate_item_nvgre(items, item_flags,
7035 							    next_protocol,
7036 							    error);
7037 			if (ret < 0)
7038 				return ret;
7039 			last_item = MLX5_FLOW_LAYER_NVGRE;
7040 			break;
7041 		case RTE_FLOW_ITEM_TYPE_GRE_KEY:
7042 			ret = mlx5_flow_validate_item_gre_key
7043 				(items, item_flags, gre_item, error);
7044 			if (ret < 0)
7045 				return ret;
7046 			last_item = MLX5_FLOW_LAYER_GRE_KEY;
7047 			break;
7048 		case RTE_FLOW_ITEM_TYPE_VXLAN:
7049 			ret = mlx5_flow_validate_item_vxlan(dev, udp_dport,
7050 							    items, item_flags,
7051 							    attr, error);
7052 			if (ret < 0)
7053 				return ret;
7054 			last_item = MLX5_FLOW_LAYER_VXLAN;
7055 			break;
7056 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
7057 			ret = mlx5_flow_validate_item_vxlan_gpe(items,
7058 								item_flags, dev,
7059 								error);
7060 			if (ret < 0)
7061 				return ret;
7062 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
7063 			break;
7064 		case RTE_FLOW_ITEM_TYPE_GENEVE:
7065 			ret = mlx5_flow_validate_item_geneve(items,
7066 							     item_flags, dev,
7067 							     error);
7068 			if (ret < 0)
7069 				return ret;
7070 			geneve_item = items;
7071 			last_item = MLX5_FLOW_LAYER_GENEVE;
7072 			break;
7073 		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
7074 			ret = mlx5_flow_validate_item_geneve_opt(items,
7075 								 last_item,
7076 								 geneve_item,
7077 								 dev,
7078 								 error);
7079 			if (ret < 0)
7080 				return ret;
7081 			last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
7082 			break;
7083 		case RTE_FLOW_ITEM_TYPE_MPLS:
7084 			ret = mlx5_flow_validate_item_mpls(dev, items,
7085 							   item_flags,
7086 							   last_item, error);
7087 			if (ret < 0)
7088 				return ret;
7089 			last_item = MLX5_FLOW_LAYER_MPLS;
7090 			break;
7091 
7092 		case RTE_FLOW_ITEM_TYPE_MARK:
7093 			ret = flow_dv_validate_item_mark(dev, items, attr,
7094 							 error);
7095 			if (ret < 0)
7096 				return ret;
7097 			last_item = MLX5_FLOW_ITEM_MARK;
7098 			break;
7099 		case RTE_FLOW_ITEM_TYPE_META:
7100 			ret = flow_dv_validate_item_meta(dev, items, attr,
7101 							 error);
7102 			if (ret < 0)
7103 				return ret;
7104 			last_item = MLX5_FLOW_ITEM_METADATA;
7105 			break;
7106 		case RTE_FLOW_ITEM_TYPE_ICMP:
7107 			ret = mlx5_flow_validate_item_icmp(items, item_flags,
7108 							   next_protocol,
7109 							   error);
7110 			if (ret < 0)
7111 				return ret;
7112 			last_item = MLX5_FLOW_LAYER_ICMP;
7113 			break;
7114 		case RTE_FLOW_ITEM_TYPE_ICMP6:
7115 			ret = mlx5_flow_validate_item_icmp6(items, item_flags,
7116 							    next_protocol,
7117 							    error);
7118 			if (ret < 0)
7119 				return ret;
7120 			item_ipv6_proto = IPPROTO_ICMPV6;
7121 			last_item = MLX5_FLOW_LAYER_ICMP6;
7122 			break;
7123 		case RTE_FLOW_ITEM_TYPE_TAG:
7124 			ret = flow_dv_validate_item_tag(dev, items,
7125 							attr, error);
7126 			if (ret < 0)
7127 				return ret;
7128 			last_item = MLX5_FLOW_ITEM_TAG;
7129 			break;
7130 		case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
7131 		case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
7132 			break;
7133 		case RTE_FLOW_ITEM_TYPE_GTP:
7134 			ret = flow_dv_validate_item_gtp(dev, items, item_flags,
7135 							error);
7136 			if (ret < 0)
7137 				return ret;
7138 			gtp_item = items;
7139 			last_item = MLX5_FLOW_LAYER_GTP;
7140 			break;
7141 		case RTE_FLOW_ITEM_TYPE_GTP_PSC:
7142 			ret = flow_dv_validate_item_gtp_psc(items, last_item,
7143 							    gtp_item, attr,
7144 							    error);
7145 			if (ret < 0)
7146 				return ret;
7147 			last_item = MLX5_FLOW_LAYER_GTP_PSC;
7148 			break;
7149 		case RTE_FLOW_ITEM_TYPE_ECPRI:
7150 			/* Capacity will be checked in the translate stage. */
7151 			ret = mlx5_flow_validate_item_ecpri(items, item_flags,
7152 							    last_item,
7153 							    ether_type,
7154 							    &nic_ecpri_mask,
7155 							    error);
7156 			if (ret < 0)
7157 				return ret;
7158 			last_item = MLX5_FLOW_LAYER_ECPRI;
7159 			break;
7160 		case RTE_FLOW_ITEM_TYPE_INTEGRITY:
7161 			if (item_flags & MLX5_FLOW_ITEM_INTEGRITY)
7162 				return rte_flow_error_set
7163 					(error, ENOTSUP,
7164 					 RTE_FLOW_ERROR_TYPE_ITEM,
7165 					 NULL, "multiple integrity items not supported");
7166 			ret = flow_dv_validate_item_integrity(dev, rule_items,
7167 							      items, error);
7168 			if (ret < 0)
7169 				return ret;
7170 			last_item = MLX5_FLOW_ITEM_INTEGRITY;
7171 			break;
7172 		case RTE_FLOW_ITEM_TYPE_CONNTRACK:
7173 			ret = flow_dv_validate_item_aso_ct(dev, items,
7174 							   &item_flags, error);
7175 			if (ret < 0)
7176 				return ret;
7177 			break;
7178 		case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL:
7179 			/* tunnel offload item was processed before
7180 			 * list it here as a supported type
7181 			 */
7182 			break;
7183 		default:
7184 			return rte_flow_error_set(error, ENOTSUP,
7185 						  RTE_FLOW_ERROR_TYPE_ITEM,
7186 						  NULL, "item not supported");
7187 		}
7188 		item_flags |= last_item;
7189 	}
7190 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
7191 		int type = actions->type;
7192 		bool shared_count = false;
7193 
7194 		if (!mlx5_flow_os_action_supported(type))
7195 			return rte_flow_error_set(error, ENOTSUP,
7196 						  RTE_FLOW_ERROR_TYPE_ACTION,
7197 						  actions,
7198 						  "action not supported");
7199 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
7200 			return rte_flow_error_set(error, ENOTSUP,
7201 						  RTE_FLOW_ERROR_TYPE_ACTION,
7202 						  actions, "too many actions");
7203 		if (action_flags &
7204 			MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
7205 			return rte_flow_error_set(error, ENOTSUP,
7206 				RTE_FLOW_ERROR_TYPE_ACTION,
7207 				NULL, "meter action with policy "
7208 				"must be the last action");
7209 		switch (type) {
7210 		case RTE_FLOW_ACTION_TYPE_VOID:
7211 			break;
7212 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
7213 			ret = flow_dv_validate_action_port_id(dev,
7214 							      action_flags,
7215 							      actions,
7216 							      attr,
7217 							      error);
7218 			if (ret)
7219 				return ret;
7220 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
7221 			++actions_n;
7222 			break;
7223 		case RTE_FLOW_ACTION_TYPE_FLAG:
7224 			ret = flow_dv_validate_action_flag(dev, action_flags,
7225 							   attr, error);
7226 			if (ret < 0)
7227 				return ret;
7228 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7229 				/* Count all modify-header actions as one. */
7230 				if (!(action_flags &
7231 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
7232 					++actions_n;
7233 				action_flags |= MLX5_FLOW_ACTION_FLAG |
7234 						MLX5_FLOW_ACTION_MARK_EXT;
7235 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7236 					modify_after_mirror = 1;
7237 
7238 			} else {
7239 				action_flags |= MLX5_FLOW_ACTION_FLAG;
7240 				++actions_n;
7241 			}
7242 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
7243 			break;
7244 		case RTE_FLOW_ACTION_TYPE_MARK:
7245 			ret = flow_dv_validate_action_mark(dev, actions,
7246 							   action_flags,
7247 							   attr, error);
7248 			if (ret < 0)
7249 				return ret;
7250 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7251 				/* Count all modify-header actions as one. */
7252 				if (!(action_flags &
7253 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
7254 					++actions_n;
7255 				action_flags |= MLX5_FLOW_ACTION_MARK |
7256 						MLX5_FLOW_ACTION_MARK_EXT;
7257 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7258 					modify_after_mirror = 1;
7259 			} else {
7260 				action_flags |= MLX5_FLOW_ACTION_MARK;
7261 				++actions_n;
7262 			}
7263 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
7264 			break;
7265 		case RTE_FLOW_ACTION_TYPE_SET_META:
7266 			ret = flow_dv_validate_action_set_meta(dev, actions,
7267 							       action_flags,
7268 							       attr, error);
7269 			if (ret < 0)
7270 				return ret;
7271 			/* Count all modify-header actions as one action. */
7272 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7273 				++actions_n;
7274 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7275 				modify_after_mirror = 1;
7276 			action_flags |= MLX5_FLOW_ACTION_SET_META;
7277 			rw_act_num += MLX5_ACT_NUM_SET_META;
7278 			break;
7279 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
7280 			ret = flow_dv_validate_action_set_tag(dev, actions,
7281 							      action_flags,
7282 							      attr, error);
7283 			if (ret < 0)
7284 				return ret;
7285 			/* Count all modify-header actions as one action. */
7286 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7287 				++actions_n;
7288 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7289 				modify_after_mirror = 1;
7290 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
7291 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7292 			break;
7293 		case RTE_FLOW_ACTION_TYPE_DROP:
7294 			ret = mlx5_flow_validate_action_drop(action_flags,
7295 							     attr, error);
7296 			if (ret < 0)
7297 				return ret;
7298 			action_flags |= MLX5_FLOW_ACTION_DROP;
7299 			++actions_n;
7300 			break;
7301 		case RTE_FLOW_ACTION_TYPE_QUEUE:
7302 			ret = mlx5_flow_validate_action_queue(actions,
7303 							      action_flags, dev,
7304 							      attr, error);
7305 			if (ret < 0)
7306 				return ret;
7307 			queue_index = ((const struct rte_flow_action_queue *)
7308 							(actions->conf))->index;
7309 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
7310 			++actions_n;
7311 			break;
7312 		case RTE_FLOW_ACTION_TYPE_RSS:
7313 			rss = actions->conf;
7314 			ret = mlx5_flow_validate_action_rss(actions,
7315 							    action_flags, dev,
7316 							    attr, item_flags,
7317 							    error);
7318 			if (ret < 0)
7319 				return ret;
7320 			if (rss && sample_rss &&
7321 			    (sample_rss->level != rss->level ||
7322 			    sample_rss->types != rss->types))
7323 				return rte_flow_error_set(error, ENOTSUP,
7324 					RTE_FLOW_ERROR_TYPE_ACTION,
7325 					NULL,
7326 					"Can't use the different RSS types "
7327 					"or level in the same flow");
7328 			if (rss != NULL && rss->queue_num)
7329 				queue_index = rss->queue[0];
7330 			action_flags |= MLX5_FLOW_ACTION_RSS;
7331 			++actions_n;
7332 			break;
7333 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
7334 			ret =
7335 			mlx5_flow_validate_action_default_miss(action_flags,
7336 					attr, error);
7337 			if (ret < 0)
7338 				return ret;
7339 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
7340 			++actions_n;
7341 			break;
7342 		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
7343 			shared_count = true;
7344 			/* fall-through. */
7345 		case RTE_FLOW_ACTION_TYPE_COUNT:
7346 			ret = flow_dv_validate_action_count(dev, shared_count,
7347 							    action_flags,
7348 							    error);
7349 			if (ret < 0)
7350 				return ret;
7351 			action_flags |= MLX5_FLOW_ACTION_COUNT;
7352 			++actions_n;
7353 			break;
7354 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
7355 			if (flow_dv_validate_action_pop_vlan(dev,
7356 							     action_flags,
7357 							     actions,
7358 							     item_flags, attr,
7359 							     error))
7360 				return -rte_errno;
7361 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7362 				modify_after_mirror = 1;
7363 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
7364 			++actions_n;
7365 			break;
7366 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
7367 			ret = flow_dv_validate_action_push_vlan(dev,
7368 								action_flags,
7369 								vlan_m,
7370 								actions, attr,
7371 								error);
7372 			if (ret < 0)
7373 				return ret;
7374 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7375 				modify_after_mirror = 1;
7376 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
7377 			++actions_n;
7378 			break;
7379 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
7380 			ret = flow_dv_validate_action_set_vlan_pcp
7381 						(action_flags, actions, error);
7382 			if (ret < 0)
7383 				return ret;
7384 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7385 				modify_after_mirror = 1;
7386 			/* Count PCP with push_vlan command. */
7387 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP;
7388 			break;
7389 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
7390 			ret = flow_dv_validate_action_set_vlan_vid
7391 						(item_flags, action_flags,
7392 						 actions, error);
7393 			if (ret < 0)
7394 				return ret;
7395 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7396 				modify_after_mirror = 1;
7397 			/* Count VID with push_vlan command. */
7398 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
7399 			rw_act_num += MLX5_ACT_NUM_MDF_VID;
7400 			break;
7401 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
7402 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
7403 			ret = flow_dv_validate_action_l2_encap(dev,
7404 							       action_flags,
7405 							       actions, attr,
7406 							       error);
7407 			if (ret < 0)
7408 				return ret;
7409 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
7410 			++actions_n;
7411 			break;
7412 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
7413 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
7414 			ret = flow_dv_validate_action_decap(dev, action_flags,
7415 							    actions, item_flags,
7416 							    attr, error);
7417 			if (ret < 0)
7418 				return ret;
7419 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7420 				modify_after_mirror = 1;
7421 			action_flags |= MLX5_FLOW_ACTION_DECAP;
7422 			++actions_n;
7423 			break;
7424 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
7425 			ret = flow_dv_validate_action_raw_encap_decap
7426 				(dev, NULL, actions->conf, attr, &action_flags,
7427 				 &actions_n, actions, item_flags, error);
7428 			if (ret < 0)
7429 				return ret;
7430 			break;
7431 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
7432 			decap = actions->conf;
7433 			while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID)
7434 				;
7435 			if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
7436 				encap = NULL;
7437 				actions--;
7438 			} else {
7439 				encap = actions->conf;
7440 			}
7441 			ret = flow_dv_validate_action_raw_encap_decap
7442 					   (dev,
7443 					    decap ? decap : &empty_decap, encap,
7444 					    attr, &action_flags, &actions_n,
7445 					    actions, item_flags, error);
7446 			if (ret < 0)
7447 				return ret;
7448 			if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
7449 			    (action_flags & MLX5_FLOW_ACTION_DECAP))
7450 				modify_after_mirror = 1;
7451 			break;
7452 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
7453 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
7454 			ret = flow_dv_validate_action_modify_mac(action_flags,
7455 								 actions,
7456 								 item_flags,
7457 								 error);
7458 			if (ret < 0)
7459 				return ret;
7460 			/* Count all modify-header actions as one action. */
7461 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7462 				++actions_n;
7463 			action_flags |= actions->type ==
7464 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
7465 						MLX5_FLOW_ACTION_SET_MAC_SRC :
7466 						MLX5_FLOW_ACTION_SET_MAC_DST;
7467 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7468 				modify_after_mirror = 1;
7469 			/*
7470 			 * Even if the source and destination MAC addresses have
7471 			 * overlap in the header with 4B alignment, the convert
7472 			 * function will handle them separately and 4 SW actions
7473 			 * will be created. And 2 actions will be added each
7474 			 * time no matter how many bytes of address will be set.
7475 			 */
7476 			rw_act_num += MLX5_ACT_NUM_MDF_MAC;
7477 			break;
7478 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
7479 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
7480 			ret = flow_dv_validate_action_modify_ipv4(action_flags,
7481 								  actions,
7482 								  item_flags,
7483 								  error);
7484 			if (ret < 0)
7485 				return ret;
7486 			/* Count all modify-header actions as one action. */
7487 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7488 				++actions_n;
7489 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7490 				modify_after_mirror = 1;
7491 			action_flags |= actions->type ==
7492 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
7493 						MLX5_FLOW_ACTION_SET_IPV4_SRC :
7494 						MLX5_FLOW_ACTION_SET_IPV4_DST;
7495 			rw_act_num += MLX5_ACT_NUM_MDF_IPV4;
7496 			break;
7497 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
7498 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
7499 			ret = flow_dv_validate_action_modify_ipv6(action_flags,
7500 								  actions,
7501 								  item_flags,
7502 								  error);
7503 			if (ret < 0)
7504 				return ret;
7505 			if (item_ipv6_proto == IPPROTO_ICMPV6)
7506 				return rte_flow_error_set(error, ENOTSUP,
7507 					RTE_FLOW_ERROR_TYPE_ACTION,
7508 					actions,
7509 					"Can't change header "
7510 					"with ICMPv6 proto");
7511 			/* Count all modify-header actions as one action. */
7512 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7513 				++actions_n;
7514 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7515 				modify_after_mirror = 1;
7516 			action_flags |= actions->type ==
7517 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
7518 						MLX5_FLOW_ACTION_SET_IPV6_SRC :
7519 						MLX5_FLOW_ACTION_SET_IPV6_DST;
7520 			rw_act_num += MLX5_ACT_NUM_MDF_IPV6;
7521 			break;
7522 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
7523 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
7524 			ret = flow_dv_validate_action_modify_tp(action_flags,
7525 								actions,
7526 								item_flags,
7527 								error);
7528 			if (ret < 0)
7529 				return ret;
7530 			/* Count all modify-header actions as one action. */
7531 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7532 				++actions_n;
7533 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7534 				modify_after_mirror = 1;
7535 			action_flags |= actions->type ==
7536 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
7537 						MLX5_FLOW_ACTION_SET_TP_SRC :
7538 						MLX5_FLOW_ACTION_SET_TP_DST;
7539 			rw_act_num += MLX5_ACT_NUM_MDF_PORT;
7540 			break;
7541 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
7542 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
7543 			ret = flow_dv_validate_action_modify_ttl(action_flags,
7544 								 actions,
7545 								 item_flags,
7546 								 error);
7547 			if (ret < 0)
7548 				return ret;
7549 			/* Count all modify-header actions as one action. */
7550 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7551 				++actions_n;
7552 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7553 				modify_after_mirror = 1;
7554 			action_flags |= actions->type ==
7555 					RTE_FLOW_ACTION_TYPE_SET_TTL ?
7556 						MLX5_FLOW_ACTION_SET_TTL :
7557 						MLX5_FLOW_ACTION_DEC_TTL;
7558 			rw_act_num += MLX5_ACT_NUM_MDF_TTL;
7559 			break;
7560 		case RTE_FLOW_ACTION_TYPE_JUMP:
7561 			ret = flow_dv_validate_action_jump(dev, tunnel, actions,
7562 							   action_flags,
7563 							   attr, external,
7564 							   error);
7565 			if (ret)
7566 				return ret;
7567 			if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
7568 			    fdb_mirror_limit)
7569 				return rte_flow_error_set(error, EINVAL,
7570 						  RTE_FLOW_ERROR_TYPE_ACTION,
7571 						  NULL,
7572 						  "sample and jump action combination is not supported");
7573 			++actions_n;
7574 			action_flags |= MLX5_FLOW_ACTION_JUMP;
7575 			break;
7576 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
7577 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
7578 			ret = flow_dv_validate_action_modify_tcp_seq
7579 								(action_flags,
7580 								 actions,
7581 								 item_flags,
7582 								 error);
7583 			if (ret < 0)
7584 				return ret;
7585 			/* Count all modify-header actions as one action. */
7586 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7587 				++actions_n;
7588 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7589 				modify_after_mirror = 1;
7590 			action_flags |= actions->type ==
7591 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
7592 						MLX5_FLOW_ACTION_INC_TCP_SEQ :
7593 						MLX5_FLOW_ACTION_DEC_TCP_SEQ;
7594 			rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ;
7595 			break;
7596 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
7597 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
7598 			ret = flow_dv_validate_action_modify_tcp_ack
7599 								(action_flags,
7600 								 actions,
7601 								 item_flags,
7602 								 error);
7603 			if (ret < 0)
7604 				return ret;
7605 			/* Count all modify-header actions as one action. */
7606 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7607 				++actions_n;
7608 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7609 				modify_after_mirror = 1;
7610 			action_flags |= actions->type ==
7611 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
7612 						MLX5_FLOW_ACTION_INC_TCP_ACK :
7613 						MLX5_FLOW_ACTION_DEC_TCP_ACK;
7614 			rw_act_num += MLX5_ACT_NUM_MDF_TCPACK;
7615 			break;
7616 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
7617 			break;
7618 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
7619 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
7620 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7621 			break;
7622 		case RTE_FLOW_ACTION_TYPE_METER:
7623 			ret = mlx5_flow_validate_action_meter(dev,
7624 							      action_flags,
7625 							      actions, attr,
7626 							      port_id_item,
7627 							      &def_policy,
7628 							      error);
7629 			if (ret < 0)
7630 				return ret;
7631 			action_flags |= MLX5_FLOW_ACTION_METER;
7632 			if (!def_policy)
7633 				action_flags |=
7634 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
7635 			++actions_n;
7636 			/* Meter action will add one more TAG action. */
7637 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7638 			break;
7639 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
7640 			if (!attr->transfer && !attr->group)
7641 				return rte_flow_error_set(error, ENOTSUP,
7642 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
7643 									   NULL,
7644 			  "Shared ASO age action is not supported for group 0");
7645 			if (action_flags & MLX5_FLOW_ACTION_AGE)
7646 				return rte_flow_error_set
7647 						  (error, EINVAL,
7648 						   RTE_FLOW_ERROR_TYPE_ACTION,
7649 						   NULL,
7650 						   "duplicate age actions set");
7651 			action_flags |= MLX5_FLOW_ACTION_AGE;
7652 			++actions_n;
7653 			break;
7654 		case RTE_FLOW_ACTION_TYPE_AGE:
7655 			ret = flow_dv_validate_action_age(action_flags,
7656 							  actions, dev,
7657 							  error);
7658 			if (ret < 0)
7659 				return ret;
7660 			/*
7661 			 * Validate the regular AGE action (using counter)
7662 			 * mutual exclusion with share counter actions.
7663 			 */
7664 			if (!priv->sh->flow_hit_aso_en) {
7665 				if (shared_count)
7666 					return rte_flow_error_set
7667 						(error, EINVAL,
7668 						RTE_FLOW_ERROR_TYPE_ACTION,
7669 						NULL,
7670 						"old age and shared count combination is not supported");
7671 				if (sample_count)
7672 					return rte_flow_error_set
7673 						(error, EINVAL,
7674 						RTE_FLOW_ERROR_TYPE_ACTION,
7675 						NULL,
7676 						"old age action and count must be in the same sub flow");
7677 			}
7678 			action_flags |= MLX5_FLOW_ACTION_AGE;
7679 			++actions_n;
7680 			break;
7681 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
7682 			ret = flow_dv_validate_action_modify_ipv4_dscp
7683 							 (action_flags,
7684 							  actions,
7685 							  item_flags,
7686 							  error);
7687 			if (ret < 0)
7688 				return ret;
7689 			/* Count all modify-header actions as one action. */
7690 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7691 				++actions_n;
7692 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7693 				modify_after_mirror = 1;
7694 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
7695 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7696 			break;
7697 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
7698 			ret = flow_dv_validate_action_modify_ipv6_dscp
7699 								(action_flags,
7700 								 actions,
7701 								 item_flags,
7702 								 error);
7703 			if (ret < 0)
7704 				return ret;
7705 			/* Count all modify-header actions as one action. */
7706 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7707 				++actions_n;
7708 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7709 				modify_after_mirror = 1;
7710 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
7711 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7712 			break;
7713 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
7714 			ret = flow_dv_validate_action_sample(&action_flags,
7715 							     actions, dev,
7716 							     attr, item_flags,
7717 							     rss, &sample_rss,
7718 							     &sample_count,
7719 							     &fdb_mirror_limit,
7720 							     error);
7721 			if (ret < 0)
7722 				return ret;
7723 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
7724 			++actions_n;
7725 			break;
7726 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
7727 			ret = flow_dv_validate_action_modify_field(dev,
7728 								   action_flags,
7729 								   actions,
7730 								   attr,
7731 								   error);
7732 			if (ret < 0)
7733 				return ret;
7734 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7735 				modify_after_mirror = 1;
7736 			/* Count all modify-header actions as one action. */
7737 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7738 				++actions_n;
7739 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
7740 			rw_act_num += ret;
7741 			break;
7742 		case RTE_FLOW_ACTION_TYPE_CONNTRACK:
7743 			ret = flow_dv_validate_action_aso_ct(dev, action_flags,
7744 							     item_flags, attr,
7745 							     error);
7746 			if (ret < 0)
7747 				return ret;
7748 			action_flags |= MLX5_FLOW_ACTION_CT;
7749 			break;
7750 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
7751 			/* tunnel offload action was processed before
7752 			 * list it here as a supported type
7753 			 */
7754 			break;
7755 		default:
7756 			return rte_flow_error_set(error, ENOTSUP,
7757 						  RTE_FLOW_ERROR_TYPE_ACTION,
7758 						  actions,
7759 						  "action not supported");
7760 		}
7761 	}
7762 	/*
7763 	 * Validate actions in flow rules
7764 	 * - Explicit decap action is prohibited by the tunnel offload API.
7765 	 * - Drop action in tunnel steer rule is prohibited by the API.
7766 	 * - Application cannot use MARK action because it's value can mask
7767 	 *   tunnel default miss nitification.
7768 	 * - JUMP in tunnel match rule has no support in current PMD
7769 	 *   implementation.
7770 	 * - TAG & META are reserved for future uses.
7771 	 */
7772 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) {
7773 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP    |
7774 					    MLX5_FLOW_ACTION_MARK     |
7775 					    MLX5_FLOW_ACTION_SET_TAG  |
7776 					    MLX5_FLOW_ACTION_SET_META |
7777 					    MLX5_FLOW_ACTION_DROP;
7778 
7779 		if (action_flags & bad_actions_mask)
7780 			return rte_flow_error_set
7781 					(error, EINVAL,
7782 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7783 					"Invalid RTE action in tunnel "
7784 					"set decap rule");
7785 		if (!(action_flags & MLX5_FLOW_ACTION_JUMP))
7786 			return rte_flow_error_set
7787 					(error, EINVAL,
7788 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7789 					"tunnel set decap rule must terminate "
7790 					"with JUMP");
7791 		if (!attr->ingress)
7792 			return rte_flow_error_set
7793 					(error, EINVAL,
7794 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7795 					"tunnel flows for ingress traffic only");
7796 	}
7797 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) {
7798 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP    |
7799 					    MLX5_FLOW_ACTION_MARK    |
7800 					    MLX5_FLOW_ACTION_SET_TAG |
7801 					    MLX5_FLOW_ACTION_SET_META;
7802 
7803 		if (action_flags & bad_actions_mask)
7804 			return rte_flow_error_set
7805 					(error, EINVAL,
7806 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7807 					"Invalid RTE action in tunnel "
7808 					"set match rule");
7809 	}
7810 	/*
7811 	 * Validate the drop action mutual exclusion with other actions.
7812 	 * Drop action is mutually-exclusive with any other action, except for
7813 	 * Count action.
7814 	 * Drop action compatibility with tunnel offload was already validated.
7815 	 */
7816 	if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH |
7817 			    MLX5_FLOW_ACTION_TUNNEL_MATCH));
7818 	else if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
7819 	    (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT)))
7820 		return rte_flow_error_set(error, EINVAL,
7821 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7822 					  "Drop action is mutually-exclusive "
7823 					  "with any other action, except for "
7824 					  "Count action");
7825 	/* Eswitch has few restrictions on using items and actions */
7826 	if (attr->transfer) {
7827 		if (!mlx5_flow_ext_mreg_supported(dev) &&
7828 		    action_flags & MLX5_FLOW_ACTION_FLAG)
7829 			return rte_flow_error_set(error, ENOTSUP,
7830 						  RTE_FLOW_ERROR_TYPE_ACTION,
7831 						  NULL,
7832 						  "unsupported action FLAG");
7833 		if (!mlx5_flow_ext_mreg_supported(dev) &&
7834 		    action_flags & MLX5_FLOW_ACTION_MARK)
7835 			return rte_flow_error_set(error, ENOTSUP,
7836 						  RTE_FLOW_ERROR_TYPE_ACTION,
7837 						  NULL,
7838 						  "unsupported action MARK");
7839 		if (action_flags & MLX5_FLOW_ACTION_QUEUE)
7840 			return rte_flow_error_set(error, ENOTSUP,
7841 						  RTE_FLOW_ERROR_TYPE_ACTION,
7842 						  NULL,
7843 						  "unsupported action QUEUE");
7844 		if (action_flags & MLX5_FLOW_ACTION_RSS)
7845 			return rte_flow_error_set(error, ENOTSUP,
7846 						  RTE_FLOW_ERROR_TYPE_ACTION,
7847 						  NULL,
7848 						  "unsupported action RSS");
7849 		if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
7850 			return rte_flow_error_set(error, EINVAL,
7851 						  RTE_FLOW_ERROR_TYPE_ACTION,
7852 						  actions,
7853 						  "no fate action is found");
7854 	} else {
7855 		if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress)
7856 			return rte_flow_error_set(error, EINVAL,
7857 						  RTE_FLOW_ERROR_TYPE_ACTION,
7858 						  actions,
7859 						  "no fate action is found");
7860 	}
7861 	/*
7862 	 * Continue validation for Xcap and VLAN actions.
7863 	 * If hairpin is working in explicit TX rule mode, there is no actions
7864 	 * splitting and the validation of hairpin ingress flow should be the
7865 	 * same as other standard flows.
7866 	 */
7867 	if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS |
7868 			     MLX5_FLOW_VLAN_ACTIONS)) &&
7869 	    (queue_index == 0xFFFF ||
7870 	     mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN ||
7871 	     ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL &&
7872 	     conf->tx_explicit != 0))) {
7873 		if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
7874 		    MLX5_FLOW_XCAP_ACTIONS)
7875 			return rte_flow_error_set(error, ENOTSUP,
7876 						  RTE_FLOW_ERROR_TYPE_ACTION,
7877 						  NULL, "encap and decap "
7878 						  "combination aren't supported");
7879 		if (!attr->transfer && attr->ingress) {
7880 			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
7881 				return rte_flow_error_set
7882 						(error, ENOTSUP,
7883 						 RTE_FLOW_ERROR_TYPE_ACTION,
7884 						 NULL, "encap is not supported"
7885 						 " for ingress traffic");
7886 			else if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
7887 				return rte_flow_error_set
7888 						(error, ENOTSUP,
7889 						 RTE_FLOW_ERROR_TYPE_ACTION,
7890 						 NULL, "push VLAN action not "
7891 						 "supported for ingress");
7892 			else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) ==
7893 					MLX5_FLOW_VLAN_ACTIONS)
7894 				return rte_flow_error_set
7895 						(error, ENOTSUP,
7896 						 RTE_FLOW_ERROR_TYPE_ACTION,
7897 						 NULL, "no support for "
7898 						 "multiple VLAN actions");
7899 		}
7900 	}
7901 	if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) {
7902 		if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
7903 			~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) &&
7904 			attr->ingress)
7905 			return rte_flow_error_set
7906 				(error, ENOTSUP,
7907 				RTE_FLOW_ERROR_TYPE_ACTION,
7908 				NULL, "fate action not supported for "
7909 				"meter with policy");
7910 		if (attr->egress) {
7911 			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
7912 				return rte_flow_error_set
7913 					(error, ENOTSUP,
7914 					RTE_FLOW_ERROR_TYPE_ACTION,
7915 					NULL, "modify header action in egress "
7916 					"cannot be done before meter action");
7917 			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
7918 				return rte_flow_error_set
7919 					(error, ENOTSUP,
7920 					RTE_FLOW_ERROR_TYPE_ACTION,
7921 					NULL, "encap action in egress "
7922 					"cannot be done before meter action");
7923 			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
7924 				return rte_flow_error_set
7925 					(error, ENOTSUP,
7926 					RTE_FLOW_ERROR_TYPE_ACTION,
7927 					NULL, "push vlan action in egress "
7928 					"cannot be done before meter action");
7929 		}
7930 	}
7931 	/*
7932 	 * Hairpin flow will add one more TAG action in TX implicit mode.
7933 	 * In TX explicit mode, there will be no hairpin flow ID.
7934 	 */
7935 	if (hairpin > 0)
7936 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
7937 	/* extra metadata enabled: one more TAG action will be add. */
7938 	if (dev_conf->dv_flow_en &&
7939 	    dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
7940 	    mlx5_flow_ext_mreg_supported(dev))
7941 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
7942 	if (rw_act_num >
7943 			flow_dv_modify_hdr_action_max(dev, is_root)) {
7944 		return rte_flow_error_set(error, ENOTSUP,
7945 					  RTE_FLOW_ERROR_TYPE_ACTION,
7946 					  NULL, "too many header modify"
7947 					  " actions to support");
7948 	}
7949 	/* Eswitch egress mirror and modify flow has limitation on CX5 */
7950 	if (fdb_mirror_limit && modify_after_mirror)
7951 		return rte_flow_error_set(error, EINVAL,
7952 				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7953 				"sample before modify action is not supported");
7954 	return 0;
7955 }
7956 
7957 /**
7958  * Internal preparation function. Allocates the DV flow size,
7959  * this size is constant.
7960  *
7961  * @param[in] dev
7962  *   Pointer to the rte_eth_dev structure.
7963  * @param[in] attr
7964  *   Pointer to the flow attributes.
7965  * @param[in] items
7966  *   Pointer to the list of items.
7967  * @param[in] actions
7968  *   Pointer to the list of actions.
7969  * @param[out] error
7970  *   Pointer to the error structure.
7971  *
7972  * @return
7973  *   Pointer to mlx5_flow object on success,
7974  *   otherwise NULL and rte_errno is set.
7975  */
7976 static struct mlx5_flow *
7977 flow_dv_prepare(struct rte_eth_dev *dev,
7978 		const struct rte_flow_attr *attr __rte_unused,
7979 		const struct rte_flow_item items[] __rte_unused,
7980 		const struct rte_flow_action actions[] __rte_unused,
7981 		struct rte_flow_error *error)
7982 {
7983 	uint32_t handle_idx = 0;
7984 	struct mlx5_flow *dev_flow;
7985 	struct mlx5_flow_handle *dev_handle;
7986 	struct mlx5_priv *priv = dev->data->dev_private;
7987 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
7988 
7989 	MLX5_ASSERT(wks);
7990 	wks->skip_matcher_reg = 0;
7991 	wks->policy = NULL;
7992 	wks->final_policy = NULL;
7993 	/* In case of corrupting the memory. */
7994 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
7995 		rte_flow_error_set(error, ENOSPC,
7996 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
7997 				   "not free temporary device flow");
7998 		return NULL;
7999 	}
8000 	dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
8001 				   &handle_idx);
8002 	if (!dev_handle) {
8003 		rte_flow_error_set(error, ENOMEM,
8004 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8005 				   "not enough memory to create flow handle");
8006 		return NULL;
8007 	}
8008 	MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows));
8009 	dev_flow = &wks->flows[wks->flow_idx++];
8010 	memset(dev_flow, 0, sizeof(*dev_flow));
8011 	dev_flow->handle = dev_handle;
8012 	dev_flow->handle_idx = handle_idx;
8013 	dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
8014 	dev_flow->ingress = attr->ingress;
8015 	dev_flow->dv.transfer = attr->transfer;
8016 	return dev_flow;
8017 }
8018 
8019 #ifdef RTE_LIBRTE_MLX5_DEBUG
8020 /**
8021  * Sanity check for match mask and value. Similar to check_valid_spec() in
8022  * kernel driver. If unmasked bit is present in value, it returns failure.
8023  *
8024  * @param match_mask
8025  *   pointer to match mask buffer.
8026  * @param match_value
8027  *   pointer to match value buffer.
8028  *
8029  * @return
8030  *   0 if valid, -EINVAL otherwise.
8031  */
8032 static int
8033 flow_dv_check_valid_spec(void *match_mask, void *match_value)
8034 {
8035 	uint8_t *m = match_mask;
8036 	uint8_t *v = match_value;
8037 	unsigned int i;
8038 
8039 	for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) {
8040 		if (v[i] & ~m[i]) {
8041 			DRV_LOG(ERR,
8042 				"match_value differs from match_criteria"
8043 				" %p[%u] != %p[%u]",
8044 				match_value, i, match_mask, i);
8045 			return -EINVAL;
8046 		}
8047 	}
8048 	return 0;
8049 }
8050 #endif
8051 
8052 /**
8053  * Add match of ip_version.
8054  *
8055  * @param[in] group
8056  *   Flow group.
8057  * @param[in] headers_v
8058  *   Values header pointer.
8059  * @param[in] headers_m
8060  *   Masks header pointer.
8061  * @param[in] ip_version
8062  *   The IP version to set.
8063  */
8064 static inline void
8065 flow_dv_set_match_ip_version(uint32_t group,
8066 			     void *headers_v,
8067 			     void *headers_m,
8068 			     uint8_t ip_version)
8069 {
8070 	if (group == 0)
8071 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
8072 	else
8073 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version,
8074 			 ip_version);
8075 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, ip_version);
8076 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0);
8077 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype, 0);
8078 }
8079 
8080 /**
8081  * Add Ethernet item to matcher and to the value.
8082  *
8083  * @param[in, out] matcher
8084  *   Flow matcher.
8085  * @param[in, out] key
8086  *   Flow matcher value.
8087  * @param[in] item
8088  *   Flow pattern to translate.
8089  * @param[in] inner
8090  *   Item is inner pattern.
8091  */
8092 static void
8093 flow_dv_translate_item_eth(void *matcher, void *key,
8094 			   const struct rte_flow_item *item, int inner,
8095 			   uint32_t group)
8096 {
8097 	const struct rte_flow_item_eth *eth_m = item->mask;
8098 	const struct rte_flow_item_eth *eth_v = item->spec;
8099 	const struct rte_flow_item_eth nic_mask = {
8100 		.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8101 		.src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8102 		.type = RTE_BE16(0xffff),
8103 		.has_vlan = 0,
8104 	};
8105 	void *hdrs_m;
8106 	void *hdrs_v;
8107 	char *l24_v;
8108 	unsigned int i;
8109 
8110 	if (!eth_v)
8111 		return;
8112 	if (!eth_m)
8113 		eth_m = &nic_mask;
8114 	if (inner) {
8115 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8116 					 inner_headers);
8117 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8118 	} else {
8119 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8120 					 outer_headers);
8121 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8122 	}
8123 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, dmac_47_16),
8124 	       &eth_m->dst, sizeof(eth_m->dst));
8125 	/* The value must be in the range of the mask. */
8126 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16);
8127 	for (i = 0; i < sizeof(eth_m->dst); ++i)
8128 		l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i];
8129 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, smac_47_16),
8130 	       &eth_m->src, sizeof(eth_m->src));
8131 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16);
8132 	/* The value must be in the range of the mask. */
8133 	for (i = 0; i < sizeof(eth_m->dst); ++i)
8134 		l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i];
8135 	/*
8136 	 * HW supports match on one Ethertype, the Ethertype following the last
8137 	 * VLAN tag of the packet (see PRM).
8138 	 * Set match on ethertype only if ETH header is not followed by VLAN.
8139 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8140 	 * ethertype, and use ip_version field instead.
8141 	 * eCPRI over Ether layer will use type value 0xAEFE.
8142 	 */
8143 	if (eth_m->type == 0xFFFF) {
8144 		/* Set cvlan_tag mask for any single\multi\un-tagged case. */
8145 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8146 		switch (eth_v->type) {
8147 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8148 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8149 			return;
8150 		case RTE_BE16(RTE_ETHER_TYPE_QINQ):
8151 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8152 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8153 			return;
8154 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8155 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
8156 			return;
8157 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8158 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
8159 			return;
8160 		default:
8161 			break;
8162 		}
8163 	}
8164 	if (eth_m->has_vlan) {
8165 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8166 		if (eth_v->has_vlan) {
8167 			/*
8168 			 * Here, when also has_more_vlan field in VLAN item is
8169 			 * not set, only single-tagged packets will be matched.
8170 			 */
8171 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8172 			return;
8173 		}
8174 	}
8175 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
8176 		 rte_be_to_cpu_16(eth_m->type));
8177 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
8178 	*(uint16_t *)(l24_v) = eth_m->type & eth_v->type;
8179 }
8180 
8181 /**
8182  * Add VLAN item to matcher and to the value.
8183  *
8184  * @param[in, out] dev_flow
8185  *   Flow descriptor.
8186  * @param[in, out] matcher
8187  *   Flow matcher.
8188  * @param[in, out] key
8189  *   Flow matcher value.
8190  * @param[in] item
8191  *   Flow pattern to translate.
8192  * @param[in] inner
8193  *   Item is inner pattern.
8194  */
8195 static void
8196 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow,
8197 			    void *matcher, void *key,
8198 			    const struct rte_flow_item *item,
8199 			    int inner, uint32_t group)
8200 {
8201 	const struct rte_flow_item_vlan *vlan_m = item->mask;
8202 	const struct rte_flow_item_vlan *vlan_v = item->spec;
8203 	void *hdrs_m;
8204 	void *hdrs_v;
8205 	uint16_t tci_m;
8206 	uint16_t tci_v;
8207 
8208 	if (inner) {
8209 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8210 					 inner_headers);
8211 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8212 	} else {
8213 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8214 					 outer_headers);
8215 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8216 		/*
8217 		 * This is workaround, masks are not supported,
8218 		 * and pre-validated.
8219 		 */
8220 		if (vlan_v)
8221 			dev_flow->handle->vf_vlan.tag =
8222 					rte_be_to_cpu_16(vlan_v->tci) & 0x0fff;
8223 	}
8224 	/*
8225 	 * When VLAN item exists in flow, mark packet as tagged,
8226 	 * even if TCI is not specified.
8227 	 */
8228 	if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag)) {
8229 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8230 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8231 	}
8232 	if (!vlan_v)
8233 		return;
8234 	if (!vlan_m)
8235 		vlan_m = &rte_flow_item_vlan_mask;
8236 	tci_m = rte_be_to_cpu_16(vlan_m->tci);
8237 	tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci);
8238 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_vid, tci_m);
8239 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v);
8240 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_cfi, tci_m >> 12);
8241 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12);
8242 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_prio, tci_m >> 13);
8243 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13);
8244 	/*
8245 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8246 	 * ethertype, and use ip_version field instead.
8247 	 */
8248 	if (vlan_m->inner_type == 0xFFFF) {
8249 		switch (vlan_v->inner_type) {
8250 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8251 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8252 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8253 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
8254 			return;
8255 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8256 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
8257 			return;
8258 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8259 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
8260 			return;
8261 		default:
8262 			break;
8263 		}
8264 	}
8265 	if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) {
8266 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8267 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8268 		/* Only one vlan_tag bit can be set. */
8269 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
8270 		return;
8271 	}
8272 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
8273 		 rte_be_to_cpu_16(vlan_m->inner_type));
8274 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype,
8275 		 rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type));
8276 }
8277 
8278 /**
8279  * Add IPV4 item to matcher and to the value.
8280  *
8281  * @param[in, out] matcher
8282  *   Flow matcher.
8283  * @param[in, out] key
8284  *   Flow matcher value.
8285  * @param[in] item
8286  *   Flow pattern to translate.
8287  * @param[in] inner
8288  *   Item is inner pattern.
8289  * @param[in] group
8290  *   The group to insert the rule.
8291  */
8292 static void
8293 flow_dv_translate_item_ipv4(void *matcher, void *key,
8294 			    const struct rte_flow_item *item,
8295 			    int inner, uint32_t group)
8296 {
8297 	const struct rte_flow_item_ipv4 *ipv4_m = item->mask;
8298 	const struct rte_flow_item_ipv4 *ipv4_v = item->spec;
8299 	const struct rte_flow_item_ipv4 nic_mask = {
8300 		.hdr = {
8301 			.src_addr = RTE_BE32(0xffffffff),
8302 			.dst_addr = RTE_BE32(0xffffffff),
8303 			.type_of_service = 0xff,
8304 			.next_proto_id = 0xff,
8305 			.time_to_live = 0xff,
8306 		},
8307 	};
8308 	void *headers_m;
8309 	void *headers_v;
8310 	char *l24_m;
8311 	char *l24_v;
8312 	uint8_t tos, ihl_m, ihl_v;
8313 
8314 	if (inner) {
8315 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8316 					 inner_headers);
8317 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8318 	} else {
8319 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8320 					 outer_headers);
8321 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8322 	}
8323 	flow_dv_set_match_ip_version(group, headers_v, headers_m, 4);
8324 	if (!ipv4_v)
8325 		return;
8326 	if (!ipv4_m)
8327 		ipv4_m = &nic_mask;
8328 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8329 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
8330 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8331 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
8332 	*(uint32_t *)l24_m = ipv4_m->hdr.dst_addr;
8333 	*(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr;
8334 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8335 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
8336 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8337 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
8338 	*(uint32_t *)l24_m = ipv4_m->hdr.src_addr;
8339 	*(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr;
8340 	tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service;
8341 	ihl_m = ipv4_m->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK;
8342 	ihl_v = ipv4_v->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK;
8343 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_ihl, ihl_m);
8344 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_ihl, ihl_m & ihl_v);
8345 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn,
8346 		 ipv4_m->hdr.type_of_service);
8347 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos);
8348 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp,
8349 		 ipv4_m->hdr.type_of_service >> 2);
8350 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2);
8351 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8352 		 ipv4_m->hdr.next_proto_id);
8353 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8354 		 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id);
8355 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
8356 		 ipv4_m->hdr.time_to_live);
8357 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8358 		 ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live);
8359 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
8360 		 !!(ipv4_m->hdr.fragment_offset));
8361 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8362 		 !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset));
8363 }
8364 
8365 /**
8366  * Add IPV6 item to matcher and to the value.
8367  *
8368  * @param[in, out] matcher
8369  *   Flow matcher.
8370  * @param[in, out] key
8371  *   Flow matcher value.
8372  * @param[in] item
8373  *   Flow pattern to translate.
8374  * @param[in] inner
8375  *   Item is inner pattern.
8376  * @param[in] group
8377  *   The group to insert the rule.
8378  */
8379 static void
8380 flow_dv_translate_item_ipv6(void *matcher, void *key,
8381 			    const struct rte_flow_item *item,
8382 			    int inner, uint32_t group)
8383 {
8384 	const struct rte_flow_item_ipv6 *ipv6_m = item->mask;
8385 	const struct rte_flow_item_ipv6 *ipv6_v = item->spec;
8386 	const struct rte_flow_item_ipv6 nic_mask = {
8387 		.hdr = {
8388 			.src_addr =
8389 				"\xff\xff\xff\xff\xff\xff\xff\xff"
8390 				"\xff\xff\xff\xff\xff\xff\xff\xff",
8391 			.dst_addr =
8392 				"\xff\xff\xff\xff\xff\xff\xff\xff"
8393 				"\xff\xff\xff\xff\xff\xff\xff\xff",
8394 			.vtc_flow = RTE_BE32(0xffffffff),
8395 			.proto = 0xff,
8396 			.hop_limits = 0xff,
8397 		},
8398 	};
8399 	void *headers_m;
8400 	void *headers_v;
8401 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8402 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8403 	char *l24_m;
8404 	char *l24_v;
8405 	uint32_t vtc_m;
8406 	uint32_t vtc_v;
8407 	int i;
8408 	int size;
8409 
8410 	if (inner) {
8411 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8412 					 inner_headers);
8413 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8414 	} else {
8415 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8416 					 outer_headers);
8417 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8418 	}
8419 	flow_dv_set_match_ip_version(group, headers_v, headers_m, 6);
8420 	if (!ipv6_v)
8421 		return;
8422 	if (!ipv6_m)
8423 		ipv6_m = &nic_mask;
8424 	size = sizeof(ipv6_m->hdr.dst_addr);
8425 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8426 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
8427 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8428 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
8429 	memcpy(l24_m, ipv6_m->hdr.dst_addr, size);
8430 	for (i = 0; i < size; ++i)
8431 		l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i];
8432 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8433 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
8434 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8435 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
8436 	memcpy(l24_m, ipv6_m->hdr.src_addr, size);
8437 	for (i = 0; i < size; ++i)
8438 		l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i];
8439 	/* TOS. */
8440 	vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow);
8441 	vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow);
8442 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20);
8443 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20);
8444 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22);
8445 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22);
8446 	/* Label. */
8447 	if (inner) {
8448 		MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label,
8449 			 vtc_m);
8450 		MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label,
8451 			 vtc_v);
8452 	} else {
8453 		MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label,
8454 			 vtc_m);
8455 		MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label,
8456 			 vtc_v);
8457 	}
8458 	/* Protocol. */
8459 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8460 		 ipv6_m->hdr.proto);
8461 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8462 		 ipv6_v->hdr.proto & ipv6_m->hdr.proto);
8463 	/* Hop limit. */
8464 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
8465 		 ipv6_m->hdr.hop_limits);
8466 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8467 		 ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits);
8468 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
8469 		 !!(ipv6_m->has_frag_ext));
8470 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8471 		 !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext));
8472 }
8473 
8474 /**
8475  * Add IPV6 fragment extension item to matcher and to the value.
8476  *
8477  * @param[in, out] matcher
8478  *   Flow matcher.
8479  * @param[in, out] key
8480  *   Flow matcher value.
8481  * @param[in] item
8482  *   Flow pattern to translate.
8483  * @param[in] inner
8484  *   Item is inner pattern.
8485  */
8486 static void
8487 flow_dv_translate_item_ipv6_frag_ext(void *matcher, void *key,
8488 				     const struct rte_flow_item *item,
8489 				     int inner)
8490 {
8491 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m = item->mask;
8492 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v = item->spec;
8493 	const struct rte_flow_item_ipv6_frag_ext nic_mask = {
8494 		.hdr = {
8495 			.next_header = 0xff,
8496 			.frag_data = RTE_BE16(0xffff),
8497 		},
8498 	};
8499 	void *headers_m;
8500 	void *headers_v;
8501 
8502 	if (inner) {
8503 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8504 					 inner_headers);
8505 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8506 	} else {
8507 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8508 					 outer_headers);
8509 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8510 	}
8511 	/* IPv6 fragment extension item exists, so packet is IP fragment. */
8512 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 1);
8513 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1);
8514 	if (!ipv6_frag_ext_v)
8515 		return;
8516 	if (!ipv6_frag_ext_m)
8517 		ipv6_frag_ext_m = &nic_mask;
8518 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8519 		 ipv6_frag_ext_m->hdr.next_header);
8520 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8521 		 ipv6_frag_ext_v->hdr.next_header &
8522 		 ipv6_frag_ext_m->hdr.next_header);
8523 }
8524 
8525 /**
8526  * Add TCP item to matcher and to the value.
8527  *
8528  * @param[in, out] matcher
8529  *   Flow matcher.
8530  * @param[in, out] key
8531  *   Flow matcher value.
8532  * @param[in] item
8533  *   Flow pattern to translate.
8534  * @param[in] inner
8535  *   Item is inner pattern.
8536  */
8537 static void
8538 flow_dv_translate_item_tcp(void *matcher, void *key,
8539 			   const struct rte_flow_item *item,
8540 			   int inner)
8541 {
8542 	const struct rte_flow_item_tcp *tcp_m = item->mask;
8543 	const struct rte_flow_item_tcp *tcp_v = item->spec;
8544 	void *headers_m;
8545 	void *headers_v;
8546 
8547 	if (inner) {
8548 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8549 					 inner_headers);
8550 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8551 	} else {
8552 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8553 					 outer_headers);
8554 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8555 	}
8556 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8557 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP);
8558 	if (!tcp_v)
8559 		return;
8560 	if (!tcp_m)
8561 		tcp_m = &rte_flow_item_tcp_mask;
8562 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport,
8563 		 rte_be_to_cpu_16(tcp_m->hdr.src_port));
8564 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
8565 		 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port));
8566 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport,
8567 		 rte_be_to_cpu_16(tcp_m->hdr.dst_port));
8568 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
8569 		 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port));
8570 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags,
8571 		 tcp_m->hdr.tcp_flags);
8572 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
8573 		 (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags));
8574 }
8575 
8576 /**
8577  * Add UDP item to matcher and to the value.
8578  *
8579  * @param[in, out] matcher
8580  *   Flow matcher.
8581  * @param[in, out] key
8582  *   Flow matcher value.
8583  * @param[in] item
8584  *   Flow pattern to translate.
8585  * @param[in] inner
8586  *   Item is inner pattern.
8587  */
8588 static void
8589 flow_dv_translate_item_udp(void *matcher, void *key,
8590 			   const struct rte_flow_item *item,
8591 			   int inner)
8592 {
8593 	const struct rte_flow_item_udp *udp_m = item->mask;
8594 	const struct rte_flow_item_udp *udp_v = item->spec;
8595 	void *headers_m;
8596 	void *headers_v;
8597 
8598 	if (inner) {
8599 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8600 					 inner_headers);
8601 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8602 	} else {
8603 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8604 					 outer_headers);
8605 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8606 	}
8607 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8608 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
8609 	if (!udp_v)
8610 		return;
8611 	if (!udp_m)
8612 		udp_m = &rte_flow_item_udp_mask;
8613 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport,
8614 		 rte_be_to_cpu_16(udp_m->hdr.src_port));
8615 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
8616 		 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port));
8617 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport,
8618 		 rte_be_to_cpu_16(udp_m->hdr.dst_port));
8619 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
8620 		 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port));
8621 }
8622 
8623 /**
8624  * Add GRE optional Key item to matcher and to the value.
8625  *
8626  * @param[in, out] matcher
8627  *   Flow matcher.
8628  * @param[in, out] key
8629  *   Flow matcher value.
8630  * @param[in] item
8631  *   Flow pattern to translate.
8632  * @param[in] inner
8633  *   Item is inner pattern.
8634  */
8635 static void
8636 flow_dv_translate_item_gre_key(void *matcher, void *key,
8637 				   const struct rte_flow_item *item)
8638 {
8639 	const rte_be32_t *key_m = item->mask;
8640 	const rte_be32_t *key_v = item->spec;
8641 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8642 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8643 	rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX);
8644 
8645 	/* GRE K bit must be on and should already be validated */
8646 	MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1);
8647 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1);
8648 	if (!key_v)
8649 		return;
8650 	if (!key_m)
8651 		key_m = &gre_key_default_mask;
8652 	MLX5_SET(fte_match_set_misc, misc_m, gre_key_h,
8653 		 rte_be_to_cpu_32(*key_m) >> 8);
8654 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_h,
8655 		 rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8);
8656 	MLX5_SET(fte_match_set_misc, misc_m, gre_key_l,
8657 		 rte_be_to_cpu_32(*key_m) & 0xFF);
8658 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_l,
8659 		 rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF);
8660 }
8661 
8662 /**
8663  * Add GRE item to matcher and to the value.
8664  *
8665  * @param[in, out] matcher
8666  *   Flow matcher.
8667  * @param[in, out] key
8668  *   Flow matcher value.
8669  * @param[in] item
8670  *   Flow pattern to translate.
8671  * @param[in] inner
8672  *   Item is inner pattern.
8673  */
8674 static void
8675 flow_dv_translate_item_gre(void *matcher, void *key,
8676 			   const struct rte_flow_item *item,
8677 			   int inner)
8678 {
8679 	const struct rte_flow_item_gre *gre_m = item->mask;
8680 	const struct rte_flow_item_gre *gre_v = item->spec;
8681 	void *headers_m;
8682 	void *headers_v;
8683 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8684 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8685 	struct {
8686 		union {
8687 			__extension__
8688 			struct {
8689 				uint16_t version:3;
8690 				uint16_t rsvd0:9;
8691 				uint16_t s_present:1;
8692 				uint16_t k_present:1;
8693 				uint16_t rsvd_bit1:1;
8694 				uint16_t c_present:1;
8695 			};
8696 			uint16_t value;
8697 		};
8698 	} gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v;
8699 
8700 	if (inner) {
8701 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8702 					 inner_headers);
8703 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8704 	} else {
8705 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8706 					 outer_headers);
8707 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8708 	}
8709 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8710 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
8711 	if (!gre_v)
8712 		return;
8713 	if (!gre_m)
8714 		gre_m = &rte_flow_item_gre_mask;
8715 	MLX5_SET(fte_match_set_misc, misc_m, gre_protocol,
8716 		 rte_be_to_cpu_16(gre_m->protocol));
8717 	MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
8718 		 rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol));
8719 	gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver);
8720 	gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver);
8721 	MLX5_SET(fte_match_set_misc, misc_m, gre_c_present,
8722 		 gre_crks_rsvd0_ver_m.c_present);
8723 	MLX5_SET(fte_match_set_misc, misc_v, gre_c_present,
8724 		 gre_crks_rsvd0_ver_v.c_present &
8725 		 gre_crks_rsvd0_ver_m.c_present);
8726 	MLX5_SET(fte_match_set_misc, misc_m, gre_k_present,
8727 		 gre_crks_rsvd0_ver_m.k_present);
8728 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present,
8729 		 gre_crks_rsvd0_ver_v.k_present &
8730 		 gre_crks_rsvd0_ver_m.k_present);
8731 	MLX5_SET(fte_match_set_misc, misc_m, gre_s_present,
8732 		 gre_crks_rsvd0_ver_m.s_present);
8733 	MLX5_SET(fte_match_set_misc, misc_v, gre_s_present,
8734 		 gre_crks_rsvd0_ver_v.s_present &
8735 		 gre_crks_rsvd0_ver_m.s_present);
8736 }
8737 
8738 /**
8739  * Add NVGRE item to matcher and to the value.
8740  *
8741  * @param[in, out] matcher
8742  *   Flow matcher.
8743  * @param[in, out] key
8744  *   Flow matcher value.
8745  * @param[in] item
8746  *   Flow pattern to translate.
8747  * @param[in] inner
8748  *   Item is inner pattern.
8749  */
8750 static void
8751 flow_dv_translate_item_nvgre(void *matcher, void *key,
8752 			     const struct rte_flow_item *item,
8753 			     int inner)
8754 {
8755 	const struct rte_flow_item_nvgre *nvgre_m = item->mask;
8756 	const struct rte_flow_item_nvgre *nvgre_v = item->spec;
8757 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8758 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8759 	const char *tni_flow_id_m;
8760 	const char *tni_flow_id_v;
8761 	char *gre_key_m;
8762 	char *gre_key_v;
8763 	int size;
8764 	int i;
8765 
8766 	/* For NVGRE, GRE header fields must be set with defined values. */
8767 	const struct rte_flow_item_gre gre_spec = {
8768 		.c_rsvd0_ver = RTE_BE16(0x2000),
8769 		.protocol = RTE_BE16(RTE_ETHER_TYPE_TEB)
8770 	};
8771 	const struct rte_flow_item_gre gre_mask = {
8772 		.c_rsvd0_ver = RTE_BE16(0xB000),
8773 		.protocol = RTE_BE16(UINT16_MAX),
8774 	};
8775 	const struct rte_flow_item gre_item = {
8776 		.spec = &gre_spec,
8777 		.mask = &gre_mask,
8778 		.last = NULL,
8779 	};
8780 	flow_dv_translate_item_gre(matcher, key, &gre_item, inner);
8781 	if (!nvgre_v)
8782 		return;
8783 	if (!nvgre_m)
8784 		nvgre_m = &rte_flow_item_nvgre_mask;
8785 	tni_flow_id_m = (const char *)nvgre_m->tni;
8786 	tni_flow_id_v = (const char *)nvgre_v->tni;
8787 	size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
8788 	gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h);
8789 	gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
8790 	memcpy(gre_key_m, tni_flow_id_m, size);
8791 	for (i = 0; i < size; ++i)
8792 		gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i];
8793 }
8794 
8795 /**
8796  * Add VXLAN item to matcher and to the value.
8797  *
8798  * @param[in] dev
8799  *   Pointer to the Ethernet device structure.
8800  * @param[in] attr
8801  *   Flow rule attributes.
8802  * @param[in, out] matcher
8803  *   Flow matcher.
8804  * @param[in, out] key
8805  *   Flow matcher value.
8806  * @param[in] item
8807  *   Flow pattern to translate.
8808  * @param[in] inner
8809  *   Item is inner pattern.
8810  */
8811 static void
8812 flow_dv_translate_item_vxlan(struct rte_eth_dev *dev,
8813 			     const struct rte_flow_attr *attr,
8814 			     void *matcher, void *key,
8815 			     const struct rte_flow_item *item,
8816 			     int inner)
8817 {
8818 	const struct rte_flow_item_vxlan *vxlan_m = item->mask;
8819 	const struct rte_flow_item_vxlan *vxlan_v = item->spec;
8820 	void *headers_m;
8821 	void *headers_v;
8822 	void *misc5_m;
8823 	void *misc5_v;
8824 	uint32_t *tunnel_header_v;
8825 	uint32_t *tunnel_header_m;
8826 	uint16_t dport;
8827 	struct mlx5_priv *priv = dev->data->dev_private;
8828 	const struct rte_flow_item_vxlan nic_mask = {
8829 		.vni = "\xff\xff\xff",
8830 		.rsvd1 = 0xff,
8831 	};
8832 
8833 	if (inner) {
8834 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8835 					 inner_headers);
8836 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8837 	} else {
8838 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8839 					 outer_headers);
8840 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8841 	}
8842 	dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
8843 		MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
8844 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8845 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8846 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8847 	}
8848 	dport = MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport);
8849 	if (!vxlan_v)
8850 		return;
8851 	if (!vxlan_m) {
8852 		if ((!attr->group && !priv->sh->tunnel_header_0_1) ||
8853 		    (attr->group && !priv->sh->misc5_cap))
8854 			vxlan_m = &rte_flow_item_vxlan_mask;
8855 		else
8856 			vxlan_m = &nic_mask;
8857 	}
8858 	if ((priv->sh->steering_format_version ==
8859 	    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 &&
8860 	    dport != MLX5_UDP_PORT_VXLAN) ||
8861 	    (!attr->group && !attr->transfer && !priv->sh->tunnel_header_0_1) ||
8862 	    ((attr->group || attr->transfer) && !priv->sh->misc5_cap)) {
8863 		void *misc_m;
8864 		void *misc_v;
8865 		char *vni_m;
8866 		char *vni_v;
8867 		int size;
8868 		int i;
8869 		misc_m = MLX5_ADDR_OF(fte_match_param,
8870 				      matcher, misc_parameters);
8871 		misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8872 		size = sizeof(vxlan_m->vni);
8873 		vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni);
8874 		vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni);
8875 		memcpy(vni_m, vxlan_m->vni, size);
8876 		for (i = 0; i < size; ++i)
8877 			vni_v[i] = vni_m[i] & vxlan_v->vni[i];
8878 		return;
8879 	}
8880 	misc5_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_5);
8881 	misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5);
8882 	tunnel_header_v = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5,
8883 						   misc5_v,
8884 						   tunnel_header_1);
8885 	tunnel_header_m = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5,
8886 						   misc5_m,
8887 						   tunnel_header_1);
8888 	*tunnel_header_v = (vxlan_v->vni[0] & vxlan_m->vni[0]) |
8889 			   (vxlan_v->vni[1] & vxlan_m->vni[1]) << 8 |
8890 			   (vxlan_v->vni[2] & vxlan_m->vni[2]) << 16;
8891 	if (*tunnel_header_v)
8892 		*tunnel_header_m = vxlan_m->vni[0] |
8893 			vxlan_m->vni[1] << 8 |
8894 			vxlan_m->vni[2] << 16;
8895 	else
8896 		*tunnel_header_m = 0x0;
8897 	*tunnel_header_v |= (vxlan_v->rsvd1 & vxlan_m->rsvd1) << 24;
8898 	if (vxlan_v->rsvd1 & vxlan_m->rsvd1)
8899 		*tunnel_header_m |= vxlan_m->rsvd1 << 24;
8900 }
8901 
8902 /**
8903  * Add VXLAN-GPE item to matcher and to the value.
8904  *
8905  * @param[in, out] matcher
8906  *   Flow matcher.
8907  * @param[in, out] key
8908  *   Flow matcher value.
8909  * @param[in] item
8910  *   Flow pattern to translate.
8911  * @param[in] inner
8912  *   Item is inner pattern.
8913  */
8914 
8915 static void
8916 flow_dv_translate_item_vxlan_gpe(void *matcher, void *key,
8917 				 const struct rte_flow_item *item, int inner)
8918 {
8919 	const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask;
8920 	const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec;
8921 	void *headers_m;
8922 	void *headers_v;
8923 	void *misc_m =
8924 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_3);
8925 	void *misc_v =
8926 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
8927 	char *vni_m;
8928 	char *vni_v;
8929 	uint16_t dport;
8930 	int size;
8931 	int i;
8932 	uint8_t flags_m = 0xff;
8933 	uint8_t flags_v = 0xc;
8934 
8935 	if (inner) {
8936 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8937 					 inner_headers);
8938 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8939 	} else {
8940 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8941 					 outer_headers);
8942 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8943 	}
8944 	dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
8945 		MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
8946 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8947 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8948 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8949 	}
8950 	if (!vxlan_v)
8951 		return;
8952 	if (!vxlan_m)
8953 		vxlan_m = &rte_flow_item_vxlan_gpe_mask;
8954 	size = sizeof(vxlan_m->vni);
8955 	vni_m = MLX5_ADDR_OF(fte_match_set_misc3, misc_m, outer_vxlan_gpe_vni);
8956 	vni_v = MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni);
8957 	memcpy(vni_m, vxlan_m->vni, size);
8958 	for (i = 0; i < size; ++i)
8959 		vni_v[i] = vni_m[i] & vxlan_v->vni[i];
8960 	if (vxlan_m->flags) {
8961 		flags_m = vxlan_m->flags;
8962 		flags_v = vxlan_v->flags;
8963 	}
8964 	MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_flags, flags_m);
8965 	MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_flags, flags_v);
8966 	MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_next_protocol,
8967 		 vxlan_m->protocol);
8968 	MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_next_protocol,
8969 		 vxlan_v->protocol);
8970 }
8971 
8972 /**
8973  * Add Geneve item to matcher and to the value.
8974  *
8975  * @param[in, out] matcher
8976  *   Flow matcher.
8977  * @param[in, out] key
8978  *   Flow matcher value.
8979  * @param[in] item
8980  *   Flow pattern to translate.
8981  * @param[in] inner
8982  *   Item is inner pattern.
8983  */
8984 
8985 static void
8986 flow_dv_translate_item_geneve(void *matcher, void *key,
8987 			      const struct rte_flow_item *item, int inner)
8988 {
8989 	const struct rte_flow_item_geneve *geneve_m = item->mask;
8990 	const struct rte_flow_item_geneve *geneve_v = item->spec;
8991 	void *headers_m;
8992 	void *headers_v;
8993 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8994 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8995 	uint16_t dport;
8996 	uint16_t gbhdr_m;
8997 	uint16_t gbhdr_v;
8998 	char *vni_m;
8999 	char *vni_v;
9000 	size_t size, i;
9001 
9002 	if (inner) {
9003 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9004 					 inner_headers);
9005 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9006 	} else {
9007 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9008 					 outer_headers);
9009 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9010 	}
9011 	dport = MLX5_UDP_PORT_GENEVE;
9012 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9013 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
9014 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
9015 	}
9016 	if (!geneve_v)
9017 		return;
9018 	if (!geneve_m)
9019 		geneve_m = &rte_flow_item_geneve_mask;
9020 	size = sizeof(geneve_m->vni);
9021 	vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, geneve_vni);
9022 	vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni);
9023 	memcpy(vni_m, geneve_m->vni, size);
9024 	for (i = 0; i < size; ++i)
9025 		vni_v[i] = vni_m[i] & geneve_v->vni[i];
9026 	MLX5_SET(fte_match_set_misc, misc_m, geneve_protocol_type,
9027 		 rte_be_to_cpu_16(geneve_m->protocol));
9028 	MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type,
9029 		 rte_be_to_cpu_16(geneve_v->protocol & geneve_m->protocol));
9030 	gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0);
9031 	gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0);
9032 	MLX5_SET(fte_match_set_misc, misc_m, geneve_oam,
9033 		 MLX5_GENEVE_OAMF_VAL(gbhdr_m));
9034 	MLX5_SET(fte_match_set_misc, misc_v, geneve_oam,
9035 		 MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m));
9036 	MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
9037 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
9038 	MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9039 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) &
9040 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
9041 }
9042 
9043 /**
9044  * Create Geneve TLV option resource.
9045  *
9046  * @param dev[in, out]
9047  *   Pointer to rte_eth_dev structure.
9048  * @param[in, out] tag_be24
9049  *   Tag value in big endian then R-shift 8.
9050  * @parm[in, out] dev_flow
9051  *   Pointer to the dev_flow.
9052  * @param[out] error
9053  *   pointer to error structure.
9054  *
9055  * @return
9056  *   0 on success otherwise -errno and errno is set.
9057  */
9058 
9059 int
9060 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev,
9061 					     const struct rte_flow_item *item,
9062 					     struct rte_flow_error *error)
9063 {
9064 	struct mlx5_priv *priv = dev->data->dev_private;
9065 	struct mlx5_dev_ctx_shared *sh = priv->sh;
9066 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
9067 			sh->geneve_tlv_option_resource;
9068 	struct mlx5_devx_obj *obj;
9069 	const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
9070 	int ret = 0;
9071 
9072 	if (!geneve_opt_v)
9073 		return -1;
9074 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
9075 	if (geneve_opt_resource != NULL) {
9076 		if (geneve_opt_resource->option_class ==
9077 			geneve_opt_v->option_class &&
9078 			geneve_opt_resource->option_type ==
9079 			geneve_opt_v->option_type &&
9080 			geneve_opt_resource->length ==
9081 			geneve_opt_v->option_len) {
9082 			/* We already have GENVE TLV option obj allocated. */
9083 			__atomic_fetch_add(&geneve_opt_resource->refcnt, 1,
9084 					   __ATOMIC_RELAXED);
9085 		} else {
9086 			ret = rte_flow_error_set(error, ENOMEM,
9087 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9088 				"Only one GENEVE TLV option supported");
9089 			goto exit;
9090 		}
9091 	} else {
9092 		/* Create a GENEVE TLV object and resource. */
9093 		obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->ctx,
9094 				geneve_opt_v->option_class,
9095 				geneve_opt_v->option_type,
9096 				geneve_opt_v->option_len);
9097 		if (!obj) {
9098 			ret = rte_flow_error_set(error, ENODATA,
9099 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9100 				"Failed to create GENEVE TLV Devx object");
9101 			goto exit;
9102 		}
9103 		sh->geneve_tlv_option_resource =
9104 				mlx5_malloc(MLX5_MEM_ZERO,
9105 						sizeof(*geneve_opt_resource),
9106 						0, SOCKET_ID_ANY);
9107 		if (!sh->geneve_tlv_option_resource) {
9108 			claim_zero(mlx5_devx_cmd_destroy(obj));
9109 			ret = rte_flow_error_set(error, ENOMEM,
9110 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9111 				"GENEVE TLV object memory allocation failed");
9112 			goto exit;
9113 		}
9114 		geneve_opt_resource = sh->geneve_tlv_option_resource;
9115 		geneve_opt_resource->obj = obj;
9116 		geneve_opt_resource->option_class = geneve_opt_v->option_class;
9117 		geneve_opt_resource->option_type = geneve_opt_v->option_type;
9118 		geneve_opt_resource->length = geneve_opt_v->option_len;
9119 		__atomic_store_n(&geneve_opt_resource->refcnt, 1,
9120 				__ATOMIC_RELAXED);
9121 	}
9122 exit:
9123 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
9124 	return ret;
9125 }
9126 
9127 /**
9128  * Add Geneve TLV option item to matcher.
9129  *
9130  * @param[in, out] dev
9131  *   Pointer to rte_eth_dev structure.
9132  * @param[in, out] matcher
9133  *   Flow matcher.
9134  * @param[in, out] key
9135  *   Flow matcher value.
9136  * @param[in] item
9137  *   Flow pattern to translate.
9138  * @param[out] error
9139  *   Pointer to error structure.
9140  */
9141 static int
9142 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *matcher,
9143 				  void *key, const struct rte_flow_item *item,
9144 				  struct rte_flow_error *error)
9145 {
9146 	const struct rte_flow_item_geneve_opt *geneve_opt_m = item->mask;
9147 	const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
9148 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9149 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9150 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9151 			misc_parameters_3);
9152 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9153 	rte_be32_t opt_data_key = 0, opt_data_mask = 0;
9154 	int ret = 0;
9155 
9156 	if (!geneve_opt_v)
9157 		return -1;
9158 	if (!geneve_opt_m)
9159 		geneve_opt_m = &rte_flow_item_geneve_opt_mask;
9160 	ret = flow_dev_geneve_tlv_option_resource_register(dev, item,
9161 							   error);
9162 	if (ret) {
9163 		DRV_LOG(ERR, "Failed to create geneve_tlv_obj");
9164 		return ret;
9165 	}
9166 	/*
9167 	 * Set the option length in GENEVE header if not requested.
9168 	 * The GENEVE TLV option length is expressed by the option length field
9169 	 * in the GENEVE header.
9170 	 * If the option length was not requested but the GENEVE TLV option item
9171 	 * is present we set the option length field implicitly.
9172 	 */
9173 	if (!MLX5_GET16(fte_match_set_misc, misc_m, geneve_opt_len)) {
9174 		MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
9175 			 MLX5_GENEVE_OPTLEN_MASK);
9176 		MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9177 			 geneve_opt_v->option_len + 1);
9178 	}
9179 	MLX5_SET(fte_match_set_misc, misc_m, geneve_tlv_option_0_exist, 1);
9180 	MLX5_SET(fte_match_set_misc, misc_v, geneve_tlv_option_0_exist, 1);
9181 	/* Set the data. */
9182 	if (geneve_opt_v->data) {
9183 		memcpy(&opt_data_key, geneve_opt_v->data,
9184 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9185 				sizeof(opt_data_key)));
9186 		MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
9187 				sizeof(opt_data_key));
9188 		memcpy(&opt_data_mask, geneve_opt_m->data,
9189 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9190 				sizeof(opt_data_mask)));
9191 		MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
9192 				sizeof(opt_data_mask));
9193 		MLX5_SET(fte_match_set_misc3, misc3_m,
9194 				geneve_tlv_option_0_data,
9195 				rte_be_to_cpu_32(opt_data_mask));
9196 		MLX5_SET(fte_match_set_misc3, misc3_v,
9197 				geneve_tlv_option_0_data,
9198 			rte_be_to_cpu_32(opt_data_key & opt_data_mask));
9199 	}
9200 	return ret;
9201 }
9202 
9203 /**
9204  * Add MPLS item to matcher and to the value.
9205  *
9206  * @param[in, out] matcher
9207  *   Flow matcher.
9208  * @param[in, out] key
9209  *   Flow matcher value.
9210  * @param[in] item
9211  *   Flow pattern to translate.
9212  * @param[in] prev_layer
9213  *   The protocol layer indicated in previous item.
9214  * @param[in] inner
9215  *   Item is inner pattern.
9216  */
9217 static void
9218 flow_dv_translate_item_mpls(void *matcher, void *key,
9219 			    const struct rte_flow_item *item,
9220 			    uint64_t prev_layer,
9221 			    int inner)
9222 {
9223 	const uint32_t *in_mpls_m = item->mask;
9224 	const uint32_t *in_mpls_v = item->spec;
9225 	uint32_t *out_mpls_m = 0;
9226 	uint32_t *out_mpls_v = 0;
9227 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9228 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9229 	void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher,
9230 				     misc_parameters_2);
9231 	void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9232 	void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
9233 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9234 
9235 	switch (prev_layer) {
9236 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9237 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff);
9238 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9239 			 MLX5_UDP_PORT_MPLS);
9240 		break;
9241 	case MLX5_FLOW_LAYER_GRE:
9242 		/* Fall-through. */
9243 	case MLX5_FLOW_LAYER_GRE_KEY:
9244 		MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff);
9245 		MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
9246 			 RTE_ETHER_TYPE_MPLS);
9247 		break;
9248 	default:
9249 		break;
9250 	}
9251 	if (!in_mpls_v)
9252 		return;
9253 	if (!in_mpls_m)
9254 		in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask;
9255 	switch (prev_layer) {
9256 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9257 		out_mpls_m =
9258 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
9259 						 outer_first_mpls_over_udp);
9260 		out_mpls_v =
9261 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9262 						 outer_first_mpls_over_udp);
9263 		break;
9264 	case MLX5_FLOW_LAYER_GRE:
9265 		out_mpls_m =
9266 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
9267 						 outer_first_mpls_over_gre);
9268 		out_mpls_v =
9269 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9270 						 outer_first_mpls_over_gre);
9271 		break;
9272 	default:
9273 		/* Inner MPLS not over GRE is not supported. */
9274 		if (!inner) {
9275 			out_mpls_m =
9276 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
9277 							 misc2_m,
9278 							 outer_first_mpls);
9279 			out_mpls_v =
9280 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
9281 							 misc2_v,
9282 							 outer_first_mpls);
9283 		}
9284 		break;
9285 	}
9286 	if (out_mpls_m && out_mpls_v) {
9287 		*out_mpls_m = *in_mpls_m;
9288 		*out_mpls_v = *in_mpls_v & *in_mpls_m;
9289 	}
9290 }
9291 
9292 /**
9293  * Add metadata register item to matcher
9294  *
9295  * @param[in, out] matcher
9296  *   Flow matcher.
9297  * @param[in, out] key
9298  *   Flow matcher value.
9299  * @param[in] reg_type
9300  *   Type of device metadata register
9301  * @param[in] value
9302  *   Register value
9303  * @param[in] mask
9304  *   Register mask
9305  */
9306 static void
9307 flow_dv_match_meta_reg(void *matcher, void *key,
9308 		       enum modify_reg reg_type,
9309 		       uint32_t data, uint32_t mask)
9310 {
9311 	void *misc2_m =
9312 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2);
9313 	void *misc2_v =
9314 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9315 	uint32_t temp;
9316 
9317 	data &= mask;
9318 	switch (reg_type) {
9319 	case REG_A:
9320 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a, mask);
9321 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data);
9322 		break;
9323 	case REG_B:
9324 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_b, mask);
9325 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data);
9326 		break;
9327 	case REG_C_0:
9328 		/*
9329 		 * The metadata register C0 field might be divided into
9330 		 * source vport index and META item value, we should set
9331 		 * this field according to specified mask, not as whole one.
9332 		 */
9333 		temp = MLX5_GET(fte_match_set_misc2, misc2_m, metadata_reg_c_0);
9334 		temp |= mask;
9335 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_0, temp);
9336 		temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0);
9337 		temp &= ~mask;
9338 		temp |= data;
9339 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp);
9340 		break;
9341 	case REG_C_1:
9342 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_1, mask);
9343 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data);
9344 		break;
9345 	case REG_C_2:
9346 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_2, mask);
9347 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data);
9348 		break;
9349 	case REG_C_3:
9350 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_3, mask);
9351 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data);
9352 		break;
9353 	case REG_C_4:
9354 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_4, mask);
9355 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data);
9356 		break;
9357 	case REG_C_5:
9358 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_5, mask);
9359 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data);
9360 		break;
9361 	case REG_C_6:
9362 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_6, mask);
9363 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data);
9364 		break;
9365 	case REG_C_7:
9366 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_7, mask);
9367 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data);
9368 		break;
9369 	default:
9370 		MLX5_ASSERT(false);
9371 		break;
9372 	}
9373 }
9374 
9375 /**
9376  * Add MARK item to matcher
9377  *
9378  * @param[in] dev
9379  *   The device to configure through.
9380  * @param[in, out] matcher
9381  *   Flow matcher.
9382  * @param[in, out] key
9383  *   Flow matcher value.
9384  * @param[in] item
9385  *   Flow pattern to translate.
9386  */
9387 static void
9388 flow_dv_translate_item_mark(struct rte_eth_dev *dev,
9389 			    void *matcher, void *key,
9390 			    const struct rte_flow_item *item)
9391 {
9392 	struct mlx5_priv *priv = dev->data->dev_private;
9393 	const struct rte_flow_item_mark *mark;
9394 	uint32_t value;
9395 	uint32_t mask;
9396 
9397 	mark = item->mask ? (const void *)item->mask :
9398 			    &rte_flow_item_mark_mask;
9399 	mask = mark->id & priv->sh->dv_mark_mask;
9400 	mark = (const void *)item->spec;
9401 	MLX5_ASSERT(mark);
9402 	value = mark->id & priv->sh->dv_mark_mask & mask;
9403 	if (mask) {
9404 		enum modify_reg reg;
9405 
9406 		/* Get the metadata register index for the mark. */
9407 		reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL);
9408 		MLX5_ASSERT(reg > 0);
9409 		if (reg == REG_C_0) {
9410 			struct mlx5_priv *priv = dev->data->dev_private;
9411 			uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9412 			uint32_t shl_c0 = rte_bsf32(msk_c0);
9413 
9414 			mask &= msk_c0;
9415 			mask <<= shl_c0;
9416 			value <<= shl_c0;
9417 		}
9418 		flow_dv_match_meta_reg(matcher, key, reg, value, mask);
9419 	}
9420 }
9421 
9422 /**
9423  * Add META item to matcher
9424  *
9425  * @param[in] dev
9426  *   The devich to configure through.
9427  * @param[in, out] matcher
9428  *   Flow matcher.
9429  * @param[in, out] key
9430  *   Flow matcher value.
9431  * @param[in] attr
9432  *   Attributes of flow that includes this item.
9433  * @param[in] item
9434  *   Flow pattern to translate.
9435  */
9436 static void
9437 flow_dv_translate_item_meta(struct rte_eth_dev *dev,
9438 			    void *matcher, void *key,
9439 			    const struct rte_flow_attr *attr,
9440 			    const struct rte_flow_item *item)
9441 {
9442 	const struct rte_flow_item_meta *meta_m;
9443 	const struct rte_flow_item_meta *meta_v;
9444 
9445 	meta_m = (const void *)item->mask;
9446 	if (!meta_m)
9447 		meta_m = &rte_flow_item_meta_mask;
9448 	meta_v = (const void *)item->spec;
9449 	if (meta_v) {
9450 		int reg;
9451 		uint32_t value = meta_v->data;
9452 		uint32_t mask = meta_m->data;
9453 
9454 		reg = flow_dv_get_metadata_reg(dev, attr, NULL);
9455 		if (reg < 0)
9456 			return;
9457 		MLX5_ASSERT(reg != REG_NON);
9458 		if (reg == REG_C_0) {
9459 			struct mlx5_priv *priv = dev->data->dev_private;
9460 			uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9461 			uint32_t shl_c0 = rte_bsf32(msk_c0);
9462 
9463 			mask &= msk_c0;
9464 			mask <<= shl_c0;
9465 			value <<= shl_c0;
9466 		}
9467 		flow_dv_match_meta_reg(matcher, key, reg, value, mask);
9468 	}
9469 }
9470 
9471 /**
9472  * Add vport metadata Reg C0 item to matcher
9473  *
9474  * @param[in, out] matcher
9475  *   Flow matcher.
9476  * @param[in, out] key
9477  *   Flow matcher value.
9478  * @param[in] reg
9479  *   Flow pattern to translate.
9480  */
9481 static void
9482 flow_dv_translate_item_meta_vport(void *matcher, void *key,
9483 				  uint32_t value, uint32_t mask)
9484 {
9485 	flow_dv_match_meta_reg(matcher, key, REG_C_0, value, mask);
9486 }
9487 
9488 /**
9489  * Add tag item to matcher
9490  *
9491  * @param[in] dev
9492  *   The devich to configure through.
9493  * @param[in, out] matcher
9494  *   Flow matcher.
9495  * @param[in, out] key
9496  *   Flow matcher value.
9497  * @param[in] item
9498  *   Flow pattern to translate.
9499  */
9500 static void
9501 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev,
9502 				void *matcher, void *key,
9503 				const struct rte_flow_item *item)
9504 {
9505 	const struct mlx5_rte_flow_item_tag *tag_v = item->spec;
9506 	const struct mlx5_rte_flow_item_tag *tag_m = item->mask;
9507 	uint32_t mask, value;
9508 
9509 	MLX5_ASSERT(tag_v);
9510 	value = tag_v->data;
9511 	mask = tag_m ? tag_m->data : UINT32_MAX;
9512 	if (tag_v->id == REG_C_0) {
9513 		struct mlx5_priv *priv = dev->data->dev_private;
9514 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9515 		uint32_t shl_c0 = rte_bsf32(msk_c0);
9516 
9517 		mask &= msk_c0;
9518 		mask <<= shl_c0;
9519 		value <<= shl_c0;
9520 	}
9521 	flow_dv_match_meta_reg(matcher, key, tag_v->id, value, mask);
9522 }
9523 
9524 /**
9525  * Add TAG item to matcher
9526  *
9527  * @param[in] dev
9528  *   The devich to configure through.
9529  * @param[in, out] matcher
9530  *   Flow matcher.
9531  * @param[in, out] key
9532  *   Flow matcher value.
9533  * @param[in] item
9534  *   Flow pattern to translate.
9535  */
9536 static void
9537 flow_dv_translate_item_tag(struct rte_eth_dev *dev,
9538 			   void *matcher, void *key,
9539 			   const struct rte_flow_item *item)
9540 {
9541 	const struct rte_flow_item_tag *tag_v = item->spec;
9542 	const struct rte_flow_item_tag *tag_m = item->mask;
9543 	enum modify_reg reg;
9544 
9545 	MLX5_ASSERT(tag_v);
9546 	tag_m = tag_m ? tag_m : &rte_flow_item_tag_mask;
9547 	/* Get the metadata register index for the tag. */
9548 	reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, tag_v->index, NULL);
9549 	MLX5_ASSERT(reg > 0);
9550 	flow_dv_match_meta_reg(matcher, key, reg, tag_v->data, tag_m->data);
9551 }
9552 
9553 /**
9554  * Add source vport match to the specified matcher.
9555  *
9556  * @param[in, out] matcher
9557  *   Flow matcher.
9558  * @param[in, out] key
9559  *   Flow matcher value.
9560  * @param[in] port
9561  *   Source vport value to match
9562  * @param[in] mask
9563  *   Mask
9564  */
9565 static void
9566 flow_dv_translate_item_source_vport(void *matcher, void *key,
9567 				    int16_t port, uint16_t mask)
9568 {
9569 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9570 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9571 
9572 	MLX5_SET(fte_match_set_misc, misc_m, source_port, mask);
9573 	MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
9574 }
9575 
9576 /**
9577  * Translate port-id item to eswitch match on  port-id.
9578  *
9579  * @param[in] dev
9580  *   The devich to configure through.
9581  * @param[in, out] matcher
9582  *   Flow matcher.
9583  * @param[in, out] key
9584  *   Flow matcher value.
9585  * @param[in] item
9586  *   Flow pattern to translate.
9587  * @param[in]
9588  *   Flow attributes.
9589  *
9590  * @return
9591  *   0 on success, a negative errno value otherwise.
9592  */
9593 static int
9594 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher,
9595 			       void *key, const struct rte_flow_item *item,
9596 			       const struct rte_flow_attr *attr)
9597 {
9598 	const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL;
9599 	const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL;
9600 	struct mlx5_priv *priv;
9601 	uint16_t mask, id;
9602 
9603 	mask = pid_m ? pid_m->id : 0xffff;
9604 	id = pid_v ? pid_v->id : dev->data->port_id;
9605 	priv = mlx5_port_to_eswitch_info(id, item == NULL);
9606 	if (!priv)
9607 		return -rte_errno;
9608 	/*
9609 	 * Translate to vport field or to metadata, depending on mode.
9610 	 * Kernel can use either misc.source_port or half of C0 metadata
9611 	 * register.
9612 	 */
9613 	if (priv->vport_meta_mask) {
9614 		/*
9615 		 * Provide the hint for SW steering library
9616 		 * to insert the flow into ingress domain and
9617 		 * save the extra vport match.
9618 		 */
9619 		if (mask == 0xffff && priv->vport_id == 0xffff &&
9620 		    priv->pf_bond < 0 && attr->transfer)
9621 			flow_dv_translate_item_source_vport
9622 				(matcher, key, priv->vport_id, mask);
9623 		/*
9624 		 * We should always set the vport metadata register,
9625 		 * otherwise the SW steering library can drop
9626 		 * the rule if wire vport metadata value is not zero,
9627 		 * it depends on kernel configuration.
9628 		 */
9629 		flow_dv_translate_item_meta_vport(matcher, key,
9630 						  priv->vport_meta_tag,
9631 						  priv->vport_meta_mask);
9632 	} else {
9633 		flow_dv_translate_item_source_vport(matcher, key,
9634 						    priv->vport_id, mask);
9635 	}
9636 	return 0;
9637 }
9638 
9639 /**
9640  * Add ICMP6 item to matcher and to the value.
9641  *
9642  * @param[in, out] matcher
9643  *   Flow matcher.
9644  * @param[in, out] key
9645  *   Flow matcher value.
9646  * @param[in] item
9647  *   Flow pattern to translate.
9648  * @param[in] inner
9649  *   Item is inner pattern.
9650  */
9651 static void
9652 flow_dv_translate_item_icmp6(void *matcher, void *key,
9653 			      const struct rte_flow_item *item,
9654 			      int inner)
9655 {
9656 	const struct rte_flow_item_icmp6 *icmp6_m = item->mask;
9657 	const struct rte_flow_item_icmp6 *icmp6_v = item->spec;
9658 	void *headers_m;
9659 	void *headers_v;
9660 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9661 				     misc_parameters_3);
9662 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9663 	if (inner) {
9664 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9665 					 inner_headers);
9666 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9667 	} else {
9668 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9669 					 outer_headers);
9670 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9671 	}
9672 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
9673 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6);
9674 	if (!icmp6_v)
9675 		return;
9676 	if (!icmp6_m)
9677 		icmp6_m = &rte_flow_item_icmp6_mask;
9678 	MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type);
9679 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type,
9680 		 icmp6_v->type & icmp6_m->type);
9681 	MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code);
9682 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code,
9683 		 icmp6_v->code & icmp6_m->code);
9684 }
9685 
9686 /**
9687  * Add ICMP item to matcher and to the value.
9688  *
9689  * @param[in, out] matcher
9690  *   Flow matcher.
9691  * @param[in, out] key
9692  *   Flow matcher value.
9693  * @param[in] item
9694  *   Flow pattern to translate.
9695  * @param[in] inner
9696  *   Item is inner pattern.
9697  */
9698 static void
9699 flow_dv_translate_item_icmp(void *matcher, void *key,
9700 			    const struct rte_flow_item *item,
9701 			    int inner)
9702 {
9703 	const struct rte_flow_item_icmp *icmp_m = item->mask;
9704 	const struct rte_flow_item_icmp *icmp_v = item->spec;
9705 	uint32_t icmp_header_data_m = 0;
9706 	uint32_t icmp_header_data_v = 0;
9707 	void *headers_m;
9708 	void *headers_v;
9709 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9710 				     misc_parameters_3);
9711 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9712 	if (inner) {
9713 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9714 					 inner_headers);
9715 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9716 	} else {
9717 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9718 					 outer_headers);
9719 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9720 	}
9721 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
9722 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP);
9723 	if (!icmp_v)
9724 		return;
9725 	if (!icmp_m)
9726 		icmp_m = &rte_flow_item_icmp_mask;
9727 	MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type,
9728 		 icmp_m->hdr.icmp_type);
9729 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type,
9730 		 icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type);
9731 	MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code,
9732 		 icmp_m->hdr.icmp_code);
9733 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code,
9734 		 icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code);
9735 	icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb);
9736 	icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16;
9737 	if (icmp_header_data_m) {
9738 		icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb);
9739 		icmp_header_data_v |=
9740 			 rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16;
9741 		MLX5_SET(fte_match_set_misc3, misc3_m, icmp_header_data,
9742 			 icmp_header_data_m);
9743 		MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data,
9744 			 icmp_header_data_v & icmp_header_data_m);
9745 	}
9746 }
9747 
9748 /**
9749  * Add GTP item to matcher and to the value.
9750  *
9751  * @param[in, out] matcher
9752  *   Flow matcher.
9753  * @param[in, out] key
9754  *   Flow matcher value.
9755  * @param[in] item
9756  *   Flow pattern to translate.
9757  * @param[in] inner
9758  *   Item is inner pattern.
9759  */
9760 static void
9761 flow_dv_translate_item_gtp(void *matcher, void *key,
9762 			   const struct rte_flow_item *item, int inner)
9763 {
9764 	const struct rte_flow_item_gtp *gtp_m = item->mask;
9765 	const struct rte_flow_item_gtp *gtp_v = item->spec;
9766 	void *headers_m;
9767 	void *headers_v;
9768 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9769 				     misc_parameters_3);
9770 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9771 	uint16_t dport = RTE_GTPU_UDP_PORT;
9772 
9773 	if (inner) {
9774 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9775 					 inner_headers);
9776 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9777 	} else {
9778 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9779 					 outer_headers);
9780 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9781 	}
9782 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9783 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
9784 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
9785 	}
9786 	if (!gtp_v)
9787 		return;
9788 	if (!gtp_m)
9789 		gtp_m = &rte_flow_item_gtp_mask;
9790 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags,
9791 		 gtp_m->v_pt_rsv_flags);
9792 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags,
9793 		 gtp_v->v_pt_rsv_flags & gtp_m->v_pt_rsv_flags);
9794 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_type, gtp_m->msg_type);
9795 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type,
9796 		 gtp_v->msg_type & gtp_m->msg_type);
9797 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_teid,
9798 		 rte_be_to_cpu_32(gtp_m->teid));
9799 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid,
9800 		 rte_be_to_cpu_32(gtp_v->teid & gtp_m->teid));
9801 }
9802 
9803 /**
9804  * Add GTP PSC item to matcher.
9805  *
9806  * @param[in, out] matcher
9807  *   Flow matcher.
9808  * @param[in, out] key
9809  *   Flow matcher value.
9810  * @param[in] item
9811  *   Flow pattern to translate.
9812  */
9813 static int
9814 flow_dv_translate_item_gtp_psc(void *matcher, void *key,
9815 			       const struct rte_flow_item *item)
9816 {
9817 	const struct rte_flow_item_gtp_psc *gtp_psc_m = item->mask;
9818 	const struct rte_flow_item_gtp_psc *gtp_psc_v = item->spec;
9819 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9820 			misc_parameters_3);
9821 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9822 	union {
9823 		uint32_t w32;
9824 		struct {
9825 			uint16_t seq_num;
9826 			uint8_t npdu_num;
9827 			uint8_t next_ext_header_type;
9828 		};
9829 	} dw_2;
9830 	uint8_t gtp_flags;
9831 
9832 	/* Always set E-flag match on one, regardless of GTP item settings. */
9833 	gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_m, gtpu_msg_flags);
9834 	gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
9835 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, gtp_flags);
9836 	gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags);
9837 	gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
9838 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags);
9839 	/*Set next extension header type. */
9840 	dw_2.seq_num = 0;
9841 	dw_2.npdu_num = 0;
9842 	dw_2.next_ext_header_type = 0xff;
9843 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_dw_2,
9844 		 rte_cpu_to_be_32(dw_2.w32));
9845 	dw_2.seq_num = 0;
9846 	dw_2.npdu_num = 0;
9847 	dw_2.next_ext_header_type = 0x85;
9848 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2,
9849 		 rte_cpu_to_be_32(dw_2.w32));
9850 	if (gtp_psc_v) {
9851 		union {
9852 			uint32_t w32;
9853 			struct {
9854 				uint8_t len;
9855 				uint8_t type_flags;
9856 				uint8_t qfi;
9857 				uint8_t reserved;
9858 			};
9859 		} dw_0;
9860 
9861 		/*Set extension header PDU type and Qos. */
9862 		if (!gtp_psc_m)
9863 			gtp_psc_m = &rte_flow_item_gtp_psc_mask;
9864 		dw_0.w32 = 0;
9865 		dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->hdr.type);
9866 		dw_0.qfi = gtp_psc_m->hdr.qfi;
9867 		MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_first_ext_dw_0,
9868 			 rte_cpu_to_be_32(dw_0.w32));
9869 		dw_0.w32 = 0;
9870 		dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->hdr.type &
9871 							gtp_psc_m->hdr.type);
9872 		dw_0.qfi = gtp_psc_v->hdr.qfi & gtp_psc_m->hdr.qfi;
9873 		MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0,
9874 			 rte_cpu_to_be_32(dw_0.w32));
9875 	}
9876 	return 0;
9877 }
9878 
9879 /**
9880  * Add eCPRI item to matcher and to the value.
9881  *
9882  * @param[in] dev
9883  *   The devich to configure through.
9884  * @param[in, out] matcher
9885  *   Flow matcher.
9886  * @param[in, out] key
9887  *   Flow matcher value.
9888  * @param[in] item
9889  *   Flow pattern to translate.
9890  * @param[in] last_item
9891  *   Last item flags.
9892  */
9893 static void
9894 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher,
9895 			     void *key, const struct rte_flow_item *item,
9896 			     uint64_t last_item)
9897 {
9898 	struct mlx5_priv *priv = dev->data->dev_private;
9899 	const struct rte_flow_item_ecpri *ecpri_m = item->mask;
9900 	const struct rte_flow_item_ecpri *ecpri_v = item->spec;
9901 	struct rte_ecpri_common_hdr common;
9902 	void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher,
9903 				     misc_parameters_4);
9904 	void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4);
9905 	uint32_t *samples;
9906 	void *dw_m;
9907 	void *dw_v;
9908 
9909 	/*
9910 	 * In case of eCPRI over Ethernet, if EtherType is not specified,
9911 	 * match on eCPRI EtherType implicitly.
9912 	 */
9913 	if (last_item & MLX5_FLOW_LAYER_OUTER_L2) {
9914 		void *hdrs_m, *hdrs_v, *l2m, *l2v;
9915 
9916 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
9917 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9918 		l2m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, ethertype);
9919 		l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
9920 		if (*(uint16_t *)l2m == 0 && *(uint16_t *)l2v == 0) {
9921 			*(uint16_t *)l2m = UINT16_MAX;
9922 			*(uint16_t *)l2v = RTE_BE16(RTE_ETHER_TYPE_ECPRI);
9923 		}
9924 	}
9925 	if (!ecpri_v)
9926 		return;
9927 	if (!ecpri_m)
9928 		ecpri_m = &rte_flow_item_ecpri_mask;
9929 	/*
9930 	 * Maximal four DW samples are supported in a single matching now.
9931 	 * Two are used now for a eCPRI matching:
9932 	 * 1. Type: one byte, mask should be 0x00ff0000 in network order
9933 	 * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000
9934 	 *    if any.
9935 	 */
9936 	if (!ecpri_m->hdr.common.u32)
9937 		return;
9938 	samples = priv->sh->fp[MLX5_FLEX_PARSER_ECPRI_0].ids;
9939 	/* Need to take the whole DW as the mask to fill the entry. */
9940 	dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
9941 			    prog_sample_field_value_0);
9942 	dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
9943 			    prog_sample_field_value_0);
9944 	/* Already big endian (network order) in the header. */
9945 	*(uint32_t *)dw_m = ecpri_m->hdr.common.u32;
9946 	*(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32;
9947 	/* Sample#0, used for matching type, offset 0. */
9948 	MLX5_SET(fte_match_set_misc4, misc4_m,
9949 		 prog_sample_field_id_0, samples[0]);
9950 	/* It makes no sense to set the sample ID in the mask field. */
9951 	MLX5_SET(fte_match_set_misc4, misc4_v,
9952 		 prog_sample_field_id_0, samples[0]);
9953 	/*
9954 	 * Checking if message body part needs to be matched.
9955 	 * Some wildcard rules only matching type field should be supported.
9956 	 */
9957 	if (ecpri_m->hdr.dummy[0]) {
9958 		common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32);
9959 		switch (common.type) {
9960 		case RTE_ECPRI_MSG_TYPE_IQ_DATA:
9961 		case RTE_ECPRI_MSG_TYPE_RTC_CTRL:
9962 		case RTE_ECPRI_MSG_TYPE_DLY_MSR:
9963 			dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
9964 					    prog_sample_field_value_1);
9965 			dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
9966 					    prog_sample_field_value_1);
9967 			*(uint32_t *)dw_m = ecpri_m->hdr.dummy[0];
9968 			*(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] &
9969 					    ecpri_m->hdr.dummy[0];
9970 			/* Sample#1, to match message body, offset 4. */
9971 			MLX5_SET(fte_match_set_misc4, misc4_m,
9972 				 prog_sample_field_id_1, samples[1]);
9973 			MLX5_SET(fte_match_set_misc4, misc4_v,
9974 				 prog_sample_field_id_1, samples[1]);
9975 			break;
9976 		default:
9977 			/* Others, do not match any sample ID. */
9978 			break;
9979 		}
9980 	}
9981 }
9982 
9983 /*
9984  * Add connection tracking status item to matcher
9985  *
9986  * @param[in] dev
9987  *   The devich to configure through.
9988  * @param[in, out] matcher
9989  *   Flow matcher.
9990  * @param[in, out] key
9991  *   Flow matcher value.
9992  * @param[in] item
9993  *   Flow pattern to translate.
9994  */
9995 static void
9996 flow_dv_translate_item_aso_ct(struct rte_eth_dev *dev,
9997 			      void *matcher, void *key,
9998 			      const struct rte_flow_item *item)
9999 {
10000 	uint32_t reg_value = 0;
10001 	int reg_id;
10002 	/* 8LSB 0b 11/0000/11, middle 4 bits are reserved. */
10003 	uint32_t reg_mask = 0;
10004 	const struct rte_flow_item_conntrack *spec = item->spec;
10005 	const struct rte_flow_item_conntrack *mask = item->mask;
10006 	uint32_t flags;
10007 	struct rte_flow_error error;
10008 
10009 	if (!mask)
10010 		mask = &rte_flow_item_conntrack_mask;
10011 	if (!spec || !mask->flags)
10012 		return;
10013 	flags = spec->flags & mask->flags;
10014 	/* The conflict should be checked in the validation. */
10015 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID)
10016 		reg_value |= MLX5_CT_SYNDROME_VALID;
10017 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
10018 		reg_value |= MLX5_CT_SYNDROME_STATE_CHANGE;
10019 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID)
10020 		reg_value |= MLX5_CT_SYNDROME_INVALID;
10021 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)
10022 		reg_value |= MLX5_CT_SYNDROME_TRAP;
10023 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
10024 		reg_value |= MLX5_CT_SYNDROME_BAD_PACKET;
10025 	if (mask->flags & (RTE_FLOW_CONNTRACK_PKT_STATE_VALID |
10026 			   RTE_FLOW_CONNTRACK_PKT_STATE_INVALID |
10027 			   RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED))
10028 		reg_mask |= 0xc0;
10029 	if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
10030 		reg_mask |= MLX5_CT_SYNDROME_STATE_CHANGE;
10031 	if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
10032 		reg_mask |= MLX5_CT_SYNDROME_BAD_PACKET;
10033 	/* The REG_C_x value could be saved during startup. */
10034 	reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, &error);
10035 	if (reg_id == REG_NON)
10036 		return;
10037 	flow_dv_match_meta_reg(matcher, key, (enum modify_reg)reg_id,
10038 			       reg_value, reg_mask);
10039 }
10040 
10041 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
10042 
10043 #define HEADER_IS_ZERO(match_criteria, headers)				     \
10044 	!(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
10045 		 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
10046 
10047 /**
10048  * Calculate flow matcher enable bitmap.
10049  *
10050  * @param match_criteria
10051  *   Pointer to flow matcher criteria.
10052  *
10053  * @return
10054  *   Bitmap of enabled fields.
10055  */
10056 static uint8_t
10057 flow_dv_matcher_enable(uint32_t *match_criteria)
10058 {
10059 	uint8_t match_criteria_enable;
10060 
10061 	match_criteria_enable =
10062 		(!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
10063 		MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
10064 	match_criteria_enable |=
10065 		(!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
10066 		MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
10067 	match_criteria_enable |=
10068 		(!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
10069 		MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
10070 	match_criteria_enable |=
10071 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
10072 		MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
10073 	match_criteria_enable |=
10074 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
10075 		MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
10076 	match_criteria_enable |=
10077 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) <<
10078 		MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT;
10079 	match_criteria_enable |=
10080 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_5)) <<
10081 		MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT;
10082 	return match_criteria_enable;
10083 }
10084 
10085 static void
10086 __flow_dv_adjust_buf_size(size_t *size, uint8_t match_criteria)
10087 {
10088 	/*
10089 	 * Check flow matching criteria first, subtract misc5/4 length if flow
10090 	 * doesn't own misc5/4 parameters. In some old rdma-core releases,
10091 	 * misc5/4 are not supported, and matcher creation failure is expected
10092 	 * w/o subtration. If misc5 is provided, misc4 must be counted in since
10093 	 * misc5 is right after misc4.
10094 	 */
10095 	if (!(match_criteria & (1 << MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT))) {
10096 		*size = MLX5_ST_SZ_BYTES(fte_match_param) -
10097 			MLX5_ST_SZ_BYTES(fte_match_set_misc5);
10098 		if (!(match_criteria & (1 <<
10099 			MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT))) {
10100 			*size -= MLX5_ST_SZ_BYTES(fte_match_set_misc4);
10101 		}
10102 	}
10103 }
10104 
10105 static struct mlx5_list_entry *
10106 flow_dv_matcher_clone_cb(void *tool_ctx __rte_unused,
10107 			 struct mlx5_list_entry *entry, void *cb_ctx)
10108 {
10109 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10110 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10111 	struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
10112 							    typeof(*tbl), tbl);
10113 	struct mlx5_flow_dv_matcher *resource = mlx5_malloc(MLX5_MEM_ANY,
10114 							    sizeof(*resource),
10115 							    0, SOCKET_ID_ANY);
10116 
10117 	if (!resource) {
10118 		rte_flow_error_set(ctx->error, ENOMEM,
10119 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10120 				   "cannot create matcher");
10121 		return NULL;
10122 	}
10123 	memcpy(resource, entry, sizeof(*resource));
10124 	resource->tbl = &tbl->tbl;
10125 	return &resource->entry;
10126 }
10127 
10128 static void
10129 flow_dv_matcher_clone_free_cb(void *tool_ctx __rte_unused,
10130 			     struct mlx5_list_entry *entry)
10131 {
10132 	mlx5_free(entry);
10133 }
10134 
10135 struct mlx5_list_entry *
10136 flow_dv_tbl_create_cb(void *tool_ctx, void *cb_ctx)
10137 {
10138 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10139 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10140 	struct rte_eth_dev *dev = ctx->dev;
10141 	struct mlx5_flow_tbl_data_entry *tbl_data;
10142 	struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data2;
10143 	struct rte_flow_error *error = ctx->error;
10144 	union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) };
10145 	struct mlx5_flow_tbl_resource *tbl;
10146 	void *domain;
10147 	uint32_t idx = 0;
10148 	int ret;
10149 
10150 	tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10151 	if (!tbl_data) {
10152 		rte_flow_error_set(error, ENOMEM,
10153 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10154 				   NULL,
10155 				   "cannot allocate flow table data entry");
10156 		return NULL;
10157 	}
10158 	tbl_data->idx = idx;
10159 	tbl_data->tunnel = tt_prm->tunnel;
10160 	tbl_data->group_id = tt_prm->group_id;
10161 	tbl_data->external = !!tt_prm->external;
10162 	tbl_data->tunnel_offload = is_tunnel_offload_active(dev);
10163 	tbl_data->is_egress = !!key.is_egress;
10164 	tbl_data->is_transfer = !!key.is_fdb;
10165 	tbl_data->dummy = !!key.dummy;
10166 	tbl_data->level = key.level;
10167 	tbl_data->id = key.id;
10168 	tbl = &tbl_data->tbl;
10169 	if (key.dummy)
10170 		return &tbl_data->entry;
10171 	if (key.is_fdb)
10172 		domain = sh->fdb_domain;
10173 	else if (key.is_egress)
10174 		domain = sh->tx_domain;
10175 	else
10176 		domain = sh->rx_domain;
10177 	ret = mlx5_flow_os_create_flow_tbl(domain, key.level, &tbl->obj);
10178 	if (ret) {
10179 		rte_flow_error_set(error, ENOMEM,
10180 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10181 				   NULL, "cannot create flow table object");
10182 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10183 		return NULL;
10184 	}
10185 	if (key.level != 0) {
10186 		ret = mlx5_flow_os_create_flow_action_dest_flow_tbl
10187 					(tbl->obj, &tbl_data->jump.action);
10188 		if (ret) {
10189 			rte_flow_error_set(error, ENOMEM,
10190 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10191 					   NULL,
10192 					   "cannot create flow jump action");
10193 			mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10194 			mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10195 			return NULL;
10196 		}
10197 	}
10198 	MKSTR(matcher_name, "%s_%s_%u_%u_matcher_list",
10199 	      key.is_fdb ? "FDB" : "NIC", key.is_egress ? "egress" : "ingress",
10200 	      key.level, key.id);
10201 	tbl_data->matchers = mlx5_list_create(matcher_name, sh, true,
10202 					      flow_dv_matcher_create_cb,
10203 					      flow_dv_matcher_match_cb,
10204 					      flow_dv_matcher_remove_cb,
10205 					      flow_dv_matcher_clone_cb,
10206 					      flow_dv_matcher_clone_free_cb);
10207 	if (!tbl_data->matchers) {
10208 		rte_flow_error_set(error, ENOMEM,
10209 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10210 				   NULL,
10211 				   "cannot create tbl matcher list");
10212 		mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10213 		mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10214 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10215 		return NULL;
10216 	}
10217 	return &tbl_data->entry;
10218 }
10219 
10220 int
10221 flow_dv_tbl_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
10222 		     void *cb_ctx)
10223 {
10224 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10225 	struct mlx5_flow_tbl_data_entry *tbl_data =
10226 		container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10227 	union mlx5_flow_tbl_key key = { .v64 =  *(uint64_t *)(ctx->data) };
10228 
10229 	return tbl_data->level != key.level ||
10230 	       tbl_data->id != key.id ||
10231 	       tbl_data->dummy != key.dummy ||
10232 	       tbl_data->is_transfer != !!key.is_fdb ||
10233 	       tbl_data->is_egress != !!key.is_egress;
10234 }
10235 
10236 struct mlx5_list_entry *
10237 flow_dv_tbl_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
10238 		      void *cb_ctx)
10239 {
10240 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10241 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10242 	struct mlx5_flow_tbl_data_entry *tbl_data;
10243 	struct rte_flow_error *error = ctx->error;
10244 	uint32_t idx = 0;
10245 
10246 	tbl_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10247 	if (!tbl_data) {
10248 		rte_flow_error_set(error, ENOMEM,
10249 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10250 				   NULL,
10251 				   "cannot allocate flow table data entry");
10252 		return NULL;
10253 	}
10254 	memcpy(tbl_data, oentry, sizeof(*tbl_data));
10255 	tbl_data->idx = idx;
10256 	return &tbl_data->entry;
10257 }
10258 
10259 void
10260 flow_dv_tbl_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10261 {
10262 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10263 	struct mlx5_flow_tbl_data_entry *tbl_data =
10264 		    container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10265 
10266 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10267 }
10268 
10269 /**
10270  * Get a flow table.
10271  *
10272  * @param[in, out] dev
10273  *   Pointer to rte_eth_dev structure.
10274  * @param[in] table_level
10275  *   Table level to use.
10276  * @param[in] egress
10277  *   Direction of the table.
10278  * @param[in] transfer
10279  *   E-Switch or NIC flow.
10280  * @param[in] dummy
10281  *   Dummy entry for dv API.
10282  * @param[in] table_id
10283  *   Table id to use.
10284  * @param[out] error
10285  *   pointer to error structure.
10286  *
10287  * @return
10288  *   Returns tables resource based on the index, NULL in case of failed.
10289  */
10290 struct mlx5_flow_tbl_resource *
10291 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
10292 			 uint32_t table_level, uint8_t egress,
10293 			 uint8_t transfer,
10294 			 bool external,
10295 			 const struct mlx5_flow_tunnel *tunnel,
10296 			 uint32_t group_id, uint8_t dummy,
10297 			 uint32_t table_id,
10298 			 struct rte_flow_error *error)
10299 {
10300 	struct mlx5_priv *priv = dev->data->dev_private;
10301 	union mlx5_flow_tbl_key table_key = {
10302 		{
10303 			.level = table_level,
10304 			.id = table_id,
10305 			.reserved = 0,
10306 			.dummy = !!dummy,
10307 			.is_fdb = !!transfer,
10308 			.is_egress = !!egress,
10309 		}
10310 	};
10311 	struct mlx5_flow_tbl_tunnel_prm tt_prm = {
10312 		.tunnel = tunnel,
10313 		.group_id = group_id,
10314 		.external = external,
10315 	};
10316 	struct mlx5_flow_cb_ctx ctx = {
10317 		.dev = dev,
10318 		.error = error,
10319 		.data = &table_key.v64,
10320 		.data2 = &tt_prm,
10321 	};
10322 	struct mlx5_list_entry *entry;
10323 	struct mlx5_flow_tbl_data_entry *tbl_data;
10324 
10325 	entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx);
10326 	if (!entry) {
10327 		rte_flow_error_set(error, ENOMEM,
10328 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10329 				   "cannot get table");
10330 		return NULL;
10331 	}
10332 	DRV_LOG(DEBUG, "table_level %u table_id %u "
10333 		"tunnel %u group %u registered.",
10334 		table_level, table_id,
10335 		tunnel ? tunnel->tunnel_id : 0, group_id);
10336 	tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10337 	return &tbl_data->tbl;
10338 }
10339 
10340 void
10341 flow_dv_tbl_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10342 {
10343 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10344 	struct mlx5_flow_tbl_data_entry *tbl_data =
10345 		    container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10346 
10347 	MLX5_ASSERT(entry && sh);
10348 	if (tbl_data->jump.action)
10349 		mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10350 	if (tbl_data->tbl.obj)
10351 		mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj);
10352 	if (tbl_data->tunnel_offload && tbl_data->external) {
10353 		struct mlx5_list_entry *he;
10354 		struct mlx5_hlist *tunnel_grp_hash;
10355 		struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;
10356 		union tunnel_tbl_key tunnel_key = {
10357 			.tunnel_id = tbl_data->tunnel ?
10358 					tbl_data->tunnel->tunnel_id : 0,
10359 			.group = tbl_data->group_id
10360 		};
10361 		uint32_t table_level = tbl_data->level;
10362 		struct mlx5_flow_cb_ctx ctx = {
10363 			.data = (void *)&tunnel_key.val,
10364 		};
10365 
10366 		tunnel_grp_hash = tbl_data->tunnel ?
10367 					tbl_data->tunnel->groups :
10368 					thub->groups;
10369 		he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, &ctx);
10370 		if (he)
10371 			mlx5_hlist_unregister(tunnel_grp_hash, he);
10372 		DRV_LOG(DEBUG,
10373 			"table_level %u id %u tunnel %u group %u released.",
10374 			table_level,
10375 			tbl_data->id,
10376 			tbl_data->tunnel ?
10377 			tbl_data->tunnel->tunnel_id : 0,
10378 			tbl_data->group_id);
10379 	}
10380 	mlx5_list_destroy(tbl_data->matchers);
10381 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10382 }
10383 
10384 /**
10385  * Release a flow table.
10386  *
10387  * @param[in] sh
10388  *   Pointer to device shared structure.
10389  * @param[in] tbl
10390  *   Table resource to be released.
10391  *
10392  * @return
10393  *   Returns 0 if table was released, else return 1;
10394  */
10395 static int
10396 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
10397 			     struct mlx5_flow_tbl_resource *tbl)
10398 {
10399 	struct mlx5_flow_tbl_data_entry *tbl_data =
10400 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
10401 
10402 	if (!tbl)
10403 		return 0;
10404 	return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry);
10405 }
10406 
10407 int
10408 flow_dv_matcher_match_cb(void *tool_ctx __rte_unused,
10409 			 struct mlx5_list_entry *entry, void *cb_ctx)
10410 {
10411 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10412 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10413 	struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur),
10414 							entry);
10415 
10416 	return cur->crc != ref->crc ||
10417 	       cur->priority != ref->priority ||
10418 	       memcmp((const void *)cur->mask.buf,
10419 		      (const void *)ref->mask.buf, ref->mask.size);
10420 }
10421 
10422 struct mlx5_list_entry *
10423 flow_dv_matcher_create_cb(void *tool_ctx, void *cb_ctx)
10424 {
10425 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10426 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10427 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10428 	struct mlx5_flow_dv_matcher *resource;
10429 	struct mlx5dv_flow_matcher_attr dv_attr = {
10430 		.type = IBV_FLOW_ATTR_NORMAL,
10431 		.match_mask = (void *)&ref->mask,
10432 	};
10433 	struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
10434 							    typeof(*tbl), tbl);
10435 	int ret;
10436 
10437 	resource = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*resource), 0,
10438 			       SOCKET_ID_ANY);
10439 	if (!resource) {
10440 		rte_flow_error_set(ctx->error, ENOMEM,
10441 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10442 				   "cannot create matcher");
10443 		return NULL;
10444 	}
10445 	*resource = *ref;
10446 	dv_attr.match_criteria_enable =
10447 		flow_dv_matcher_enable(resource->mask.buf);
10448 	__flow_dv_adjust_buf_size(&ref->mask.size,
10449 				  dv_attr.match_criteria_enable);
10450 	dv_attr.priority = ref->priority;
10451 	if (tbl->is_egress)
10452 		dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
10453 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->tbl.obj,
10454 					       &resource->matcher_object);
10455 	if (ret) {
10456 		mlx5_free(resource);
10457 		rte_flow_error_set(ctx->error, ENOMEM,
10458 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10459 				   "cannot create matcher");
10460 		return NULL;
10461 	}
10462 	return &resource->entry;
10463 }
10464 
10465 /**
10466  * Register the flow matcher.
10467  *
10468  * @param[in, out] dev
10469  *   Pointer to rte_eth_dev structure.
10470  * @param[in, out] matcher
10471  *   Pointer to flow matcher.
10472  * @param[in, out] key
10473  *   Pointer to flow table key.
10474  * @parm[in, out] dev_flow
10475  *   Pointer to the dev_flow.
10476  * @param[out] error
10477  *   pointer to error structure.
10478  *
10479  * @return
10480  *   0 on success otherwise -errno and errno is set.
10481  */
10482 static int
10483 flow_dv_matcher_register(struct rte_eth_dev *dev,
10484 			 struct mlx5_flow_dv_matcher *ref,
10485 			 union mlx5_flow_tbl_key *key,
10486 			 struct mlx5_flow *dev_flow,
10487 			 const struct mlx5_flow_tunnel *tunnel,
10488 			 uint32_t group_id,
10489 			 struct rte_flow_error *error)
10490 {
10491 	struct mlx5_list_entry *entry;
10492 	struct mlx5_flow_dv_matcher *resource;
10493 	struct mlx5_flow_tbl_resource *tbl;
10494 	struct mlx5_flow_tbl_data_entry *tbl_data;
10495 	struct mlx5_flow_cb_ctx ctx = {
10496 		.error = error,
10497 		.data = ref,
10498 	};
10499 	/**
10500 	 * tunnel offload API requires this registration for cases when
10501 	 * tunnel match rule was inserted before tunnel set rule.
10502 	 */
10503 	tbl = flow_dv_tbl_resource_get(dev, key->level,
10504 				       key->is_egress, key->is_fdb,
10505 				       dev_flow->external, tunnel,
10506 				       group_id, 0, key->id, error);
10507 	if (!tbl)
10508 		return -rte_errno;	/* No need to refill the error info */
10509 	tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
10510 	ref->tbl = tbl;
10511 	entry = mlx5_list_register(tbl_data->matchers, &ctx);
10512 	if (!entry) {
10513 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
10514 		return rte_flow_error_set(error, ENOMEM,
10515 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10516 					  "cannot allocate ref memory");
10517 	}
10518 	resource = container_of(entry, typeof(*resource), entry);
10519 	dev_flow->handle->dvh.matcher = resource;
10520 	return 0;
10521 }
10522 
10523 struct mlx5_list_entry *
10524 flow_dv_tag_create_cb(void *tool_ctx, void *cb_ctx)
10525 {
10526 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10527 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10528 	struct mlx5_flow_dv_tag_resource *entry;
10529 	uint32_t idx = 0;
10530 	int ret;
10531 
10532 	entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
10533 	if (!entry) {
10534 		rte_flow_error_set(ctx->error, ENOMEM,
10535 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10536 				   "cannot allocate resource memory");
10537 		return NULL;
10538 	}
10539 	entry->idx = idx;
10540 	entry->tag_id = *(uint32_t *)(ctx->data);
10541 	ret = mlx5_flow_os_create_flow_action_tag(entry->tag_id,
10542 						  &entry->action);
10543 	if (ret) {
10544 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx);
10545 		rte_flow_error_set(ctx->error, ENOMEM,
10546 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10547 				   NULL, "cannot create action");
10548 		return NULL;
10549 	}
10550 	return &entry->entry;
10551 }
10552 
10553 int
10554 flow_dv_tag_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
10555 		     void *cb_ctx)
10556 {
10557 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10558 	struct mlx5_flow_dv_tag_resource *tag =
10559 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10560 
10561 	return *(uint32_t *)(ctx->data) != tag->tag_id;
10562 }
10563 
10564 struct mlx5_list_entry *
10565 flow_dv_tag_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
10566 		     void *cb_ctx)
10567 {
10568 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10569 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10570 	struct mlx5_flow_dv_tag_resource *entry;
10571 	uint32_t idx = 0;
10572 
10573 	entry = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
10574 	if (!entry) {
10575 		rte_flow_error_set(ctx->error, ENOMEM,
10576 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10577 				   "cannot allocate tag resource memory");
10578 		return NULL;
10579 	}
10580 	memcpy(entry, oentry, sizeof(*entry));
10581 	entry->idx = idx;
10582 	return &entry->entry;
10583 }
10584 
10585 void
10586 flow_dv_tag_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10587 {
10588 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10589 	struct mlx5_flow_dv_tag_resource *tag =
10590 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10591 
10592 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
10593 }
10594 
10595 /**
10596  * Find existing tag resource or create and register a new one.
10597  *
10598  * @param dev[in, out]
10599  *   Pointer to rte_eth_dev structure.
10600  * @param[in, out] tag_be24
10601  *   Tag value in big endian then R-shift 8.
10602  * @parm[in, out] dev_flow
10603  *   Pointer to the dev_flow.
10604  * @param[out] error
10605  *   pointer to error structure.
10606  *
10607  * @return
10608  *   0 on success otherwise -errno and errno is set.
10609  */
10610 static int
10611 flow_dv_tag_resource_register
10612 			(struct rte_eth_dev *dev,
10613 			 uint32_t tag_be24,
10614 			 struct mlx5_flow *dev_flow,
10615 			 struct rte_flow_error *error)
10616 {
10617 	struct mlx5_priv *priv = dev->data->dev_private;
10618 	struct mlx5_flow_dv_tag_resource *resource;
10619 	struct mlx5_list_entry *entry;
10620 	struct mlx5_flow_cb_ctx ctx = {
10621 					.error = error,
10622 					.data = &tag_be24,
10623 					};
10624 	struct mlx5_hlist *tag_table;
10625 
10626 	tag_table = flow_dv_hlist_prepare(priv->sh, &priv->sh->tag_table,
10627 				      "tags",
10628 				      MLX5_TAGS_HLIST_ARRAY_SIZE,
10629 				      false, false, priv->sh,
10630 				      flow_dv_tag_create_cb,
10631 				      flow_dv_tag_match_cb,
10632 				      flow_dv_tag_remove_cb,
10633 				      flow_dv_tag_clone_cb,
10634 				      flow_dv_tag_clone_free_cb);
10635 	if (unlikely(!tag_table))
10636 		return -rte_errno;
10637 	entry = mlx5_hlist_register(tag_table, tag_be24, &ctx);
10638 	if (entry) {
10639 		resource = container_of(entry, struct mlx5_flow_dv_tag_resource,
10640 					entry);
10641 		dev_flow->handle->dvh.rix_tag = resource->idx;
10642 		dev_flow->dv.tag_resource = resource;
10643 		return 0;
10644 	}
10645 	return -rte_errno;
10646 }
10647 
10648 void
10649 flow_dv_tag_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10650 {
10651 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10652 	struct mlx5_flow_dv_tag_resource *tag =
10653 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10654 
10655 	MLX5_ASSERT(tag && sh && tag->action);
10656 	claim_zero(mlx5_flow_os_destroy_flow_action(tag->action));
10657 	DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag);
10658 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
10659 }
10660 
10661 /**
10662  * Release the tag.
10663  *
10664  * @param dev
10665  *   Pointer to Ethernet device.
10666  * @param tag_idx
10667  *   Tag index.
10668  *
10669  * @return
10670  *   1 while a reference on it exists, 0 when freed.
10671  */
10672 static int
10673 flow_dv_tag_release(struct rte_eth_dev *dev,
10674 		    uint32_t tag_idx)
10675 {
10676 	struct mlx5_priv *priv = dev->data->dev_private;
10677 	struct mlx5_flow_dv_tag_resource *tag;
10678 
10679 	tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx);
10680 	if (!tag)
10681 		return 0;
10682 	DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
10683 		dev->data->port_id, (void *)tag, tag->entry.ref_cnt);
10684 	return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry);
10685 }
10686 
10687 /**
10688  * Translate port ID action to vport.
10689  *
10690  * @param[in] dev
10691  *   Pointer to rte_eth_dev structure.
10692  * @param[in] action
10693  *   Pointer to the port ID action.
10694  * @param[out] dst_port_id
10695  *   The target port ID.
10696  * @param[out] error
10697  *   Pointer to the error structure.
10698  *
10699  * @return
10700  *   0 on success, a negative errno value otherwise and rte_errno is set.
10701  */
10702 static int
10703 flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
10704 				 const struct rte_flow_action *action,
10705 				 uint32_t *dst_port_id,
10706 				 struct rte_flow_error *error)
10707 {
10708 	uint32_t port;
10709 	struct mlx5_priv *priv;
10710 	const struct rte_flow_action_port_id *conf =
10711 			(const struct rte_flow_action_port_id *)action->conf;
10712 
10713 	port = conf->original ? dev->data->port_id : conf->id;
10714 	priv = mlx5_port_to_eswitch_info(port, false);
10715 	if (!priv)
10716 		return rte_flow_error_set(error, -rte_errno,
10717 					  RTE_FLOW_ERROR_TYPE_ACTION,
10718 					  NULL,
10719 					  "No eswitch info was found for port");
10720 #ifdef HAVE_MLX5DV_DR_CREATE_DEST_IB_PORT
10721 	/*
10722 	 * This parameter is transferred to
10723 	 * mlx5dv_dr_action_create_dest_ib_port().
10724 	 */
10725 	*dst_port_id = priv->dev_port;
10726 #else
10727 	/*
10728 	 * Legacy mode, no LAG configurations is supported.
10729 	 * This parameter is transferred to
10730 	 * mlx5dv_dr_action_create_dest_vport().
10731 	 */
10732 	*dst_port_id = priv->vport_id;
10733 #endif
10734 	return 0;
10735 }
10736 
10737 /**
10738  * Create a counter with aging configuration.
10739  *
10740  * @param[in] dev
10741  *   Pointer to rte_eth_dev structure.
10742  * @param[in] dev_flow
10743  *   Pointer to the mlx5_flow.
10744  * @param[out] count
10745  *   Pointer to the counter action configuration.
10746  * @param[in] age
10747  *   Pointer to the aging action configuration.
10748  *
10749  * @return
10750  *   Index to flow counter on success, 0 otherwise.
10751  */
10752 static uint32_t
10753 flow_dv_translate_create_counter(struct rte_eth_dev *dev,
10754 				struct mlx5_flow *dev_flow,
10755 				const struct rte_flow_action_count *count
10756 					__rte_unused,
10757 				const struct rte_flow_action_age *age)
10758 {
10759 	uint32_t counter;
10760 	struct mlx5_age_param *age_param;
10761 
10762 	counter = flow_dv_counter_alloc(dev, !!age);
10763 	if (!counter || age == NULL)
10764 		return counter;
10765 	age_param = flow_dv_counter_idx_get_age(dev, counter);
10766 	age_param->context = age->context ? age->context :
10767 		(void *)(uintptr_t)(dev_flow->flow_idx);
10768 	age_param->timeout = age->timeout;
10769 	age_param->port_id = dev->data->port_id;
10770 	__atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED);
10771 	__atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED);
10772 	return counter;
10773 }
10774 
10775 /**
10776  * Add Tx queue matcher
10777  *
10778  * @param[in] dev
10779  *   Pointer to the dev struct.
10780  * @param[in, out] matcher
10781  *   Flow matcher.
10782  * @param[in, out] key
10783  *   Flow matcher value.
10784  * @param[in] item
10785  *   Flow pattern to translate.
10786  * @param[in] inner
10787  *   Item is inner pattern.
10788  */
10789 static void
10790 flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev,
10791 				void *matcher, void *key,
10792 				const struct rte_flow_item *item)
10793 {
10794 	const struct mlx5_rte_flow_item_tx_queue *queue_m;
10795 	const struct mlx5_rte_flow_item_tx_queue *queue_v;
10796 	void *misc_m =
10797 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
10798 	void *misc_v =
10799 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
10800 	struct mlx5_txq_ctrl *txq;
10801 	uint32_t queue;
10802 
10803 
10804 	queue_m = (const void *)item->mask;
10805 	if (!queue_m)
10806 		return;
10807 	queue_v = (const void *)item->spec;
10808 	if (!queue_v)
10809 		return;
10810 	txq = mlx5_txq_get(dev, queue_v->queue);
10811 	if (!txq)
10812 		return;
10813 	queue = txq->obj->sq->id;
10814 	MLX5_SET(fte_match_set_misc, misc_m, source_sqn, queue_m->queue);
10815 	MLX5_SET(fte_match_set_misc, misc_v, source_sqn,
10816 		 queue & queue_m->queue);
10817 	mlx5_txq_release(dev, queue_v->queue);
10818 }
10819 
10820 /**
10821  * Set the hash fields according to the @p flow information.
10822  *
10823  * @param[in] dev_flow
10824  *   Pointer to the mlx5_flow.
10825  * @param[in] rss_desc
10826  *   Pointer to the mlx5_flow_rss_desc.
10827  */
10828 static void
10829 flow_dv_hashfields_set(struct mlx5_flow *dev_flow,
10830 		       struct mlx5_flow_rss_desc *rss_desc)
10831 {
10832 	uint64_t items = dev_flow->handle->layers;
10833 	int rss_inner = 0;
10834 	uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types);
10835 
10836 	dev_flow->hash_fields = 0;
10837 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
10838 	if (rss_desc->level >= 2)
10839 		rss_inner = 1;
10840 #endif
10841 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) ||
10842 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) {
10843 		if (rss_types & MLX5_IPV4_LAYER_TYPES) {
10844 			if (rss_types & ETH_RSS_L3_SRC_ONLY)
10845 				dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV4;
10846 			else if (rss_types & ETH_RSS_L3_DST_ONLY)
10847 				dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV4;
10848 			else
10849 				dev_flow->hash_fields |= MLX5_IPV4_IBV_RX_HASH;
10850 		}
10851 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
10852 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) {
10853 		if (rss_types & MLX5_IPV6_LAYER_TYPES) {
10854 			if (rss_types & ETH_RSS_L3_SRC_ONLY)
10855 				dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV6;
10856 			else if (rss_types & ETH_RSS_L3_DST_ONLY)
10857 				dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV6;
10858 			else
10859 				dev_flow->hash_fields |= MLX5_IPV6_IBV_RX_HASH;
10860 		}
10861 	}
10862 	if (dev_flow->hash_fields == 0)
10863 		/*
10864 		 * There is no match between the RSS types and the
10865 		 * L3 protocol (IPv4/IPv6) defined in the flow rule.
10866 		 */
10867 		return;
10868 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) ||
10869 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) {
10870 		if (rss_types & ETH_RSS_UDP) {
10871 			if (rss_types & ETH_RSS_L4_SRC_ONLY)
10872 				dev_flow->hash_fields |=
10873 						IBV_RX_HASH_SRC_PORT_UDP;
10874 			else if (rss_types & ETH_RSS_L4_DST_ONLY)
10875 				dev_flow->hash_fields |=
10876 						IBV_RX_HASH_DST_PORT_UDP;
10877 			else
10878 				dev_flow->hash_fields |= MLX5_UDP_IBV_RX_HASH;
10879 		}
10880 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) ||
10881 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) {
10882 		if (rss_types & ETH_RSS_TCP) {
10883 			if (rss_types & ETH_RSS_L4_SRC_ONLY)
10884 				dev_flow->hash_fields |=
10885 						IBV_RX_HASH_SRC_PORT_TCP;
10886 			else if (rss_types & ETH_RSS_L4_DST_ONLY)
10887 				dev_flow->hash_fields |=
10888 						IBV_RX_HASH_DST_PORT_TCP;
10889 			else
10890 				dev_flow->hash_fields |= MLX5_TCP_IBV_RX_HASH;
10891 		}
10892 	}
10893 	if (rss_inner)
10894 		dev_flow->hash_fields |= IBV_RX_HASH_INNER;
10895 }
10896 
10897 /**
10898  * Prepare an Rx Hash queue.
10899  *
10900  * @param dev
10901  *   Pointer to Ethernet device.
10902  * @param[in] dev_flow
10903  *   Pointer to the mlx5_flow.
10904  * @param[in] rss_desc
10905  *   Pointer to the mlx5_flow_rss_desc.
10906  * @param[out] hrxq_idx
10907  *   Hash Rx queue index.
10908  *
10909  * @return
10910  *   The Verbs/DevX object initialised, NULL otherwise and rte_errno is set.
10911  */
10912 static struct mlx5_hrxq *
10913 flow_dv_hrxq_prepare(struct rte_eth_dev *dev,
10914 		     struct mlx5_flow *dev_flow,
10915 		     struct mlx5_flow_rss_desc *rss_desc,
10916 		     uint32_t *hrxq_idx)
10917 {
10918 	struct mlx5_priv *priv = dev->data->dev_private;
10919 	struct mlx5_flow_handle *dh = dev_flow->handle;
10920 	struct mlx5_hrxq *hrxq;
10921 
10922 	MLX5_ASSERT(rss_desc->queue_num);
10923 	rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN;
10924 	rss_desc->hash_fields = dev_flow->hash_fields;
10925 	rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL);
10926 	rss_desc->shared_rss = 0;
10927 	if (rss_desc->hash_fields == 0)
10928 		rss_desc->queue_num = 1;
10929 	*hrxq_idx = mlx5_hrxq_get(dev, rss_desc);
10930 	if (!*hrxq_idx)
10931 		return NULL;
10932 	hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
10933 			      *hrxq_idx);
10934 	return hrxq;
10935 }
10936 
10937 /**
10938  * Release sample sub action resource.
10939  *
10940  * @param[in, out] dev
10941  *   Pointer to rte_eth_dev structure.
10942  * @param[in] act_res
10943  *   Pointer to sample sub action resource.
10944  */
10945 static void
10946 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev,
10947 				   struct mlx5_flow_sub_actions_idx *act_res)
10948 {
10949 	if (act_res->rix_hrxq) {
10950 		mlx5_hrxq_release(dev, act_res->rix_hrxq);
10951 		act_res->rix_hrxq = 0;
10952 	}
10953 	if (act_res->rix_encap_decap) {
10954 		flow_dv_encap_decap_resource_release(dev,
10955 						     act_res->rix_encap_decap);
10956 		act_res->rix_encap_decap = 0;
10957 	}
10958 	if (act_res->rix_port_id_action) {
10959 		flow_dv_port_id_action_resource_release(dev,
10960 						act_res->rix_port_id_action);
10961 		act_res->rix_port_id_action = 0;
10962 	}
10963 	if (act_res->rix_tag) {
10964 		flow_dv_tag_release(dev, act_res->rix_tag);
10965 		act_res->rix_tag = 0;
10966 	}
10967 	if (act_res->rix_jump) {
10968 		flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump);
10969 		act_res->rix_jump = 0;
10970 	}
10971 }
10972 
10973 int
10974 flow_dv_sample_match_cb(void *tool_ctx __rte_unused,
10975 			struct mlx5_list_entry *entry, void *cb_ctx)
10976 {
10977 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10978 	struct rte_eth_dev *dev = ctx->dev;
10979 	struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
10980 	struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
10981 							      typeof(*resource),
10982 							      entry);
10983 
10984 	if (ctx_resource->ratio == resource->ratio &&
10985 	    ctx_resource->ft_type == resource->ft_type &&
10986 	    ctx_resource->ft_id == resource->ft_id &&
10987 	    ctx_resource->set_action == resource->set_action &&
10988 	    !memcmp((void *)&ctx_resource->sample_act,
10989 		    (void *)&resource->sample_act,
10990 		    sizeof(struct mlx5_flow_sub_actions_list))) {
10991 		/*
10992 		 * Existing sample action should release the prepared
10993 		 * sub-actions reference counter.
10994 		 */
10995 		flow_dv_sample_sub_actions_release(dev,
10996 						   &ctx_resource->sample_idx);
10997 		return 0;
10998 	}
10999 	return 1;
11000 }
11001 
11002 struct mlx5_list_entry *
11003 flow_dv_sample_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
11004 {
11005 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11006 	struct rte_eth_dev *dev = ctx->dev;
11007 	struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
11008 	void **sample_dv_actions = ctx_resource->sub_actions;
11009 	struct mlx5_flow_dv_sample_resource *resource;
11010 	struct mlx5dv_dr_flow_sampler_attr sampler_attr;
11011 	struct mlx5_priv *priv = dev->data->dev_private;
11012 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11013 	struct mlx5_flow_tbl_resource *tbl;
11014 	uint32_t idx = 0;
11015 	const uint32_t next_ft_step = 1;
11016 	uint32_t next_ft_id = ctx_resource->ft_id + next_ft_step;
11017 	uint8_t is_egress = 0;
11018 	uint8_t is_transfer = 0;
11019 	struct rte_flow_error *error = ctx->error;
11020 
11021 	/* Register new sample resource. */
11022 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11023 	if (!resource) {
11024 		rte_flow_error_set(error, ENOMEM,
11025 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11026 					  NULL,
11027 					  "cannot allocate resource memory");
11028 		return NULL;
11029 	}
11030 	*resource = *ctx_resource;
11031 	/* Create normal path table level */
11032 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11033 		is_transfer = 1;
11034 	else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
11035 		is_egress = 1;
11036 	tbl = flow_dv_tbl_resource_get(dev, next_ft_id,
11037 					is_egress, is_transfer,
11038 					true, NULL, 0, 0, 0, error);
11039 	if (!tbl) {
11040 		rte_flow_error_set(error, ENOMEM,
11041 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11042 					  NULL,
11043 					  "fail to create normal path table "
11044 					  "for sample");
11045 		goto error;
11046 	}
11047 	resource->normal_path_tbl = tbl;
11048 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) {
11049 		if (!sh->default_miss_action) {
11050 			rte_flow_error_set(error, ENOMEM,
11051 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11052 						NULL,
11053 						"default miss action was not "
11054 						"created");
11055 			goto error;
11056 		}
11057 		sample_dv_actions[ctx_resource->sample_act.actions_num++] =
11058 						sh->default_miss_action;
11059 	}
11060 	/* Create a DR sample action */
11061 	sampler_attr.sample_ratio = resource->ratio;
11062 	sampler_attr.default_next_table = tbl->obj;
11063 	sampler_attr.num_sample_actions = ctx_resource->sample_act.actions_num;
11064 	sampler_attr.sample_actions = (struct mlx5dv_dr_action **)
11065 							&sample_dv_actions[0];
11066 	sampler_attr.action = resource->set_action;
11067 	if (mlx5_os_flow_dr_create_flow_action_sampler
11068 			(&sampler_attr, &resource->verbs_action)) {
11069 		rte_flow_error_set(error, ENOMEM,
11070 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11071 					NULL, "cannot create sample action");
11072 		goto error;
11073 	}
11074 	resource->idx = idx;
11075 	resource->dev = dev;
11076 	return &resource->entry;
11077 error:
11078 	if (resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB)
11079 		flow_dv_sample_sub_actions_release(dev,
11080 						   &resource->sample_idx);
11081 	if (resource->normal_path_tbl)
11082 		flow_dv_tbl_resource_release(MLX5_SH(dev),
11083 				resource->normal_path_tbl);
11084 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx);
11085 	return NULL;
11086 
11087 }
11088 
11089 struct mlx5_list_entry *
11090 flow_dv_sample_clone_cb(void *tool_ctx __rte_unused,
11091 			 struct mlx5_list_entry *entry __rte_unused,
11092 			 void *cb_ctx)
11093 {
11094 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11095 	struct rte_eth_dev *dev = ctx->dev;
11096 	struct mlx5_flow_dv_sample_resource *resource;
11097 	struct mlx5_priv *priv = dev->data->dev_private;
11098 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11099 	uint32_t idx = 0;
11100 
11101 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11102 	if (!resource) {
11103 		rte_flow_error_set(ctx->error, ENOMEM,
11104 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11105 					  NULL,
11106 					  "cannot allocate resource memory");
11107 		return NULL;
11108 	}
11109 	memcpy(resource, entry, sizeof(*resource));
11110 	resource->idx = idx;
11111 	resource->dev = dev;
11112 	return &resource->entry;
11113 }
11114 
11115 void
11116 flow_dv_sample_clone_free_cb(void *tool_ctx __rte_unused,
11117 			     struct mlx5_list_entry *entry)
11118 {
11119 	struct mlx5_flow_dv_sample_resource *resource =
11120 				  container_of(entry, typeof(*resource), entry);
11121 	struct rte_eth_dev *dev = resource->dev;
11122 	struct mlx5_priv *priv = dev->data->dev_private;
11123 
11124 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
11125 }
11126 
11127 /**
11128  * Find existing sample resource or create and register a new one.
11129  *
11130  * @param[in, out] dev
11131  *   Pointer to rte_eth_dev structure.
11132  * @param[in] ref
11133  *   Pointer to sample resource reference.
11134  * @parm[in, out] dev_flow
11135  *   Pointer to the dev_flow.
11136  * @param[out] error
11137  *   pointer to error structure.
11138  *
11139  * @return
11140  *   0 on success otherwise -errno and errno is set.
11141  */
11142 static int
11143 flow_dv_sample_resource_register(struct rte_eth_dev *dev,
11144 			 struct mlx5_flow_dv_sample_resource *ref,
11145 			 struct mlx5_flow *dev_flow,
11146 			 struct rte_flow_error *error)
11147 {
11148 	struct mlx5_flow_dv_sample_resource *resource;
11149 	struct mlx5_list_entry *entry;
11150 	struct mlx5_priv *priv = dev->data->dev_private;
11151 	struct mlx5_flow_cb_ctx ctx = {
11152 		.dev = dev,
11153 		.error = error,
11154 		.data = ref,
11155 	};
11156 
11157 	entry = mlx5_list_register(priv->sh->sample_action_list, &ctx);
11158 	if (!entry)
11159 		return -rte_errno;
11160 	resource = container_of(entry, typeof(*resource), entry);
11161 	dev_flow->handle->dvh.rix_sample = resource->idx;
11162 	dev_flow->dv.sample_res = resource;
11163 	return 0;
11164 }
11165 
11166 int
11167 flow_dv_dest_array_match_cb(void *tool_ctx __rte_unused,
11168 			    struct mlx5_list_entry *entry, void *cb_ctx)
11169 {
11170 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11171 	struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11172 	struct rte_eth_dev *dev = ctx->dev;
11173 	struct mlx5_flow_dv_dest_array_resource *resource =
11174 				  container_of(entry, typeof(*resource), entry);
11175 	uint32_t idx = 0;
11176 
11177 	if (ctx_resource->num_of_dest == resource->num_of_dest &&
11178 	    ctx_resource->ft_type == resource->ft_type &&
11179 	    !memcmp((void *)resource->sample_act,
11180 		    (void *)ctx_resource->sample_act,
11181 		   (ctx_resource->num_of_dest *
11182 		   sizeof(struct mlx5_flow_sub_actions_list)))) {
11183 		/*
11184 		 * Existing sample action should release the prepared
11185 		 * sub-actions reference counter.
11186 		 */
11187 		for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11188 			flow_dv_sample_sub_actions_release(dev,
11189 					&ctx_resource->sample_idx[idx]);
11190 		return 0;
11191 	}
11192 	return 1;
11193 }
11194 
11195 struct mlx5_list_entry *
11196 flow_dv_dest_array_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
11197 {
11198 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11199 	struct rte_eth_dev *dev = ctx->dev;
11200 	struct mlx5_flow_dv_dest_array_resource *resource;
11201 	struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11202 	struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 };
11203 	struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM];
11204 	struct mlx5_priv *priv = dev->data->dev_private;
11205 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11206 	struct mlx5_flow_sub_actions_list *sample_act;
11207 	struct mlx5dv_dr_domain *domain;
11208 	uint32_t idx = 0, res_idx = 0;
11209 	struct rte_flow_error *error = ctx->error;
11210 	uint64_t action_flags;
11211 	int ret;
11212 
11213 	/* Register new destination array resource. */
11214 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11215 					    &res_idx);
11216 	if (!resource) {
11217 		rte_flow_error_set(error, ENOMEM,
11218 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11219 					  NULL,
11220 					  "cannot allocate resource memory");
11221 		return NULL;
11222 	}
11223 	*resource = *ctx_resource;
11224 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11225 		domain = sh->fdb_domain;
11226 	else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
11227 		domain = sh->rx_domain;
11228 	else
11229 		domain = sh->tx_domain;
11230 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11231 		dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *)
11232 				 mlx5_malloc(MLX5_MEM_ZERO,
11233 				 sizeof(struct mlx5dv_dr_action_dest_attr),
11234 				 0, SOCKET_ID_ANY);
11235 		if (!dest_attr[idx]) {
11236 			rte_flow_error_set(error, ENOMEM,
11237 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11238 					   NULL,
11239 					   "cannot allocate resource memory");
11240 			goto error;
11241 		}
11242 		dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST;
11243 		sample_act = &ctx_resource->sample_act[idx];
11244 		action_flags = sample_act->action_flags;
11245 		switch (action_flags) {
11246 		case MLX5_FLOW_ACTION_QUEUE:
11247 			dest_attr[idx]->dest = sample_act->dr_queue_action;
11248 			break;
11249 		case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP):
11250 			dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT;
11251 			dest_attr[idx]->dest_reformat = &dest_reformat[idx];
11252 			dest_attr[idx]->dest_reformat->reformat =
11253 					sample_act->dr_encap_action;
11254 			dest_attr[idx]->dest_reformat->dest =
11255 					sample_act->dr_port_id_action;
11256 			break;
11257 		case MLX5_FLOW_ACTION_PORT_ID:
11258 			dest_attr[idx]->dest = sample_act->dr_port_id_action;
11259 			break;
11260 		case MLX5_FLOW_ACTION_JUMP:
11261 			dest_attr[idx]->dest = sample_act->dr_jump_action;
11262 			break;
11263 		default:
11264 			rte_flow_error_set(error, EINVAL,
11265 					   RTE_FLOW_ERROR_TYPE_ACTION,
11266 					   NULL,
11267 					   "unsupported actions type");
11268 			goto error;
11269 		}
11270 	}
11271 	/* create a dest array actioin */
11272 	ret = mlx5_os_flow_dr_create_flow_action_dest_array
11273 						(domain,
11274 						 resource->num_of_dest,
11275 						 dest_attr,
11276 						 &resource->action);
11277 	if (ret) {
11278 		rte_flow_error_set(error, ENOMEM,
11279 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11280 				   NULL,
11281 				   "cannot create destination array action");
11282 		goto error;
11283 	}
11284 	resource->idx = res_idx;
11285 	resource->dev = dev;
11286 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11287 		mlx5_free(dest_attr[idx]);
11288 	return &resource->entry;
11289 error:
11290 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11291 		flow_dv_sample_sub_actions_release(dev,
11292 						   &resource->sample_idx[idx]);
11293 		if (dest_attr[idx])
11294 			mlx5_free(dest_attr[idx]);
11295 	}
11296 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx);
11297 	return NULL;
11298 }
11299 
11300 struct mlx5_list_entry *
11301 flow_dv_dest_array_clone_cb(void *tool_ctx __rte_unused,
11302 			    struct mlx5_list_entry *entry __rte_unused,
11303 			    void *cb_ctx)
11304 {
11305 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11306 	struct rte_eth_dev *dev = ctx->dev;
11307 	struct mlx5_flow_dv_dest_array_resource *resource;
11308 	struct mlx5_priv *priv = dev->data->dev_private;
11309 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11310 	uint32_t res_idx = 0;
11311 	struct rte_flow_error *error = ctx->error;
11312 
11313 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11314 				      &res_idx);
11315 	if (!resource) {
11316 		rte_flow_error_set(error, ENOMEM,
11317 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11318 					  NULL,
11319 					  "cannot allocate dest-array memory");
11320 		return NULL;
11321 	}
11322 	memcpy(resource, entry, sizeof(*resource));
11323 	resource->idx = res_idx;
11324 	resource->dev = dev;
11325 	return &resource->entry;
11326 }
11327 
11328 void
11329 flow_dv_dest_array_clone_free_cb(void *tool_ctx __rte_unused,
11330 				 struct mlx5_list_entry *entry)
11331 {
11332 	struct mlx5_flow_dv_dest_array_resource *resource =
11333 			container_of(entry, typeof(*resource), entry);
11334 	struct rte_eth_dev *dev = resource->dev;
11335 	struct mlx5_priv *priv = dev->data->dev_private;
11336 
11337 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
11338 }
11339 
11340 /**
11341  * Find existing destination array resource or create and register a new one.
11342  *
11343  * @param[in, out] dev
11344  *   Pointer to rte_eth_dev structure.
11345  * @param[in] ref
11346  *   Pointer to destination array resource reference.
11347  * @parm[in, out] dev_flow
11348  *   Pointer to the dev_flow.
11349  * @param[out] error
11350  *   pointer to error structure.
11351  *
11352  * @return
11353  *   0 on success otherwise -errno and errno is set.
11354  */
11355 static int
11356 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev,
11357 			 struct mlx5_flow_dv_dest_array_resource *ref,
11358 			 struct mlx5_flow *dev_flow,
11359 			 struct rte_flow_error *error)
11360 {
11361 	struct mlx5_flow_dv_dest_array_resource *resource;
11362 	struct mlx5_priv *priv = dev->data->dev_private;
11363 	struct mlx5_list_entry *entry;
11364 	struct mlx5_flow_cb_ctx ctx = {
11365 		.dev = dev,
11366 		.error = error,
11367 		.data = ref,
11368 	};
11369 
11370 	entry = mlx5_list_register(priv->sh->dest_array_list, &ctx);
11371 	if (!entry)
11372 		return -rte_errno;
11373 	resource = container_of(entry, typeof(*resource), entry);
11374 	dev_flow->handle->dvh.rix_dest_array = resource->idx;
11375 	dev_flow->dv.dest_array_res = resource;
11376 	return 0;
11377 }
11378 
11379 /**
11380  * Convert Sample action to DV specification.
11381  *
11382  * @param[in] dev
11383  *   Pointer to rte_eth_dev structure.
11384  * @param[in] action
11385  *   Pointer to sample action structure.
11386  * @param[in, out] dev_flow
11387  *   Pointer to the mlx5_flow.
11388  * @param[in] attr
11389  *   Pointer to the flow attributes.
11390  * @param[in, out] num_of_dest
11391  *   Pointer to the num of destination.
11392  * @param[in, out] sample_actions
11393  *   Pointer to sample actions list.
11394  * @param[in, out] res
11395  *   Pointer to sample resource.
11396  * @param[out] error
11397  *   Pointer to the error structure.
11398  *
11399  * @return
11400  *   0 on success, a negative errno value otherwise and rte_errno is set.
11401  */
11402 static int
11403 flow_dv_translate_action_sample(struct rte_eth_dev *dev,
11404 				const struct rte_flow_action_sample *action,
11405 				struct mlx5_flow *dev_flow,
11406 				const struct rte_flow_attr *attr,
11407 				uint32_t *num_of_dest,
11408 				void **sample_actions,
11409 				struct mlx5_flow_dv_sample_resource *res,
11410 				struct rte_flow_error *error)
11411 {
11412 	struct mlx5_priv *priv = dev->data->dev_private;
11413 	const struct rte_flow_action *sub_actions;
11414 	struct mlx5_flow_sub_actions_list *sample_act;
11415 	struct mlx5_flow_sub_actions_idx *sample_idx;
11416 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
11417 	struct rte_flow *flow = dev_flow->flow;
11418 	struct mlx5_flow_rss_desc *rss_desc;
11419 	uint64_t action_flags = 0;
11420 
11421 	MLX5_ASSERT(wks);
11422 	rss_desc = &wks->rss_desc;
11423 	sample_act = &res->sample_act;
11424 	sample_idx = &res->sample_idx;
11425 	res->ratio = action->ratio;
11426 	sub_actions = action->actions;
11427 	for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) {
11428 		int type = sub_actions->type;
11429 		uint32_t pre_rix = 0;
11430 		void *pre_r;
11431 		switch (type) {
11432 		case RTE_FLOW_ACTION_TYPE_QUEUE:
11433 		{
11434 			const struct rte_flow_action_queue *queue;
11435 			struct mlx5_hrxq *hrxq;
11436 			uint32_t hrxq_idx;
11437 
11438 			queue = sub_actions->conf;
11439 			rss_desc->queue_num = 1;
11440 			rss_desc->queue[0] = queue->index;
11441 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11442 						    rss_desc, &hrxq_idx);
11443 			if (!hrxq)
11444 				return rte_flow_error_set
11445 					(error, rte_errno,
11446 					 RTE_FLOW_ERROR_TYPE_ACTION,
11447 					 NULL,
11448 					 "cannot create fate queue");
11449 			sample_act->dr_queue_action = hrxq->action;
11450 			sample_idx->rix_hrxq = hrxq_idx;
11451 			sample_actions[sample_act->actions_num++] =
11452 						hrxq->action;
11453 			(*num_of_dest)++;
11454 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
11455 			if (action_flags & MLX5_FLOW_ACTION_MARK)
11456 				dev_flow->handle->rix_hrxq = hrxq_idx;
11457 			dev_flow->handle->fate_action =
11458 					MLX5_FLOW_FATE_QUEUE;
11459 			break;
11460 		}
11461 		case RTE_FLOW_ACTION_TYPE_RSS:
11462 		{
11463 			struct mlx5_hrxq *hrxq;
11464 			uint32_t hrxq_idx;
11465 			const struct rte_flow_action_rss *rss;
11466 			const uint8_t *rss_key;
11467 
11468 			rss = sub_actions->conf;
11469 			memcpy(rss_desc->queue, rss->queue,
11470 			       rss->queue_num * sizeof(uint16_t));
11471 			rss_desc->queue_num = rss->queue_num;
11472 			/* NULL RSS key indicates default RSS key. */
11473 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
11474 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
11475 			/*
11476 			 * rss->level and rss.types should be set in advance
11477 			 * when expanding items for RSS.
11478 			 */
11479 			flow_dv_hashfields_set(dev_flow, rss_desc);
11480 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11481 						    rss_desc, &hrxq_idx);
11482 			if (!hrxq)
11483 				return rte_flow_error_set
11484 					(error, rte_errno,
11485 					 RTE_FLOW_ERROR_TYPE_ACTION,
11486 					 NULL,
11487 					 "cannot create fate queue");
11488 			sample_act->dr_queue_action = hrxq->action;
11489 			sample_idx->rix_hrxq = hrxq_idx;
11490 			sample_actions[sample_act->actions_num++] =
11491 						hrxq->action;
11492 			(*num_of_dest)++;
11493 			action_flags |= MLX5_FLOW_ACTION_RSS;
11494 			if (action_flags & MLX5_FLOW_ACTION_MARK)
11495 				dev_flow->handle->rix_hrxq = hrxq_idx;
11496 			dev_flow->handle->fate_action =
11497 					MLX5_FLOW_FATE_QUEUE;
11498 			break;
11499 		}
11500 		case RTE_FLOW_ACTION_TYPE_MARK:
11501 		{
11502 			uint32_t tag_be = mlx5_flow_mark_set
11503 				(((const struct rte_flow_action_mark *)
11504 				(sub_actions->conf))->id);
11505 
11506 			dev_flow->handle->mark = 1;
11507 			pre_rix = dev_flow->handle->dvh.rix_tag;
11508 			/* Save the mark resource before sample */
11509 			pre_r = dev_flow->dv.tag_resource;
11510 			if (flow_dv_tag_resource_register(dev, tag_be,
11511 						  dev_flow, error))
11512 				return -rte_errno;
11513 			MLX5_ASSERT(dev_flow->dv.tag_resource);
11514 			sample_act->dr_tag_action =
11515 				dev_flow->dv.tag_resource->action;
11516 			sample_idx->rix_tag =
11517 				dev_flow->handle->dvh.rix_tag;
11518 			sample_actions[sample_act->actions_num++] =
11519 						sample_act->dr_tag_action;
11520 			/* Recover the mark resource after sample */
11521 			dev_flow->dv.tag_resource = pre_r;
11522 			dev_flow->handle->dvh.rix_tag = pre_rix;
11523 			action_flags |= MLX5_FLOW_ACTION_MARK;
11524 			break;
11525 		}
11526 		case RTE_FLOW_ACTION_TYPE_COUNT:
11527 		{
11528 			if (!flow->counter) {
11529 				flow->counter =
11530 					flow_dv_translate_create_counter(dev,
11531 						dev_flow, sub_actions->conf,
11532 						0);
11533 				if (!flow->counter)
11534 					return rte_flow_error_set
11535 						(error, rte_errno,
11536 						RTE_FLOW_ERROR_TYPE_ACTION,
11537 						NULL,
11538 						"cannot create counter"
11539 						" object.");
11540 			}
11541 			sample_act->dr_cnt_action =
11542 				  (flow_dv_counter_get_by_idx(dev,
11543 				  flow->counter, NULL))->action;
11544 			sample_actions[sample_act->actions_num++] =
11545 						sample_act->dr_cnt_action;
11546 			action_flags |= MLX5_FLOW_ACTION_COUNT;
11547 			break;
11548 		}
11549 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
11550 		{
11551 			struct mlx5_flow_dv_port_id_action_resource
11552 					port_id_resource;
11553 			uint32_t port_id = 0;
11554 
11555 			memset(&port_id_resource, 0, sizeof(port_id_resource));
11556 			/* Save the port id resource before sample */
11557 			pre_rix = dev_flow->handle->rix_port_id_action;
11558 			pre_r = dev_flow->dv.port_id_action;
11559 			if (flow_dv_translate_action_port_id(dev, sub_actions,
11560 							     &port_id, error))
11561 				return -rte_errno;
11562 			port_id_resource.port_id = port_id;
11563 			if (flow_dv_port_id_action_resource_register
11564 			    (dev, &port_id_resource, dev_flow, error))
11565 				return -rte_errno;
11566 			sample_act->dr_port_id_action =
11567 				dev_flow->dv.port_id_action->action;
11568 			sample_idx->rix_port_id_action =
11569 				dev_flow->handle->rix_port_id_action;
11570 			sample_actions[sample_act->actions_num++] =
11571 						sample_act->dr_port_id_action;
11572 			/* Recover the port id resource after sample */
11573 			dev_flow->dv.port_id_action = pre_r;
11574 			dev_flow->handle->rix_port_id_action = pre_rix;
11575 			(*num_of_dest)++;
11576 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
11577 			break;
11578 		}
11579 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
11580 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
11581 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
11582 			/* Save the encap resource before sample */
11583 			pre_rix = dev_flow->handle->dvh.rix_encap_decap;
11584 			pre_r = dev_flow->dv.encap_decap;
11585 			if (flow_dv_create_action_l2_encap(dev, sub_actions,
11586 							   dev_flow,
11587 							   attr->transfer,
11588 							   error))
11589 				return -rte_errno;
11590 			sample_act->dr_encap_action =
11591 				dev_flow->dv.encap_decap->action;
11592 			sample_idx->rix_encap_decap =
11593 				dev_flow->handle->dvh.rix_encap_decap;
11594 			sample_actions[sample_act->actions_num++] =
11595 						sample_act->dr_encap_action;
11596 			/* Recover the encap resource after sample */
11597 			dev_flow->dv.encap_decap = pre_r;
11598 			dev_flow->handle->dvh.rix_encap_decap = pre_rix;
11599 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
11600 			break;
11601 		default:
11602 			return rte_flow_error_set(error, EINVAL,
11603 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11604 				NULL,
11605 				"Not support for sampler action");
11606 		}
11607 	}
11608 	sample_act->action_flags = action_flags;
11609 	res->ft_id = dev_flow->dv.group;
11610 	if (attr->transfer) {
11611 		union {
11612 			uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)];
11613 			uint64_t set_action;
11614 		} action_ctx = { .set_action = 0 };
11615 
11616 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
11617 		MLX5_SET(set_action_in, action_ctx.action_in, action_type,
11618 			 MLX5_MODIFICATION_TYPE_SET);
11619 		MLX5_SET(set_action_in, action_ctx.action_in, field,
11620 			 MLX5_MODI_META_REG_C_0);
11621 		MLX5_SET(set_action_in, action_ctx.action_in, data,
11622 			 priv->vport_meta_tag);
11623 		res->set_action = action_ctx.set_action;
11624 	} else if (attr->ingress) {
11625 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
11626 	} else {
11627 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
11628 	}
11629 	return 0;
11630 }
11631 
11632 /**
11633  * Convert Sample action to DV specification.
11634  *
11635  * @param[in] dev
11636  *   Pointer to rte_eth_dev structure.
11637  * @param[in, out] dev_flow
11638  *   Pointer to the mlx5_flow.
11639  * @param[in] num_of_dest
11640  *   The num of destination.
11641  * @param[in, out] res
11642  *   Pointer to sample resource.
11643  * @param[in, out] mdest_res
11644  *   Pointer to destination array resource.
11645  * @param[in] sample_actions
11646  *   Pointer to sample path actions list.
11647  * @param[in] action_flags
11648  *   Holds the actions detected until now.
11649  * @param[out] error
11650  *   Pointer to the error structure.
11651  *
11652  * @return
11653  *   0 on success, a negative errno value otherwise and rte_errno is set.
11654  */
11655 static int
11656 flow_dv_create_action_sample(struct rte_eth_dev *dev,
11657 			     struct mlx5_flow *dev_flow,
11658 			     uint32_t num_of_dest,
11659 			     struct mlx5_flow_dv_sample_resource *res,
11660 			     struct mlx5_flow_dv_dest_array_resource *mdest_res,
11661 			     void **sample_actions,
11662 			     uint64_t action_flags,
11663 			     struct rte_flow_error *error)
11664 {
11665 	/* update normal path action resource into last index of array */
11666 	uint32_t dest_index = MLX5_MAX_DEST_NUM - 1;
11667 	struct mlx5_flow_sub_actions_list *sample_act =
11668 					&mdest_res->sample_act[dest_index];
11669 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
11670 	struct mlx5_flow_rss_desc *rss_desc;
11671 	uint32_t normal_idx = 0;
11672 	struct mlx5_hrxq *hrxq;
11673 	uint32_t hrxq_idx;
11674 
11675 	MLX5_ASSERT(wks);
11676 	rss_desc = &wks->rss_desc;
11677 	if (num_of_dest > 1) {
11678 		if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) {
11679 			/* Handle QP action for mirroring */
11680 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11681 						    rss_desc, &hrxq_idx);
11682 			if (!hrxq)
11683 				return rte_flow_error_set
11684 				     (error, rte_errno,
11685 				      RTE_FLOW_ERROR_TYPE_ACTION,
11686 				      NULL,
11687 				      "cannot create rx queue");
11688 			normal_idx++;
11689 			mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx;
11690 			sample_act->dr_queue_action = hrxq->action;
11691 			if (action_flags & MLX5_FLOW_ACTION_MARK)
11692 				dev_flow->handle->rix_hrxq = hrxq_idx;
11693 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
11694 		}
11695 		if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) {
11696 			normal_idx++;
11697 			mdest_res->sample_idx[dest_index].rix_encap_decap =
11698 				dev_flow->handle->dvh.rix_encap_decap;
11699 			sample_act->dr_encap_action =
11700 				dev_flow->dv.encap_decap->action;
11701 			dev_flow->handle->dvh.rix_encap_decap = 0;
11702 		}
11703 		if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) {
11704 			normal_idx++;
11705 			mdest_res->sample_idx[dest_index].rix_port_id_action =
11706 				dev_flow->handle->rix_port_id_action;
11707 			sample_act->dr_port_id_action =
11708 				dev_flow->dv.port_id_action->action;
11709 			dev_flow->handle->rix_port_id_action = 0;
11710 		}
11711 		if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) {
11712 			normal_idx++;
11713 			mdest_res->sample_idx[dest_index].rix_jump =
11714 				dev_flow->handle->rix_jump;
11715 			sample_act->dr_jump_action =
11716 				dev_flow->dv.jump->action;
11717 			dev_flow->handle->rix_jump = 0;
11718 		}
11719 		sample_act->actions_num = normal_idx;
11720 		/* update sample action resource into first index of array */
11721 		mdest_res->ft_type = res->ft_type;
11722 		memcpy(&mdest_res->sample_idx[0], &res->sample_idx,
11723 				sizeof(struct mlx5_flow_sub_actions_idx));
11724 		memcpy(&mdest_res->sample_act[0], &res->sample_act,
11725 				sizeof(struct mlx5_flow_sub_actions_list));
11726 		mdest_res->num_of_dest = num_of_dest;
11727 		if (flow_dv_dest_array_resource_register(dev, mdest_res,
11728 							 dev_flow, error))
11729 			return rte_flow_error_set(error, EINVAL,
11730 						  RTE_FLOW_ERROR_TYPE_ACTION,
11731 						  NULL, "can't create sample "
11732 						  "action");
11733 	} else {
11734 		res->sub_actions = sample_actions;
11735 		if (flow_dv_sample_resource_register(dev, res, dev_flow, error))
11736 			return rte_flow_error_set(error, EINVAL,
11737 						  RTE_FLOW_ERROR_TYPE_ACTION,
11738 						  NULL,
11739 						  "can't create sample action");
11740 	}
11741 	return 0;
11742 }
11743 
11744 /**
11745  * Remove an ASO age action from age actions list.
11746  *
11747  * @param[in] dev
11748  *   Pointer to the Ethernet device structure.
11749  * @param[in] age
11750  *   Pointer to the aso age action handler.
11751  */
11752 static void
11753 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev,
11754 				struct mlx5_aso_age_action *age)
11755 {
11756 	struct mlx5_age_info *age_info;
11757 	struct mlx5_age_param *age_param = &age->age_params;
11758 	struct mlx5_priv *priv = dev->data->dev_private;
11759 	uint16_t expected = AGE_CANDIDATE;
11760 
11761 	age_info = GET_PORT_AGE_INFO(priv);
11762 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
11763 					 AGE_FREE, false, __ATOMIC_RELAXED,
11764 					 __ATOMIC_RELAXED)) {
11765 		/**
11766 		 * We need the lock even it is age timeout,
11767 		 * since age action may still in process.
11768 		 */
11769 		rte_spinlock_lock(&age_info->aged_sl);
11770 		LIST_REMOVE(age, next);
11771 		rte_spinlock_unlock(&age_info->aged_sl);
11772 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
11773 	}
11774 }
11775 
11776 /**
11777  * Release an ASO age action.
11778  *
11779  * @param[in] dev
11780  *   Pointer to the Ethernet device structure.
11781  * @param[in] age_idx
11782  *   Index of ASO age action to release.
11783  * @param[in] flow
11784  *   True if the release operation is during flow destroy operation.
11785  *   False if the release operation is during action destroy operation.
11786  *
11787  * @return
11788  *   0 when age action was removed, otherwise the number of references.
11789  */
11790 static int
11791 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx)
11792 {
11793 	struct mlx5_priv *priv = dev->data->dev_private;
11794 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11795 	struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx);
11796 	uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED);
11797 
11798 	if (!ret) {
11799 		flow_dv_aso_age_remove_from_age(dev, age);
11800 		rte_spinlock_lock(&mng->free_sl);
11801 		LIST_INSERT_HEAD(&mng->free, age, next);
11802 		rte_spinlock_unlock(&mng->free_sl);
11803 	}
11804 	return ret;
11805 }
11806 
11807 /**
11808  * Resize the ASO age pools array by MLX5_CNT_CONTAINER_RESIZE pools.
11809  *
11810  * @param[in] dev
11811  *   Pointer to the Ethernet device structure.
11812  *
11813  * @return
11814  *   0 on success, otherwise negative errno value and rte_errno is set.
11815  */
11816 static int
11817 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev)
11818 {
11819 	struct mlx5_priv *priv = dev->data->dev_private;
11820 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11821 	void *old_pools = mng->pools;
11822 	uint32_t resize = mng->n + MLX5_CNT_CONTAINER_RESIZE;
11823 	uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize;
11824 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
11825 
11826 	if (!pools) {
11827 		rte_errno = ENOMEM;
11828 		return -ENOMEM;
11829 	}
11830 	if (old_pools) {
11831 		memcpy(pools, old_pools,
11832 		       mng->n * sizeof(struct mlx5_flow_counter_pool *));
11833 		mlx5_free(old_pools);
11834 	} else {
11835 		/* First ASO flow hit allocation - starting ASO data-path. */
11836 		int ret = mlx5_aso_flow_hit_queue_poll_start(priv->sh);
11837 
11838 		if (ret) {
11839 			mlx5_free(pools);
11840 			return ret;
11841 		}
11842 	}
11843 	mng->n = resize;
11844 	mng->pools = pools;
11845 	return 0;
11846 }
11847 
11848 /**
11849  * Create and initialize a new ASO aging pool.
11850  *
11851  * @param[in] dev
11852  *   Pointer to the Ethernet device structure.
11853  * @param[out] age_free
11854  *   Where to put the pointer of a new age action.
11855  *
11856  * @return
11857  *   The age actions pool pointer and @p age_free is set on success,
11858  *   NULL otherwise and rte_errno is set.
11859  */
11860 static struct mlx5_aso_age_pool *
11861 flow_dv_age_pool_create(struct rte_eth_dev *dev,
11862 			struct mlx5_aso_age_action **age_free)
11863 {
11864 	struct mlx5_priv *priv = dev->data->dev_private;
11865 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11866 	struct mlx5_aso_age_pool *pool = NULL;
11867 	struct mlx5_devx_obj *obj = NULL;
11868 	uint32_t i;
11869 
11870 	obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->ctx,
11871 						    priv->sh->pdn);
11872 	if (!obj) {
11873 		rte_errno = ENODATA;
11874 		DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX.");
11875 		return NULL;
11876 	}
11877 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
11878 	if (!pool) {
11879 		claim_zero(mlx5_devx_cmd_destroy(obj));
11880 		rte_errno = ENOMEM;
11881 		return NULL;
11882 	}
11883 	pool->flow_hit_aso_obj = obj;
11884 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
11885 	rte_spinlock_lock(&mng->resize_sl);
11886 	pool->index = mng->next;
11887 	/* Resize pools array if there is no room for the new pool in it. */
11888 	if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) {
11889 		claim_zero(mlx5_devx_cmd_destroy(obj));
11890 		mlx5_free(pool);
11891 		rte_spinlock_unlock(&mng->resize_sl);
11892 		return NULL;
11893 	}
11894 	mng->pools[pool->index] = pool;
11895 	mng->next++;
11896 	rte_spinlock_unlock(&mng->resize_sl);
11897 	/* Assign the first action in the new pool, the rest go to free list. */
11898 	*age_free = &pool->actions[0];
11899 	for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) {
11900 		pool->actions[i].offset = i;
11901 		LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next);
11902 	}
11903 	return pool;
11904 }
11905 
11906 /**
11907  * Allocate a ASO aging bit.
11908  *
11909  * @param[in] dev
11910  *   Pointer to the Ethernet device structure.
11911  * @param[out] error
11912  *   Pointer to the error structure.
11913  *
11914  * @return
11915  *   Index to ASO age action on success, 0 otherwise and rte_errno is set.
11916  */
11917 static uint32_t
11918 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
11919 {
11920 	struct mlx5_priv *priv = dev->data->dev_private;
11921 	const struct mlx5_aso_age_pool *pool;
11922 	struct mlx5_aso_age_action *age_free = NULL;
11923 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11924 
11925 	MLX5_ASSERT(mng);
11926 	/* Try to get the next free age action bit. */
11927 	rte_spinlock_lock(&mng->free_sl);
11928 	age_free = LIST_FIRST(&mng->free);
11929 	if (age_free) {
11930 		LIST_REMOVE(age_free, next);
11931 	} else if (!flow_dv_age_pool_create(dev, &age_free)) {
11932 		rte_spinlock_unlock(&mng->free_sl);
11933 		rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
11934 				   NULL, "failed to create ASO age pool");
11935 		return 0; /* 0 is an error. */
11936 	}
11937 	rte_spinlock_unlock(&mng->free_sl);
11938 	pool = container_of
11939 	  ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL])
11940 		  (age_free - age_free->offset), const struct mlx5_aso_age_pool,
11941 								       actions);
11942 	if (!age_free->dr_action) {
11943 		int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0,
11944 						 error);
11945 
11946 		if (reg_c < 0) {
11947 			rte_flow_error_set(error, rte_errno,
11948 					   RTE_FLOW_ERROR_TYPE_ACTION,
11949 					   NULL, "failed to get reg_c "
11950 					   "for ASO flow hit");
11951 			return 0; /* 0 is an error. */
11952 		}
11953 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
11954 		age_free->dr_action = mlx5_glue->dv_create_flow_action_aso
11955 				(priv->sh->rx_domain,
11956 				 pool->flow_hit_aso_obj->obj, age_free->offset,
11957 				 MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET,
11958 				 (reg_c - REG_C_0));
11959 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
11960 		if (!age_free->dr_action) {
11961 			rte_errno = errno;
11962 			rte_spinlock_lock(&mng->free_sl);
11963 			LIST_INSERT_HEAD(&mng->free, age_free, next);
11964 			rte_spinlock_unlock(&mng->free_sl);
11965 			rte_flow_error_set(error, rte_errno,
11966 					   RTE_FLOW_ERROR_TYPE_ACTION,
11967 					   NULL, "failed to create ASO "
11968 					   "flow hit action");
11969 			return 0; /* 0 is an error. */
11970 		}
11971 	}
11972 	__atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED);
11973 	return pool->index | ((age_free->offset + 1) << 16);
11974 }
11975 
11976 /**
11977  * Initialize flow ASO age parameters.
11978  *
11979  * @param[in] dev
11980  *   Pointer to rte_eth_dev structure.
11981  * @param[in] age_idx
11982  *   Index of ASO age action.
11983  * @param[in] context
11984  *   Pointer to flow counter age context.
11985  * @param[in] timeout
11986  *   Aging timeout in seconds.
11987  *
11988  */
11989 static void
11990 flow_dv_aso_age_params_init(struct rte_eth_dev *dev,
11991 			    uint32_t age_idx,
11992 			    void *context,
11993 			    uint32_t timeout)
11994 {
11995 	struct mlx5_aso_age_action *aso_age;
11996 
11997 	aso_age = flow_aso_age_get_by_idx(dev, age_idx);
11998 	MLX5_ASSERT(aso_age);
11999 	aso_age->age_params.context = context;
12000 	aso_age->age_params.timeout = timeout;
12001 	aso_age->age_params.port_id = dev->data->port_id;
12002 	__atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0,
12003 			 __ATOMIC_RELAXED);
12004 	__atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE,
12005 			 __ATOMIC_RELAXED);
12006 }
12007 
12008 static void
12009 flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask,
12010 			       const struct rte_flow_item_integrity *value,
12011 			       void *headers_m, void *headers_v)
12012 {
12013 	if (mask->l4_ok) {
12014 		/* application l4_ok filter aggregates all hardware l4 filters
12015 		 * therefore hw l4_checksum_ok must be implicitly added here.
12016 		 */
12017 		struct rte_flow_item_integrity local_item;
12018 
12019 		local_item.l4_csum_ok = 1;
12020 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok,
12021 			 local_item.l4_csum_ok);
12022 		if (value->l4_ok) {
12023 			/* application l4_ok = 1 matches sets both hw flags
12024 			 * l4_ok and l4_checksum_ok flags to 1.
12025 			 */
12026 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12027 				 l4_checksum_ok, local_item.l4_csum_ok);
12028 			MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_ok,
12029 				 mask->l4_ok);
12030 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_ok,
12031 				 value->l4_ok);
12032 		} else {
12033 			/* application l4_ok = 0 matches on hw flag
12034 			 * l4_checksum_ok = 0 only.
12035 			 */
12036 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12037 				 l4_checksum_ok, 0);
12038 		}
12039 	} else if (mask->l4_csum_ok) {
12040 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok,
12041 			 mask->l4_csum_ok);
12042 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok,
12043 			 value->l4_csum_ok);
12044 	}
12045 }
12046 
12047 static void
12048 flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask,
12049 			       const struct rte_flow_item_integrity *value,
12050 			       void *headers_m, void *headers_v,
12051 			       bool is_ipv4)
12052 {
12053 	if (mask->l3_ok) {
12054 		/* application l3_ok filter aggregates all hardware l3 filters
12055 		 * therefore hw ipv4_checksum_ok must be implicitly added here.
12056 		 */
12057 		struct rte_flow_item_integrity local_item;
12058 
12059 		local_item.ipv4_csum_ok = !!is_ipv4;
12060 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok,
12061 			 local_item.ipv4_csum_ok);
12062 		if (value->l3_ok) {
12063 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12064 				 ipv4_checksum_ok, local_item.ipv4_csum_ok);
12065 			MLX5_SET(fte_match_set_lyr_2_4, headers_m, l3_ok,
12066 				 mask->l3_ok);
12067 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, l3_ok,
12068 				 value->l3_ok);
12069 		} else {
12070 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12071 				 ipv4_checksum_ok, 0);
12072 		}
12073 	} else if (mask->ipv4_csum_ok) {
12074 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok,
12075 			 mask->ipv4_csum_ok);
12076 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_checksum_ok,
12077 			 value->ipv4_csum_ok);
12078 	}
12079 }
12080 
12081 static void
12082 flow_dv_translate_item_integrity(void *matcher, void *key,
12083 				 const struct rte_flow_item *head_item,
12084 				 const struct rte_flow_item *integrity_item)
12085 {
12086 	const struct rte_flow_item_integrity *mask = integrity_item->mask;
12087 	const struct rte_flow_item_integrity *value = integrity_item->spec;
12088 	const struct rte_flow_item *tunnel_item, *end_item, *item;
12089 	void *headers_m;
12090 	void *headers_v;
12091 	uint32_t l3_protocol;
12092 
12093 	if (!value)
12094 		return;
12095 	if (!mask)
12096 		mask = &rte_flow_item_integrity_mask;
12097 	if (value->level > 1) {
12098 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
12099 					 inner_headers);
12100 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
12101 	} else {
12102 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
12103 					 outer_headers);
12104 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
12105 	}
12106 	tunnel_item = mlx5_flow_find_tunnel_item(head_item);
12107 	if (value->level > 1) {
12108 		/* tunnel item was verified during the item validation */
12109 		item = tunnel_item;
12110 		end_item = mlx5_find_end_item(tunnel_item);
12111 	} else {
12112 		item = head_item;
12113 		end_item = tunnel_item ? tunnel_item :
12114 			   mlx5_find_end_item(integrity_item);
12115 	}
12116 	l3_protocol = mask->l3_ok ?
12117 		      mlx5_flow_locate_proto_l3(&item, end_item) : 0;
12118 	flow_dv_translate_integrity_l3(mask, value, headers_m, headers_v,
12119 				       l3_protocol == RTE_ETHER_TYPE_IPV4);
12120 	flow_dv_translate_integrity_l4(mask, value, headers_m, headers_v);
12121 }
12122 
12123 /**
12124  * Prepares DV flow counter with aging configuration.
12125  * Gets it by index when exists, creates a new one when doesn't.
12126  *
12127  * @param[in] dev
12128  *   Pointer to rte_eth_dev structure.
12129  * @param[in] dev_flow
12130  *   Pointer to the mlx5_flow.
12131  * @param[in, out] flow
12132  *   Pointer to the sub flow.
12133  * @param[in] count
12134  *   Pointer to the counter action configuration.
12135  * @param[in] age
12136  *   Pointer to the aging action configuration.
12137  * @param[out] error
12138  *   Pointer to the error structure.
12139  *
12140  * @return
12141  *   Pointer to the counter, NULL otherwise.
12142  */
12143 static struct mlx5_flow_counter *
12144 flow_dv_prepare_counter(struct rte_eth_dev *dev,
12145 			struct mlx5_flow *dev_flow,
12146 			struct rte_flow *flow,
12147 			const struct rte_flow_action_count *count,
12148 			const struct rte_flow_action_age *age,
12149 			struct rte_flow_error *error)
12150 {
12151 	if (!flow->counter) {
12152 		flow->counter = flow_dv_translate_create_counter(dev, dev_flow,
12153 								 count, age);
12154 		if (!flow->counter) {
12155 			rte_flow_error_set(error, rte_errno,
12156 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12157 					   "cannot create counter object.");
12158 			return NULL;
12159 		}
12160 	}
12161 	return flow_dv_counter_get_by_idx(dev, flow->counter, NULL);
12162 }
12163 
12164 /*
12165  * Release an ASO CT action by its own device.
12166  *
12167  * @param[in] dev
12168  *   Pointer to the Ethernet device structure.
12169  * @param[in] idx
12170  *   Index of ASO CT action to release.
12171  *
12172  * @return
12173  *   0 when CT action was removed, otherwise the number of references.
12174  */
12175 static inline int
12176 flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx)
12177 {
12178 	struct mlx5_priv *priv = dev->data->dev_private;
12179 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12180 	uint32_t ret;
12181 	struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx);
12182 	enum mlx5_aso_ct_state state =
12183 			__atomic_load_n(&ct->state, __ATOMIC_RELAXED);
12184 
12185 	/* Cannot release when CT is in the ASO SQ. */
12186 	if (state == ASO_CONNTRACK_WAIT || state == ASO_CONNTRACK_QUERY)
12187 		return -1;
12188 	ret = __atomic_sub_fetch(&ct->refcnt, 1, __ATOMIC_RELAXED);
12189 	if (!ret) {
12190 		if (ct->dr_action_orig) {
12191 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12192 			claim_zero(mlx5_glue->destroy_flow_action
12193 					(ct->dr_action_orig));
12194 #endif
12195 			ct->dr_action_orig = NULL;
12196 		}
12197 		if (ct->dr_action_rply) {
12198 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12199 			claim_zero(mlx5_glue->destroy_flow_action
12200 					(ct->dr_action_rply));
12201 #endif
12202 			ct->dr_action_rply = NULL;
12203 		}
12204 		/* Clear the state to free, no need in 1st allocation. */
12205 		MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_FREE);
12206 		rte_spinlock_lock(&mng->ct_sl);
12207 		LIST_INSERT_HEAD(&mng->free_cts, ct, next);
12208 		rte_spinlock_unlock(&mng->ct_sl);
12209 	}
12210 	return (int)ret;
12211 }
12212 
12213 static inline int
12214 flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx,
12215 		       struct rte_flow_error *error)
12216 {
12217 	uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx);
12218 	uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx);
12219 	struct rte_eth_dev *owndev = &rte_eth_devices[owner];
12220 	int ret;
12221 
12222 	MLX5_ASSERT(owner < RTE_MAX_ETHPORTS);
12223 	if (dev->data->dev_started != 1)
12224 		return rte_flow_error_set(error, EAGAIN,
12225 					  RTE_FLOW_ERROR_TYPE_ACTION,
12226 					  NULL,
12227 					  "Indirect CT action cannot be destroyed when the port is stopped");
12228 	ret = flow_dv_aso_ct_dev_release(owndev, idx);
12229 	if (ret < 0)
12230 		return rte_flow_error_set(error, EAGAIN,
12231 					  RTE_FLOW_ERROR_TYPE_ACTION,
12232 					  NULL,
12233 					  "Current state prevents indirect CT action from being destroyed");
12234 	return ret;
12235 }
12236 
12237 /*
12238  * Resize the ASO CT pools array by 64 pools.
12239  *
12240  * @param[in] dev
12241  *   Pointer to the Ethernet device structure.
12242  *
12243  * @return
12244  *   0 on success, otherwise negative errno value and rte_errno is set.
12245  */
12246 static int
12247 flow_dv_aso_ct_pools_resize(struct rte_eth_dev *dev)
12248 {
12249 	struct mlx5_priv *priv = dev->data->dev_private;
12250 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12251 	void *old_pools = mng->pools;
12252 	/* Magic number now, need a macro. */
12253 	uint32_t resize = mng->n + 64;
12254 	uint32_t mem_size = sizeof(struct mlx5_aso_ct_pool *) * resize;
12255 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
12256 
12257 	if (!pools) {
12258 		rte_errno = ENOMEM;
12259 		return -rte_errno;
12260 	}
12261 	rte_rwlock_write_lock(&mng->resize_rwl);
12262 	/* ASO SQ/QP was already initialized in the startup. */
12263 	if (old_pools) {
12264 		/* Realloc could be an alternative choice. */
12265 		rte_memcpy(pools, old_pools,
12266 			   mng->n * sizeof(struct mlx5_aso_ct_pool *));
12267 		mlx5_free(old_pools);
12268 	}
12269 	mng->n = resize;
12270 	mng->pools = pools;
12271 	rte_rwlock_write_unlock(&mng->resize_rwl);
12272 	return 0;
12273 }
12274 
12275 /*
12276  * Create and initialize a new ASO CT pool.
12277  *
12278  * @param[in] dev
12279  *   Pointer to the Ethernet device structure.
12280  * @param[out] ct_free
12281  *   Where to put the pointer of a new CT action.
12282  *
12283  * @return
12284  *   The CT actions pool pointer and @p ct_free is set on success,
12285  *   NULL otherwise and rte_errno is set.
12286  */
12287 static struct mlx5_aso_ct_pool *
12288 flow_dv_ct_pool_create(struct rte_eth_dev *dev,
12289 		       struct mlx5_aso_ct_action **ct_free)
12290 {
12291 	struct mlx5_priv *priv = dev->data->dev_private;
12292 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12293 	struct mlx5_aso_ct_pool *pool = NULL;
12294 	struct mlx5_devx_obj *obj = NULL;
12295 	uint32_t i;
12296 	uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL);
12297 
12298 	obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->ctx,
12299 						priv->sh->pdn, log_obj_size);
12300 	if (!obj) {
12301 		rte_errno = ENODATA;
12302 		DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX.");
12303 		return NULL;
12304 	}
12305 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
12306 	if (!pool) {
12307 		rte_errno = ENOMEM;
12308 		claim_zero(mlx5_devx_cmd_destroy(obj));
12309 		return NULL;
12310 	}
12311 	pool->devx_obj = obj;
12312 	pool->index = mng->next;
12313 	/* Resize pools array if there is no room for the new pool in it. */
12314 	if (pool->index == mng->n && flow_dv_aso_ct_pools_resize(dev)) {
12315 		claim_zero(mlx5_devx_cmd_destroy(obj));
12316 		mlx5_free(pool);
12317 		return NULL;
12318 	}
12319 	mng->pools[pool->index] = pool;
12320 	mng->next++;
12321 	/* Assign the first action in the new pool, the rest go to free list. */
12322 	*ct_free = &pool->actions[0];
12323 	/* Lock outside, the list operation is safe here. */
12324 	for (i = 1; i < MLX5_ASO_CT_ACTIONS_PER_POOL; i++) {
12325 		/* refcnt is 0 when allocating the memory. */
12326 		pool->actions[i].offset = i;
12327 		LIST_INSERT_HEAD(&mng->free_cts, &pool->actions[i], next);
12328 	}
12329 	return pool;
12330 }
12331 
12332 /*
12333  * Allocate a ASO CT action from free list.
12334  *
12335  * @param[in] dev
12336  *   Pointer to the Ethernet device structure.
12337  * @param[out] error
12338  *   Pointer to the error structure.
12339  *
12340  * @return
12341  *   Index to ASO CT action on success, 0 otherwise and rte_errno is set.
12342  */
12343 static uint32_t
12344 flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
12345 {
12346 	struct mlx5_priv *priv = dev->data->dev_private;
12347 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12348 	struct mlx5_aso_ct_action *ct = NULL;
12349 	struct mlx5_aso_ct_pool *pool;
12350 	uint8_t reg_c;
12351 	uint32_t ct_idx;
12352 
12353 	MLX5_ASSERT(mng);
12354 	if (!priv->config.devx) {
12355 		rte_errno = ENOTSUP;
12356 		return 0;
12357 	}
12358 	/* Get a free CT action, if no, a new pool will be created. */
12359 	rte_spinlock_lock(&mng->ct_sl);
12360 	ct = LIST_FIRST(&mng->free_cts);
12361 	if (ct) {
12362 		LIST_REMOVE(ct, next);
12363 	} else if (!flow_dv_ct_pool_create(dev, &ct)) {
12364 		rte_spinlock_unlock(&mng->ct_sl);
12365 		rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
12366 				   NULL, "failed to create ASO CT pool");
12367 		return 0;
12368 	}
12369 	rte_spinlock_unlock(&mng->ct_sl);
12370 	pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]);
12371 	ct_idx = MLX5_MAKE_CT_IDX(pool->index, ct->offset);
12372 	/* 0: inactive, 1: created, 2+: used by flows. */
12373 	__atomic_store_n(&ct->refcnt, 1, __ATOMIC_RELAXED);
12374 	reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, error);
12375 	if (!ct->dr_action_orig) {
12376 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12377 		ct->dr_action_orig = mlx5_glue->dv_create_flow_action_aso
12378 			(priv->sh->rx_domain, pool->devx_obj->obj,
12379 			 ct->offset,
12380 			 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_INITIATOR,
12381 			 reg_c - REG_C_0);
12382 #else
12383 		RTE_SET_USED(reg_c);
12384 #endif
12385 		if (!ct->dr_action_orig) {
12386 			flow_dv_aso_ct_dev_release(dev, ct_idx);
12387 			rte_flow_error_set(error, rte_errno,
12388 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12389 					   "failed to create ASO CT action");
12390 			return 0;
12391 		}
12392 	}
12393 	if (!ct->dr_action_rply) {
12394 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12395 		ct->dr_action_rply = mlx5_glue->dv_create_flow_action_aso
12396 			(priv->sh->rx_domain, pool->devx_obj->obj,
12397 			 ct->offset,
12398 			 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_RESPONDER,
12399 			 reg_c - REG_C_0);
12400 #endif
12401 		if (!ct->dr_action_rply) {
12402 			flow_dv_aso_ct_dev_release(dev, ct_idx);
12403 			rte_flow_error_set(error, rte_errno,
12404 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12405 					   "failed to create ASO CT action");
12406 			return 0;
12407 		}
12408 	}
12409 	return ct_idx;
12410 }
12411 
12412 /*
12413  * Create a conntrack object with context and actions by using ASO mechanism.
12414  *
12415  * @param[in] dev
12416  *   Pointer to rte_eth_dev structure.
12417  * @param[in] pro
12418  *   Pointer to conntrack information profile.
12419  * @param[out] error
12420  *   Pointer to the error structure.
12421  *
12422  * @return
12423  *   Index to conntrack object on success, 0 otherwise.
12424  */
12425 static uint32_t
12426 flow_dv_translate_create_conntrack(struct rte_eth_dev *dev,
12427 				   const struct rte_flow_action_conntrack *pro,
12428 				   struct rte_flow_error *error)
12429 {
12430 	struct mlx5_priv *priv = dev->data->dev_private;
12431 	struct mlx5_dev_ctx_shared *sh = priv->sh;
12432 	struct mlx5_aso_ct_action *ct;
12433 	uint32_t idx;
12434 
12435 	if (!sh->ct_aso_en)
12436 		return rte_flow_error_set(error, ENOTSUP,
12437 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12438 					  "Connection is not supported");
12439 	idx = flow_dv_aso_ct_alloc(dev, error);
12440 	if (!idx)
12441 		return rte_flow_error_set(error, rte_errno,
12442 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12443 					  "Failed to allocate CT object");
12444 	ct = flow_aso_ct_get_by_dev_idx(dev, idx);
12445 	if (mlx5_aso_ct_update_by_wqe(sh, ct, pro))
12446 		return rte_flow_error_set(error, EBUSY,
12447 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12448 					  "Failed to update CT");
12449 	ct->is_original = !!pro->is_original_dir;
12450 	ct->peer = pro->peer_port;
12451 	return idx;
12452 }
12453 
12454 /**
12455  * Fill the flow with DV spec, lock free
12456  * (mutex should be acquired by caller).
12457  *
12458  * @param[in] dev
12459  *   Pointer to rte_eth_dev structure.
12460  * @param[in, out] dev_flow
12461  *   Pointer to the sub flow.
12462  * @param[in] attr
12463  *   Pointer to the flow attributes.
12464  * @param[in] items
12465  *   Pointer to the list of items.
12466  * @param[in] actions
12467  *   Pointer to the list of actions.
12468  * @param[out] error
12469  *   Pointer to the error structure.
12470  *
12471  * @return
12472  *   0 on success, a negative errno value otherwise and rte_errno is set.
12473  */
12474 static int
12475 flow_dv_translate(struct rte_eth_dev *dev,
12476 		  struct mlx5_flow *dev_flow,
12477 		  const struct rte_flow_attr *attr,
12478 		  const struct rte_flow_item items[],
12479 		  const struct rte_flow_action actions[],
12480 		  struct rte_flow_error *error)
12481 {
12482 	struct mlx5_priv *priv = dev->data->dev_private;
12483 	struct mlx5_dev_config *dev_conf = &priv->config;
12484 	struct rte_flow *flow = dev_flow->flow;
12485 	struct mlx5_flow_handle *handle = dev_flow->handle;
12486 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
12487 	struct mlx5_flow_rss_desc *rss_desc;
12488 	uint64_t item_flags = 0;
12489 	uint64_t last_item = 0;
12490 	uint64_t action_flags = 0;
12491 	struct mlx5_flow_dv_matcher matcher = {
12492 		.mask = {
12493 			.size = sizeof(matcher.mask.buf),
12494 		},
12495 	};
12496 	int actions_n = 0;
12497 	bool actions_end = false;
12498 	union {
12499 		struct mlx5_flow_dv_modify_hdr_resource res;
12500 		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
12501 			    sizeof(struct mlx5_modification_cmd) *
12502 			    (MLX5_MAX_MODIFY_NUM + 1)];
12503 	} mhdr_dummy;
12504 	struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
12505 	const struct rte_flow_action_count *count = NULL;
12506 	const struct rte_flow_action_age *non_shared_age = NULL;
12507 	union flow_dv_attr flow_attr = { .attr = 0 };
12508 	uint32_t tag_be;
12509 	union mlx5_flow_tbl_key tbl_key;
12510 	uint32_t modify_action_position = UINT32_MAX;
12511 	void *match_mask = matcher.mask.buf;
12512 	void *match_value = dev_flow->dv.value.buf;
12513 	uint8_t next_protocol = 0xff;
12514 	struct rte_vlan_hdr vlan = { 0 };
12515 	struct mlx5_flow_dv_dest_array_resource mdest_res;
12516 	struct mlx5_flow_dv_sample_resource sample_res;
12517 	void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
12518 	const struct rte_flow_action_sample *sample = NULL;
12519 	struct mlx5_flow_sub_actions_list *sample_act;
12520 	uint32_t sample_act_pos = UINT32_MAX;
12521 	uint32_t age_act_pos = UINT32_MAX;
12522 	uint32_t num_of_dest = 0;
12523 	int tmp_actions_n = 0;
12524 	uint32_t table;
12525 	int ret = 0;
12526 	const struct mlx5_flow_tunnel *tunnel = NULL;
12527 	struct flow_grp_info grp_info = {
12528 		.external = !!dev_flow->external,
12529 		.transfer = !!attr->transfer,
12530 		.fdb_def_rule = !!priv->fdb_def_rule,
12531 		.skip_scale = dev_flow->skip_scale &
12532 			(1 << MLX5_SCALE_FLOW_GROUP_BIT),
12533 		.std_tbl_fix = true,
12534 	};
12535 	const struct rte_flow_item *head_item = items;
12536 
12537 	if (!wks)
12538 		return rte_flow_error_set(error, ENOMEM,
12539 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12540 					  NULL,
12541 					  "failed to push flow workspace");
12542 	rss_desc = &wks->rss_desc;
12543 	memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource));
12544 	memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource));
12545 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
12546 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
12547 	/* update normal path action resource into last index of array */
12548 	sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1];
12549 	if (is_tunnel_offload_active(dev)) {
12550 		if (dev_flow->tunnel) {
12551 			RTE_VERIFY(dev_flow->tof_type ==
12552 				   MLX5_TUNNEL_OFFLOAD_MISS_RULE);
12553 			tunnel = dev_flow->tunnel;
12554 		} else {
12555 			tunnel = mlx5_get_tof(items, actions,
12556 					      &dev_flow->tof_type);
12557 			dev_flow->tunnel = tunnel;
12558 		}
12559 		grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
12560 					(dev, attr, tunnel, dev_flow->tof_type);
12561 	}
12562 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
12563 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
12564 	ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table,
12565 				       &grp_info, error);
12566 	if (ret)
12567 		return ret;
12568 	dev_flow->dv.group = table;
12569 	if (attr->transfer)
12570 		mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
12571 	/* number of actions must be set to 0 in case of dirty stack. */
12572 	mhdr_res->actions_num = 0;
12573 	if (is_flow_tunnel_match_rule(dev_flow->tof_type)) {
12574 		/*
12575 		 * do not add decap action if match rule drops packet
12576 		 * HW rejects rules with decap & drop
12577 		 *
12578 		 * if tunnel match rule was inserted before matching tunnel set
12579 		 * rule flow table used in the match rule must be registered.
12580 		 * current implementation handles that in the
12581 		 * flow_dv_match_register() at the function end.
12582 		 */
12583 		bool add_decap = true;
12584 		const struct rte_flow_action *ptr = actions;
12585 
12586 		for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) {
12587 			if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) {
12588 				add_decap = false;
12589 				break;
12590 			}
12591 		}
12592 		if (add_decap) {
12593 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
12594 							   attr->transfer,
12595 							   error))
12596 				return -rte_errno;
12597 			dev_flow->dv.actions[actions_n++] =
12598 					dev_flow->dv.encap_decap->action;
12599 			action_flags |= MLX5_FLOW_ACTION_DECAP;
12600 		}
12601 	}
12602 	for (; !actions_end ; actions++) {
12603 		const struct rte_flow_action_queue *queue;
12604 		const struct rte_flow_action_rss *rss;
12605 		const struct rte_flow_action *action = actions;
12606 		const uint8_t *rss_key;
12607 		struct mlx5_flow_tbl_resource *tbl;
12608 		struct mlx5_aso_age_action *age_act;
12609 		struct mlx5_flow_counter *cnt_act;
12610 		uint32_t port_id = 0;
12611 		struct mlx5_flow_dv_port_id_action_resource port_id_resource;
12612 		int action_type = actions->type;
12613 		const struct rte_flow_action *found_action = NULL;
12614 		uint32_t jump_group = 0;
12615 		uint32_t owner_idx;
12616 		struct mlx5_aso_ct_action *ct;
12617 
12618 		if (!mlx5_flow_os_action_supported(action_type))
12619 			return rte_flow_error_set(error, ENOTSUP,
12620 						  RTE_FLOW_ERROR_TYPE_ACTION,
12621 						  actions,
12622 						  "action not supported");
12623 		switch (action_type) {
12624 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
12625 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
12626 			break;
12627 		case RTE_FLOW_ACTION_TYPE_VOID:
12628 			break;
12629 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
12630 			if (flow_dv_translate_action_port_id(dev, action,
12631 							     &port_id, error))
12632 				return -rte_errno;
12633 			port_id_resource.port_id = port_id;
12634 			MLX5_ASSERT(!handle->rix_port_id_action);
12635 			if (flow_dv_port_id_action_resource_register
12636 			    (dev, &port_id_resource, dev_flow, error))
12637 				return -rte_errno;
12638 			dev_flow->dv.actions[actions_n++] =
12639 					dev_flow->dv.port_id_action->action;
12640 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
12641 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID;
12642 			sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID;
12643 			num_of_dest++;
12644 			break;
12645 		case RTE_FLOW_ACTION_TYPE_FLAG:
12646 			action_flags |= MLX5_FLOW_ACTION_FLAG;
12647 			dev_flow->handle->mark = 1;
12648 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
12649 				struct rte_flow_action_mark mark = {
12650 					.id = MLX5_FLOW_MARK_DEFAULT,
12651 				};
12652 
12653 				if (flow_dv_convert_action_mark(dev, &mark,
12654 								mhdr_res,
12655 								error))
12656 					return -rte_errno;
12657 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
12658 				break;
12659 			}
12660 			tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
12661 			/*
12662 			 * Only one FLAG or MARK is supported per device flow
12663 			 * right now. So the pointer to the tag resource must be
12664 			 * zero before the register process.
12665 			 */
12666 			MLX5_ASSERT(!handle->dvh.rix_tag);
12667 			if (flow_dv_tag_resource_register(dev, tag_be,
12668 							  dev_flow, error))
12669 				return -rte_errno;
12670 			MLX5_ASSERT(dev_flow->dv.tag_resource);
12671 			dev_flow->dv.actions[actions_n++] =
12672 					dev_flow->dv.tag_resource->action;
12673 			break;
12674 		case RTE_FLOW_ACTION_TYPE_MARK:
12675 			action_flags |= MLX5_FLOW_ACTION_MARK;
12676 			dev_flow->handle->mark = 1;
12677 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
12678 				const struct rte_flow_action_mark *mark =
12679 					(const struct rte_flow_action_mark *)
12680 						actions->conf;
12681 
12682 				if (flow_dv_convert_action_mark(dev, mark,
12683 								mhdr_res,
12684 								error))
12685 					return -rte_errno;
12686 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
12687 				break;
12688 			}
12689 			/* Fall-through */
12690 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
12691 			/* Legacy (non-extensive) MARK action. */
12692 			tag_be = mlx5_flow_mark_set
12693 			      (((const struct rte_flow_action_mark *)
12694 			       (actions->conf))->id);
12695 			MLX5_ASSERT(!handle->dvh.rix_tag);
12696 			if (flow_dv_tag_resource_register(dev, tag_be,
12697 							  dev_flow, error))
12698 				return -rte_errno;
12699 			MLX5_ASSERT(dev_flow->dv.tag_resource);
12700 			dev_flow->dv.actions[actions_n++] =
12701 					dev_flow->dv.tag_resource->action;
12702 			break;
12703 		case RTE_FLOW_ACTION_TYPE_SET_META:
12704 			if (flow_dv_convert_action_set_meta
12705 				(dev, mhdr_res, attr,
12706 				 (const struct rte_flow_action_set_meta *)
12707 				  actions->conf, error))
12708 				return -rte_errno;
12709 			action_flags |= MLX5_FLOW_ACTION_SET_META;
12710 			break;
12711 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
12712 			if (flow_dv_convert_action_set_tag
12713 				(dev, mhdr_res,
12714 				 (const struct rte_flow_action_set_tag *)
12715 				  actions->conf, error))
12716 				return -rte_errno;
12717 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
12718 			break;
12719 		case RTE_FLOW_ACTION_TYPE_DROP:
12720 			action_flags |= MLX5_FLOW_ACTION_DROP;
12721 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
12722 			break;
12723 		case RTE_FLOW_ACTION_TYPE_QUEUE:
12724 			queue = actions->conf;
12725 			rss_desc->queue_num = 1;
12726 			rss_desc->queue[0] = queue->index;
12727 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
12728 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
12729 			sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE;
12730 			num_of_dest++;
12731 			break;
12732 		case RTE_FLOW_ACTION_TYPE_RSS:
12733 			rss = actions->conf;
12734 			memcpy(rss_desc->queue, rss->queue,
12735 			       rss->queue_num * sizeof(uint16_t));
12736 			rss_desc->queue_num = rss->queue_num;
12737 			/* NULL RSS key indicates default RSS key. */
12738 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
12739 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
12740 			/*
12741 			 * rss->level and rss.types should be set in advance
12742 			 * when expanding items for RSS.
12743 			 */
12744 			action_flags |= MLX5_FLOW_ACTION_RSS;
12745 			dev_flow->handle->fate_action = rss_desc->shared_rss ?
12746 				MLX5_FLOW_FATE_SHARED_RSS :
12747 				MLX5_FLOW_FATE_QUEUE;
12748 			break;
12749 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
12750 			owner_idx = (uint32_t)(uintptr_t)action->conf;
12751 			age_act = flow_aso_age_get_by_idx(dev, owner_idx);
12752 			if (flow->age == 0) {
12753 				flow->age = owner_idx;
12754 				__atomic_fetch_add(&age_act->refcnt, 1,
12755 						   __ATOMIC_RELAXED);
12756 			}
12757 			age_act_pos = actions_n++;
12758 			action_flags |= MLX5_FLOW_ACTION_AGE;
12759 			break;
12760 		case RTE_FLOW_ACTION_TYPE_AGE:
12761 			non_shared_age = action->conf;
12762 			age_act_pos = actions_n++;
12763 			action_flags |= MLX5_FLOW_ACTION_AGE;
12764 			break;
12765 		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
12766 			owner_idx = (uint32_t)(uintptr_t)action->conf;
12767 			cnt_act = flow_dv_counter_get_by_idx(dev, owner_idx,
12768 							     NULL);
12769 			MLX5_ASSERT(cnt_act != NULL);
12770 			/**
12771 			 * When creating meter drop flow in drop table, the
12772 			 * counter should not overwrite the rte flow counter.
12773 			 */
12774 			if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
12775 			    dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) {
12776 				dev_flow->dv.actions[actions_n++] =
12777 							cnt_act->action;
12778 			} else {
12779 				if (flow->counter == 0) {
12780 					flow->counter = owner_idx;
12781 					__atomic_fetch_add
12782 						(&cnt_act->shared_info.refcnt,
12783 						 1, __ATOMIC_RELAXED);
12784 				}
12785 				/* Save information first, will apply later. */
12786 				action_flags |= MLX5_FLOW_ACTION_COUNT;
12787 			}
12788 			break;
12789 		case RTE_FLOW_ACTION_TYPE_COUNT:
12790 			if (!dev_conf->devx) {
12791 				return rte_flow_error_set
12792 					      (error, ENOTSUP,
12793 					       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12794 					       NULL,
12795 					       "count action not supported");
12796 			}
12797 			/* Save information first, will apply later. */
12798 			count = action->conf;
12799 			action_flags |= MLX5_FLOW_ACTION_COUNT;
12800 			break;
12801 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
12802 			dev_flow->dv.actions[actions_n++] =
12803 						priv->sh->pop_vlan_action;
12804 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
12805 			break;
12806 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
12807 			if (!(action_flags &
12808 			      MLX5_FLOW_ACTION_OF_SET_VLAN_VID))
12809 				flow_dev_get_vlan_info_from_items(items, &vlan);
12810 			vlan.eth_proto = rte_be_to_cpu_16
12811 			     ((((const struct rte_flow_action_of_push_vlan *)
12812 						   actions->conf)->ethertype));
12813 			found_action = mlx5_flow_find_action
12814 					(actions + 1,
12815 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID);
12816 			if (found_action)
12817 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
12818 			found_action = mlx5_flow_find_action
12819 					(actions + 1,
12820 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP);
12821 			if (found_action)
12822 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
12823 			if (flow_dv_create_action_push_vlan
12824 					    (dev, attr, &vlan, dev_flow, error))
12825 				return -rte_errno;
12826 			dev_flow->dv.actions[actions_n++] =
12827 					dev_flow->dv.push_vlan_res->action;
12828 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
12829 			break;
12830 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
12831 			/* of_vlan_push action handled this action */
12832 			MLX5_ASSERT(action_flags &
12833 				    MLX5_FLOW_ACTION_OF_PUSH_VLAN);
12834 			break;
12835 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
12836 			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
12837 				break;
12838 			flow_dev_get_vlan_info_from_items(items, &vlan);
12839 			mlx5_update_vlan_vid_pcp(actions, &vlan);
12840 			/* If no VLAN push - this is a modify header action */
12841 			if (flow_dv_convert_action_modify_vlan_vid
12842 						(mhdr_res, actions, error))
12843 				return -rte_errno;
12844 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
12845 			break;
12846 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
12847 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
12848 			if (flow_dv_create_action_l2_encap(dev, actions,
12849 							   dev_flow,
12850 							   attr->transfer,
12851 							   error))
12852 				return -rte_errno;
12853 			dev_flow->dv.actions[actions_n++] =
12854 					dev_flow->dv.encap_decap->action;
12855 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
12856 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
12857 				sample_act->action_flags |=
12858 							MLX5_FLOW_ACTION_ENCAP;
12859 			break;
12860 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
12861 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
12862 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
12863 							   attr->transfer,
12864 							   error))
12865 				return -rte_errno;
12866 			dev_flow->dv.actions[actions_n++] =
12867 					dev_flow->dv.encap_decap->action;
12868 			action_flags |= MLX5_FLOW_ACTION_DECAP;
12869 			break;
12870 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
12871 			/* Handle encap with preceding decap. */
12872 			if (action_flags & MLX5_FLOW_ACTION_DECAP) {
12873 				if (flow_dv_create_action_raw_encap
12874 					(dev, actions, dev_flow, attr, error))
12875 					return -rte_errno;
12876 				dev_flow->dv.actions[actions_n++] =
12877 					dev_flow->dv.encap_decap->action;
12878 			} else {
12879 				/* Handle encap without preceding decap. */
12880 				if (flow_dv_create_action_l2_encap
12881 				    (dev, actions, dev_flow, attr->transfer,
12882 				     error))
12883 					return -rte_errno;
12884 				dev_flow->dv.actions[actions_n++] =
12885 					dev_flow->dv.encap_decap->action;
12886 			}
12887 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
12888 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
12889 				sample_act->action_flags |=
12890 							MLX5_FLOW_ACTION_ENCAP;
12891 			break;
12892 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
12893 			while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID)
12894 				;
12895 			if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
12896 				if (flow_dv_create_action_l2_decap
12897 				    (dev, dev_flow, attr->transfer, error))
12898 					return -rte_errno;
12899 				dev_flow->dv.actions[actions_n++] =
12900 					dev_flow->dv.encap_decap->action;
12901 			}
12902 			/* If decap is followed by encap, handle it at encap. */
12903 			action_flags |= MLX5_FLOW_ACTION_DECAP;
12904 			break;
12905 		case MLX5_RTE_FLOW_ACTION_TYPE_JUMP:
12906 			dev_flow->dv.actions[actions_n++] =
12907 				(void *)(uintptr_t)action->conf;
12908 			action_flags |= MLX5_FLOW_ACTION_JUMP;
12909 			break;
12910 		case RTE_FLOW_ACTION_TYPE_JUMP:
12911 			jump_group = ((const struct rte_flow_action_jump *)
12912 							action->conf)->group;
12913 			grp_info.std_tbl_fix = 0;
12914 			if (dev_flow->skip_scale &
12915 				(1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT))
12916 				grp_info.skip_scale = 1;
12917 			else
12918 				grp_info.skip_scale = 0;
12919 			ret = mlx5_flow_group_to_table(dev, tunnel,
12920 						       jump_group,
12921 						       &table,
12922 						       &grp_info, error);
12923 			if (ret)
12924 				return ret;
12925 			tbl = flow_dv_tbl_resource_get(dev, table, attr->egress,
12926 						       attr->transfer,
12927 						       !!dev_flow->external,
12928 						       tunnel, jump_group, 0,
12929 						       0, error);
12930 			if (!tbl)
12931 				return rte_flow_error_set
12932 						(error, errno,
12933 						 RTE_FLOW_ERROR_TYPE_ACTION,
12934 						 NULL,
12935 						 "cannot create jump action.");
12936 			if (flow_dv_jump_tbl_resource_register
12937 			    (dev, tbl, dev_flow, error)) {
12938 				flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
12939 				return rte_flow_error_set
12940 						(error, errno,
12941 						 RTE_FLOW_ERROR_TYPE_ACTION,
12942 						 NULL,
12943 						 "cannot create jump action.");
12944 			}
12945 			dev_flow->dv.actions[actions_n++] =
12946 					dev_flow->dv.jump->action;
12947 			action_flags |= MLX5_FLOW_ACTION_JUMP;
12948 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP;
12949 			sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP;
12950 			num_of_dest++;
12951 			break;
12952 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
12953 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
12954 			if (flow_dv_convert_action_modify_mac
12955 					(mhdr_res, actions, error))
12956 				return -rte_errno;
12957 			action_flags |= actions->type ==
12958 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
12959 					MLX5_FLOW_ACTION_SET_MAC_SRC :
12960 					MLX5_FLOW_ACTION_SET_MAC_DST;
12961 			break;
12962 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
12963 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
12964 			if (flow_dv_convert_action_modify_ipv4
12965 					(mhdr_res, actions, error))
12966 				return -rte_errno;
12967 			action_flags |= actions->type ==
12968 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
12969 					MLX5_FLOW_ACTION_SET_IPV4_SRC :
12970 					MLX5_FLOW_ACTION_SET_IPV4_DST;
12971 			break;
12972 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
12973 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
12974 			if (flow_dv_convert_action_modify_ipv6
12975 					(mhdr_res, actions, error))
12976 				return -rte_errno;
12977 			action_flags |= actions->type ==
12978 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
12979 					MLX5_FLOW_ACTION_SET_IPV6_SRC :
12980 					MLX5_FLOW_ACTION_SET_IPV6_DST;
12981 			break;
12982 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
12983 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
12984 			if (flow_dv_convert_action_modify_tp
12985 					(mhdr_res, actions, items,
12986 					 &flow_attr, dev_flow, !!(action_flags &
12987 					 MLX5_FLOW_ACTION_DECAP), error))
12988 				return -rte_errno;
12989 			action_flags |= actions->type ==
12990 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
12991 					MLX5_FLOW_ACTION_SET_TP_SRC :
12992 					MLX5_FLOW_ACTION_SET_TP_DST;
12993 			break;
12994 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
12995 			if (flow_dv_convert_action_modify_dec_ttl
12996 					(mhdr_res, items, &flow_attr, dev_flow,
12997 					 !!(action_flags &
12998 					 MLX5_FLOW_ACTION_DECAP), error))
12999 				return -rte_errno;
13000 			action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
13001 			break;
13002 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
13003 			if (flow_dv_convert_action_modify_ttl
13004 					(mhdr_res, actions, items, &flow_attr,
13005 					 dev_flow, !!(action_flags &
13006 					 MLX5_FLOW_ACTION_DECAP), error))
13007 				return -rte_errno;
13008 			action_flags |= MLX5_FLOW_ACTION_SET_TTL;
13009 			break;
13010 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
13011 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
13012 			if (flow_dv_convert_action_modify_tcp_seq
13013 					(mhdr_res, actions, error))
13014 				return -rte_errno;
13015 			action_flags |= actions->type ==
13016 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
13017 					MLX5_FLOW_ACTION_INC_TCP_SEQ :
13018 					MLX5_FLOW_ACTION_DEC_TCP_SEQ;
13019 			break;
13020 
13021 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
13022 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
13023 			if (flow_dv_convert_action_modify_tcp_ack
13024 					(mhdr_res, actions, error))
13025 				return -rte_errno;
13026 			action_flags |= actions->type ==
13027 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
13028 					MLX5_FLOW_ACTION_INC_TCP_ACK :
13029 					MLX5_FLOW_ACTION_DEC_TCP_ACK;
13030 			break;
13031 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
13032 			if (flow_dv_convert_action_set_reg
13033 					(mhdr_res, actions, error))
13034 				return -rte_errno;
13035 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
13036 			break;
13037 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
13038 			if (flow_dv_convert_action_copy_mreg
13039 					(dev, mhdr_res, actions, error))
13040 				return -rte_errno;
13041 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
13042 			break;
13043 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
13044 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
13045 			dev_flow->handle->fate_action =
13046 					MLX5_FLOW_FATE_DEFAULT_MISS;
13047 			break;
13048 		case RTE_FLOW_ACTION_TYPE_METER:
13049 			if (!wks->fm)
13050 				return rte_flow_error_set(error, rte_errno,
13051 					RTE_FLOW_ERROR_TYPE_ACTION,
13052 					NULL, "Failed to get meter in flow.");
13053 			/* Set the meter action. */
13054 			dev_flow->dv.actions[actions_n++] =
13055 				wks->fm->meter_action;
13056 			action_flags |= MLX5_FLOW_ACTION_METER;
13057 			break;
13058 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
13059 			if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res,
13060 							      actions, error))
13061 				return -rte_errno;
13062 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
13063 			break;
13064 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
13065 			if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res,
13066 							      actions, error))
13067 				return -rte_errno;
13068 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
13069 			break;
13070 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
13071 			sample_act_pos = actions_n;
13072 			sample = (const struct rte_flow_action_sample *)
13073 				 action->conf;
13074 			actions_n++;
13075 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
13076 			/* put encap action into group if work with port id */
13077 			if ((action_flags & MLX5_FLOW_ACTION_ENCAP) &&
13078 			    (action_flags & MLX5_FLOW_ACTION_PORT_ID))
13079 				sample_act->action_flags |=
13080 							MLX5_FLOW_ACTION_ENCAP;
13081 			break;
13082 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
13083 			if (flow_dv_convert_action_modify_field
13084 					(dev, mhdr_res, actions, attr, error))
13085 				return -rte_errno;
13086 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
13087 			break;
13088 		case RTE_FLOW_ACTION_TYPE_CONNTRACK:
13089 			owner_idx = (uint32_t)(uintptr_t)action->conf;
13090 			ct = flow_aso_ct_get_by_idx(dev, owner_idx);
13091 			if (!ct)
13092 				return rte_flow_error_set(error, EINVAL,
13093 						RTE_FLOW_ERROR_TYPE_ACTION,
13094 						NULL,
13095 						"Failed to get CT object.");
13096 			if (mlx5_aso_ct_available(priv->sh, ct))
13097 				return rte_flow_error_set(error, rte_errno,
13098 						RTE_FLOW_ERROR_TYPE_ACTION,
13099 						NULL,
13100 						"CT is unavailable.");
13101 			if (ct->is_original)
13102 				dev_flow->dv.actions[actions_n] =
13103 							ct->dr_action_orig;
13104 			else
13105 				dev_flow->dv.actions[actions_n] =
13106 							ct->dr_action_rply;
13107 			if (flow->ct == 0) {
13108 				flow->indirect_type =
13109 						MLX5_INDIRECT_ACTION_TYPE_CT;
13110 				flow->ct = owner_idx;
13111 				__atomic_fetch_add(&ct->refcnt, 1,
13112 						   __ATOMIC_RELAXED);
13113 			}
13114 			actions_n++;
13115 			action_flags |= MLX5_FLOW_ACTION_CT;
13116 			break;
13117 		case RTE_FLOW_ACTION_TYPE_END:
13118 			actions_end = true;
13119 			if (mhdr_res->actions_num) {
13120 				/* create modify action if needed. */
13121 				if (flow_dv_modify_hdr_resource_register
13122 					(dev, mhdr_res, dev_flow, error))
13123 					return -rte_errno;
13124 				dev_flow->dv.actions[modify_action_position] =
13125 					handle->dvh.modify_hdr->action;
13126 			}
13127 			/*
13128 			 * Handle AGE and COUNT action by single HW counter
13129 			 * when they are not shared.
13130 			 */
13131 			if (action_flags & MLX5_FLOW_ACTION_AGE) {
13132 				if ((non_shared_age && count) ||
13133 				    !(priv->sh->flow_hit_aso_en &&
13134 				      (attr->group || attr->transfer))) {
13135 					/* Creates age by counters. */
13136 					cnt_act = flow_dv_prepare_counter
13137 								(dev, dev_flow,
13138 								 flow, count,
13139 								 non_shared_age,
13140 								 error);
13141 					if (!cnt_act)
13142 						return -rte_errno;
13143 					dev_flow->dv.actions[age_act_pos] =
13144 								cnt_act->action;
13145 					break;
13146 				}
13147 				if (!flow->age && non_shared_age) {
13148 					flow->age = flow_dv_aso_age_alloc
13149 								(dev, error);
13150 					if (!flow->age)
13151 						return -rte_errno;
13152 					flow_dv_aso_age_params_init
13153 						    (dev, flow->age,
13154 						     non_shared_age->context ?
13155 						     non_shared_age->context :
13156 						     (void *)(uintptr_t)
13157 						     (dev_flow->flow_idx),
13158 						     non_shared_age->timeout);
13159 				}
13160 				age_act = flow_aso_age_get_by_idx(dev,
13161 								  flow->age);
13162 				dev_flow->dv.actions[age_act_pos] =
13163 							     age_act->dr_action;
13164 			}
13165 			if (action_flags & MLX5_FLOW_ACTION_COUNT) {
13166 				/*
13167 				 * Create one count action, to be used
13168 				 * by all sub-flows.
13169 				 */
13170 				cnt_act = flow_dv_prepare_counter(dev, dev_flow,
13171 								  flow, count,
13172 								  NULL, error);
13173 				if (!cnt_act)
13174 					return -rte_errno;
13175 				dev_flow->dv.actions[actions_n++] =
13176 								cnt_act->action;
13177 			}
13178 		default:
13179 			break;
13180 		}
13181 		if (mhdr_res->actions_num &&
13182 		    modify_action_position == UINT32_MAX)
13183 			modify_action_position = actions_n++;
13184 	}
13185 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
13186 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
13187 		int item_type = items->type;
13188 
13189 		if (!mlx5_flow_os_item_supported(item_type))
13190 			return rte_flow_error_set(error, ENOTSUP,
13191 						  RTE_FLOW_ERROR_TYPE_ITEM,
13192 						  NULL, "item not supported");
13193 		switch (item_type) {
13194 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
13195 			flow_dv_translate_item_port_id
13196 				(dev, match_mask, match_value, items, attr);
13197 			last_item = MLX5_FLOW_ITEM_PORT_ID;
13198 			break;
13199 		case RTE_FLOW_ITEM_TYPE_ETH:
13200 			flow_dv_translate_item_eth(match_mask, match_value,
13201 						   items, tunnel,
13202 						   dev_flow->dv.group);
13203 			matcher.priority = action_flags &
13204 					MLX5_FLOW_ACTION_DEFAULT_MISS &&
13205 					!dev_flow->external ?
13206 					MLX5_PRIORITY_MAP_L3 :
13207 					MLX5_PRIORITY_MAP_L2;
13208 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
13209 					     MLX5_FLOW_LAYER_OUTER_L2;
13210 			break;
13211 		case RTE_FLOW_ITEM_TYPE_VLAN:
13212 			flow_dv_translate_item_vlan(dev_flow,
13213 						    match_mask, match_value,
13214 						    items, tunnel,
13215 						    dev_flow->dv.group);
13216 			matcher.priority = MLX5_PRIORITY_MAP_L2;
13217 			last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
13218 					      MLX5_FLOW_LAYER_INNER_VLAN) :
13219 					     (MLX5_FLOW_LAYER_OUTER_L2 |
13220 					      MLX5_FLOW_LAYER_OUTER_VLAN);
13221 			break;
13222 		case RTE_FLOW_ITEM_TYPE_IPV4:
13223 			mlx5_flow_tunnel_ip_check(items, next_protocol,
13224 						  &item_flags, &tunnel);
13225 			flow_dv_translate_item_ipv4(match_mask, match_value,
13226 						    items, tunnel,
13227 						    dev_flow->dv.group);
13228 			matcher.priority = MLX5_PRIORITY_MAP_L3;
13229 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
13230 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
13231 			if (items->mask != NULL &&
13232 			    ((const struct rte_flow_item_ipv4 *)
13233 			     items->mask)->hdr.next_proto_id) {
13234 				next_protocol =
13235 					((const struct rte_flow_item_ipv4 *)
13236 					 (items->spec))->hdr.next_proto_id;
13237 				next_protocol &=
13238 					((const struct rte_flow_item_ipv4 *)
13239 					 (items->mask))->hdr.next_proto_id;
13240 			} else {
13241 				/* Reset for inner layer. */
13242 				next_protocol = 0xff;
13243 			}
13244 			break;
13245 		case RTE_FLOW_ITEM_TYPE_IPV6:
13246 			mlx5_flow_tunnel_ip_check(items, next_protocol,
13247 						  &item_flags, &tunnel);
13248 			flow_dv_translate_item_ipv6(match_mask, match_value,
13249 						    items, tunnel,
13250 						    dev_flow->dv.group);
13251 			matcher.priority = MLX5_PRIORITY_MAP_L3;
13252 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
13253 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
13254 			if (items->mask != NULL &&
13255 			    ((const struct rte_flow_item_ipv6 *)
13256 			     items->mask)->hdr.proto) {
13257 				next_protocol =
13258 					((const struct rte_flow_item_ipv6 *)
13259 					 items->spec)->hdr.proto;
13260 				next_protocol &=
13261 					((const struct rte_flow_item_ipv6 *)
13262 					 items->mask)->hdr.proto;
13263 			} else {
13264 				/* Reset for inner layer. */
13265 				next_protocol = 0xff;
13266 			}
13267 			break;
13268 		case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
13269 			flow_dv_translate_item_ipv6_frag_ext(match_mask,
13270 							     match_value,
13271 							     items, tunnel);
13272 			last_item = tunnel ?
13273 					MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
13274 					MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
13275 			if (items->mask != NULL &&
13276 			    ((const struct rte_flow_item_ipv6_frag_ext *)
13277 			     items->mask)->hdr.next_header) {
13278 				next_protocol =
13279 				((const struct rte_flow_item_ipv6_frag_ext *)
13280 				 items->spec)->hdr.next_header;
13281 				next_protocol &=
13282 				((const struct rte_flow_item_ipv6_frag_ext *)
13283 				 items->mask)->hdr.next_header;
13284 			} else {
13285 				/* Reset for inner layer. */
13286 				next_protocol = 0xff;
13287 			}
13288 			break;
13289 		case RTE_FLOW_ITEM_TYPE_TCP:
13290 			flow_dv_translate_item_tcp(match_mask, match_value,
13291 						   items, tunnel);
13292 			matcher.priority = MLX5_PRIORITY_MAP_L4;
13293 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
13294 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
13295 			break;
13296 		case RTE_FLOW_ITEM_TYPE_UDP:
13297 			flow_dv_translate_item_udp(match_mask, match_value,
13298 						   items, tunnel);
13299 			matcher.priority = MLX5_PRIORITY_MAP_L4;
13300 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
13301 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
13302 			break;
13303 		case RTE_FLOW_ITEM_TYPE_GRE:
13304 			flow_dv_translate_item_gre(match_mask, match_value,
13305 						   items, tunnel);
13306 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13307 			last_item = MLX5_FLOW_LAYER_GRE;
13308 			break;
13309 		case RTE_FLOW_ITEM_TYPE_GRE_KEY:
13310 			flow_dv_translate_item_gre_key(match_mask,
13311 						       match_value, items);
13312 			last_item = MLX5_FLOW_LAYER_GRE_KEY;
13313 			break;
13314 		case RTE_FLOW_ITEM_TYPE_NVGRE:
13315 			flow_dv_translate_item_nvgre(match_mask, match_value,
13316 						     items, tunnel);
13317 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13318 			last_item = MLX5_FLOW_LAYER_GRE;
13319 			break;
13320 		case RTE_FLOW_ITEM_TYPE_VXLAN:
13321 			flow_dv_translate_item_vxlan(dev, attr,
13322 						     match_mask, match_value,
13323 						     items, tunnel);
13324 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13325 			last_item = MLX5_FLOW_LAYER_VXLAN;
13326 			break;
13327 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
13328 			flow_dv_translate_item_vxlan_gpe(match_mask,
13329 							 match_value, items,
13330 							 tunnel);
13331 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13332 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
13333 			break;
13334 		case RTE_FLOW_ITEM_TYPE_GENEVE:
13335 			flow_dv_translate_item_geneve(match_mask, match_value,
13336 						      items, tunnel);
13337 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13338 			last_item = MLX5_FLOW_LAYER_GENEVE;
13339 			break;
13340 		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
13341 			ret = flow_dv_translate_item_geneve_opt(dev, match_mask,
13342 							  match_value,
13343 							  items, error);
13344 			if (ret)
13345 				return rte_flow_error_set(error, -ret,
13346 					RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13347 					"cannot create GENEVE TLV option");
13348 			flow->geneve_tlv_option = 1;
13349 			last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
13350 			break;
13351 		case RTE_FLOW_ITEM_TYPE_MPLS:
13352 			flow_dv_translate_item_mpls(match_mask, match_value,
13353 						    items, last_item, tunnel);
13354 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13355 			last_item = MLX5_FLOW_LAYER_MPLS;
13356 			break;
13357 		case RTE_FLOW_ITEM_TYPE_MARK:
13358 			flow_dv_translate_item_mark(dev, match_mask,
13359 						    match_value, items);
13360 			last_item = MLX5_FLOW_ITEM_MARK;
13361 			break;
13362 		case RTE_FLOW_ITEM_TYPE_META:
13363 			flow_dv_translate_item_meta(dev, match_mask,
13364 						    match_value, attr, items);
13365 			last_item = MLX5_FLOW_ITEM_METADATA;
13366 			break;
13367 		case RTE_FLOW_ITEM_TYPE_ICMP:
13368 			flow_dv_translate_item_icmp(match_mask, match_value,
13369 						    items, tunnel);
13370 			last_item = MLX5_FLOW_LAYER_ICMP;
13371 			break;
13372 		case RTE_FLOW_ITEM_TYPE_ICMP6:
13373 			flow_dv_translate_item_icmp6(match_mask, match_value,
13374 						      items, tunnel);
13375 			last_item = MLX5_FLOW_LAYER_ICMP6;
13376 			break;
13377 		case RTE_FLOW_ITEM_TYPE_TAG:
13378 			flow_dv_translate_item_tag(dev, match_mask,
13379 						   match_value, items);
13380 			last_item = MLX5_FLOW_ITEM_TAG;
13381 			break;
13382 		case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
13383 			flow_dv_translate_mlx5_item_tag(dev, match_mask,
13384 							match_value, items);
13385 			last_item = MLX5_FLOW_ITEM_TAG;
13386 			break;
13387 		case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
13388 			flow_dv_translate_item_tx_queue(dev, match_mask,
13389 							match_value,
13390 							items);
13391 			last_item = MLX5_FLOW_ITEM_TX_QUEUE;
13392 			break;
13393 		case RTE_FLOW_ITEM_TYPE_GTP:
13394 			flow_dv_translate_item_gtp(match_mask, match_value,
13395 						   items, tunnel);
13396 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13397 			last_item = MLX5_FLOW_LAYER_GTP;
13398 			break;
13399 		case RTE_FLOW_ITEM_TYPE_GTP_PSC:
13400 			ret = flow_dv_translate_item_gtp_psc(match_mask,
13401 							  match_value,
13402 							  items);
13403 			if (ret)
13404 				return rte_flow_error_set(error, -ret,
13405 					RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13406 					"cannot create GTP PSC item");
13407 			last_item = MLX5_FLOW_LAYER_GTP_PSC;
13408 			break;
13409 		case RTE_FLOW_ITEM_TYPE_ECPRI:
13410 			if (!mlx5_flex_parser_ecpri_exist(dev)) {
13411 				/* Create it only the first time to be used. */
13412 				ret = mlx5_flex_parser_ecpri_alloc(dev);
13413 				if (ret)
13414 					return rte_flow_error_set
13415 						(error, -ret,
13416 						RTE_FLOW_ERROR_TYPE_ITEM,
13417 						NULL,
13418 						"cannot create eCPRI parser");
13419 			}
13420 			flow_dv_translate_item_ecpri(dev, match_mask,
13421 						     match_value, items,
13422 						     last_item);
13423 			/* No other protocol should follow eCPRI layer. */
13424 			last_item = MLX5_FLOW_LAYER_ECPRI;
13425 			break;
13426 		case RTE_FLOW_ITEM_TYPE_INTEGRITY:
13427 			flow_dv_translate_item_integrity(match_mask,
13428 							 match_value,
13429 							 head_item, items);
13430 			break;
13431 		case RTE_FLOW_ITEM_TYPE_CONNTRACK:
13432 			flow_dv_translate_item_aso_ct(dev, match_mask,
13433 						      match_value, items);
13434 			break;
13435 		default:
13436 			break;
13437 		}
13438 		item_flags |= last_item;
13439 	}
13440 	/*
13441 	 * When E-Switch mode is enabled, we have two cases where we need to
13442 	 * set the source port manually.
13443 	 * The first one, is in case of Nic steering rule, and the second is
13444 	 * E-Switch rule where no port_id item was found. In both cases
13445 	 * the source port is set according the current port in use.
13446 	 */
13447 	if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) &&
13448 	    (priv->representor || priv->master)) {
13449 		if (flow_dv_translate_item_port_id(dev, match_mask,
13450 						   match_value, NULL, attr))
13451 			return -rte_errno;
13452 	}
13453 #ifdef RTE_LIBRTE_MLX5_DEBUG
13454 	MLX5_ASSERT(!flow_dv_check_valid_spec(matcher.mask.buf,
13455 					      dev_flow->dv.value.buf));
13456 #endif
13457 	/*
13458 	 * Layers may be already initialized from prefix flow if this dev_flow
13459 	 * is the suffix flow.
13460 	 */
13461 	handle->layers |= item_flags;
13462 	if (action_flags & MLX5_FLOW_ACTION_RSS)
13463 		flow_dv_hashfields_set(dev_flow, rss_desc);
13464 	/* If has RSS action in the sample action, the Sample/Mirror resource
13465 	 * should be registered after the hash filed be update.
13466 	 */
13467 	if (action_flags & MLX5_FLOW_ACTION_SAMPLE) {
13468 		ret = flow_dv_translate_action_sample(dev,
13469 						      sample,
13470 						      dev_flow, attr,
13471 						      &num_of_dest,
13472 						      sample_actions,
13473 						      &sample_res,
13474 						      error);
13475 		if (ret < 0)
13476 			return ret;
13477 		ret = flow_dv_create_action_sample(dev,
13478 						   dev_flow,
13479 						   num_of_dest,
13480 						   &sample_res,
13481 						   &mdest_res,
13482 						   sample_actions,
13483 						   action_flags,
13484 						   error);
13485 		if (ret < 0)
13486 			return rte_flow_error_set
13487 						(error, rte_errno,
13488 						RTE_FLOW_ERROR_TYPE_ACTION,
13489 						NULL,
13490 						"cannot create sample action");
13491 		if (num_of_dest > 1) {
13492 			dev_flow->dv.actions[sample_act_pos] =
13493 			dev_flow->dv.dest_array_res->action;
13494 		} else {
13495 			dev_flow->dv.actions[sample_act_pos] =
13496 			dev_flow->dv.sample_res->verbs_action;
13497 		}
13498 	}
13499 	/*
13500 	 * For multiple destination (sample action with ratio=1), the encap
13501 	 * action and port id action will be combined into group action.
13502 	 * So need remove the original these actions in the flow and only
13503 	 * use the sample action instead of.
13504 	 */
13505 	if (num_of_dest > 1 &&
13506 	    (sample_act->dr_port_id_action || sample_act->dr_jump_action)) {
13507 		int i;
13508 		void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
13509 
13510 		for (i = 0; i < actions_n; i++) {
13511 			if ((sample_act->dr_encap_action &&
13512 				sample_act->dr_encap_action ==
13513 				dev_flow->dv.actions[i]) ||
13514 				(sample_act->dr_port_id_action &&
13515 				sample_act->dr_port_id_action ==
13516 				dev_flow->dv.actions[i]) ||
13517 				(sample_act->dr_jump_action &&
13518 				sample_act->dr_jump_action ==
13519 				dev_flow->dv.actions[i]))
13520 				continue;
13521 			temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];
13522 		}
13523 		memcpy((void *)dev_flow->dv.actions,
13524 				(void *)temp_actions,
13525 				tmp_actions_n * sizeof(void *));
13526 		actions_n = tmp_actions_n;
13527 	}
13528 	dev_flow->dv.actions_n = actions_n;
13529 	dev_flow->act_flags = action_flags;
13530 	if (wks->skip_matcher_reg)
13531 		return 0;
13532 	/* Register matcher. */
13533 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
13534 				    matcher.mask.size);
13535 	matcher.priority = mlx5_get_matcher_priority(dev, attr,
13536 					matcher.priority);
13537 	/**
13538 	 * When creating meter drop flow in drop table, using original
13539 	 * 5-tuple match, the matcher priority should be lower than
13540 	 * mtr_id matcher.
13541 	 */
13542 	if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
13543 	    dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP &&
13544 	    matcher.priority <= MLX5_REG_BITS)
13545 		matcher.priority += MLX5_REG_BITS;
13546 	/* reserved field no needs to be set to 0 here. */
13547 	tbl_key.is_fdb = attr->transfer;
13548 	tbl_key.is_egress = attr->egress;
13549 	tbl_key.level = dev_flow->dv.group;
13550 	tbl_key.id = dev_flow->dv.table_id;
13551 	if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow,
13552 				     tunnel, attr->group, error))
13553 		return -rte_errno;
13554 	return 0;
13555 }
13556 
13557 /**
13558  * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields)
13559  * and tunnel.
13560  *
13561  * @param[in, out] action
13562  *   Shred RSS action holding hash RX queue objects.
13563  * @param[in] hash_fields
13564  *   Defines combination of packet fields to participate in RX hash.
13565  * @param[in] tunnel
13566  *   Tunnel type
13567  * @param[in] hrxq_idx
13568  *   Hash RX queue index to set.
13569  *
13570  * @return
13571  *   0 on success, otherwise negative errno value.
13572  */
13573 static int
13574 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action,
13575 			      const uint64_t hash_fields,
13576 			      uint32_t hrxq_idx)
13577 {
13578 	uint32_t *hrxqs = action->hrxq;
13579 
13580 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
13581 	case MLX5_RSS_HASH_IPV4:
13582 		/* fall-through. */
13583 	case MLX5_RSS_HASH_IPV4_DST_ONLY:
13584 		/* fall-through. */
13585 	case MLX5_RSS_HASH_IPV4_SRC_ONLY:
13586 		hrxqs[0] = hrxq_idx;
13587 		return 0;
13588 	case MLX5_RSS_HASH_IPV4_TCP:
13589 		/* fall-through. */
13590 	case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY:
13591 		/* fall-through. */
13592 	case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY:
13593 		hrxqs[1] = hrxq_idx;
13594 		return 0;
13595 	case MLX5_RSS_HASH_IPV4_UDP:
13596 		/* fall-through. */
13597 	case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
13598 		/* fall-through. */
13599 	case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
13600 		hrxqs[2] = hrxq_idx;
13601 		return 0;
13602 	case MLX5_RSS_HASH_IPV6:
13603 		/* fall-through. */
13604 	case MLX5_RSS_HASH_IPV6_DST_ONLY:
13605 		/* fall-through. */
13606 	case MLX5_RSS_HASH_IPV6_SRC_ONLY:
13607 		hrxqs[3] = hrxq_idx;
13608 		return 0;
13609 	case MLX5_RSS_HASH_IPV6_TCP:
13610 		/* fall-through. */
13611 	case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
13612 		/* fall-through. */
13613 	case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
13614 		hrxqs[4] = hrxq_idx;
13615 		return 0;
13616 	case MLX5_RSS_HASH_IPV6_UDP:
13617 		/* fall-through. */
13618 	case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
13619 		/* fall-through. */
13620 	case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
13621 		hrxqs[5] = hrxq_idx;
13622 		return 0;
13623 	case MLX5_RSS_HASH_NONE:
13624 		hrxqs[6] = hrxq_idx;
13625 		return 0;
13626 	default:
13627 		return -1;
13628 	}
13629 }
13630 
13631 /**
13632  * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields)
13633  * and tunnel.
13634  *
13635  * @param[in] dev
13636  *   Pointer to the Ethernet device structure.
13637  * @param[in] idx
13638  *   Shared RSS action ID holding hash RX queue objects.
13639  * @param[in] hash_fields
13640  *   Defines combination of packet fields to participate in RX hash.
13641  * @param[in] tunnel
13642  *   Tunnel type
13643  *
13644  * @return
13645  *   Valid hash RX queue index, otherwise 0.
13646  */
13647 static uint32_t
13648 __flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx,
13649 				 const uint64_t hash_fields)
13650 {
13651 	struct mlx5_priv *priv = dev->data->dev_private;
13652 	struct mlx5_shared_action_rss *shared_rss =
13653 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
13654 	const uint32_t *hrxqs = shared_rss->hrxq;
13655 
13656 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
13657 	case MLX5_RSS_HASH_IPV4:
13658 		/* fall-through. */
13659 	case MLX5_RSS_HASH_IPV4_DST_ONLY:
13660 		/* fall-through. */
13661 	case MLX5_RSS_HASH_IPV4_SRC_ONLY:
13662 		return hrxqs[0];
13663 	case MLX5_RSS_HASH_IPV4_TCP:
13664 		/* fall-through. */
13665 	case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY:
13666 		/* fall-through. */
13667 	case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY:
13668 		return hrxqs[1];
13669 	case MLX5_RSS_HASH_IPV4_UDP:
13670 		/* fall-through. */
13671 	case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
13672 		/* fall-through. */
13673 	case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
13674 		return hrxqs[2];
13675 	case MLX5_RSS_HASH_IPV6:
13676 		/* fall-through. */
13677 	case MLX5_RSS_HASH_IPV6_DST_ONLY:
13678 		/* fall-through. */
13679 	case MLX5_RSS_HASH_IPV6_SRC_ONLY:
13680 		return hrxqs[3];
13681 	case MLX5_RSS_HASH_IPV6_TCP:
13682 		/* fall-through. */
13683 	case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
13684 		/* fall-through. */
13685 	case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
13686 		return hrxqs[4];
13687 	case MLX5_RSS_HASH_IPV6_UDP:
13688 		/* fall-through. */
13689 	case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
13690 		/* fall-through. */
13691 	case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
13692 		return hrxqs[5];
13693 	case MLX5_RSS_HASH_NONE:
13694 		return hrxqs[6];
13695 	default:
13696 		return 0;
13697 	}
13698 
13699 }
13700 
13701 /**
13702  * Apply the flow to the NIC, lock free,
13703  * (mutex should be acquired by caller).
13704  *
13705  * @param[in] dev
13706  *   Pointer to the Ethernet device structure.
13707  * @param[in, out] flow
13708  *   Pointer to flow structure.
13709  * @param[out] error
13710  *   Pointer to error structure.
13711  *
13712  * @return
13713  *   0 on success, a negative errno value otherwise and rte_errno is set.
13714  */
13715 static int
13716 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
13717 	      struct rte_flow_error *error)
13718 {
13719 	struct mlx5_flow_dv_workspace *dv;
13720 	struct mlx5_flow_handle *dh;
13721 	struct mlx5_flow_handle_dv *dv_h;
13722 	struct mlx5_flow *dev_flow;
13723 	struct mlx5_priv *priv = dev->data->dev_private;
13724 	uint32_t handle_idx;
13725 	int n;
13726 	int err;
13727 	int idx;
13728 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
13729 	struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc;
13730 	uint8_t misc_mask;
13731 
13732 	MLX5_ASSERT(wks);
13733 	for (idx = wks->flow_idx - 1; idx >= 0; idx--) {
13734 		dev_flow = &wks->flows[idx];
13735 		dv = &dev_flow->dv;
13736 		dh = dev_flow->handle;
13737 		dv_h = &dh->dvh;
13738 		n = dv->actions_n;
13739 		if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
13740 			if (dv->transfer) {
13741 				MLX5_ASSERT(priv->sh->dr_drop_action);
13742 				dv->actions[n++] = priv->sh->dr_drop_action;
13743 			} else {
13744 #ifdef HAVE_MLX5DV_DR
13745 				/* DR supports drop action placeholder. */
13746 				MLX5_ASSERT(priv->sh->dr_drop_action);
13747 				dv->actions[n++] = dv->group ?
13748 					priv->sh->dr_drop_action :
13749 					priv->root_drop_action;
13750 #else
13751 				/* For DV we use the explicit drop queue. */
13752 				MLX5_ASSERT(priv->drop_queue.hrxq);
13753 				dv->actions[n++] =
13754 						priv->drop_queue.hrxq->action;
13755 #endif
13756 			}
13757 		} else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE &&
13758 			   !dv_h->rix_sample && !dv_h->rix_dest_array)) {
13759 			struct mlx5_hrxq *hrxq;
13760 			uint32_t hrxq_idx;
13761 
13762 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc,
13763 						    &hrxq_idx);
13764 			if (!hrxq) {
13765 				rte_flow_error_set
13766 					(error, rte_errno,
13767 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13768 					 "cannot get hash queue");
13769 				goto error;
13770 			}
13771 			dh->rix_hrxq = hrxq_idx;
13772 			dv->actions[n++] = hrxq->action;
13773 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
13774 			struct mlx5_hrxq *hrxq = NULL;
13775 			uint32_t hrxq_idx;
13776 
13777 			hrxq_idx = __flow_dv_action_rss_hrxq_lookup(dev,
13778 						rss_desc->shared_rss,
13779 						dev_flow->hash_fields);
13780 			if (hrxq_idx)
13781 				hrxq = mlx5_ipool_get
13782 					(priv->sh->ipool[MLX5_IPOOL_HRXQ],
13783 					 hrxq_idx);
13784 			if (!hrxq) {
13785 				rte_flow_error_set
13786 					(error, rte_errno,
13787 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13788 					 "cannot get hash queue");
13789 				goto error;
13790 			}
13791 			dh->rix_srss = rss_desc->shared_rss;
13792 			dv->actions[n++] = hrxq->action;
13793 		} else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) {
13794 			if (!priv->sh->default_miss_action) {
13795 				rte_flow_error_set
13796 					(error, rte_errno,
13797 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13798 					 "default miss action not be created.");
13799 				goto error;
13800 			}
13801 			dv->actions[n++] = priv->sh->default_miss_action;
13802 		}
13803 		misc_mask = flow_dv_matcher_enable(dv->value.buf);
13804 		__flow_dv_adjust_buf_size(&dv->value.size, misc_mask);
13805 		err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object,
13806 					       (void *)&dv->value, n,
13807 					       dv->actions, &dh->drv_flow);
13808 		if (err) {
13809 			rte_flow_error_set
13810 				(error, errno,
13811 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13812 				NULL,
13813 				(!priv->config.allow_duplicate_pattern &&
13814 				errno == EEXIST) ?
13815 				"duplicating pattern is not allowed" :
13816 				"hardware refuses to create flow");
13817 			goto error;
13818 		}
13819 		if (priv->vmwa_context &&
13820 		    dh->vf_vlan.tag && !dh->vf_vlan.created) {
13821 			/*
13822 			 * The rule contains the VLAN pattern.
13823 			 * For VF we are going to create VLAN
13824 			 * interface to make hypervisor set correct
13825 			 * e-Switch vport context.
13826 			 */
13827 			mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan);
13828 		}
13829 	}
13830 	return 0;
13831 error:
13832 	err = rte_errno; /* Save rte_errno before cleanup. */
13833 	SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
13834 		       handle_idx, dh, next) {
13835 		/* hrxq is union, don't clear it if the flag is not set. */
13836 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) {
13837 			mlx5_hrxq_release(dev, dh->rix_hrxq);
13838 			dh->rix_hrxq = 0;
13839 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
13840 			dh->rix_srss = 0;
13841 		}
13842 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
13843 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
13844 	}
13845 	rte_errno = err; /* Restore rte_errno. */
13846 	return -rte_errno;
13847 }
13848 
13849 void
13850 flow_dv_matcher_remove_cb(void *tool_ctx __rte_unused,
13851 			  struct mlx5_list_entry *entry)
13852 {
13853 	struct mlx5_flow_dv_matcher *resource = container_of(entry,
13854 							     typeof(*resource),
13855 							     entry);
13856 
13857 	claim_zero(mlx5_flow_os_destroy_flow_matcher(resource->matcher_object));
13858 	mlx5_free(resource);
13859 }
13860 
13861 /**
13862  * Release the flow matcher.
13863  *
13864  * @param dev
13865  *   Pointer to Ethernet device.
13866  * @param port_id
13867  *   Index to port ID action resource.
13868  *
13869  * @return
13870  *   1 while a reference on it exists, 0 when freed.
13871  */
13872 static int
13873 flow_dv_matcher_release(struct rte_eth_dev *dev,
13874 			struct mlx5_flow_handle *handle)
13875 {
13876 	struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher;
13877 	struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl,
13878 							    typeof(*tbl), tbl);
13879 	int ret;
13880 
13881 	MLX5_ASSERT(matcher->matcher_object);
13882 	ret = mlx5_list_unregister(tbl->matchers, &matcher->entry);
13883 	flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl);
13884 	return ret;
13885 }
13886 
13887 void
13888 flow_dv_encap_decap_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
13889 {
13890 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
13891 	struct mlx5_flow_dv_encap_decap_resource *res =
13892 				       container_of(entry, typeof(*res), entry);
13893 
13894 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
13895 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
13896 }
13897 
13898 /**
13899  * Release an encap/decap resource.
13900  *
13901  * @param dev
13902  *   Pointer to Ethernet device.
13903  * @param encap_decap_idx
13904  *   Index of encap decap resource.
13905  *
13906  * @return
13907  *   1 while a reference on it exists, 0 when freed.
13908  */
13909 static int
13910 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
13911 				     uint32_t encap_decap_idx)
13912 {
13913 	struct mlx5_priv *priv = dev->data->dev_private;
13914 	struct mlx5_flow_dv_encap_decap_resource *resource;
13915 
13916 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
13917 				  encap_decap_idx);
13918 	if (!resource)
13919 		return 0;
13920 	MLX5_ASSERT(resource->action);
13921 	return mlx5_hlist_unregister(priv->sh->encaps_decaps, &resource->entry);
13922 }
13923 
13924 /**
13925  * Release an jump to table action resource.
13926  *
13927  * @param dev
13928  *   Pointer to Ethernet device.
13929  * @param rix_jump
13930  *   Index to the jump action resource.
13931  *
13932  * @return
13933  *   1 while a reference on it exists, 0 when freed.
13934  */
13935 static int
13936 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
13937 				  uint32_t rix_jump)
13938 {
13939 	struct mlx5_priv *priv = dev->data->dev_private;
13940 	struct mlx5_flow_tbl_data_entry *tbl_data;
13941 
13942 	tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP],
13943 				  rix_jump);
13944 	if (!tbl_data)
13945 		return 0;
13946 	return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl);
13947 }
13948 
13949 void
13950 flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
13951 {
13952 	struct mlx5_flow_dv_modify_hdr_resource *res =
13953 		container_of(entry, typeof(*res), entry);
13954 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
13955 
13956 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
13957 	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
13958 }
13959 
13960 /**
13961  * Release a modify-header resource.
13962  *
13963  * @param dev
13964  *   Pointer to Ethernet device.
13965  * @param handle
13966  *   Pointer to mlx5_flow_handle.
13967  *
13968  * @return
13969  *   1 while a reference on it exists, 0 when freed.
13970  */
13971 static int
13972 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev,
13973 				    struct mlx5_flow_handle *handle)
13974 {
13975 	struct mlx5_priv *priv = dev->data->dev_private;
13976 	struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr;
13977 
13978 	MLX5_ASSERT(entry->action);
13979 	return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry);
13980 }
13981 
13982 void
13983 flow_dv_port_id_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
13984 {
13985 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
13986 	struct mlx5_flow_dv_port_id_action_resource *resource =
13987 				  container_of(entry, typeof(*resource), entry);
13988 
13989 	claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
13990 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
13991 }
13992 
13993 /**
13994  * Release port ID action resource.
13995  *
13996  * @param dev
13997  *   Pointer to Ethernet device.
13998  * @param handle
13999  *   Pointer to mlx5_flow_handle.
14000  *
14001  * @return
14002  *   1 while a reference on it exists, 0 when freed.
14003  */
14004 static int
14005 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
14006 					uint32_t port_id)
14007 {
14008 	struct mlx5_priv *priv = dev->data->dev_private;
14009 	struct mlx5_flow_dv_port_id_action_resource *resource;
14010 
14011 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id);
14012 	if (!resource)
14013 		return 0;
14014 	MLX5_ASSERT(resource->action);
14015 	return mlx5_list_unregister(priv->sh->port_id_action_list,
14016 				    &resource->entry);
14017 }
14018 
14019 /**
14020  * Release shared RSS action resource.
14021  *
14022  * @param dev
14023  *   Pointer to Ethernet device.
14024  * @param srss
14025  *   Shared RSS action index.
14026  */
14027 static void
14028 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss)
14029 {
14030 	struct mlx5_priv *priv = dev->data->dev_private;
14031 	struct mlx5_shared_action_rss *shared_rss;
14032 
14033 	shared_rss = mlx5_ipool_get
14034 			(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss);
14035 	__atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
14036 }
14037 
14038 void
14039 flow_dv_push_vlan_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14040 {
14041 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14042 	struct mlx5_flow_dv_push_vlan_action_resource *resource =
14043 			container_of(entry, typeof(*resource), entry);
14044 
14045 	claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14046 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
14047 }
14048 
14049 /**
14050  * Release push vlan action resource.
14051  *
14052  * @param dev
14053  *   Pointer to Ethernet device.
14054  * @param handle
14055  *   Pointer to mlx5_flow_handle.
14056  *
14057  * @return
14058  *   1 while a reference on it exists, 0 when freed.
14059  */
14060 static int
14061 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev,
14062 					  struct mlx5_flow_handle *handle)
14063 {
14064 	struct mlx5_priv *priv = dev->data->dev_private;
14065 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
14066 	uint32_t idx = handle->dvh.rix_push_vlan;
14067 
14068 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
14069 	if (!resource)
14070 		return 0;
14071 	MLX5_ASSERT(resource->action);
14072 	return mlx5_list_unregister(priv->sh->push_vlan_action_list,
14073 				    &resource->entry);
14074 }
14075 
14076 /**
14077  * Release the fate resource.
14078  *
14079  * @param dev
14080  *   Pointer to Ethernet device.
14081  * @param handle
14082  *   Pointer to mlx5_flow_handle.
14083  */
14084 static void
14085 flow_dv_fate_resource_release(struct rte_eth_dev *dev,
14086 			       struct mlx5_flow_handle *handle)
14087 {
14088 	if (!handle->rix_fate)
14089 		return;
14090 	switch (handle->fate_action) {
14091 	case MLX5_FLOW_FATE_QUEUE:
14092 		if (!handle->dvh.rix_sample && !handle->dvh.rix_dest_array)
14093 			mlx5_hrxq_release(dev, handle->rix_hrxq);
14094 		break;
14095 	case MLX5_FLOW_FATE_JUMP:
14096 		flow_dv_jump_tbl_resource_release(dev, handle->rix_jump);
14097 		break;
14098 	case MLX5_FLOW_FATE_PORT_ID:
14099 		flow_dv_port_id_action_resource_release(dev,
14100 				handle->rix_port_id_action);
14101 		break;
14102 	default:
14103 		DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action);
14104 		break;
14105 	}
14106 	handle->rix_fate = 0;
14107 }
14108 
14109 void
14110 flow_dv_sample_remove_cb(void *tool_ctx __rte_unused,
14111 			 struct mlx5_list_entry *entry)
14112 {
14113 	struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
14114 							      typeof(*resource),
14115 							      entry);
14116 	struct rte_eth_dev *dev = resource->dev;
14117 	struct mlx5_priv *priv = dev->data->dev_private;
14118 
14119 	if (resource->verbs_action)
14120 		claim_zero(mlx5_flow_os_destroy_flow_action
14121 						      (resource->verbs_action));
14122 	if (resource->normal_path_tbl)
14123 		flow_dv_tbl_resource_release(MLX5_SH(dev),
14124 					     resource->normal_path_tbl);
14125 	flow_dv_sample_sub_actions_release(dev, &resource->sample_idx);
14126 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
14127 	DRV_LOG(DEBUG, "sample resource %p: removed", (void *)resource);
14128 }
14129 
14130 /**
14131  * Release an sample resource.
14132  *
14133  * @param dev
14134  *   Pointer to Ethernet device.
14135  * @param handle
14136  *   Pointer to mlx5_flow_handle.
14137  *
14138  * @return
14139  *   1 while a reference on it exists, 0 when freed.
14140  */
14141 static int
14142 flow_dv_sample_resource_release(struct rte_eth_dev *dev,
14143 				     struct mlx5_flow_handle *handle)
14144 {
14145 	struct mlx5_priv *priv = dev->data->dev_private;
14146 	struct mlx5_flow_dv_sample_resource *resource;
14147 
14148 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE],
14149 				  handle->dvh.rix_sample);
14150 	if (!resource)
14151 		return 0;
14152 	MLX5_ASSERT(resource->verbs_action);
14153 	return mlx5_list_unregister(priv->sh->sample_action_list,
14154 				    &resource->entry);
14155 }
14156 
14157 void
14158 flow_dv_dest_array_remove_cb(void *tool_ctx __rte_unused,
14159 			     struct mlx5_list_entry *entry)
14160 {
14161 	struct mlx5_flow_dv_dest_array_resource *resource =
14162 			container_of(entry, typeof(*resource), entry);
14163 	struct rte_eth_dev *dev = resource->dev;
14164 	struct mlx5_priv *priv = dev->data->dev_private;
14165 	uint32_t i = 0;
14166 
14167 	MLX5_ASSERT(resource->action);
14168 	if (resource->action)
14169 		claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14170 	for (; i < resource->num_of_dest; i++)
14171 		flow_dv_sample_sub_actions_release(dev,
14172 						   &resource->sample_idx[i]);
14173 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
14174 	DRV_LOG(DEBUG, "destination array resource %p: removed",
14175 		(void *)resource);
14176 }
14177 
14178 /**
14179  * Release an destination array resource.
14180  *
14181  * @param dev
14182  *   Pointer to Ethernet device.
14183  * @param handle
14184  *   Pointer to mlx5_flow_handle.
14185  *
14186  * @return
14187  *   1 while a reference on it exists, 0 when freed.
14188  */
14189 static int
14190 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev,
14191 				    struct mlx5_flow_handle *handle)
14192 {
14193 	struct mlx5_priv *priv = dev->data->dev_private;
14194 	struct mlx5_flow_dv_dest_array_resource *resource;
14195 
14196 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY],
14197 				  handle->dvh.rix_dest_array);
14198 	if (!resource)
14199 		return 0;
14200 	MLX5_ASSERT(resource->action);
14201 	return mlx5_list_unregister(priv->sh->dest_array_list,
14202 				    &resource->entry);
14203 }
14204 
14205 static void
14206 flow_dv_geneve_tlv_option_resource_release(struct rte_eth_dev *dev)
14207 {
14208 	struct mlx5_priv *priv = dev->data->dev_private;
14209 	struct mlx5_dev_ctx_shared *sh = priv->sh;
14210 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
14211 				sh->geneve_tlv_option_resource;
14212 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
14213 	if (geneve_opt_resource) {
14214 		if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1,
14215 					 __ATOMIC_RELAXED))) {
14216 			claim_zero(mlx5_devx_cmd_destroy
14217 					(geneve_opt_resource->obj));
14218 			mlx5_free(sh->geneve_tlv_option_resource);
14219 			sh->geneve_tlv_option_resource = NULL;
14220 		}
14221 	}
14222 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
14223 }
14224 
14225 /**
14226  * Remove the flow from the NIC but keeps it in memory.
14227  * Lock free, (mutex should be acquired by caller).
14228  *
14229  * @param[in] dev
14230  *   Pointer to Ethernet device.
14231  * @param[in, out] flow
14232  *   Pointer to flow structure.
14233  */
14234 static void
14235 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
14236 {
14237 	struct mlx5_flow_handle *dh;
14238 	uint32_t handle_idx;
14239 	struct mlx5_priv *priv = dev->data->dev_private;
14240 
14241 	if (!flow)
14242 		return;
14243 	handle_idx = flow->dev_handles;
14244 	while (handle_idx) {
14245 		dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
14246 				    handle_idx);
14247 		if (!dh)
14248 			return;
14249 		if (dh->drv_flow) {
14250 			claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow));
14251 			dh->drv_flow = NULL;
14252 		}
14253 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE)
14254 			flow_dv_fate_resource_release(dev, dh);
14255 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
14256 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
14257 		handle_idx = dh->next.next;
14258 	}
14259 }
14260 
14261 /**
14262  * Remove the flow from the NIC and the memory.
14263  * Lock free, (mutex should be acquired by caller).
14264  *
14265  * @param[in] dev
14266  *   Pointer to the Ethernet device structure.
14267  * @param[in, out] flow
14268  *   Pointer to flow structure.
14269  */
14270 static void
14271 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
14272 {
14273 	struct mlx5_flow_handle *dev_handle;
14274 	struct mlx5_priv *priv = dev->data->dev_private;
14275 	struct mlx5_flow_meter_info *fm = NULL;
14276 	uint32_t srss = 0;
14277 
14278 	if (!flow)
14279 		return;
14280 	flow_dv_remove(dev, flow);
14281 	if (flow->counter) {
14282 		flow_dv_counter_free(dev, flow->counter);
14283 		flow->counter = 0;
14284 	}
14285 	if (flow->meter) {
14286 		fm = flow_dv_meter_find_by_idx(priv, flow->meter);
14287 		if (fm)
14288 			mlx5_flow_meter_detach(priv, fm);
14289 		flow->meter = 0;
14290 	}
14291 	/* Keep the current age handling by default. */
14292 	if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct)
14293 		flow_dv_aso_ct_release(dev, flow->ct, NULL);
14294 	else if (flow->age)
14295 		flow_dv_aso_age_release(dev, flow->age);
14296 	if (flow->geneve_tlv_option) {
14297 		flow_dv_geneve_tlv_option_resource_release(dev);
14298 		flow->geneve_tlv_option = 0;
14299 	}
14300 	while (flow->dev_handles) {
14301 		uint32_t tmp_idx = flow->dev_handles;
14302 
14303 		dev_handle = mlx5_ipool_get(priv->sh->ipool
14304 					    [MLX5_IPOOL_MLX5_FLOW], tmp_idx);
14305 		if (!dev_handle)
14306 			return;
14307 		flow->dev_handles = dev_handle->next.next;
14308 		if (dev_handle->dvh.matcher)
14309 			flow_dv_matcher_release(dev, dev_handle);
14310 		if (dev_handle->dvh.rix_sample)
14311 			flow_dv_sample_resource_release(dev, dev_handle);
14312 		if (dev_handle->dvh.rix_dest_array)
14313 			flow_dv_dest_array_resource_release(dev, dev_handle);
14314 		if (dev_handle->dvh.rix_encap_decap)
14315 			flow_dv_encap_decap_resource_release(dev,
14316 				dev_handle->dvh.rix_encap_decap);
14317 		if (dev_handle->dvh.modify_hdr)
14318 			flow_dv_modify_hdr_resource_release(dev, dev_handle);
14319 		if (dev_handle->dvh.rix_push_vlan)
14320 			flow_dv_push_vlan_action_resource_release(dev,
14321 								  dev_handle);
14322 		if (dev_handle->dvh.rix_tag)
14323 			flow_dv_tag_release(dev,
14324 					    dev_handle->dvh.rix_tag);
14325 		if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS)
14326 			flow_dv_fate_resource_release(dev, dev_handle);
14327 		else if (!srss)
14328 			srss = dev_handle->rix_srss;
14329 		if (fm && dev_handle->is_meter_flow_id &&
14330 		    dev_handle->split_flow_id)
14331 			mlx5_ipool_free(fm->flow_ipool,
14332 					dev_handle->split_flow_id);
14333 		else if (dev_handle->split_flow_id &&
14334 		    !dev_handle->is_meter_flow_id)
14335 			mlx5_ipool_free(priv->sh->ipool
14336 					[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID],
14337 					dev_handle->split_flow_id);
14338 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
14339 			   tmp_idx);
14340 	}
14341 	if (srss)
14342 		flow_dv_shared_rss_action_release(dev, srss);
14343 }
14344 
14345 /**
14346  * Release array of hash RX queue objects.
14347  * Helper function.
14348  *
14349  * @param[in] dev
14350  *   Pointer to the Ethernet device structure.
14351  * @param[in, out] hrxqs
14352  *   Array of hash RX queue objects.
14353  *
14354  * @return
14355  *   Total number of references to hash RX queue objects in *hrxqs* array
14356  *   after this operation.
14357  */
14358 static int
14359 __flow_dv_hrxqs_release(struct rte_eth_dev *dev,
14360 			uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN])
14361 {
14362 	size_t i;
14363 	int remaining = 0;
14364 
14365 	for (i = 0; i < RTE_DIM(*hrxqs); i++) {
14366 		int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]);
14367 
14368 		if (!ret)
14369 			(*hrxqs)[i] = 0;
14370 		remaining += ret;
14371 	}
14372 	return remaining;
14373 }
14374 
14375 /**
14376  * Release all hash RX queue objects representing shared RSS action.
14377  *
14378  * @param[in] dev
14379  *   Pointer to the Ethernet device structure.
14380  * @param[in, out] action
14381  *   Shared RSS action to remove hash RX queue objects from.
14382  *
14383  * @return
14384  *   Total number of references to hash RX queue objects stored in *action*
14385  *   after this operation.
14386  *   Expected to be 0 if no external references held.
14387  */
14388 static int
14389 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev,
14390 				 struct mlx5_shared_action_rss *shared_rss)
14391 {
14392 	return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq);
14393 }
14394 
14395 /**
14396  * Adjust L3/L4 hash value of pre-created shared RSS hrxq according to
14397  * user input.
14398  *
14399  * Only one hash value is available for one L3+L4 combination:
14400  * for example:
14401  * MLX5_RSS_HASH_IPV4, MLX5_RSS_HASH_IPV4_SRC_ONLY, and
14402  * MLX5_RSS_HASH_IPV4_DST_ONLY are mutually exclusive so they can share
14403  * same slot in mlx5_rss_hash_fields.
14404  *
14405  * @param[in] rss
14406  *   Pointer to the shared action RSS conf.
14407  * @param[in, out] hash_field
14408  *   hash_field variable needed to be adjusted.
14409  *
14410  * @return
14411  *   void
14412  */
14413 static void
14414 __flow_dv_action_rss_l34_hash_adjust(struct mlx5_shared_action_rss *rss,
14415 				     uint64_t *hash_field)
14416 {
14417 	uint64_t rss_types = rss->origin.types;
14418 
14419 	switch (*hash_field & ~IBV_RX_HASH_INNER) {
14420 	case MLX5_RSS_HASH_IPV4:
14421 		if (rss_types & MLX5_IPV4_LAYER_TYPES) {
14422 			*hash_field &= ~MLX5_RSS_HASH_IPV4;
14423 			if (rss_types & ETH_RSS_L3_DST_ONLY)
14424 				*hash_field |= IBV_RX_HASH_DST_IPV4;
14425 			else if (rss_types & ETH_RSS_L3_SRC_ONLY)
14426 				*hash_field |= IBV_RX_HASH_SRC_IPV4;
14427 			else
14428 				*hash_field |= MLX5_RSS_HASH_IPV4;
14429 		}
14430 		return;
14431 	case MLX5_RSS_HASH_IPV6:
14432 		if (rss_types & MLX5_IPV6_LAYER_TYPES) {
14433 			*hash_field &= ~MLX5_RSS_HASH_IPV6;
14434 			if (rss_types & ETH_RSS_L3_DST_ONLY)
14435 				*hash_field |= IBV_RX_HASH_DST_IPV6;
14436 			else if (rss_types & ETH_RSS_L3_SRC_ONLY)
14437 				*hash_field |= IBV_RX_HASH_SRC_IPV6;
14438 			else
14439 				*hash_field |= MLX5_RSS_HASH_IPV6;
14440 		}
14441 		return;
14442 	case MLX5_RSS_HASH_IPV4_UDP:
14443 		/* fall-through. */
14444 	case MLX5_RSS_HASH_IPV6_UDP:
14445 		if (rss_types & ETH_RSS_UDP) {
14446 			*hash_field &= ~MLX5_UDP_IBV_RX_HASH;
14447 			if (rss_types & ETH_RSS_L4_DST_ONLY)
14448 				*hash_field |= IBV_RX_HASH_DST_PORT_UDP;
14449 			else if (rss_types & ETH_RSS_L4_SRC_ONLY)
14450 				*hash_field |= IBV_RX_HASH_SRC_PORT_UDP;
14451 			else
14452 				*hash_field |= MLX5_UDP_IBV_RX_HASH;
14453 		}
14454 		return;
14455 	case MLX5_RSS_HASH_IPV4_TCP:
14456 		/* fall-through. */
14457 	case MLX5_RSS_HASH_IPV6_TCP:
14458 		if (rss_types & ETH_RSS_TCP) {
14459 			*hash_field &= ~MLX5_TCP_IBV_RX_HASH;
14460 			if (rss_types & ETH_RSS_L4_DST_ONLY)
14461 				*hash_field |= IBV_RX_HASH_DST_PORT_TCP;
14462 			else if (rss_types & ETH_RSS_L4_SRC_ONLY)
14463 				*hash_field |= IBV_RX_HASH_SRC_PORT_TCP;
14464 			else
14465 				*hash_field |= MLX5_TCP_IBV_RX_HASH;
14466 		}
14467 		return;
14468 	default:
14469 		return;
14470 	}
14471 }
14472 
14473 /**
14474  * Setup shared RSS action.
14475  * Prepare set of hash RX queue objects sufficient to handle all valid
14476  * hash_fields combinations (see enum ibv_rx_hash_fields).
14477  *
14478  * @param[in] dev
14479  *   Pointer to the Ethernet device structure.
14480  * @param[in] action_idx
14481  *   Shared RSS action ipool index.
14482  * @param[in, out] action
14483  *   Partially initialized shared RSS action.
14484  * @param[out] error
14485  *   Perform verbose error reporting if not NULL. Initialized in case of
14486  *   error only.
14487  *
14488  * @return
14489  *   0 on success, otherwise negative errno value.
14490  */
14491 static int
14492 __flow_dv_action_rss_setup(struct rte_eth_dev *dev,
14493 			   uint32_t action_idx,
14494 			   struct mlx5_shared_action_rss *shared_rss,
14495 			   struct rte_flow_error *error)
14496 {
14497 	struct mlx5_flow_rss_desc rss_desc = { 0 };
14498 	size_t i;
14499 	int err;
14500 
14501 	if (mlx5_ind_table_obj_setup(dev, shared_rss->ind_tbl)) {
14502 		return rte_flow_error_set(error, rte_errno,
14503 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14504 					  "cannot setup indirection table");
14505 	}
14506 	memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN);
14507 	rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN;
14508 	rss_desc.const_q = shared_rss->origin.queue;
14509 	rss_desc.queue_num = shared_rss->origin.queue_num;
14510 	/* Set non-zero value to indicate a shared RSS. */
14511 	rss_desc.shared_rss = action_idx;
14512 	rss_desc.ind_tbl = shared_rss->ind_tbl;
14513 	for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) {
14514 		uint32_t hrxq_idx;
14515 		uint64_t hash_fields = mlx5_rss_hash_fields[i];
14516 		int tunnel = 0;
14517 
14518 		__flow_dv_action_rss_l34_hash_adjust(shared_rss, &hash_fields);
14519 		if (shared_rss->origin.level > 1) {
14520 			hash_fields |= IBV_RX_HASH_INNER;
14521 			tunnel = 1;
14522 		}
14523 		rss_desc.tunnel = tunnel;
14524 		rss_desc.hash_fields = hash_fields;
14525 		hrxq_idx = mlx5_hrxq_get(dev, &rss_desc);
14526 		if (!hrxq_idx) {
14527 			rte_flow_error_set
14528 				(error, rte_errno,
14529 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14530 				 "cannot get hash queue");
14531 			goto error_hrxq_new;
14532 		}
14533 		err = __flow_dv_action_rss_hrxq_set
14534 			(shared_rss, hash_fields, hrxq_idx);
14535 		MLX5_ASSERT(!err);
14536 	}
14537 	return 0;
14538 error_hrxq_new:
14539 	err = rte_errno;
14540 	__flow_dv_action_rss_hrxqs_release(dev, shared_rss);
14541 	if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true))
14542 		shared_rss->ind_tbl = NULL;
14543 	rte_errno = err;
14544 	return -rte_errno;
14545 }
14546 
14547 /**
14548  * Create shared RSS action.
14549  *
14550  * @param[in] dev
14551  *   Pointer to the Ethernet device structure.
14552  * @param[in] conf
14553  *   Shared action configuration.
14554  * @param[in] rss
14555  *   RSS action specification used to create shared action.
14556  * @param[out] error
14557  *   Perform verbose error reporting if not NULL. Initialized in case of
14558  *   error only.
14559  *
14560  * @return
14561  *   A valid shared action ID in case of success, 0 otherwise and
14562  *   rte_errno is set.
14563  */
14564 static uint32_t
14565 __flow_dv_action_rss_create(struct rte_eth_dev *dev,
14566 			    const struct rte_flow_indir_action_conf *conf,
14567 			    const struct rte_flow_action_rss *rss,
14568 			    struct rte_flow_error *error)
14569 {
14570 	struct mlx5_priv *priv = dev->data->dev_private;
14571 	struct mlx5_shared_action_rss *shared_rss = NULL;
14572 	void *queue = NULL;
14573 	struct rte_flow_action_rss *origin;
14574 	const uint8_t *rss_key;
14575 	uint32_t queue_size = rss->queue_num * sizeof(uint16_t);
14576 	uint32_t idx;
14577 
14578 	RTE_SET_USED(conf);
14579 	queue = mlx5_malloc(0, RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
14580 			    0, SOCKET_ID_ANY);
14581 	shared_rss = mlx5_ipool_zmalloc
14582 			 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx);
14583 	if (!shared_rss || !queue) {
14584 		rte_flow_error_set(error, ENOMEM,
14585 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14586 				   "cannot allocate resource memory");
14587 		goto error_rss_init;
14588 	}
14589 	if (idx > (1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET)) {
14590 		rte_flow_error_set(error, E2BIG,
14591 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14592 				   "rss action number out of range");
14593 		goto error_rss_init;
14594 	}
14595 	shared_rss->ind_tbl = mlx5_malloc(MLX5_MEM_ZERO,
14596 					  sizeof(*shared_rss->ind_tbl),
14597 					  0, SOCKET_ID_ANY);
14598 	if (!shared_rss->ind_tbl) {
14599 		rte_flow_error_set(error, ENOMEM,
14600 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14601 				   "cannot allocate resource memory");
14602 		goto error_rss_init;
14603 	}
14604 	memcpy(queue, rss->queue, queue_size);
14605 	shared_rss->ind_tbl->queues = queue;
14606 	shared_rss->ind_tbl->queues_n = rss->queue_num;
14607 	origin = &shared_rss->origin;
14608 	origin->func = rss->func;
14609 	origin->level = rss->level;
14610 	/* RSS type 0 indicates default RSS type (ETH_RSS_IP). */
14611 	origin->types = !rss->types ? ETH_RSS_IP : rss->types;
14612 	/* NULL RSS key indicates default RSS key. */
14613 	rss_key = !rss->key ? rss_hash_default_key : rss->key;
14614 	memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
14615 	origin->key = &shared_rss->key[0];
14616 	origin->key_len = MLX5_RSS_HASH_KEY_LEN;
14617 	origin->queue = queue;
14618 	origin->queue_num = rss->queue_num;
14619 	if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error))
14620 		goto error_rss_init;
14621 	rte_spinlock_init(&shared_rss->action_rss_sl);
14622 	__atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
14623 	rte_spinlock_lock(&priv->shared_act_sl);
14624 	ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14625 		     &priv->rss_shared_actions, idx, shared_rss, next);
14626 	rte_spinlock_unlock(&priv->shared_act_sl);
14627 	return idx;
14628 error_rss_init:
14629 	if (shared_rss) {
14630 		if (shared_rss->ind_tbl)
14631 			mlx5_free(shared_rss->ind_tbl);
14632 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14633 				idx);
14634 	}
14635 	if (queue)
14636 		mlx5_free(queue);
14637 	return 0;
14638 }
14639 
14640 /**
14641  * Destroy the shared RSS action.
14642  * Release related hash RX queue objects.
14643  *
14644  * @param[in] dev
14645  *   Pointer to the Ethernet device structure.
14646  * @param[in] idx
14647  *   The shared RSS action object ID to be removed.
14648  * @param[out] error
14649  *   Perform verbose error reporting if not NULL. Initialized in case of
14650  *   error only.
14651  *
14652  * @return
14653  *   0 on success, otherwise negative errno value.
14654  */
14655 static int
14656 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx,
14657 			     struct rte_flow_error *error)
14658 {
14659 	struct mlx5_priv *priv = dev->data->dev_private;
14660 	struct mlx5_shared_action_rss *shared_rss =
14661 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
14662 	uint32_t old_refcnt = 1;
14663 	int remaining;
14664 	uint16_t *queue = NULL;
14665 
14666 	if (!shared_rss)
14667 		return rte_flow_error_set(error, EINVAL,
14668 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14669 					  "invalid shared action");
14670 	if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt,
14671 					 0, 0, __ATOMIC_ACQUIRE,
14672 					 __ATOMIC_RELAXED))
14673 		return rte_flow_error_set(error, EBUSY,
14674 					  RTE_FLOW_ERROR_TYPE_ACTION,
14675 					  NULL,
14676 					  "shared rss has references");
14677 	remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss);
14678 	if (remaining)
14679 		return rte_flow_error_set(error, EBUSY,
14680 					  RTE_FLOW_ERROR_TYPE_ACTION,
14681 					  NULL,
14682 					  "shared rss hrxq has references");
14683 	queue = shared_rss->ind_tbl->queues;
14684 	remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true);
14685 	if (remaining)
14686 		return rte_flow_error_set(error, EBUSY,
14687 					  RTE_FLOW_ERROR_TYPE_ACTION,
14688 					  NULL,
14689 					  "shared rss indirection table has"
14690 					  " references");
14691 	mlx5_free(queue);
14692 	rte_spinlock_lock(&priv->shared_act_sl);
14693 	ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14694 		     &priv->rss_shared_actions, idx, shared_rss, next);
14695 	rte_spinlock_unlock(&priv->shared_act_sl);
14696 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14697 			idx);
14698 	return 0;
14699 }
14700 
14701 /**
14702  * Create indirect action, lock free,
14703  * (mutex should be acquired by caller).
14704  * Dispatcher for action type specific call.
14705  *
14706  * @param[in] dev
14707  *   Pointer to the Ethernet device structure.
14708  * @param[in] conf
14709  *   Shared action configuration.
14710  * @param[in] action
14711  *   Action specification used to create indirect action.
14712  * @param[out] error
14713  *   Perform verbose error reporting if not NULL. Initialized in case of
14714  *   error only.
14715  *
14716  * @return
14717  *   A valid shared action handle in case of success, NULL otherwise and
14718  *   rte_errno is set.
14719  */
14720 static struct rte_flow_action_handle *
14721 flow_dv_action_create(struct rte_eth_dev *dev,
14722 		      const struct rte_flow_indir_action_conf *conf,
14723 		      const struct rte_flow_action *action,
14724 		      struct rte_flow_error *err)
14725 {
14726 	struct mlx5_priv *priv = dev->data->dev_private;
14727 	uint32_t age_idx = 0;
14728 	uint32_t idx = 0;
14729 	uint32_t ret = 0;
14730 
14731 	switch (action->type) {
14732 	case RTE_FLOW_ACTION_TYPE_RSS:
14733 		ret = __flow_dv_action_rss_create(dev, conf, action->conf, err);
14734 		idx = (MLX5_INDIRECT_ACTION_TYPE_RSS <<
14735 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
14736 		break;
14737 	case RTE_FLOW_ACTION_TYPE_AGE:
14738 		age_idx = flow_dv_aso_age_alloc(dev, err);
14739 		if (!age_idx) {
14740 			ret = -rte_errno;
14741 			break;
14742 		}
14743 		idx = (MLX5_INDIRECT_ACTION_TYPE_AGE <<
14744 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx;
14745 		flow_dv_aso_age_params_init(dev, age_idx,
14746 					((const struct rte_flow_action_age *)
14747 						action->conf)->context ?
14748 					((const struct rte_flow_action_age *)
14749 						action->conf)->context :
14750 					(void *)(uintptr_t)idx,
14751 					((const struct rte_flow_action_age *)
14752 						action->conf)->timeout);
14753 		ret = age_idx;
14754 		break;
14755 	case RTE_FLOW_ACTION_TYPE_COUNT:
14756 		ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL);
14757 		idx = (MLX5_INDIRECT_ACTION_TYPE_COUNT <<
14758 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
14759 		break;
14760 	case RTE_FLOW_ACTION_TYPE_CONNTRACK:
14761 		ret = flow_dv_translate_create_conntrack(dev, action->conf,
14762 							 err);
14763 		idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret);
14764 		break;
14765 	default:
14766 		rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
14767 				   NULL, "action type not supported");
14768 		break;
14769 	}
14770 	return ret ? (struct rte_flow_action_handle *)(uintptr_t)idx : NULL;
14771 }
14772 
14773 /**
14774  * Destroy the indirect action.
14775  * Release action related resources on the NIC and the memory.
14776  * Lock free, (mutex should be acquired by caller).
14777  * Dispatcher for action type specific call.
14778  *
14779  * @param[in] dev
14780  *   Pointer to the Ethernet device structure.
14781  * @param[in] handle
14782  *   The indirect action object handle to be removed.
14783  * @param[out] error
14784  *   Perform verbose error reporting if not NULL. Initialized in case of
14785  *   error only.
14786  *
14787  * @return
14788  *   0 on success, otherwise negative errno value.
14789  */
14790 static int
14791 flow_dv_action_destroy(struct rte_eth_dev *dev,
14792 		       struct rte_flow_action_handle *handle,
14793 		       struct rte_flow_error *error)
14794 {
14795 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
14796 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
14797 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
14798 	struct mlx5_flow_counter *cnt;
14799 	uint32_t no_flow_refcnt = 1;
14800 	int ret;
14801 
14802 	switch (type) {
14803 	case MLX5_INDIRECT_ACTION_TYPE_RSS:
14804 		return __flow_dv_action_rss_release(dev, idx, error);
14805 	case MLX5_INDIRECT_ACTION_TYPE_COUNT:
14806 		cnt = flow_dv_counter_get_by_idx(dev, idx, NULL);
14807 		if (!__atomic_compare_exchange_n(&cnt->shared_info.refcnt,
14808 						 &no_flow_refcnt, 1, false,
14809 						 __ATOMIC_ACQUIRE,
14810 						 __ATOMIC_RELAXED))
14811 			return rte_flow_error_set(error, EBUSY,
14812 						  RTE_FLOW_ERROR_TYPE_ACTION,
14813 						  NULL,
14814 						  "Indirect count action has references");
14815 		flow_dv_counter_free(dev, idx);
14816 		return 0;
14817 	case MLX5_INDIRECT_ACTION_TYPE_AGE:
14818 		ret = flow_dv_aso_age_release(dev, idx);
14819 		if (ret)
14820 			/*
14821 			 * In this case, the last flow has a reference will
14822 			 * actually release the age action.
14823 			 */
14824 			DRV_LOG(DEBUG, "Indirect age action %" PRIu32 " was"
14825 				" released with references %d.", idx, ret);
14826 		return 0;
14827 	case MLX5_INDIRECT_ACTION_TYPE_CT:
14828 		ret = flow_dv_aso_ct_release(dev, idx, error);
14829 		if (ret < 0)
14830 			return ret;
14831 		if (ret > 0)
14832 			DRV_LOG(DEBUG, "Connection tracking object %u still "
14833 				"has references %d.", idx, ret);
14834 		return 0;
14835 	default:
14836 		return rte_flow_error_set(error, ENOTSUP,
14837 					  RTE_FLOW_ERROR_TYPE_ACTION,
14838 					  NULL,
14839 					  "action type not supported");
14840 	}
14841 }
14842 
14843 /**
14844  * Updates in place shared RSS action configuration.
14845  *
14846  * @param[in] dev
14847  *   Pointer to the Ethernet device structure.
14848  * @param[in] idx
14849  *   The shared RSS action object ID to be updated.
14850  * @param[in] action_conf
14851  *   RSS action specification used to modify *shared_rss*.
14852  * @param[out] error
14853  *   Perform verbose error reporting if not NULL. Initialized in case of
14854  *   error only.
14855  *
14856  * @return
14857  *   0 on success, otherwise negative errno value.
14858  * @note: currently only support update of RSS queues.
14859  */
14860 static int
14861 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx,
14862 			    const struct rte_flow_action_rss *action_conf,
14863 			    struct rte_flow_error *error)
14864 {
14865 	struct mlx5_priv *priv = dev->data->dev_private;
14866 	struct mlx5_shared_action_rss *shared_rss =
14867 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
14868 	int ret = 0;
14869 	void *queue = NULL;
14870 	uint16_t *queue_old = NULL;
14871 	uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t);
14872 
14873 	if (!shared_rss)
14874 		return rte_flow_error_set(error, EINVAL,
14875 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14876 					  "invalid shared action to update");
14877 	if (priv->obj_ops.ind_table_modify == NULL)
14878 		return rte_flow_error_set(error, ENOTSUP,
14879 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14880 					  "cannot modify indirection table");
14881 	queue = mlx5_malloc(MLX5_MEM_ZERO,
14882 			    RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
14883 			    0, SOCKET_ID_ANY);
14884 	if (!queue)
14885 		return rte_flow_error_set(error, ENOMEM,
14886 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14887 					  NULL,
14888 					  "cannot allocate resource memory");
14889 	memcpy(queue, action_conf->queue, queue_size);
14890 	MLX5_ASSERT(shared_rss->ind_tbl);
14891 	rte_spinlock_lock(&shared_rss->action_rss_sl);
14892 	queue_old = shared_rss->ind_tbl->queues;
14893 	ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl,
14894 					queue, action_conf->queue_num, true);
14895 	if (ret) {
14896 		mlx5_free(queue);
14897 		ret = rte_flow_error_set(error, rte_errno,
14898 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14899 					  "cannot update indirection table");
14900 	} else {
14901 		mlx5_free(queue_old);
14902 		shared_rss->origin.queue = queue;
14903 		shared_rss->origin.queue_num = action_conf->queue_num;
14904 	}
14905 	rte_spinlock_unlock(&shared_rss->action_rss_sl);
14906 	return ret;
14907 }
14908 
14909 /*
14910  * Updates in place conntrack context or direction.
14911  * Context update should be synchronized.
14912  *
14913  * @param[in] dev
14914  *   Pointer to the Ethernet device structure.
14915  * @param[in] idx
14916  *   The conntrack object ID to be updated.
14917  * @param[in] update
14918  *   Pointer to the structure of information to update.
14919  * @param[out] error
14920  *   Perform verbose error reporting if not NULL. Initialized in case of
14921  *   error only.
14922  *
14923  * @return
14924  *   0 on success, otherwise negative errno value.
14925  */
14926 static int
14927 __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx,
14928 			   const struct rte_flow_modify_conntrack *update,
14929 			   struct rte_flow_error *error)
14930 {
14931 	struct mlx5_priv *priv = dev->data->dev_private;
14932 	struct mlx5_aso_ct_action *ct;
14933 	const struct rte_flow_action_conntrack *new_prf;
14934 	int ret = 0;
14935 	uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
14936 	uint32_t dev_idx;
14937 
14938 	if (PORT_ID(priv) != owner)
14939 		return rte_flow_error_set(error, EACCES,
14940 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14941 					  NULL,
14942 					  "CT object owned by another port");
14943 	dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
14944 	ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
14945 	if (!ct->refcnt)
14946 		return rte_flow_error_set(error, ENOMEM,
14947 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14948 					  NULL,
14949 					  "CT object is inactive");
14950 	new_prf = &update->new_ct;
14951 	if (update->direction)
14952 		ct->is_original = !!new_prf->is_original_dir;
14953 	if (update->state) {
14954 		/* Only validate the profile when it needs to be updated. */
14955 		ret = mlx5_validate_action_ct(dev, new_prf, error);
14956 		if (ret)
14957 			return ret;
14958 		ret = mlx5_aso_ct_update_by_wqe(priv->sh, ct, new_prf);
14959 		if (ret)
14960 			return rte_flow_error_set(error, EIO,
14961 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14962 					NULL,
14963 					"Failed to send CT context update WQE");
14964 		/* Block until ready or a failure. */
14965 		ret = mlx5_aso_ct_available(priv->sh, ct);
14966 		if (ret)
14967 			rte_flow_error_set(error, rte_errno,
14968 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14969 					   NULL,
14970 					   "Timeout to get the CT update");
14971 	}
14972 	return ret;
14973 }
14974 
14975 /**
14976  * Updates in place shared action configuration, lock free,
14977  * (mutex should be acquired by caller).
14978  *
14979  * @param[in] dev
14980  *   Pointer to the Ethernet device structure.
14981  * @param[in] handle
14982  *   The indirect action object handle to be updated.
14983  * @param[in] update
14984  *   Action specification used to modify the action pointed by *handle*.
14985  *   *update* could be of same type with the action pointed by the *handle*
14986  *   handle argument, or some other structures like a wrapper, depending on
14987  *   the indirect action type.
14988  * @param[out] error
14989  *   Perform verbose error reporting if not NULL. Initialized in case of
14990  *   error only.
14991  *
14992  * @return
14993  *   0 on success, otherwise negative errno value.
14994  */
14995 static int
14996 flow_dv_action_update(struct rte_eth_dev *dev,
14997 			struct rte_flow_action_handle *handle,
14998 			const void *update,
14999 			struct rte_flow_error *err)
15000 {
15001 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15002 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15003 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15004 	const void *action_conf;
15005 
15006 	switch (type) {
15007 	case MLX5_INDIRECT_ACTION_TYPE_RSS:
15008 		action_conf = ((const struct rte_flow_action *)update)->conf;
15009 		return __flow_dv_action_rss_update(dev, idx, action_conf, err);
15010 	case MLX5_INDIRECT_ACTION_TYPE_CT:
15011 		return __flow_dv_action_ct_update(dev, idx, update, err);
15012 	default:
15013 		return rte_flow_error_set(err, ENOTSUP,
15014 					  RTE_FLOW_ERROR_TYPE_ACTION,
15015 					  NULL,
15016 					  "action type update not supported");
15017 	}
15018 }
15019 
15020 /**
15021  * Destroy the meter sub policy table rules.
15022  * Lock free, (mutex should be acquired by caller).
15023  *
15024  * @param[in] dev
15025  *   Pointer to Ethernet device.
15026  * @param[in] sub_policy
15027  *   Pointer to meter sub policy table.
15028  */
15029 static void
15030 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
15031 			     struct mlx5_flow_meter_sub_policy *sub_policy)
15032 {
15033 	struct mlx5_priv *priv = dev->data->dev_private;
15034 	struct mlx5_flow_tbl_data_entry *tbl;
15035 	struct mlx5_flow_meter_policy *policy = sub_policy->main_policy;
15036 	struct mlx5_flow_meter_info *next_fm;
15037 	struct mlx5_sub_policy_color_rule *color_rule;
15038 	void *tmp;
15039 	uint32_t i;
15040 
15041 	for (i = 0; i < RTE_COLORS; i++) {
15042 		next_fm = NULL;
15043 		if (i == RTE_COLOR_GREEN && policy &&
15044 		    policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
15045 			next_fm = mlx5_flow_meter_find(priv,
15046 					policy->act_cnt[i].next_mtr_id, NULL);
15047 		RTE_TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i],
15048 				   next_port, tmp) {
15049 			claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule));
15050 			tbl = container_of(color_rule->matcher->tbl,
15051 					   typeof(*tbl), tbl);
15052 			mlx5_list_unregister(tbl->matchers,
15053 					     &color_rule->matcher->entry);
15054 			TAILQ_REMOVE(&sub_policy->color_rules[i],
15055 				     color_rule, next_port);
15056 			mlx5_free(color_rule);
15057 			if (next_fm)
15058 				mlx5_flow_meter_detach(priv, next_fm);
15059 		}
15060 	}
15061 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
15062 		if (sub_policy->rix_hrxq[i]) {
15063 			if (policy && !policy->is_hierarchy)
15064 				mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
15065 			sub_policy->rix_hrxq[i] = 0;
15066 		}
15067 		if (sub_policy->jump_tbl[i]) {
15068 			flow_dv_tbl_resource_release(MLX5_SH(dev),
15069 						     sub_policy->jump_tbl[i]);
15070 			sub_policy->jump_tbl[i] = NULL;
15071 		}
15072 	}
15073 	if (sub_policy->tbl_rsc) {
15074 		flow_dv_tbl_resource_release(MLX5_SH(dev),
15075 					     sub_policy->tbl_rsc);
15076 		sub_policy->tbl_rsc = NULL;
15077 	}
15078 }
15079 
15080 /**
15081  * Destroy policy rules, lock free,
15082  * (mutex should be acquired by caller).
15083  * Dispatcher for action type specific call.
15084  *
15085  * @param[in] dev
15086  *   Pointer to the Ethernet device structure.
15087  * @param[in] mtr_policy
15088  *   Meter policy struct.
15089  */
15090 static void
15091 flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
15092 			     struct mlx5_flow_meter_policy *mtr_policy)
15093 {
15094 	uint32_t i, j;
15095 	struct mlx5_flow_meter_sub_policy *sub_policy;
15096 	uint16_t sub_policy_num;
15097 
15098 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15099 		sub_policy_num = (mtr_policy->sub_policy_num >>
15100 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
15101 			MLX5_MTR_SUB_POLICY_NUM_MASK;
15102 		for (j = 0; j < sub_policy_num; j++) {
15103 			sub_policy = mtr_policy->sub_policys[i][j];
15104 			if (sub_policy)
15105 				__flow_dv_destroy_sub_policy_rules(dev,
15106 								   sub_policy);
15107 		}
15108 	}
15109 }
15110 
15111 /**
15112  * Destroy policy action, lock free,
15113  * (mutex should be acquired by caller).
15114  * Dispatcher for action type specific call.
15115  *
15116  * @param[in] dev
15117  *   Pointer to the Ethernet device structure.
15118  * @param[in] mtr_policy
15119  *   Meter policy struct.
15120  */
15121 static void
15122 flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
15123 		      struct mlx5_flow_meter_policy *mtr_policy)
15124 {
15125 	struct rte_flow_action *rss_action;
15126 	struct mlx5_flow_handle dev_handle;
15127 	uint32_t i, j;
15128 
15129 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
15130 		if (mtr_policy->act_cnt[i].rix_mark) {
15131 			flow_dv_tag_release(dev,
15132 				mtr_policy->act_cnt[i].rix_mark);
15133 			mtr_policy->act_cnt[i].rix_mark = 0;
15134 		}
15135 		if (mtr_policy->act_cnt[i].modify_hdr) {
15136 			dev_handle.dvh.modify_hdr =
15137 				mtr_policy->act_cnt[i].modify_hdr;
15138 			flow_dv_modify_hdr_resource_release(dev, &dev_handle);
15139 		}
15140 		switch (mtr_policy->act_cnt[i].fate_action) {
15141 		case MLX5_FLOW_FATE_SHARED_RSS:
15142 			rss_action = mtr_policy->act_cnt[i].rss;
15143 			mlx5_free(rss_action);
15144 			break;
15145 		case MLX5_FLOW_FATE_PORT_ID:
15146 			if (mtr_policy->act_cnt[i].rix_port_id_action) {
15147 				flow_dv_port_id_action_resource_release(dev,
15148 				mtr_policy->act_cnt[i].rix_port_id_action);
15149 				mtr_policy->act_cnt[i].rix_port_id_action = 0;
15150 			}
15151 			break;
15152 		case MLX5_FLOW_FATE_DROP:
15153 		case MLX5_FLOW_FATE_JUMP:
15154 			for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
15155 				mtr_policy->act_cnt[i].dr_jump_action[j] =
15156 						NULL;
15157 			break;
15158 		default:
15159 			/*Queue action do nothing*/
15160 			break;
15161 		}
15162 	}
15163 	for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
15164 		mtr_policy->dr_drop_action[j] = NULL;
15165 }
15166 
15167 /**
15168  * Create policy action per domain, lock free,
15169  * (mutex should be acquired by caller).
15170  * Dispatcher for action type specific call.
15171  *
15172  * @param[in] dev
15173  *   Pointer to the Ethernet device structure.
15174  * @param[in] mtr_policy
15175  *   Meter policy struct.
15176  * @param[in] action
15177  *   Action specification used to create meter actions.
15178  * @param[out] error
15179  *   Perform verbose error reporting if not NULL. Initialized in case of
15180  *   error only.
15181  *
15182  * @return
15183  *   0 on success, otherwise negative errno value.
15184  */
15185 static int
15186 __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
15187 			struct mlx5_flow_meter_policy *mtr_policy,
15188 			const struct rte_flow_action *actions[RTE_COLORS],
15189 			enum mlx5_meter_domain domain,
15190 			struct rte_mtr_error *error)
15191 {
15192 	struct mlx5_priv *priv = dev->data->dev_private;
15193 	struct rte_flow_error flow_err;
15194 	const struct rte_flow_action *act;
15195 	uint64_t action_flags;
15196 	struct mlx5_flow_handle dh;
15197 	struct mlx5_flow dev_flow;
15198 	struct mlx5_flow_dv_port_id_action_resource port_id_action;
15199 	int i, ret;
15200 	uint8_t egress, transfer;
15201 	struct mlx5_meter_policy_action_container *act_cnt = NULL;
15202 	union {
15203 		struct mlx5_flow_dv_modify_hdr_resource res;
15204 		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
15205 			    sizeof(struct mlx5_modification_cmd) *
15206 			    (MLX5_MAX_MODIFY_NUM + 1)];
15207 	} mhdr_dummy;
15208 	struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
15209 
15210 	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
15211 	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
15212 	memset(&dh, 0, sizeof(struct mlx5_flow_handle));
15213 	memset(&dev_flow, 0, sizeof(struct mlx5_flow));
15214 	memset(&port_id_action, 0,
15215 	       sizeof(struct mlx5_flow_dv_port_id_action_resource));
15216 	memset(mhdr_res, 0, sizeof(*mhdr_res));
15217 	mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
15218 				       (egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
15219 					MLX5DV_FLOW_TABLE_TYPE_NIC_RX);
15220 	dev_flow.handle = &dh;
15221 	dev_flow.dv.port_id_action = &port_id_action;
15222 	dev_flow.external = true;
15223 	for (i = 0; i < RTE_COLORS; i++) {
15224 		if (i < MLX5_MTR_RTE_COLORS)
15225 			act_cnt = &mtr_policy->act_cnt[i];
15226 		/* Skip the color policy actions creation. */
15227 		if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) ||
15228 		    (i == RTE_COLOR_GREEN && mtr_policy->skip_g))
15229 			continue;
15230 		action_flags = 0;
15231 		for (act = actions[i];
15232 		     act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
15233 			switch (act->type) {
15234 			case RTE_FLOW_ACTION_TYPE_MARK:
15235 			{
15236 				uint32_t tag_be = mlx5_flow_mark_set
15237 					(((const struct rte_flow_action_mark *)
15238 					(act->conf))->id);
15239 
15240 				if (i >= MLX5_MTR_RTE_COLORS)
15241 					return -rte_mtr_error_set(error,
15242 					  ENOTSUP,
15243 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15244 					  NULL,
15245 					  "cannot create policy "
15246 					  "mark action for this color");
15247 				dev_flow.handle->mark = 1;
15248 				if (flow_dv_tag_resource_register(dev, tag_be,
15249 						  &dev_flow, &flow_err))
15250 					return -rte_mtr_error_set(error,
15251 					ENOTSUP,
15252 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15253 					NULL,
15254 					"cannot setup policy mark action");
15255 				MLX5_ASSERT(dev_flow.dv.tag_resource);
15256 				act_cnt->rix_mark =
15257 					dev_flow.handle->dvh.rix_tag;
15258 				action_flags |= MLX5_FLOW_ACTION_MARK;
15259 				break;
15260 			}
15261 			case RTE_FLOW_ACTION_TYPE_SET_TAG:
15262 				if (i >= MLX5_MTR_RTE_COLORS)
15263 					return -rte_mtr_error_set(error,
15264 					  ENOTSUP,
15265 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15266 					  NULL,
15267 					  "cannot create policy "
15268 					  "set tag action for this color");
15269 				if (flow_dv_convert_action_set_tag
15270 				(dev, mhdr_res,
15271 				(const struct rte_flow_action_set_tag *)
15272 				act->conf,  &flow_err))
15273 					return -rte_mtr_error_set(error,
15274 					ENOTSUP,
15275 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15276 					NULL, "cannot convert policy "
15277 					"set tag action");
15278 				if (!mhdr_res->actions_num)
15279 					return -rte_mtr_error_set(error,
15280 					ENOTSUP,
15281 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15282 					NULL, "cannot find policy "
15283 					"set tag action");
15284 				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
15285 				break;
15286 			case RTE_FLOW_ACTION_TYPE_DROP:
15287 			{
15288 				struct mlx5_flow_mtr_mng *mtrmng =
15289 						priv->sh->mtrmng;
15290 				struct mlx5_flow_tbl_data_entry *tbl_data;
15291 
15292 				/*
15293 				 * Create the drop table with
15294 				 * METER DROP level.
15295 				 */
15296 				if (!mtrmng->drop_tbl[domain]) {
15297 					mtrmng->drop_tbl[domain] =
15298 					flow_dv_tbl_resource_get(dev,
15299 					MLX5_FLOW_TABLE_LEVEL_METER,
15300 					egress, transfer, false, NULL, 0,
15301 					0, MLX5_MTR_TABLE_ID_DROP, &flow_err);
15302 					if (!mtrmng->drop_tbl[domain])
15303 						return -rte_mtr_error_set
15304 					(error, ENOTSUP,
15305 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15306 					NULL,
15307 					"Failed to create meter drop table");
15308 				}
15309 				tbl_data = container_of
15310 				(mtrmng->drop_tbl[domain],
15311 				struct mlx5_flow_tbl_data_entry, tbl);
15312 				if (i < MLX5_MTR_RTE_COLORS) {
15313 					act_cnt->dr_jump_action[domain] =
15314 						tbl_data->jump.action;
15315 					act_cnt->fate_action =
15316 						MLX5_FLOW_FATE_DROP;
15317 				}
15318 				if (i == RTE_COLOR_RED)
15319 					mtr_policy->dr_drop_action[domain] =
15320 						tbl_data->jump.action;
15321 				action_flags |= MLX5_FLOW_ACTION_DROP;
15322 				break;
15323 			}
15324 			case RTE_FLOW_ACTION_TYPE_QUEUE:
15325 			{
15326 				if (i >= MLX5_MTR_RTE_COLORS)
15327 					return -rte_mtr_error_set(error,
15328 					ENOTSUP,
15329 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15330 					NULL, "cannot create policy "
15331 					"fate queue for this color");
15332 				act_cnt->queue =
15333 				((const struct rte_flow_action_queue *)
15334 					(act->conf))->index;
15335 				act_cnt->fate_action =
15336 					MLX5_FLOW_FATE_QUEUE;
15337 				dev_flow.handle->fate_action =
15338 					MLX5_FLOW_FATE_QUEUE;
15339 				mtr_policy->is_queue = 1;
15340 				action_flags |= MLX5_FLOW_ACTION_QUEUE;
15341 				break;
15342 			}
15343 			case RTE_FLOW_ACTION_TYPE_RSS:
15344 			{
15345 				int rss_size;
15346 
15347 				if (i >= MLX5_MTR_RTE_COLORS)
15348 					return -rte_mtr_error_set(error,
15349 					  ENOTSUP,
15350 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15351 					  NULL,
15352 					  "cannot create policy "
15353 					  "rss action for this color");
15354 				/*
15355 				 * Save RSS conf into policy struct
15356 				 * for translate stage.
15357 				 */
15358 				rss_size = (int)rte_flow_conv
15359 					(RTE_FLOW_CONV_OP_ACTION,
15360 					NULL, 0, act, &flow_err);
15361 				if (rss_size <= 0)
15362 					return -rte_mtr_error_set(error,
15363 					  ENOTSUP,
15364 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15365 					  NULL, "Get the wrong "
15366 					  "rss action struct size");
15367 				act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
15368 						rss_size, 0, SOCKET_ID_ANY);
15369 				if (!act_cnt->rss)
15370 					return -rte_mtr_error_set(error,
15371 					  ENOTSUP,
15372 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15373 					  NULL,
15374 					  "Fail to malloc rss action memory");
15375 				ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
15376 					act_cnt->rss, rss_size,
15377 					act, &flow_err);
15378 				if (ret < 0)
15379 					return -rte_mtr_error_set(error,
15380 					  ENOTSUP,
15381 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15382 					  NULL, "Fail to save "
15383 					  "rss action into policy struct");
15384 				act_cnt->fate_action =
15385 					MLX5_FLOW_FATE_SHARED_RSS;
15386 				action_flags |= MLX5_FLOW_ACTION_RSS;
15387 				break;
15388 			}
15389 			case RTE_FLOW_ACTION_TYPE_PORT_ID:
15390 			{
15391 				struct mlx5_flow_dv_port_id_action_resource
15392 					port_id_resource;
15393 				uint32_t port_id = 0;
15394 
15395 				if (i >= MLX5_MTR_RTE_COLORS)
15396 					return -rte_mtr_error_set(error,
15397 					ENOTSUP,
15398 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15399 					NULL, "cannot create policy "
15400 					"port action for this color");
15401 				memset(&port_id_resource, 0,
15402 					sizeof(port_id_resource));
15403 				if (flow_dv_translate_action_port_id(dev, act,
15404 						&port_id, &flow_err))
15405 					return -rte_mtr_error_set(error,
15406 					ENOTSUP,
15407 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15408 					NULL, "cannot translate "
15409 					"policy port action");
15410 				port_id_resource.port_id = port_id;
15411 				if (flow_dv_port_id_action_resource_register
15412 					(dev, &port_id_resource,
15413 					&dev_flow, &flow_err))
15414 					return -rte_mtr_error_set(error,
15415 					ENOTSUP,
15416 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15417 					NULL, "cannot setup "
15418 					"policy port action");
15419 				act_cnt->rix_port_id_action =
15420 					dev_flow.handle->rix_port_id_action;
15421 				act_cnt->fate_action =
15422 					MLX5_FLOW_FATE_PORT_ID;
15423 				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
15424 				break;
15425 			}
15426 			case RTE_FLOW_ACTION_TYPE_JUMP:
15427 			{
15428 				uint32_t jump_group = 0;
15429 				uint32_t table = 0;
15430 				struct mlx5_flow_tbl_data_entry *tbl_data;
15431 				struct flow_grp_info grp_info = {
15432 					.external = !!dev_flow.external,
15433 					.transfer = !!transfer,
15434 					.fdb_def_rule = !!priv->fdb_def_rule,
15435 					.std_tbl_fix = 0,
15436 					.skip_scale = dev_flow.skip_scale &
15437 					(1 << MLX5_SCALE_FLOW_GROUP_BIT),
15438 				};
15439 				struct mlx5_flow_meter_sub_policy *sub_policy =
15440 					mtr_policy->sub_policys[domain][0];
15441 
15442 				if (i >= MLX5_MTR_RTE_COLORS)
15443 					return -rte_mtr_error_set(error,
15444 					  ENOTSUP,
15445 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15446 					  NULL,
15447 					  "cannot create policy "
15448 					  "jump action for this color");
15449 				jump_group =
15450 				((const struct rte_flow_action_jump *)
15451 							act->conf)->group;
15452 				if (mlx5_flow_group_to_table(dev, NULL,
15453 						       jump_group,
15454 						       &table,
15455 						       &grp_info, &flow_err))
15456 					return -rte_mtr_error_set(error,
15457 					ENOTSUP,
15458 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15459 					NULL, "cannot setup "
15460 					"policy jump action");
15461 				sub_policy->jump_tbl[i] =
15462 				flow_dv_tbl_resource_get(dev,
15463 					table, egress,
15464 					transfer,
15465 					!!dev_flow.external,
15466 					NULL, jump_group, 0,
15467 					0, &flow_err);
15468 				if
15469 				(!sub_policy->jump_tbl[i])
15470 					return  -rte_mtr_error_set(error,
15471 					ENOTSUP,
15472 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15473 					NULL, "cannot create jump action.");
15474 				tbl_data = container_of
15475 				(sub_policy->jump_tbl[i],
15476 				struct mlx5_flow_tbl_data_entry, tbl);
15477 				act_cnt->dr_jump_action[domain] =
15478 					tbl_data->jump.action;
15479 				act_cnt->fate_action =
15480 					MLX5_FLOW_FATE_JUMP;
15481 				action_flags |= MLX5_FLOW_ACTION_JUMP;
15482 				break;
15483 			}
15484 			/*
15485 			 * No need to check meter hierarchy for Y or R colors
15486 			 * here since it is done in the validation stage.
15487 			 */
15488 			case RTE_FLOW_ACTION_TYPE_METER:
15489 			{
15490 				const struct rte_flow_action_meter *mtr;
15491 				struct mlx5_flow_meter_info *next_fm;
15492 				struct mlx5_flow_meter_policy *next_policy;
15493 				struct rte_flow_action tag_action;
15494 				struct mlx5_rte_flow_action_set_tag set_tag;
15495 				uint32_t next_mtr_idx = 0;
15496 
15497 				mtr = act->conf;
15498 				next_fm = mlx5_flow_meter_find(priv,
15499 							mtr->mtr_id,
15500 							&next_mtr_idx);
15501 				if (!next_fm)
15502 					return -rte_mtr_error_set(error, EINVAL,
15503 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
15504 						"Fail to find next meter.");
15505 				if (next_fm->def_policy)
15506 					return -rte_mtr_error_set(error, EINVAL,
15507 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
15508 				"Hierarchy only supports termination meter.");
15509 				next_policy = mlx5_flow_meter_policy_find(dev,
15510 						next_fm->policy_id, NULL);
15511 				MLX5_ASSERT(next_policy);
15512 				if (next_fm->drop_cnt) {
15513 					set_tag.id =
15514 						(enum modify_reg)
15515 						mlx5_flow_get_reg_id(dev,
15516 						MLX5_MTR_ID,
15517 						0,
15518 						(struct rte_flow_error *)error);
15519 					set_tag.offset = (priv->mtr_reg_share ?
15520 						MLX5_MTR_COLOR_BITS : 0);
15521 					set_tag.length = (priv->mtr_reg_share ?
15522 					       MLX5_MTR_IDLE_BITS_IN_COLOR_REG :
15523 					       MLX5_REG_BITS);
15524 					set_tag.data = next_mtr_idx;
15525 					tag_action.type =
15526 						(enum rte_flow_action_type)
15527 						MLX5_RTE_FLOW_ACTION_TYPE_TAG;
15528 					tag_action.conf = &set_tag;
15529 					if (flow_dv_convert_action_set_reg
15530 						(mhdr_res, &tag_action,
15531 						(struct rte_flow_error *)error))
15532 						return -rte_errno;
15533 					action_flags |=
15534 						MLX5_FLOW_ACTION_SET_TAG;
15535 				}
15536 				act_cnt->fate_action = MLX5_FLOW_FATE_MTR;
15537 				act_cnt->next_mtr_id = next_fm->meter_id;
15538 				act_cnt->next_sub_policy = NULL;
15539 				mtr_policy->is_hierarchy = 1;
15540 				mtr_policy->dev = next_policy->dev;
15541 				action_flags |=
15542 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
15543 				break;
15544 			}
15545 			default:
15546 				return -rte_mtr_error_set(error, ENOTSUP,
15547 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15548 					  NULL, "action type not supported");
15549 			}
15550 			if (action_flags & MLX5_FLOW_ACTION_SET_TAG) {
15551 				/* create modify action if needed. */
15552 				dev_flow.dv.group = 1;
15553 				if (flow_dv_modify_hdr_resource_register
15554 					(dev, mhdr_res, &dev_flow, &flow_err))
15555 					return -rte_mtr_error_set(error,
15556 						ENOTSUP,
15557 						RTE_MTR_ERROR_TYPE_METER_POLICY,
15558 						NULL, "cannot register policy "
15559 						"set tag action");
15560 				act_cnt->modify_hdr =
15561 					dev_flow.handle->dvh.modify_hdr;
15562 			}
15563 		}
15564 	}
15565 	return 0;
15566 }
15567 
15568 /**
15569  * Create policy action per domain, lock free,
15570  * (mutex should be acquired by caller).
15571  * Dispatcher for action type specific call.
15572  *
15573  * @param[in] dev
15574  *   Pointer to the Ethernet device structure.
15575  * @param[in] mtr_policy
15576  *   Meter policy struct.
15577  * @param[in] action
15578  *   Action specification used to create meter actions.
15579  * @param[out] error
15580  *   Perform verbose error reporting if not NULL. Initialized in case of
15581  *   error only.
15582  *
15583  * @return
15584  *   0 on success, otherwise negative errno value.
15585  */
15586 static int
15587 flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
15588 		      struct mlx5_flow_meter_policy *mtr_policy,
15589 		      const struct rte_flow_action *actions[RTE_COLORS],
15590 		      struct rte_mtr_error *error)
15591 {
15592 	int ret, i;
15593 	uint16_t sub_policy_num;
15594 
15595 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15596 		sub_policy_num = (mtr_policy->sub_policy_num >>
15597 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
15598 			MLX5_MTR_SUB_POLICY_NUM_MASK;
15599 		if (sub_policy_num) {
15600 			ret = __flow_dv_create_domain_policy_acts(dev,
15601 				mtr_policy, actions,
15602 				(enum mlx5_meter_domain)i, error);
15603 			/* Cleaning resource is done in the caller level. */
15604 			if (ret)
15605 				return ret;
15606 		}
15607 	}
15608 	return 0;
15609 }
15610 
15611 /**
15612  * Query a DV flow rule for its statistics via DevX.
15613  *
15614  * @param[in] dev
15615  *   Pointer to Ethernet device.
15616  * @param[in] cnt_idx
15617  *   Index to the flow counter.
15618  * @param[out] data
15619  *   Data retrieved by the query.
15620  * @param[out] error
15621  *   Perform verbose error reporting if not NULL.
15622  *
15623  * @return
15624  *   0 on success, a negative errno value otherwise and rte_errno is set.
15625  */
15626 static int
15627 flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data,
15628 		    struct rte_flow_error *error)
15629 {
15630 	struct mlx5_priv *priv = dev->data->dev_private;
15631 	struct rte_flow_query_count *qc = data;
15632 
15633 	if (!priv->config.devx)
15634 		return rte_flow_error_set(error, ENOTSUP,
15635 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15636 					  NULL,
15637 					  "counters are not supported");
15638 	if (cnt_idx) {
15639 		uint64_t pkts, bytes;
15640 		struct mlx5_flow_counter *cnt;
15641 		int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes);
15642 
15643 		if (err)
15644 			return rte_flow_error_set(error, -err,
15645 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15646 					NULL, "cannot read counters");
15647 		cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL);
15648 		qc->hits_set = 1;
15649 		qc->bytes_set = 1;
15650 		qc->hits = pkts - cnt->hits;
15651 		qc->bytes = bytes - cnt->bytes;
15652 		if (qc->reset) {
15653 			cnt->hits = pkts;
15654 			cnt->bytes = bytes;
15655 		}
15656 		return 0;
15657 	}
15658 	return rte_flow_error_set(error, EINVAL,
15659 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15660 				  NULL,
15661 				  "counters are not available");
15662 }
15663 
15664 static int
15665 flow_dv_action_query(struct rte_eth_dev *dev,
15666 		     const struct rte_flow_action_handle *handle, void *data,
15667 		     struct rte_flow_error *error)
15668 {
15669 	struct mlx5_age_param *age_param;
15670 	struct rte_flow_query_age *resp;
15671 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15672 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15673 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15674 	struct mlx5_priv *priv = dev->data->dev_private;
15675 	struct mlx5_aso_ct_action *ct;
15676 	uint16_t owner;
15677 	uint32_t dev_idx;
15678 
15679 	switch (type) {
15680 	case MLX5_INDIRECT_ACTION_TYPE_AGE:
15681 		age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params;
15682 		resp = data;
15683 		resp->aged = __atomic_load_n(&age_param->state,
15684 					      __ATOMIC_RELAXED) == AGE_TMOUT ?
15685 									  1 : 0;
15686 		resp->sec_since_last_hit_valid = !resp->aged;
15687 		if (resp->sec_since_last_hit_valid)
15688 			resp->sec_since_last_hit = __atomic_load_n
15689 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
15690 		return 0;
15691 	case MLX5_INDIRECT_ACTION_TYPE_COUNT:
15692 		return flow_dv_query_count(dev, idx, data, error);
15693 	case MLX5_INDIRECT_ACTION_TYPE_CT:
15694 		owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
15695 		if (owner != PORT_ID(priv))
15696 			return rte_flow_error_set(error, EACCES,
15697 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15698 					NULL,
15699 					"CT object owned by another port");
15700 		dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
15701 		ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
15702 		MLX5_ASSERT(ct);
15703 		if (!ct->refcnt)
15704 			return rte_flow_error_set(error, EFAULT,
15705 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15706 					NULL,
15707 					"CT object is inactive");
15708 		((struct rte_flow_action_conntrack *)data)->peer_port =
15709 							ct->peer;
15710 		((struct rte_flow_action_conntrack *)data)->is_original_dir =
15711 							ct->is_original;
15712 		if (mlx5_aso_ct_query_by_wqe(priv->sh, ct, data))
15713 			return rte_flow_error_set(error, EIO,
15714 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15715 					NULL,
15716 					"Failed to query CT context");
15717 		return 0;
15718 	default:
15719 		return rte_flow_error_set(error, ENOTSUP,
15720 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15721 					  "action type query not supported");
15722 	}
15723 }
15724 
15725 /**
15726  * Query a flow rule AGE action for aging information.
15727  *
15728  * @param[in] dev
15729  *   Pointer to Ethernet device.
15730  * @param[in] flow
15731  *   Pointer to the sub flow.
15732  * @param[out] data
15733  *   data retrieved by the query.
15734  * @param[out] error
15735  *   Perform verbose error reporting if not NULL.
15736  *
15737  * @return
15738  *   0 on success, a negative errno value otherwise and rte_errno is set.
15739  */
15740 static int
15741 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow,
15742 		  void *data, struct rte_flow_error *error)
15743 {
15744 	struct rte_flow_query_age *resp = data;
15745 	struct mlx5_age_param *age_param;
15746 
15747 	if (flow->age) {
15748 		struct mlx5_aso_age_action *act =
15749 				     flow_aso_age_get_by_idx(dev, flow->age);
15750 
15751 		age_param = &act->age_params;
15752 	} else if (flow->counter) {
15753 		age_param = flow_dv_counter_idx_get_age(dev, flow->counter);
15754 
15755 		if (!age_param || !age_param->timeout)
15756 			return rte_flow_error_set
15757 					(error, EINVAL,
15758 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15759 					 NULL, "cannot read age data");
15760 	} else {
15761 		return rte_flow_error_set(error, EINVAL,
15762 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15763 					  NULL, "age data not available");
15764 	}
15765 	resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) ==
15766 				     AGE_TMOUT ? 1 : 0;
15767 	resp->sec_since_last_hit_valid = !resp->aged;
15768 	if (resp->sec_since_last_hit_valid)
15769 		resp->sec_since_last_hit = __atomic_load_n
15770 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
15771 	return 0;
15772 }
15773 
15774 /**
15775  * Query a flow.
15776  *
15777  * @see rte_flow_query()
15778  * @see rte_flow_ops
15779  */
15780 static int
15781 flow_dv_query(struct rte_eth_dev *dev,
15782 	      struct rte_flow *flow __rte_unused,
15783 	      const struct rte_flow_action *actions __rte_unused,
15784 	      void *data __rte_unused,
15785 	      struct rte_flow_error *error __rte_unused)
15786 {
15787 	int ret = -EINVAL;
15788 
15789 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
15790 		switch (actions->type) {
15791 		case RTE_FLOW_ACTION_TYPE_VOID:
15792 			break;
15793 		case RTE_FLOW_ACTION_TYPE_COUNT:
15794 			ret = flow_dv_query_count(dev, flow->counter, data,
15795 						  error);
15796 			break;
15797 		case RTE_FLOW_ACTION_TYPE_AGE:
15798 			ret = flow_dv_query_age(dev, flow, data, error);
15799 			break;
15800 		default:
15801 			return rte_flow_error_set(error, ENOTSUP,
15802 						  RTE_FLOW_ERROR_TYPE_ACTION,
15803 						  actions,
15804 						  "action not supported");
15805 		}
15806 	}
15807 	return ret;
15808 }
15809 
15810 /**
15811  * Destroy the meter table set.
15812  * Lock free, (mutex should be acquired by caller).
15813  *
15814  * @param[in] dev
15815  *   Pointer to Ethernet device.
15816  * @param[in] fm
15817  *   Meter information table.
15818  */
15819 static void
15820 flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
15821 			struct mlx5_flow_meter_info *fm)
15822 {
15823 	struct mlx5_priv *priv = dev->data->dev_private;
15824 	int i;
15825 
15826 	if (!fm || !priv->config.dv_flow_en)
15827 		return;
15828 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15829 		if (fm->drop_rule[i]) {
15830 			claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
15831 			fm->drop_rule[i] = NULL;
15832 		}
15833 	}
15834 }
15835 
15836 static void
15837 flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
15838 {
15839 	struct mlx5_priv *priv = dev->data->dev_private;
15840 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
15841 	struct mlx5_flow_tbl_data_entry *tbl;
15842 	int i, j;
15843 
15844 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15845 		if (mtrmng->def_rule[i]) {
15846 			claim_zero(mlx5_flow_os_destroy_flow
15847 					(mtrmng->def_rule[i]));
15848 			mtrmng->def_rule[i] = NULL;
15849 		}
15850 		if (mtrmng->def_matcher[i]) {
15851 			tbl = container_of(mtrmng->def_matcher[i]->tbl,
15852 				struct mlx5_flow_tbl_data_entry, tbl);
15853 			mlx5_list_unregister(tbl->matchers,
15854 					     &mtrmng->def_matcher[i]->entry);
15855 			mtrmng->def_matcher[i] = NULL;
15856 		}
15857 		for (j = 0; j < MLX5_REG_BITS; j++) {
15858 			if (mtrmng->drop_matcher[i][j]) {
15859 				tbl =
15860 				container_of(mtrmng->drop_matcher[i][j]->tbl,
15861 					     struct mlx5_flow_tbl_data_entry,
15862 					     tbl);
15863 				mlx5_list_unregister(tbl->matchers,
15864 					    &mtrmng->drop_matcher[i][j]->entry);
15865 				mtrmng->drop_matcher[i][j] = NULL;
15866 			}
15867 		}
15868 		if (mtrmng->drop_tbl[i]) {
15869 			flow_dv_tbl_resource_release(MLX5_SH(dev),
15870 				mtrmng->drop_tbl[i]);
15871 			mtrmng->drop_tbl[i] = NULL;
15872 		}
15873 	}
15874 }
15875 
15876 /* Number of meter flow actions, count and jump or count and drop. */
15877 #define METER_ACTIONS 2
15878 
15879 static void
15880 __flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
15881 				    enum mlx5_meter_domain domain)
15882 {
15883 	struct mlx5_priv *priv = dev->data->dev_private;
15884 	struct mlx5_flow_meter_def_policy *def_policy =
15885 			priv->sh->mtrmng->def_policy[domain];
15886 
15887 	__flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
15888 	mlx5_free(def_policy);
15889 	priv->sh->mtrmng->def_policy[domain] = NULL;
15890 }
15891 
15892 /**
15893  * Destroy the default policy table set.
15894  *
15895  * @param[in] dev
15896  *   Pointer to Ethernet device.
15897  */
15898 static void
15899 flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
15900 {
15901 	struct mlx5_priv *priv = dev->data->dev_private;
15902 	int i;
15903 
15904 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
15905 		if (priv->sh->mtrmng->def_policy[i])
15906 			__flow_dv_destroy_domain_def_policy(dev,
15907 					(enum mlx5_meter_domain)i);
15908 	priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
15909 }
15910 
15911 static int
15912 __flow_dv_create_policy_flow(struct rte_eth_dev *dev,
15913 			uint32_t color_reg_c_idx,
15914 			enum rte_color color, void *matcher_object,
15915 			int actions_n, void *actions,
15916 			bool match_src_port, const struct rte_flow_item *item,
15917 			void **rule, const struct rte_flow_attr *attr)
15918 {
15919 	int ret;
15920 	struct mlx5_flow_dv_match_params value = {
15921 		.size = sizeof(value.buf),
15922 	};
15923 	struct mlx5_flow_dv_match_params matcher = {
15924 		.size = sizeof(matcher.buf),
15925 	};
15926 	struct mlx5_priv *priv = dev->data->dev_private;
15927 	uint8_t misc_mask;
15928 
15929 	if (match_src_port && (priv->representor || priv->master)) {
15930 		if (flow_dv_translate_item_port_id(dev, matcher.buf,
15931 						   value.buf, item, attr)) {
15932 			DRV_LOG(ERR, "Failed to create meter policy%d flow's"
15933 				" value with port.", color);
15934 			return -1;
15935 		}
15936 	}
15937 	flow_dv_match_meta_reg(matcher.buf, value.buf,
15938 			       (enum modify_reg)color_reg_c_idx,
15939 			       rte_col_2_mlx5_col(color), UINT32_MAX);
15940 	misc_mask = flow_dv_matcher_enable(value.buf);
15941 	__flow_dv_adjust_buf_size(&value.size, misc_mask);
15942 	ret = mlx5_flow_os_create_flow(matcher_object, (void *)&value,
15943 				       actions_n, actions, rule);
15944 	if (ret) {
15945 		DRV_LOG(ERR, "Failed to create meter policy%d flow.", color);
15946 		return -1;
15947 	}
15948 	return 0;
15949 }
15950 
15951 static int
15952 __flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
15953 			uint32_t color_reg_c_idx,
15954 			uint16_t priority,
15955 			struct mlx5_flow_meter_sub_policy *sub_policy,
15956 			const struct rte_flow_attr *attr,
15957 			bool match_src_port,
15958 			const struct rte_flow_item *item,
15959 			struct mlx5_flow_dv_matcher **policy_matcher,
15960 			struct rte_flow_error *error)
15961 {
15962 	struct mlx5_list_entry *entry;
15963 	struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
15964 	struct mlx5_flow_dv_matcher matcher = {
15965 		.mask = {
15966 			.size = sizeof(matcher.mask.buf),
15967 		},
15968 		.tbl = tbl_rsc,
15969 	};
15970 	struct mlx5_flow_dv_match_params value = {
15971 		.size = sizeof(value.buf),
15972 	};
15973 	struct mlx5_flow_cb_ctx ctx = {
15974 		.error = error,
15975 		.data = &matcher,
15976 	};
15977 	struct mlx5_flow_tbl_data_entry *tbl_data;
15978 	struct mlx5_priv *priv = dev->data->dev_private;
15979 	const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
15980 
15981 	if (match_src_port && (priv->representor || priv->master)) {
15982 		if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
15983 						   value.buf, item, attr)) {
15984 			DRV_LOG(ERR, "Failed to register meter policy%d matcher"
15985 				" with port.", priority);
15986 			return -1;
15987 		}
15988 	}
15989 	tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
15990 	if (priority < RTE_COLOR_RED)
15991 		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
15992 			(enum modify_reg)color_reg_c_idx, 0, color_mask);
15993 	matcher.priority = priority;
15994 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
15995 				    matcher.mask.size);
15996 	entry = mlx5_list_register(tbl_data->matchers, &ctx);
15997 	if (!entry) {
15998 		DRV_LOG(ERR, "Failed to register meter drop matcher.");
15999 		return -1;
16000 	}
16001 	*policy_matcher =
16002 		container_of(entry, struct mlx5_flow_dv_matcher, entry);
16003 	return 0;
16004 }
16005 
16006 /**
16007  * Create the policy rules per domain.
16008  *
16009  * @param[in] dev
16010  *   Pointer to Ethernet device.
16011  * @param[in] sub_policy
16012  *    Pointer to sub policy table..
16013  * @param[in] egress
16014  *   Direction of the table.
16015  * @param[in] transfer
16016  *   E-Switch or NIC flow.
16017  * @param[in] acts
16018  *   Pointer to policy action list per color.
16019  *
16020  * @return
16021  *   0 on success, -1 otherwise.
16022  */
16023 static int
16024 __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
16025 		struct mlx5_flow_meter_sub_policy *sub_policy,
16026 		uint8_t egress, uint8_t transfer, bool match_src_port,
16027 		struct mlx5_meter_policy_acts acts[RTE_COLORS])
16028 {
16029 	struct mlx5_priv *priv = dev->data->dev_private;
16030 	struct rte_flow_error flow_err;
16031 	uint32_t color_reg_c_idx;
16032 	struct rte_flow_attr attr = {
16033 		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
16034 		.priority = 0,
16035 		.ingress = 0,
16036 		.egress = !!egress,
16037 		.transfer = !!transfer,
16038 		.reserved = 0,
16039 	};
16040 	int i;
16041 	int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
16042 	struct mlx5_sub_policy_color_rule *color_rule;
16043 	bool svport_match;
16044 	struct mlx5_sub_policy_color_rule *tmp_rules[RTE_COLORS] = {NULL};
16045 
16046 	if (ret < 0)
16047 		return -1;
16048 	/* Create policy table with POLICY level. */
16049 	if (!sub_policy->tbl_rsc)
16050 		sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
16051 				MLX5_FLOW_TABLE_LEVEL_POLICY,
16052 				egress, transfer, false, NULL, 0, 0,
16053 				sub_policy->idx, &flow_err);
16054 	if (!sub_policy->tbl_rsc) {
16055 		DRV_LOG(ERR,
16056 			"Failed to create meter sub policy table.");
16057 		return -1;
16058 	}
16059 	/* Prepare matchers. */
16060 	color_reg_c_idx = ret;
16061 	for (i = 0; i < RTE_COLORS; i++) {
16062 		TAILQ_INIT(&sub_policy->color_rules[i]);
16063 		if (!acts[i].actions_n)
16064 			continue;
16065 		color_rule = mlx5_malloc(MLX5_MEM_ZERO,
16066 				sizeof(struct mlx5_sub_policy_color_rule),
16067 				0, SOCKET_ID_ANY);
16068 		if (!color_rule) {
16069 			DRV_LOG(ERR, "No memory to create color rule.");
16070 			goto err_exit;
16071 		}
16072 		tmp_rules[i] = color_rule;
16073 		TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
16074 				  color_rule, next_port);
16075 		color_rule->src_port = priv->representor_id;
16076 		/* No use. */
16077 		attr.priority = i;
16078 		/* Create matchers for colors. */
16079 		svport_match = (i != RTE_COLOR_RED) ? match_src_port : false;
16080 		if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
16081 				MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
16082 				&attr, svport_match, NULL,
16083 				&color_rule->matcher, &flow_err)) {
16084 			DRV_LOG(ERR, "Failed to create color%u matcher.", i);
16085 			goto err_exit;
16086 		}
16087 		/* Create flow, matching color. */
16088 		if (__flow_dv_create_policy_flow(dev,
16089 				color_reg_c_idx, (enum rte_color)i,
16090 				color_rule->matcher->matcher_object,
16091 				acts[i].actions_n, acts[i].dv_actions,
16092 				svport_match, NULL, &color_rule->rule,
16093 				&attr)) {
16094 			DRV_LOG(ERR, "Failed to create color%u rule.", i);
16095 			goto err_exit;
16096 		}
16097 	}
16098 	return 0;
16099 err_exit:
16100 	/* All the policy rules will be cleared. */
16101 	do {
16102 		color_rule = tmp_rules[i];
16103 		if (color_rule) {
16104 			if (color_rule->rule)
16105 				mlx5_flow_os_destroy_flow(color_rule->rule);
16106 			if (color_rule->matcher) {
16107 				struct mlx5_flow_tbl_data_entry *tbl =
16108 					container_of(color_rule->matcher->tbl,
16109 						     typeof(*tbl), tbl);
16110 				mlx5_list_unregister(tbl->matchers,
16111 						&color_rule->matcher->entry);
16112 			}
16113 			TAILQ_REMOVE(&sub_policy->color_rules[i],
16114 				     color_rule, next_port);
16115 			mlx5_free(color_rule);
16116 		}
16117 	} while (i--);
16118 	return -1;
16119 }
16120 
16121 static int
16122 __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
16123 			struct mlx5_flow_meter_policy *mtr_policy,
16124 			struct mlx5_flow_meter_sub_policy *sub_policy,
16125 			uint32_t domain)
16126 {
16127 	struct mlx5_priv *priv = dev->data->dev_private;
16128 	struct mlx5_meter_policy_acts acts[RTE_COLORS];
16129 	struct mlx5_flow_dv_tag_resource *tag;
16130 	struct mlx5_flow_dv_port_id_action_resource *port_action;
16131 	struct mlx5_hrxq *hrxq;
16132 	struct mlx5_flow_meter_info *next_fm = NULL;
16133 	struct mlx5_flow_meter_policy *next_policy;
16134 	struct mlx5_flow_meter_sub_policy *next_sub_policy;
16135 	struct mlx5_flow_tbl_data_entry *tbl_data;
16136 	struct rte_flow_error error;
16137 	uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16138 	uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16139 	bool mtr_first = egress || (transfer && priv->representor_id != UINT16_MAX);
16140 	bool match_src_port = false;
16141 	int i;
16142 
16143 	/* If RSS or Queue, no previous actions / rules is created. */
16144 	for (i = 0; i < RTE_COLORS; i++) {
16145 		acts[i].actions_n = 0;
16146 		if (i == RTE_COLOR_RED) {
16147 			/* Only support drop on red. */
16148 			acts[i].dv_actions[0] =
16149 				mtr_policy->dr_drop_action[domain];
16150 			acts[i].actions_n = 1;
16151 			continue;
16152 		}
16153 		if (i == RTE_COLOR_GREEN &&
16154 		    mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) {
16155 			struct rte_flow_attr attr = {
16156 				.transfer = transfer
16157 			};
16158 
16159 			next_fm = mlx5_flow_meter_find(priv,
16160 					mtr_policy->act_cnt[i].next_mtr_id,
16161 					NULL);
16162 			if (!next_fm) {
16163 				DRV_LOG(ERR,
16164 					"Failed to get next hierarchy meter.");
16165 				goto err_exit;
16166 			}
16167 			if (mlx5_flow_meter_attach(priv, next_fm,
16168 						   &attr, &error)) {
16169 				DRV_LOG(ERR, "%s", error.message);
16170 				next_fm = NULL;
16171 				goto err_exit;
16172 			}
16173 			/* Meter action must be the first for TX. */
16174 			if (mtr_first) {
16175 				acts[i].dv_actions[acts[i].actions_n] =
16176 					next_fm->meter_action;
16177 				acts[i].actions_n++;
16178 			}
16179 		}
16180 		if (mtr_policy->act_cnt[i].rix_mark) {
16181 			tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
16182 					mtr_policy->act_cnt[i].rix_mark);
16183 			if (!tag) {
16184 				DRV_LOG(ERR, "Failed to find "
16185 				"mark action for policy.");
16186 				goto err_exit;
16187 			}
16188 			acts[i].dv_actions[acts[i].actions_n] = tag->action;
16189 			acts[i].actions_n++;
16190 		}
16191 		if (mtr_policy->act_cnt[i].modify_hdr) {
16192 			acts[i].dv_actions[acts[i].actions_n] =
16193 				mtr_policy->act_cnt[i].modify_hdr->action;
16194 			acts[i].actions_n++;
16195 		}
16196 		if (mtr_policy->act_cnt[i].fate_action) {
16197 			switch (mtr_policy->act_cnt[i].fate_action) {
16198 			case MLX5_FLOW_FATE_PORT_ID:
16199 				port_action = mlx5_ipool_get
16200 					(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
16201 				mtr_policy->act_cnt[i].rix_port_id_action);
16202 				if (!port_action) {
16203 					DRV_LOG(ERR, "Failed to find "
16204 						"port action for policy.");
16205 					goto err_exit;
16206 				}
16207 				acts[i].dv_actions[acts[i].actions_n] =
16208 					port_action->action;
16209 				acts[i].actions_n++;
16210 				mtr_policy->dev = dev;
16211 				match_src_port = true;
16212 				break;
16213 			case MLX5_FLOW_FATE_DROP:
16214 			case MLX5_FLOW_FATE_JUMP:
16215 				acts[i].dv_actions[acts[i].actions_n] =
16216 				mtr_policy->act_cnt[i].dr_jump_action[domain];
16217 				acts[i].actions_n++;
16218 				break;
16219 			case MLX5_FLOW_FATE_SHARED_RSS:
16220 			case MLX5_FLOW_FATE_QUEUE:
16221 				hrxq = mlx5_ipool_get
16222 					(priv->sh->ipool[MLX5_IPOOL_HRXQ],
16223 					 sub_policy->rix_hrxq[i]);
16224 				if (!hrxq) {
16225 					DRV_LOG(ERR, "Failed to find "
16226 						"queue action for policy.");
16227 					goto err_exit;
16228 				}
16229 				acts[i].dv_actions[acts[i].actions_n] =
16230 					hrxq->action;
16231 				acts[i].actions_n++;
16232 				break;
16233 			case MLX5_FLOW_FATE_MTR:
16234 				if (!next_fm) {
16235 					DRV_LOG(ERR,
16236 						"No next hierarchy meter.");
16237 					goto err_exit;
16238 				}
16239 				if (!mtr_first) {
16240 					acts[i].dv_actions[acts[i].actions_n] =
16241 							next_fm->meter_action;
16242 					acts[i].actions_n++;
16243 				}
16244 				if (mtr_policy->act_cnt[i].next_sub_policy) {
16245 					next_sub_policy =
16246 					mtr_policy->act_cnt[i].next_sub_policy;
16247 				} else {
16248 					next_policy =
16249 						mlx5_flow_meter_policy_find(dev,
16250 						next_fm->policy_id, NULL);
16251 					MLX5_ASSERT(next_policy);
16252 					next_sub_policy =
16253 					next_policy->sub_policys[domain][0];
16254 				}
16255 				tbl_data =
16256 					container_of(next_sub_policy->tbl_rsc,
16257 					struct mlx5_flow_tbl_data_entry, tbl);
16258 				acts[i].dv_actions[acts[i].actions_n++] =
16259 							tbl_data->jump.action;
16260 				if (mtr_policy->act_cnt[i].modify_hdr)
16261 					match_src_port = !!transfer;
16262 				break;
16263 			default:
16264 				/*Queue action do nothing*/
16265 				break;
16266 			}
16267 		}
16268 	}
16269 	if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
16270 				egress, transfer, match_src_port, acts)) {
16271 		DRV_LOG(ERR,
16272 			"Failed to create policy rules per domain.");
16273 		goto err_exit;
16274 	}
16275 	return 0;
16276 err_exit:
16277 	if (next_fm)
16278 		mlx5_flow_meter_detach(priv, next_fm);
16279 	return -1;
16280 }
16281 
16282 /**
16283  * Create the policy rules.
16284  *
16285  * @param[in] dev
16286  *   Pointer to Ethernet device.
16287  * @param[in,out] mtr_policy
16288  *   Pointer to meter policy table.
16289  *
16290  * @return
16291  *   0 on success, -1 otherwise.
16292  */
16293 static int
16294 flow_dv_create_policy_rules(struct rte_eth_dev *dev,
16295 			     struct mlx5_flow_meter_policy *mtr_policy)
16296 {
16297 	int i;
16298 	uint16_t sub_policy_num;
16299 
16300 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16301 		sub_policy_num = (mtr_policy->sub_policy_num >>
16302 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
16303 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16304 		if (!sub_policy_num)
16305 			continue;
16306 		/* Prepare actions list and create policy rules. */
16307 		if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
16308 			mtr_policy->sub_policys[i][0], i)) {
16309 			DRV_LOG(ERR, "Failed to create policy action "
16310 				"list per domain.");
16311 			return -1;
16312 		}
16313 	}
16314 	return 0;
16315 }
16316 
16317 static int
16318 __flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
16319 {
16320 	struct mlx5_priv *priv = dev->data->dev_private;
16321 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16322 	struct mlx5_flow_meter_def_policy *def_policy;
16323 	struct mlx5_flow_tbl_resource *jump_tbl;
16324 	struct mlx5_flow_tbl_data_entry *tbl_data;
16325 	uint8_t egress, transfer;
16326 	struct rte_flow_error error;
16327 	struct mlx5_meter_policy_acts acts[RTE_COLORS];
16328 	int ret;
16329 
16330 	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16331 	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16332 	def_policy = mtrmng->def_policy[domain];
16333 	if (!def_policy) {
16334 		def_policy = mlx5_malloc(MLX5_MEM_ZERO,
16335 			sizeof(struct mlx5_flow_meter_def_policy),
16336 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
16337 		if (!def_policy) {
16338 			DRV_LOG(ERR, "Failed to alloc default policy table.");
16339 			goto def_policy_error;
16340 		}
16341 		mtrmng->def_policy[domain] = def_policy;
16342 		/* Create the meter suffix table with SUFFIX level. */
16343 		jump_tbl = flow_dv_tbl_resource_get(dev,
16344 				MLX5_FLOW_TABLE_LEVEL_METER,
16345 				egress, transfer, false, NULL, 0,
16346 				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
16347 		if (!jump_tbl) {
16348 			DRV_LOG(ERR,
16349 				"Failed to create meter suffix table.");
16350 			goto def_policy_error;
16351 		}
16352 		def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
16353 		tbl_data = container_of(jump_tbl,
16354 					struct mlx5_flow_tbl_data_entry, tbl);
16355 		def_policy->dr_jump_action[RTE_COLOR_GREEN] =
16356 						tbl_data->jump.action;
16357 		acts[RTE_COLOR_GREEN].dv_actions[0] = tbl_data->jump.action;
16358 		acts[RTE_COLOR_GREEN].actions_n = 1;
16359 		/*
16360 		 * YELLOW has the same default policy as GREEN does.
16361 		 * G & Y share the same table and action. The 2nd time of table
16362 		 * resource getting is just to update the reference count for
16363 		 * the releasing stage.
16364 		 */
16365 		jump_tbl = flow_dv_tbl_resource_get(dev,
16366 				MLX5_FLOW_TABLE_LEVEL_METER,
16367 				egress, transfer, false, NULL, 0,
16368 				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
16369 		if (!jump_tbl) {
16370 			DRV_LOG(ERR,
16371 				"Failed to get meter suffix table.");
16372 			goto def_policy_error;
16373 		}
16374 		def_policy->sub_policy.jump_tbl[RTE_COLOR_YELLOW] = jump_tbl;
16375 		tbl_data = container_of(jump_tbl,
16376 					struct mlx5_flow_tbl_data_entry, tbl);
16377 		def_policy->dr_jump_action[RTE_COLOR_YELLOW] =
16378 						tbl_data->jump.action;
16379 		acts[RTE_COLOR_YELLOW].dv_actions[0] = tbl_data->jump.action;
16380 		acts[RTE_COLOR_YELLOW].actions_n = 1;
16381 		/* Create jump action to the drop table. */
16382 		if (!mtrmng->drop_tbl[domain]) {
16383 			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
16384 				(dev, MLX5_FLOW_TABLE_LEVEL_METER,
16385 				 egress, transfer, false, NULL, 0,
16386 				 0, MLX5_MTR_TABLE_ID_DROP, &error);
16387 			if (!mtrmng->drop_tbl[domain]) {
16388 				DRV_LOG(ERR, "Failed to create meter "
16389 					"drop table for default policy.");
16390 				goto def_policy_error;
16391 			}
16392 		}
16393 		/* all RED: unique Drop table for jump action. */
16394 		tbl_data = container_of(mtrmng->drop_tbl[domain],
16395 					struct mlx5_flow_tbl_data_entry, tbl);
16396 		def_policy->dr_jump_action[RTE_COLOR_RED] =
16397 						tbl_data->jump.action;
16398 		acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
16399 		acts[RTE_COLOR_RED].actions_n = 1;
16400 		/* Create default policy rules. */
16401 		ret = __flow_dv_create_domain_policy_rules(dev,
16402 					&def_policy->sub_policy,
16403 					egress, transfer, false, acts);
16404 		if (ret) {
16405 			DRV_LOG(ERR, "Failed to create default policy rules.");
16406 			goto def_policy_error;
16407 		}
16408 	}
16409 	return 0;
16410 def_policy_error:
16411 	__flow_dv_destroy_domain_def_policy(dev,
16412 					    (enum mlx5_meter_domain)domain);
16413 	return -1;
16414 }
16415 
16416 /**
16417  * Create the default policy table set.
16418  *
16419  * @param[in] dev
16420  *   Pointer to Ethernet device.
16421  * @return
16422  *   0 on success, -1 otherwise.
16423  */
16424 static int
16425 flow_dv_create_def_policy(struct rte_eth_dev *dev)
16426 {
16427 	struct mlx5_priv *priv = dev->data->dev_private;
16428 	int i;
16429 
16430 	/* Non-termination policy table. */
16431 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16432 		if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER)
16433 			continue;
16434 		if (__flow_dv_create_domain_def_policy(dev, i)) {
16435 			DRV_LOG(ERR, "Failed to create default policy");
16436 			/* Rollback the created default policies for others. */
16437 			flow_dv_destroy_def_policy(dev);
16438 			return -1;
16439 		}
16440 	}
16441 	return 0;
16442 }
16443 
16444 /**
16445  * Create the needed meter tables.
16446  * Lock free, (mutex should be acquired by caller).
16447  *
16448  * @param[in] dev
16449  *   Pointer to Ethernet device.
16450  * @param[in] fm
16451  *   Meter information table.
16452  * @param[in] mtr_idx
16453  *   Meter index.
16454  * @param[in] domain_bitmap
16455  *   Domain bitmap.
16456  * @return
16457  *   0 on success, -1 otherwise.
16458  */
16459 static int
16460 flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
16461 			struct mlx5_flow_meter_info *fm,
16462 			uint32_t mtr_idx,
16463 			uint8_t domain_bitmap)
16464 {
16465 	struct mlx5_priv *priv = dev->data->dev_private;
16466 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16467 	struct rte_flow_error error;
16468 	struct mlx5_flow_tbl_data_entry *tbl_data;
16469 	uint8_t egress, transfer;
16470 	void *actions[METER_ACTIONS];
16471 	int domain, ret, i;
16472 	struct mlx5_flow_counter *cnt;
16473 	struct mlx5_flow_dv_match_params value = {
16474 		.size = sizeof(value.buf),
16475 	};
16476 	struct mlx5_flow_dv_match_params matcher_para = {
16477 		.size = sizeof(matcher_para.buf),
16478 	};
16479 	int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
16480 						     0, &error);
16481 	uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1;
16482 	uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
16483 	struct mlx5_list_entry *entry;
16484 	struct mlx5_flow_dv_matcher matcher = {
16485 		.mask = {
16486 			.size = sizeof(matcher.mask.buf),
16487 		},
16488 	};
16489 	struct mlx5_flow_dv_matcher *drop_matcher;
16490 	struct mlx5_flow_cb_ctx ctx = {
16491 		.error = &error,
16492 		.data = &matcher,
16493 	};
16494 	uint8_t misc_mask;
16495 
16496 	if (!priv->mtr_en || mtr_id_reg_c < 0) {
16497 		rte_errno = ENOTSUP;
16498 		return -1;
16499 	}
16500 	for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
16501 		if (!(domain_bitmap & (1 << domain)) ||
16502 			(mtrmng->def_rule[domain] && !fm->drop_cnt))
16503 			continue;
16504 		egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16505 		transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16506 		/* Create the drop table with METER DROP level. */
16507 		if (!mtrmng->drop_tbl[domain]) {
16508 			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev,
16509 					MLX5_FLOW_TABLE_LEVEL_METER,
16510 					egress, transfer, false, NULL, 0,
16511 					0, MLX5_MTR_TABLE_ID_DROP, &error);
16512 			if (!mtrmng->drop_tbl[domain]) {
16513 				DRV_LOG(ERR, "Failed to create meter drop table.");
16514 				goto policy_error;
16515 			}
16516 		}
16517 		/* Create default matcher in drop table. */
16518 		matcher.tbl = mtrmng->drop_tbl[domain],
16519 		tbl_data = container_of(mtrmng->drop_tbl[domain],
16520 				struct mlx5_flow_tbl_data_entry, tbl);
16521 		if (!mtrmng->def_matcher[domain]) {
16522 			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16523 				       (enum modify_reg)mtr_id_reg_c,
16524 				       0, 0);
16525 			matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
16526 			matcher.crc = rte_raw_cksum
16527 					((const void *)matcher.mask.buf,
16528 					matcher.mask.size);
16529 			entry = mlx5_list_register(tbl_data->matchers, &ctx);
16530 			if (!entry) {
16531 				DRV_LOG(ERR, "Failed to register meter "
16532 				"drop default matcher.");
16533 				goto policy_error;
16534 			}
16535 			mtrmng->def_matcher[domain] = container_of(entry,
16536 			struct mlx5_flow_dv_matcher, entry);
16537 		}
16538 		/* Create default rule in drop table. */
16539 		if (!mtrmng->def_rule[domain]) {
16540 			i = 0;
16541 			actions[i++] = priv->sh->dr_drop_action;
16542 			flow_dv_match_meta_reg(matcher_para.buf, value.buf,
16543 				(enum modify_reg)mtr_id_reg_c, 0, 0);
16544 			misc_mask = flow_dv_matcher_enable(value.buf);
16545 			__flow_dv_adjust_buf_size(&value.size, misc_mask);
16546 			ret = mlx5_flow_os_create_flow
16547 				(mtrmng->def_matcher[domain]->matcher_object,
16548 				(void *)&value, i, actions,
16549 				&mtrmng->def_rule[domain]);
16550 			if (ret) {
16551 				DRV_LOG(ERR, "Failed to create meter "
16552 				"default drop rule for drop table.");
16553 				goto policy_error;
16554 			}
16555 		}
16556 		if (!fm->drop_cnt)
16557 			continue;
16558 		MLX5_ASSERT(mtrmng->max_mtr_bits);
16559 		if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) {
16560 			/* Create matchers for Drop. */
16561 			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16562 					(enum modify_reg)mtr_id_reg_c, 0,
16563 					(mtr_id_mask << mtr_id_offset));
16564 			matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
16565 			matcher.crc = rte_raw_cksum
16566 					((const void *)matcher.mask.buf,
16567 					matcher.mask.size);
16568 			entry = mlx5_list_register(tbl_data->matchers, &ctx);
16569 			if (!entry) {
16570 				DRV_LOG(ERR,
16571 				"Failed to register meter drop matcher.");
16572 				goto policy_error;
16573 			}
16574 			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] =
16575 				container_of(entry, struct mlx5_flow_dv_matcher,
16576 					     entry);
16577 		}
16578 		drop_matcher =
16579 			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1];
16580 		/* Create drop rule, matching meter_id only. */
16581 		flow_dv_match_meta_reg(matcher_para.buf, value.buf,
16582 				(enum modify_reg)mtr_id_reg_c,
16583 				(mtr_idx << mtr_id_offset), UINT32_MAX);
16584 		i = 0;
16585 		cnt = flow_dv_counter_get_by_idx(dev,
16586 					fm->drop_cnt, NULL);
16587 		actions[i++] = cnt->action;
16588 		actions[i++] = priv->sh->dr_drop_action;
16589 		misc_mask = flow_dv_matcher_enable(value.buf);
16590 		__flow_dv_adjust_buf_size(&value.size, misc_mask);
16591 		ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
16592 					       (void *)&value, i, actions,
16593 					       &fm->drop_rule[domain]);
16594 		if (ret) {
16595 			DRV_LOG(ERR, "Failed to create meter "
16596 				"drop rule for drop table.");
16597 				goto policy_error;
16598 		}
16599 	}
16600 	return 0;
16601 policy_error:
16602 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16603 		if (fm->drop_rule[i]) {
16604 			claim_zero(mlx5_flow_os_destroy_flow
16605 				(fm->drop_rule[i]));
16606 			fm->drop_rule[i] = NULL;
16607 		}
16608 	}
16609 	return -1;
16610 }
16611 
16612 static struct mlx5_flow_meter_sub_policy *
16613 __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev,
16614 		struct mlx5_flow_meter_policy *mtr_policy,
16615 		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS],
16616 		struct mlx5_flow_meter_sub_policy *next_sub_policy,
16617 		bool *is_reuse)
16618 {
16619 	struct mlx5_priv *priv = dev->data->dev_private;
16620 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
16621 	uint32_t sub_policy_idx = 0;
16622 	uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
16623 	uint32_t i, j;
16624 	struct mlx5_hrxq *hrxq;
16625 	struct mlx5_flow_handle dh;
16626 	struct mlx5_meter_policy_action_container *act_cnt;
16627 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
16628 	uint16_t sub_policy_num;
16629 
16630 	rte_spinlock_lock(&mtr_policy->sl);
16631 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16632 		if (!rss_desc[i])
16633 			continue;
16634 		hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]);
16635 		if (!hrxq_idx[i]) {
16636 			rte_spinlock_unlock(&mtr_policy->sl);
16637 			return NULL;
16638 		}
16639 	}
16640 	sub_policy_num = (mtr_policy->sub_policy_num >>
16641 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16642 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16643 	for (j = 0; j < sub_policy_num; j++) {
16644 		for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16645 			if (rss_desc[i] &&
16646 			    hrxq_idx[i] !=
16647 			    mtr_policy->sub_policys[domain][j]->rix_hrxq[i])
16648 				break;
16649 		}
16650 		if (i >= MLX5_MTR_RTE_COLORS) {
16651 			/*
16652 			 * Found the sub policy table with
16653 			 * the same queue per color.
16654 			 */
16655 			rte_spinlock_unlock(&mtr_policy->sl);
16656 			for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
16657 				mlx5_hrxq_release(dev, hrxq_idx[i]);
16658 			*is_reuse = true;
16659 			return mtr_policy->sub_policys[domain][j];
16660 		}
16661 	}
16662 	/* Create sub policy. */
16663 	if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) {
16664 		/* Reuse the first pre-allocated sub_policy. */
16665 		sub_policy = mtr_policy->sub_policys[domain][0];
16666 		sub_policy_idx = sub_policy->idx;
16667 	} else {
16668 		sub_policy = mlx5_ipool_zmalloc
16669 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16670 				 &sub_policy_idx);
16671 		if (!sub_policy ||
16672 		    sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) {
16673 			for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
16674 				mlx5_hrxq_release(dev, hrxq_idx[i]);
16675 			goto rss_sub_policy_error;
16676 		}
16677 		sub_policy->idx = sub_policy_idx;
16678 		sub_policy->main_policy = mtr_policy;
16679 	}
16680 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16681 		if (!rss_desc[i])
16682 			continue;
16683 		sub_policy->rix_hrxq[i] = hrxq_idx[i];
16684 		if (mtr_policy->is_hierarchy) {
16685 			act_cnt = &mtr_policy->act_cnt[i];
16686 			act_cnt->next_sub_policy = next_sub_policy;
16687 			mlx5_hrxq_release(dev, hrxq_idx[i]);
16688 		} else {
16689 			/*
16690 			 * Overwrite the last action from
16691 			 * RSS action to Queue action.
16692 			 */
16693 			hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
16694 					      hrxq_idx[i]);
16695 			if (!hrxq) {
16696 				DRV_LOG(ERR, "Failed to get policy hrxq");
16697 				goto rss_sub_policy_error;
16698 			}
16699 			act_cnt = &mtr_policy->act_cnt[i];
16700 			if (act_cnt->rix_mark || act_cnt->modify_hdr) {
16701 				memset(&dh, 0, sizeof(struct mlx5_flow_handle));
16702 				if (act_cnt->rix_mark)
16703 					dh.mark = 1;
16704 				dh.fate_action = MLX5_FLOW_FATE_QUEUE;
16705 				dh.rix_hrxq = hrxq_idx[i];
16706 				flow_drv_rxq_flags_set(dev, &dh);
16707 			}
16708 		}
16709 	}
16710 	if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
16711 					       sub_policy, domain)) {
16712 		DRV_LOG(ERR, "Failed to create policy "
16713 			"rules for ingress domain.");
16714 		goto rss_sub_policy_error;
16715 	}
16716 	if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16717 		i = (mtr_policy->sub_policy_num >>
16718 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16719 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16720 		if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) {
16721 			DRV_LOG(ERR, "No free sub-policy slot.");
16722 			goto rss_sub_policy_error;
16723 		}
16724 		mtr_policy->sub_policys[domain][i] = sub_policy;
16725 		i++;
16726 		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
16727 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
16728 		mtr_policy->sub_policy_num |=
16729 			(i & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
16730 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
16731 	}
16732 	rte_spinlock_unlock(&mtr_policy->sl);
16733 	*is_reuse = false;
16734 	return sub_policy;
16735 rss_sub_policy_error:
16736 	if (sub_policy) {
16737 		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
16738 		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16739 			i = (mtr_policy->sub_policy_num >>
16740 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16741 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16742 			mtr_policy->sub_policys[domain][i] = NULL;
16743 			mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16744 					sub_policy->idx);
16745 		}
16746 	}
16747 	rte_spinlock_unlock(&mtr_policy->sl);
16748 	return NULL;
16749 }
16750 
16751 /**
16752  * Find the policy table for prefix table with RSS.
16753  *
16754  * @param[in] dev
16755  *   Pointer to Ethernet device.
16756  * @param[in] mtr_policy
16757  *   Pointer to meter policy table.
16758  * @param[in] rss_desc
16759  *   Pointer to rss_desc
16760  * @return
16761  *   Pointer to table set on success, NULL otherwise and rte_errno is set.
16762  */
16763 static struct mlx5_flow_meter_sub_policy *
16764 flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
16765 		struct mlx5_flow_meter_policy *mtr_policy,
16766 		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
16767 {
16768 	struct mlx5_priv *priv = dev->data->dev_private;
16769 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
16770 	struct mlx5_flow_meter_info *next_fm;
16771 	struct mlx5_flow_meter_policy *next_policy;
16772 	struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL;
16773 	struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM];
16774 	struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM];
16775 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
16776 	bool reuse_sub_policy;
16777 	uint32_t i = 0;
16778 	uint32_t j = 0;
16779 
16780 	while (true) {
16781 		/* Iterate hierarchy to get all policies in this hierarchy. */
16782 		policies[i++] = mtr_policy;
16783 		if (!mtr_policy->is_hierarchy)
16784 			break;
16785 		if (i >= MLX5_MTR_CHAIN_MAX_NUM) {
16786 			DRV_LOG(ERR, "Exceed max meter number in hierarchy.");
16787 			return NULL;
16788 		}
16789 		next_fm = mlx5_flow_meter_find(priv,
16790 			mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
16791 		if (!next_fm) {
16792 			DRV_LOG(ERR, "Failed to get next meter in hierarchy.");
16793 			return NULL;
16794 		}
16795 		next_policy =
16796 			mlx5_flow_meter_policy_find(dev, next_fm->policy_id,
16797 						    NULL);
16798 		MLX5_ASSERT(next_policy);
16799 		mtr_policy = next_policy;
16800 	}
16801 	while (i) {
16802 		/**
16803 		 * From last policy to the first one in hierarchy,
16804 		 * create / get the sub policy for each of them.
16805 		 */
16806 		sub_policy = __flow_dv_meter_get_rss_sub_policy(dev,
16807 							policies[--i],
16808 							rss_desc,
16809 							next_sub_policy,
16810 							&reuse_sub_policy);
16811 		if (!sub_policy) {
16812 			DRV_LOG(ERR, "Failed to get the sub policy.");
16813 			goto err_exit;
16814 		}
16815 		if (!reuse_sub_policy)
16816 			sub_policies[j++] = sub_policy;
16817 		next_sub_policy = sub_policy;
16818 	}
16819 	return sub_policy;
16820 err_exit:
16821 	while (j) {
16822 		uint16_t sub_policy_num;
16823 
16824 		sub_policy = sub_policies[--j];
16825 		mtr_policy = sub_policy->main_policy;
16826 		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
16827 		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16828 			sub_policy_num = (mtr_policy->sub_policy_num >>
16829 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16830 				MLX5_MTR_SUB_POLICY_NUM_MASK;
16831 			mtr_policy->sub_policys[domain][sub_policy_num - 1] =
16832 									NULL;
16833 			sub_policy_num--;
16834 			mtr_policy->sub_policy_num &=
16835 				~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
16836 				  (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
16837 			mtr_policy->sub_policy_num |=
16838 			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
16839 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
16840 			mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16841 					sub_policy->idx);
16842 		}
16843 	}
16844 	return NULL;
16845 }
16846 
16847 /**
16848  * Create the sub policy tag rule for all meters in hierarchy.
16849  *
16850  * @param[in] dev
16851  *   Pointer to Ethernet device.
16852  * @param[in] fm
16853  *   Meter information table.
16854  * @param[in] src_port
16855  *   The src port this extra rule should use.
16856  * @param[in] item
16857  *   The src port match item.
16858  * @param[out] error
16859  *   Perform verbose error reporting if not NULL.
16860  * @return
16861  *   0 on success, a negative errno value otherwise and rte_errno is set.
16862  */
16863 static int
16864 flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev,
16865 				struct mlx5_flow_meter_info *fm,
16866 				int32_t src_port,
16867 				const struct rte_flow_item *item,
16868 				struct rte_flow_error *error)
16869 {
16870 	struct mlx5_priv *priv = dev->data->dev_private;
16871 	struct mlx5_flow_meter_policy *mtr_policy;
16872 	struct mlx5_flow_meter_sub_policy *sub_policy;
16873 	struct mlx5_flow_meter_info *next_fm = NULL;
16874 	struct mlx5_flow_meter_policy *next_policy;
16875 	struct mlx5_flow_meter_sub_policy *next_sub_policy;
16876 	struct mlx5_flow_tbl_data_entry *tbl_data;
16877 	struct mlx5_sub_policy_color_rule *color_rule;
16878 	struct mlx5_meter_policy_acts acts;
16879 	uint32_t color_reg_c_idx;
16880 	bool mtr_first = (src_port != UINT16_MAX) ? true : false;
16881 	struct rte_flow_attr attr = {
16882 		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
16883 		.priority = 0,
16884 		.ingress = 0,
16885 		.egress = 0,
16886 		.transfer = 1,
16887 		.reserved = 0,
16888 	};
16889 	uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER;
16890 	int i;
16891 
16892 	mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
16893 	MLX5_ASSERT(mtr_policy);
16894 	if (!mtr_policy->is_hierarchy)
16895 		return 0;
16896 	next_fm = mlx5_flow_meter_find(priv,
16897 			mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
16898 	if (!next_fm) {
16899 		return rte_flow_error_set(error, EINVAL,
16900 				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
16901 				"Failed to find next meter in hierarchy.");
16902 	}
16903 	if (!next_fm->drop_cnt)
16904 		goto exit;
16905 	color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error);
16906 	sub_policy = mtr_policy->sub_policys[domain][0];
16907 	for (i = 0; i < RTE_COLORS; i++) {
16908 		bool rule_exist = false;
16909 		struct mlx5_meter_policy_action_container *act_cnt;
16910 
16911 		if (i >= RTE_COLOR_YELLOW)
16912 			break;
16913 		TAILQ_FOREACH(color_rule,
16914 			      &sub_policy->color_rules[i], next_port)
16915 			if (color_rule->src_port == src_port) {
16916 				rule_exist = true;
16917 				break;
16918 			}
16919 		if (rule_exist)
16920 			continue;
16921 		color_rule = mlx5_malloc(MLX5_MEM_ZERO,
16922 				sizeof(struct mlx5_sub_policy_color_rule),
16923 				0, SOCKET_ID_ANY);
16924 		if (!color_rule)
16925 			return rte_flow_error_set(error, ENOMEM,
16926 				RTE_FLOW_ERROR_TYPE_ACTION,
16927 				NULL, "No memory to create tag color rule.");
16928 		color_rule->src_port = src_port;
16929 		attr.priority = i;
16930 		next_policy = mlx5_flow_meter_policy_find(dev,
16931 						next_fm->policy_id, NULL);
16932 		MLX5_ASSERT(next_policy);
16933 		next_sub_policy = next_policy->sub_policys[domain][0];
16934 		tbl_data = container_of(next_sub_policy->tbl_rsc,
16935 					struct mlx5_flow_tbl_data_entry, tbl);
16936 		act_cnt = &mtr_policy->act_cnt[i];
16937 		if (mtr_first) {
16938 			acts.dv_actions[0] = next_fm->meter_action;
16939 			acts.dv_actions[1] = act_cnt->modify_hdr->action;
16940 		} else {
16941 			acts.dv_actions[0] = act_cnt->modify_hdr->action;
16942 			acts.dv_actions[1] = next_fm->meter_action;
16943 		}
16944 		acts.dv_actions[2] = tbl_data->jump.action;
16945 		acts.actions_n = 3;
16946 		if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) {
16947 			next_fm = NULL;
16948 			goto err_exit;
16949 		}
16950 		if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
16951 				MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
16952 				&attr, true, item,
16953 				&color_rule->matcher, error)) {
16954 			rte_flow_error_set(error, errno,
16955 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
16956 				"Failed to create hierarchy meter matcher.");
16957 			goto err_exit;
16958 		}
16959 		if (__flow_dv_create_policy_flow(dev, color_reg_c_idx,
16960 					(enum rte_color)i,
16961 					color_rule->matcher->matcher_object,
16962 					acts.actions_n, acts.dv_actions,
16963 					true, item,
16964 					&color_rule->rule, &attr)) {
16965 			rte_flow_error_set(error, errno,
16966 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
16967 				"Failed to create hierarchy meter rule.");
16968 			goto err_exit;
16969 		}
16970 		TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
16971 				  color_rule, next_port);
16972 	}
16973 exit:
16974 	/**
16975 	 * Recursive call to iterate all meters in hierarchy and
16976 	 * create needed rules.
16977 	 */
16978 	return flow_dv_meter_hierarchy_rule_create(dev, next_fm,
16979 						src_port, item, error);
16980 err_exit:
16981 	if (color_rule) {
16982 		if (color_rule->rule)
16983 			mlx5_flow_os_destroy_flow(color_rule->rule);
16984 		if (color_rule->matcher) {
16985 			struct mlx5_flow_tbl_data_entry *tbl =
16986 				container_of(color_rule->matcher->tbl,
16987 						typeof(*tbl), tbl);
16988 			mlx5_list_unregister(tbl->matchers,
16989 						&color_rule->matcher->entry);
16990 		}
16991 		mlx5_free(color_rule);
16992 	}
16993 	if (next_fm)
16994 		mlx5_flow_meter_detach(priv, next_fm);
16995 	return -rte_errno;
16996 }
16997 
16998 /**
16999  * Destroy the sub policy table with RX queue.
17000  *
17001  * @param[in] dev
17002  *   Pointer to Ethernet device.
17003  * @param[in] mtr_policy
17004  *   Pointer to meter policy table.
17005  */
17006 static void
17007 flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev,
17008 				    struct mlx5_flow_meter_policy *mtr_policy)
17009 {
17010 	struct mlx5_priv *priv = dev->data->dev_private;
17011 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
17012 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
17013 	uint32_t i, j;
17014 	uint16_t sub_policy_num, new_policy_num;
17015 
17016 	rte_spinlock_lock(&mtr_policy->sl);
17017 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
17018 		switch (mtr_policy->act_cnt[i].fate_action) {
17019 		case MLX5_FLOW_FATE_SHARED_RSS:
17020 			sub_policy_num = (mtr_policy->sub_policy_num >>
17021 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
17022 			MLX5_MTR_SUB_POLICY_NUM_MASK;
17023 			new_policy_num = sub_policy_num;
17024 			for (j = 0; j < sub_policy_num; j++) {
17025 				sub_policy =
17026 					mtr_policy->sub_policys[domain][j];
17027 				if (sub_policy) {
17028 					__flow_dv_destroy_sub_policy_rules(dev,
17029 						sub_policy);
17030 				if (sub_policy !=
17031 					mtr_policy->sub_policys[domain][0]) {
17032 					mtr_policy->sub_policys[domain][j] =
17033 								NULL;
17034 					mlx5_ipool_free
17035 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
17036 						sub_policy->idx);
17037 						new_policy_num--;
17038 					}
17039 				}
17040 			}
17041 			if (new_policy_num != sub_policy_num) {
17042 				mtr_policy->sub_policy_num &=
17043 				~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
17044 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
17045 				mtr_policy->sub_policy_num |=
17046 				(new_policy_num &
17047 					MLX5_MTR_SUB_POLICY_NUM_MASK) <<
17048 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
17049 			}
17050 			break;
17051 		case MLX5_FLOW_FATE_QUEUE:
17052 			sub_policy = mtr_policy->sub_policys[domain][0];
17053 			__flow_dv_destroy_sub_policy_rules(dev,
17054 							   sub_policy);
17055 			break;
17056 		default:
17057 			/*Other actions without queue and do nothing*/
17058 			break;
17059 		}
17060 	}
17061 	rte_spinlock_unlock(&mtr_policy->sl);
17062 }
17063 /**
17064  * Check whether the DR drop action is supported on the root table or not.
17065  *
17066  * Create a simple flow with DR drop action on root table to validate
17067  * if DR drop action on root table is supported or not.
17068  *
17069  * @param[in] dev
17070  *   Pointer to rte_eth_dev structure.
17071  *
17072  * @return
17073  *   0 on success, a negative errno value otherwise and rte_errno is set.
17074  */
17075 int
17076 mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev)
17077 {
17078 	struct mlx5_priv *priv = dev->data->dev_private;
17079 	struct mlx5_dev_ctx_shared *sh = priv->sh;
17080 	struct mlx5_flow_dv_match_params mask = {
17081 		.size = sizeof(mask.buf),
17082 	};
17083 	struct mlx5_flow_dv_match_params value = {
17084 		.size = sizeof(value.buf),
17085 	};
17086 	struct mlx5dv_flow_matcher_attr dv_attr = {
17087 		.type = IBV_FLOW_ATTR_NORMAL,
17088 		.priority = 0,
17089 		.match_criteria_enable = 0,
17090 		.match_mask = (void *)&mask,
17091 	};
17092 	struct mlx5_flow_tbl_resource *tbl = NULL;
17093 	void *matcher = NULL;
17094 	void *flow = NULL;
17095 	int ret = -1;
17096 
17097 	tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL,
17098 					0, 0, 0, NULL);
17099 	if (!tbl)
17100 		goto err;
17101 	dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
17102 	__flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
17103 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj,
17104 					       &matcher);
17105 	if (ret)
17106 		goto err;
17107 	__flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
17108 	ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
17109 				       &sh->dr_drop_action, &flow);
17110 err:
17111 	/*
17112 	 * If DR drop action is not supported on root table, flow create will
17113 	 * be failed with EOPNOTSUPP or EPROTONOSUPPORT.
17114 	 */
17115 	if (!flow) {
17116 		if (matcher &&
17117 		    (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP))
17118 			DRV_LOG(INFO, "DR drop action is not supported in root table.");
17119 		else
17120 			DRV_LOG(ERR, "Unexpected error in DR drop action support detection");
17121 		ret = -1;
17122 	} else {
17123 		claim_zero(mlx5_flow_os_destroy_flow(flow));
17124 	}
17125 	if (matcher)
17126 		claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
17127 	if (tbl)
17128 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
17129 	return ret;
17130 }
17131 
17132 /**
17133  * Validate the batch counter support in root table.
17134  *
17135  * Create a simple flow with invalid counter and drop action on root table to
17136  * validate if batch counter with offset on root table is supported or not.
17137  *
17138  * @param[in] dev
17139  *   Pointer to rte_eth_dev structure.
17140  *
17141  * @return
17142  *   0 on success, a negative errno value otherwise and rte_errno is set.
17143  */
17144 int
17145 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev)
17146 {
17147 	struct mlx5_priv *priv = dev->data->dev_private;
17148 	struct mlx5_dev_ctx_shared *sh = priv->sh;
17149 	struct mlx5_flow_dv_match_params mask = {
17150 		.size = sizeof(mask.buf),
17151 	};
17152 	struct mlx5_flow_dv_match_params value = {
17153 		.size = sizeof(value.buf),
17154 	};
17155 	struct mlx5dv_flow_matcher_attr dv_attr = {
17156 		.type = IBV_FLOW_ATTR_NORMAL | IBV_FLOW_ATTR_FLAGS_EGRESS,
17157 		.priority = 0,
17158 		.match_criteria_enable = 0,
17159 		.match_mask = (void *)&mask,
17160 	};
17161 	void *actions[2] = { 0 };
17162 	struct mlx5_flow_tbl_resource *tbl = NULL;
17163 	struct mlx5_devx_obj *dcs = NULL;
17164 	void *matcher = NULL;
17165 	void *flow = NULL;
17166 	int ret = -1;
17167 
17168 	tbl = flow_dv_tbl_resource_get(dev, 0, 1, 0, false, NULL,
17169 					0, 0, 0, NULL);
17170 	if (!tbl)
17171 		goto err;
17172 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4);
17173 	if (!dcs)
17174 		goto err;
17175 	ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX,
17176 						    &actions[0]);
17177 	if (ret)
17178 		goto err;
17179 	dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
17180 	__flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
17181 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj,
17182 					       &matcher);
17183 	if (ret)
17184 		goto err;
17185 	__flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
17186 	ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
17187 				       actions, &flow);
17188 err:
17189 	/*
17190 	 * If batch counter with offset is not supported, the driver will not
17191 	 * validate the invalid offset value, flow create should success.
17192 	 * In this case, it means batch counter is not supported in root table.
17193 	 *
17194 	 * Otherwise, if flow create is failed, counter offset is supported.
17195 	 */
17196 	if (flow) {
17197 		DRV_LOG(INFO, "Batch counter is not supported in root "
17198 			      "table. Switch to fallback mode.");
17199 		rte_errno = ENOTSUP;
17200 		ret = -rte_errno;
17201 		claim_zero(mlx5_flow_os_destroy_flow(flow));
17202 	} else {
17203 		/* Check matcher to make sure validate fail at flow create. */
17204 		if (!matcher || (matcher && errno != EINVAL))
17205 			DRV_LOG(ERR, "Unexpected error in counter offset "
17206 				     "support detection");
17207 		ret = 0;
17208 	}
17209 	if (actions[0])
17210 		claim_zero(mlx5_flow_os_destroy_flow_action(actions[0]));
17211 	if (matcher)
17212 		claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
17213 	if (tbl)
17214 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
17215 	if (dcs)
17216 		claim_zero(mlx5_devx_cmd_destroy(dcs));
17217 	return ret;
17218 }
17219 
17220 /**
17221  * Query a devx counter.
17222  *
17223  * @param[in] dev
17224  *   Pointer to the Ethernet device structure.
17225  * @param[in] cnt
17226  *   Index to the flow counter.
17227  * @param[in] clear
17228  *   Set to clear the counter statistics.
17229  * @param[out] pkts
17230  *   The statistics value of packets.
17231  * @param[out] bytes
17232  *   The statistics value of bytes.
17233  *
17234  * @return
17235  *   0 on success, otherwise return -1.
17236  */
17237 static int
17238 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear,
17239 		      uint64_t *pkts, uint64_t *bytes)
17240 {
17241 	struct mlx5_priv *priv = dev->data->dev_private;
17242 	struct mlx5_flow_counter *cnt;
17243 	uint64_t inn_pkts, inn_bytes;
17244 	int ret;
17245 
17246 	if (!priv->config.devx)
17247 		return -1;
17248 
17249 	ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes);
17250 	if (ret)
17251 		return -1;
17252 	cnt = flow_dv_counter_get_by_idx(dev, counter, NULL);
17253 	*pkts = inn_pkts - cnt->hits;
17254 	*bytes = inn_bytes - cnt->bytes;
17255 	if (clear) {
17256 		cnt->hits = inn_pkts;
17257 		cnt->bytes = inn_bytes;
17258 	}
17259 	return 0;
17260 }
17261 
17262 /**
17263  * Get aged-out flows.
17264  *
17265  * @param[in] dev
17266  *   Pointer to the Ethernet device structure.
17267  * @param[in] context
17268  *   The address of an array of pointers to the aged-out flows contexts.
17269  * @param[in] nb_contexts
17270  *   The length of context array pointers.
17271  * @param[out] error
17272  *   Perform verbose error reporting if not NULL. Initialized in case of
17273  *   error only.
17274  *
17275  * @return
17276  *   how many contexts get in success, otherwise negative errno value.
17277  *   if nb_contexts is 0, return the amount of all aged contexts.
17278  *   if nb_contexts is not 0 , return the amount of aged flows reported
17279  *   in the context array.
17280  * @note: only stub for now
17281  */
17282 static int
17283 flow_dv_get_aged_flows(struct rte_eth_dev *dev,
17284 		    void **context,
17285 		    uint32_t nb_contexts,
17286 		    struct rte_flow_error *error)
17287 {
17288 	struct mlx5_priv *priv = dev->data->dev_private;
17289 	struct mlx5_age_info *age_info;
17290 	struct mlx5_age_param *age_param;
17291 	struct mlx5_flow_counter *counter;
17292 	struct mlx5_aso_age_action *act;
17293 	int nb_flows = 0;
17294 
17295 	if (nb_contexts && !context)
17296 		return rte_flow_error_set(error, EINVAL,
17297 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
17298 					  NULL, "empty context");
17299 	age_info = GET_PORT_AGE_INFO(priv);
17300 	rte_spinlock_lock(&age_info->aged_sl);
17301 	LIST_FOREACH(act, &age_info->aged_aso, next) {
17302 		nb_flows++;
17303 		if (nb_contexts) {
17304 			context[nb_flows - 1] =
17305 						act->age_params.context;
17306 			if (!(--nb_contexts))
17307 				break;
17308 		}
17309 	}
17310 	TAILQ_FOREACH(counter, &age_info->aged_counters, next) {
17311 		nb_flows++;
17312 		if (nb_contexts) {
17313 			age_param = MLX5_CNT_TO_AGE(counter);
17314 			context[nb_flows - 1] = age_param->context;
17315 			if (!(--nb_contexts))
17316 				break;
17317 		}
17318 	}
17319 	rte_spinlock_unlock(&age_info->aged_sl);
17320 	MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER);
17321 	return nb_flows;
17322 }
17323 
17324 /*
17325  * Mutex-protected thunk to lock-free flow_dv_counter_alloc().
17326  */
17327 static uint32_t
17328 flow_dv_counter_allocate(struct rte_eth_dev *dev)
17329 {
17330 	return flow_dv_counter_alloc(dev, 0);
17331 }
17332 
17333 /**
17334  * Validate indirect action.
17335  * Dispatcher for action type specific validation.
17336  *
17337  * @param[in] dev
17338  *   Pointer to the Ethernet device structure.
17339  * @param[in] conf
17340  *   Indirect action configuration.
17341  * @param[in] action
17342  *   The indirect action object to validate.
17343  * @param[out] error
17344  *   Perform verbose error reporting if not NULL. Initialized in case of
17345  *   error only.
17346  *
17347  * @return
17348  *   0 on success, otherwise negative errno value.
17349  */
17350 static int
17351 flow_dv_action_validate(struct rte_eth_dev *dev,
17352 			const struct rte_flow_indir_action_conf *conf,
17353 			const struct rte_flow_action *action,
17354 			struct rte_flow_error *err)
17355 {
17356 	struct mlx5_priv *priv = dev->data->dev_private;
17357 
17358 	RTE_SET_USED(conf);
17359 	switch (action->type) {
17360 	case RTE_FLOW_ACTION_TYPE_RSS:
17361 		/*
17362 		 * priv->obj_ops is set according to driver capabilities.
17363 		 * When DevX capabilities are
17364 		 * sufficient, it is set to devx_obj_ops.
17365 		 * Otherwise, it is set to ibv_obj_ops.
17366 		 * ibv_obj_ops doesn't support ind_table_modify operation.
17367 		 * In this case the indirect RSS action can't be used.
17368 		 */
17369 		if (priv->obj_ops.ind_table_modify == NULL)
17370 			return rte_flow_error_set
17371 					(err, ENOTSUP,
17372 					 RTE_FLOW_ERROR_TYPE_ACTION,
17373 					 NULL,
17374 					 "Indirect RSS action not supported");
17375 		return mlx5_validate_action_rss(dev, action, err);
17376 	case RTE_FLOW_ACTION_TYPE_AGE:
17377 		if (!priv->sh->aso_age_mng)
17378 			return rte_flow_error_set(err, ENOTSUP,
17379 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
17380 						NULL,
17381 						"Indirect age action not supported");
17382 		return flow_dv_validate_action_age(0, action, dev, err);
17383 	case RTE_FLOW_ACTION_TYPE_COUNT:
17384 		return flow_dv_validate_action_count(dev, true, 0, err);
17385 	case RTE_FLOW_ACTION_TYPE_CONNTRACK:
17386 		if (!priv->sh->ct_aso_en)
17387 			return rte_flow_error_set(err, ENOTSUP,
17388 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
17389 					"ASO CT is not supported");
17390 		return mlx5_validate_action_ct(dev, action->conf, err);
17391 	default:
17392 		return rte_flow_error_set(err, ENOTSUP,
17393 					  RTE_FLOW_ERROR_TYPE_ACTION,
17394 					  NULL,
17395 					  "action type not supported");
17396 	}
17397 }
17398 
17399 /*
17400  * Check if the RSS configurations for colors of a meter policy match
17401  * each other, except the queues.
17402  *
17403  * @param[in] r1
17404  *   Pointer to the first RSS flow action.
17405  * @param[in] r2
17406  *   Pointer to the second RSS flow action.
17407  *
17408  * @return
17409  *   0 on match, 1 on conflict.
17410  */
17411 static inline int
17412 flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1,
17413 			       const struct rte_flow_action_rss *r2)
17414 {
17415 	if (!r1 || !r2)
17416 		return 0;
17417 	if (r1->func != r2->func || r1->level != r2->level ||
17418 	    r1->types != r2->types || r1->key_len != r2->key_len ||
17419 	    memcmp(r1->key, r2->key, r1->key_len))
17420 		return 1;
17421 	return 0;
17422 }
17423 
17424 /**
17425  * Validate the meter hierarchy chain for meter policy.
17426  *
17427  * @param[in] dev
17428  *   Pointer to the Ethernet device structure.
17429  * @param[in] meter_id
17430  *   Meter id.
17431  * @param[in] action_flags
17432  *   Holds the actions detected until now.
17433  * @param[out] is_rss
17434  *   Is RSS or not.
17435  * @param[out] hierarchy_domain
17436  *   The domain bitmap for hierarchy policy.
17437  * @param[out] error
17438  *   Perform verbose error reporting if not NULL. Initialized in case of
17439  *   error only.
17440  *
17441  * @return
17442  *   0 on success, otherwise negative errno value with error set.
17443  */
17444 static int
17445 flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev,
17446 				  uint32_t meter_id,
17447 				  uint64_t action_flags,
17448 				  bool *is_rss,
17449 				  uint8_t *hierarchy_domain,
17450 				  struct rte_mtr_error *error)
17451 {
17452 	struct mlx5_priv *priv = dev->data->dev_private;
17453 	struct mlx5_flow_meter_info *fm;
17454 	struct mlx5_flow_meter_policy *policy;
17455 	uint8_t cnt = 1;
17456 
17457 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
17458 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
17459 		return -rte_mtr_error_set(error, EINVAL,
17460 					RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN,
17461 					NULL,
17462 					"Multiple fate actions not supported.");
17463 	*hierarchy_domain = 0;
17464 	while (true) {
17465 		fm = mlx5_flow_meter_find(priv, meter_id, NULL);
17466 		if (!fm)
17467 			return -rte_mtr_error_set(error, EINVAL,
17468 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
17469 					"Meter not found in meter hierarchy.");
17470 		if (fm->def_policy)
17471 			return -rte_mtr_error_set(error, EINVAL,
17472 					RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
17473 			"Non termination meter not supported in hierarchy.");
17474 		policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
17475 		MLX5_ASSERT(policy);
17476 		/**
17477 		 * Only inherit the supported domains of the first meter in
17478 		 * hierarchy.
17479 		 * One meter supports at least one domain.
17480 		 */
17481 		if (!*hierarchy_domain) {
17482 			if (policy->transfer)
17483 				*hierarchy_domain |=
17484 						MLX5_MTR_DOMAIN_TRANSFER_BIT;
17485 			if (policy->ingress)
17486 				*hierarchy_domain |=
17487 						MLX5_MTR_DOMAIN_INGRESS_BIT;
17488 			if (policy->egress)
17489 				*hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT;
17490 		}
17491 		if (!policy->is_hierarchy) {
17492 			*is_rss = policy->is_rss;
17493 			break;
17494 		}
17495 		meter_id = policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id;
17496 		if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM)
17497 			return -rte_mtr_error_set(error, EINVAL,
17498 					RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
17499 					"Exceed max hierarchy meter number.");
17500 	}
17501 	return 0;
17502 }
17503 
17504 /**
17505  * Validate meter policy actions.
17506  * Dispatcher for action type specific validation.
17507  *
17508  * @param[in] dev
17509  *   Pointer to the Ethernet device structure.
17510  * @param[in] action
17511  *   The meter policy action object to validate.
17512  * @param[in] attr
17513  *   Attributes of flow to determine steering domain.
17514  * @param[out] error
17515  *   Perform verbose error reporting if not NULL. Initialized in case of
17516  *   error only.
17517  *
17518  * @return
17519  *   0 on success, otherwise negative errno value.
17520  */
17521 static int
17522 flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
17523 			const struct rte_flow_action *actions[RTE_COLORS],
17524 			struct rte_flow_attr *attr,
17525 			bool *is_rss,
17526 			uint8_t *domain_bitmap,
17527 			uint8_t *policy_mode,
17528 			struct rte_mtr_error *error)
17529 {
17530 	struct mlx5_priv *priv = dev->data->dev_private;
17531 	struct mlx5_dev_config *dev_conf = &priv->config;
17532 	const struct rte_flow_action *act;
17533 	uint64_t action_flags[RTE_COLORS] = {0};
17534 	int actions_n;
17535 	int i, ret;
17536 	struct rte_flow_error flow_err;
17537 	uint8_t domain_color[RTE_COLORS] = {0};
17538 	uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
17539 	uint8_t hierarchy_domain = 0;
17540 	const struct rte_flow_action_meter *mtr;
17541 	bool def_green = false;
17542 	bool def_yellow = false;
17543 	const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL};
17544 
17545 	if (!priv->config.dv_esw_en)
17546 		def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
17547 	*domain_bitmap = def_domain;
17548 	/* Red color could only support DROP action. */
17549 	if (!actions[RTE_COLOR_RED] ||
17550 	    actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP)
17551 		return -rte_mtr_error_set(error, ENOTSUP,
17552 				RTE_MTR_ERROR_TYPE_METER_POLICY,
17553 				NULL, "Red color only supports drop action.");
17554 	/*
17555 	 * Check default policy actions:
17556 	 * Green / Yellow: no action, Red: drop action
17557 	 * Either G or Y will trigger default policy actions to be created.
17558 	 */
17559 	if (!actions[RTE_COLOR_GREEN] ||
17560 	    actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END)
17561 		def_green = true;
17562 	if (!actions[RTE_COLOR_YELLOW] ||
17563 	    actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END)
17564 		def_yellow = true;
17565 	if (def_green && def_yellow) {
17566 		*policy_mode = MLX5_MTR_POLICY_MODE_DEF;
17567 		return 0;
17568 	} else if (!def_green && def_yellow) {
17569 		*policy_mode = MLX5_MTR_POLICY_MODE_OG;
17570 	} else if (def_green && !def_yellow) {
17571 		*policy_mode = MLX5_MTR_POLICY_MODE_OY;
17572 	}
17573 	/* Set to empty string in case of NULL pointer access by user. */
17574 	flow_err.message = "";
17575 	for (i = 0; i < RTE_COLORS; i++) {
17576 		act = actions[i];
17577 		for (action_flags[i] = 0, actions_n = 0;
17578 		     act && act->type != RTE_FLOW_ACTION_TYPE_END;
17579 		     act++) {
17580 			if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
17581 				return -rte_mtr_error_set(error, ENOTSUP,
17582 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17583 					  NULL, "too many actions");
17584 			switch (act->type) {
17585 			case RTE_FLOW_ACTION_TYPE_PORT_ID:
17586 				if (!priv->config.dv_esw_en)
17587 					return -rte_mtr_error_set(error,
17588 					ENOTSUP,
17589 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17590 					NULL, "PORT action validate check"
17591 					" fail for ESW disable");
17592 				ret = flow_dv_validate_action_port_id(dev,
17593 						action_flags[i],
17594 						act, attr, &flow_err);
17595 				if (ret)
17596 					return -rte_mtr_error_set(error,
17597 					ENOTSUP,
17598 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17599 					NULL, flow_err.message ?
17600 					flow_err.message :
17601 					"PORT action validate check fail");
17602 				++actions_n;
17603 				action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID;
17604 				break;
17605 			case RTE_FLOW_ACTION_TYPE_MARK:
17606 				ret = flow_dv_validate_action_mark(dev, act,
17607 							   action_flags[i],
17608 							   attr, &flow_err);
17609 				if (ret < 0)
17610 					return -rte_mtr_error_set(error,
17611 					ENOTSUP,
17612 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17613 					NULL, flow_err.message ?
17614 					flow_err.message :
17615 					"Mark action validate check fail");
17616 				if (dev_conf->dv_xmeta_en !=
17617 					MLX5_XMETA_MODE_LEGACY)
17618 					return -rte_mtr_error_set(error,
17619 					ENOTSUP,
17620 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17621 					NULL, "Extend MARK action is "
17622 					"not supported. Please try use "
17623 					"default policy for meter.");
17624 				action_flags[i] |= MLX5_FLOW_ACTION_MARK;
17625 				++actions_n;
17626 				break;
17627 			case RTE_FLOW_ACTION_TYPE_SET_TAG:
17628 				ret = flow_dv_validate_action_set_tag(dev,
17629 							act, action_flags[i],
17630 							attr, &flow_err);
17631 				if (ret)
17632 					return -rte_mtr_error_set(error,
17633 					ENOTSUP,
17634 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17635 					NULL, flow_err.message ?
17636 					flow_err.message :
17637 					"Set tag action validate check fail");
17638 				action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG;
17639 				++actions_n;
17640 				break;
17641 			case RTE_FLOW_ACTION_TYPE_DROP:
17642 				ret = mlx5_flow_validate_action_drop
17643 					(action_flags[i], attr, &flow_err);
17644 				if (ret < 0)
17645 					return -rte_mtr_error_set(error,
17646 					ENOTSUP,
17647 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17648 					NULL, flow_err.message ?
17649 					flow_err.message :
17650 					"Drop action validate check fail");
17651 				action_flags[i] |= MLX5_FLOW_ACTION_DROP;
17652 				++actions_n;
17653 				break;
17654 			case RTE_FLOW_ACTION_TYPE_QUEUE:
17655 				/*
17656 				 * Check whether extensive
17657 				 * metadata feature is engaged.
17658 				 */
17659 				if (dev_conf->dv_flow_en &&
17660 				    (dev_conf->dv_xmeta_en !=
17661 				     MLX5_XMETA_MODE_LEGACY) &&
17662 				    mlx5_flow_ext_mreg_supported(dev))
17663 					return -rte_mtr_error_set(error,
17664 					  ENOTSUP,
17665 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17666 					  NULL, "Queue action with meta "
17667 					  "is not supported. Please try use "
17668 					  "default policy for meter.");
17669 				ret = mlx5_flow_validate_action_queue(act,
17670 							action_flags[i], dev,
17671 							attr, &flow_err);
17672 				if (ret < 0)
17673 					return -rte_mtr_error_set(error,
17674 					  ENOTSUP,
17675 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17676 					  NULL, flow_err.message ?
17677 					  flow_err.message :
17678 					  "Queue action validate check fail");
17679 				action_flags[i] |= MLX5_FLOW_ACTION_QUEUE;
17680 				++actions_n;
17681 				break;
17682 			case RTE_FLOW_ACTION_TYPE_RSS:
17683 				if (dev_conf->dv_flow_en &&
17684 				    (dev_conf->dv_xmeta_en !=
17685 				     MLX5_XMETA_MODE_LEGACY) &&
17686 				    mlx5_flow_ext_mreg_supported(dev))
17687 					return -rte_mtr_error_set(error,
17688 					  ENOTSUP,
17689 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17690 					  NULL, "RSS action with meta "
17691 					  "is not supported. Please try use "
17692 					  "default policy for meter.");
17693 				ret = mlx5_validate_action_rss(dev, act,
17694 							       &flow_err);
17695 				if (ret < 0)
17696 					return -rte_mtr_error_set(error,
17697 					  ENOTSUP,
17698 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17699 					  NULL, flow_err.message ?
17700 					  flow_err.message :
17701 					  "RSS action validate check fail");
17702 				action_flags[i] |= MLX5_FLOW_ACTION_RSS;
17703 				++actions_n;
17704 				/* Either G or Y will set the RSS. */
17705 				rss_color[i] = act->conf;
17706 				break;
17707 			case RTE_FLOW_ACTION_TYPE_JUMP:
17708 				ret = flow_dv_validate_action_jump(dev,
17709 					NULL, act, action_flags[i],
17710 					attr, true, &flow_err);
17711 				if (ret)
17712 					return -rte_mtr_error_set(error,
17713 					  ENOTSUP,
17714 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17715 					  NULL, flow_err.message ?
17716 					  flow_err.message :
17717 					  "Jump action validate check fail");
17718 				++actions_n;
17719 				action_flags[i] |= MLX5_FLOW_ACTION_JUMP;
17720 				break;
17721 			/*
17722 			 * Only the last meter in the hierarchy will support
17723 			 * the YELLOW color steering. Then in the meter policy
17724 			 * actions list, there should be no other meter inside.
17725 			 */
17726 			case RTE_FLOW_ACTION_TYPE_METER:
17727 				if (i != RTE_COLOR_GREEN)
17728 					return -rte_mtr_error_set(error,
17729 						ENOTSUP,
17730 						RTE_MTR_ERROR_TYPE_METER_POLICY,
17731 						NULL,
17732 						"Meter hierarchy only supports GREEN color.");
17733 				if (*policy_mode != MLX5_MTR_POLICY_MODE_OG)
17734 					return -rte_mtr_error_set(error,
17735 						ENOTSUP,
17736 						RTE_MTR_ERROR_TYPE_METER_POLICY,
17737 						NULL,
17738 						"No yellow policy should be provided in meter hierarchy.");
17739 				mtr = act->conf;
17740 				ret = flow_dv_validate_policy_mtr_hierarchy(dev,
17741 							mtr->mtr_id,
17742 							action_flags[i],
17743 							is_rss,
17744 							&hierarchy_domain,
17745 							error);
17746 				if (ret)
17747 					return ret;
17748 				++actions_n;
17749 				action_flags[i] |=
17750 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
17751 				break;
17752 			default:
17753 				return -rte_mtr_error_set(error, ENOTSUP,
17754 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17755 					NULL,
17756 					"Doesn't support optional action");
17757 			}
17758 		}
17759 		if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID)
17760 			domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
17761 		else if ((action_flags[i] &
17762 			  (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
17763 			 (action_flags[i] & MLX5_FLOW_ACTION_MARK))
17764 			/*
17765 			 * Only support MLX5_XMETA_MODE_LEGACY
17766 			 * so MARK action is only in ingress domain.
17767 			 */
17768 			domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
17769 		else
17770 			domain_color[i] = def_domain;
17771 		if (action_flags[i] &
17772 		    MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
17773 			domain_color[i] &= hierarchy_domain;
17774 		/*
17775 		 * Non-termination actions only support NIC Tx domain.
17776 		 * The adjustion should be skipped when there is no
17777 		 * action or only END is provided. The default domains
17778 		 * bit-mask is set to find the MIN intersection.
17779 		 * The action flags checking should also be skipped.
17780 		 */
17781 		if ((def_green && i == RTE_COLOR_GREEN) ||
17782 		    (def_yellow && i == RTE_COLOR_YELLOW))
17783 			continue;
17784 		/*
17785 		 * Validate the drop action mutual exclusion
17786 		 * with other actions. Drop action is mutually-exclusive
17787 		 * with any other action, except for Count action.
17788 		 */
17789 		if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) &&
17790 		    (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) {
17791 			return -rte_mtr_error_set(error, ENOTSUP,
17792 				RTE_MTR_ERROR_TYPE_METER_POLICY,
17793 				NULL, "Drop action is mutually-exclusive "
17794 				"with any other action");
17795 		}
17796 		/* Eswitch has few restrictions on using items and actions */
17797 		if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
17798 			if (!mlx5_flow_ext_mreg_supported(dev) &&
17799 			    action_flags[i] & MLX5_FLOW_ACTION_MARK)
17800 				return -rte_mtr_error_set(error, ENOTSUP,
17801 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17802 					NULL, "unsupported action MARK");
17803 			if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE)
17804 				return -rte_mtr_error_set(error, ENOTSUP,
17805 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17806 					NULL, "unsupported action QUEUE");
17807 			if (action_flags[i] & MLX5_FLOW_ACTION_RSS)
17808 				return -rte_mtr_error_set(error, ENOTSUP,
17809 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17810 					NULL, "unsupported action RSS");
17811 			if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
17812 				return -rte_mtr_error_set(error, ENOTSUP,
17813 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17814 					NULL, "no fate action is found");
17815 		} else {
17816 			if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) &&
17817 			    (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) {
17818 				if ((domain_color[i] &
17819 				     MLX5_MTR_DOMAIN_EGRESS_BIT))
17820 					domain_color[i] =
17821 						MLX5_MTR_DOMAIN_EGRESS_BIT;
17822 				else
17823 					return -rte_mtr_error_set(error,
17824 						ENOTSUP,
17825 						RTE_MTR_ERROR_TYPE_METER_POLICY,
17826 						NULL,
17827 						"no fate action is found");
17828 			}
17829 		}
17830 	}
17831 	/* If both colors have RSS, the attributes should be the same. */
17832 	if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN],
17833 					   rss_color[RTE_COLOR_YELLOW]))
17834 		return -rte_mtr_error_set(error, EINVAL,
17835 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17836 					  NULL, "policy RSS attr conflict");
17837 	if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW])
17838 		*is_rss = true;
17839 	/* "domain_color[C]" is non-zero for each color, default is ALL. */
17840 	if (!def_green && !def_yellow &&
17841 	    domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] &&
17842 	    !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) &&
17843 	    !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP))
17844 		return -rte_mtr_error_set(error, EINVAL,
17845 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17846 					  NULL, "policy domains conflict");
17847 	/*
17848 	 * At least one color policy is listed in the actions, the domains
17849 	 * to be supported should be the intersection.
17850 	 */
17851 	*domain_bitmap = domain_color[RTE_COLOR_GREEN] &
17852 			 domain_color[RTE_COLOR_YELLOW];
17853 	return 0;
17854 }
17855 
17856 static int
17857 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
17858 {
17859 	struct mlx5_priv *priv = dev->data->dev_private;
17860 	int ret = 0;
17861 
17862 	if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) {
17863 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain,
17864 						flags);
17865 		if (ret != 0)
17866 			return ret;
17867 	}
17868 	if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) {
17869 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags);
17870 		if (ret != 0)
17871 			return ret;
17872 	}
17873 	if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) {
17874 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags);
17875 		if (ret != 0)
17876 			return ret;
17877 	}
17878 	return 0;
17879 }
17880 
17881 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
17882 	.validate = flow_dv_validate,
17883 	.prepare = flow_dv_prepare,
17884 	.translate = flow_dv_translate,
17885 	.apply = flow_dv_apply,
17886 	.remove = flow_dv_remove,
17887 	.destroy = flow_dv_destroy,
17888 	.query = flow_dv_query,
17889 	.create_mtr_tbls = flow_dv_create_mtr_tbls,
17890 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
17891 	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
17892 	.create_meter = flow_dv_mtr_alloc,
17893 	.free_meter = flow_dv_aso_mtr_release_to_pool,
17894 	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
17895 	.create_mtr_acts = flow_dv_create_mtr_policy_acts,
17896 	.destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
17897 	.create_policy_rules = flow_dv_create_policy_rules,
17898 	.destroy_policy_rules = flow_dv_destroy_policy_rules,
17899 	.create_def_policy = flow_dv_create_def_policy,
17900 	.destroy_def_policy = flow_dv_destroy_def_policy,
17901 	.meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare,
17902 	.meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create,
17903 	.destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq,
17904 	.counter_alloc = flow_dv_counter_allocate,
17905 	.counter_free = flow_dv_counter_free,
17906 	.counter_query = flow_dv_counter_query,
17907 	.get_aged_flows = flow_dv_get_aged_flows,
17908 	.action_validate = flow_dv_action_validate,
17909 	.action_create = flow_dv_action_create,
17910 	.action_destroy = flow_dv_action_destroy,
17911 	.action_update = flow_dv_action_update,
17912 	.action_query = flow_dv_action_query,
17913 	.sync_domain = flow_dv_sync_domain,
17914 };
17915 
17916 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
17917 
17918