xref: /dpdk/drivers/net/mlx5/mlx5_flow_dv.c (revision d38febb08d57fec29fed27a2d12a507fc6fcdfa1)
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 *spec;
2416 	const struct rte_flow_item_gtp_psc *mask;
2417 	const struct rte_flow_item_gtp_psc nic_mask = {
2418 		.pdu_type = 0xFF,
2419 		.qfi = 0xFF,
2420 	};
2421 
2422 	if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP))
2423 		return rte_flow_error_set
2424 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2425 			 "GTP PSC item must be preceded with GTP item");
2426 	gtp_spec = gtp_item->spec;
2427 	gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask;
2428 	/* GTP spec and E flag is requested to match zero. */
2429 	if (gtp_spec &&
2430 		(gtp_mask->v_pt_rsv_flags &
2431 		~gtp_spec->v_pt_rsv_flags & MLX5_GTP_EXT_HEADER_FLAG))
2432 		return rte_flow_error_set
2433 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2434 			 "GTP E flag must be 1 to match GTP PSC");
2435 	/* Check the flow is not created in group zero. */
2436 	if (!attr->transfer && !attr->group)
2437 		return rte_flow_error_set
2438 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2439 			 "GTP PSC is not supported for group 0");
2440 	/* GTP spec is here and E flag is requested to match zero. */
2441 	if (!item->spec)
2442 		return 0;
2443 	spec = item->spec;
2444 	mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask;
2445 	if (spec->pdu_type > MLX5_GTP_EXT_MAX_PDU_TYPE)
2446 		return rte_flow_error_set
2447 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2448 			 "PDU type should be smaller than 16");
2449 	return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2450 					 (const uint8_t *)&nic_mask,
2451 					 sizeof(struct rte_flow_item_gtp_psc),
2452 					 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2453 }
2454 
2455 /**
2456  * Validate IPV4 item.
2457  * Use existing validation function mlx5_flow_validate_item_ipv4(), and
2458  * add specific validation of fragment_offset field,
2459  *
2460  * @param[in] item
2461  *   Item specification.
2462  * @param[in] item_flags
2463  *   Bit-fields that holds the items detected until now.
2464  * @param[out] error
2465  *   Pointer to error structure.
2466  *
2467  * @return
2468  *   0 on success, a negative errno value otherwise and rte_errno is set.
2469  */
2470 static int
2471 flow_dv_validate_item_ipv4(struct rte_eth_dev *dev,
2472 			   const struct rte_flow_item *item,
2473 			   uint64_t item_flags, uint64_t last_item,
2474 			   uint16_t ether_type, struct rte_flow_error *error)
2475 {
2476 	int ret;
2477 	struct mlx5_priv *priv = dev->data->dev_private;
2478 	const struct rte_flow_item_ipv4 *spec = item->spec;
2479 	const struct rte_flow_item_ipv4 *last = item->last;
2480 	const struct rte_flow_item_ipv4 *mask = item->mask;
2481 	rte_be16_t fragment_offset_spec = 0;
2482 	rte_be16_t fragment_offset_last = 0;
2483 	struct rte_flow_item_ipv4 nic_ipv4_mask = {
2484 		.hdr = {
2485 			.src_addr = RTE_BE32(0xffffffff),
2486 			.dst_addr = RTE_BE32(0xffffffff),
2487 			.type_of_service = 0xff,
2488 			.fragment_offset = RTE_BE16(0xffff),
2489 			.next_proto_id = 0xff,
2490 			.time_to_live = 0xff,
2491 		},
2492 	};
2493 
2494 	if (mask && (mask->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK)) {
2495 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2496 		bool ihl_cap = !tunnel ? priv->config.hca_attr.outer_ipv4_ihl :
2497 			       priv->config.hca_attr.inner_ipv4_ihl;
2498 		if (!ihl_cap)
2499 			return rte_flow_error_set(error, ENOTSUP,
2500 						  RTE_FLOW_ERROR_TYPE_ITEM,
2501 						  item,
2502 						  "IPV4 ihl offload not supported");
2503 		nic_ipv4_mask.hdr.version_ihl = mask->hdr.version_ihl;
2504 	}
2505 	ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item,
2506 					   ether_type, &nic_ipv4_mask,
2507 					   MLX5_ITEM_RANGE_ACCEPTED, error);
2508 	if (ret < 0)
2509 		return ret;
2510 	if (spec && mask)
2511 		fragment_offset_spec = spec->hdr.fragment_offset &
2512 				       mask->hdr.fragment_offset;
2513 	if (!fragment_offset_spec)
2514 		return 0;
2515 	/*
2516 	 * spec and mask are valid, enforce using full mask to make sure the
2517 	 * complete value is used correctly.
2518 	 */
2519 	if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2520 			!= RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2521 		return rte_flow_error_set(error, EINVAL,
2522 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2523 					  item, "must use full mask for"
2524 					  " fragment_offset");
2525 	/*
2526 	 * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0,
2527 	 * indicating this is 1st fragment of fragmented packet.
2528 	 * This is not yet supported in MLX5, return appropriate error message.
2529 	 */
2530 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG))
2531 		return rte_flow_error_set(error, ENOTSUP,
2532 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2533 					  "match on first fragment not "
2534 					  "supported");
2535 	if (fragment_offset_spec && !last)
2536 		return rte_flow_error_set(error, ENOTSUP,
2537 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2538 					  "specified value not supported");
2539 	/* spec and last are valid, validate the specified range. */
2540 	fragment_offset_last = last->hdr.fragment_offset &
2541 			       mask->hdr.fragment_offset;
2542 	/*
2543 	 * Match on fragment_offset spec 0x2001 and last 0x3fff
2544 	 * means MF is 1 and frag-offset is > 0.
2545 	 * This packet is fragment 2nd and onward, excluding last.
2546 	 * This is not yet supported in MLX5, return appropriate
2547 	 * error message.
2548 	 */
2549 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) &&
2550 	    fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2551 		return rte_flow_error_set(error, ENOTSUP,
2552 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2553 					  last, "match on following "
2554 					  "fragments not supported");
2555 	/*
2556 	 * Match on fragment_offset spec 0x0001 and last 0x1fff
2557 	 * means MF is 0 and frag-offset is > 0.
2558 	 * This packet is last fragment of fragmented packet.
2559 	 * This is not yet supported in MLX5, return appropriate
2560 	 * error message.
2561 	 */
2562 	if (fragment_offset_spec == RTE_BE16(1) &&
2563 	    fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK))
2564 		return rte_flow_error_set(error, ENOTSUP,
2565 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2566 					  last, "match on last "
2567 					  "fragment not supported");
2568 	/*
2569 	 * Match on fragment_offset spec 0x0001 and last 0x3fff
2570 	 * means MF and/or frag-offset is not 0.
2571 	 * This is a fragmented packet.
2572 	 * Other range values are invalid and rejected.
2573 	 */
2574 	if (!(fragment_offset_spec == RTE_BE16(1) &&
2575 	      fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)))
2576 		return rte_flow_error_set(error, ENOTSUP,
2577 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2578 					  "specified range not supported");
2579 	return 0;
2580 }
2581 
2582 /**
2583  * Validate IPV6 fragment extension item.
2584  *
2585  * @param[in] item
2586  *   Item specification.
2587  * @param[in] item_flags
2588  *   Bit-fields that holds the items detected until now.
2589  * @param[out] error
2590  *   Pointer to error structure.
2591  *
2592  * @return
2593  *   0 on success, a negative errno value otherwise and rte_errno is set.
2594  */
2595 static int
2596 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item,
2597 				    uint64_t item_flags,
2598 				    struct rte_flow_error *error)
2599 {
2600 	const struct rte_flow_item_ipv6_frag_ext *spec = item->spec;
2601 	const struct rte_flow_item_ipv6_frag_ext *last = item->last;
2602 	const struct rte_flow_item_ipv6_frag_ext *mask = item->mask;
2603 	rte_be16_t frag_data_spec = 0;
2604 	rte_be16_t frag_data_last = 0;
2605 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2606 	const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 :
2607 				      MLX5_FLOW_LAYER_OUTER_L4;
2608 	int ret = 0;
2609 	struct rte_flow_item_ipv6_frag_ext nic_mask = {
2610 		.hdr = {
2611 			.next_header = 0xff,
2612 			.frag_data = RTE_BE16(0xffff),
2613 		},
2614 	};
2615 
2616 	if (item_flags & l4m)
2617 		return rte_flow_error_set(error, EINVAL,
2618 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2619 					  "ipv6 fragment extension item cannot "
2620 					  "follow L4 item.");
2621 	if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
2622 	    (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6)))
2623 		return rte_flow_error_set(error, EINVAL,
2624 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2625 					  "ipv6 fragment extension item must "
2626 					  "follow ipv6 item");
2627 	if (spec && mask)
2628 		frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data;
2629 	if (!frag_data_spec)
2630 		return 0;
2631 	/*
2632 	 * spec and mask are valid, enforce using full mask to make sure the
2633 	 * complete value is used correctly.
2634 	 */
2635 	if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) !=
2636 				RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2637 		return rte_flow_error_set(error, EINVAL,
2638 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2639 					  item, "must use full mask for"
2640 					  " frag_data");
2641 	/*
2642 	 * Match on frag_data 0x00001 means M is 1 and frag-offset is 0.
2643 	 * This is 1st fragment of fragmented packet.
2644 	 */
2645 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK))
2646 		return rte_flow_error_set(error, ENOTSUP,
2647 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2648 					  "match on first fragment not "
2649 					  "supported");
2650 	if (frag_data_spec && !last)
2651 		return rte_flow_error_set(error, EINVAL,
2652 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2653 					  "specified value not supported");
2654 	ret = mlx5_flow_item_acceptable
2655 				(item, (const uint8_t *)mask,
2656 				 (const uint8_t *)&nic_mask,
2657 				 sizeof(struct rte_flow_item_ipv6_frag_ext),
2658 				 MLX5_ITEM_RANGE_ACCEPTED, error);
2659 	if (ret)
2660 		return ret;
2661 	/* spec and last are valid, validate the specified range. */
2662 	frag_data_last = last->hdr.frag_data & mask->hdr.frag_data;
2663 	/*
2664 	 * Match on frag_data spec 0x0009 and last 0xfff9
2665 	 * means M is 1 and frag-offset is > 0.
2666 	 * This packet is fragment 2nd and onward, excluding last.
2667 	 * This is not yet supported in MLX5, return appropriate
2668 	 * error message.
2669 	 */
2670 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN |
2671 				       RTE_IPV6_EHDR_MF_MASK) &&
2672 	    frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2673 		return rte_flow_error_set(error, ENOTSUP,
2674 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2675 					  last, "match on following "
2676 					  "fragments not supported");
2677 	/*
2678 	 * Match on frag_data spec 0x0008 and last 0xfff8
2679 	 * means M is 0 and frag-offset is > 0.
2680 	 * This packet is last fragment of fragmented packet.
2681 	 * This is not yet supported in MLX5, return appropriate
2682 	 * error message.
2683 	 */
2684 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) &&
2685 	    frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK))
2686 		return rte_flow_error_set(error, ENOTSUP,
2687 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2688 					  last, "match on last "
2689 					  "fragment not supported");
2690 	/* Other range values are invalid and rejected. */
2691 	return rte_flow_error_set(error, EINVAL,
2692 				  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2693 				  "specified range not supported");
2694 }
2695 
2696 /*
2697  * Validate ASO CT item.
2698  *
2699  * @param[in] dev
2700  *   Pointer to the rte_eth_dev structure.
2701  * @param[in] item
2702  *   Item specification.
2703  * @param[in] item_flags
2704  *   Pointer to bit-fields that holds the items detected until now.
2705  * @param[out] error
2706  *   Pointer to error structure.
2707  *
2708  * @return
2709  *   0 on success, a negative errno value otherwise and rte_errno is set.
2710  */
2711 static int
2712 flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev,
2713 			     const struct rte_flow_item *item,
2714 			     uint64_t *item_flags,
2715 			     struct rte_flow_error *error)
2716 {
2717 	const struct rte_flow_item_conntrack *spec = item->spec;
2718 	const struct rte_flow_item_conntrack *mask = item->mask;
2719 	RTE_SET_USED(dev);
2720 	uint32_t flags;
2721 
2722 	if (*item_flags & MLX5_FLOW_LAYER_ASO_CT)
2723 		return rte_flow_error_set(error, EINVAL,
2724 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2725 					  "Only one CT is supported");
2726 	if (!mask)
2727 		mask = &rte_flow_item_conntrack_mask;
2728 	flags = spec->flags & mask->flags;
2729 	if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) &&
2730 	    ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) ||
2731 	     (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) ||
2732 	     (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)))
2733 		return rte_flow_error_set(error, EINVAL,
2734 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2735 					  "Conflict status bits");
2736 	/* State change also needs to be considered. */
2737 	*item_flags |= MLX5_FLOW_LAYER_ASO_CT;
2738 	return 0;
2739 }
2740 
2741 /**
2742  * Validate the pop VLAN action.
2743  *
2744  * @param[in] dev
2745  *   Pointer to the rte_eth_dev structure.
2746  * @param[in] action_flags
2747  *   Holds the actions detected until now.
2748  * @param[in] action
2749  *   Pointer to the pop vlan action.
2750  * @param[in] item_flags
2751  *   The items found in this flow rule.
2752  * @param[in] attr
2753  *   Pointer to flow attributes.
2754  * @param[out] error
2755  *   Pointer to error structure.
2756  *
2757  * @return
2758  *   0 on success, a negative errno value otherwise and rte_errno is set.
2759  */
2760 static int
2761 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev,
2762 				 uint64_t action_flags,
2763 				 const struct rte_flow_action *action,
2764 				 uint64_t item_flags,
2765 				 const struct rte_flow_attr *attr,
2766 				 struct rte_flow_error *error)
2767 {
2768 	const struct mlx5_priv *priv = dev->data->dev_private;
2769 	struct mlx5_dev_ctx_shared *sh = priv->sh;
2770 	bool direction_error = false;
2771 
2772 	if (!priv->sh->pop_vlan_action)
2773 		return rte_flow_error_set(error, ENOTSUP,
2774 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2775 					  NULL,
2776 					  "pop vlan action is not supported");
2777 	/* Pop VLAN is not supported in egress except for CX6 FDB mode. */
2778 	if (attr->transfer) {
2779 		bool fdb_tx = priv->representor_id != UINT16_MAX;
2780 		bool is_cx5 = sh->steering_format_version ==
2781 		    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
2782 
2783 		if (fdb_tx && is_cx5)
2784 			direction_error = true;
2785 	} else if (attr->egress) {
2786 		direction_error = true;
2787 	}
2788 	if (direction_error)
2789 		return rte_flow_error_set(error, ENOTSUP,
2790 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
2791 					  NULL,
2792 					  "pop vlan action not supported for egress");
2793 	if (action_flags & MLX5_FLOW_VLAN_ACTIONS)
2794 		return rte_flow_error_set(error, ENOTSUP,
2795 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2796 					  "no support for multiple VLAN "
2797 					  "actions");
2798 	/* Pop VLAN with preceding Decap requires inner header with VLAN. */
2799 	if ((action_flags & MLX5_FLOW_ACTION_DECAP) &&
2800 	    !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN))
2801 		return rte_flow_error_set(error, ENOTSUP,
2802 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2803 					  NULL,
2804 					  "cannot pop vlan after decap without "
2805 					  "match on inner vlan in the flow");
2806 	/* Pop VLAN without preceding Decap requires outer header with VLAN. */
2807 	if (!(action_flags & MLX5_FLOW_ACTION_DECAP) &&
2808 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
2809 		return rte_flow_error_set(error, ENOTSUP,
2810 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2811 					  NULL,
2812 					  "cannot pop vlan without a "
2813 					  "match on (outer) vlan in the flow");
2814 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2815 		return rte_flow_error_set(error, EINVAL,
2816 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2817 					  "wrong action order, port_id should "
2818 					  "be after pop VLAN action");
2819 	if (!attr->transfer && priv->representor)
2820 		return rte_flow_error_set(error, ENOTSUP,
2821 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2822 					  "pop vlan action for VF representor "
2823 					  "not supported on NIC table");
2824 	return 0;
2825 }
2826 
2827 /**
2828  * Get VLAN default info from vlan match info.
2829  *
2830  * @param[in] items
2831  *   the list of item specifications.
2832  * @param[out] vlan
2833  *   pointer VLAN info to fill to.
2834  *
2835  * @return
2836  *   0 on success, a negative errno value otherwise and rte_errno is set.
2837  */
2838 static void
2839 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items,
2840 				  struct rte_vlan_hdr *vlan)
2841 {
2842 	const struct rte_flow_item_vlan nic_mask = {
2843 		.tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK |
2844 				MLX5DV_FLOW_VLAN_VID_MASK),
2845 		.inner_type = RTE_BE16(0xffff),
2846 	};
2847 
2848 	if (items == NULL)
2849 		return;
2850 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
2851 		int type = items->type;
2852 
2853 		if (type == RTE_FLOW_ITEM_TYPE_VLAN ||
2854 		    type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN)
2855 			break;
2856 	}
2857 	if (items->type != RTE_FLOW_ITEM_TYPE_END) {
2858 		const struct rte_flow_item_vlan *vlan_m = items->mask;
2859 		const struct rte_flow_item_vlan *vlan_v = items->spec;
2860 
2861 		/* If VLAN item in pattern doesn't contain data, return here. */
2862 		if (!vlan_v)
2863 			return;
2864 		if (!vlan_m)
2865 			vlan_m = &nic_mask;
2866 		/* Only full match values are accepted */
2867 		if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) ==
2868 		     MLX5DV_FLOW_VLAN_PCP_MASK_BE) {
2869 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
2870 			vlan->vlan_tci |=
2871 				rte_be_to_cpu_16(vlan_v->tci &
2872 						 MLX5DV_FLOW_VLAN_PCP_MASK_BE);
2873 		}
2874 		if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) ==
2875 		     MLX5DV_FLOW_VLAN_VID_MASK_BE) {
2876 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
2877 			vlan->vlan_tci |=
2878 				rte_be_to_cpu_16(vlan_v->tci &
2879 						 MLX5DV_FLOW_VLAN_VID_MASK_BE);
2880 		}
2881 		if (vlan_m->inner_type == nic_mask.inner_type)
2882 			vlan->eth_proto = rte_be_to_cpu_16(vlan_v->inner_type &
2883 							   vlan_m->inner_type);
2884 	}
2885 }
2886 
2887 /**
2888  * Validate the push VLAN action.
2889  *
2890  * @param[in] dev
2891  *   Pointer to the rte_eth_dev structure.
2892  * @param[in] action_flags
2893  *   Holds the actions detected until now.
2894  * @param[in] item_flags
2895  *   The items found in this flow rule.
2896  * @param[in] action
2897  *   Pointer to the action structure.
2898  * @param[in] attr
2899  *   Pointer to flow attributes
2900  * @param[out] error
2901  *   Pointer to error structure.
2902  *
2903  * @return
2904  *   0 on success, a negative errno value otherwise and rte_errno is set.
2905  */
2906 static int
2907 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev,
2908 				  uint64_t action_flags,
2909 				  const struct rte_flow_item_vlan *vlan_m,
2910 				  const struct rte_flow_action *action,
2911 				  const struct rte_flow_attr *attr,
2912 				  struct rte_flow_error *error)
2913 {
2914 	const struct rte_flow_action_of_push_vlan *push_vlan = action->conf;
2915 	const struct mlx5_priv *priv = dev->data->dev_private;
2916 	struct mlx5_dev_ctx_shared *sh = priv->sh;
2917 	bool direction_error = false;
2918 
2919 	if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) &&
2920 	    push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ))
2921 		return rte_flow_error_set(error, EINVAL,
2922 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2923 					  "invalid vlan ethertype");
2924 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2925 		return rte_flow_error_set(error, EINVAL,
2926 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2927 					  "wrong action order, port_id should "
2928 					  "be after push VLAN");
2929 	/* Push VLAN is not supported in ingress except for CX6 FDB mode. */
2930 	if (attr->transfer) {
2931 		bool fdb_tx = priv->representor_id != UINT16_MAX;
2932 		bool is_cx5 = sh->steering_format_version ==
2933 		    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
2934 
2935 		if (!fdb_tx && is_cx5)
2936 			direction_error = true;
2937 	} else if (attr->ingress) {
2938 		direction_error = true;
2939 	}
2940 	if (direction_error)
2941 		return rte_flow_error_set(error, ENOTSUP,
2942 					  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
2943 					  NULL,
2944 					  "push vlan action not supported for ingress");
2945 	if (!attr->transfer && priv->representor)
2946 		return rte_flow_error_set(error, ENOTSUP,
2947 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2948 					  "push vlan action for VF representor "
2949 					  "not supported on NIC table");
2950 	if (vlan_m &&
2951 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) &&
2952 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) !=
2953 		MLX5DV_FLOW_VLAN_PCP_MASK_BE &&
2954 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) &&
2955 	    !(mlx5_flow_find_action
2956 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP)))
2957 		return rte_flow_error_set(error, EINVAL,
2958 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2959 					  "not full match mask on VLAN PCP and "
2960 					  "there is no of_set_vlan_pcp action, "
2961 					  "push VLAN action cannot figure out "
2962 					  "PCP value");
2963 	if (vlan_m &&
2964 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) &&
2965 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) !=
2966 		MLX5DV_FLOW_VLAN_VID_MASK_BE &&
2967 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) &&
2968 	    !(mlx5_flow_find_action
2969 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)))
2970 		return rte_flow_error_set(error, EINVAL,
2971 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2972 					  "not full match mask on VLAN VID and "
2973 					  "there is no of_set_vlan_vid action, "
2974 					  "push VLAN action cannot figure out "
2975 					  "VID value");
2976 	(void)attr;
2977 	return 0;
2978 }
2979 
2980 /**
2981  * Validate the set VLAN PCP.
2982  *
2983  * @param[in] action_flags
2984  *   Holds the actions detected until now.
2985  * @param[in] actions
2986  *   Pointer to the list of actions remaining in the flow rule.
2987  * @param[out] error
2988  *   Pointer to error structure.
2989  *
2990  * @return
2991  *   0 on success, a negative errno value otherwise and rte_errno is set.
2992  */
2993 static int
2994 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags,
2995 				     const struct rte_flow_action actions[],
2996 				     struct rte_flow_error *error)
2997 {
2998 	const struct rte_flow_action *action = actions;
2999 	const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf;
3000 
3001 	if (conf->vlan_pcp > 7)
3002 		return rte_flow_error_set(error, EINVAL,
3003 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3004 					  "VLAN PCP value is too big");
3005 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN))
3006 		return rte_flow_error_set(error, ENOTSUP,
3007 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3008 					  "set VLAN PCP action must follow "
3009 					  "the push VLAN action");
3010 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
3011 		return rte_flow_error_set(error, ENOTSUP,
3012 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3013 					  "Multiple VLAN PCP modification are "
3014 					  "not supported");
3015 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
3016 		return rte_flow_error_set(error, EINVAL,
3017 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3018 					  "wrong action order, port_id should "
3019 					  "be after set VLAN PCP");
3020 	return 0;
3021 }
3022 
3023 /**
3024  * Validate the set VLAN VID.
3025  *
3026  * @param[in] item_flags
3027  *   Holds the items detected in this rule.
3028  * @param[in] action_flags
3029  *   Holds the actions detected until now.
3030  * @param[in] actions
3031  *   Pointer to the list of actions remaining in the flow rule.
3032  * @param[out] error
3033  *   Pointer to error structure.
3034  *
3035  * @return
3036  *   0 on success, a negative errno value otherwise and rte_errno is set.
3037  */
3038 static int
3039 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
3040 				     uint64_t action_flags,
3041 				     const struct rte_flow_action actions[],
3042 				     struct rte_flow_error *error)
3043 {
3044 	const struct rte_flow_action *action = actions;
3045 	const struct rte_flow_action_of_set_vlan_vid *conf = action->conf;
3046 
3047 	if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE)
3048 		return rte_flow_error_set(error, EINVAL,
3049 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3050 					  "VLAN VID value is too big");
3051 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) &&
3052 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
3053 		return rte_flow_error_set(error, ENOTSUP,
3054 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3055 					  "set VLAN VID action must follow push"
3056 					  " VLAN action or match on VLAN item");
3057 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID)
3058 		return rte_flow_error_set(error, ENOTSUP,
3059 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3060 					  "Multiple VLAN VID modifications are "
3061 					  "not supported");
3062 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
3063 		return rte_flow_error_set(error, EINVAL,
3064 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3065 					  "wrong action order, port_id should "
3066 					  "be after set VLAN VID");
3067 	return 0;
3068 }
3069 
3070 /*
3071  * Validate the FLAG action.
3072  *
3073  * @param[in] dev
3074  *   Pointer to the rte_eth_dev structure.
3075  * @param[in] action_flags
3076  *   Holds the actions detected until now.
3077  * @param[in] attr
3078  *   Pointer to flow attributes
3079  * @param[out] error
3080  *   Pointer to error structure.
3081  *
3082  * @return
3083  *   0 on success, a negative errno value otherwise and rte_errno is set.
3084  */
3085 static int
3086 flow_dv_validate_action_flag(struct rte_eth_dev *dev,
3087 			     uint64_t action_flags,
3088 			     const struct rte_flow_attr *attr,
3089 			     struct rte_flow_error *error)
3090 {
3091 	struct mlx5_priv *priv = dev->data->dev_private;
3092 	struct mlx5_dev_config *config = &priv->config;
3093 	int ret;
3094 
3095 	/* Fall back if no extended metadata register support. */
3096 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3097 		return mlx5_flow_validate_action_flag(action_flags, attr,
3098 						      error);
3099 	/* Extensive metadata mode requires registers. */
3100 	if (!mlx5_flow_ext_mreg_supported(dev))
3101 		return rte_flow_error_set(error, ENOTSUP,
3102 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3103 					  "no metadata registers "
3104 					  "to support flag action");
3105 	if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT))
3106 		return rte_flow_error_set(error, ENOTSUP,
3107 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3108 					  "extended metadata register"
3109 					  " isn't available");
3110 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3111 	if (ret < 0)
3112 		return ret;
3113 	MLX5_ASSERT(ret > 0);
3114 	if (action_flags & MLX5_FLOW_ACTION_MARK)
3115 		return rte_flow_error_set(error, EINVAL,
3116 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3117 					  "can't mark and flag in same flow");
3118 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
3119 		return rte_flow_error_set(error, EINVAL,
3120 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3121 					  "can't have 2 flag"
3122 					  " actions in same flow");
3123 	return 0;
3124 }
3125 
3126 /**
3127  * Validate MARK action.
3128  *
3129  * @param[in] dev
3130  *   Pointer to the rte_eth_dev structure.
3131  * @param[in] action
3132  *   Pointer to action.
3133  * @param[in] action_flags
3134  *   Holds the actions detected until now.
3135  * @param[in] attr
3136  *   Pointer to flow attributes
3137  * @param[out] error
3138  *   Pointer to error structure.
3139  *
3140  * @return
3141  *   0 on success, a negative errno value otherwise and rte_errno is set.
3142  */
3143 static int
3144 flow_dv_validate_action_mark(struct rte_eth_dev *dev,
3145 			     const struct rte_flow_action *action,
3146 			     uint64_t action_flags,
3147 			     const struct rte_flow_attr *attr,
3148 			     struct rte_flow_error *error)
3149 {
3150 	struct mlx5_priv *priv = dev->data->dev_private;
3151 	struct mlx5_dev_config *config = &priv->config;
3152 	const struct rte_flow_action_mark *mark = action->conf;
3153 	int ret;
3154 
3155 	if (is_tunnel_offload_active(dev))
3156 		return rte_flow_error_set(error, ENOTSUP,
3157 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3158 					  "no mark action "
3159 					  "if tunnel offload active");
3160 	/* Fall back if no extended metadata register support. */
3161 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3162 		return mlx5_flow_validate_action_mark(action, action_flags,
3163 						      attr, error);
3164 	/* Extensive metadata mode requires registers. */
3165 	if (!mlx5_flow_ext_mreg_supported(dev))
3166 		return rte_flow_error_set(error, ENOTSUP,
3167 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3168 					  "no metadata registers "
3169 					  "to support mark action");
3170 	if (!priv->sh->dv_mark_mask)
3171 		return rte_flow_error_set(error, ENOTSUP,
3172 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3173 					  "extended metadata register"
3174 					  " isn't available");
3175 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3176 	if (ret < 0)
3177 		return ret;
3178 	MLX5_ASSERT(ret > 0);
3179 	if (!mark)
3180 		return rte_flow_error_set(error, EINVAL,
3181 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3182 					  "configuration cannot be null");
3183 	if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask))
3184 		return rte_flow_error_set(error, EINVAL,
3185 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
3186 					  &mark->id,
3187 					  "mark id exceeds the limit");
3188 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
3189 		return rte_flow_error_set(error, EINVAL,
3190 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3191 					  "can't flag and mark in same flow");
3192 	if (action_flags & MLX5_FLOW_ACTION_MARK)
3193 		return rte_flow_error_set(error, EINVAL,
3194 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3195 					  "can't have 2 mark actions in same"
3196 					  " flow");
3197 	return 0;
3198 }
3199 
3200 /**
3201  * Validate SET_META action.
3202  *
3203  * @param[in] dev
3204  *   Pointer to the rte_eth_dev structure.
3205  * @param[in] action
3206  *   Pointer to the action structure.
3207  * @param[in] action_flags
3208  *   Holds the actions detected until now.
3209  * @param[in] attr
3210  *   Pointer to flow attributes
3211  * @param[out] error
3212  *   Pointer to error structure.
3213  *
3214  * @return
3215  *   0 on success, a negative errno value otherwise and rte_errno is set.
3216  */
3217 static int
3218 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev,
3219 				 const struct rte_flow_action *action,
3220 				 uint64_t action_flags __rte_unused,
3221 				 const struct rte_flow_attr *attr,
3222 				 struct rte_flow_error *error)
3223 {
3224 	const struct rte_flow_action_set_meta *conf;
3225 	uint32_t nic_mask = UINT32_MAX;
3226 	int reg;
3227 
3228 	if (!mlx5_flow_ext_mreg_supported(dev))
3229 		return rte_flow_error_set(error, ENOTSUP,
3230 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3231 					  "extended metadata register"
3232 					  " isn't supported");
3233 	reg = flow_dv_get_metadata_reg(dev, attr, error);
3234 	if (reg < 0)
3235 		return reg;
3236 	if (reg == REG_NON)
3237 		return rte_flow_error_set(error, ENOTSUP,
3238 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3239 					  "unavalable extended metadata register");
3240 	if (reg != REG_A && reg != REG_B) {
3241 		struct mlx5_priv *priv = dev->data->dev_private;
3242 
3243 		nic_mask = priv->sh->dv_meta_mask;
3244 	}
3245 	if (!(action->conf))
3246 		return rte_flow_error_set(error, EINVAL,
3247 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3248 					  "configuration cannot be null");
3249 	conf = (const struct rte_flow_action_set_meta *)action->conf;
3250 	if (!conf->mask)
3251 		return rte_flow_error_set(error, EINVAL,
3252 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3253 					  "zero mask doesn't have any effect");
3254 	if (conf->mask & ~nic_mask)
3255 		return rte_flow_error_set(error, EINVAL,
3256 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3257 					  "meta data must be within reg C0");
3258 	return 0;
3259 }
3260 
3261 /**
3262  * Validate SET_TAG action.
3263  *
3264  * @param[in] dev
3265  *   Pointer to the rte_eth_dev structure.
3266  * @param[in] action
3267  *   Pointer to the action structure.
3268  * @param[in] action_flags
3269  *   Holds the actions detected until now.
3270  * @param[in] attr
3271  *   Pointer to flow attributes
3272  * @param[out] error
3273  *   Pointer to error structure.
3274  *
3275  * @return
3276  *   0 on success, a negative errno value otherwise and rte_errno is set.
3277  */
3278 static int
3279 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev,
3280 				const struct rte_flow_action *action,
3281 				uint64_t action_flags,
3282 				const struct rte_flow_attr *attr,
3283 				struct rte_flow_error *error)
3284 {
3285 	const struct rte_flow_action_set_tag *conf;
3286 	const uint64_t terminal_action_flags =
3287 		MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE |
3288 		MLX5_FLOW_ACTION_RSS;
3289 	int ret;
3290 
3291 	if (!mlx5_flow_ext_mreg_supported(dev))
3292 		return rte_flow_error_set(error, ENOTSUP,
3293 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3294 					  "extensive metadata register"
3295 					  " isn't supported");
3296 	if (!(action->conf))
3297 		return rte_flow_error_set(error, EINVAL,
3298 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3299 					  "configuration cannot be null");
3300 	conf = (const struct rte_flow_action_set_tag *)action->conf;
3301 	if (!conf->mask)
3302 		return rte_flow_error_set(error, EINVAL,
3303 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3304 					  "zero mask doesn't have any effect");
3305 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
3306 	if (ret < 0)
3307 		return ret;
3308 	if (!attr->transfer && attr->ingress &&
3309 	    (action_flags & terminal_action_flags))
3310 		return rte_flow_error_set(error, EINVAL,
3311 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3312 					  "set_tag has no effect"
3313 					  " with terminal actions");
3314 	return 0;
3315 }
3316 
3317 /**
3318  * Check if action counter is shared by either old or new mechanism.
3319  *
3320  * @param[in] action
3321  *   Pointer to the action structure.
3322  *
3323  * @return
3324  *   True when counter is shared, false otherwise.
3325  */
3326 static inline bool
3327 is_shared_action_count(const struct rte_flow_action *action)
3328 {
3329 	const struct rte_flow_action_count *count =
3330 			(const struct rte_flow_action_count *)action->conf;
3331 
3332 	if ((int)action->type == MLX5_RTE_FLOW_ACTION_TYPE_COUNT)
3333 		return true;
3334 	return !!(count && count->shared);
3335 }
3336 
3337 /**
3338  * Validate count action.
3339  *
3340  * @param[in] dev
3341  *   Pointer to rte_eth_dev structure.
3342  * @param[in] shared
3343  *   Indicator if action is shared.
3344  * @param[in] action_flags
3345  *   Holds the actions detected until now.
3346  * @param[out] error
3347  *   Pointer to error structure.
3348  *
3349  * @return
3350  *   0 on success, a negative errno value otherwise and rte_errno is set.
3351  */
3352 static int
3353 flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared,
3354 			      uint64_t action_flags,
3355 			      struct rte_flow_error *error)
3356 {
3357 	struct mlx5_priv *priv = dev->data->dev_private;
3358 
3359 	if (!priv->config.devx)
3360 		goto notsup_err;
3361 	if (action_flags & MLX5_FLOW_ACTION_COUNT)
3362 		return rte_flow_error_set(error, EINVAL,
3363 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3364 					  "duplicate count actions set");
3365 	if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) &&
3366 	    !priv->sh->flow_hit_aso_en)
3367 		return rte_flow_error_set(error, EINVAL,
3368 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3369 					  "old age and shared count combination is not supported");
3370 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
3371 	return 0;
3372 #endif
3373 notsup_err:
3374 	return rte_flow_error_set
3375 		      (error, ENOTSUP,
3376 		       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3377 		       NULL,
3378 		       "count action not supported");
3379 }
3380 
3381 /**
3382  * Validate the L2 encap action.
3383  *
3384  * @param[in] dev
3385  *   Pointer to the rte_eth_dev structure.
3386  * @param[in] action_flags
3387  *   Holds the actions detected until now.
3388  * @param[in] action
3389  *   Pointer to the action structure.
3390  * @param[in] attr
3391  *   Pointer to flow attributes.
3392  * @param[out] error
3393  *   Pointer to error structure.
3394  *
3395  * @return
3396  *   0 on success, a negative errno value otherwise and rte_errno is set.
3397  */
3398 static int
3399 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev,
3400 				 uint64_t action_flags,
3401 				 const struct rte_flow_action *action,
3402 				 const struct rte_flow_attr *attr,
3403 				 struct rte_flow_error *error)
3404 {
3405 	const struct mlx5_priv *priv = dev->data->dev_private;
3406 
3407 	if (!(action->conf))
3408 		return rte_flow_error_set(error, EINVAL,
3409 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3410 					  "configuration cannot be null");
3411 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3412 		return rte_flow_error_set(error, EINVAL,
3413 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3414 					  "can only have a single encap action "
3415 					  "in a flow");
3416 	if (!attr->transfer && priv->representor)
3417 		return rte_flow_error_set(error, ENOTSUP,
3418 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3419 					  "encap action for VF representor "
3420 					  "not supported on NIC table");
3421 	return 0;
3422 }
3423 
3424 /**
3425  * Validate a decap action.
3426  *
3427  * @param[in] dev
3428  *   Pointer to the rte_eth_dev structure.
3429  * @param[in] action_flags
3430  *   Holds the actions detected until now.
3431  * @param[in] action
3432  *   Pointer to the action structure.
3433  * @param[in] item_flags
3434  *   Holds the items detected.
3435  * @param[in] attr
3436  *   Pointer to flow attributes
3437  * @param[out] error
3438  *   Pointer to error structure.
3439  *
3440  * @return
3441  *   0 on success, a negative errno value otherwise and rte_errno is set.
3442  */
3443 static int
3444 flow_dv_validate_action_decap(struct rte_eth_dev *dev,
3445 			      uint64_t action_flags,
3446 			      const struct rte_flow_action *action,
3447 			      const uint64_t item_flags,
3448 			      const struct rte_flow_attr *attr,
3449 			      struct rte_flow_error *error)
3450 {
3451 	const struct mlx5_priv *priv = dev->data->dev_private;
3452 
3453 	if (priv->config.hca_attr.scatter_fcs_w_decap_disable &&
3454 	    !priv->config.decap_en)
3455 		return rte_flow_error_set(error, ENOTSUP,
3456 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3457 					  "decap is not enabled");
3458 	if (action_flags & MLX5_FLOW_XCAP_ACTIONS)
3459 		return rte_flow_error_set(error, ENOTSUP,
3460 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3461 					  action_flags &
3462 					  MLX5_FLOW_ACTION_DECAP ? "can only "
3463 					  "have a single decap action" : "decap "
3464 					  "after encap is not supported");
3465 	if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
3466 		return rte_flow_error_set(error, EINVAL,
3467 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3468 					  "can't have decap action after"
3469 					  " modify action");
3470 	if (attr->egress)
3471 		return rte_flow_error_set(error, ENOTSUP,
3472 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
3473 					  NULL,
3474 					  "decap action not supported for "
3475 					  "egress");
3476 	if (!attr->transfer && priv->representor)
3477 		return rte_flow_error_set(error, ENOTSUP,
3478 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3479 					  "decap action for VF representor "
3480 					  "not supported on NIC table");
3481 	if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP &&
3482 	    !(item_flags & MLX5_FLOW_LAYER_VXLAN))
3483 		return rte_flow_error_set(error, ENOTSUP,
3484 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3485 				"VXLAN item should be present for VXLAN decap");
3486 	return 0;
3487 }
3488 
3489 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,};
3490 
3491 /**
3492  * Validate the raw encap and decap actions.
3493  *
3494  * @param[in] dev
3495  *   Pointer to the rte_eth_dev structure.
3496  * @param[in] decap
3497  *   Pointer to the decap action.
3498  * @param[in] encap
3499  *   Pointer to the encap action.
3500  * @param[in] attr
3501  *   Pointer to flow attributes
3502  * @param[in/out] action_flags
3503  *   Holds the actions detected until now.
3504  * @param[out] actions_n
3505  *   pointer to the number of actions counter.
3506  * @param[in] action
3507  *   Pointer to the action structure.
3508  * @param[in] item_flags
3509  *   Holds the items detected.
3510  * @param[out] error
3511  *   Pointer to error structure.
3512  *
3513  * @return
3514  *   0 on success, a negative errno value otherwise and rte_errno is set.
3515  */
3516 static int
3517 flow_dv_validate_action_raw_encap_decap
3518 	(struct rte_eth_dev *dev,
3519 	 const struct rte_flow_action_raw_decap *decap,
3520 	 const struct rte_flow_action_raw_encap *encap,
3521 	 const struct rte_flow_attr *attr, uint64_t *action_flags,
3522 	 int *actions_n, const struct rte_flow_action *action,
3523 	 uint64_t item_flags, struct rte_flow_error *error)
3524 {
3525 	const struct mlx5_priv *priv = dev->data->dev_private;
3526 	int ret;
3527 
3528 	if (encap && (!encap->size || !encap->data))
3529 		return rte_flow_error_set(error, EINVAL,
3530 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3531 					  "raw encap data cannot be empty");
3532 	if (decap && encap) {
3533 		if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE &&
3534 		    encap->size > MLX5_ENCAPSULATION_DECISION_SIZE)
3535 			/* L3 encap. */
3536 			decap = NULL;
3537 		else if (encap->size <=
3538 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3539 			   decap->size >
3540 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3541 			/* L3 decap. */
3542 			encap = NULL;
3543 		else if (encap->size >
3544 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3545 			   decap->size >
3546 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3547 			/* 2 L2 actions: encap and decap. */
3548 			;
3549 		else
3550 			return rte_flow_error_set(error,
3551 				ENOTSUP,
3552 				RTE_FLOW_ERROR_TYPE_ACTION,
3553 				NULL, "unsupported too small "
3554 				"raw decap and too small raw "
3555 				"encap combination");
3556 	}
3557 	if (decap) {
3558 		ret = flow_dv_validate_action_decap(dev, *action_flags, action,
3559 						    item_flags, attr, error);
3560 		if (ret < 0)
3561 			return ret;
3562 		*action_flags |= MLX5_FLOW_ACTION_DECAP;
3563 		++(*actions_n);
3564 	}
3565 	if (encap) {
3566 		if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE)
3567 			return rte_flow_error_set(error, ENOTSUP,
3568 						  RTE_FLOW_ERROR_TYPE_ACTION,
3569 						  NULL,
3570 						  "small raw encap size");
3571 		if (*action_flags & MLX5_FLOW_ACTION_ENCAP)
3572 			return rte_flow_error_set(error, EINVAL,
3573 						  RTE_FLOW_ERROR_TYPE_ACTION,
3574 						  NULL,
3575 						  "more than one encap action");
3576 		if (!attr->transfer && priv->representor)
3577 			return rte_flow_error_set
3578 					(error, ENOTSUP,
3579 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3580 					 "encap action for VF representor "
3581 					 "not supported on NIC table");
3582 		*action_flags |= MLX5_FLOW_ACTION_ENCAP;
3583 		++(*actions_n);
3584 	}
3585 	return 0;
3586 }
3587 
3588 /*
3589  * Validate the ASO CT action.
3590  *
3591  * @param[in] dev
3592  *   Pointer to the rte_eth_dev structure.
3593  * @param[in] action_flags
3594  *   Holds the actions detected until now.
3595  * @param[in] item_flags
3596  *   The items found in this flow rule.
3597  * @param[in] attr
3598  *   Pointer to flow attributes.
3599  * @param[out] error
3600  *   Pointer to error structure.
3601  *
3602  * @return
3603  *   0 on success, a negative errno value otherwise and rte_errno is set.
3604  */
3605 static int
3606 flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev,
3607 			       uint64_t action_flags,
3608 			       uint64_t item_flags,
3609 			       const struct rte_flow_attr *attr,
3610 			       struct rte_flow_error *error)
3611 {
3612 	RTE_SET_USED(dev);
3613 
3614 	if (attr->group == 0 && !attr->transfer)
3615 		return rte_flow_error_set(error, ENOTSUP,
3616 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3617 					  NULL,
3618 					  "Only support non-root table");
3619 	if (action_flags & MLX5_FLOW_FATE_ACTIONS)
3620 		return rte_flow_error_set(error, ENOTSUP,
3621 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3622 					  "CT cannot follow a fate action");
3623 	if ((action_flags & MLX5_FLOW_ACTION_METER) ||
3624 	    (action_flags & MLX5_FLOW_ACTION_AGE))
3625 		return rte_flow_error_set(error, EINVAL,
3626 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3627 					  "Only one ASO action is supported");
3628 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3629 		return rte_flow_error_set(error, EINVAL,
3630 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3631 					  "Encap cannot exist before CT");
3632 	if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP))
3633 		return rte_flow_error_set(error, EINVAL,
3634 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3635 					  "Not a outer TCP packet");
3636 	return 0;
3637 }
3638 
3639 int
3640 flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused,
3641 			     struct mlx5_list_entry *entry, void *cb_ctx)
3642 {
3643 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3644 	struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3645 	struct mlx5_flow_dv_encap_decap_resource *resource;
3646 
3647 	resource = container_of(entry, struct mlx5_flow_dv_encap_decap_resource,
3648 				entry);
3649 	if (resource->reformat_type == ctx_resource->reformat_type &&
3650 	    resource->ft_type == ctx_resource->ft_type &&
3651 	    resource->flags == ctx_resource->flags &&
3652 	    resource->size == ctx_resource->size &&
3653 	    !memcmp((const void *)resource->buf,
3654 		    (const void *)ctx_resource->buf,
3655 		    resource->size))
3656 		return 0;
3657 	return -1;
3658 }
3659 
3660 struct mlx5_list_entry *
3661 flow_dv_encap_decap_create_cb(void *tool_ctx, void *cb_ctx)
3662 {
3663 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3664 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3665 	struct mlx5dv_dr_domain *domain;
3666 	struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3667 	struct mlx5_flow_dv_encap_decap_resource *resource;
3668 	uint32_t idx;
3669 	int ret;
3670 
3671 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3672 		domain = sh->fdb_domain;
3673 	else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3674 		domain = sh->rx_domain;
3675 	else
3676 		domain = sh->tx_domain;
3677 	/* Register new encap/decap resource. */
3678 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &idx);
3679 	if (!resource) {
3680 		rte_flow_error_set(ctx->error, ENOMEM,
3681 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3682 				   "cannot allocate resource memory");
3683 		return NULL;
3684 	}
3685 	*resource = *ctx_resource;
3686 	resource->idx = idx;
3687 	ret = mlx5_flow_os_create_flow_action_packet_reformat(sh->ctx, domain,
3688 							      resource,
3689 							     &resource->action);
3690 	if (ret) {
3691 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx);
3692 		rte_flow_error_set(ctx->error, ENOMEM,
3693 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3694 				   NULL, "cannot create action");
3695 		return NULL;
3696 	}
3697 
3698 	return &resource->entry;
3699 }
3700 
3701 struct mlx5_list_entry *
3702 flow_dv_encap_decap_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
3703 			     void *cb_ctx)
3704 {
3705 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3706 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3707 	struct mlx5_flow_dv_encap_decap_resource *cache_resource;
3708 	uint32_t idx;
3709 
3710 	cache_resource = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
3711 					   &idx);
3712 	if (!cache_resource) {
3713 		rte_flow_error_set(ctx->error, ENOMEM,
3714 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3715 				   "cannot allocate resource memory");
3716 		return NULL;
3717 	}
3718 	memcpy(cache_resource, oentry, sizeof(*cache_resource));
3719 	cache_resource->idx = idx;
3720 	return &cache_resource->entry;
3721 }
3722 
3723 void
3724 flow_dv_encap_decap_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3725 {
3726 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3727 	struct mlx5_flow_dv_encap_decap_resource *res =
3728 				       container_of(entry, typeof(*res), entry);
3729 
3730 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
3731 }
3732 
3733 /**
3734  * Find existing encap/decap resource or create and register a new one.
3735  *
3736  * @param[in, out] dev
3737  *   Pointer to rte_eth_dev structure.
3738  * @param[in, out] resource
3739  *   Pointer to encap/decap resource.
3740  * @parm[in, out] dev_flow
3741  *   Pointer to the dev_flow.
3742  * @param[out] error
3743  *   pointer to error structure.
3744  *
3745  * @return
3746  *   0 on success otherwise -errno and errno is set.
3747  */
3748 static int
3749 flow_dv_encap_decap_resource_register
3750 			(struct rte_eth_dev *dev,
3751 			 struct mlx5_flow_dv_encap_decap_resource *resource,
3752 			 struct mlx5_flow *dev_flow,
3753 			 struct rte_flow_error *error)
3754 {
3755 	struct mlx5_priv *priv = dev->data->dev_private;
3756 	struct mlx5_dev_ctx_shared *sh = priv->sh;
3757 	struct mlx5_list_entry *entry;
3758 	union {
3759 		struct {
3760 			uint32_t ft_type:8;
3761 			uint32_t refmt_type:8;
3762 			/*
3763 			 * Header reformat actions can be shared between
3764 			 * non-root tables. One bit to indicate non-root
3765 			 * table or not.
3766 			 */
3767 			uint32_t is_root:1;
3768 			uint32_t reserve:15;
3769 		};
3770 		uint32_t v32;
3771 	} encap_decap_key = {
3772 		{
3773 			.ft_type = resource->ft_type,
3774 			.refmt_type = resource->reformat_type,
3775 			.is_root = !!dev_flow->dv.group,
3776 			.reserve = 0,
3777 		}
3778 	};
3779 	struct mlx5_flow_cb_ctx ctx = {
3780 		.error = error,
3781 		.data = resource,
3782 	};
3783 	struct mlx5_hlist *encaps_decaps;
3784 	uint64_t key64;
3785 
3786 	encaps_decaps = flow_dv_hlist_prepare(sh, &sh->encaps_decaps,
3787 				"encaps_decaps",
3788 				MLX5_FLOW_ENCAP_DECAP_HTABLE_SZ,
3789 				true, true, sh,
3790 				flow_dv_encap_decap_create_cb,
3791 				flow_dv_encap_decap_match_cb,
3792 				flow_dv_encap_decap_remove_cb,
3793 				flow_dv_encap_decap_clone_cb,
3794 				flow_dv_encap_decap_clone_free_cb);
3795 	if (unlikely(!encaps_decaps))
3796 		return -rte_errno;
3797 	resource->flags = dev_flow->dv.group ? 0 : 1;
3798 	key64 =  __rte_raw_cksum(&encap_decap_key.v32,
3799 				 sizeof(encap_decap_key.v32), 0);
3800 	if (resource->reformat_type !=
3801 	    MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 &&
3802 	    resource->size)
3803 		key64 = __rte_raw_cksum(resource->buf, resource->size, key64);
3804 	entry = mlx5_hlist_register(encaps_decaps, key64, &ctx);
3805 	if (!entry)
3806 		return -rte_errno;
3807 	resource = container_of(entry, typeof(*resource), entry);
3808 	dev_flow->dv.encap_decap = resource;
3809 	dev_flow->handle->dvh.rix_encap_decap = resource->idx;
3810 	return 0;
3811 }
3812 
3813 /**
3814  * Find existing table jump resource or create and register a new one.
3815  *
3816  * @param[in, out] dev
3817  *   Pointer to rte_eth_dev structure.
3818  * @param[in, out] tbl
3819  *   Pointer to flow table resource.
3820  * @parm[in, out] dev_flow
3821  *   Pointer to the dev_flow.
3822  * @param[out] error
3823  *   pointer to error structure.
3824  *
3825  * @return
3826  *   0 on success otherwise -errno and errno is set.
3827  */
3828 static int
3829 flow_dv_jump_tbl_resource_register
3830 			(struct rte_eth_dev *dev __rte_unused,
3831 			 struct mlx5_flow_tbl_resource *tbl,
3832 			 struct mlx5_flow *dev_flow,
3833 			 struct rte_flow_error *error __rte_unused)
3834 {
3835 	struct mlx5_flow_tbl_data_entry *tbl_data =
3836 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
3837 
3838 	MLX5_ASSERT(tbl);
3839 	MLX5_ASSERT(tbl_data->jump.action);
3840 	dev_flow->handle->rix_jump = tbl_data->idx;
3841 	dev_flow->dv.jump = &tbl_data->jump;
3842 	return 0;
3843 }
3844 
3845 int
3846 flow_dv_port_id_match_cb(void *tool_ctx __rte_unused,
3847 			 struct mlx5_list_entry *entry, void *cb_ctx)
3848 {
3849 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3850 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3851 	struct mlx5_flow_dv_port_id_action_resource *res =
3852 				       container_of(entry, typeof(*res), entry);
3853 
3854 	return ref->port_id != res->port_id;
3855 }
3856 
3857 struct mlx5_list_entry *
3858 flow_dv_port_id_create_cb(void *tool_ctx, void *cb_ctx)
3859 {
3860 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3861 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3862 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3863 	struct mlx5_flow_dv_port_id_action_resource *resource;
3864 	uint32_t idx;
3865 	int ret;
3866 
3867 	/* Register new port id action resource. */
3868 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3869 	if (!resource) {
3870 		rte_flow_error_set(ctx->error, ENOMEM,
3871 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3872 				   "cannot allocate port_id action memory");
3873 		return NULL;
3874 	}
3875 	*resource = *ref;
3876 	ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain,
3877 							ref->port_id,
3878 							&resource->action);
3879 	if (ret) {
3880 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx);
3881 		rte_flow_error_set(ctx->error, ENOMEM,
3882 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3883 				   "cannot create action");
3884 		return NULL;
3885 	}
3886 	resource->idx = idx;
3887 	return &resource->entry;
3888 }
3889 
3890 struct mlx5_list_entry *
3891 flow_dv_port_id_clone_cb(void *tool_ctx,
3892 			 struct mlx5_list_entry *entry __rte_unused,
3893 			 void *cb_ctx)
3894 {
3895 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3896 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3897 	struct mlx5_flow_dv_port_id_action_resource *resource;
3898 	uint32_t idx;
3899 
3900 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3901 	if (!resource) {
3902 		rte_flow_error_set(ctx->error, ENOMEM,
3903 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3904 				   "cannot allocate port_id action memory");
3905 		return NULL;
3906 	}
3907 	memcpy(resource, entry, sizeof(*resource));
3908 	resource->idx = idx;
3909 	return &resource->entry;
3910 }
3911 
3912 void
3913 flow_dv_port_id_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3914 {
3915 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3916 	struct mlx5_flow_dv_port_id_action_resource *resource =
3917 				  container_of(entry, typeof(*resource), entry);
3918 
3919 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
3920 }
3921 
3922 /**
3923  * Find existing table port ID resource or create and register a new one.
3924  *
3925  * @param[in, out] dev
3926  *   Pointer to rte_eth_dev structure.
3927  * @param[in, out] ref
3928  *   Pointer to port ID action resource reference.
3929  * @parm[in, out] dev_flow
3930  *   Pointer to the dev_flow.
3931  * @param[out] error
3932  *   pointer to error structure.
3933  *
3934  * @return
3935  *   0 on success otherwise -errno and errno is set.
3936  */
3937 static int
3938 flow_dv_port_id_action_resource_register
3939 			(struct rte_eth_dev *dev,
3940 			 struct mlx5_flow_dv_port_id_action_resource *ref,
3941 			 struct mlx5_flow *dev_flow,
3942 			 struct rte_flow_error *error)
3943 {
3944 	struct mlx5_priv *priv = dev->data->dev_private;
3945 	struct mlx5_list_entry *entry;
3946 	struct mlx5_flow_dv_port_id_action_resource *resource;
3947 	struct mlx5_flow_cb_ctx ctx = {
3948 		.error = error,
3949 		.data = ref,
3950 	};
3951 
3952 	entry = mlx5_list_register(priv->sh->port_id_action_list, &ctx);
3953 	if (!entry)
3954 		return -rte_errno;
3955 	resource = container_of(entry, typeof(*resource), entry);
3956 	dev_flow->dv.port_id_action = resource;
3957 	dev_flow->handle->rix_port_id_action = resource->idx;
3958 	return 0;
3959 }
3960 
3961 int
3962 flow_dv_push_vlan_match_cb(void *tool_ctx __rte_unused,
3963 			   struct mlx5_list_entry *entry, void *cb_ctx)
3964 {
3965 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3966 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3967 	struct mlx5_flow_dv_push_vlan_action_resource *res =
3968 				       container_of(entry, typeof(*res), entry);
3969 
3970 	return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type;
3971 }
3972 
3973 struct mlx5_list_entry *
3974 flow_dv_push_vlan_create_cb(void *tool_ctx, void *cb_ctx)
3975 {
3976 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3977 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3978 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3979 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
3980 	struct mlx5dv_dr_domain *domain;
3981 	uint32_t idx;
3982 	int ret;
3983 
3984 	/* Register new port id action resource. */
3985 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
3986 	if (!resource) {
3987 		rte_flow_error_set(ctx->error, ENOMEM,
3988 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3989 				   "cannot allocate push_vlan action memory");
3990 		return NULL;
3991 	}
3992 	*resource = *ref;
3993 	if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3994 		domain = sh->fdb_domain;
3995 	else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3996 		domain = sh->rx_domain;
3997 	else
3998 		domain = sh->tx_domain;
3999 	ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag,
4000 							&resource->action);
4001 	if (ret) {
4002 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
4003 		rte_flow_error_set(ctx->error, ENOMEM,
4004 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4005 				   "cannot create push vlan action");
4006 		return NULL;
4007 	}
4008 	resource->idx = idx;
4009 	return &resource->entry;
4010 }
4011 
4012 struct mlx5_list_entry *
4013 flow_dv_push_vlan_clone_cb(void *tool_ctx,
4014 			   struct mlx5_list_entry *entry __rte_unused,
4015 			   void *cb_ctx)
4016 {
4017 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
4018 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
4019 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
4020 	uint32_t idx;
4021 
4022 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
4023 	if (!resource) {
4024 		rte_flow_error_set(ctx->error, ENOMEM,
4025 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4026 				   "cannot allocate push_vlan action memory");
4027 		return NULL;
4028 	}
4029 	memcpy(resource, entry, sizeof(*resource));
4030 	resource->idx = idx;
4031 	return &resource->entry;
4032 }
4033 
4034 void
4035 flow_dv_push_vlan_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
4036 {
4037 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
4038 	struct mlx5_flow_dv_push_vlan_action_resource *resource =
4039 				  container_of(entry, typeof(*resource), entry);
4040 
4041 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
4042 }
4043 
4044 /**
4045  * Find existing push vlan resource or create and register a new one.
4046  *
4047  * @param [in, out] dev
4048  *   Pointer to rte_eth_dev structure.
4049  * @param[in, out] ref
4050  *   Pointer to port ID action resource reference.
4051  * @parm[in, out] dev_flow
4052  *   Pointer to the dev_flow.
4053  * @param[out] error
4054  *   pointer to error structure.
4055  *
4056  * @return
4057  *   0 on success otherwise -errno and errno is set.
4058  */
4059 static int
4060 flow_dv_push_vlan_action_resource_register
4061 		       (struct rte_eth_dev *dev,
4062 			struct mlx5_flow_dv_push_vlan_action_resource *ref,
4063 			struct mlx5_flow *dev_flow,
4064 			struct rte_flow_error *error)
4065 {
4066 	struct mlx5_priv *priv = dev->data->dev_private;
4067 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
4068 	struct mlx5_list_entry *entry;
4069 	struct mlx5_flow_cb_ctx ctx = {
4070 		.error = error,
4071 		.data = ref,
4072 	};
4073 
4074 	entry = mlx5_list_register(priv->sh->push_vlan_action_list, &ctx);
4075 	if (!entry)
4076 		return -rte_errno;
4077 	resource = container_of(entry, typeof(*resource), entry);
4078 
4079 	dev_flow->handle->dvh.rix_push_vlan = resource->idx;
4080 	dev_flow->dv.push_vlan_res = resource;
4081 	return 0;
4082 }
4083 
4084 /**
4085  * Get the size of specific rte_flow_item_type hdr size
4086  *
4087  * @param[in] item_type
4088  *   Tested rte_flow_item_type.
4089  *
4090  * @return
4091  *   sizeof struct item_type, 0 if void or irrelevant.
4092  */
4093 static size_t
4094 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type)
4095 {
4096 	size_t retval;
4097 
4098 	switch (item_type) {
4099 	case RTE_FLOW_ITEM_TYPE_ETH:
4100 		retval = sizeof(struct rte_ether_hdr);
4101 		break;
4102 	case RTE_FLOW_ITEM_TYPE_VLAN:
4103 		retval = sizeof(struct rte_vlan_hdr);
4104 		break;
4105 	case RTE_FLOW_ITEM_TYPE_IPV4:
4106 		retval = sizeof(struct rte_ipv4_hdr);
4107 		break;
4108 	case RTE_FLOW_ITEM_TYPE_IPV6:
4109 		retval = sizeof(struct rte_ipv6_hdr);
4110 		break;
4111 	case RTE_FLOW_ITEM_TYPE_UDP:
4112 		retval = sizeof(struct rte_udp_hdr);
4113 		break;
4114 	case RTE_FLOW_ITEM_TYPE_TCP:
4115 		retval = sizeof(struct rte_tcp_hdr);
4116 		break;
4117 	case RTE_FLOW_ITEM_TYPE_VXLAN:
4118 	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4119 		retval = sizeof(struct rte_vxlan_hdr);
4120 		break;
4121 	case RTE_FLOW_ITEM_TYPE_GRE:
4122 	case RTE_FLOW_ITEM_TYPE_NVGRE:
4123 		retval = sizeof(struct rte_gre_hdr);
4124 		break;
4125 	case RTE_FLOW_ITEM_TYPE_MPLS:
4126 		retval = sizeof(struct rte_mpls_hdr);
4127 		break;
4128 	case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */
4129 	default:
4130 		retval = 0;
4131 		break;
4132 	}
4133 	return retval;
4134 }
4135 
4136 #define MLX5_ENCAP_IPV4_VERSION		0x40
4137 #define MLX5_ENCAP_IPV4_IHL_MIN		0x05
4138 #define MLX5_ENCAP_IPV4_TTL_DEF		0x40
4139 #define MLX5_ENCAP_IPV6_VTC_FLOW	0x60000000
4140 #define MLX5_ENCAP_IPV6_HOP_LIMIT	0xff
4141 #define MLX5_ENCAP_VXLAN_FLAGS		0x08000000
4142 #define MLX5_ENCAP_VXLAN_GPE_FLAGS	0x04
4143 
4144 /**
4145  * Convert the encap action data from list of rte_flow_item to raw buffer
4146  *
4147  * @param[in] items
4148  *   Pointer to rte_flow_item objects list.
4149  * @param[out] buf
4150  *   Pointer to the output buffer.
4151  * @param[out] size
4152  *   Pointer to the output buffer size.
4153  * @param[out] error
4154  *   Pointer to the error structure.
4155  *
4156  * @return
4157  *   0 on success, a negative errno value otherwise and rte_errno is set.
4158  */
4159 static int
4160 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf,
4161 			   size_t *size, struct rte_flow_error *error)
4162 {
4163 	struct rte_ether_hdr *eth = NULL;
4164 	struct rte_vlan_hdr *vlan = NULL;
4165 	struct rte_ipv4_hdr *ipv4 = NULL;
4166 	struct rte_ipv6_hdr *ipv6 = NULL;
4167 	struct rte_udp_hdr *udp = NULL;
4168 	struct rte_vxlan_hdr *vxlan = NULL;
4169 	struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL;
4170 	struct rte_gre_hdr *gre = NULL;
4171 	size_t len;
4172 	size_t temp_size = 0;
4173 
4174 	if (!items)
4175 		return rte_flow_error_set(error, EINVAL,
4176 					  RTE_FLOW_ERROR_TYPE_ACTION,
4177 					  NULL, "invalid empty data");
4178 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
4179 		len = flow_dv_get_item_hdr_len(items->type);
4180 		if (len + temp_size > MLX5_ENCAP_MAX_LEN)
4181 			return rte_flow_error_set(error, EINVAL,
4182 						  RTE_FLOW_ERROR_TYPE_ACTION,
4183 						  (void *)items->type,
4184 						  "items total size is too big"
4185 						  " for encap action");
4186 		rte_memcpy((void *)&buf[temp_size], items->spec, len);
4187 		switch (items->type) {
4188 		case RTE_FLOW_ITEM_TYPE_ETH:
4189 			eth = (struct rte_ether_hdr *)&buf[temp_size];
4190 			break;
4191 		case RTE_FLOW_ITEM_TYPE_VLAN:
4192 			vlan = (struct rte_vlan_hdr *)&buf[temp_size];
4193 			if (!eth)
4194 				return rte_flow_error_set(error, EINVAL,
4195 						RTE_FLOW_ERROR_TYPE_ACTION,
4196 						(void *)items->type,
4197 						"eth header not found");
4198 			if (!eth->ether_type)
4199 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN);
4200 			break;
4201 		case RTE_FLOW_ITEM_TYPE_IPV4:
4202 			ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size];
4203 			if (!vlan && !eth)
4204 				return rte_flow_error_set(error, EINVAL,
4205 						RTE_FLOW_ERROR_TYPE_ACTION,
4206 						(void *)items->type,
4207 						"neither eth nor vlan"
4208 						" header found");
4209 			if (vlan && !vlan->eth_proto)
4210 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4211 			else if (eth && !eth->ether_type)
4212 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4213 			if (!ipv4->version_ihl)
4214 				ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION |
4215 						    MLX5_ENCAP_IPV4_IHL_MIN;
4216 			if (!ipv4->time_to_live)
4217 				ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF;
4218 			break;
4219 		case RTE_FLOW_ITEM_TYPE_IPV6:
4220 			ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size];
4221 			if (!vlan && !eth)
4222 				return rte_flow_error_set(error, EINVAL,
4223 						RTE_FLOW_ERROR_TYPE_ACTION,
4224 						(void *)items->type,
4225 						"neither eth nor vlan"
4226 						" header found");
4227 			if (vlan && !vlan->eth_proto)
4228 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4229 			else if (eth && !eth->ether_type)
4230 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4231 			if (!ipv6->vtc_flow)
4232 				ipv6->vtc_flow =
4233 					RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW);
4234 			if (!ipv6->hop_limits)
4235 				ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT;
4236 			break;
4237 		case RTE_FLOW_ITEM_TYPE_UDP:
4238 			udp = (struct rte_udp_hdr *)&buf[temp_size];
4239 			if (!ipv4 && !ipv6)
4240 				return rte_flow_error_set(error, EINVAL,
4241 						RTE_FLOW_ERROR_TYPE_ACTION,
4242 						(void *)items->type,
4243 						"ip header not found");
4244 			if (ipv4 && !ipv4->next_proto_id)
4245 				ipv4->next_proto_id = IPPROTO_UDP;
4246 			else if (ipv6 && !ipv6->proto)
4247 				ipv6->proto = IPPROTO_UDP;
4248 			break;
4249 		case RTE_FLOW_ITEM_TYPE_VXLAN:
4250 			vxlan = (struct rte_vxlan_hdr *)&buf[temp_size];
4251 			if (!udp)
4252 				return rte_flow_error_set(error, EINVAL,
4253 						RTE_FLOW_ERROR_TYPE_ACTION,
4254 						(void *)items->type,
4255 						"udp header not found");
4256 			if (!udp->dst_port)
4257 				udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN);
4258 			if (!vxlan->vx_flags)
4259 				vxlan->vx_flags =
4260 					RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS);
4261 			break;
4262 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4263 			vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size];
4264 			if (!udp)
4265 				return rte_flow_error_set(error, EINVAL,
4266 						RTE_FLOW_ERROR_TYPE_ACTION,
4267 						(void *)items->type,
4268 						"udp header not found");
4269 			if (!vxlan_gpe->proto)
4270 				return rte_flow_error_set(error, EINVAL,
4271 						RTE_FLOW_ERROR_TYPE_ACTION,
4272 						(void *)items->type,
4273 						"next protocol not found");
4274 			if (!udp->dst_port)
4275 				udp->dst_port =
4276 					RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE);
4277 			if (!vxlan_gpe->vx_flags)
4278 				vxlan_gpe->vx_flags =
4279 						MLX5_ENCAP_VXLAN_GPE_FLAGS;
4280 			break;
4281 		case RTE_FLOW_ITEM_TYPE_GRE:
4282 		case RTE_FLOW_ITEM_TYPE_NVGRE:
4283 			gre = (struct rte_gre_hdr *)&buf[temp_size];
4284 			if (!gre->proto)
4285 				return rte_flow_error_set(error, EINVAL,
4286 						RTE_FLOW_ERROR_TYPE_ACTION,
4287 						(void *)items->type,
4288 						"next protocol not found");
4289 			if (!ipv4 && !ipv6)
4290 				return rte_flow_error_set(error, EINVAL,
4291 						RTE_FLOW_ERROR_TYPE_ACTION,
4292 						(void *)items->type,
4293 						"ip header not found");
4294 			if (ipv4 && !ipv4->next_proto_id)
4295 				ipv4->next_proto_id = IPPROTO_GRE;
4296 			else if (ipv6 && !ipv6->proto)
4297 				ipv6->proto = IPPROTO_GRE;
4298 			break;
4299 		case RTE_FLOW_ITEM_TYPE_VOID:
4300 			break;
4301 		default:
4302 			return rte_flow_error_set(error, EINVAL,
4303 						  RTE_FLOW_ERROR_TYPE_ACTION,
4304 						  (void *)items->type,
4305 						  "unsupported item type");
4306 			break;
4307 		}
4308 		temp_size += len;
4309 	}
4310 	*size = temp_size;
4311 	return 0;
4312 }
4313 
4314 static int
4315 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error)
4316 {
4317 	struct rte_ether_hdr *eth = NULL;
4318 	struct rte_vlan_hdr *vlan = NULL;
4319 	struct rte_ipv6_hdr *ipv6 = NULL;
4320 	struct rte_udp_hdr *udp = NULL;
4321 	char *next_hdr;
4322 	uint16_t proto;
4323 
4324 	eth = (struct rte_ether_hdr *)data;
4325 	next_hdr = (char *)(eth + 1);
4326 	proto = RTE_BE16(eth->ether_type);
4327 
4328 	/* VLAN skipping */
4329 	while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) {
4330 		vlan = (struct rte_vlan_hdr *)next_hdr;
4331 		proto = RTE_BE16(vlan->eth_proto);
4332 		next_hdr += sizeof(struct rte_vlan_hdr);
4333 	}
4334 
4335 	/* HW calculates IPv4 csum. no need to proceed */
4336 	if (proto == RTE_ETHER_TYPE_IPV4)
4337 		return 0;
4338 
4339 	/* non IPv4/IPv6 header. not supported */
4340 	if (proto != RTE_ETHER_TYPE_IPV6) {
4341 		return rte_flow_error_set(error, ENOTSUP,
4342 					  RTE_FLOW_ERROR_TYPE_ACTION,
4343 					  NULL, "Cannot offload non IPv4/IPv6");
4344 	}
4345 
4346 	ipv6 = (struct rte_ipv6_hdr *)next_hdr;
4347 
4348 	/* ignore non UDP */
4349 	if (ipv6->proto != IPPROTO_UDP)
4350 		return 0;
4351 
4352 	udp = (struct rte_udp_hdr *)(ipv6 + 1);
4353 	udp->dgram_cksum = 0;
4354 
4355 	return 0;
4356 }
4357 
4358 /**
4359  * Convert L2 encap action to DV specification.
4360  *
4361  * @param[in] dev
4362  *   Pointer to rte_eth_dev structure.
4363  * @param[in] action
4364  *   Pointer to action structure.
4365  * @param[in, out] dev_flow
4366  *   Pointer to the mlx5_flow.
4367  * @param[in] transfer
4368  *   Mark if the flow is E-Switch flow.
4369  * @param[out] error
4370  *   Pointer to the error structure.
4371  *
4372  * @return
4373  *   0 on success, a negative errno value otherwise and rte_errno is set.
4374  */
4375 static int
4376 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev,
4377 			       const struct rte_flow_action *action,
4378 			       struct mlx5_flow *dev_flow,
4379 			       uint8_t transfer,
4380 			       struct rte_flow_error *error)
4381 {
4382 	const struct rte_flow_item *encap_data;
4383 	const struct rte_flow_action_raw_encap *raw_encap_data;
4384 	struct mlx5_flow_dv_encap_decap_resource res = {
4385 		.reformat_type =
4386 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL,
4387 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4388 				      MLX5DV_FLOW_TABLE_TYPE_NIC_TX,
4389 	};
4390 
4391 	if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
4392 		raw_encap_data =
4393 			(const struct rte_flow_action_raw_encap *)action->conf;
4394 		res.size = raw_encap_data->size;
4395 		memcpy(res.buf, raw_encap_data->data, res.size);
4396 	} else {
4397 		if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
4398 			encap_data =
4399 				((const struct rte_flow_action_vxlan_encap *)
4400 						action->conf)->definition;
4401 		else
4402 			encap_data =
4403 				((const struct rte_flow_action_nvgre_encap *)
4404 						action->conf)->definition;
4405 		if (flow_dv_convert_encap_data(encap_data, res.buf,
4406 					       &res.size, error))
4407 			return -rte_errno;
4408 	}
4409 	if (flow_dv_zero_encap_udp_csum(res.buf, error))
4410 		return -rte_errno;
4411 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4412 		return rte_flow_error_set(error, EINVAL,
4413 					  RTE_FLOW_ERROR_TYPE_ACTION,
4414 					  NULL, "can't create L2 encap action");
4415 	return 0;
4416 }
4417 
4418 /**
4419  * Convert L2 decap action to DV specification.
4420  *
4421  * @param[in] dev
4422  *   Pointer to rte_eth_dev structure.
4423  * @param[in, out] dev_flow
4424  *   Pointer to the mlx5_flow.
4425  * @param[in] transfer
4426  *   Mark if the flow is E-Switch flow.
4427  * @param[out] error
4428  *   Pointer to the error structure.
4429  *
4430  * @return
4431  *   0 on success, a negative errno value otherwise and rte_errno is set.
4432  */
4433 static int
4434 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev,
4435 			       struct mlx5_flow *dev_flow,
4436 			       uint8_t transfer,
4437 			       struct rte_flow_error *error)
4438 {
4439 	struct mlx5_flow_dv_encap_decap_resource res = {
4440 		.size = 0,
4441 		.reformat_type =
4442 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2,
4443 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4444 				      MLX5DV_FLOW_TABLE_TYPE_NIC_RX,
4445 	};
4446 
4447 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4448 		return rte_flow_error_set(error, EINVAL,
4449 					  RTE_FLOW_ERROR_TYPE_ACTION,
4450 					  NULL, "can't create L2 decap action");
4451 	return 0;
4452 }
4453 
4454 /**
4455  * Convert raw decap/encap (L3 tunnel) action to DV specification.
4456  *
4457  * @param[in] dev
4458  *   Pointer to rte_eth_dev structure.
4459  * @param[in] action
4460  *   Pointer to action structure.
4461  * @param[in, out] dev_flow
4462  *   Pointer to the mlx5_flow.
4463  * @param[in] attr
4464  *   Pointer to the flow attributes.
4465  * @param[out] error
4466  *   Pointer to the error structure.
4467  *
4468  * @return
4469  *   0 on success, a negative errno value otherwise and rte_errno is set.
4470  */
4471 static int
4472 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
4473 				const struct rte_flow_action *action,
4474 				struct mlx5_flow *dev_flow,
4475 				const struct rte_flow_attr *attr,
4476 				struct rte_flow_error *error)
4477 {
4478 	const struct rte_flow_action_raw_encap *encap_data;
4479 	struct mlx5_flow_dv_encap_decap_resource res;
4480 
4481 	memset(&res, 0, sizeof(res));
4482 	encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
4483 	res.size = encap_data->size;
4484 	memcpy(res.buf, encap_data->data, res.size);
4485 	res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ?
4486 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 :
4487 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
4488 	if (attr->transfer)
4489 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4490 	else
4491 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4492 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4493 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4494 		return rte_flow_error_set(error, EINVAL,
4495 					  RTE_FLOW_ERROR_TYPE_ACTION,
4496 					  NULL, "can't create encap action");
4497 	return 0;
4498 }
4499 
4500 /**
4501  * Create action push VLAN.
4502  *
4503  * @param[in] dev
4504  *   Pointer to rte_eth_dev structure.
4505  * @param[in] attr
4506  *   Pointer to the flow attributes.
4507  * @param[in] vlan
4508  *   Pointer to the vlan to push to the Ethernet header.
4509  * @param[in, out] dev_flow
4510  *   Pointer to the mlx5_flow.
4511  * @param[out] error
4512  *   Pointer to the error structure.
4513  *
4514  * @return
4515  *   0 on success, a negative errno value otherwise and rte_errno is set.
4516  */
4517 static int
4518 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
4519 				const struct rte_flow_attr *attr,
4520 				const struct rte_vlan_hdr *vlan,
4521 				struct mlx5_flow *dev_flow,
4522 				struct rte_flow_error *error)
4523 {
4524 	struct mlx5_flow_dv_push_vlan_action_resource res;
4525 
4526 	memset(&res, 0, sizeof(res));
4527 	res.vlan_tag =
4528 		rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 |
4529 				 vlan->vlan_tci);
4530 	if (attr->transfer)
4531 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4532 	else
4533 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4534 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4535 	return flow_dv_push_vlan_action_resource_register
4536 					    (dev, &res, dev_flow, error);
4537 }
4538 
4539 /**
4540  * Validate the modify-header actions.
4541  *
4542  * @param[in] action_flags
4543  *   Holds the actions detected until now.
4544  * @param[in] action
4545  *   Pointer to the modify action.
4546  * @param[out] error
4547  *   Pointer to error structure.
4548  *
4549  * @return
4550  *   0 on success, a negative errno value otherwise and rte_errno is set.
4551  */
4552 static int
4553 flow_dv_validate_action_modify_hdr(const uint64_t action_flags,
4554 				   const struct rte_flow_action *action,
4555 				   struct rte_flow_error *error)
4556 {
4557 	if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf)
4558 		return rte_flow_error_set(error, EINVAL,
4559 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
4560 					  NULL, "action configuration not set");
4561 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
4562 		return rte_flow_error_set(error, EINVAL,
4563 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4564 					  "can't have encap action before"
4565 					  " modify action");
4566 	return 0;
4567 }
4568 
4569 /**
4570  * Validate the modify-header MAC address actions.
4571  *
4572  * @param[in] action_flags
4573  *   Holds the actions detected until now.
4574  * @param[in] action
4575  *   Pointer to the modify action.
4576  * @param[in] item_flags
4577  *   Holds the items detected.
4578  * @param[out] error
4579  *   Pointer to error structure.
4580  *
4581  * @return
4582  *   0 on success, a negative errno value otherwise and rte_errno is set.
4583  */
4584 static int
4585 flow_dv_validate_action_modify_mac(const uint64_t action_flags,
4586 				   const struct rte_flow_action *action,
4587 				   const uint64_t item_flags,
4588 				   struct rte_flow_error *error)
4589 {
4590 	int ret = 0;
4591 
4592 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4593 	if (!ret) {
4594 		if (!(item_flags & MLX5_FLOW_LAYER_L2))
4595 			return rte_flow_error_set(error, EINVAL,
4596 						  RTE_FLOW_ERROR_TYPE_ACTION,
4597 						  NULL,
4598 						  "no L2 item in pattern");
4599 	}
4600 	return ret;
4601 }
4602 
4603 /**
4604  * Validate the modify-header IPv4 address actions.
4605  *
4606  * @param[in] action_flags
4607  *   Holds the actions detected until now.
4608  * @param[in] action
4609  *   Pointer to the modify action.
4610  * @param[in] item_flags
4611  *   Holds the items detected.
4612  * @param[out] error
4613  *   Pointer to error structure.
4614  *
4615  * @return
4616  *   0 on success, a negative errno value otherwise and rte_errno is set.
4617  */
4618 static int
4619 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags,
4620 				    const struct rte_flow_action *action,
4621 				    const uint64_t item_flags,
4622 				    struct rte_flow_error *error)
4623 {
4624 	int ret = 0;
4625 	uint64_t layer;
4626 
4627 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4628 	if (!ret) {
4629 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4630 				 MLX5_FLOW_LAYER_INNER_L3_IPV4 :
4631 				 MLX5_FLOW_LAYER_OUTER_L3_IPV4;
4632 		if (!(item_flags & layer))
4633 			return rte_flow_error_set(error, EINVAL,
4634 						  RTE_FLOW_ERROR_TYPE_ACTION,
4635 						  NULL,
4636 						  "no ipv4 item in pattern");
4637 	}
4638 	return ret;
4639 }
4640 
4641 /**
4642  * Validate the modify-header IPv6 address actions.
4643  *
4644  * @param[in] action_flags
4645  *   Holds the actions detected until now.
4646  * @param[in] action
4647  *   Pointer to the modify action.
4648  * @param[in] item_flags
4649  *   Holds the items detected.
4650  * @param[out] error
4651  *   Pointer to error structure.
4652  *
4653  * @return
4654  *   0 on success, a negative errno value otherwise and rte_errno is set.
4655  */
4656 static int
4657 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags,
4658 				    const struct rte_flow_action *action,
4659 				    const uint64_t item_flags,
4660 				    struct rte_flow_error *error)
4661 {
4662 	int ret = 0;
4663 	uint64_t layer;
4664 
4665 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4666 	if (!ret) {
4667 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4668 				 MLX5_FLOW_LAYER_INNER_L3_IPV6 :
4669 				 MLX5_FLOW_LAYER_OUTER_L3_IPV6;
4670 		if (!(item_flags & layer))
4671 			return rte_flow_error_set(error, EINVAL,
4672 						  RTE_FLOW_ERROR_TYPE_ACTION,
4673 						  NULL,
4674 						  "no ipv6 item in pattern");
4675 	}
4676 	return ret;
4677 }
4678 
4679 /**
4680  * Validate the modify-header TP actions.
4681  *
4682  * @param[in] action_flags
4683  *   Holds the actions detected until now.
4684  * @param[in] action
4685  *   Pointer to the modify action.
4686  * @param[in] item_flags
4687  *   Holds the items detected.
4688  * @param[out] error
4689  *   Pointer to error structure.
4690  *
4691  * @return
4692  *   0 on success, a negative errno value otherwise and rte_errno is set.
4693  */
4694 static int
4695 flow_dv_validate_action_modify_tp(const uint64_t action_flags,
4696 				  const struct rte_flow_action *action,
4697 				  const uint64_t item_flags,
4698 				  struct rte_flow_error *error)
4699 {
4700 	int ret = 0;
4701 	uint64_t layer;
4702 
4703 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4704 	if (!ret) {
4705 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4706 				 MLX5_FLOW_LAYER_INNER_L4 :
4707 				 MLX5_FLOW_LAYER_OUTER_L4;
4708 		if (!(item_flags & layer))
4709 			return rte_flow_error_set(error, EINVAL,
4710 						  RTE_FLOW_ERROR_TYPE_ACTION,
4711 						  NULL, "no transport layer "
4712 						  "in pattern");
4713 	}
4714 	return ret;
4715 }
4716 
4717 /**
4718  * Validate the modify-header actions of increment/decrement
4719  * TCP Sequence-number.
4720  *
4721  * @param[in] action_flags
4722  *   Holds the actions detected until now.
4723  * @param[in] action
4724  *   Pointer to the modify action.
4725  * @param[in] item_flags
4726  *   Holds the items detected.
4727  * @param[out] error
4728  *   Pointer to error structure.
4729  *
4730  * @return
4731  *   0 on success, a negative errno value otherwise and rte_errno is set.
4732  */
4733 static int
4734 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags,
4735 				       const struct rte_flow_action *action,
4736 				       const uint64_t item_flags,
4737 				       struct rte_flow_error *error)
4738 {
4739 	int ret = 0;
4740 	uint64_t layer;
4741 
4742 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4743 	if (!ret) {
4744 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4745 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4746 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4747 		if (!(item_flags & layer))
4748 			return rte_flow_error_set(error, EINVAL,
4749 						  RTE_FLOW_ERROR_TYPE_ACTION,
4750 						  NULL, "no TCP item in"
4751 						  " pattern");
4752 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ &&
4753 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) ||
4754 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ &&
4755 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ)))
4756 			return rte_flow_error_set(error, EINVAL,
4757 						  RTE_FLOW_ERROR_TYPE_ACTION,
4758 						  NULL,
4759 						  "cannot decrease and increase"
4760 						  " TCP sequence number"
4761 						  " at the same time");
4762 	}
4763 	return ret;
4764 }
4765 
4766 /**
4767  * Validate the modify-header actions of increment/decrement
4768  * TCP Acknowledgment number.
4769  *
4770  * @param[in] action_flags
4771  *   Holds the actions detected until now.
4772  * @param[in] action
4773  *   Pointer to the modify action.
4774  * @param[in] item_flags
4775  *   Holds the items detected.
4776  * @param[out] error
4777  *   Pointer to error structure.
4778  *
4779  * @return
4780  *   0 on success, a negative errno value otherwise and rte_errno is set.
4781  */
4782 static int
4783 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags,
4784 				       const struct rte_flow_action *action,
4785 				       const uint64_t item_flags,
4786 				       struct rte_flow_error *error)
4787 {
4788 	int ret = 0;
4789 	uint64_t layer;
4790 
4791 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4792 	if (!ret) {
4793 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4794 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4795 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4796 		if (!(item_flags & layer))
4797 			return rte_flow_error_set(error, EINVAL,
4798 						  RTE_FLOW_ERROR_TYPE_ACTION,
4799 						  NULL, "no TCP item in"
4800 						  " pattern");
4801 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK &&
4802 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) ||
4803 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK &&
4804 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK)))
4805 			return rte_flow_error_set(error, EINVAL,
4806 						  RTE_FLOW_ERROR_TYPE_ACTION,
4807 						  NULL,
4808 						  "cannot decrease and increase"
4809 						  " TCP acknowledgment number"
4810 						  " at the same time");
4811 	}
4812 	return ret;
4813 }
4814 
4815 /**
4816  * Validate the modify-header TTL actions.
4817  *
4818  * @param[in] action_flags
4819  *   Holds the actions detected until now.
4820  * @param[in] action
4821  *   Pointer to the modify action.
4822  * @param[in] item_flags
4823  *   Holds the items detected.
4824  * @param[out] error
4825  *   Pointer to error structure.
4826  *
4827  * @return
4828  *   0 on success, a negative errno value otherwise and rte_errno is set.
4829  */
4830 static int
4831 flow_dv_validate_action_modify_ttl(const uint64_t action_flags,
4832 				   const struct rte_flow_action *action,
4833 				   const uint64_t item_flags,
4834 				   struct rte_flow_error *error)
4835 {
4836 	int ret = 0;
4837 	uint64_t layer;
4838 
4839 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4840 	if (!ret) {
4841 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4842 				 MLX5_FLOW_LAYER_INNER_L3 :
4843 				 MLX5_FLOW_LAYER_OUTER_L3;
4844 		if (!(item_flags & layer))
4845 			return rte_flow_error_set(error, EINVAL,
4846 						  RTE_FLOW_ERROR_TYPE_ACTION,
4847 						  NULL,
4848 						  "no IP protocol in pattern");
4849 	}
4850 	return ret;
4851 }
4852 
4853 /**
4854  * Validate the generic modify field actions.
4855  * @param[in] dev
4856  *   Pointer to the rte_eth_dev structure.
4857  * @param[in] action_flags
4858  *   Holds the actions detected until now.
4859  * @param[in] action
4860  *   Pointer to the modify action.
4861  * @param[in] attr
4862  *   Pointer to the flow attributes.
4863  * @param[out] error
4864  *   Pointer to error structure.
4865  *
4866  * @return
4867  *   Number of header fields to modify (0 or more) on success,
4868  *   a negative errno value otherwise and rte_errno is set.
4869  */
4870 static int
4871 flow_dv_validate_action_modify_field(struct rte_eth_dev *dev,
4872 				   const uint64_t action_flags,
4873 				   const struct rte_flow_action *action,
4874 				   const struct rte_flow_attr *attr,
4875 				   struct rte_flow_error *error)
4876 {
4877 	int ret = 0;
4878 	struct mlx5_priv *priv = dev->data->dev_private;
4879 	struct mlx5_dev_config *config = &priv->config;
4880 	const struct rte_flow_action_modify_field *action_modify_field =
4881 		action->conf;
4882 	uint32_t dst_width = mlx5_flow_item_field_width(priv,
4883 				action_modify_field->dst.field);
4884 	uint32_t src_width = mlx5_flow_item_field_width(priv,
4885 				action_modify_field->src.field);
4886 
4887 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4888 	if (ret)
4889 		return ret;
4890 
4891 	if (action_modify_field->width == 0)
4892 		return rte_flow_error_set(error, EINVAL,
4893 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4894 				"no bits are requested to be modified");
4895 	else if (action_modify_field->width > dst_width ||
4896 		 action_modify_field->width > src_width)
4897 		return rte_flow_error_set(error, EINVAL,
4898 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4899 				"cannot modify more bits than"
4900 				" the width of a field");
4901 	if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE &&
4902 	    action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) {
4903 		if ((action_modify_field->dst.offset +
4904 		     action_modify_field->width > dst_width) ||
4905 		    (action_modify_field->dst.offset % 32))
4906 			return rte_flow_error_set(error, EINVAL,
4907 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4908 					"destination offset is too big"
4909 					" or not aligned to 4 bytes");
4910 		if (action_modify_field->dst.level &&
4911 		    action_modify_field->dst.field != RTE_FLOW_FIELD_TAG)
4912 			return rte_flow_error_set(error, ENOTSUP,
4913 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4914 					"inner header fields modification"
4915 					" is not supported");
4916 	}
4917 	if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE &&
4918 	    action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) {
4919 		if (!attr->transfer && !attr->group)
4920 			return rte_flow_error_set(error, ENOTSUP,
4921 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4922 					"modify field action is not"
4923 					" supported for group 0");
4924 		if ((action_modify_field->src.offset +
4925 		     action_modify_field->width > src_width) ||
4926 		    (action_modify_field->src.offset % 32))
4927 			return rte_flow_error_set(error, EINVAL,
4928 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4929 					"source offset is too big"
4930 					" or not aligned to 4 bytes");
4931 		if (action_modify_field->src.level &&
4932 		    action_modify_field->src.field != RTE_FLOW_FIELD_TAG)
4933 			return rte_flow_error_set(error, ENOTSUP,
4934 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4935 					"inner header fields modification"
4936 					" is not supported");
4937 	}
4938 	if ((action_modify_field->dst.field ==
4939 	     action_modify_field->src.field) &&
4940 	    (action_modify_field->dst.level ==
4941 	     action_modify_field->src.level))
4942 		return rte_flow_error_set(error, EINVAL,
4943 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4944 				"source and destination fields"
4945 				" cannot be the same");
4946 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE ||
4947 	    action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER ||
4948 	    action_modify_field->dst.field == RTE_FLOW_FIELD_MARK)
4949 		return rte_flow_error_set(error, EINVAL,
4950 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4951 				"mark, immediate value or a pointer to it"
4952 				" cannot be used as a destination");
4953 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_START ||
4954 	    action_modify_field->src.field == RTE_FLOW_FIELD_START)
4955 		return rte_flow_error_set(error, ENOTSUP,
4956 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4957 				"modifications of an arbitrary"
4958 				" place in a packet is not supported");
4959 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VLAN_TYPE ||
4960 	    action_modify_field->src.field == RTE_FLOW_FIELD_VLAN_TYPE)
4961 		return rte_flow_error_set(error, ENOTSUP,
4962 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4963 				"modifications of the 802.1Q Tag"
4964 				" Identifier is not supported");
4965 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VXLAN_VNI ||
4966 	    action_modify_field->src.field == RTE_FLOW_FIELD_VXLAN_VNI)
4967 		return rte_flow_error_set(error, ENOTSUP,
4968 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4969 				"modifications of the VXLAN Network"
4970 				" Identifier is not supported");
4971 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_GENEVE_VNI ||
4972 	    action_modify_field->src.field == RTE_FLOW_FIELD_GENEVE_VNI)
4973 		return rte_flow_error_set(error, ENOTSUP,
4974 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4975 				"modifications of the GENEVE Network"
4976 				" Identifier is not supported");
4977 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_MARK ||
4978 	    action_modify_field->src.field == RTE_FLOW_FIELD_MARK ||
4979 	    action_modify_field->dst.field == RTE_FLOW_FIELD_META ||
4980 	    action_modify_field->src.field == RTE_FLOW_FIELD_META) {
4981 		if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||
4982 		    !mlx5_flow_ext_mreg_supported(dev))
4983 			return rte_flow_error_set(error, ENOTSUP,
4984 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4985 					"cannot modify mark or metadata without"
4986 					" extended metadata register support");
4987 	}
4988 	if (action_modify_field->operation != RTE_FLOW_MODIFY_SET)
4989 		return rte_flow_error_set(error, ENOTSUP,
4990 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4991 				"add and sub operations"
4992 				" are not supported");
4993 	return (action_modify_field->width / 32) +
4994 	       !!(action_modify_field->width % 32);
4995 }
4996 
4997 /**
4998  * Validate jump action.
4999  *
5000  * @param[in] action
5001  *   Pointer to the jump action.
5002  * @param[in] action_flags
5003  *   Holds the actions detected until now.
5004  * @param[in] attributes
5005  *   Pointer to flow attributes
5006  * @param[in] external
5007  *   Action belongs to flow rule created by request external to PMD.
5008  * @param[out] error
5009  *   Pointer to error structure.
5010  *
5011  * @return
5012  *   0 on success, a negative errno value otherwise and rte_errno is set.
5013  */
5014 static int
5015 flow_dv_validate_action_jump(struct rte_eth_dev *dev,
5016 			     const struct mlx5_flow_tunnel *tunnel,
5017 			     const struct rte_flow_action *action,
5018 			     uint64_t action_flags,
5019 			     const struct rte_flow_attr *attributes,
5020 			     bool external, struct rte_flow_error *error)
5021 {
5022 	uint32_t target_group, table;
5023 	int ret = 0;
5024 	struct flow_grp_info grp_info = {
5025 		.external = !!external,
5026 		.transfer = !!attributes->transfer,
5027 		.fdb_def_rule = 1,
5028 		.std_tbl_fix = 0
5029 	};
5030 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
5031 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
5032 		return rte_flow_error_set(error, EINVAL,
5033 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5034 					  "can't have 2 fate actions in"
5035 					  " same flow");
5036 	if (!action->conf)
5037 		return rte_flow_error_set(error, EINVAL,
5038 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5039 					  NULL, "action configuration not set");
5040 	target_group =
5041 		((const struct rte_flow_action_jump *)action->conf)->group;
5042 	ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table,
5043 				       &grp_info, error);
5044 	if (ret)
5045 		return ret;
5046 	if (attributes->group == target_group &&
5047 	    !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET |
5048 			      MLX5_FLOW_ACTION_TUNNEL_MATCH)))
5049 		return rte_flow_error_set(error, EINVAL,
5050 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5051 					  "target group must be other than"
5052 					  " the current flow group");
5053 	return 0;
5054 }
5055 
5056 /*
5057  * Validate the port_id action.
5058  *
5059  * @param[in] dev
5060  *   Pointer to rte_eth_dev structure.
5061  * @param[in] action_flags
5062  *   Bit-fields that holds the actions detected until now.
5063  * @param[in] action
5064  *   Port_id RTE action structure.
5065  * @param[in] attr
5066  *   Attributes of flow that includes this action.
5067  * @param[out] error
5068  *   Pointer to error structure.
5069  *
5070  * @return
5071  *   0 on success, a negative errno value otherwise and rte_errno is set.
5072  */
5073 static int
5074 flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
5075 				uint64_t action_flags,
5076 				const struct rte_flow_action *action,
5077 				const struct rte_flow_attr *attr,
5078 				struct rte_flow_error *error)
5079 {
5080 	const struct rte_flow_action_port_id *port_id;
5081 	struct mlx5_priv *act_priv;
5082 	struct mlx5_priv *dev_priv;
5083 	uint16_t port;
5084 
5085 	if (!attr->transfer)
5086 		return rte_flow_error_set(error, ENOTSUP,
5087 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5088 					  NULL,
5089 					  "port id action is valid in transfer"
5090 					  " mode only");
5091 	if (!action || !action->conf)
5092 		return rte_flow_error_set(error, ENOTSUP,
5093 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5094 					  NULL,
5095 					  "port id action parameters must be"
5096 					  " specified");
5097 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
5098 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
5099 		return rte_flow_error_set(error, EINVAL,
5100 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5101 					  "can have only one fate actions in"
5102 					  " a flow");
5103 	dev_priv = mlx5_dev_to_eswitch_info(dev);
5104 	if (!dev_priv)
5105 		return rte_flow_error_set(error, rte_errno,
5106 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5107 					  NULL,
5108 					  "failed to obtain E-Switch info");
5109 	port_id = action->conf;
5110 	port = port_id->original ? dev->data->port_id : port_id->id;
5111 	act_priv = mlx5_port_to_eswitch_info(port, false);
5112 	if (!act_priv)
5113 		return rte_flow_error_set
5114 				(error, rte_errno,
5115 				 RTE_FLOW_ERROR_TYPE_ACTION_CONF, port_id,
5116 				 "failed to obtain E-Switch port id for port");
5117 	if (act_priv->domain_id != dev_priv->domain_id)
5118 		return rte_flow_error_set
5119 				(error, EINVAL,
5120 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5121 				 "port does not belong to"
5122 				 " E-Switch being configured");
5123 	return 0;
5124 }
5125 
5126 /**
5127  * Get the maximum number of modify header actions.
5128  *
5129  * @param dev
5130  *   Pointer to rte_eth_dev structure.
5131  * @param root
5132  *   Whether action is on root table.
5133  *
5134  * @return
5135  *   Max number of modify header actions device can support.
5136  */
5137 static inline unsigned int
5138 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused,
5139 			      bool root)
5140 {
5141 	/*
5142 	 * There's no way to directly query the max capacity from FW.
5143 	 * The maximal value on root table should be assumed to be supported.
5144 	 */
5145 	if (!root)
5146 		return MLX5_MAX_MODIFY_NUM;
5147 	else
5148 		return MLX5_ROOT_TBL_MODIFY_NUM;
5149 }
5150 
5151 /**
5152  * Validate the meter action.
5153  *
5154  * @param[in] dev
5155  *   Pointer to rte_eth_dev structure.
5156  * @param[in] action_flags
5157  *   Bit-fields that holds the actions detected until now.
5158  * @param[in] action
5159  *   Pointer to the meter action.
5160  * @param[in] attr
5161  *   Attributes of flow that includes this action.
5162  * @param[in] port_id_item
5163  *   Pointer to item indicating port id.
5164  * @param[out] error
5165  *   Pointer to error structure.
5166  *
5167  * @return
5168  *   0 on success, a negative errno value otherwise and rte_ernno is set.
5169  */
5170 static int
5171 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
5172 				uint64_t action_flags,
5173 				const struct rte_flow_action *action,
5174 				const struct rte_flow_attr *attr,
5175 				const struct rte_flow_item *port_id_item,
5176 				bool *def_policy,
5177 				struct rte_flow_error *error)
5178 {
5179 	struct mlx5_priv *priv = dev->data->dev_private;
5180 	const struct rte_flow_action_meter *am = action->conf;
5181 	struct mlx5_flow_meter_info *fm;
5182 	struct mlx5_flow_meter_policy *mtr_policy;
5183 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
5184 
5185 	if (!am)
5186 		return rte_flow_error_set(error, EINVAL,
5187 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5188 					  "meter action conf is NULL");
5189 
5190 	if (action_flags & MLX5_FLOW_ACTION_METER)
5191 		return rte_flow_error_set(error, ENOTSUP,
5192 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5193 					  "meter chaining not support");
5194 	if (action_flags & MLX5_FLOW_ACTION_JUMP)
5195 		return rte_flow_error_set(error, ENOTSUP,
5196 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5197 					  "meter with jump not support");
5198 	if (!priv->mtr_en)
5199 		return rte_flow_error_set(error, ENOTSUP,
5200 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5201 					  NULL,
5202 					  "meter action not supported");
5203 	fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL);
5204 	if (!fm)
5205 		return rte_flow_error_set(error, EINVAL,
5206 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5207 					  "Meter not found");
5208 	/* aso meter can always be shared by different domains */
5209 	if (fm->ref_cnt && !priv->sh->meter_aso_en &&
5210 	    !(fm->transfer == attr->transfer ||
5211 	      (!fm->ingress && !attr->ingress && attr->egress) ||
5212 	      (!fm->egress && !attr->egress && attr->ingress)))
5213 		return rte_flow_error_set(error, EINVAL,
5214 			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5215 			"Flow attributes domain are either invalid "
5216 			"or have a domain conflict with current "
5217 			"meter attributes");
5218 	if (fm->def_policy) {
5219 		if (!((attr->transfer &&
5220 			mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
5221 			(attr->egress &&
5222 			mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
5223 			(attr->ingress &&
5224 			mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
5225 			return rte_flow_error_set(error, EINVAL,
5226 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5227 					  "Flow attributes domain "
5228 					  "have a conflict with current "
5229 					  "meter domain attributes");
5230 		*def_policy = true;
5231 	} else {
5232 		mtr_policy = mlx5_flow_meter_policy_find(dev,
5233 						fm->policy_id, NULL);
5234 		if (!mtr_policy)
5235 			return rte_flow_error_set(error, EINVAL,
5236 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5237 					  "Invalid policy id for meter ");
5238 		if (!((attr->transfer && mtr_policy->transfer) ||
5239 			(attr->egress && mtr_policy->egress) ||
5240 			(attr->ingress && mtr_policy->ingress)))
5241 			return rte_flow_error_set(error, EINVAL,
5242 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5243 					  "Flow attributes domain "
5244 					  "have a conflict with current "
5245 					  "meter domain attributes");
5246 		if (attr->transfer && mtr_policy->dev) {
5247 			/**
5248 			 * When policy has fate action of port_id,
5249 			 * the flow should have the same src port as policy.
5250 			 */
5251 			struct mlx5_priv *policy_port_priv =
5252 					mtr_policy->dev->data->dev_private;
5253 			int32_t flow_src_port = priv->representor_id;
5254 
5255 			if (port_id_item) {
5256 				const struct rte_flow_item_port_id *spec =
5257 							port_id_item->spec;
5258 				struct mlx5_priv *port_priv =
5259 					mlx5_port_to_eswitch_info(spec->id,
5260 								  false);
5261 				if (!port_priv)
5262 					return rte_flow_error_set(error,
5263 						rte_errno,
5264 						RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
5265 						spec,
5266 						"Failed to get port info.");
5267 				flow_src_port = port_priv->representor_id;
5268 			}
5269 			if (flow_src_port != policy_port_priv->representor_id)
5270 				return rte_flow_error_set(error,
5271 						rte_errno,
5272 						RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
5273 						NULL,
5274 						"Flow and meter policy "
5275 						"have different src port.");
5276 		}
5277 		*def_policy = false;
5278 	}
5279 	return 0;
5280 }
5281 
5282 /**
5283  * Validate the age action.
5284  *
5285  * @param[in] action_flags
5286  *   Holds the actions detected until now.
5287  * @param[in] action
5288  *   Pointer to the age action.
5289  * @param[in] dev
5290  *   Pointer to the Ethernet device structure.
5291  * @param[out] error
5292  *   Pointer to error structure.
5293  *
5294  * @return
5295  *   0 on success, a negative errno value otherwise and rte_errno is set.
5296  */
5297 static int
5298 flow_dv_validate_action_age(uint64_t action_flags,
5299 			    const struct rte_flow_action *action,
5300 			    struct rte_eth_dev *dev,
5301 			    struct rte_flow_error *error)
5302 {
5303 	struct mlx5_priv *priv = dev->data->dev_private;
5304 	const struct rte_flow_action_age *age = action->conf;
5305 
5306 	if (!priv->config.devx || (priv->sh->cmng.counter_fallback &&
5307 	    !priv->sh->aso_age_mng))
5308 		return rte_flow_error_set(error, ENOTSUP,
5309 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5310 					  NULL,
5311 					  "age action not supported");
5312 	if (!(action->conf))
5313 		return rte_flow_error_set(error, EINVAL,
5314 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5315 					  "configuration cannot be null");
5316 	if (!(age->timeout))
5317 		return rte_flow_error_set(error, EINVAL,
5318 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5319 					  "invalid timeout value 0");
5320 	if (action_flags & MLX5_FLOW_ACTION_AGE)
5321 		return rte_flow_error_set(error, EINVAL,
5322 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5323 					  "duplicate age actions set");
5324 	return 0;
5325 }
5326 
5327 /**
5328  * Validate the modify-header IPv4 DSCP actions.
5329  *
5330  * @param[in] action_flags
5331  *   Holds the actions detected until now.
5332  * @param[in] action
5333  *   Pointer to the modify action.
5334  * @param[in] item_flags
5335  *   Holds the items detected.
5336  * @param[out] error
5337  *   Pointer to error structure.
5338  *
5339  * @return
5340  *   0 on success, a negative errno value otherwise and rte_errno is set.
5341  */
5342 static int
5343 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags,
5344 					 const struct rte_flow_action *action,
5345 					 const uint64_t item_flags,
5346 					 struct rte_flow_error *error)
5347 {
5348 	int ret = 0;
5349 
5350 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5351 	if (!ret) {
5352 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4))
5353 			return rte_flow_error_set(error, EINVAL,
5354 						  RTE_FLOW_ERROR_TYPE_ACTION,
5355 						  NULL,
5356 						  "no ipv4 item in pattern");
5357 	}
5358 	return ret;
5359 }
5360 
5361 /**
5362  * Validate the modify-header IPv6 DSCP actions.
5363  *
5364  * @param[in] action_flags
5365  *   Holds the actions detected until now.
5366  * @param[in] action
5367  *   Pointer to the modify action.
5368  * @param[in] item_flags
5369  *   Holds the items detected.
5370  * @param[out] error
5371  *   Pointer to error structure.
5372  *
5373  * @return
5374  *   0 on success, a negative errno value otherwise and rte_errno is set.
5375  */
5376 static int
5377 flow_dv_validate_action_modify_ipv6_dscp(const uint64_t action_flags,
5378 					 const struct rte_flow_action *action,
5379 					 const uint64_t item_flags,
5380 					 struct rte_flow_error *error)
5381 {
5382 	int ret = 0;
5383 
5384 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5385 	if (!ret) {
5386 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6))
5387 			return rte_flow_error_set(error, EINVAL,
5388 						  RTE_FLOW_ERROR_TYPE_ACTION,
5389 						  NULL,
5390 						  "no ipv6 item in pattern");
5391 	}
5392 	return ret;
5393 }
5394 
5395 int
5396 flow_dv_modify_match_cb(void *tool_ctx __rte_unused,
5397 			struct mlx5_list_entry *entry, void *cb_ctx)
5398 {
5399 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5400 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5401 	struct mlx5_flow_dv_modify_hdr_resource *resource =
5402 				  container_of(entry, typeof(*resource), entry);
5403 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5404 
5405 	key_len += ref->actions_num * sizeof(ref->actions[0]);
5406 	return ref->actions_num != resource->actions_num ||
5407 	       memcmp(&ref->ft_type, &resource->ft_type, key_len);
5408 }
5409 
5410 static struct mlx5_indexed_pool *
5411 flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index)
5412 {
5413 	struct mlx5_indexed_pool *ipool = __atomic_load_n
5414 				     (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST);
5415 
5416 	if (!ipool) {
5417 		struct mlx5_indexed_pool *expected = NULL;
5418 		struct mlx5_indexed_pool_config cfg =
5419 		    (struct mlx5_indexed_pool_config) {
5420 		       .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
5421 								   (index + 1) *
5422 					   sizeof(struct mlx5_modification_cmd),
5423 		       .trunk_size = 64,
5424 		       .grow_trunk = 3,
5425 		       .grow_shift = 2,
5426 		       .need_lock = 1,
5427 		       .release_mem_en = !!sh->reclaim_mode,
5428 		       .per_core_cache = sh->reclaim_mode ? 0 : (1 << 16),
5429 		       .malloc = mlx5_malloc,
5430 		       .free = mlx5_free,
5431 		       .type = "mlx5_modify_action_resource",
5432 		};
5433 
5434 		cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool));
5435 		ipool = mlx5_ipool_create(&cfg);
5436 		if (!ipool)
5437 			return NULL;
5438 		if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index],
5439 						 &expected, ipool, false,
5440 						 __ATOMIC_SEQ_CST,
5441 						 __ATOMIC_SEQ_CST)) {
5442 			mlx5_ipool_destroy(ipool);
5443 			ipool = __atomic_load_n(&sh->mdh_ipools[index],
5444 						__ATOMIC_SEQ_CST);
5445 		}
5446 	}
5447 	return ipool;
5448 }
5449 
5450 struct mlx5_list_entry *
5451 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx)
5452 {
5453 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5454 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5455 	struct mlx5dv_dr_domain *ns;
5456 	struct mlx5_flow_dv_modify_hdr_resource *entry;
5457 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5458 	struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh,
5459 							  ref->actions_num - 1);
5460 	int ret;
5461 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5462 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5463 	uint32_t idx;
5464 
5465 	if (unlikely(!ipool)) {
5466 		rte_flow_error_set(ctx->error, ENOMEM,
5467 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5468 				   NULL, "cannot allocate modify ipool");
5469 		return NULL;
5470 	}
5471 	entry = mlx5_ipool_zmalloc(ipool, &idx);
5472 	if (!entry) {
5473 		rte_flow_error_set(ctx->error, ENOMEM,
5474 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5475 				   "cannot allocate resource memory");
5476 		return NULL;
5477 	}
5478 	rte_memcpy(&entry->ft_type,
5479 		   RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)),
5480 		   key_len + data_len);
5481 	if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
5482 		ns = sh->fdb_domain;
5483 	else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
5484 		ns = sh->tx_domain;
5485 	else
5486 		ns = sh->rx_domain;
5487 	ret = mlx5_flow_os_create_flow_action_modify_header
5488 					(sh->ctx, ns, entry,
5489 					 data_len, &entry->action);
5490 	if (ret) {
5491 		mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx);
5492 		rte_flow_error_set(ctx->error, ENOMEM,
5493 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5494 				   NULL, "cannot create modification action");
5495 		return NULL;
5496 	}
5497 	entry->idx = idx;
5498 	return &entry->entry;
5499 }
5500 
5501 struct mlx5_list_entry *
5502 flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
5503 			void *cb_ctx)
5504 {
5505 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5506 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5507 	struct mlx5_flow_dv_modify_hdr_resource *entry;
5508 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5509 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5510 	uint32_t idx;
5511 
5512 	entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1],
5513 				  &idx);
5514 	if (!entry) {
5515 		rte_flow_error_set(ctx->error, ENOMEM,
5516 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5517 				   "cannot allocate resource memory");
5518 		return NULL;
5519 	}
5520 	memcpy(entry, oentry, sizeof(*entry) + data_len);
5521 	entry->idx = idx;
5522 	return &entry->entry;
5523 }
5524 
5525 void
5526 flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
5527 {
5528 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5529 	struct mlx5_flow_dv_modify_hdr_resource *res =
5530 		container_of(entry, typeof(*res), entry);
5531 
5532 	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
5533 }
5534 
5535 /**
5536  * Validate the sample action.
5537  *
5538  * @param[in, out] action_flags
5539  *   Holds the actions detected until now.
5540  * @param[in] action
5541  *   Pointer to the sample action.
5542  * @param[in] dev
5543  *   Pointer to the Ethernet device structure.
5544  * @param[in] attr
5545  *   Attributes of flow that includes this action.
5546  * @param[in] item_flags
5547  *   Holds the items detected.
5548  * @param[in] rss
5549  *   Pointer to the RSS action.
5550  * @param[out] sample_rss
5551  *   Pointer to the RSS action in sample action list.
5552  * @param[out] count
5553  *   Pointer to the COUNT action in sample action list.
5554  * @param[out] fdb_mirror_limit
5555  *   Pointer to the FDB mirror limitation flag.
5556  * @param[out] error
5557  *   Pointer to error structure.
5558  *
5559  * @return
5560  *   0 on success, a negative errno value otherwise and rte_errno is set.
5561  */
5562 static int
5563 flow_dv_validate_action_sample(uint64_t *action_flags,
5564 			       const struct rte_flow_action *action,
5565 			       struct rte_eth_dev *dev,
5566 			       const struct rte_flow_attr *attr,
5567 			       uint64_t item_flags,
5568 			       const struct rte_flow_action_rss *rss,
5569 			       const struct rte_flow_action_rss **sample_rss,
5570 			       const struct rte_flow_action_count **count,
5571 			       int *fdb_mirror_limit,
5572 			       struct rte_flow_error *error)
5573 {
5574 	struct mlx5_priv *priv = dev->data->dev_private;
5575 	struct mlx5_dev_config *dev_conf = &priv->config;
5576 	const struct rte_flow_action_sample *sample = action->conf;
5577 	const struct rte_flow_action *act;
5578 	uint64_t sub_action_flags = 0;
5579 	uint16_t queue_index = 0xFFFF;
5580 	int actions_n = 0;
5581 	int ret;
5582 
5583 	if (!sample)
5584 		return rte_flow_error_set(error, EINVAL,
5585 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5586 					  "configuration cannot be NULL");
5587 	if (sample->ratio == 0)
5588 		return rte_flow_error_set(error, EINVAL,
5589 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5590 					  "ratio value starts from 1");
5591 	if (!priv->config.devx || (sample->ratio > 0 && !priv->sampler_en))
5592 		return rte_flow_error_set(error, ENOTSUP,
5593 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5594 					  NULL,
5595 					  "sample action not supported");
5596 	if (*action_flags & MLX5_FLOW_ACTION_SAMPLE)
5597 		return rte_flow_error_set(error, EINVAL,
5598 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5599 					  "Multiple sample actions not "
5600 					  "supported");
5601 	if (*action_flags & MLX5_FLOW_ACTION_METER)
5602 		return rte_flow_error_set(error, EINVAL,
5603 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5604 					  "wrong action order, meter should "
5605 					  "be after sample action");
5606 	if (*action_flags & MLX5_FLOW_ACTION_JUMP)
5607 		return rte_flow_error_set(error, EINVAL,
5608 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5609 					  "wrong action order, jump should "
5610 					  "be after sample action");
5611 	act = sample->actions;
5612 	for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
5613 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
5614 			return rte_flow_error_set(error, ENOTSUP,
5615 						  RTE_FLOW_ERROR_TYPE_ACTION,
5616 						  act, "too many actions");
5617 		switch (act->type) {
5618 		case RTE_FLOW_ACTION_TYPE_QUEUE:
5619 			ret = mlx5_flow_validate_action_queue(act,
5620 							      sub_action_flags,
5621 							      dev,
5622 							      attr, error);
5623 			if (ret < 0)
5624 				return ret;
5625 			queue_index = ((const struct rte_flow_action_queue *)
5626 							(act->conf))->index;
5627 			sub_action_flags |= MLX5_FLOW_ACTION_QUEUE;
5628 			++actions_n;
5629 			break;
5630 		case RTE_FLOW_ACTION_TYPE_RSS:
5631 			*sample_rss = act->conf;
5632 			ret = mlx5_flow_validate_action_rss(act,
5633 							    sub_action_flags,
5634 							    dev, attr,
5635 							    item_flags,
5636 							    error);
5637 			if (ret < 0)
5638 				return ret;
5639 			if (rss && *sample_rss &&
5640 			    ((*sample_rss)->level != rss->level ||
5641 			    (*sample_rss)->types != rss->types))
5642 				return rte_flow_error_set(error, ENOTSUP,
5643 					RTE_FLOW_ERROR_TYPE_ACTION,
5644 					NULL,
5645 					"Can't use the different RSS types "
5646 					"or level in the same flow");
5647 			if (*sample_rss != NULL && (*sample_rss)->queue_num)
5648 				queue_index = (*sample_rss)->queue[0];
5649 			sub_action_flags |= MLX5_FLOW_ACTION_RSS;
5650 			++actions_n;
5651 			break;
5652 		case RTE_FLOW_ACTION_TYPE_MARK:
5653 			ret = flow_dv_validate_action_mark(dev, act,
5654 							   sub_action_flags,
5655 							   attr, error);
5656 			if (ret < 0)
5657 				return ret;
5658 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)
5659 				sub_action_flags |= MLX5_FLOW_ACTION_MARK |
5660 						MLX5_FLOW_ACTION_MARK_EXT;
5661 			else
5662 				sub_action_flags |= MLX5_FLOW_ACTION_MARK;
5663 			++actions_n;
5664 			break;
5665 		case RTE_FLOW_ACTION_TYPE_COUNT:
5666 			ret = flow_dv_validate_action_count
5667 				(dev, is_shared_action_count(act),
5668 				 *action_flags | sub_action_flags,
5669 				 error);
5670 			if (ret < 0)
5671 				return ret;
5672 			*count = act->conf;
5673 			sub_action_flags |= MLX5_FLOW_ACTION_COUNT;
5674 			*action_flags |= MLX5_FLOW_ACTION_COUNT;
5675 			++actions_n;
5676 			break;
5677 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
5678 			ret = flow_dv_validate_action_port_id(dev,
5679 							      sub_action_flags,
5680 							      act,
5681 							      attr,
5682 							      error);
5683 			if (ret)
5684 				return ret;
5685 			sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID;
5686 			++actions_n;
5687 			break;
5688 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
5689 			ret = flow_dv_validate_action_raw_encap_decap
5690 				(dev, NULL, act->conf, attr, &sub_action_flags,
5691 				 &actions_n, action, item_flags, error);
5692 			if (ret < 0)
5693 				return ret;
5694 			++actions_n;
5695 			break;
5696 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5697 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
5698 			ret = flow_dv_validate_action_l2_encap(dev,
5699 							       sub_action_flags,
5700 							       act, attr,
5701 							       error);
5702 			if (ret < 0)
5703 				return ret;
5704 			sub_action_flags |= MLX5_FLOW_ACTION_ENCAP;
5705 			++actions_n;
5706 			break;
5707 		default:
5708 			return rte_flow_error_set(error, ENOTSUP,
5709 						  RTE_FLOW_ERROR_TYPE_ACTION,
5710 						  NULL,
5711 						  "Doesn't support optional "
5712 						  "action");
5713 		}
5714 	}
5715 	if (attr->ingress && !attr->transfer) {
5716 		if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE |
5717 					  MLX5_FLOW_ACTION_RSS)))
5718 			return rte_flow_error_set(error, EINVAL,
5719 						  RTE_FLOW_ERROR_TYPE_ACTION,
5720 						  NULL,
5721 						  "Ingress must has a dest "
5722 						  "QUEUE for Sample");
5723 	} else if (attr->egress && !attr->transfer) {
5724 		return rte_flow_error_set(error, ENOTSUP,
5725 					  RTE_FLOW_ERROR_TYPE_ACTION,
5726 					  NULL,
5727 					  "Sample Only support Ingress "
5728 					  "or E-Switch");
5729 	} else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) {
5730 		MLX5_ASSERT(attr->transfer);
5731 		if (sample->ratio > 1)
5732 			return rte_flow_error_set(error, ENOTSUP,
5733 						  RTE_FLOW_ERROR_TYPE_ACTION,
5734 						  NULL,
5735 						  "E-Switch doesn't support "
5736 						  "any optional action "
5737 						  "for sampling");
5738 		if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE)
5739 			return rte_flow_error_set(error, ENOTSUP,
5740 						  RTE_FLOW_ERROR_TYPE_ACTION,
5741 						  NULL,
5742 						  "unsupported action QUEUE");
5743 		if (sub_action_flags & MLX5_FLOW_ACTION_RSS)
5744 			return rte_flow_error_set(error, ENOTSUP,
5745 						  RTE_FLOW_ERROR_TYPE_ACTION,
5746 						  NULL,
5747 						  "unsupported action QUEUE");
5748 		if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID))
5749 			return rte_flow_error_set(error, EINVAL,
5750 						  RTE_FLOW_ERROR_TYPE_ACTION,
5751 						  NULL,
5752 						  "E-Switch must has a dest "
5753 						  "port for mirroring");
5754 		if (!priv->config.hca_attr.reg_c_preserve &&
5755 		     priv->representor_id != UINT16_MAX)
5756 			*fdb_mirror_limit = 1;
5757 	}
5758 	/* Continue validation for Xcap actions.*/
5759 	if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) &&
5760 	    (queue_index == 0xFFFF ||
5761 	     mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) {
5762 		if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
5763 		     MLX5_FLOW_XCAP_ACTIONS)
5764 			return rte_flow_error_set(error, ENOTSUP,
5765 						  RTE_FLOW_ERROR_TYPE_ACTION,
5766 						  NULL, "encap and decap "
5767 						  "combination aren't "
5768 						  "supported");
5769 		if (!attr->transfer && attr->ingress && (sub_action_flags &
5770 							MLX5_FLOW_ACTION_ENCAP))
5771 			return rte_flow_error_set(error, ENOTSUP,
5772 						  RTE_FLOW_ERROR_TYPE_ACTION,
5773 						  NULL, "encap is not supported"
5774 						  " for ingress traffic");
5775 	}
5776 	return 0;
5777 }
5778 
5779 /**
5780  * Find existing modify-header resource or create and register a new one.
5781  *
5782  * @param dev[in, out]
5783  *   Pointer to rte_eth_dev structure.
5784  * @param[in, out] resource
5785  *   Pointer to modify-header resource.
5786  * @parm[in, out] dev_flow
5787  *   Pointer to the dev_flow.
5788  * @param[out] error
5789  *   pointer to error structure.
5790  *
5791  * @return
5792  *   0 on success otherwise -errno and errno is set.
5793  */
5794 static int
5795 flow_dv_modify_hdr_resource_register
5796 			(struct rte_eth_dev *dev,
5797 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
5798 			 struct mlx5_flow *dev_flow,
5799 			 struct rte_flow_error *error)
5800 {
5801 	struct mlx5_priv *priv = dev->data->dev_private;
5802 	struct mlx5_dev_ctx_shared *sh = priv->sh;
5803 	uint32_t key_len = sizeof(*resource) -
5804 			   offsetof(typeof(*resource), ft_type) +
5805 			   resource->actions_num * sizeof(resource->actions[0]);
5806 	struct mlx5_list_entry *entry;
5807 	struct mlx5_flow_cb_ctx ctx = {
5808 		.error = error,
5809 		.data = resource,
5810 	};
5811 	struct mlx5_hlist *modify_cmds;
5812 	uint64_t key64;
5813 
5814 	modify_cmds = flow_dv_hlist_prepare(sh, &sh->modify_cmds,
5815 				"hdr_modify",
5816 				MLX5_FLOW_HDR_MODIFY_HTABLE_SZ,
5817 				true, false, sh,
5818 				flow_dv_modify_create_cb,
5819 				flow_dv_modify_match_cb,
5820 				flow_dv_modify_remove_cb,
5821 				flow_dv_modify_clone_cb,
5822 				flow_dv_modify_clone_free_cb);
5823 	if (unlikely(!modify_cmds))
5824 		return -rte_errno;
5825 	resource->root = !dev_flow->dv.group;
5826 	if (resource->actions_num > flow_dv_modify_hdr_action_max(dev,
5827 								resource->root))
5828 		return rte_flow_error_set(error, EOVERFLOW,
5829 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5830 					  "too many modify header items");
5831 	key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0);
5832 	entry = mlx5_hlist_register(modify_cmds, key64, &ctx);
5833 	if (!entry)
5834 		return -rte_errno;
5835 	resource = container_of(entry, typeof(*resource), entry);
5836 	dev_flow->handle->dvh.modify_hdr = resource;
5837 	return 0;
5838 }
5839 
5840 /**
5841  * Get DV flow counter by index.
5842  *
5843  * @param[in] dev
5844  *   Pointer to the Ethernet device structure.
5845  * @param[in] idx
5846  *   mlx5 flow counter index in the container.
5847  * @param[out] ppool
5848  *   mlx5 flow counter pool in the container.
5849  *
5850  * @return
5851  *   Pointer to the counter, NULL otherwise.
5852  */
5853 static struct mlx5_flow_counter *
5854 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev,
5855 			   uint32_t idx,
5856 			   struct mlx5_flow_counter_pool **ppool)
5857 {
5858 	struct mlx5_priv *priv = dev->data->dev_private;
5859 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5860 	struct mlx5_flow_counter_pool *pool;
5861 
5862 	/* Decrease to original index and clear shared bit. */
5863 	idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
5864 	MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < cmng->n);
5865 	pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
5866 	MLX5_ASSERT(pool);
5867 	if (ppool)
5868 		*ppool = pool;
5869 	return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
5870 }
5871 
5872 /**
5873  * Check the devx counter belongs to the pool.
5874  *
5875  * @param[in] pool
5876  *   Pointer to the counter pool.
5877  * @param[in] id
5878  *   The counter devx ID.
5879  *
5880  * @return
5881  *   True if counter belongs to the pool, false otherwise.
5882  */
5883 static bool
5884 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id)
5885 {
5886 	int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) *
5887 		   MLX5_COUNTERS_PER_POOL;
5888 
5889 	if (id >= base && id < base + MLX5_COUNTERS_PER_POOL)
5890 		return true;
5891 	return false;
5892 }
5893 
5894 /**
5895  * Get a pool by devx counter ID.
5896  *
5897  * @param[in] cmng
5898  *   Pointer to the counter management.
5899  * @param[in] id
5900  *   The counter devx ID.
5901  *
5902  * @return
5903  *   The counter pool pointer if exists, NULL otherwise,
5904  */
5905 static struct mlx5_flow_counter_pool *
5906 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id)
5907 {
5908 	uint32_t i;
5909 	struct mlx5_flow_counter_pool *pool = NULL;
5910 
5911 	rte_spinlock_lock(&cmng->pool_update_sl);
5912 	/* Check last used pool. */
5913 	if (cmng->last_pool_idx != POOL_IDX_INVALID &&
5914 	    flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) {
5915 		pool = cmng->pools[cmng->last_pool_idx];
5916 		goto out;
5917 	}
5918 	/* ID out of range means no suitable pool in the container. */
5919 	if (id > cmng->max_id || id < cmng->min_id)
5920 		goto out;
5921 	/*
5922 	 * Find the pool from the end of the container, since mostly counter
5923 	 * ID is sequence increasing, and the last pool should be the needed
5924 	 * one.
5925 	 */
5926 	i = cmng->n_valid;
5927 	while (i--) {
5928 		struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i];
5929 
5930 		if (flow_dv_is_counter_in_pool(pool_tmp, id)) {
5931 			pool = pool_tmp;
5932 			break;
5933 		}
5934 	}
5935 out:
5936 	rte_spinlock_unlock(&cmng->pool_update_sl);
5937 	return pool;
5938 }
5939 
5940 /**
5941  * Resize a counter container.
5942  *
5943  * @param[in] dev
5944  *   Pointer to the Ethernet device structure.
5945  *
5946  * @return
5947  *   0 on success, otherwise negative errno value and rte_errno is set.
5948  */
5949 static int
5950 flow_dv_container_resize(struct rte_eth_dev *dev)
5951 {
5952 	struct mlx5_priv *priv = dev->data->dev_private;
5953 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5954 	void *old_pools = cmng->pools;
5955 	uint32_t resize = cmng->n + MLX5_CNT_CONTAINER_RESIZE;
5956 	uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize;
5957 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
5958 
5959 	if (!pools) {
5960 		rte_errno = ENOMEM;
5961 		return -ENOMEM;
5962 	}
5963 	if (old_pools)
5964 		memcpy(pools, old_pools, cmng->n *
5965 				       sizeof(struct mlx5_flow_counter_pool *));
5966 	cmng->n = resize;
5967 	cmng->pools = pools;
5968 	if (old_pools)
5969 		mlx5_free(old_pools);
5970 	return 0;
5971 }
5972 
5973 /**
5974  * Query a devx flow counter.
5975  *
5976  * @param[in] dev
5977  *   Pointer to the Ethernet device structure.
5978  * @param[in] counter
5979  *   Index to the flow counter.
5980  * @param[out] pkts
5981  *   The statistics value of packets.
5982  * @param[out] bytes
5983  *   The statistics value of bytes.
5984  *
5985  * @return
5986  *   0 on success, otherwise a negative errno value and rte_errno is set.
5987  */
5988 static inline int
5989 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts,
5990 		     uint64_t *bytes)
5991 {
5992 	struct mlx5_priv *priv = dev->data->dev_private;
5993 	struct mlx5_flow_counter_pool *pool = NULL;
5994 	struct mlx5_flow_counter *cnt;
5995 	int offset;
5996 
5997 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
5998 	MLX5_ASSERT(pool);
5999 	if (priv->sh->cmng.counter_fallback)
6000 		return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0,
6001 					0, pkts, bytes, 0, NULL, NULL, 0);
6002 	rte_spinlock_lock(&pool->sl);
6003 	if (!pool->raw) {
6004 		*pkts = 0;
6005 		*bytes = 0;
6006 	} else {
6007 		offset = MLX5_CNT_ARRAY_IDX(pool, cnt);
6008 		*pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits);
6009 		*bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes);
6010 	}
6011 	rte_spinlock_unlock(&pool->sl);
6012 	return 0;
6013 }
6014 
6015 /**
6016  * Create and initialize a new counter pool.
6017  *
6018  * @param[in] dev
6019  *   Pointer to the Ethernet device structure.
6020  * @param[out] dcs
6021  *   The devX counter handle.
6022  * @param[in] age
6023  *   Whether the pool is for counter that was allocated for aging.
6024  * @param[in/out] cont_cur
6025  *   Pointer to the container pointer, it will be update in pool resize.
6026  *
6027  * @return
6028  *   The pool container pointer on success, NULL otherwise and rte_errno is set.
6029  */
6030 static struct mlx5_flow_counter_pool *
6031 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
6032 		    uint32_t age)
6033 {
6034 	struct mlx5_priv *priv = dev->data->dev_private;
6035 	struct mlx5_flow_counter_pool *pool;
6036 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6037 	bool fallback = priv->sh->cmng.counter_fallback;
6038 	uint32_t size = sizeof(*pool);
6039 
6040 	size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE;
6041 	size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE);
6042 	pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
6043 	if (!pool) {
6044 		rte_errno = ENOMEM;
6045 		return NULL;
6046 	}
6047 	pool->raw = NULL;
6048 	pool->is_aged = !!age;
6049 	pool->query_gen = 0;
6050 	pool->min_dcs = dcs;
6051 	rte_spinlock_init(&pool->sl);
6052 	rte_spinlock_init(&pool->csl);
6053 	TAILQ_INIT(&pool->counters[0]);
6054 	TAILQ_INIT(&pool->counters[1]);
6055 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
6056 	rte_spinlock_lock(&cmng->pool_update_sl);
6057 	pool->index = cmng->n_valid;
6058 	if (pool->index == cmng->n && flow_dv_container_resize(dev)) {
6059 		mlx5_free(pool);
6060 		rte_spinlock_unlock(&cmng->pool_update_sl);
6061 		return NULL;
6062 	}
6063 	cmng->pools[pool->index] = pool;
6064 	cmng->n_valid++;
6065 	if (unlikely(fallback)) {
6066 		int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL);
6067 
6068 		if (base < cmng->min_id)
6069 			cmng->min_id = base;
6070 		if (base > cmng->max_id)
6071 			cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1;
6072 		cmng->last_pool_idx = pool->index;
6073 	}
6074 	rte_spinlock_unlock(&cmng->pool_update_sl);
6075 	return pool;
6076 }
6077 
6078 /**
6079  * Prepare a new counter and/or a new counter pool.
6080  *
6081  * @param[in] dev
6082  *   Pointer to the Ethernet device structure.
6083  * @param[out] cnt_free
6084  *   Where to put the pointer of a new counter.
6085  * @param[in] age
6086  *   Whether the pool is for counter that was allocated for aging.
6087  *
6088  * @return
6089  *   The counter pool pointer and @p cnt_free is set on success,
6090  *   NULL otherwise and rte_errno is set.
6091  */
6092 static struct mlx5_flow_counter_pool *
6093 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev,
6094 			     struct mlx5_flow_counter **cnt_free,
6095 			     uint32_t age)
6096 {
6097 	struct mlx5_priv *priv = dev->data->dev_private;
6098 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6099 	struct mlx5_flow_counter_pool *pool;
6100 	struct mlx5_counters tmp_tq;
6101 	struct mlx5_devx_obj *dcs = NULL;
6102 	struct mlx5_flow_counter *cnt;
6103 	enum mlx5_counter_type cnt_type =
6104 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6105 	bool fallback = priv->sh->cmng.counter_fallback;
6106 	uint32_t i;
6107 
6108 	if (fallback) {
6109 		/* bulk_bitmap must be 0 for single counter allocation. */
6110 		dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
6111 		if (!dcs)
6112 			return NULL;
6113 		pool = flow_dv_find_pool_by_id(cmng, dcs->id);
6114 		if (!pool) {
6115 			pool = flow_dv_pool_create(dev, dcs, age);
6116 			if (!pool) {
6117 				mlx5_devx_cmd_destroy(dcs);
6118 				return NULL;
6119 			}
6120 		}
6121 		i = dcs->id % MLX5_COUNTERS_PER_POOL;
6122 		cnt = MLX5_POOL_GET_CNT(pool, i);
6123 		cnt->pool = pool;
6124 		cnt->dcs_when_free = dcs;
6125 		*cnt_free = cnt;
6126 		return pool;
6127 	}
6128 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4);
6129 	if (!dcs) {
6130 		rte_errno = ENODATA;
6131 		return NULL;
6132 	}
6133 	pool = flow_dv_pool_create(dev, dcs, age);
6134 	if (!pool) {
6135 		mlx5_devx_cmd_destroy(dcs);
6136 		return NULL;
6137 	}
6138 	TAILQ_INIT(&tmp_tq);
6139 	for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) {
6140 		cnt = MLX5_POOL_GET_CNT(pool, i);
6141 		cnt->pool = pool;
6142 		TAILQ_INSERT_HEAD(&tmp_tq, cnt, next);
6143 	}
6144 	rte_spinlock_lock(&cmng->csl[cnt_type]);
6145 	TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next);
6146 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
6147 	*cnt_free = MLX5_POOL_GET_CNT(pool, 0);
6148 	(*cnt_free)->pool = pool;
6149 	return pool;
6150 }
6151 
6152 /**
6153  * Allocate a flow counter.
6154  *
6155  * @param[in] dev
6156  *   Pointer to the Ethernet device structure.
6157  * @param[in] age
6158  *   Whether the counter was allocated for aging.
6159  *
6160  * @return
6161  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
6162  */
6163 static uint32_t
6164 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age)
6165 {
6166 	struct mlx5_priv *priv = dev->data->dev_private;
6167 	struct mlx5_flow_counter_pool *pool = NULL;
6168 	struct mlx5_flow_counter *cnt_free = NULL;
6169 	bool fallback = priv->sh->cmng.counter_fallback;
6170 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6171 	enum mlx5_counter_type cnt_type =
6172 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6173 	uint32_t cnt_idx;
6174 
6175 	if (!priv->config.devx) {
6176 		rte_errno = ENOTSUP;
6177 		return 0;
6178 	}
6179 	/* Get free counters from container. */
6180 	rte_spinlock_lock(&cmng->csl[cnt_type]);
6181 	cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]);
6182 	if (cnt_free)
6183 		TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next);
6184 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
6185 	if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age))
6186 		goto err;
6187 	pool = cnt_free->pool;
6188 	if (fallback)
6189 		cnt_free->dcs_when_active = cnt_free->dcs_when_free;
6190 	/* Create a DV counter action only in the first time usage. */
6191 	if (!cnt_free->action) {
6192 		uint16_t offset;
6193 		struct mlx5_devx_obj *dcs;
6194 		int ret;
6195 
6196 		if (!fallback) {
6197 			offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free);
6198 			dcs = pool->min_dcs;
6199 		} else {
6200 			offset = 0;
6201 			dcs = cnt_free->dcs_when_free;
6202 		}
6203 		ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset,
6204 							    &cnt_free->action);
6205 		if (ret) {
6206 			rte_errno = errno;
6207 			goto err;
6208 		}
6209 	}
6210 	cnt_idx = MLX5_MAKE_CNT_IDX(pool->index,
6211 				MLX5_CNT_ARRAY_IDX(pool, cnt_free));
6212 	/* Update the counter reset values. */
6213 	if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits,
6214 				 &cnt_free->bytes))
6215 		goto err;
6216 	if (!fallback && !priv->sh->cmng.query_thread_on)
6217 		/* Start the asynchronous batch query by the host thread. */
6218 		mlx5_set_query_alarm(priv->sh);
6219 	/*
6220 	 * When the count action isn't shared (by ID), shared_info field is
6221 	 * used for indirect action API's refcnt.
6222 	 * When the counter action is not shared neither by ID nor by indirect
6223 	 * action API, shared info must be 1.
6224 	 */
6225 	cnt_free->shared_info.refcnt = 1;
6226 	return cnt_idx;
6227 err:
6228 	if (cnt_free) {
6229 		cnt_free->pool = pool;
6230 		if (fallback)
6231 			cnt_free->dcs_when_free = cnt_free->dcs_when_active;
6232 		rte_spinlock_lock(&cmng->csl[cnt_type]);
6233 		TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next);
6234 		rte_spinlock_unlock(&cmng->csl[cnt_type]);
6235 	}
6236 	return 0;
6237 }
6238 
6239 /**
6240  * Allocate a shared flow counter.
6241  *
6242  * @param[in] ctx
6243  *   Pointer to the shared counter configuration.
6244  * @param[in] data
6245  *   Pointer to save the allocated counter index.
6246  *
6247  * @return
6248  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
6249  */
6250 
6251 static int32_t
6252 flow_dv_counter_alloc_shared_cb(void *ctx, union mlx5_l3t_data *data)
6253 {
6254 	struct mlx5_shared_counter_conf *conf = ctx;
6255 	struct rte_eth_dev *dev = conf->dev;
6256 	struct mlx5_flow_counter *cnt;
6257 
6258 	data->dword = flow_dv_counter_alloc(dev, 0);
6259 	data->dword |= MLX5_CNT_SHARED_OFFSET;
6260 	cnt = flow_dv_counter_get_by_idx(dev, data->dword, NULL);
6261 	cnt->shared_info.id = conf->id;
6262 	return 0;
6263 }
6264 
6265 /**
6266  * Get a shared flow counter.
6267  *
6268  * @param[in] dev
6269  *   Pointer to the Ethernet device structure.
6270  * @param[in] id
6271  *   Counter identifier.
6272  *
6273  * @return
6274  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
6275  */
6276 static uint32_t
6277 flow_dv_counter_get_shared(struct rte_eth_dev *dev, uint32_t id)
6278 {
6279 	struct mlx5_priv *priv = dev->data->dev_private;
6280 	struct mlx5_shared_counter_conf conf = {
6281 		.dev = dev,
6282 		.id = id,
6283 	};
6284 	union mlx5_l3t_data data = {
6285 		.dword = 0,
6286 	};
6287 
6288 	mlx5_l3t_prepare_entry(priv->sh->cnt_id_tbl, id, &data,
6289 			       flow_dv_counter_alloc_shared_cb, &conf);
6290 	return data.dword;
6291 }
6292 
6293 /**
6294  * Get age param from counter index.
6295  *
6296  * @param[in] dev
6297  *   Pointer to the Ethernet device structure.
6298  * @param[in] counter
6299  *   Index to the counter handler.
6300  *
6301  * @return
6302  *   The aging parameter specified for the counter index.
6303  */
6304 static struct mlx5_age_param*
6305 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev,
6306 				uint32_t counter)
6307 {
6308 	struct mlx5_flow_counter *cnt;
6309 	struct mlx5_flow_counter_pool *pool = NULL;
6310 
6311 	flow_dv_counter_get_by_idx(dev, counter, &pool);
6312 	counter = (counter - 1) % MLX5_COUNTERS_PER_POOL;
6313 	cnt = MLX5_POOL_GET_CNT(pool, counter);
6314 	return MLX5_CNT_TO_AGE(cnt);
6315 }
6316 
6317 /**
6318  * Remove a flow counter from aged counter list.
6319  *
6320  * @param[in] dev
6321  *   Pointer to the Ethernet device structure.
6322  * @param[in] counter
6323  *   Index to the counter handler.
6324  * @param[in] cnt
6325  *   Pointer to the counter handler.
6326  */
6327 static void
6328 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev,
6329 				uint32_t counter, struct mlx5_flow_counter *cnt)
6330 {
6331 	struct mlx5_age_info *age_info;
6332 	struct mlx5_age_param *age_param;
6333 	struct mlx5_priv *priv = dev->data->dev_private;
6334 	uint16_t expected = AGE_CANDIDATE;
6335 
6336 	age_info = GET_PORT_AGE_INFO(priv);
6337 	age_param = flow_dv_counter_idx_get_age(dev, counter);
6338 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
6339 					 AGE_FREE, false, __ATOMIC_RELAXED,
6340 					 __ATOMIC_RELAXED)) {
6341 		/**
6342 		 * We need the lock even it is age timeout,
6343 		 * since counter may still in process.
6344 		 */
6345 		rte_spinlock_lock(&age_info->aged_sl);
6346 		TAILQ_REMOVE(&age_info->aged_counters, cnt, next);
6347 		rte_spinlock_unlock(&age_info->aged_sl);
6348 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
6349 	}
6350 }
6351 
6352 /**
6353  * Release a flow counter.
6354  *
6355  * @param[in] dev
6356  *   Pointer to the Ethernet device structure.
6357  * @param[in] counter
6358  *   Index to the counter handler.
6359  */
6360 static void
6361 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter)
6362 {
6363 	struct mlx5_priv *priv = dev->data->dev_private;
6364 	struct mlx5_flow_counter_pool *pool = NULL;
6365 	struct mlx5_flow_counter *cnt;
6366 	enum mlx5_counter_type cnt_type;
6367 
6368 	if (!counter)
6369 		return;
6370 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
6371 	MLX5_ASSERT(pool);
6372 	if (pool->is_aged) {
6373 		flow_dv_counter_remove_from_age(dev, counter, cnt);
6374 	} else {
6375 		/*
6376 		 * If the counter action is shared by ID, the l3t_clear_entry
6377 		 * function reduces its references counter. If after the
6378 		 * reduction the action is still referenced, the function
6379 		 * returns here and does not release it.
6380 		 */
6381 		if (IS_LEGACY_SHARED_CNT(counter) &&
6382 		    mlx5_l3t_clear_entry(priv->sh->cnt_id_tbl,
6383 					 cnt->shared_info.id))
6384 			return;
6385 		/*
6386 		 * If the counter action is shared by indirect action API,
6387 		 * the atomic function reduces its references counter.
6388 		 * If after the reduction the action is still referenced, the
6389 		 * function returns here and does not release it.
6390 		 * When the counter action is not shared neither by ID nor by
6391 		 * indirect action API, shared info is 1 before the reduction,
6392 		 * so this condition is failed and function doesn't return here.
6393 		 */
6394 		if (!IS_LEGACY_SHARED_CNT(counter) &&
6395 		    __atomic_sub_fetch(&cnt->shared_info.refcnt, 1,
6396 				       __ATOMIC_RELAXED))
6397 			return;
6398 	}
6399 	cnt->pool = pool;
6400 	/*
6401 	 * Put the counter back to list to be updated in none fallback mode.
6402 	 * Currently, we are using two list alternately, while one is in query,
6403 	 * add the freed counter to the other list based on the pool query_gen
6404 	 * value. After query finishes, add counter the list to the global
6405 	 * container counter list. The list changes while query starts. In
6406 	 * this case, lock will not be needed as query callback and release
6407 	 * function both operate with the different list.
6408 	 */
6409 	if (!priv->sh->cmng.counter_fallback) {
6410 		rte_spinlock_lock(&pool->csl);
6411 		TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next);
6412 		rte_spinlock_unlock(&pool->csl);
6413 	} else {
6414 		cnt->dcs_when_free = cnt->dcs_when_active;
6415 		cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE :
6416 					   MLX5_COUNTER_TYPE_ORIGIN;
6417 		rte_spinlock_lock(&priv->sh->cmng.csl[cnt_type]);
6418 		TAILQ_INSERT_TAIL(&priv->sh->cmng.counters[cnt_type],
6419 				  cnt, next);
6420 		rte_spinlock_unlock(&priv->sh->cmng.csl[cnt_type]);
6421 	}
6422 }
6423 
6424 /**
6425  * Resize a meter id container.
6426  *
6427  * @param[in] dev
6428  *   Pointer to the Ethernet device structure.
6429  *
6430  * @return
6431  *   0 on success, otherwise negative errno value and rte_errno is set.
6432  */
6433 static int
6434 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
6435 {
6436 	struct mlx5_priv *priv = dev->data->dev_private;
6437 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6438 				&priv->sh->mtrmng->pools_mng;
6439 	void *old_pools = pools_mng->pools;
6440 	uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
6441 	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
6442 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
6443 
6444 	if (!pools) {
6445 		rte_errno = ENOMEM;
6446 		return -ENOMEM;
6447 	}
6448 	if (!pools_mng->n)
6449 		if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {
6450 			mlx5_free(pools);
6451 			return -ENOMEM;
6452 		}
6453 	if (old_pools)
6454 		memcpy(pools, old_pools, pools_mng->n *
6455 				       sizeof(struct mlx5_aso_mtr_pool *));
6456 	pools_mng->n = resize;
6457 	pools_mng->pools = pools;
6458 	if (old_pools)
6459 		mlx5_free(old_pools);
6460 	return 0;
6461 }
6462 
6463 /**
6464  * Prepare a new meter and/or a new meter pool.
6465  *
6466  * @param[in] dev
6467  *   Pointer to the Ethernet device structure.
6468  * @param[out] mtr_free
6469  *   Where to put the pointer of a new meter.g.
6470  *
6471  * @return
6472  *   The meter pool pointer and @mtr_free is set on success,
6473  *   NULL otherwise and rte_errno is set.
6474  */
6475 static struct mlx5_aso_mtr_pool *
6476 flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
6477 			     struct mlx5_aso_mtr **mtr_free)
6478 {
6479 	struct mlx5_priv *priv = dev->data->dev_private;
6480 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6481 				&priv->sh->mtrmng->pools_mng;
6482 	struct mlx5_aso_mtr_pool *pool = NULL;
6483 	struct mlx5_devx_obj *dcs = NULL;
6484 	uint32_t i;
6485 	uint32_t log_obj_size;
6486 
6487 	log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1);
6488 	dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->ctx,
6489 			priv->sh->pdn, log_obj_size);
6490 	if (!dcs) {
6491 		rte_errno = ENODATA;
6492 		return NULL;
6493 	}
6494 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
6495 	if (!pool) {
6496 		rte_errno = ENOMEM;
6497 		claim_zero(mlx5_devx_cmd_destroy(dcs));
6498 		return NULL;
6499 	}
6500 	pool->devx_obj = dcs;
6501 	pool->index = pools_mng->n_valid;
6502 	if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
6503 		mlx5_free(pool);
6504 		claim_zero(mlx5_devx_cmd_destroy(dcs));
6505 		return NULL;
6506 	}
6507 	pools_mng->pools[pool->index] = pool;
6508 	pools_mng->n_valid++;
6509 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
6510 		pool->mtrs[i].offset = i;
6511 		LIST_INSERT_HEAD(&pools_mng->meters,
6512 						&pool->mtrs[i], next);
6513 	}
6514 	pool->mtrs[0].offset = 0;
6515 	*mtr_free = &pool->mtrs[0];
6516 	return pool;
6517 }
6518 
6519 /**
6520  * Release a flow meter into pool.
6521  *
6522  * @param[in] dev
6523  *   Pointer to the Ethernet device structure.
6524  * @param[in] mtr_idx
6525  *   Index to aso flow meter.
6526  */
6527 static void
6528 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
6529 {
6530 	struct mlx5_priv *priv = dev->data->dev_private;
6531 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6532 				&priv->sh->mtrmng->pools_mng;
6533 	struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
6534 
6535 	MLX5_ASSERT(aso_mtr);
6536 	rte_spinlock_lock(&pools_mng->mtrsl);
6537 	memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
6538 	aso_mtr->state = ASO_METER_FREE;
6539 	LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
6540 	rte_spinlock_unlock(&pools_mng->mtrsl);
6541 }
6542 
6543 /**
6544  * Allocate a aso flow meter.
6545  *
6546  * @param[in] dev
6547  *   Pointer to the Ethernet device structure.
6548  *
6549  * @return
6550  *   Index to aso flow meter on success, 0 otherwise and rte_errno is set.
6551  */
6552 static uint32_t
6553 flow_dv_mtr_alloc(struct rte_eth_dev *dev)
6554 {
6555 	struct mlx5_priv *priv = dev->data->dev_private;
6556 	struct mlx5_aso_mtr *mtr_free = NULL;
6557 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6558 				&priv->sh->mtrmng->pools_mng;
6559 	struct mlx5_aso_mtr_pool *pool;
6560 	uint32_t mtr_idx = 0;
6561 
6562 	if (!priv->config.devx) {
6563 		rte_errno = ENOTSUP;
6564 		return 0;
6565 	}
6566 	/* Allocate the flow meter memory. */
6567 	/* Get free meters from management. */
6568 	rte_spinlock_lock(&pools_mng->mtrsl);
6569 	mtr_free = LIST_FIRST(&pools_mng->meters);
6570 	if (mtr_free)
6571 		LIST_REMOVE(mtr_free, next);
6572 	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
6573 		rte_spinlock_unlock(&pools_mng->mtrsl);
6574 		return 0;
6575 	}
6576 	mtr_free->state = ASO_METER_WAIT;
6577 	rte_spinlock_unlock(&pools_mng->mtrsl);
6578 	pool = container_of(mtr_free,
6579 			struct mlx5_aso_mtr_pool,
6580 			mtrs[mtr_free->offset]);
6581 	mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
6582 	if (!mtr_free->fm.meter_action) {
6583 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
6584 		struct rte_flow_error error;
6585 		uint8_t reg_id;
6586 
6587 		reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error);
6588 		mtr_free->fm.meter_action =
6589 			mlx5_glue->dv_create_flow_action_aso
6590 						(priv->sh->rx_domain,
6591 						 pool->devx_obj->obj,
6592 						 mtr_free->offset,
6593 						 (1 << MLX5_FLOW_COLOR_GREEN),
6594 						 reg_id - REG_C_0);
6595 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
6596 		if (!mtr_free->fm.meter_action) {
6597 			flow_dv_aso_mtr_release_to_pool(dev, mtr_idx);
6598 			return 0;
6599 		}
6600 	}
6601 	return mtr_idx;
6602 }
6603 
6604 /**
6605  * Verify the @p attributes will be correctly understood by the NIC and store
6606  * them in the @p flow if everything is correct.
6607  *
6608  * @param[in] dev
6609  *   Pointer to dev struct.
6610  * @param[in] attributes
6611  *   Pointer to flow attributes
6612  * @param[in] external
6613  *   This flow rule is created by request external to PMD.
6614  * @param[out] error
6615  *   Pointer to error structure.
6616  *
6617  * @return
6618  *   - 0 on success and non root table.
6619  *   - 1 on success and root table.
6620  *   - a negative errno value otherwise and rte_errno is set.
6621  */
6622 static int
6623 flow_dv_validate_attributes(struct rte_eth_dev *dev,
6624 			    const struct mlx5_flow_tunnel *tunnel,
6625 			    const struct rte_flow_attr *attributes,
6626 			    const struct flow_grp_info *grp_info,
6627 			    struct rte_flow_error *error)
6628 {
6629 	struct mlx5_priv *priv = dev->data->dev_private;
6630 	uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes);
6631 	int ret = 0;
6632 
6633 #ifndef HAVE_MLX5DV_DR
6634 	RTE_SET_USED(tunnel);
6635 	RTE_SET_USED(grp_info);
6636 	if (attributes->group)
6637 		return rte_flow_error_set(error, ENOTSUP,
6638 					  RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
6639 					  NULL,
6640 					  "groups are not supported");
6641 #else
6642 	uint32_t table = 0;
6643 
6644 	ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table,
6645 				       grp_info, error);
6646 	if (ret)
6647 		return ret;
6648 	if (!table)
6649 		ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
6650 #endif
6651 	if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR &&
6652 	    attributes->priority > lowest_priority)
6653 		return rte_flow_error_set(error, ENOTSUP,
6654 					  RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
6655 					  NULL,
6656 					  "priority out of range");
6657 	if (attributes->transfer) {
6658 		if (!priv->config.dv_esw_en)
6659 			return rte_flow_error_set
6660 				(error, ENOTSUP,
6661 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
6662 				 "E-Switch dr is not supported");
6663 		if (!(priv->representor || priv->master))
6664 			return rte_flow_error_set
6665 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6666 				 NULL, "E-Switch configuration can only be"
6667 				 " done by a master or a representor device");
6668 		if (attributes->egress)
6669 			return rte_flow_error_set
6670 				(error, ENOTSUP,
6671 				 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes,
6672 				 "egress is not supported");
6673 	}
6674 	if (!(attributes->egress ^ attributes->ingress))
6675 		return rte_flow_error_set(error, ENOTSUP,
6676 					  RTE_FLOW_ERROR_TYPE_ATTR, NULL,
6677 					  "must specify exactly one of "
6678 					  "ingress or egress");
6679 	return ret;
6680 }
6681 
6682 static uint16_t
6683 mlx5_flow_locate_proto_l3(const struct rte_flow_item **head,
6684 			  const struct rte_flow_item *end)
6685 {
6686 	const struct rte_flow_item *item = *head;
6687 	uint16_t l3_protocol;
6688 
6689 	for (; item != end; item++) {
6690 		switch (item->type) {
6691 		default:
6692 			break;
6693 		case RTE_FLOW_ITEM_TYPE_IPV4:
6694 			l3_protocol = RTE_ETHER_TYPE_IPV4;
6695 			goto l3_ok;
6696 		case RTE_FLOW_ITEM_TYPE_IPV6:
6697 			l3_protocol = RTE_ETHER_TYPE_IPV6;
6698 			goto l3_ok;
6699 		case RTE_FLOW_ITEM_TYPE_ETH:
6700 			if (item->mask && item->spec) {
6701 				MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_eth,
6702 							    type, item,
6703 							    l3_protocol);
6704 				if (l3_protocol == RTE_ETHER_TYPE_IPV4 ||
6705 				    l3_protocol == RTE_ETHER_TYPE_IPV6)
6706 					goto l3_ok;
6707 			}
6708 			break;
6709 		case RTE_FLOW_ITEM_TYPE_VLAN:
6710 			if (item->mask && item->spec) {
6711 				MLX5_ETHER_TYPE_FROM_HEADER(rte_flow_item_vlan,
6712 							    inner_type, item,
6713 							    l3_protocol);
6714 				if (l3_protocol == RTE_ETHER_TYPE_IPV4 ||
6715 				    l3_protocol == RTE_ETHER_TYPE_IPV6)
6716 					goto l3_ok;
6717 			}
6718 			break;
6719 		}
6720 	}
6721 	return 0;
6722 l3_ok:
6723 	*head = item;
6724 	return l3_protocol;
6725 }
6726 
6727 static uint8_t
6728 mlx5_flow_locate_proto_l4(const struct rte_flow_item **head,
6729 			  const struct rte_flow_item *end)
6730 {
6731 	const struct rte_flow_item *item = *head;
6732 	uint8_t l4_protocol;
6733 
6734 	for (; item != end; item++) {
6735 		switch (item->type) {
6736 		default:
6737 			break;
6738 		case RTE_FLOW_ITEM_TYPE_TCP:
6739 			l4_protocol = IPPROTO_TCP;
6740 			goto l4_ok;
6741 		case RTE_FLOW_ITEM_TYPE_UDP:
6742 			l4_protocol = IPPROTO_UDP;
6743 			goto l4_ok;
6744 		case RTE_FLOW_ITEM_TYPE_IPV4:
6745 			if (item->mask && item->spec) {
6746 				const struct rte_flow_item_ipv4 *mask, *spec;
6747 
6748 				mask = (typeof(mask))item->mask;
6749 				spec = (typeof(spec))item->spec;
6750 				l4_protocol = mask->hdr.next_proto_id &
6751 					      spec->hdr.next_proto_id;
6752 				if (l4_protocol == IPPROTO_TCP ||
6753 				    l4_protocol == IPPROTO_UDP)
6754 					goto l4_ok;
6755 			}
6756 			break;
6757 		case RTE_FLOW_ITEM_TYPE_IPV6:
6758 			if (item->mask && item->spec) {
6759 				const struct rte_flow_item_ipv6 *mask, *spec;
6760 				mask = (typeof(mask))item->mask;
6761 				spec = (typeof(spec))item->spec;
6762 				l4_protocol = mask->hdr.proto & spec->hdr.proto;
6763 				if (l4_protocol == IPPROTO_TCP ||
6764 				    l4_protocol == IPPROTO_UDP)
6765 					goto l4_ok;
6766 			}
6767 			break;
6768 		}
6769 	}
6770 	return 0;
6771 l4_ok:
6772 	*head = item;
6773 	return l4_protocol;
6774 }
6775 
6776 static int
6777 flow_dv_validate_item_integrity(struct rte_eth_dev *dev,
6778 				const struct rte_flow_item *rule_items,
6779 				const struct rte_flow_item *integrity_item,
6780 				struct rte_flow_error *error)
6781 {
6782 	struct mlx5_priv *priv = dev->data->dev_private;
6783 	const struct rte_flow_item *tunnel_item, *end_item, *item = rule_items;
6784 	const struct rte_flow_item_integrity *mask = (typeof(mask))
6785 						     integrity_item->mask;
6786 	const struct rte_flow_item_integrity *spec = (typeof(spec))
6787 						     integrity_item->spec;
6788 	uint32_t protocol;
6789 
6790 	if (!priv->config.hca_attr.pkt_integrity_match)
6791 		return rte_flow_error_set(error, ENOTSUP,
6792 					  RTE_FLOW_ERROR_TYPE_ITEM,
6793 					  integrity_item,
6794 					  "packet integrity integrity_item not supported");
6795 	if (!mask)
6796 		mask = &rte_flow_item_integrity_mask;
6797 	if (!mlx5_validate_integrity_item(mask))
6798 		return rte_flow_error_set(error, ENOTSUP,
6799 					  RTE_FLOW_ERROR_TYPE_ITEM,
6800 					  integrity_item,
6801 					  "unsupported integrity filter");
6802 	tunnel_item = mlx5_flow_find_tunnel_item(rule_items);
6803 	if (spec->level > 1) {
6804 		if (!tunnel_item)
6805 			return rte_flow_error_set(error, ENOTSUP,
6806 						  RTE_FLOW_ERROR_TYPE_ITEM,
6807 						  integrity_item,
6808 						  "missing tunnel item");
6809 		item = tunnel_item;
6810 		end_item = mlx5_find_end_item(tunnel_item);
6811 	} else {
6812 		end_item = tunnel_item ? tunnel_item :
6813 			   mlx5_find_end_item(integrity_item);
6814 	}
6815 	if (mask->l3_ok || mask->ipv4_csum_ok) {
6816 		protocol = mlx5_flow_locate_proto_l3(&item, end_item);
6817 		if (!protocol)
6818 			return rte_flow_error_set(error, EINVAL,
6819 						  RTE_FLOW_ERROR_TYPE_ITEM,
6820 						  integrity_item,
6821 						  "missing L3 protocol");
6822 	}
6823 	if (mask->l4_ok || mask->l4_csum_ok) {
6824 		protocol = mlx5_flow_locate_proto_l4(&item, end_item);
6825 		if (!protocol)
6826 			return rte_flow_error_set(error, EINVAL,
6827 						  RTE_FLOW_ERROR_TYPE_ITEM,
6828 						  integrity_item,
6829 						  "missing L4 protocol");
6830 	}
6831 	return 0;
6832 }
6833 
6834 /**
6835  * Internal validation function. For validating both actions and items.
6836  *
6837  * @param[in] dev
6838  *   Pointer to the rte_eth_dev structure.
6839  * @param[in] attr
6840  *   Pointer to the flow attributes.
6841  * @param[in] items
6842  *   Pointer to the list of items.
6843  * @param[in] actions
6844  *   Pointer to the list of actions.
6845  * @param[in] external
6846  *   This flow rule is created by request external to PMD.
6847  * @param[in] hairpin
6848  *   Number of hairpin TX actions, 0 means classic flow.
6849  * @param[out] error
6850  *   Pointer to the error structure.
6851  *
6852  * @return
6853  *   0 on success, a negative errno value otherwise and rte_errno is set.
6854  */
6855 static int
6856 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
6857 		 const struct rte_flow_item items[],
6858 		 const struct rte_flow_action actions[],
6859 		 bool external, int hairpin, struct rte_flow_error *error)
6860 {
6861 	int ret;
6862 	uint64_t action_flags = 0;
6863 	uint64_t item_flags = 0;
6864 	uint64_t last_item = 0;
6865 	uint8_t next_protocol = 0xff;
6866 	uint16_t ether_type = 0;
6867 	int actions_n = 0;
6868 	uint8_t item_ipv6_proto = 0;
6869 	int fdb_mirror_limit = 0;
6870 	int modify_after_mirror = 0;
6871 	const struct rte_flow_item *geneve_item = NULL;
6872 	const struct rte_flow_item *gre_item = NULL;
6873 	const struct rte_flow_item *gtp_item = NULL;
6874 	const struct rte_flow_action_raw_decap *decap;
6875 	const struct rte_flow_action_raw_encap *encap;
6876 	const struct rte_flow_action_rss *rss = NULL;
6877 	const struct rte_flow_action_rss *sample_rss = NULL;
6878 	const struct rte_flow_action_count *sample_count = NULL;
6879 	const struct rte_flow_item_tcp nic_tcp_mask = {
6880 		.hdr = {
6881 			.tcp_flags = 0xFF,
6882 			.src_port = RTE_BE16(UINT16_MAX),
6883 			.dst_port = RTE_BE16(UINT16_MAX),
6884 		}
6885 	};
6886 	const struct rte_flow_item_ipv6 nic_ipv6_mask = {
6887 		.hdr = {
6888 			.src_addr =
6889 			"\xff\xff\xff\xff\xff\xff\xff\xff"
6890 			"\xff\xff\xff\xff\xff\xff\xff\xff",
6891 			.dst_addr =
6892 			"\xff\xff\xff\xff\xff\xff\xff\xff"
6893 			"\xff\xff\xff\xff\xff\xff\xff\xff",
6894 			.vtc_flow = RTE_BE32(0xffffffff),
6895 			.proto = 0xff,
6896 			.hop_limits = 0xff,
6897 		},
6898 		.has_frag_ext = 1,
6899 	};
6900 	const struct rte_flow_item_ecpri nic_ecpri_mask = {
6901 		.hdr = {
6902 			.common = {
6903 				.u32 =
6904 				RTE_BE32(((const struct rte_ecpri_common_hdr) {
6905 					.type = 0xFF,
6906 					}).u32),
6907 			},
6908 			.dummy[0] = 0xffffffff,
6909 		},
6910 	};
6911 	struct mlx5_priv *priv = dev->data->dev_private;
6912 	struct mlx5_dev_config *dev_conf = &priv->config;
6913 	uint16_t queue_index = 0xFFFF;
6914 	const struct rte_flow_item_vlan *vlan_m = NULL;
6915 	uint32_t rw_act_num = 0;
6916 	uint64_t is_root;
6917 	const struct mlx5_flow_tunnel *tunnel;
6918 	enum mlx5_tof_rule_type tof_rule_type;
6919 	struct flow_grp_info grp_info = {
6920 		.external = !!external,
6921 		.transfer = !!attr->transfer,
6922 		.fdb_def_rule = !!priv->fdb_def_rule,
6923 		.std_tbl_fix = true,
6924 	};
6925 	const struct rte_eth_hairpin_conf *conf;
6926 	const struct rte_flow_item *rule_items = items;
6927 	const struct rte_flow_item *port_id_item = NULL;
6928 	bool def_policy = false;
6929 	uint16_t udp_dport = 0;
6930 
6931 	if (items == NULL)
6932 		return -1;
6933 	tunnel = is_tunnel_offload_active(dev) ?
6934 		 mlx5_get_tof(items, actions, &tof_rule_type) : NULL;
6935 	if (tunnel) {
6936 		if (priv->representor)
6937 			return rte_flow_error_set
6938 				(error, ENOTSUP,
6939 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6940 				 NULL, "decap not supported for VF representor");
6941 		if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE)
6942 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
6943 		else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE)
6944 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH |
6945 					MLX5_FLOW_ACTION_DECAP;
6946 		grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
6947 					(dev, attr, tunnel, tof_rule_type);
6948 	}
6949 	ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error);
6950 	if (ret < 0)
6951 		return ret;
6952 	is_root = (uint64_t)ret;
6953 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
6954 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
6955 		int type = items->type;
6956 
6957 		if (!mlx5_flow_os_item_supported(type))
6958 			return rte_flow_error_set(error, ENOTSUP,
6959 						  RTE_FLOW_ERROR_TYPE_ITEM,
6960 						  NULL, "item not supported");
6961 		switch (type) {
6962 		case RTE_FLOW_ITEM_TYPE_VOID:
6963 			break;
6964 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
6965 			ret = flow_dv_validate_item_port_id
6966 					(dev, items, attr, item_flags, error);
6967 			if (ret < 0)
6968 				return ret;
6969 			last_item = MLX5_FLOW_ITEM_PORT_ID;
6970 			port_id_item = items;
6971 			break;
6972 		case RTE_FLOW_ITEM_TYPE_ETH:
6973 			ret = mlx5_flow_validate_item_eth(items, item_flags,
6974 							  true, error);
6975 			if (ret < 0)
6976 				return ret;
6977 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
6978 					     MLX5_FLOW_LAYER_OUTER_L2;
6979 			if (items->mask != NULL && items->spec != NULL) {
6980 				ether_type =
6981 					((const struct rte_flow_item_eth *)
6982 					 items->spec)->type;
6983 				ether_type &=
6984 					((const struct rte_flow_item_eth *)
6985 					 items->mask)->type;
6986 				ether_type = rte_be_to_cpu_16(ether_type);
6987 			} else {
6988 				ether_type = 0;
6989 			}
6990 			break;
6991 		case RTE_FLOW_ITEM_TYPE_VLAN:
6992 			ret = flow_dv_validate_item_vlan(items, item_flags,
6993 							 dev, error);
6994 			if (ret < 0)
6995 				return ret;
6996 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
6997 					     MLX5_FLOW_LAYER_OUTER_VLAN;
6998 			if (items->mask != NULL && items->spec != NULL) {
6999 				ether_type =
7000 					((const struct rte_flow_item_vlan *)
7001 					 items->spec)->inner_type;
7002 				ether_type &=
7003 					((const struct rte_flow_item_vlan *)
7004 					 items->mask)->inner_type;
7005 				ether_type = rte_be_to_cpu_16(ether_type);
7006 			} else {
7007 				ether_type = 0;
7008 			}
7009 			/* Store outer VLAN mask for of_push_vlan action. */
7010 			if (!tunnel)
7011 				vlan_m = items->mask;
7012 			break;
7013 		case RTE_FLOW_ITEM_TYPE_IPV4:
7014 			mlx5_flow_tunnel_ip_check(items, next_protocol,
7015 						  &item_flags, &tunnel);
7016 			ret = flow_dv_validate_item_ipv4(dev, items, item_flags,
7017 							 last_item, ether_type,
7018 							 error);
7019 			if (ret < 0)
7020 				return ret;
7021 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
7022 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
7023 			if (items->mask != NULL &&
7024 			    ((const struct rte_flow_item_ipv4 *)
7025 			     items->mask)->hdr.next_proto_id) {
7026 				next_protocol =
7027 					((const struct rte_flow_item_ipv4 *)
7028 					 (items->spec))->hdr.next_proto_id;
7029 				next_protocol &=
7030 					((const struct rte_flow_item_ipv4 *)
7031 					 (items->mask))->hdr.next_proto_id;
7032 			} else {
7033 				/* Reset for inner layer. */
7034 				next_protocol = 0xff;
7035 			}
7036 			break;
7037 		case RTE_FLOW_ITEM_TYPE_IPV6:
7038 			mlx5_flow_tunnel_ip_check(items, next_protocol,
7039 						  &item_flags, &tunnel);
7040 			ret = mlx5_flow_validate_item_ipv6(items, item_flags,
7041 							   last_item,
7042 							   ether_type,
7043 							   &nic_ipv6_mask,
7044 							   error);
7045 			if (ret < 0)
7046 				return ret;
7047 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
7048 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
7049 			if (items->mask != NULL &&
7050 			    ((const struct rte_flow_item_ipv6 *)
7051 			     items->mask)->hdr.proto) {
7052 				item_ipv6_proto =
7053 					((const struct rte_flow_item_ipv6 *)
7054 					 items->spec)->hdr.proto;
7055 				next_protocol =
7056 					((const struct rte_flow_item_ipv6 *)
7057 					 items->spec)->hdr.proto;
7058 				next_protocol &=
7059 					((const struct rte_flow_item_ipv6 *)
7060 					 items->mask)->hdr.proto;
7061 			} else {
7062 				/* Reset for inner layer. */
7063 				next_protocol = 0xff;
7064 			}
7065 			break;
7066 		case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
7067 			ret = flow_dv_validate_item_ipv6_frag_ext(items,
7068 								  item_flags,
7069 								  error);
7070 			if (ret < 0)
7071 				return ret;
7072 			last_item = tunnel ?
7073 					MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
7074 					MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
7075 			if (items->mask != NULL &&
7076 			    ((const struct rte_flow_item_ipv6_frag_ext *)
7077 			     items->mask)->hdr.next_header) {
7078 				next_protocol =
7079 				((const struct rte_flow_item_ipv6_frag_ext *)
7080 				 items->spec)->hdr.next_header;
7081 				next_protocol &=
7082 				((const struct rte_flow_item_ipv6_frag_ext *)
7083 				 items->mask)->hdr.next_header;
7084 			} else {
7085 				/* Reset for inner layer. */
7086 				next_protocol = 0xff;
7087 			}
7088 			break;
7089 		case RTE_FLOW_ITEM_TYPE_TCP:
7090 			ret = mlx5_flow_validate_item_tcp
7091 						(items, item_flags,
7092 						 next_protocol,
7093 						 &nic_tcp_mask,
7094 						 error);
7095 			if (ret < 0)
7096 				return ret;
7097 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
7098 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
7099 			break;
7100 		case RTE_FLOW_ITEM_TYPE_UDP:
7101 			ret = mlx5_flow_validate_item_udp(items, item_flags,
7102 							  next_protocol,
7103 							  error);
7104 			const struct rte_flow_item_udp *spec = items->spec;
7105 			const struct rte_flow_item_udp *mask = items->mask;
7106 			if (!mask)
7107 				mask = &rte_flow_item_udp_mask;
7108 			if (spec != NULL)
7109 				udp_dport = rte_be_to_cpu_16
7110 						(spec->hdr.dst_port &
7111 						 mask->hdr.dst_port);
7112 			if (ret < 0)
7113 				return ret;
7114 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
7115 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
7116 			break;
7117 		case RTE_FLOW_ITEM_TYPE_GRE:
7118 			ret = mlx5_flow_validate_item_gre(items, item_flags,
7119 							  next_protocol, error);
7120 			if (ret < 0)
7121 				return ret;
7122 			gre_item = items;
7123 			last_item = MLX5_FLOW_LAYER_GRE;
7124 			break;
7125 		case RTE_FLOW_ITEM_TYPE_NVGRE:
7126 			ret = mlx5_flow_validate_item_nvgre(items, item_flags,
7127 							    next_protocol,
7128 							    error);
7129 			if (ret < 0)
7130 				return ret;
7131 			last_item = MLX5_FLOW_LAYER_NVGRE;
7132 			break;
7133 		case RTE_FLOW_ITEM_TYPE_GRE_KEY:
7134 			ret = mlx5_flow_validate_item_gre_key
7135 				(items, item_flags, gre_item, error);
7136 			if (ret < 0)
7137 				return ret;
7138 			last_item = MLX5_FLOW_LAYER_GRE_KEY;
7139 			break;
7140 		case RTE_FLOW_ITEM_TYPE_VXLAN:
7141 			ret = mlx5_flow_validate_item_vxlan(dev, udp_dport,
7142 							    items, item_flags,
7143 							    attr, error);
7144 			if (ret < 0)
7145 				return ret;
7146 			last_item = MLX5_FLOW_LAYER_VXLAN;
7147 			break;
7148 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
7149 			ret = mlx5_flow_validate_item_vxlan_gpe(items,
7150 								item_flags, dev,
7151 								error);
7152 			if (ret < 0)
7153 				return ret;
7154 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
7155 			break;
7156 		case RTE_FLOW_ITEM_TYPE_GENEVE:
7157 			ret = mlx5_flow_validate_item_geneve(items,
7158 							     item_flags, dev,
7159 							     error);
7160 			if (ret < 0)
7161 				return ret;
7162 			geneve_item = items;
7163 			last_item = MLX5_FLOW_LAYER_GENEVE;
7164 			break;
7165 		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
7166 			ret = mlx5_flow_validate_item_geneve_opt(items,
7167 								 last_item,
7168 								 geneve_item,
7169 								 dev,
7170 								 error);
7171 			if (ret < 0)
7172 				return ret;
7173 			last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
7174 			break;
7175 		case RTE_FLOW_ITEM_TYPE_MPLS:
7176 			ret = mlx5_flow_validate_item_mpls(dev, items,
7177 							   item_flags,
7178 							   last_item, error);
7179 			if (ret < 0)
7180 				return ret;
7181 			last_item = MLX5_FLOW_LAYER_MPLS;
7182 			break;
7183 
7184 		case RTE_FLOW_ITEM_TYPE_MARK:
7185 			ret = flow_dv_validate_item_mark(dev, items, attr,
7186 							 error);
7187 			if (ret < 0)
7188 				return ret;
7189 			last_item = MLX5_FLOW_ITEM_MARK;
7190 			break;
7191 		case RTE_FLOW_ITEM_TYPE_META:
7192 			ret = flow_dv_validate_item_meta(dev, items, attr,
7193 							 error);
7194 			if (ret < 0)
7195 				return ret;
7196 			last_item = MLX5_FLOW_ITEM_METADATA;
7197 			break;
7198 		case RTE_FLOW_ITEM_TYPE_ICMP:
7199 			ret = mlx5_flow_validate_item_icmp(items, item_flags,
7200 							   next_protocol,
7201 							   error);
7202 			if (ret < 0)
7203 				return ret;
7204 			last_item = MLX5_FLOW_LAYER_ICMP;
7205 			break;
7206 		case RTE_FLOW_ITEM_TYPE_ICMP6:
7207 			ret = mlx5_flow_validate_item_icmp6(items, item_flags,
7208 							    next_protocol,
7209 							    error);
7210 			if (ret < 0)
7211 				return ret;
7212 			item_ipv6_proto = IPPROTO_ICMPV6;
7213 			last_item = MLX5_FLOW_LAYER_ICMP6;
7214 			break;
7215 		case RTE_FLOW_ITEM_TYPE_TAG:
7216 			ret = flow_dv_validate_item_tag(dev, items,
7217 							attr, error);
7218 			if (ret < 0)
7219 				return ret;
7220 			last_item = MLX5_FLOW_ITEM_TAG;
7221 			break;
7222 		case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
7223 		case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
7224 			break;
7225 		case RTE_FLOW_ITEM_TYPE_GTP:
7226 			ret = flow_dv_validate_item_gtp(dev, items, item_flags,
7227 							error);
7228 			if (ret < 0)
7229 				return ret;
7230 			gtp_item = items;
7231 			last_item = MLX5_FLOW_LAYER_GTP;
7232 			break;
7233 		case RTE_FLOW_ITEM_TYPE_GTP_PSC:
7234 			ret = flow_dv_validate_item_gtp_psc(items, last_item,
7235 							    gtp_item, attr,
7236 							    error);
7237 			if (ret < 0)
7238 				return ret;
7239 			last_item = MLX5_FLOW_LAYER_GTP_PSC;
7240 			break;
7241 		case RTE_FLOW_ITEM_TYPE_ECPRI:
7242 			/* Capacity will be checked in the translate stage. */
7243 			ret = mlx5_flow_validate_item_ecpri(items, item_flags,
7244 							    last_item,
7245 							    ether_type,
7246 							    &nic_ecpri_mask,
7247 							    error);
7248 			if (ret < 0)
7249 				return ret;
7250 			last_item = MLX5_FLOW_LAYER_ECPRI;
7251 			break;
7252 		case RTE_FLOW_ITEM_TYPE_INTEGRITY:
7253 			if (item_flags & MLX5_FLOW_ITEM_INTEGRITY)
7254 				return rte_flow_error_set
7255 					(error, ENOTSUP,
7256 					 RTE_FLOW_ERROR_TYPE_ITEM,
7257 					 NULL, "multiple integrity items not supported");
7258 			ret = flow_dv_validate_item_integrity(dev, rule_items,
7259 							      items, error);
7260 			if (ret < 0)
7261 				return ret;
7262 			last_item = MLX5_FLOW_ITEM_INTEGRITY;
7263 			break;
7264 		case RTE_FLOW_ITEM_TYPE_CONNTRACK:
7265 			ret = flow_dv_validate_item_aso_ct(dev, items,
7266 							   &item_flags, error);
7267 			if (ret < 0)
7268 				return ret;
7269 			break;
7270 		case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL:
7271 			/* tunnel offload item was processed before
7272 			 * list it here as a supported type
7273 			 */
7274 			break;
7275 		default:
7276 			return rte_flow_error_set(error, ENOTSUP,
7277 						  RTE_FLOW_ERROR_TYPE_ITEM,
7278 						  NULL, "item not supported");
7279 		}
7280 		item_flags |= last_item;
7281 	}
7282 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
7283 		int type = actions->type;
7284 		bool shared_count = false;
7285 
7286 		if (!mlx5_flow_os_action_supported(type))
7287 			return rte_flow_error_set(error, ENOTSUP,
7288 						  RTE_FLOW_ERROR_TYPE_ACTION,
7289 						  actions,
7290 						  "action not supported");
7291 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
7292 			return rte_flow_error_set(error, ENOTSUP,
7293 						  RTE_FLOW_ERROR_TYPE_ACTION,
7294 						  actions, "too many actions");
7295 		if (action_flags &
7296 			MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
7297 			return rte_flow_error_set(error, ENOTSUP,
7298 				RTE_FLOW_ERROR_TYPE_ACTION,
7299 				NULL, "meter action with policy "
7300 				"must be the last action");
7301 		switch (type) {
7302 		case RTE_FLOW_ACTION_TYPE_VOID:
7303 			break;
7304 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
7305 			ret = flow_dv_validate_action_port_id(dev,
7306 							      action_flags,
7307 							      actions,
7308 							      attr,
7309 							      error);
7310 			if (ret)
7311 				return ret;
7312 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
7313 			++actions_n;
7314 			break;
7315 		case RTE_FLOW_ACTION_TYPE_FLAG:
7316 			ret = flow_dv_validate_action_flag(dev, action_flags,
7317 							   attr, error);
7318 			if (ret < 0)
7319 				return ret;
7320 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7321 				/* Count all modify-header actions as one. */
7322 				if (!(action_flags &
7323 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
7324 					++actions_n;
7325 				action_flags |= MLX5_FLOW_ACTION_FLAG |
7326 						MLX5_FLOW_ACTION_MARK_EXT;
7327 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7328 					modify_after_mirror = 1;
7329 
7330 			} else {
7331 				action_flags |= MLX5_FLOW_ACTION_FLAG;
7332 				++actions_n;
7333 			}
7334 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
7335 			break;
7336 		case RTE_FLOW_ACTION_TYPE_MARK:
7337 			ret = flow_dv_validate_action_mark(dev, actions,
7338 							   action_flags,
7339 							   attr, error);
7340 			if (ret < 0)
7341 				return ret;
7342 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7343 				/* Count all modify-header actions as one. */
7344 				if (!(action_flags &
7345 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
7346 					++actions_n;
7347 				action_flags |= MLX5_FLOW_ACTION_MARK |
7348 						MLX5_FLOW_ACTION_MARK_EXT;
7349 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7350 					modify_after_mirror = 1;
7351 			} else {
7352 				action_flags |= MLX5_FLOW_ACTION_MARK;
7353 				++actions_n;
7354 			}
7355 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
7356 			break;
7357 		case RTE_FLOW_ACTION_TYPE_SET_META:
7358 			ret = flow_dv_validate_action_set_meta(dev, actions,
7359 							       action_flags,
7360 							       attr, error);
7361 			if (ret < 0)
7362 				return ret;
7363 			/* Count all modify-header actions as one action. */
7364 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7365 				++actions_n;
7366 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7367 				modify_after_mirror = 1;
7368 			action_flags |= MLX5_FLOW_ACTION_SET_META;
7369 			rw_act_num += MLX5_ACT_NUM_SET_META;
7370 			break;
7371 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
7372 			ret = flow_dv_validate_action_set_tag(dev, actions,
7373 							      action_flags,
7374 							      attr, error);
7375 			if (ret < 0)
7376 				return ret;
7377 			/* Count all modify-header actions as one action. */
7378 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7379 				++actions_n;
7380 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7381 				modify_after_mirror = 1;
7382 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
7383 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7384 			break;
7385 		case RTE_FLOW_ACTION_TYPE_DROP:
7386 			ret = mlx5_flow_validate_action_drop(action_flags,
7387 							     attr, error);
7388 			if (ret < 0)
7389 				return ret;
7390 			action_flags |= MLX5_FLOW_ACTION_DROP;
7391 			++actions_n;
7392 			break;
7393 		case RTE_FLOW_ACTION_TYPE_QUEUE:
7394 			ret = mlx5_flow_validate_action_queue(actions,
7395 							      action_flags, dev,
7396 							      attr, error);
7397 			if (ret < 0)
7398 				return ret;
7399 			queue_index = ((const struct rte_flow_action_queue *)
7400 							(actions->conf))->index;
7401 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
7402 			++actions_n;
7403 			break;
7404 		case RTE_FLOW_ACTION_TYPE_RSS:
7405 			rss = actions->conf;
7406 			ret = mlx5_flow_validate_action_rss(actions,
7407 							    action_flags, dev,
7408 							    attr, item_flags,
7409 							    error);
7410 			if (ret < 0)
7411 				return ret;
7412 			if (rss && sample_rss &&
7413 			    (sample_rss->level != rss->level ||
7414 			    sample_rss->types != rss->types))
7415 				return rte_flow_error_set(error, ENOTSUP,
7416 					RTE_FLOW_ERROR_TYPE_ACTION,
7417 					NULL,
7418 					"Can't use the different RSS types "
7419 					"or level in the same flow");
7420 			if (rss != NULL && rss->queue_num)
7421 				queue_index = rss->queue[0];
7422 			action_flags |= MLX5_FLOW_ACTION_RSS;
7423 			++actions_n;
7424 			break;
7425 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
7426 			ret =
7427 			mlx5_flow_validate_action_default_miss(action_flags,
7428 					attr, error);
7429 			if (ret < 0)
7430 				return ret;
7431 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
7432 			++actions_n;
7433 			break;
7434 		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
7435 		case RTE_FLOW_ACTION_TYPE_COUNT:
7436 			shared_count = is_shared_action_count(actions);
7437 			ret = flow_dv_validate_action_count(dev, shared_count,
7438 							    action_flags,
7439 							    error);
7440 			if (ret < 0)
7441 				return ret;
7442 			action_flags |= MLX5_FLOW_ACTION_COUNT;
7443 			++actions_n;
7444 			break;
7445 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
7446 			if (flow_dv_validate_action_pop_vlan(dev,
7447 							     action_flags,
7448 							     actions,
7449 							     item_flags, attr,
7450 							     error))
7451 				return -rte_errno;
7452 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7453 				modify_after_mirror = 1;
7454 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
7455 			++actions_n;
7456 			break;
7457 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
7458 			ret = flow_dv_validate_action_push_vlan(dev,
7459 								action_flags,
7460 								vlan_m,
7461 								actions, attr,
7462 								error);
7463 			if (ret < 0)
7464 				return ret;
7465 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7466 				modify_after_mirror = 1;
7467 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
7468 			++actions_n;
7469 			break;
7470 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
7471 			ret = flow_dv_validate_action_set_vlan_pcp
7472 						(action_flags, actions, error);
7473 			if (ret < 0)
7474 				return ret;
7475 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7476 				modify_after_mirror = 1;
7477 			/* Count PCP with push_vlan command. */
7478 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP;
7479 			break;
7480 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
7481 			ret = flow_dv_validate_action_set_vlan_vid
7482 						(item_flags, action_flags,
7483 						 actions, error);
7484 			if (ret < 0)
7485 				return ret;
7486 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7487 				modify_after_mirror = 1;
7488 			/* Count VID with push_vlan command. */
7489 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
7490 			rw_act_num += MLX5_ACT_NUM_MDF_VID;
7491 			break;
7492 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
7493 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
7494 			ret = flow_dv_validate_action_l2_encap(dev,
7495 							       action_flags,
7496 							       actions, attr,
7497 							       error);
7498 			if (ret < 0)
7499 				return ret;
7500 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
7501 			++actions_n;
7502 			break;
7503 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
7504 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
7505 			ret = flow_dv_validate_action_decap(dev, action_flags,
7506 							    actions, item_flags,
7507 							    attr, error);
7508 			if (ret < 0)
7509 				return ret;
7510 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7511 				modify_after_mirror = 1;
7512 			action_flags |= MLX5_FLOW_ACTION_DECAP;
7513 			++actions_n;
7514 			break;
7515 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
7516 			ret = flow_dv_validate_action_raw_encap_decap
7517 				(dev, NULL, actions->conf, attr, &action_flags,
7518 				 &actions_n, actions, item_flags, error);
7519 			if (ret < 0)
7520 				return ret;
7521 			break;
7522 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
7523 			decap = actions->conf;
7524 			while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID)
7525 				;
7526 			if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
7527 				encap = NULL;
7528 				actions--;
7529 			} else {
7530 				encap = actions->conf;
7531 			}
7532 			ret = flow_dv_validate_action_raw_encap_decap
7533 					   (dev,
7534 					    decap ? decap : &empty_decap, encap,
7535 					    attr, &action_flags, &actions_n,
7536 					    actions, item_flags, error);
7537 			if (ret < 0)
7538 				return ret;
7539 			if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
7540 			    (action_flags & MLX5_FLOW_ACTION_DECAP))
7541 				modify_after_mirror = 1;
7542 			break;
7543 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
7544 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
7545 			ret = flow_dv_validate_action_modify_mac(action_flags,
7546 								 actions,
7547 								 item_flags,
7548 								 error);
7549 			if (ret < 0)
7550 				return ret;
7551 			/* Count all modify-header actions as one action. */
7552 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7553 				++actions_n;
7554 			action_flags |= actions->type ==
7555 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
7556 						MLX5_FLOW_ACTION_SET_MAC_SRC :
7557 						MLX5_FLOW_ACTION_SET_MAC_DST;
7558 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7559 				modify_after_mirror = 1;
7560 			/*
7561 			 * Even if the source and destination MAC addresses have
7562 			 * overlap in the header with 4B alignment, the convert
7563 			 * function will handle them separately and 4 SW actions
7564 			 * will be created. And 2 actions will be added each
7565 			 * time no matter how many bytes of address will be set.
7566 			 */
7567 			rw_act_num += MLX5_ACT_NUM_MDF_MAC;
7568 			break;
7569 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
7570 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
7571 			ret = flow_dv_validate_action_modify_ipv4(action_flags,
7572 								  actions,
7573 								  item_flags,
7574 								  error);
7575 			if (ret < 0)
7576 				return ret;
7577 			/* Count all modify-header actions as one action. */
7578 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7579 				++actions_n;
7580 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7581 				modify_after_mirror = 1;
7582 			action_flags |= actions->type ==
7583 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
7584 						MLX5_FLOW_ACTION_SET_IPV4_SRC :
7585 						MLX5_FLOW_ACTION_SET_IPV4_DST;
7586 			rw_act_num += MLX5_ACT_NUM_MDF_IPV4;
7587 			break;
7588 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
7589 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
7590 			ret = flow_dv_validate_action_modify_ipv6(action_flags,
7591 								  actions,
7592 								  item_flags,
7593 								  error);
7594 			if (ret < 0)
7595 				return ret;
7596 			if (item_ipv6_proto == IPPROTO_ICMPV6)
7597 				return rte_flow_error_set(error, ENOTSUP,
7598 					RTE_FLOW_ERROR_TYPE_ACTION,
7599 					actions,
7600 					"Can't change header "
7601 					"with ICMPv6 proto");
7602 			/* Count all modify-header actions as one action. */
7603 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7604 				++actions_n;
7605 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7606 				modify_after_mirror = 1;
7607 			action_flags |= actions->type ==
7608 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
7609 						MLX5_FLOW_ACTION_SET_IPV6_SRC :
7610 						MLX5_FLOW_ACTION_SET_IPV6_DST;
7611 			rw_act_num += MLX5_ACT_NUM_MDF_IPV6;
7612 			break;
7613 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
7614 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
7615 			ret = flow_dv_validate_action_modify_tp(action_flags,
7616 								actions,
7617 								item_flags,
7618 								error);
7619 			if (ret < 0)
7620 				return ret;
7621 			/* Count all modify-header actions as one action. */
7622 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7623 				++actions_n;
7624 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7625 				modify_after_mirror = 1;
7626 			action_flags |= actions->type ==
7627 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
7628 						MLX5_FLOW_ACTION_SET_TP_SRC :
7629 						MLX5_FLOW_ACTION_SET_TP_DST;
7630 			rw_act_num += MLX5_ACT_NUM_MDF_PORT;
7631 			break;
7632 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
7633 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
7634 			ret = flow_dv_validate_action_modify_ttl(action_flags,
7635 								 actions,
7636 								 item_flags,
7637 								 error);
7638 			if (ret < 0)
7639 				return ret;
7640 			/* Count all modify-header actions as one action. */
7641 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7642 				++actions_n;
7643 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7644 				modify_after_mirror = 1;
7645 			action_flags |= actions->type ==
7646 					RTE_FLOW_ACTION_TYPE_SET_TTL ?
7647 						MLX5_FLOW_ACTION_SET_TTL :
7648 						MLX5_FLOW_ACTION_DEC_TTL;
7649 			rw_act_num += MLX5_ACT_NUM_MDF_TTL;
7650 			break;
7651 		case RTE_FLOW_ACTION_TYPE_JUMP:
7652 			ret = flow_dv_validate_action_jump(dev, tunnel, actions,
7653 							   action_flags,
7654 							   attr, external,
7655 							   error);
7656 			if (ret)
7657 				return ret;
7658 			if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
7659 			    fdb_mirror_limit)
7660 				return rte_flow_error_set(error, EINVAL,
7661 						  RTE_FLOW_ERROR_TYPE_ACTION,
7662 						  NULL,
7663 						  "sample and jump action combination is not supported");
7664 			++actions_n;
7665 			action_flags |= MLX5_FLOW_ACTION_JUMP;
7666 			break;
7667 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
7668 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
7669 			ret = flow_dv_validate_action_modify_tcp_seq
7670 								(action_flags,
7671 								 actions,
7672 								 item_flags,
7673 								 error);
7674 			if (ret < 0)
7675 				return ret;
7676 			/* Count all modify-header actions as one action. */
7677 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7678 				++actions_n;
7679 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7680 				modify_after_mirror = 1;
7681 			action_flags |= actions->type ==
7682 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
7683 						MLX5_FLOW_ACTION_INC_TCP_SEQ :
7684 						MLX5_FLOW_ACTION_DEC_TCP_SEQ;
7685 			rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ;
7686 			break;
7687 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
7688 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
7689 			ret = flow_dv_validate_action_modify_tcp_ack
7690 								(action_flags,
7691 								 actions,
7692 								 item_flags,
7693 								 error);
7694 			if (ret < 0)
7695 				return ret;
7696 			/* Count all modify-header actions as one action. */
7697 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7698 				++actions_n;
7699 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7700 				modify_after_mirror = 1;
7701 			action_flags |= actions->type ==
7702 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
7703 						MLX5_FLOW_ACTION_INC_TCP_ACK :
7704 						MLX5_FLOW_ACTION_DEC_TCP_ACK;
7705 			rw_act_num += MLX5_ACT_NUM_MDF_TCPACK;
7706 			break;
7707 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
7708 			break;
7709 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
7710 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
7711 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7712 			break;
7713 		case RTE_FLOW_ACTION_TYPE_METER:
7714 			ret = mlx5_flow_validate_action_meter(dev,
7715 							      action_flags,
7716 							      actions, attr,
7717 							      port_id_item,
7718 							      &def_policy,
7719 							      error);
7720 			if (ret < 0)
7721 				return ret;
7722 			action_flags |= MLX5_FLOW_ACTION_METER;
7723 			if (!def_policy)
7724 				action_flags |=
7725 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
7726 			++actions_n;
7727 			/* Meter action will add one more TAG action. */
7728 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7729 			break;
7730 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
7731 			if (!attr->transfer && !attr->group)
7732 				return rte_flow_error_set(error, ENOTSUP,
7733 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
7734 									   NULL,
7735 			  "Shared ASO age action is not supported for group 0");
7736 			if (action_flags & MLX5_FLOW_ACTION_AGE)
7737 				return rte_flow_error_set
7738 						  (error, EINVAL,
7739 						   RTE_FLOW_ERROR_TYPE_ACTION,
7740 						   NULL,
7741 						   "duplicate age actions set");
7742 			action_flags |= MLX5_FLOW_ACTION_AGE;
7743 			++actions_n;
7744 			break;
7745 		case RTE_FLOW_ACTION_TYPE_AGE:
7746 			ret = flow_dv_validate_action_age(action_flags,
7747 							  actions, dev,
7748 							  error);
7749 			if (ret < 0)
7750 				return ret;
7751 			/*
7752 			 * Validate the regular AGE action (using counter)
7753 			 * mutual exclusion with share counter actions.
7754 			 */
7755 			if (!priv->sh->flow_hit_aso_en) {
7756 				if (shared_count)
7757 					return rte_flow_error_set
7758 						(error, EINVAL,
7759 						RTE_FLOW_ERROR_TYPE_ACTION,
7760 						NULL,
7761 						"old age and shared count combination is not supported");
7762 				if (sample_count)
7763 					return rte_flow_error_set
7764 						(error, EINVAL,
7765 						RTE_FLOW_ERROR_TYPE_ACTION,
7766 						NULL,
7767 						"old age action and count must be in the same sub flow");
7768 			}
7769 			action_flags |= MLX5_FLOW_ACTION_AGE;
7770 			++actions_n;
7771 			break;
7772 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
7773 			ret = flow_dv_validate_action_modify_ipv4_dscp
7774 							 (action_flags,
7775 							  actions,
7776 							  item_flags,
7777 							  error);
7778 			if (ret < 0)
7779 				return ret;
7780 			/* Count all modify-header actions as one action. */
7781 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7782 				++actions_n;
7783 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7784 				modify_after_mirror = 1;
7785 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
7786 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7787 			break;
7788 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
7789 			ret = flow_dv_validate_action_modify_ipv6_dscp
7790 								(action_flags,
7791 								 actions,
7792 								 item_flags,
7793 								 error);
7794 			if (ret < 0)
7795 				return ret;
7796 			/* Count all modify-header actions as one action. */
7797 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7798 				++actions_n;
7799 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7800 				modify_after_mirror = 1;
7801 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
7802 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7803 			break;
7804 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
7805 			ret = flow_dv_validate_action_sample(&action_flags,
7806 							     actions, dev,
7807 							     attr, item_flags,
7808 							     rss, &sample_rss,
7809 							     &sample_count,
7810 							     &fdb_mirror_limit,
7811 							     error);
7812 			if (ret < 0)
7813 				return ret;
7814 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
7815 			++actions_n;
7816 			break;
7817 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
7818 			ret = flow_dv_validate_action_modify_field(dev,
7819 								   action_flags,
7820 								   actions,
7821 								   attr,
7822 								   error);
7823 			if (ret < 0)
7824 				return ret;
7825 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7826 				modify_after_mirror = 1;
7827 			/* Count all modify-header actions as one action. */
7828 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7829 				++actions_n;
7830 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
7831 			rw_act_num += ret;
7832 			break;
7833 		case RTE_FLOW_ACTION_TYPE_CONNTRACK:
7834 			ret = flow_dv_validate_action_aso_ct(dev, action_flags,
7835 							     item_flags, attr,
7836 							     error);
7837 			if (ret < 0)
7838 				return ret;
7839 			action_flags |= MLX5_FLOW_ACTION_CT;
7840 			break;
7841 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
7842 			/* tunnel offload action was processed before
7843 			 * list it here as a supported type
7844 			 */
7845 			break;
7846 		default:
7847 			return rte_flow_error_set(error, ENOTSUP,
7848 						  RTE_FLOW_ERROR_TYPE_ACTION,
7849 						  actions,
7850 						  "action not supported");
7851 		}
7852 	}
7853 	/*
7854 	 * Validate actions in flow rules
7855 	 * - Explicit decap action is prohibited by the tunnel offload API.
7856 	 * - Drop action in tunnel steer rule is prohibited by the API.
7857 	 * - Application cannot use MARK action because it's value can mask
7858 	 *   tunnel default miss nitification.
7859 	 * - JUMP in tunnel match rule has no support in current PMD
7860 	 *   implementation.
7861 	 * - TAG & META are reserved for future uses.
7862 	 */
7863 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) {
7864 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP    |
7865 					    MLX5_FLOW_ACTION_MARK     |
7866 					    MLX5_FLOW_ACTION_SET_TAG  |
7867 					    MLX5_FLOW_ACTION_SET_META |
7868 					    MLX5_FLOW_ACTION_DROP;
7869 
7870 		if (action_flags & bad_actions_mask)
7871 			return rte_flow_error_set
7872 					(error, EINVAL,
7873 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7874 					"Invalid RTE action in tunnel "
7875 					"set decap rule");
7876 		if (!(action_flags & MLX5_FLOW_ACTION_JUMP))
7877 			return rte_flow_error_set
7878 					(error, EINVAL,
7879 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7880 					"tunnel set decap rule must terminate "
7881 					"with JUMP");
7882 		if (!attr->ingress)
7883 			return rte_flow_error_set
7884 					(error, EINVAL,
7885 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7886 					"tunnel flows for ingress traffic only");
7887 	}
7888 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) {
7889 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP    |
7890 					    MLX5_FLOW_ACTION_MARK    |
7891 					    MLX5_FLOW_ACTION_SET_TAG |
7892 					    MLX5_FLOW_ACTION_SET_META;
7893 
7894 		if (action_flags & bad_actions_mask)
7895 			return rte_flow_error_set
7896 					(error, EINVAL,
7897 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7898 					"Invalid RTE action in tunnel "
7899 					"set match rule");
7900 	}
7901 	/*
7902 	 * Validate the drop action mutual exclusion with other actions.
7903 	 * Drop action is mutually-exclusive with any other action, except for
7904 	 * Count action.
7905 	 * Drop action compatibility with tunnel offload was already validated.
7906 	 */
7907 	if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH |
7908 			    MLX5_FLOW_ACTION_TUNNEL_MATCH));
7909 	else if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
7910 	    (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT)))
7911 		return rte_flow_error_set(error, EINVAL,
7912 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7913 					  "Drop action is mutually-exclusive "
7914 					  "with any other action, except for "
7915 					  "Count action");
7916 	/* Eswitch has few restrictions on using items and actions */
7917 	if (attr->transfer) {
7918 		if (!mlx5_flow_ext_mreg_supported(dev) &&
7919 		    action_flags & MLX5_FLOW_ACTION_FLAG)
7920 			return rte_flow_error_set(error, ENOTSUP,
7921 						  RTE_FLOW_ERROR_TYPE_ACTION,
7922 						  NULL,
7923 						  "unsupported action FLAG");
7924 		if (!mlx5_flow_ext_mreg_supported(dev) &&
7925 		    action_flags & MLX5_FLOW_ACTION_MARK)
7926 			return rte_flow_error_set(error, ENOTSUP,
7927 						  RTE_FLOW_ERROR_TYPE_ACTION,
7928 						  NULL,
7929 						  "unsupported action MARK");
7930 		if (action_flags & MLX5_FLOW_ACTION_QUEUE)
7931 			return rte_flow_error_set(error, ENOTSUP,
7932 						  RTE_FLOW_ERROR_TYPE_ACTION,
7933 						  NULL,
7934 						  "unsupported action QUEUE");
7935 		if (action_flags & MLX5_FLOW_ACTION_RSS)
7936 			return rte_flow_error_set(error, ENOTSUP,
7937 						  RTE_FLOW_ERROR_TYPE_ACTION,
7938 						  NULL,
7939 						  "unsupported action RSS");
7940 		if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
7941 			return rte_flow_error_set(error, EINVAL,
7942 						  RTE_FLOW_ERROR_TYPE_ACTION,
7943 						  actions,
7944 						  "no fate action is found");
7945 	} else {
7946 		if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress)
7947 			return rte_flow_error_set(error, EINVAL,
7948 						  RTE_FLOW_ERROR_TYPE_ACTION,
7949 						  actions,
7950 						  "no fate action is found");
7951 	}
7952 	/*
7953 	 * Continue validation for Xcap and VLAN actions.
7954 	 * If hairpin is working in explicit TX rule mode, there is no actions
7955 	 * splitting and the validation of hairpin ingress flow should be the
7956 	 * same as other standard flows.
7957 	 */
7958 	if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS |
7959 			     MLX5_FLOW_VLAN_ACTIONS)) &&
7960 	    (queue_index == 0xFFFF ||
7961 	     mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN ||
7962 	     ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL &&
7963 	     conf->tx_explicit != 0))) {
7964 		if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
7965 		    MLX5_FLOW_XCAP_ACTIONS)
7966 			return rte_flow_error_set(error, ENOTSUP,
7967 						  RTE_FLOW_ERROR_TYPE_ACTION,
7968 						  NULL, "encap and decap "
7969 						  "combination aren't supported");
7970 		if (!attr->transfer && attr->ingress) {
7971 			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
7972 				return rte_flow_error_set
7973 						(error, ENOTSUP,
7974 						 RTE_FLOW_ERROR_TYPE_ACTION,
7975 						 NULL, "encap is not supported"
7976 						 " for ingress traffic");
7977 			else if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
7978 				return rte_flow_error_set
7979 						(error, ENOTSUP,
7980 						 RTE_FLOW_ERROR_TYPE_ACTION,
7981 						 NULL, "push VLAN action not "
7982 						 "supported for ingress");
7983 			else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) ==
7984 					MLX5_FLOW_VLAN_ACTIONS)
7985 				return rte_flow_error_set
7986 						(error, ENOTSUP,
7987 						 RTE_FLOW_ERROR_TYPE_ACTION,
7988 						 NULL, "no support for "
7989 						 "multiple VLAN actions");
7990 		}
7991 	}
7992 	if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) {
7993 		if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
7994 			~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) &&
7995 			attr->ingress)
7996 			return rte_flow_error_set
7997 				(error, ENOTSUP,
7998 				RTE_FLOW_ERROR_TYPE_ACTION,
7999 				NULL, "fate action not supported for "
8000 				"meter with policy");
8001 		if (attr->egress) {
8002 			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
8003 				return rte_flow_error_set
8004 					(error, ENOTSUP,
8005 					RTE_FLOW_ERROR_TYPE_ACTION,
8006 					NULL, "modify header action in egress "
8007 					"cannot be done before meter action");
8008 			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
8009 				return rte_flow_error_set
8010 					(error, ENOTSUP,
8011 					RTE_FLOW_ERROR_TYPE_ACTION,
8012 					NULL, "encap action in egress "
8013 					"cannot be done before meter action");
8014 			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
8015 				return rte_flow_error_set
8016 					(error, ENOTSUP,
8017 					RTE_FLOW_ERROR_TYPE_ACTION,
8018 					NULL, "push vlan action in egress "
8019 					"cannot be done before meter action");
8020 		}
8021 	}
8022 	/*
8023 	 * Hairpin flow will add one more TAG action in TX implicit mode.
8024 	 * In TX explicit mode, there will be no hairpin flow ID.
8025 	 */
8026 	if (hairpin > 0)
8027 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
8028 	/* extra metadata enabled: one more TAG action will be add. */
8029 	if (dev_conf->dv_flow_en &&
8030 	    dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
8031 	    mlx5_flow_ext_mreg_supported(dev))
8032 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
8033 	if (rw_act_num >
8034 			flow_dv_modify_hdr_action_max(dev, is_root)) {
8035 		return rte_flow_error_set(error, ENOTSUP,
8036 					  RTE_FLOW_ERROR_TYPE_ACTION,
8037 					  NULL, "too many header modify"
8038 					  " actions to support");
8039 	}
8040 	/* Eswitch egress mirror and modify flow has limitation on CX5 */
8041 	if (fdb_mirror_limit && modify_after_mirror)
8042 		return rte_flow_error_set(error, EINVAL,
8043 				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8044 				"sample before modify action is not supported");
8045 	return 0;
8046 }
8047 
8048 /**
8049  * Internal preparation function. Allocates the DV flow size,
8050  * this size is constant.
8051  *
8052  * @param[in] dev
8053  *   Pointer to the rte_eth_dev structure.
8054  * @param[in] attr
8055  *   Pointer to the flow attributes.
8056  * @param[in] items
8057  *   Pointer to the list of items.
8058  * @param[in] actions
8059  *   Pointer to the list of actions.
8060  * @param[out] error
8061  *   Pointer to the error structure.
8062  *
8063  * @return
8064  *   Pointer to mlx5_flow object on success,
8065  *   otherwise NULL and rte_errno is set.
8066  */
8067 static struct mlx5_flow *
8068 flow_dv_prepare(struct rte_eth_dev *dev,
8069 		const struct rte_flow_attr *attr __rte_unused,
8070 		const struct rte_flow_item items[] __rte_unused,
8071 		const struct rte_flow_action actions[] __rte_unused,
8072 		struct rte_flow_error *error)
8073 {
8074 	uint32_t handle_idx = 0;
8075 	struct mlx5_flow *dev_flow;
8076 	struct mlx5_flow_handle *dev_handle;
8077 	struct mlx5_priv *priv = dev->data->dev_private;
8078 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
8079 
8080 	MLX5_ASSERT(wks);
8081 	wks->skip_matcher_reg = 0;
8082 	wks->policy = NULL;
8083 	wks->final_policy = NULL;
8084 	/* In case of corrupting the memory. */
8085 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
8086 		rte_flow_error_set(error, ENOSPC,
8087 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8088 				   "not free temporary device flow");
8089 		return NULL;
8090 	}
8091 	dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
8092 				   &handle_idx);
8093 	if (!dev_handle) {
8094 		rte_flow_error_set(error, ENOMEM,
8095 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8096 				   "not enough memory to create flow handle");
8097 		return NULL;
8098 	}
8099 	MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows));
8100 	dev_flow = &wks->flows[wks->flow_idx++];
8101 	memset(dev_flow, 0, sizeof(*dev_flow));
8102 	dev_flow->handle = dev_handle;
8103 	dev_flow->handle_idx = handle_idx;
8104 	dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
8105 	dev_flow->ingress = attr->ingress;
8106 	dev_flow->dv.transfer = attr->transfer;
8107 	return dev_flow;
8108 }
8109 
8110 #ifdef RTE_LIBRTE_MLX5_DEBUG
8111 /**
8112  * Sanity check for match mask and value. Similar to check_valid_spec() in
8113  * kernel driver. If unmasked bit is present in value, it returns failure.
8114  *
8115  * @param match_mask
8116  *   pointer to match mask buffer.
8117  * @param match_value
8118  *   pointer to match value buffer.
8119  *
8120  * @return
8121  *   0 if valid, -EINVAL otherwise.
8122  */
8123 static int
8124 flow_dv_check_valid_spec(void *match_mask, void *match_value)
8125 {
8126 	uint8_t *m = match_mask;
8127 	uint8_t *v = match_value;
8128 	unsigned int i;
8129 
8130 	for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) {
8131 		if (v[i] & ~m[i]) {
8132 			DRV_LOG(ERR,
8133 				"match_value differs from match_criteria"
8134 				" %p[%u] != %p[%u]",
8135 				match_value, i, match_mask, i);
8136 			return -EINVAL;
8137 		}
8138 	}
8139 	return 0;
8140 }
8141 #endif
8142 
8143 /**
8144  * Add match of ip_version.
8145  *
8146  * @param[in] group
8147  *   Flow group.
8148  * @param[in] headers_v
8149  *   Values header pointer.
8150  * @param[in] headers_m
8151  *   Masks header pointer.
8152  * @param[in] ip_version
8153  *   The IP version to set.
8154  */
8155 static inline void
8156 flow_dv_set_match_ip_version(uint32_t group,
8157 			     void *headers_v,
8158 			     void *headers_m,
8159 			     uint8_t ip_version)
8160 {
8161 	if (group == 0)
8162 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
8163 	else
8164 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version,
8165 			 ip_version);
8166 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, ip_version);
8167 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0);
8168 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype, 0);
8169 }
8170 
8171 /**
8172  * Add Ethernet item to matcher and to the value.
8173  *
8174  * @param[in, out] matcher
8175  *   Flow matcher.
8176  * @param[in, out] key
8177  *   Flow matcher value.
8178  * @param[in] item
8179  *   Flow pattern to translate.
8180  * @param[in] inner
8181  *   Item is inner pattern.
8182  */
8183 static void
8184 flow_dv_translate_item_eth(void *matcher, void *key,
8185 			   const struct rte_flow_item *item, int inner,
8186 			   uint32_t group)
8187 {
8188 	const struct rte_flow_item_eth *eth_m = item->mask;
8189 	const struct rte_flow_item_eth *eth_v = item->spec;
8190 	const struct rte_flow_item_eth nic_mask = {
8191 		.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8192 		.src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8193 		.type = RTE_BE16(0xffff),
8194 		.has_vlan = 0,
8195 	};
8196 	void *hdrs_m;
8197 	void *hdrs_v;
8198 	char *l24_v;
8199 	unsigned int i;
8200 
8201 	if (!eth_v)
8202 		return;
8203 	if (!eth_m)
8204 		eth_m = &nic_mask;
8205 	if (inner) {
8206 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8207 					 inner_headers);
8208 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8209 	} else {
8210 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8211 					 outer_headers);
8212 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8213 	}
8214 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, dmac_47_16),
8215 	       &eth_m->dst, sizeof(eth_m->dst));
8216 	/* The value must be in the range of the mask. */
8217 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16);
8218 	for (i = 0; i < sizeof(eth_m->dst); ++i)
8219 		l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i];
8220 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, smac_47_16),
8221 	       &eth_m->src, sizeof(eth_m->src));
8222 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16);
8223 	/* The value must be in the range of the mask. */
8224 	for (i = 0; i < sizeof(eth_m->dst); ++i)
8225 		l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i];
8226 	/*
8227 	 * HW supports match on one Ethertype, the Ethertype following the last
8228 	 * VLAN tag of the packet (see PRM).
8229 	 * Set match on ethertype only if ETH header is not followed by VLAN.
8230 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8231 	 * ethertype, and use ip_version field instead.
8232 	 * eCPRI over Ether layer will use type value 0xAEFE.
8233 	 */
8234 	if (eth_m->type == 0xFFFF) {
8235 		/* Set cvlan_tag mask for any single\multi\un-tagged case. */
8236 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8237 		switch (eth_v->type) {
8238 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8239 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8240 			return;
8241 		case RTE_BE16(RTE_ETHER_TYPE_QINQ):
8242 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8243 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8244 			return;
8245 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8246 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
8247 			return;
8248 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8249 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
8250 			return;
8251 		default:
8252 			break;
8253 		}
8254 	}
8255 	if (eth_m->has_vlan) {
8256 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8257 		if (eth_v->has_vlan) {
8258 			/*
8259 			 * Here, when also has_more_vlan field in VLAN item is
8260 			 * not set, only single-tagged packets will be matched.
8261 			 */
8262 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8263 			return;
8264 		}
8265 	}
8266 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
8267 		 rte_be_to_cpu_16(eth_m->type));
8268 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
8269 	*(uint16_t *)(l24_v) = eth_m->type & eth_v->type;
8270 }
8271 
8272 /**
8273  * Add VLAN item to matcher and to the value.
8274  *
8275  * @param[in, out] dev_flow
8276  *   Flow descriptor.
8277  * @param[in, out] matcher
8278  *   Flow matcher.
8279  * @param[in, out] key
8280  *   Flow matcher value.
8281  * @param[in] item
8282  *   Flow pattern to translate.
8283  * @param[in] inner
8284  *   Item is inner pattern.
8285  */
8286 static void
8287 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow,
8288 			    void *matcher, void *key,
8289 			    const struct rte_flow_item *item,
8290 			    int inner, uint32_t group)
8291 {
8292 	const struct rte_flow_item_vlan *vlan_m = item->mask;
8293 	const struct rte_flow_item_vlan *vlan_v = item->spec;
8294 	void *hdrs_m;
8295 	void *hdrs_v;
8296 	uint16_t tci_m;
8297 	uint16_t tci_v;
8298 
8299 	if (inner) {
8300 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8301 					 inner_headers);
8302 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8303 	} else {
8304 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8305 					 outer_headers);
8306 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8307 		/*
8308 		 * This is workaround, masks are not supported,
8309 		 * and pre-validated.
8310 		 */
8311 		if (vlan_v)
8312 			dev_flow->handle->vf_vlan.tag =
8313 					rte_be_to_cpu_16(vlan_v->tci) & 0x0fff;
8314 	}
8315 	/*
8316 	 * When VLAN item exists in flow, mark packet as tagged,
8317 	 * even if TCI is not specified.
8318 	 */
8319 	if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag)) {
8320 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8321 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8322 	}
8323 	if (!vlan_v)
8324 		return;
8325 	if (!vlan_m)
8326 		vlan_m = &rte_flow_item_vlan_mask;
8327 	tci_m = rte_be_to_cpu_16(vlan_m->tci);
8328 	tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci);
8329 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_vid, tci_m);
8330 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v);
8331 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_cfi, tci_m >> 12);
8332 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12);
8333 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_prio, tci_m >> 13);
8334 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13);
8335 	/*
8336 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8337 	 * ethertype, and use ip_version field instead.
8338 	 */
8339 	if (vlan_m->inner_type == 0xFFFF) {
8340 		switch (vlan_v->inner_type) {
8341 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8342 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8343 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8344 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
8345 			return;
8346 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8347 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
8348 			return;
8349 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8350 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
8351 			return;
8352 		default:
8353 			break;
8354 		}
8355 	}
8356 	if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) {
8357 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8358 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8359 		/* Only one vlan_tag bit can be set. */
8360 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
8361 		return;
8362 	}
8363 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
8364 		 rte_be_to_cpu_16(vlan_m->inner_type));
8365 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype,
8366 		 rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type));
8367 }
8368 
8369 /**
8370  * Add IPV4 item to matcher and to the value.
8371  *
8372  * @param[in, out] matcher
8373  *   Flow matcher.
8374  * @param[in, out] key
8375  *   Flow matcher value.
8376  * @param[in] item
8377  *   Flow pattern to translate.
8378  * @param[in] inner
8379  *   Item is inner pattern.
8380  * @param[in] group
8381  *   The group to insert the rule.
8382  */
8383 static void
8384 flow_dv_translate_item_ipv4(void *matcher, void *key,
8385 			    const struct rte_flow_item *item,
8386 			    int inner, uint32_t group)
8387 {
8388 	const struct rte_flow_item_ipv4 *ipv4_m = item->mask;
8389 	const struct rte_flow_item_ipv4 *ipv4_v = item->spec;
8390 	const struct rte_flow_item_ipv4 nic_mask = {
8391 		.hdr = {
8392 			.src_addr = RTE_BE32(0xffffffff),
8393 			.dst_addr = RTE_BE32(0xffffffff),
8394 			.type_of_service = 0xff,
8395 			.next_proto_id = 0xff,
8396 			.time_to_live = 0xff,
8397 		},
8398 	};
8399 	void *headers_m;
8400 	void *headers_v;
8401 	char *l24_m;
8402 	char *l24_v;
8403 	uint8_t tos, ihl_m, ihl_v;
8404 
8405 	if (inner) {
8406 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8407 					 inner_headers);
8408 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8409 	} else {
8410 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8411 					 outer_headers);
8412 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8413 	}
8414 	flow_dv_set_match_ip_version(group, headers_v, headers_m, 4);
8415 	if (!ipv4_v)
8416 		return;
8417 	if (!ipv4_m)
8418 		ipv4_m = &nic_mask;
8419 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8420 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
8421 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8422 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
8423 	*(uint32_t *)l24_m = ipv4_m->hdr.dst_addr;
8424 	*(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr;
8425 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8426 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
8427 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8428 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
8429 	*(uint32_t *)l24_m = ipv4_m->hdr.src_addr;
8430 	*(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr;
8431 	tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service;
8432 	ihl_m = ipv4_m->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK;
8433 	ihl_v = ipv4_v->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK;
8434 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_ihl, ihl_m);
8435 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_ihl, ihl_m & ihl_v);
8436 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn,
8437 		 ipv4_m->hdr.type_of_service);
8438 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos);
8439 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp,
8440 		 ipv4_m->hdr.type_of_service >> 2);
8441 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2);
8442 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8443 		 ipv4_m->hdr.next_proto_id);
8444 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8445 		 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id);
8446 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
8447 		 ipv4_m->hdr.time_to_live);
8448 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8449 		 ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live);
8450 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
8451 		 !!(ipv4_m->hdr.fragment_offset));
8452 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8453 		 !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset));
8454 }
8455 
8456 /**
8457  * Add IPV6 item to matcher and to the value.
8458  *
8459  * @param[in, out] matcher
8460  *   Flow matcher.
8461  * @param[in, out] key
8462  *   Flow matcher value.
8463  * @param[in] item
8464  *   Flow pattern to translate.
8465  * @param[in] inner
8466  *   Item is inner pattern.
8467  * @param[in] group
8468  *   The group to insert the rule.
8469  */
8470 static void
8471 flow_dv_translate_item_ipv6(void *matcher, void *key,
8472 			    const struct rte_flow_item *item,
8473 			    int inner, uint32_t group)
8474 {
8475 	const struct rte_flow_item_ipv6 *ipv6_m = item->mask;
8476 	const struct rte_flow_item_ipv6 *ipv6_v = item->spec;
8477 	const struct rte_flow_item_ipv6 nic_mask = {
8478 		.hdr = {
8479 			.src_addr =
8480 				"\xff\xff\xff\xff\xff\xff\xff\xff"
8481 				"\xff\xff\xff\xff\xff\xff\xff\xff",
8482 			.dst_addr =
8483 				"\xff\xff\xff\xff\xff\xff\xff\xff"
8484 				"\xff\xff\xff\xff\xff\xff\xff\xff",
8485 			.vtc_flow = RTE_BE32(0xffffffff),
8486 			.proto = 0xff,
8487 			.hop_limits = 0xff,
8488 		},
8489 	};
8490 	void *headers_m;
8491 	void *headers_v;
8492 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8493 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8494 	char *l24_m;
8495 	char *l24_v;
8496 	uint32_t vtc_m;
8497 	uint32_t vtc_v;
8498 	int i;
8499 	int size;
8500 
8501 	if (inner) {
8502 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8503 					 inner_headers);
8504 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8505 	} else {
8506 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8507 					 outer_headers);
8508 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8509 	}
8510 	flow_dv_set_match_ip_version(group, headers_v, headers_m, 6);
8511 	if (!ipv6_v)
8512 		return;
8513 	if (!ipv6_m)
8514 		ipv6_m = &nic_mask;
8515 	size = sizeof(ipv6_m->hdr.dst_addr);
8516 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8517 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
8518 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8519 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
8520 	memcpy(l24_m, ipv6_m->hdr.dst_addr, size);
8521 	for (i = 0; i < size; ++i)
8522 		l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i];
8523 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8524 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
8525 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8526 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
8527 	memcpy(l24_m, ipv6_m->hdr.src_addr, size);
8528 	for (i = 0; i < size; ++i)
8529 		l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i];
8530 	/* TOS. */
8531 	vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow);
8532 	vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow);
8533 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20);
8534 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20);
8535 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22);
8536 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22);
8537 	/* Label. */
8538 	if (inner) {
8539 		MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label,
8540 			 vtc_m);
8541 		MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label,
8542 			 vtc_v);
8543 	} else {
8544 		MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label,
8545 			 vtc_m);
8546 		MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label,
8547 			 vtc_v);
8548 	}
8549 	/* Protocol. */
8550 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8551 		 ipv6_m->hdr.proto);
8552 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8553 		 ipv6_v->hdr.proto & ipv6_m->hdr.proto);
8554 	/* Hop limit. */
8555 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
8556 		 ipv6_m->hdr.hop_limits);
8557 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8558 		 ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits);
8559 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
8560 		 !!(ipv6_m->has_frag_ext));
8561 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8562 		 !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext));
8563 }
8564 
8565 /**
8566  * Add IPV6 fragment extension item to matcher and to the value.
8567  *
8568  * @param[in, out] matcher
8569  *   Flow matcher.
8570  * @param[in, out] key
8571  *   Flow matcher value.
8572  * @param[in] item
8573  *   Flow pattern to translate.
8574  * @param[in] inner
8575  *   Item is inner pattern.
8576  */
8577 static void
8578 flow_dv_translate_item_ipv6_frag_ext(void *matcher, void *key,
8579 				     const struct rte_flow_item *item,
8580 				     int inner)
8581 {
8582 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m = item->mask;
8583 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v = item->spec;
8584 	const struct rte_flow_item_ipv6_frag_ext nic_mask = {
8585 		.hdr = {
8586 			.next_header = 0xff,
8587 			.frag_data = RTE_BE16(0xffff),
8588 		},
8589 	};
8590 	void *headers_m;
8591 	void *headers_v;
8592 
8593 	if (inner) {
8594 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8595 					 inner_headers);
8596 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8597 	} else {
8598 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8599 					 outer_headers);
8600 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8601 	}
8602 	/* IPv6 fragment extension item exists, so packet is IP fragment. */
8603 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 1);
8604 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1);
8605 	if (!ipv6_frag_ext_v)
8606 		return;
8607 	if (!ipv6_frag_ext_m)
8608 		ipv6_frag_ext_m = &nic_mask;
8609 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8610 		 ipv6_frag_ext_m->hdr.next_header);
8611 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8612 		 ipv6_frag_ext_v->hdr.next_header &
8613 		 ipv6_frag_ext_m->hdr.next_header);
8614 }
8615 
8616 /**
8617  * Add TCP item to matcher and to the value.
8618  *
8619  * @param[in, out] matcher
8620  *   Flow matcher.
8621  * @param[in, out] key
8622  *   Flow matcher value.
8623  * @param[in] item
8624  *   Flow pattern to translate.
8625  * @param[in] inner
8626  *   Item is inner pattern.
8627  */
8628 static void
8629 flow_dv_translate_item_tcp(void *matcher, void *key,
8630 			   const struct rte_flow_item *item,
8631 			   int inner)
8632 {
8633 	const struct rte_flow_item_tcp *tcp_m = item->mask;
8634 	const struct rte_flow_item_tcp *tcp_v = item->spec;
8635 	void *headers_m;
8636 	void *headers_v;
8637 
8638 	if (inner) {
8639 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8640 					 inner_headers);
8641 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8642 	} else {
8643 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8644 					 outer_headers);
8645 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8646 	}
8647 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8648 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP);
8649 	if (!tcp_v)
8650 		return;
8651 	if (!tcp_m)
8652 		tcp_m = &rte_flow_item_tcp_mask;
8653 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport,
8654 		 rte_be_to_cpu_16(tcp_m->hdr.src_port));
8655 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
8656 		 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port));
8657 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport,
8658 		 rte_be_to_cpu_16(tcp_m->hdr.dst_port));
8659 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
8660 		 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port));
8661 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags,
8662 		 tcp_m->hdr.tcp_flags);
8663 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
8664 		 (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags));
8665 }
8666 
8667 /**
8668  * Add UDP item to matcher and to the value.
8669  *
8670  * @param[in, out] matcher
8671  *   Flow matcher.
8672  * @param[in, out] key
8673  *   Flow matcher value.
8674  * @param[in] item
8675  *   Flow pattern to translate.
8676  * @param[in] inner
8677  *   Item is inner pattern.
8678  */
8679 static void
8680 flow_dv_translate_item_udp(void *matcher, void *key,
8681 			   const struct rte_flow_item *item,
8682 			   int inner)
8683 {
8684 	const struct rte_flow_item_udp *udp_m = item->mask;
8685 	const struct rte_flow_item_udp *udp_v = item->spec;
8686 	void *headers_m;
8687 	void *headers_v;
8688 
8689 	if (inner) {
8690 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8691 					 inner_headers);
8692 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8693 	} else {
8694 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8695 					 outer_headers);
8696 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8697 	}
8698 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8699 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
8700 	if (!udp_v)
8701 		return;
8702 	if (!udp_m)
8703 		udp_m = &rte_flow_item_udp_mask;
8704 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport,
8705 		 rte_be_to_cpu_16(udp_m->hdr.src_port));
8706 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
8707 		 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port));
8708 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport,
8709 		 rte_be_to_cpu_16(udp_m->hdr.dst_port));
8710 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
8711 		 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port));
8712 }
8713 
8714 /**
8715  * Add GRE optional Key item to matcher and to the value.
8716  *
8717  * @param[in, out] matcher
8718  *   Flow matcher.
8719  * @param[in, out] key
8720  *   Flow matcher value.
8721  * @param[in] item
8722  *   Flow pattern to translate.
8723  * @param[in] inner
8724  *   Item is inner pattern.
8725  */
8726 static void
8727 flow_dv_translate_item_gre_key(void *matcher, void *key,
8728 				   const struct rte_flow_item *item)
8729 {
8730 	const rte_be32_t *key_m = item->mask;
8731 	const rte_be32_t *key_v = item->spec;
8732 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8733 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8734 	rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX);
8735 
8736 	/* GRE K bit must be on and should already be validated */
8737 	MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1);
8738 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1);
8739 	if (!key_v)
8740 		return;
8741 	if (!key_m)
8742 		key_m = &gre_key_default_mask;
8743 	MLX5_SET(fte_match_set_misc, misc_m, gre_key_h,
8744 		 rte_be_to_cpu_32(*key_m) >> 8);
8745 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_h,
8746 		 rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8);
8747 	MLX5_SET(fte_match_set_misc, misc_m, gre_key_l,
8748 		 rte_be_to_cpu_32(*key_m) & 0xFF);
8749 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_l,
8750 		 rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF);
8751 }
8752 
8753 /**
8754  * Add GRE item to matcher and to the value.
8755  *
8756  * @param[in, out] matcher
8757  *   Flow matcher.
8758  * @param[in, out] key
8759  *   Flow matcher value.
8760  * @param[in] item
8761  *   Flow pattern to translate.
8762  * @param[in] inner
8763  *   Item is inner pattern.
8764  */
8765 static void
8766 flow_dv_translate_item_gre(void *matcher, void *key,
8767 			   const struct rte_flow_item *item,
8768 			   int inner)
8769 {
8770 	const struct rte_flow_item_gre *gre_m = item->mask;
8771 	const struct rte_flow_item_gre *gre_v = item->spec;
8772 	void *headers_m;
8773 	void *headers_v;
8774 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8775 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8776 	struct {
8777 		union {
8778 			__extension__
8779 			struct {
8780 				uint16_t version:3;
8781 				uint16_t rsvd0:9;
8782 				uint16_t s_present:1;
8783 				uint16_t k_present:1;
8784 				uint16_t rsvd_bit1:1;
8785 				uint16_t c_present:1;
8786 			};
8787 			uint16_t value;
8788 		};
8789 	} gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v;
8790 
8791 	if (inner) {
8792 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8793 					 inner_headers);
8794 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8795 	} else {
8796 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8797 					 outer_headers);
8798 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8799 	}
8800 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8801 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
8802 	if (!gre_v)
8803 		return;
8804 	if (!gre_m)
8805 		gre_m = &rte_flow_item_gre_mask;
8806 	MLX5_SET(fte_match_set_misc, misc_m, gre_protocol,
8807 		 rte_be_to_cpu_16(gre_m->protocol));
8808 	MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
8809 		 rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol));
8810 	gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver);
8811 	gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver);
8812 	MLX5_SET(fte_match_set_misc, misc_m, gre_c_present,
8813 		 gre_crks_rsvd0_ver_m.c_present);
8814 	MLX5_SET(fte_match_set_misc, misc_v, gre_c_present,
8815 		 gre_crks_rsvd0_ver_v.c_present &
8816 		 gre_crks_rsvd0_ver_m.c_present);
8817 	MLX5_SET(fte_match_set_misc, misc_m, gre_k_present,
8818 		 gre_crks_rsvd0_ver_m.k_present);
8819 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present,
8820 		 gre_crks_rsvd0_ver_v.k_present &
8821 		 gre_crks_rsvd0_ver_m.k_present);
8822 	MLX5_SET(fte_match_set_misc, misc_m, gre_s_present,
8823 		 gre_crks_rsvd0_ver_m.s_present);
8824 	MLX5_SET(fte_match_set_misc, misc_v, gre_s_present,
8825 		 gre_crks_rsvd0_ver_v.s_present &
8826 		 gre_crks_rsvd0_ver_m.s_present);
8827 }
8828 
8829 /**
8830  * Add NVGRE item to matcher and to the value.
8831  *
8832  * @param[in, out] matcher
8833  *   Flow matcher.
8834  * @param[in, out] key
8835  *   Flow matcher value.
8836  * @param[in] item
8837  *   Flow pattern to translate.
8838  * @param[in] inner
8839  *   Item is inner pattern.
8840  */
8841 static void
8842 flow_dv_translate_item_nvgre(void *matcher, void *key,
8843 			     const struct rte_flow_item *item,
8844 			     int inner)
8845 {
8846 	const struct rte_flow_item_nvgre *nvgre_m = item->mask;
8847 	const struct rte_flow_item_nvgre *nvgre_v = item->spec;
8848 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8849 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8850 	const char *tni_flow_id_m;
8851 	const char *tni_flow_id_v;
8852 	char *gre_key_m;
8853 	char *gre_key_v;
8854 	int size;
8855 	int i;
8856 
8857 	/* For NVGRE, GRE header fields must be set with defined values. */
8858 	const struct rte_flow_item_gre gre_spec = {
8859 		.c_rsvd0_ver = RTE_BE16(0x2000),
8860 		.protocol = RTE_BE16(RTE_ETHER_TYPE_TEB)
8861 	};
8862 	const struct rte_flow_item_gre gre_mask = {
8863 		.c_rsvd0_ver = RTE_BE16(0xB000),
8864 		.protocol = RTE_BE16(UINT16_MAX),
8865 	};
8866 	const struct rte_flow_item gre_item = {
8867 		.spec = &gre_spec,
8868 		.mask = &gre_mask,
8869 		.last = NULL,
8870 	};
8871 	flow_dv_translate_item_gre(matcher, key, &gre_item, inner);
8872 	if (!nvgre_v)
8873 		return;
8874 	if (!nvgre_m)
8875 		nvgre_m = &rte_flow_item_nvgre_mask;
8876 	tni_flow_id_m = (const char *)nvgre_m->tni;
8877 	tni_flow_id_v = (const char *)nvgre_v->tni;
8878 	size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
8879 	gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h);
8880 	gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
8881 	memcpy(gre_key_m, tni_flow_id_m, size);
8882 	for (i = 0; i < size; ++i)
8883 		gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i];
8884 }
8885 
8886 /**
8887  * Add VXLAN item to matcher and to the value.
8888  *
8889  * @param[in] dev
8890  *   Pointer to the Ethernet device structure.
8891  * @param[in] attr
8892  *   Flow rule attributes.
8893  * @param[in, out] matcher
8894  *   Flow matcher.
8895  * @param[in, out] key
8896  *   Flow matcher value.
8897  * @param[in] item
8898  *   Flow pattern to translate.
8899  * @param[in] inner
8900  *   Item is inner pattern.
8901  */
8902 static void
8903 flow_dv_translate_item_vxlan(struct rte_eth_dev *dev,
8904 			     const struct rte_flow_attr *attr,
8905 			     void *matcher, void *key,
8906 			     const struct rte_flow_item *item,
8907 			     int inner)
8908 {
8909 	const struct rte_flow_item_vxlan *vxlan_m = item->mask;
8910 	const struct rte_flow_item_vxlan *vxlan_v = item->spec;
8911 	void *headers_m;
8912 	void *headers_v;
8913 	void *misc5_m;
8914 	void *misc5_v;
8915 	uint32_t *tunnel_header_v;
8916 	uint32_t *tunnel_header_m;
8917 	uint16_t dport;
8918 	struct mlx5_priv *priv = dev->data->dev_private;
8919 	const struct rte_flow_item_vxlan nic_mask = {
8920 		.vni = "\xff\xff\xff",
8921 		.rsvd1 = 0xff,
8922 	};
8923 
8924 	if (inner) {
8925 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8926 					 inner_headers);
8927 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8928 	} else {
8929 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8930 					 outer_headers);
8931 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8932 	}
8933 	dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
8934 		MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
8935 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8936 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8937 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8938 	}
8939 	dport = MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport);
8940 	if (!vxlan_v)
8941 		return;
8942 	if (!vxlan_m) {
8943 		if ((!attr->group && !priv->sh->tunnel_header_0_1) ||
8944 		    (attr->group && !priv->sh->misc5_cap))
8945 			vxlan_m = &rte_flow_item_vxlan_mask;
8946 		else
8947 			vxlan_m = &nic_mask;
8948 	}
8949 	if ((priv->sh->steering_format_version ==
8950 	    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 &&
8951 	    dport != MLX5_UDP_PORT_VXLAN) ||
8952 	    (!attr->group && !attr->transfer && !priv->sh->tunnel_header_0_1) ||
8953 	    ((attr->group || attr->transfer) && !priv->sh->misc5_cap)) {
8954 		void *misc_m;
8955 		void *misc_v;
8956 		char *vni_m;
8957 		char *vni_v;
8958 		int size;
8959 		int i;
8960 		misc_m = MLX5_ADDR_OF(fte_match_param,
8961 				      matcher, misc_parameters);
8962 		misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8963 		size = sizeof(vxlan_m->vni);
8964 		vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni);
8965 		vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni);
8966 		memcpy(vni_m, vxlan_m->vni, size);
8967 		for (i = 0; i < size; ++i)
8968 			vni_v[i] = vni_m[i] & vxlan_v->vni[i];
8969 		return;
8970 	}
8971 	misc5_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_5);
8972 	misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5);
8973 	tunnel_header_v = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5,
8974 						   misc5_v,
8975 						   tunnel_header_1);
8976 	tunnel_header_m = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5,
8977 						   misc5_m,
8978 						   tunnel_header_1);
8979 	*tunnel_header_v = (vxlan_v->vni[0] & vxlan_m->vni[0]) |
8980 			   (vxlan_v->vni[1] & vxlan_m->vni[1]) << 8 |
8981 			   (vxlan_v->vni[2] & vxlan_m->vni[2]) << 16;
8982 	if (*tunnel_header_v)
8983 		*tunnel_header_m = vxlan_m->vni[0] |
8984 			vxlan_m->vni[1] << 8 |
8985 			vxlan_m->vni[2] << 16;
8986 	else
8987 		*tunnel_header_m = 0x0;
8988 	*tunnel_header_v |= (vxlan_v->rsvd1 & vxlan_m->rsvd1) << 24;
8989 	if (vxlan_v->rsvd1 & vxlan_m->rsvd1)
8990 		*tunnel_header_m |= vxlan_m->rsvd1 << 24;
8991 }
8992 
8993 /**
8994  * Add VXLAN-GPE item to matcher and to the value.
8995  *
8996  * @param[in, out] matcher
8997  *   Flow matcher.
8998  * @param[in, out] key
8999  *   Flow matcher value.
9000  * @param[in] item
9001  *   Flow pattern to translate.
9002  * @param[in] inner
9003  *   Item is inner pattern.
9004  */
9005 
9006 static void
9007 flow_dv_translate_item_vxlan_gpe(void *matcher, void *key,
9008 				 const struct rte_flow_item *item, int inner)
9009 {
9010 	const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask;
9011 	const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec;
9012 	void *headers_m;
9013 	void *headers_v;
9014 	void *misc_m =
9015 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_3);
9016 	void *misc_v =
9017 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9018 	char *vni_m;
9019 	char *vni_v;
9020 	uint16_t dport;
9021 	int size;
9022 	int i;
9023 	uint8_t flags_m = 0xff;
9024 	uint8_t flags_v = 0xc;
9025 
9026 	if (inner) {
9027 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9028 					 inner_headers);
9029 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9030 	} else {
9031 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9032 					 outer_headers);
9033 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9034 	}
9035 	dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
9036 		MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
9037 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9038 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
9039 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
9040 	}
9041 	if (!vxlan_v)
9042 		return;
9043 	if (!vxlan_m)
9044 		vxlan_m = &rte_flow_item_vxlan_gpe_mask;
9045 	size = sizeof(vxlan_m->vni);
9046 	vni_m = MLX5_ADDR_OF(fte_match_set_misc3, misc_m, outer_vxlan_gpe_vni);
9047 	vni_v = MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni);
9048 	memcpy(vni_m, vxlan_m->vni, size);
9049 	for (i = 0; i < size; ++i)
9050 		vni_v[i] = vni_m[i] & vxlan_v->vni[i];
9051 	if (vxlan_m->flags) {
9052 		flags_m = vxlan_m->flags;
9053 		flags_v = vxlan_v->flags;
9054 	}
9055 	MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_flags, flags_m);
9056 	MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_flags, flags_v);
9057 	MLX5_SET(fte_match_set_misc3, misc_m, outer_vxlan_gpe_next_protocol,
9058 		 vxlan_m->protocol);
9059 	MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_next_protocol,
9060 		 vxlan_v->protocol);
9061 }
9062 
9063 /**
9064  * Add Geneve item to matcher and to the value.
9065  *
9066  * @param[in, out] matcher
9067  *   Flow matcher.
9068  * @param[in, out] key
9069  *   Flow matcher value.
9070  * @param[in] item
9071  *   Flow pattern to translate.
9072  * @param[in] inner
9073  *   Item is inner pattern.
9074  */
9075 
9076 static void
9077 flow_dv_translate_item_geneve(void *matcher, void *key,
9078 			      const struct rte_flow_item *item, int inner)
9079 {
9080 	const struct rte_flow_item_geneve *geneve_m = item->mask;
9081 	const struct rte_flow_item_geneve *geneve_v = item->spec;
9082 	void *headers_m;
9083 	void *headers_v;
9084 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9085 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9086 	uint16_t dport;
9087 	uint16_t gbhdr_m;
9088 	uint16_t gbhdr_v;
9089 	char *vni_m;
9090 	char *vni_v;
9091 	size_t size, i;
9092 
9093 	if (inner) {
9094 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9095 					 inner_headers);
9096 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9097 	} else {
9098 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9099 					 outer_headers);
9100 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9101 	}
9102 	dport = MLX5_UDP_PORT_GENEVE;
9103 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9104 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
9105 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
9106 	}
9107 	if (!geneve_v)
9108 		return;
9109 	if (!geneve_m)
9110 		geneve_m = &rte_flow_item_geneve_mask;
9111 	size = sizeof(geneve_m->vni);
9112 	vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, geneve_vni);
9113 	vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni);
9114 	memcpy(vni_m, geneve_m->vni, size);
9115 	for (i = 0; i < size; ++i)
9116 		vni_v[i] = vni_m[i] & geneve_v->vni[i];
9117 	MLX5_SET(fte_match_set_misc, misc_m, geneve_protocol_type,
9118 		 rte_be_to_cpu_16(geneve_m->protocol));
9119 	MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type,
9120 		 rte_be_to_cpu_16(geneve_v->protocol & geneve_m->protocol));
9121 	gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0);
9122 	gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0);
9123 	MLX5_SET(fte_match_set_misc, misc_m, geneve_oam,
9124 		 MLX5_GENEVE_OAMF_VAL(gbhdr_m));
9125 	MLX5_SET(fte_match_set_misc, misc_v, geneve_oam,
9126 		 MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m));
9127 	MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
9128 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
9129 	MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9130 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) &
9131 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
9132 }
9133 
9134 /**
9135  * Create Geneve TLV option resource.
9136  *
9137  * @param dev[in, out]
9138  *   Pointer to rte_eth_dev structure.
9139  * @param[in, out] tag_be24
9140  *   Tag value in big endian then R-shift 8.
9141  * @parm[in, out] dev_flow
9142  *   Pointer to the dev_flow.
9143  * @param[out] error
9144  *   pointer to error structure.
9145  *
9146  * @return
9147  *   0 on success otherwise -errno and errno is set.
9148  */
9149 
9150 int
9151 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev,
9152 					     const struct rte_flow_item *item,
9153 					     struct rte_flow_error *error)
9154 {
9155 	struct mlx5_priv *priv = dev->data->dev_private;
9156 	struct mlx5_dev_ctx_shared *sh = priv->sh;
9157 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
9158 			sh->geneve_tlv_option_resource;
9159 	struct mlx5_devx_obj *obj;
9160 	const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
9161 	int ret = 0;
9162 
9163 	if (!geneve_opt_v)
9164 		return -1;
9165 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
9166 	if (geneve_opt_resource != NULL) {
9167 		if (geneve_opt_resource->option_class ==
9168 			geneve_opt_v->option_class &&
9169 			geneve_opt_resource->option_type ==
9170 			geneve_opt_v->option_type &&
9171 			geneve_opt_resource->length ==
9172 			geneve_opt_v->option_len) {
9173 			/* We already have GENVE TLV option obj allocated. */
9174 			__atomic_fetch_add(&geneve_opt_resource->refcnt, 1,
9175 					   __ATOMIC_RELAXED);
9176 		} else {
9177 			ret = rte_flow_error_set(error, ENOMEM,
9178 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9179 				"Only one GENEVE TLV option supported");
9180 			goto exit;
9181 		}
9182 	} else {
9183 		/* Create a GENEVE TLV object and resource. */
9184 		obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->ctx,
9185 				geneve_opt_v->option_class,
9186 				geneve_opt_v->option_type,
9187 				geneve_opt_v->option_len);
9188 		if (!obj) {
9189 			ret = rte_flow_error_set(error, ENODATA,
9190 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9191 				"Failed to create GENEVE TLV Devx object");
9192 			goto exit;
9193 		}
9194 		sh->geneve_tlv_option_resource =
9195 				mlx5_malloc(MLX5_MEM_ZERO,
9196 						sizeof(*geneve_opt_resource),
9197 						0, SOCKET_ID_ANY);
9198 		if (!sh->geneve_tlv_option_resource) {
9199 			claim_zero(mlx5_devx_cmd_destroy(obj));
9200 			ret = rte_flow_error_set(error, ENOMEM,
9201 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9202 				"GENEVE TLV object memory allocation failed");
9203 			goto exit;
9204 		}
9205 		geneve_opt_resource = sh->geneve_tlv_option_resource;
9206 		geneve_opt_resource->obj = obj;
9207 		geneve_opt_resource->option_class = geneve_opt_v->option_class;
9208 		geneve_opt_resource->option_type = geneve_opt_v->option_type;
9209 		geneve_opt_resource->length = geneve_opt_v->option_len;
9210 		__atomic_store_n(&geneve_opt_resource->refcnt, 1,
9211 				__ATOMIC_RELAXED);
9212 	}
9213 exit:
9214 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
9215 	return ret;
9216 }
9217 
9218 /**
9219  * Add Geneve TLV option item to matcher.
9220  *
9221  * @param[in, out] dev
9222  *   Pointer to rte_eth_dev structure.
9223  * @param[in, out] matcher
9224  *   Flow matcher.
9225  * @param[in, out] key
9226  *   Flow matcher value.
9227  * @param[in] item
9228  *   Flow pattern to translate.
9229  * @param[out] error
9230  *   Pointer to error structure.
9231  */
9232 static int
9233 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *matcher,
9234 				  void *key, const struct rte_flow_item *item,
9235 				  struct rte_flow_error *error)
9236 {
9237 	const struct rte_flow_item_geneve_opt *geneve_opt_m = item->mask;
9238 	const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
9239 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9240 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9241 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9242 			misc_parameters_3);
9243 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9244 	rte_be32_t opt_data_key = 0, opt_data_mask = 0;
9245 	int ret = 0;
9246 
9247 	if (!geneve_opt_v)
9248 		return -1;
9249 	if (!geneve_opt_m)
9250 		geneve_opt_m = &rte_flow_item_geneve_opt_mask;
9251 	ret = flow_dev_geneve_tlv_option_resource_register(dev, item,
9252 							   error);
9253 	if (ret) {
9254 		DRV_LOG(ERR, "Failed to create geneve_tlv_obj");
9255 		return ret;
9256 	}
9257 	/*
9258 	 * Set the option length in GENEVE header if not requested.
9259 	 * The GENEVE TLV option length is expressed by the option length field
9260 	 * in the GENEVE header.
9261 	 * If the option length was not requested but the GENEVE TLV option item
9262 	 * is present we set the option length field implicitly.
9263 	 */
9264 	if (!MLX5_GET16(fte_match_set_misc, misc_m, geneve_opt_len)) {
9265 		MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
9266 			 MLX5_GENEVE_OPTLEN_MASK);
9267 		MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9268 			 geneve_opt_v->option_len + 1);
9269 	}
9270 	MLX5_SET(fte_match_set_misc, misc_m, geneve_tlv_option_0_exist, 1);
9271 	MLX5_SET(fte_match_set_misc, misc_v, geneve_tlv_option_0_exist, 1);
9272 	/* Set the data. */
9273 	if (geneve_opt_v->data) {
9274 		memcpy(&opt_data_key, geneve_opt_v->data,
9275 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9276 				sizeof(opt_data_key)));
9277 		MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
9278 				sizeof(opt_data_key));
9279 		memcpy(&opt_data_mask, geneve_opt_m->data,
9280 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9281 				sizeof(opt_data_mask)));
9282 		MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
9283 				sizeof(opt_data_mask));
9284 		MLX5_SET(fte_match_set_misc3, misc3_m,
9285 				geneve_tlv_option_0_data,
9286 				rte_be_to_cpu_32(opt_data_mask));
9287 		MLX5_SET(fte_match_set_misc3, misc3_v,
9288 				geneve_tlv_option_0_data,
9289 			rte_be_to_cpu_32(opt_data_key & opt_data_mask));
9290 	}
9291 	return ret;
9292 }
9293 
9294 /**
9295  * Add MPLS item to matcher and to the value.
9296  *
9297  * @param[in, out] matcher
9298  *   Flow matcher.
9299  * @param[in, out] key
9300  *   Flow matcher value.
9301  * @param[in] item
9302  *   Flow pattern to translate.
9303  * @param[in] prev_layer
9304  *   The protocol layer indicated in previous item.
9305  * @param[in] inner
9306  *   Item is inner pattern.
9307  */
9308 static void
9309 flow_dv_translate_item_mpls(void *matcher, void *key,
9310 			    const struct rte_flow_item *item,
9311 			    uint64_t prev_layer,
9312 			    int inner)
9313 {
9314 	const uint32_t *in_mpls_m = item->mask;
9315 	const uint32_t *in_mpls_v = item->spec;
9316 	uint32_t *out_mpls_m = 0;
9317 	uint32_t *out_mpls_v = 0;
9318 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9319 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9320 	void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher,
9321 				     misc_parameters_2);
9322 	void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9323 	void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
9324 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9325 
9326 	switch (prev_layer) {
9327 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9328 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff);
9329 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9330 			 MLX5_UDP_PORT_MPLS);
9331 		break;
9332 	case MLX5_FLOW_LAYER_GRE:
9333 		/* Fall-through. */
9334 	case MLX5_FLOW_LAYER_GRE_KEY:
9335 		MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff);
9336 		MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
9337 			 RTE_ETHER_TYPE_MPLS);
9338 		break;
9339 	default:
9340 		break;
9341 	}
9342 	if (!in_mpls_v)
9343 		return;
9344 	if (!in_mpls_m)
9345 		in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask;
9346 	switch (prev_layer) {
9347 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9348 		out_mpls_m =
9349 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
9350 						 outer_first_mpls_over_udp);
9351 		out_mpls_v =
9352 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9353 						 outer_first_mpls_over_udp);
9354 		break;
9355 	case MLX5_FLOW_LAYER_GRE:
9356 		out_mpls_m =
9357 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
9358 						 outer_first_mpls_over_gre);
9359 		out_mpls_v =
9360 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9361 						 outer_first_mpls_over_gre);
9362 		break;
9363 	default:
9364 		/* Inner MPLS not over GRE is not supported. */
9365 		if (!inner) {
9366 			out_mpls_m =
9367 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
9368 							 misc2_m,
9369 							 outer_first_mpls);
9370 			out_mpls_v =
9371 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
9372 							 misc2_v,
9373 							 outer_first_mpls);
9374 		}
9375 		break;
9376 	}
9377 	if (out_mpls_m && out_mpls_v) {
9378 		*out_mpls_m = *in_mpls_m;
9379 		*out_mpls_v = *in_mpls_v & *in_mpls_m;
9380 	}
9381 }
9382 
9383 /**
9384  * Add metadata register item to matcher
9385  *
9386  * @param[in, out] matcher
9387  *   Flow matcher.
9388  * @param[in, out] key
9389  *   Flow matcher value.
9390  * @param[in] reg_type
9391  *   Type of device metadata register
9392  * @param[in] value
9393  *   Register value
9394  * @param[in] mask
9395  *   Register mask
9396  */
9397 static void
9398 flow_dv_match_meta_reg(void *matcher, void *key,
9399 		       enum modify_reg reg_type,
9400 		       uint32_t data, uint32_t mask)
9401 {
9402 	void *misc2_m =
9403 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2);
9404 	void *misc2_v =
9405 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9406 	uint32_t temp;
9407 
9408 	data &= mask;
9409 	switch (reg_type) {
9410 	case REG_A:
9411 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a, mask);
9412 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data);
9413 		break;
9414 	case REG_B:
9415 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_b, mask);
9416 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data);
9417 		break;
9418 	case REG_C_0:
9419 		/*
9420 		 * The metadata register C0 field might be divided into
9421 		 * source vport index and META item value, we should set
9422 		 * this field according to specified mask, not as whole one.
9423 		 */
9424 		temp = MLX5_GET(fte_match_set_misc2, misc2_m, metadata_reg_c_0);
9425 		temp |= mask;
9426 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_0, temp);
9427 		temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0);
9428 		temp &= ~mask;
9429 		temp |= data;
9430 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp);
9431 		break;
9432 	case REG_C_1:
9433 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_1, mask);
9434 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data);
9435 		break;
9436 	case REG_C_2:
9437 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_2, mask);
9438 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data);
9439 		break;
9440 	case REG_C_3:
9441 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_3, mask);
9442 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data);
9443 		break;
9444 	case REG_C_4:
9445 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_4, mask);
9446 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data);
9447 		break;
9448 	case REG_C_5:
9449 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_5, mask);
9450 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data);
9451 		break;
9452 	case REG_C_6:
9453 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_6, mask);
9454 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data);
9455 		break;
9456 	case REG_C_7:
9457 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_7, mask);
9458 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data);
9459 		break;
9460 	default:
9461 		MLX5_ASSERT(false);
9462 		break;
9463 	}
9464 }
9465 
9466 /**
9467  * Add MARK item to matcher
9468  *
9469  * @param[in] dev
9470  *   The device to configure through.
9471  * @param[in, out] matcher
9472  *   Flow matcher.
9473  * @param[in, out] key
9474  *   Flow matcher value.
9475  * @param[in] item
9476  *   Flow pattern to translate.
9477  */
9478 static void
9479 flow_dv_translate_item_mark(struct rte_eth_dev *dev,
9480 			    void *matcher, void *key,
9481 			    const struct rte_flow_item *item)
9482 {
9483 	struct mlx5_priv *priv = dev->data->dev_private;
9484 	const struct rte_flow_item_mark *mark;
9485 	uint32_t value;
9486 	uint32_t mask;
9487 
9488 	mark = item->mask ? (const void *)item->mask :
9489 			    &rte_flow_item_mark_mask;
9490 	mask = mark->id & priv->sh->dv_mark_mask;
9491 	mark = (const void *)item->spec;
9492 	MLX5_ASSERT(mark);
9493 	value = mark->id & priv->sh->dv_mark_mask & mask;
9494 	if (mask) {
9495 		enum modify_reg reg;
9496 
9497 		/* Get the metadata register index for the mark. */
9498 		reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL);
9499 		MLX5_ASSERT(reg > 0);
9500 		if (reg == REG_C_0) {
9501 			struct mlx5_priv *priv = dev->data->dev_private;
9502 			uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9503 			uint32_t shl_c0 = rte_bsf32(msk_c0);
9504 
9505 			mask &= msk_c0;
9506 			mask <<= shl_c0;
9507 			value <<= shl_c0;
9508 		}
9509 		flow_dv_match_meta_reg(matcher, key, reg, value, mask);
9510 	}
9511 }
9512 
9513 /**
9514  * Add META item to matcher
9515  *
9516  * @param[in] dev
9517  *   The devich to configure through.
9518  * @param[in, out] matcher
9519  *   Flow matcher.
9520  * @param[in, out] key
9521  *   Flow matcher value.
9522  * @param[in] attr
9523  *   Attributes of flow that includes this item.
9524  * @param[in] item
9525  *   Flow pattern to translate.
9526  */
9527 static void
9528 flow_dv_translate_item_meta(struct rte_eth_dev *dev,
9529 			    void *matcher, void *key,
9530 			    const struct rte_flow_attr *attr,
9531 			    const struct rte_flow_item *item)
9532 {
9533 	const struct rte_flow_item_meta *meta_m;
9534 	const struct rte_flow_item_meta *meta_v;
9535 
9536 	meta_m = (const void *)item->mask;
9537 	if (!meta_m)
9538 		meta_m = &rte_flow_item_meta_mask;
9539 	meta_v = (const void *)item->spec;
9540 	if (meta_v) {
9541 		int reg;
9542 		uint32_t value = meta_v->data;
9543 		uint32_t mask = meta_m->data;
9544 
9545 		reg = flow_dv_get_metadata_reg(dev, attr, NULL);
9546 		if (reg < 0)
9547 			return;
9548 		MLX5_ASSERT(reg != REG_NON);
9549 		if (reg == REG_C_0) {
9550 			struct mlx5_priv *priv = dev->data->dev_private;
9551 			uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9552 			uint32_t shl_c0 = rte_bsf32(msk_c0);
9553 
9554 			mask &= msk_c0;
9555 			mask <<= shl_c0;
9556 			value <<= shl_c0;
9557 		}
9558 		flow_dv_match_meta_reg(matcher, key, reg, value, mask);
9559 	}
9560 }
9561 
9562 /**
9563  * Add vport metadata Reg C0 item to matcher
9564  *
9565  * @param[in, out] matcher
9566  *   Flow matcher.
9567  * @param[in, out] key
9568  *   Flow matcher value.
9569  * @param[in] reg
9570  *   Flow pattern to translate.
9571  */
9572 static void
9573 flow_dv_translate_item_meta_vport(void *matcher, void *key,
9574 				  uint32_t value, uint32_t mask)
9575 {
9576 	flow_dv_match_meta_reg(matcher, key, REG_C_0, value, mask);
9577 }
9578 
9579 /**
9580  * Add tag item to matcher
9581  *
9582  * @param[in] dev
9583  *   The devich to configure through.
9584  * @param[in, out] matcher
9585  *   Flow matcher.
9586  * @param[in, out] key
9587  *   Flow matcher value.
9588  * @param[in] item
9589  *   Flow pattern to translate.
9590  */
9591 static void
9592 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev,
9593 				void *matcher, void *key,
9594 				const struct rte_flow_item *item)
9595 {
9596 	const struct mlx5_rte_flow_item_tag *tag_v = item->spec;
9597 	const struct mlx5_rte_flow_item_tag *tag_m = item->mask;
9598 	uint32_t mask, value;
9599 
9600 	MLX5_ASSERT(tag_v);
9601 	value = tag_v->data;
9602 	mask = tag_m ? tag_m->data : UINT32_MAX;
9603 	if (tag_v->id == REG_C_0) {
9604 		struct mlx5_priv *priv = dev->data->dev_private;
9605 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9606 		uint32_t shl_c0 = rte_bsf32(msk_c0);
9607 
9608 		mask &= msk_c0;
9609 		mask <<= shl_c0;
9610 		value <<= shl_c0;
9611 	}
9612 	flow_dv_match_meta_reg(matcher, key, tag_v->id, value, mask);
9613 }
9614 
9615 /**
9616  * Add TAG item to matcher
9617  *
9618  * @param[in] dev
9619  *   The devich to configure through.
9620  * @param[in, out] matcher
9621  *   Flow matcher.
9622  * @param[in, out] key
9623  *   Flow matcher value.
9624  * @param[in] item
9625  *   Flow pattern to translate.
9626  */
9627 static void
9628 flow_dv_translate_item_tag(struct rte_eth_dev *dev,
9629 			   void *matcher, void *key,
9630 			   const struct rte_flow_item *item)
9631 {
9632 	const struct rte_flow_item_tag *tag_v = item->spec;
9633 	const struct rte_flow_item_tag *tag_m = item->mask;
9634 	enum modify_reg reg;
9635 
9636 	MLX5_ASSERT(tag_v);
9637 	tag_m = tag_m ? tag_m : &rte_flow_item_tag_mask;
9638 	/* Get the metadata register index for the tag. */
9639 	reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, tag_v->index, NULL);
9640 	MLX5_ASSERT(reg > 0);
9641 	flow_dv_match_meta_reg(matcher, key, reg, tag_v->data, tag_m->data);
9642 }
9643 
9644 /**
9645  * Add source vport match to the specified matcher.
9646  *
9647  * @param[in, out] matcher
9648  *   Flow matcher.
9649  * @param[in, out] key
9650  *   Flow matcher value.
9651  * @param[in] port
9652  *   Source vport value to match
9653  * @param[in] mask
9654  *   Mask
9655  */
9656 static void
9657 flow_dv_translate_item_source_vport(void *matcher, void *key,
9658 				    int16_t port, uint16_t mask)
9659 {
9660 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9661 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9662 
9663 	MLX5_SET(fte_match_set_misc, misc_m, source_port, mask);
9664 	MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
9665 }
9666 
9667 /**
9668  * Translate port-id item to eswitch match on  port-id.
9669  *
9670  * @param[in] dev
9671  *   The devich to configure through.
9672  * @param[in, out] matcher
9673  *   Flow matcher.
9674  * @param[in, out] key
9675  *   Flow matcher value.
9676  * @param[in] item
9677  *   Flow pattern to translate.
9678  * @param[in]
9679  *   Flow attributes.
9680  *
9681  * @return
9682  *   0 on success, a negative errno value otherwise.
9683  */
9684 static int
9685 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher,
9686 			       void *key, const struct rte_flow_item *item,
9687 			       const struct rte_flow_attr *attr)
9688 {
9689 	const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL;
9690 	const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL;
9691 	struct mlx5_priv *priv;
9692 	uint16_t mask, id;
9693 
9694 	mask = pid_m ? pid_m->id : 0xffff;
9695 	id = pid_v ? pid_v->id : dev->data->port_id;
9696 	priv = mlx5_port_to_eswitch_info(id, item == NULL);
9697 	if (!priv)
9698 		return -rte_errno;
9699 	/*
9700 	 * Translate to vport field or to metadata, depending on mode.
9701 	 * Kernel can use either misc.source_port or half of C0 metadata
9702 	 * register.
9703 	 */
9704 	if (priv->vport_meta_mask) {
9705 		/*
9706 		 * Provide the hint for SW steering library
9707 		 * to insert the flow into ingress domain and
9708 		 * save the extra vport match.
9709 		 */
9710 		if (mask == 0xffff && priv->vport_id == 0xffff &&
9711 		    priv->pf_bond < 0 && attr->transfer)
9712 			flow_dv_translate_item_source_vport
9713 				(matcher, key, priv->vport_id, mask);
9714 		/*
9715 		 * We should always set the vport metadata register,
9716 		 * otherwise the SW steering library can drop
9717 		 * the rule if wire vport metadata value is not zero,
9718 		 * it depends on kernel configuration.
9719 		 */
9720 		flow_dv_translate_item_meta_vport(matcher, key,
9721 						  priv->vport_meta_tag,
9722 						  priv->vport_meta_mask);
9723 	} else {
9724 		flow_dv_translate_item_source_vport(matcher, key,
9725 						    priv->vport_id, mask);
9726 	}
9727 	return 0;
9728 }
9729 
9730 /**
9731  * Add ICMP6 item to matcher and to the value.
9732  *
9733  * @param[in, out] matcher
9734  *   Flow matcher.
9735  * @param[in, out] key
9736  *   Flow matcher value.
9737  * @param[in] item
9738  *   Flow pattern to translate.
9739  * @param[in] inner
9740  *   Item is inner pattern.
9741  */
9742 static void
9743 flow_dv_translate_item_icmp6(void *matcher, void *key,
9744 			      const struct rte_flow_item *item,
9745 			      int inner)
9746 {
9747 	const struct rte_flow_item_icmp6 *icmp6_m = item->mask;
9748 	const struct rte_flow_item_icmp6 *icmp6_v = item->spec;
9749 	void *headers_m;
9750 	void *headers_v;
9751 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9752 				     misc_parameters_3);
9753 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9754 	if (inner) {
9755 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9756 					 inner_headers);
9757 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9758 	} else {
9759 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9760 					 outer_headers);
9761 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9762 	}
9763 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
9764 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6);
9765 	if (!icmp6_v)
9766 		return;
9767 	if (!icmp6_m)
9768 		icmp6_m = &rte_flow_item_icmp6_mask;
9769 	MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type);
9770 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type,
9771 		 icmp6_v->type & icmp6_m->type);
9772 	MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code);
9773 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code,
9774 		 icmp6_v->code & icmp6_m->code);
9775 }
9776 
9777 /**
9778  * Add ICMP item to matcher and to the value.
9779  *
9780  * @param[in, out] matcher
9781  *   Flow matcher.
9782  * @param[in, out] key
9783  *   Flow matcher value.
9784  * @param[in] item
9785  *   Flow pattern to translate.
9786  * @param[in] inner
9787  *   Item is inner pattern.
9788  */
9789 static void
9790 flow_dv_translate_item_icmp(void *matcher, void *key,
9791 			    const struct rte_flow_item *item,
9792 			    int inner)
9793 {
9794 	const struct rte_flow_item_icmp *icmp_m = item->mask;
9795 	const struct rte_flow_item_icmp *icmp_v = item->spec;
9796 	uint32_t icmp_header_data_m = 0;
9797 	uint32_t icmp_header_data_v = 0;
9798 	void *headers_m;
9799 	void *headers_v;
9800 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9801 				     misc_parameters_3);
9802 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9803 	if (inner) {
9804 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9805 					 inner_headers);
9806 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9807 	} else {
9808 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9809 					 outer_headers);
9810 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9811 	}
9812 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
9813 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP);
9814 	if (!icmp_v)
9815 		return;
9816 	if (!icmp_m)
9817 		icmp_m = &rte_flow_item_icmp_mask;
9818 	MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type,
9819 		 icmp_m->hdr.icmp_type);
9820 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type,
9821 		 icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type);
9822 	MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code,
9823 		 icmp_m->hdr.icmp_code);
9824 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code,
9825 		 icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code);
9826 	icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb);
9827 	icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16;
9828 	if (icmp_header_data_m) {
9829 		icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb);
9830 		icmp_header_data_v |=
9831 			 rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16;
9832 		MLX5_SET(fte_match_set_misc3, misc3_m, icmp_header_data,
9833 			 icmp_header_data_m);
9834 		MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data,
9835 			 icmp_header_data_v & icmp_header_data_m);
9836 	}
9837 }
9838 
9839 /**
9840  * Add GTP item to matcher and to the value.
9841  *
9842  * @param[in, out] matcher
9843  *   Flow matcher.
9844  * @param[in, out] key
9845  *   Flow matcher value.
9846  * @param[in] item
9847  *   Flow pattern to translate.
9848  * @param[in] inner
9849  *   Item is inner pattern.
9850  */
9851 static void
9852 flow_dv_translate_item_gtp(void *matcher, void *key,
9853 			   const struct rte_flow_item *item, int inner)
9854 {
9855 	const struct rte_flow_item_gtp *gtp_m = item->mask;
9856 	const struct rte_flow_item_gtp *gtp_v = item->spec;
9857 	void *headers_m;
9858 	void *headers_v;
9859 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9860 				     misc_parameters_3);
9861 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9862 	uint16_t dport = RTE_GTPU_UDP_PORT;
9863 
9864 	if (inner) {
9865 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9866 					 inner_headers);
9867 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9868 	} else {
9869 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9870 					 outer_headers);
9871 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9872 	}
9873 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9874 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
9875 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
9876 	}
9877 	if (!gtp_v)
9878 		return;
9879 	if (!gtp_m)
9880 		gtp_m = &rte_flow_item_gtp_mask;
9881 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags,
9882 		 gtp_m->v_pt_rsv_flags);
9883 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags,
9884 		 gtp_v->v_pt_rsv_flags & gtp_m->v_pt_rsv_flags);
9885 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_type, gtp_m->msg_type);
9886 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type,
9887 		 gtp_v->msg_type & gtp_m->msg_type);
9888 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_teid,
9889 		 rte_be_to_cpu_32(gtp_m->teid));
9890 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid,
9891 		 rte_be_to_cpu_32(gtp_v->teid & gtp_m->teid));
9892 }
9893 
9894 /**
9895  * Add GTP PSC item to matcher.
9896  *
9897  * @param[in, out] matcher
9898  *   Flow matcher.
9899  * @param[in, out] key
9900  *   Flow matcher value.
9901  * @param[in] item
9902  *   Flow pattern to translate.
9903  */
9904 static int
9905 flow_dv_translate_item_gtp_psc(void *matcher, void *key,
9906 			       const struct rte_flow_item *item)
9907 {
9908 	const struct rte_flow_item_gtp_psc *gtp_psc_m = item->mask;
9909 	const struct rte_flow_item_gtp_psc *gtp_psc_v = item->spec;
9910 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9911 			misc_parameters_3);
9912 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9913 	union {
9914 		uint32_t w32;
9915 		struct {
9916 			uint16_t seq_num;
9917 			uint8_t npdu_num;
9918 			uint8_t next_ext_header_type;
9919 		};
9920 	} dw_2;
9921 	uint8_t gtp_flags;
9922 
9923 	/* Always set E-flag match on one, regardless of GTP item settings. */
9924 	gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_m, gtpu_msg_flags);
9925 	gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
9926 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, gtp_flags);
9927 	gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags);
9928 	gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
9929 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags);
9930 	/*Set next extension header type. */
9931 	dw_2.seq_num = 0;
9932 	dw_2.npdu_num = 0;
9933 	dw_2.next_ext_header_type = 0xff;
9934 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_dw_2,
9935 		 rte_cpu_to_be_32(dw_2.w32));
9936 	dw_2.seq_num = 0;
9937 	dw_2.npdu_num = 0;
9938 	dw_2.next_ext_header_type = 0x85;
9939 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2,
9940 		 rte_cpu_to_be_32(dw_2.w32));
9941 	if (gtp_psc_v) {
9942 		union {
9943 			uint32_t w32;
9944 			struct {
9945 				uint8_t len;
9946 				uint8_t type_flags;
9947 				uint8_t qfi;
9948 				uint8_t reserved;
9949 			};
9950 		} dw_0;
9951 
9952 		/*Set extension header PDU type and Qos. */
9953 		if (!gtp_psc_m)
9954 			gtp_psc_m = &rte_flow_item_gtp_psc_mask;
9955 		dw_0.w32 = 0;
9956 		dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->pdu_type);
9957 		dw_0.qfi = gtp_psc_m->qfi;
9958 		MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_first_ext_dw_0,
9959 			 rte_cpu_to_be_32(dw_0.w32));
9960 		dw_0.w32 = 0;
9961 		dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->pdu_type &
9962 							gtp_psc_m->pdu_type);
9963 		dw_0.qfi = gtp_psc_v->qfi & gtp_psc_m->qfi;
9964 		MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0,
9965 			 rte_cpu_to_be_32(dw_0.w32));
9966 	}
9967 	return 0;
9968 }
9969 
9970 /**
9971  * Add eCPRI item to matcher and to the value.
9972  *
9973  * @param[in] dev
9974  *   The devich to configure through.
9975  * @param[in, out] matcher
9976  *   Flow matcher.
9977  * @param[in, out] key
9978  *   Flow matcher value.
9979  * @param[in] item
9980  *   Flow pattern to translate.
9981  * @param[in] last_item
9982  *   Last item flags.
9983  */
9984 static void
9985 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher,
9986 			     void *key, const struct rte_flow_item *item,
9987 			     uint64_t last_item)
9988 {
9989 	struct mlx5_priv *priv = dev->data->dev_private;
9990 	const struct rte_flow_item_ecpri *ecpri_m = item->mask;
9991 	const struct rte_flow_item_ecpri *ecpri_v = item->spec;
9992 	struct rte_ecpri_common_hdr common;
9993 	void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher,
9994 				     misc_parameters_4);
9995 	void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4);
9996 	uint32_t *samples;
9997 	void *dw_m;
9998 	void *dw_v;
9999 
10000 	/*
10001 	 * In case of eCPRI over Ethernet, if EtherType is not specified,
10002 	 * match on eCPRI EtherType implicitly.
10003 	 */
10004 	if (last_item & MLX5_FLOW_LAYER_OUTER_L2) {
10005 		void *hdrs_m, *hdrs_v, *l2m, *l2v;
10006 
10007 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
10008 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
10009 		l2m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, ethertype);
10010 		l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
10011 		if (*(uint16_t *)l2m == 0 && *(uint16_t *)l2v == 0) {
10012 			*(uint16_t *)l2m = UINT16_MAX;
10013 			*(uint16_t *)l2v = RTE_BE16(RTE_ETHER_TYPE_ECPRI);
10014 		}
10015 	}
10016 	if (!ecpri_v)
10017 		return;
10018 	if (!ecpri_m)
10019 		ecpri_m = &rte_flow_item_ecpri_mask;
10020 	/*
10021 	 * Maximal four DW samples are supported in a single matching now.
10022 	 * Two are used now for a eCPRI matching:
10023 	 * 1. Type: one byte, mask should be 0x00ff0000 in network order
10024 	 * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000
10025 	 *    if any.
10026 	 */
10027 	if (!ecpri_m->hdr.common.u32)
10028 		return;
10029 	samples = priv->sh->fp[MLX5_FLEX_PARSER_ECPRI_0].ids;
10030 	/* Need to take the whole DW as the mask to fill the entry. */
10031 	dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
10032 			    prog_sample_field_value_0);
10033 	dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
10034 			    prog_sample_field_value_0);
10035 	/* Already big endian (network order) in the header. */
10036 	*(uint32_t *)dw_m = ecpri_m->hdr.common.u32;
10037 	*(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32;
10038 	/* Sample#0, used for matching type, offset 0. */
10039 	MLX5_SET(fte_match_set_misc4, misc4_m,
10040 		 prog_sample_field_id_0, samples[0]);
10041 	/* It makes no sense to set the sample ID in the mask field. */
10042 	MLX5_SET(fte_match_set_misc4, misc4_v,
10043 		 prog_sample_field_id_0, samples[0]);
10044 	/*
10045 	 * Checking if message body part needs to be matched.
10046 	 * Some wildcard rules only matching type field should be supported.
10047 	 */
10048 	if (ecpri_m->hdr.dummy[0]) {
10049 		common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32);
10050 		switch (common.type) {
10051 		case RTE_ECPRI_MSG_TYPE_IQ_DATA:
10052 		case RTE_ECPRI_MSG_TYPE_RTC_CTRL:
10053 		case RTE_ECPRI_MSG_TYPE_DLY_MSR:
10054 			dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
10055 					    prog_sample_field_value_1);
10056 			dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
10057 					    prog_sample_field_value_1);
10058 			*(uint32_t *)dw_m = ecpri_m->hdr.dummy[0];
10059 			*(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] &
10060 					    ecpri_m->hdr.dummy[0];
10061 			/* Sample#1, to match message body, offset 4. */
10062 			MLX5_SET(fte_match_set_misc4, misc4_m,
10063 				 prog_sample_field_id_1, samples[1]);
10064 			MLX5_SET(fte_match_set_misc4, misc4_v,
10065 				 prog_sample_field_id_1, samples[1]);
10066 			break;
10067 		default:
10068 			/* Others, do not match any sample ID. */
10069 			break;
10070 		}
10071 	}
10072 }
10073 
10074 /*
10075  * Add connection tracking status item to matcher
10076  *
10077  * @param[in] dev
10078  *   The devich to configure through.
10079  * @param[in, out] matcher
10080  *   Flow matcher.
10081  * @param[in, out] key
10082  *   Flow matcher value.
10083  * @param[in] item
10084  *   Flow pattern to translate.
10085  */
10086 static void
10087 flow_dv_translate_item_aso_ct(struct rte_eth_dev *dev,
10088 			      void *matcher, void *key,
10089 			      const struct rte_flow_item *item)
10090 {
10091 	uint32_t reg_value = 0;
10092 	int reg_id;
10093 	/* 8LSB 0b 11/0000/11, middle 4 bits are reserved. */
10094 	uint32_t reg_mask = 0;
10095 	const struct rte_flow_item_conntrack *spec = item->spec;
10096 	const struct rte_flow_item_conntrack *mask = item->mask;
10097 	uint32_t flags;
10098 	struct rte_flow_error error;
10099 
10100 	if (!mask)
10101 		mask = &rte_flow_item_conntrack_mask;
10102 	if (!spec || !mask->flags)
10103 		return;
10104 	flags = spec->flags & mask->flags;
10105 	/* The conflict should be checked in the validation. */
10106 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID)
10107 		reg_value |= MLX5_CT_SYNDROME_VALID;
10108 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
10109 		reg_value |= MLX5_CT_SYNDROME_STATE_CHANGE;
10110 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID)
10111 		reg_value |= MLX5_CT_SYNDROME_INVALID;
10112 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)
10113 		reg_value |= MLX5_CT_SYNDROME_TRAP;
10114 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
10115 		reg_value |= MLX5_CT_SYNDROME_BAD_PACKET;
10116 	if (mask->flags & (RTE_FLOW_CONNTRACK_PKT_STATE_VALID |
10117 			   RTE_FLOW_CONNTRACK_PKT_STATE_INVALID |
10118 			   RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED))
10119 		reg_mask |= 0xc0;
10120 	if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
10121 		reg_mask |= MLX5_CT_SYNDROME_STATE_CHANGE;
10122 	if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
10123 		reg_mask |= MLX5_CT_SYNDROME_BAD_PACKET;
10124 	/* The REG_C_x value could be saved during startup. */
10125 	reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, &error);
10126 	if (reg_id == REG_NON)
10127 		return;
10128 	flow_dv_match_meta_reg(matcher, key, (enum modify_reg)reg_id,
10129 			       reg_value, reg_mask);
10130 }
10131 
10132 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
10133 
10134 #define HEADER_IS_ZERO(match_criteria, headers)				     \
10135 	!(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
10136 		 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
10137 
10138 /**
10139  * Calculate flow matcher enable bitmap.
10140  *
10141  * @param match_criteria
10142  *   Pointer to flow matcher criteria.
10143  *
10144  * @return
10145  *   Bitmap of enabled fields.
10146  */
10147 static uint8_t
10148 flow_dv_matcher_enable(uint32_t *match_criteria)
10149 {
10150 	uint8_t match_criteria_enable;
10151 
10152 	match_criteria_enable =
10153 		(!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
10154 		MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
10155 	match_criteria_enable |=
10156 		(!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
10157 		MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
10158 	match_criteria_enable |=
10159 		(!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
10160 		MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
10161 	match_criteria_enable |=
10162 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
10163 		MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
10164 	match_criteria_enable |=
10165 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
10166 		MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
10167 	match_criteria_enable |=
10168 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) <<
10169 		MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT;
10170 	match_criteria_enable |=
10171 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_5)) <<
10172 		MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT;
10173 	return match_criteria_enable;
10174 }
10175 
10176 static void
10177 __flow_dv_adjust_buf_size(size_t *size, uint8_t match_criteria)
10178 {
10179 	/*
10180 	 * Check flow matching criteria first, subtract misc5/4 length if flow
10181 	 * doesn't own misc5/4 parameters. In some old rdma-core releases,
10182 	 * misc5/4 are not supported, and matcher creation failure is expected
10183 	 * w/o subtration. If misc5 is provided, misc4 must be counted in since
10184 	 * misc5 is right after misc4.
10185 	 */
10186 	if (!(match_criteria & (1 << MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT))) {
10187 		*size = MLX5_ST_SZ_BYTES(fte_match_param) -
10188 			MLX5_ST_SZ_BYTES(fte_match_set_misc5);
10189 		if (!(match_criteria & (1 <<
10190 			MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT))) {
10191 			*size -= MLX5_ST_SZ_BYTES(fte_match_set_misc4);
10192 		}
10193 	}
10194 }
10195 
10196 static struct mlx5_list_entry *
10197 flow_dv_matcher_clone_cb(void *tool_ctx __rte_unused,
10198 			 struct mlx5_list_entry *entry, void *cb_ctx)
10199 {
10200 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10201 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10202 	struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
10203 							    typeof(*tbl), tbl);
10204 	struct mlx5_flow_dv_matcher *resource = mlx5_malloc(MLX5_MEM_ANY,
10205 							    sizeof(*resource),
10206 							    0, SOCKET_ID_ANY);
10207 
10208 	if (!resource) {
10209 		rte_flow_error_set(ctx->error, ENOMEM,
10210 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10211 				   "cannot create matcher");
10212 		return NULL;
10213 	}
10214 	memcpy(resource, entry, sizeof(*resource));
10215 	resource->tbl = &tbl->tbl;
10216 	return &resource->entry;
10217 }
10218 
10219 static void
10220 flow_dv_matcher_clone_free_cb(void *tool_ctx __rte_unused,
10221 			     struct mlx5_list_entry *entry)
10222 {
10223 	mlx5_free(entry);
10224 }
10225 
10226 struct mlx5_list_entry *
10227 flow_dv_tbl_create_cb(void *tool_ctx, void *cb_ctx)
10228 {
10229 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10230 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10231 	struct rte_eth_dev *dev = ctx->dev;
10232 	struct mlx5_flow_tbl_data_entry *tbl_data;
10233 	struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data2;
10234 	struct rte_flow_error *error = ctx->error;
10235 	union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) };
10236 	struct mlx5_flow_tbl_resource *tbl;
10237 	void *domain;
10238 	uint32_t idx = 0;
10239 	int ret;
10240 
10241 	tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10242 	if (!tbl_data) {
10243 		rte_flow_error_set(error, ENOMEM,
10244 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10245 				   NULL,
10246 				   "cannot allocate flow table data entry");
10247 		return NULL;
10248 	}
10249 	tbl_data->idx = idx;
10250 	tbl_data->tunnel = tt_prm->tunnel;
10251 	tbl_data->group_id = tt_prm->group_id;
10252 	tbl_data->external = !!tt_prm->external;
10253 	tbl_data->tunnel_offload = is_tunnel_offload_active(dev);
10254 	tbl_data->is_egress = !!key.is_egress;
10255 	tbl_data->is_transfer = !!key.is_fdb;
10256 	tbl_data->dummy = !!key.dummy;
10257 	tbl_data->level = key.level;
10258 	tbl_data->id = key.id;
10259 	tbl = &tbl_data->tbl;
10260 	if (key.dummy)
10261 		return &tbl_data->entry;
10262 	if (key.is_fdb)
10263 		domain = sh->fdb_domain;
10264 	else if (key.is_egress)
10265 		domain = sh->tx_domain;
10266 	else
10267 		domain = sh->rx_domain;
10268 	ret = mlx5_flow_os_create_flow_tbl(domain, key.level, &tbl->obj);
10269 	if (ret) {
10270 		rte_flow_error_set(error, ENOMEM,
10271 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10272 				   NULL, "cannot create flow table object");
10273 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10274 		return NULL;
10275 	}
10276 	if (key.level != 0) {
10277 		ret = mlx5_flow_os_create_flow_action_dest_flow_tbl
10278 					(tbl->obj, &tbl_data->jump.action);
10279 		if (ret) {
10280 			rte_flow_error_set(error, ENOMEM,
10281 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10282 					   NULL,
10283 					   "cannot create flow jump action");
10284 			mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10285 			mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10286 			return NULL;
10287 		}
10288 	}
10289 	MKSTR(matcher_name, "%s_%s_%u_%u_matcher_list",
10290 	      key.is_fdb ? "FDB" : "NIC", key.is_egress ? "egress" : "ingress",
10291 	      key.level, key.id);
10292 	tbl_data->matchers = mlx5_list_create(matcher_name, sh, true,
10293 					      flow_dv_matcher_create_cb,
10294 					      flow_dv_matcher_match_cb,
10295 					      flow_dv_matcher_remove_cb,
10296 					      flow_dv_matcher_clone_cb,
10297 					      flow_dv_matcher_clone_free_cb);
10298 	if (!tbl_data->matchers) {
10299 		rte_flow_error_set(error, ENOMEM,
10300 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10301 				   NULL,
10302 				   "cannot create tbl matcher list");
10303 		mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10304 		mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10305 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10306 		return NULL;
10307 	}
10308 	return &tbl_data->entry;
10309 }
10310 
10311 int
10312 flow_dv_tbl_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
10313 		     void *cb_ctx)
10314 {
10315 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10316 	struct mlx5_flow_tbl_data_entry *tbl_data =
10317 		container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10318 	union mlx5_flow_tbl_key key = { .v64 =  *(uint64_t *)(ctx->data) };
10319 
10320 	return tbl_data->level != key.level ||
10321 	       tbl_data->id != key.id ||
10322 	       tbl_data->dummy != key.dummy ||
10323 	       tbl_data->is_transfer != !!key.is_fdb ||
10324 	       tbl_data->is_egress != !!key.is_egress;
10325 }
10326 
10327 struct mlx5_list_entry *
10328 flow_dv_tbl_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
10329 		      void *cb_ctx)
10330 {
10331 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10332 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10333 	struct mlx5_flow_tbl_data_entry *tbl_data;
10334 	struct rte_flow_error *error = ctx->error;
10335 	uint32_t idx = 0;
10336 
10337 	tbl_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10338 	if (!tbl_data) {
10339 		rte_flow_error_set(error, ENOMEM,
10340 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10341 				   NULL,
10342 				   "cannot allocate flow table data entry");
10343 		return NULL;
10344 	}
10345 	memcpy(tbl_data, oentry, sizeof(*tbl_data));
10346 	tbl_data->idx = idx;
10347 	return &tbl_data->entry;
10348 }
10349 
10350 void
10351 flow_dv_tbl_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10352 {
10353 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10354 	struct mlx5_flow_tbl_data_entry *tbl_data =
10355 		    container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10356 
10357 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10358 }
10359 
10360 /**
10361  * Get a flow table.
10362  *
10363  * @param[in, out] dev
10364  *   Pointer to rte_eth_dev structure.
10365  * @param[in] table_level
10366  *   Table level to use.
10367  * @param[in] egress
10368  *   Direction of the table.
10369  * @param[in] transfer
10370  *   E-Switch or NIC flow.
10371  * @param[in] dummy
10372  *   Dummy entry for dv API.
10373  * @param[in] table_id
10374  *   Table id to use.
10375  * @param[out] error
10376  *   pointer to error structure.
10377  *
10378  * @return
10379  *   Returns tables resource based on the index, NULL in case of failed.
10380  */
10381 struct mlx5_flow_tbl_resource *
10382 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
10383 			 uint32_t table_level, uint8_t egress,
10384 			 uint8_t transfer,
10385 			 bool external,
10386 			 const struct mlx5_flow_tunnel *tunnel,
10387 			 uint32_t group_id, uint8_t dummy,
10388 			 uint32_t table_id,
10389 			 struct rte_flow_error *error)
10390 {
10391 	struct mlx5_priv *priv = dev->data->dev_private;
10392 	union mlx5_flow_tbl_key table_key = {
10393 		{
10394 			.level = table_level,
10395 			.id = table_id,
10396 			.reserved = 0,
10397 			.dummy = !!dummy,
10398 			.is_fdb = !!transfer,
10399 			.is_egress = !!egress,
10400 		}
10401 	};
10402 	struct mlx5_flow_tbl_tunnel_prm tt_prm = {
10403 		.tunnel = tunnel,
10404 		.group_id = group_id,
10405 		.external = external,
10406 	};
10407 	struct mlx5_flow_cb_ctx ctx = {
10408 		.dev = dev,
10409 		.error = error,
10410 		.data = &table_key.v64,
10411 		.data2 = &tt_prm,
10412 	};
10413 	struct mlx5_list_entry *entry;
10414 	struct mlx5_flow_tbl_data_entry *tbl_data;
10415 
10416 	entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx);
10417 	if (!entry) {
10418 		rte_flow_error_set(error, ENOMEM,
10419 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10420 				   "cannot get table");
10421 		return NULL;
10422 	}
10423 	DRV_LOG(DEBUG, "table_level %u table_id %u "
10424 		"tunnel %u group %u registered.",
10425 		table_level, table_id,
10426 		tunnel ? tunnel->tunnel_id : 0, group_id);
10427 	tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10428 	return &tbl_data->tbl;
10429 }
10430 
10431 void
10432 flow_dv_tbl_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10433 {
10434 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10435 	struct mlx5_flow_tbl_data_entry *tbl_data =
10436 		    container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10437 
10438 	MLX5_ASSERT(entry && sh);
10439 	if (tbl_data->jump.action)
10440 		mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10441 	if (tbl_data->tbl.obj)
10442 		mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj);
10443 	if (tbl_data->tunnel_offload && tbl_data->external) {
10444 		struct mlx5_list_entry *he;
10445 		struct mlx5_hlist *tunnel_grp_hash;
10446 		struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;
10447 		union tunnel_tbl_key tunnel_key = {
10448 			.tunnel_id = tbl_data->tunnel ?
10449 					tbl_data->tunnel->tunnel_id : 0,
10450 			.group = tbl_data->group_id
10451 		};
10452 		uint32_t table_level = tbl_data->level;
10453 		struct mlx5_flow_cb_ctx ctx = {
10454 			.data = (void *)&tunnel_key.val,
10455 		};
10456 
10457 		tunnel_grp_hash = tbl_data->tunnel ?
10458 					tbl_data->tunnel->groups :
10459 					thub->groups;
10460 		he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, &ctx);
10461 		if (he)
10462 			mlx5_hlist_unregister(tunnel_grp_hash, he);
10463 		DRV_LOG(DEBUG,
10464 			"table_level %u id %u tunnel %u group %u released.",
10465 			table_level,
10466 			tbl_data->id,
10467 			tbl_data->tunnel ?
10468 			tbl_data->tunnel->tunnel_id : 0,
10469 			tbl_data->group_id);
10470 	}
10471 	mlx5_list_destroy(tbl_data->matchers);
10472 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10473 }
10474 
10475 /**
10476  * Release a flow table.
10477  *
10478  * @param[in] sh
10479  *   Pointer to device shared structure.
10480  * @param[in] tbl
10481  *   Table resource to be released.
10482  *
10483  * @return
10484  *   Returns 0 if table was released, else return 1;
10485  */
10486 static int
10487 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
10488 			     struct mlx5_flow_tbl_resource *tbl)
10489 {
10490 	struct mlx5_flow_tbl_data_entry *tbl_data =
10491 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
10492 
10493 	if (!tbl)
10494 		return 0;
10495 	return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry);
10496 }
10497 
10498 int
10499 flow_dv_matcher_match_cb(void *tool_ctx __rte_unused,
10500 			 struct mlx5_list_entry *entry, void *cb_ctx)
10501 {
10502 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10503 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10504 	struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur),
10505 							entry);
10506 
10507 	return cur->crc != ref->crc ||
10508 	       cur->priority != ref->priority ||
10509 	       memcmp((const void *)cur->mask.buf,
10510 		      (const void *)ref->mask.buf, ref->mask.size);
10511 }
10512 
10513 struct mlx5_list_entry *
10514 flow_dv_matcher_create_cb(void *tool_ctx, void *cb_ctx)
10515 {
10516 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10517 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10518 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10519 	struct mlx5_flow_dv_matcher *resource;
10520 	struct mlx5dv_flow_matcher_attr dv_attr = {
10521 		.type = IBV_FLOW_ATTR_NORMAL,
10522 		.match_mask = (void *)&ref->mask,
10523 	};
10524 	struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
10525 							    typeof(*tbl), tbl);
10526 	int ret;
10527 
10528 	resource = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*resource), 0,
10529 			       SOCKET_ID_ANY);
10530 	if (!resource) {
10531 		rte_flow_error_set(ctx->error, ENOMEM,
10532 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10533 				   "cannot create matcher");
10534 		return NULL;
10535 	}
10536 	*resource = *ref;
10537 	dv_attr.match_criteria_enable =
10538 		flow_dv_matcher_enable(resource->mask.buf);
10539 	__flow_dv_adjust_buf_size(&ref->mask.size,
10540 				  dv_attr.match_criteria_enable);
10541 	dv_attr.priority = ref->priority;
10542 	if (tbl->is_egress)
10543 		dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
10544 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->tbl.obj,
10545 					       &resource->matcher_object);
10546 	if (ret) {
10547 		mlx5_free(resource);
10548 		rte_flow_error_set(ctx->error, ENOMEM,
10549 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10550 				   "cannot create matcher");
10551 		return NULL;
10552 	}
10553 	return &resource->entry;
10554 }
10555 
10556 /**
10557  * Register the flow matcher.
10558  *
10559  * @param[in, out] dev
10560  *   Pointer to rte_eth_dev structure.
10561  * @param[in, out] matcher
10562  *   Pointer to flow matcher.
10563  * @param[in, out] key
10564  *   Pointer to flow table key.
10565  * @parm[in, out] dev_flow
10566  *   Pointer to the dev_flow.
10567  * @param[out] error
10568  *   pointer to error structure.
10569  *
10570  * @return
10571  *   0 on success otherwise -errno and errno is set.
10572  */
10573 static int
10574 flow_dv_matcher_register(struct rte_eth_dev *dev,
10575 			 struct mlx5_flow_dv_matcher *ref,
10576 			 union mlx5_flow_tbl_key *key,
10577 			 struct mlx5_flow *dev_flow,
10578 			 const struct mlx5_flow_tunnel *tunnel,
10579 			 uint32_t group_id,
10580 			 struct rte_flow_error *error)
10581 {
10582 	struct mlx5_list_entry *entry;
10583 	struct mlx5_flow_dv_matcher *resource;
10584 	struct mlx5_flow_tbl_resource *tbl;
10585 	struct mlx5_flow_tbl_data_entry *tbl_data;
10586 	struct mlx5_flow_cb_ctx ctx = {
10587 		.error = error,
10588 		.data = ref,
10589 	};
10590 	/**
10591 	 * tunnel offload API requires this registration for cases when
10592 	 * tunnel match rule was inserted before tunnel set rule.
10593 	 */
10594 	tbl = flow_dv_tbl_resource_get(dev, key->level,
10595 				       key->is_egress, key->is_fdb,
10596 				       dev_flow->external, tunnel,
10597 				       group_id, 0, key->id, error);
10598 	if (!tbl)
10599 		return -rte_errno;	/* No need to refill the error info */
10600 	tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
10601 	ref->tbl = tbl;
10602 	entry = mlx5_list_register(tbl_data->matchers, &ctx);
10603 	if (!entry) {
10604 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
10605 		return rte_flow_error_set(error, ENOMEM,
10606 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10607 					  "cannot allocate ref memory");
10608 	}
10609 	resource = container_of(entry, typeof(*resource), entry);
10610 	dev_flow->handle->dvh.matcher = resource;
10611 	return 0;
10612 }
10613 
10614 struct mlx5_list_entry *
10615 flow_dv_tag_create_cb(void *tool_ctx, void *cb_ctx)
10616 {
10617 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10618 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10619 	struct mlx5_flow_dv_tag_resource *entry;
10620 	uint32_t idx = 0;
10621 	int ret;
10622 
10623 	entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
10624 	if (!entry) {
10625 		rte_flow_error_set(ctx->error, ENOMEM,
10626 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10627 				   "cannot allocate resource memory");
10628 		return NULL;
10629 	}
10630 	entry->idx = idx;
10631 	entry->tag_id = *(uint32_t *)(ctx->data);
10632 	ret = mlx5_flow_os_create_flow_action_tag(entry->tag_id,
10633 						  &entry->action);
10634 	if (ret) {
10635 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx);
10636 		rte_flow_error_set(ctx->error, ENOMEM,
10637 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10638 				   NULL, "cannot create action");
10639 		return NULL;
10640 	}
10641 	return &entry->entry;
10642 }
10643 
10644 int
10645 flow_dv_tag_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
10646 		     void *cb_ctx)
10647 {
10648 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10649 	struct mlx5_flow_dv_tag_resource *tag =
10650 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10651 
10652 	return *(uint32_t *)(ctx->data) != tag->tag_id;
10653 }
10654 
10655 struct mlx5_list_entry *
10656 flow_dv_tag_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
10657 		     void *cb_ctx)
10658 {
10659 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10660 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10661 	struct mlx5_flow_dv_tag_resource *entry;
10662 	uint32_t idx = 0;
10663 
10664 	entry = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
10665 	if (!entry) {
10666 		rte_flow_error_set(ctx->error, ENOMEM,
10667 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10668 				   "cannot allocate tag resource memory");
10669 		return NULL;
10670 	}
10671 	memcpy(entry, oentry, sizeof(*entry));
10672 	entry->idx = idx;
10673 	return &entry->entry;
10674 }
10675 
10676 void
10677 flow_dv_tag_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10678 {
10679 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10680 	struct mlx5_flow_dv_tag_resource *tag =
10681 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10682 
10683 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
10684 }
10685 
10686 /**
10687  * Find existing tag resource or create and register a new one.
10688  *
10689  * @param dev[in, out]
10690  *   Pointer to rte_eth_dev structure.
10691  * @param[in, out] tag_be24
10692  *   Tag value in big endian then R-shift 8.
10693  * @parm[in, out] dev_flow
10694  *   Pointer to the dev_flow.
10695  * @param[out] error
10696  *   pointer to error structure.
10697  *
10698  * @return
10699  *   0 on success otherwise -errno and errno is set.
10700  */
10701 static int
10702 flow_dv_tag_resource_register
10703 			(struct rte_eth_dev *dev,
10704 			 uint32_t tag_be24,
10705 			 struct mlx5_flow *dev_flow,
10706 			 struct rte_flow_error *error)
10707 {
10708 	struct mlx5_priv *priv = dev->data->dev_private;
10709 	struct mlx5_flow_dv_tag_resource *resource;
10710 	struct mlx5_list_entry *entry;
10711 	struct mlx5_flow_cb_ctx ctx = {
10712 					.error = error,
10713 					.data = &tag_be24,
10714 					};
10715 	struct mlx5_hlist *tag_table;
10716 
10717 	tag_table = flow_dv_hlist_prepare(priv->sh, &priv->sh->tag_table,
10718 				      "tags",
10719 				      MLX5_TAGS_HLIST_ARRAY_SIZE,
10720 				      false, false, priv->sh,
10721 				      flow_dv_tag_create_cb,
10722 				      flow_dv_tag_match_cb,
10723 				      flow_dv_tag_remove_cb,
10724 				      flow_dv_tag_clone_cb,
10725 				      flow_dv_tag_clone_free_cb);
10726 	if (unlikely(!tag_table))
10727 		return -rte_errno;
10728 	entry = mlx5_hlist_register(tag_table, tag_be24, &ctx);
10729 	if (entry) {
10730 		resource = container_of(entry, struct mlx5_flow_dv_tag_resource,
10731 					entry);
10732 		dev_flow->handle->dvh.rix_tag = resource->idx;
10733 		dev_flow->dv.tag_resource = resource;
10734 		return 0;
10735 	}
10736 	return -rte_errno;
10737 }
10738 
10739 void
10740 flow_dv_tag_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10741 {
10742 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10743 	struct mlx5_flow_dv_tag_resource *tag =
10744 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10745 
10746 	MLX5_ASSERT(tag && sh && tag->action);
10747 	claim_zero(mlx5_flow_os_destroy_flow_action(tag->action));
10748 	DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag);
10749 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
10750 }
10751 
10752 /**
10753  * Release the tag.
10754  *
10755  * @param dev
10756  *   Pointer to Ethernet device.
10757  * @param tag_idx
10758  *   Tag index.
10759  *
10760  * @return
10761  *   1 while a reference on it exists, 0 when freed.
10762  */
10763 static int
10764 flow_dv_tag_release(struct rte_eth_dev *dev,
10765 		    uint32_t tag_idx)
10766 {
10767 	struct mlx5_priv *priv = dev->data->dev_private;
10768 	struct mlx5_flow_dv_tag_resource *tag;
10769 
10770 	tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx);
10771 	if (!tag)
10772 		return 0;
10773 	DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
10774 		dev->data->port_id, (void *)tag, tag->entry.ref_cnt);
10775 	return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry);
10776 }
10777 
10778 /**
10779  * Translate port ID action to vport.
10780  *
10781  * @param[in] dev
10782  *   Pointer to rte_eth_dev structure.
10783  * @param[in] action
10784  *   Pointer to the port ID action.
10785  * @param[out] dst_port_id
10786  *   The target port ID.
10787  * @param[out] error
10788  *   Pointer to the error structure.
10789  *
10790  * @return
10791  *   0 on success, a negative errno value otherwise and rte_errno is set.
10792  */
10793 static int
10794 flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
10795 				 const struct rte_flow_action *action,
10796 				 uint32_t *dst_port_id,
10797 				 struct rte_flow_error *error)
10798 {
10799 	uint32_t port;
10800 	struct mlx5_priv *priv;
10801 	const struct rte_flow_action_port_id *conf =
10802 			(const struct rte_flow_action_port_id *)action->conf;
10803 
10804 	port = conf->original ? dev->data->port_id : conf->id;
10805 	priv = mlx5_port_to_eswitch_info(port, false);
10806 	if (!priv)
10807 		return rte_flow_error_set(error, -rte_errno,
10808 					  RTE_FLOW_ERROR_TYPE_ACTION,
10809 					  NULL,
10810 					  "No eswitch info was found for port");
10811 #ifdef HAVE_MLX5DV_DR_CREATE_DEST_IB_PORT
10812 	/*
10813 	 * This parameter is transferred to
10814 	 * mlx5dv_dr_action_create_dest_ib_port().
10815 	 */
10816 	*dst_port_id = priv->dev_port;
10817 #else
10818 	/*
10819 	 * Legacy mode, no LAG configurations is supported.
10820 	 * This parameter is transferred to
10821 	 * mlx5dv_dr_action_create_dest_vport().
10822 	 */
10823 	*dst_port_id = priv->vport_id;
10824 #endif
10825 	return 0;
10826 }
10827 
10828 /**
10829  * Create a counter with aging configuration.
10830  *
10831  * @param[in] dev
10832  *   Pointer to rte_eth_dev structure.
10833  * @param[in] dev_flow
10834  *   Pointer to the mlx5_flow.
10835  * @param[out] count
10836  *   Pointer to the counter action configuration.
10837  * @param[in] age
10838  *   Pointer to the aging action configuration.
10839  *
10840  * @return
10841  *   Index to flow counter on success, 0 otherwise.
10842  */
10843 static uint32_t
10844 flow_dv_translate_create_counter(struct rte_eth_dev *dev,
10845 				struct mlx5_flow *dev_flow,
10846 				const struct rte_flow_action_count *count,
10847 				const struct rte_flow_action_age *age)
10848 {
10849 	uint32_t counter;
10850 	struct mlx5_age_param *age_param;
10851 
10852 	if (count && count->shared)
10853 		counter = flow_dv_counter_get_shared(dev, count->id);
10854 	else
10855 		counter = flow_dv_counter_alloc(dev, !!age);
10856 	if (!counter || age == NULL)
10857 		return counter;
10858 	age_param = flow_dv_counter_idx_get_age(dev, counter);
10859 	age_param->context = age->context ? age->context :
10860 		(void *)(uintptr_t)(dev_flow->flow_idx);
10861 	age_param->timeout = age->timeout;
10862 	age_param->port_id = dev->data->port_id;
10863 	__atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED);
10864 	__atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED);
10865 	return counter;
10866 }
10867 
10868 /**
10869  * Add Tx queue matcher
10870  *
10871  * @param[in] dev
10872  *   Pointer to the dev struct.
10873  * @param[in, out] matcher
10874  *   Flow matcher.
10875  * @param[in, out] key
10876  *   Flow matcher value.
10877  * @param[in] item
10878  *   Flow pattern to translate.
10879  * @param[in] inner
10880  *   Item is inner pattern.
10881  */
10882 static void
10883 flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev,
10884 				void *matcher, void *key,
10885 				const struct rte_flow_item *item)
10886 {
10887 	const struct mlx5_rte_flow_item_tx_queue *queue_m;
10888 	const struct mlx5_rte_flow_item_tx_queue *queue_v;
10889 	void *misc_m =
10890 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
10891 	void *misc_v =
10892 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
10893 	struct mlx5_txq_ctrl *txq;
10894 	uint32_t queue;
10895 
10896 
10897 	queue_m = (const void *)item->mask;
10898 	if (!queue_m)
10899 		return;
10900 	queue_v = (const void *)item->spec;
10901 	if (!queue_v)
10902 		return;
10903 	txq = mlx5_txq_get(dev, queue_v->queue);
10904 	if (!txq)
10905 		return;
10906 	queue = txq->obj->sq->id;
10907 	MLX5_SET(fte_match_set_misc, misc_m, source_sqn, queue_m->queue);
10908 	MLX5_SET(fte_match_set_misc, misc_v, source_sqn,
10909 		 queue & queue_m->queue);
10910 	mlx5_txq_release(dev, queue_v->queue);
10911 }
10912 
10913 /**
10914  * Set the hash fields according to the @p flow information.
10915  *
10916  * @param[in] dev_flow
10917  *   Pointer to the mlx5_flow.
10918  * @param[in] rss_desc
10919  *   Pointer to the mlx5_flow_rss_desc.
10920  */
10921 static void
10922 flow_dv_hashfields_set(struct mlx5_flow *dev_flow,
10923 		       struct mlx5_flow_rss_desc *rss_desc)
10924 {
10925 	uint64_t items = dev_flow->handle->layers;
10926 	int rss_inner = 0;
10927 	uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types);
10928 
10929 	dev_flow->hash_fields = 0;
10930 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
10931 	if (rss_desc->level >= 2)
10932 		rss_inner = 1;
10933 #endif
10934 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) ||
10935 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) {
10936 		if (rss_types & MLX5_IPV4_LAYER_TYPES) {
10937 			if (rss_types & ETH_RSS_L3_SRC_ONLY)
10938 				dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV4;
10939 			else if (rss_types & ETH_RSS_L3_DST_ONLY)
10940 				dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV4;
10941 			else
10942 				dev_flow->hash_fields |= MLX5_IPV4_IBV_RX_HASH;
10943 		}
10944 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
10945 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) {
10946 		if (rss_types & MLX5_IPV6_LAYER_TYPES) {
10947 			if (rss_types & ETH_RSS_L3_SRC_ONLY)
10948 				dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV6;
10949 			else if (rss_types & ETH_RSS_L3_DST_ONLY)
10950 				dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV6;
10951 			else
10952 				dev_flow->hash_fields |= MLX5_IPV6_IBV_RX_HASH;
10953 		}
10954 	}
10955 	if (dev_flow->hash_fields == 0)
10956 		/*
10957 		 * There is no match between the RSS types and the
10958 		 * L3 protocol (IPv4/IPv6) defined in the flow rule.
10959 		 */
10960 		return;
10961 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) ||
10962 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) {
10963 		if (rss_types & ETH_RSS_UDP) {
10964 			if (rss_types & ETH_RSS_L4_SRC_ONLY)
10965 				dev_flow->hash_fields |=
10966 						IBV_RX_HASH_SRC_PORT_UDP;
10967 			else if (rss_types & ETH_RSS_L4_DST_ONLY)
10968 				dev_flow->hash_fields |=
10969 						IBV_RX_HASH_DST_PORT_UDP;
10970 			else
10971 				dev_flow->hash_fields |= MLX5_UDP_IBV_RX_HASH;
10972 		}
10973 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) ||
10974 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) {
10975 		if (rss_types & ETH_RSS_TCP) {
10976 			if (rss_types & ETH_RSS_L4_SRC_ONLY)
10977 				dev_flow->hash_fields |=
10978 						IBV_RX_HASH_SRC_PORT_TCP;
10979 			else if (rss_types & ETH_RSS_L4_DST_ONLY)
10980 				dev_flow->hash_fields |=
10981 						IBV_RX_HASH_DST_PORT_TCP;
10982 			else
10983 				dev_flow->hash_fields |= MLX5_TCP_IBV_RX_HASH;
10984 		}
10985 	}
10986 	if (rss_inner)
10987 		dev_flow->hash_fields |= IBV_RX_HASH_INNER;
10988 }
10989 
10990 /**
10991  * Prepare an Rx Hash queue.
10992  *
10993  * @param dev
10994  *   Pointer to Ethernet device.
10995  * @param[in] dev_flow
10996  *   Pointer to the mlx5_flow.
10997  * @param[in] rss_desc
10998  *   Pointer to the mlx5_flow_rss_desc.
10999  * @param[out] hrxq_idx
11000  *   Hash Rx queue index.
11001  *
11002  * @return
11003  *   The Verbs/DevX object initialised, NULL otherwise and rte_errno is set.
11004  */
11005 static struct mlx5_hrxq *
11006 flow_dv_hrxq_prepare(struct rte_eth_dev *dev,
11007 		     struct mlx5_flow *dev_flow,
11008 		     struct mlx5_flow_rss_desc *rss_desc,
11009 		     uint32_t *hrxq_idx)
11010 {
11011 	struct mlx5_priv *priv = dev->data->dev_private;
11012 	struct mlx5_flow_handle *dh = dev_flow->handle;
11013 	struct mlx5_hrxq *hrxq;
11014 
11015 	MLX5_ASSERT(rss_desc->queue_num);
11016 	rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN;
11017 	rss_desc->hash_fields = dev_flow->hash_fields;
11018 	rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL);
11019 	rss_desc->shared_rss = 0;
11020 	if (rss_desc->hash_fields == 0)
11021 		rss_desc->queue_num = 1;
11022 	*hrxq_idx = mlx5_hrxq_get(dev, rss_desc);
11023 	if (!*hrxq_idx)
11024 		return NULL;
11025 	hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
11026 			      *hrxq_idx);
11027 	return hrxq;
11028 }
11029 
11030 /**
11031  * Release sample sub action resource.
11032  *
11033  * @param[in, out] dev
11034  *   Pointer to rte_eth_dev structure.
11035  * @param[in] act_res
11036  *   Pointer to sample sub action resource.
11037  */
11038 static void
11039 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev,
11040 				   struct mlx5_flow_sub_actions_idx *act_res)
11041 {
11042 	if (act_res->rix_hrxq) {
11043 		mlx5_hrxq_release(dev, act_res->rix_hrxq);
11044 		act_res->rix_hrxq = 0;
11045 	}
11046 	if (act_res->rix_encap_decap) {
11047 		flow_dv_encap_decap_resource_release(dev,
11048 						     act_res->rix_encap_decap);
11049 		act_res->rix_encap_decap = 0;
11050 	}
11051 	if (act_res->rix_port_id_action) {
11052 		flow_dv_port_id_action_resource_release(dev,
11053 						act_res->rix_port_id_action);
11054 		act_res->rix_port_id_action = 0;
11055 	}
11056 	if (act_res->rix_tag) {
11057 		flow_dv_tag_release(dev, act_res->rix_tag);
11058 		act_res->rix_tag = 0;
11059 	}
11060 	if (act_res->rix_jump) {
11061 		flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump);
11062 		act_res->rix_jump = 0;
11063 	}
11064 }
11065 
11066 int
11067 flow_dv_sample_match_cb(void *tool_ctx __rte_unused,
11068 			struct mlx5_list_entry *entry, void *cb_ctx)
11069 {
11070 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11071 	struct rte_eth_dev *dev = ctx->dev;
11072 	struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
11073 	struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
11074 							      typeof(*resource),
11075 							      entry);
11076 
11077 	if (ctx_resource->ratio == resource->ratio &&
11078 	    ctx_resource->ft_type == resource->ft_type &&
11079 	    ctx_resource->ft_id == resource->ft_id &&
11080 	    ctx_resource->set_action == resource->set_action &&
11081 	    !memcmp((void *)&ctx_resource->sample_act,
11082 		    (void *)&resource->sample_act,
11083 		    sizeof(struct mlx5_flow_sub_actions_list))) {
11084 		/*
11085 		 * Existing sample action should release the prepared
11086 		 * sub-actions reference counter.
11087 		 */
11088 		flow_dv_sample_sub_actions_release(dev,
11089 						   &ctx_resource->sample_idx);
11090 		return 0;
11091 	}
11092 	return 1;
11093 }
11094 
11095 struct mlx5_list_entry *
11096 flow_dv_sample_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
11097 {
11098 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11099 	struct rte_eth_dev *dev = ctx->dev;
11100 	struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
11101 	void **sample_dv_actions = ctx_resource->sub_actions;
11102 	struct mlx5_flow_dv_sample_resource *resource;
11103 	struct mlx5dv_dr_flow_sampler_attr sampler_attr;
11104 	struct mlx5_priv *priv = dev->data->dev_private;
11105 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11106 	struct mlx5_flow_tbl_resource *tbl;
11107 	uint32_t idx = 0;
11108 	const uint32_t next_ft_step = 1;
11109 	uint32_t next_ft_id = ctx_resource->ft_id + next_ft_step;
11110 	uint8_t is_egress = 0;
11111 	uint8_t is_transfer = 0;
11112 	struct rte_flow_error *error = ctx->error;
11113 
11114 	/* Register new sample resource. */
11115 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11116 	if (!resource) {
11117 		rte_flow_error_set(error, ENOMEM,
11118 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11119 					  NULL,
11120 					  "cannot allocate resource memory");
11121 		return NULL;
11122 	}
11123 	*resource = *ctx_resource;
11124 	/* Create normal path table level */
11125 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11126 		is_transfer = 1;
11127 	else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
11128 		is_egress = 1;
11129 	tbl = flow_dv_tbl_resource_get(dev, next_ft_id,
11130 					is_egress, is_transfer,
11131 					true, NULL, 0, 0, 0, error);
11132 	if (!tbl) {
11133 		rte_flow_error_set(error, ENOMEM,
11134 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11135 					  NULL,
11136 					  "fail to create normal path table "
11137 					  "for sample");
11138 		goto error;
11139 	}
11140 	resource->normal_path_tbl = tbl;
11141 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) {
11142 		if (!sh->default_miss_action) {
11143 			rte_flow_error_set(error, ENOMEM,
11144 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11145 						NULL,
11146 						"default miss action was not "
11147 						"created");
11148 			goto error;
11149 		}
11150 		sample_dv_actions[ctx_resource->sample_act.actions_num++] =
11151 						sh->default_miss_action;
11152 	}
11153 	/* Create a DR sample action */
11154 	sampler_attr.sample_ratio = resource->ratio;
11155 	sampler_attr.default_next_table = tbl->obj;
11156 	sampler_attr.num_sample_actions = ctx_resource->sample_act.actions_num;
11157 	sampler_attr.sample_actions = (struct mlx5dv_dr_action **)
11158 							&sample_dv_actions[0];
11159 	sampler_attr.action = resource->set_action;
11160 	if (mlx5_os_flow_dr_create_flow_action_sampler
11161 			(&sampler_attr, &resource->verbs_action)) {
11162 		rte_flow_error_set(error, ENOMEM,
11163 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11164 					NULL, "cannot create sample action");
11165 		goto error;
11166 	}
11167 	resource->idx = idx;
11168 	resource->dev = dev;
11169 	return &resource->entry;
11170 error:
11171 	if (resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB)
11172 		flow_dv_sample_sub_actions_release(dev,
11173 						   &resource->sample_idx);
11174 	if (resource->normal_path_tbl)
11175 		flow_dv_tbl_resource_release(MLX5_SH(dev),
11176 				resource->normal_path_tbl);
11177 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx);
11178 	return NULL;
11179 
11180 }
11181 
11182 struct mlx5_list_entry *
11183 flow_dv_sample_clone_cb(void *tool_ctx __rte_unused,
11184 			 struct mlx5_list_entry *entry __rte_unused,
11185 			 void *cb_ctx)
11186 {
11187 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11188 	struct rte_eth_dev *dev = ctx->dev;
11189 	struct mlx5_flow_dv_sample_resource *resource;
11190 	struct mlx5_priv *priv = dev->data->dev_private;
11191 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11192 	uint32_t idx = 0;
11193 
11194 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11195 	if (!resource) {
11196 		rte_flow_error_set(ctx->error, ENOMEM,
11197 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11198 					  NULL,
11199 					  "cannot allocate resource memory");
11200 		return NULL;
11201 	}
11202 	memcpy(resource, entry, sizeof(*resource));
11203 	resource->idx = idx;
11204 	resource->dev = dev;
11205 	return &resource->entry;
11206 }
11207 
11208 void
11209 flow_dv_sample_clone_free_cb(void *tool_ctx __rte_unused,
11210 			     struct mlx5_list_entry *entry)
11211 {
11212 	struct mlx5_flow_dv_sample_resource *resource =
11213 				  container_of(entry, typeof(*resource), entry);
11214 	struct rte_eth_dev *dev = resource->dev;
11215 	struct mlx5_priv *priv = dev->data->dev_private;
11216 
11217 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
11218 }
11219 
11220 /**
11221  * Find existing sample resource or create and register a new one.
11222  *
11223  * @param[in, out] dev
11224  *   Pointer to rte_eth_dev structure.
11225  * @param[in] ref
11226  *   Pointer to sample resource reference.
11227  * @parm[in, out] dev_flow
11228  *   Pointer to the dev_flow.
11229  * @param[out] error
11230  *   pointer to error structure.
11231  *
11232  * @return
11233  *   0 on success otherwise -errno and errno is set.
11234  */
11235 static int
11236 flow_dv_sample_resource_register(struct rte_eth_dev *dev,
11237 			 struct mlx5_flow_dv_sample_resource *ref,
11238 			 struct mlx5_flow *dev_flow,
11239 			 struct rte_flow_error *error)
11240 {
11241 	struct mlx5_flow_dv_sample_resource *resource;
11242 	struct mlx5_list_entry *entry;
11243 	struct mlx5_priv *priv = dev->data->dev_private;
11244 	struct mlx5_flow_cb_ctx ctx = {
11245 		.dev = dev,
11246 		.error = error,
11247 		.data = ref,
11248 	};
11249 
11250 	entry = mlx5_list_register(priv->sh->sample_action_list, &ctx);
11251 	if (!entry)
11252 		return -rte_errno;
11253 	resource = container_of(entry, typeof(*resource), entry);
11254 	dev_flow->handle->dvh.rix_sample = resource->idx;
11255 	dev_flow->dv.sample_res = resource;
11256 	return 0;
11257 }
11258 
11259 int
11260 flow_dv_dest_array_match_cb(void *tool_ctx __rte_unused,
11261 			    struct mlx5_list_entry *entry, void *cb_ctx)
11262 {
11263 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11264 	struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11265 	struct rte_eth_dev *dev = ctx->dev;
11266 	struct mlx5_flow_dv_dest_array_resource *resource =
11267 				  container_of(entry, typeof(*resource), entry);
11268 	uint32_t idx = 0;
11269 
11270 	if (ctx_resource->num_of_dest == resource->num_of_dest &&
11271 	    ctx_resource->ft_type == resource->ft_type &&
11272 	    !memcmp((void *)resource->sample_act,
11273 		    (void *)ctx_resource->sample_act,
11274 		   (ctx_resource->num_of_dest *
11275 		   sizeof(struct mlx5_flow_sub_actions_list)))) {
11276 		/*
11277 		 * Existing sample action should release the prepared
11278 		 * sub-actions reference counter.
11279 		 */
11280 		for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11281 			flow_dv_sample_sub_actions_release(dev,
11282 					&ctx_resource->sample_idx[idx]);
11283 		return 0;
11284 	}
11285 	return 1;
11286 }
11287 
11288 struct mlx5_list_entry *
11289 flow_dv_dest_array_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
11290 {
11291 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11292 	struct rte_eth_dev *dev = ctx->dev;
11293 	struct mlx5_flow_dv_dest_array_resource *resource;
11294 	struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11295 	struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 };
11296 	struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM];
11297 	struct mlx5_priv *priv = dev->data->dev_private;
11298 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11299 	struct mlx5_flow_sub_actions_list *sample_act;
11300 	struct mlx5dv_dr_domain *domain;
11301 	uint32_t idx = 0, res_idx = 0;
11302 	struct rte_flow_error *error = ctx->error;
11303 	uint64_t action_flags;
11304 	int ret;
11305 
11306 	/* Register new destination array resource. */
11307 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11308 					    &res_idx);
11309 	if (!resource) {
11310 		rte_flow_error_set(error, ENOMEM,
11311 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11312 					  NULL,
11313 					  "cannot allocate resource memory");
11314 		return NULL;
11315 	}
11316 	*resource = *ctx_resource;
11317 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11318 		domain = sh->fdb_domain;
11319 	else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
11320 		domain = sh->rx_domain;
11321 	else
11322 		domain = sh->tx_domain;
11323 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11324 		dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *)
11325 				 mlx5_malloc(MLX5_MEM_ZERO,
11326 				 sizeof(struct mlx5dv_dr_action_dest_attr),
11327 				 0, SOCKET_ID_ANY);
11328 		if (!dest_attr[idx]) {
11329 			rte_flow_error_set(error, ENOMEM,
11330 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11331 					   NULL,
11332 					   "cannot allocate resource memory");
11333 			goto error;
11334 		}
11335 		dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST;
11336 		sample_act = &ctx_resource->sample_act[idx];
11337 		action_flags = sample_act->action_flags;
11338 		switch (action_flags) {
11339 		case MLX5_FLOW_ACTION_QUEUE:
11340 			dest_attr[idx]->dest = sample_act->dr_queue_action;
11341 			break;
11342 		case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP):
11343 			dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT;
11344 			dest_attr[idx]->dest_reformat = &dest_reformat[idx];
11345 			dest_attr[idx]->dest_reformat->reformat =
11346 					sample_act->dr_encap_action;
11347 			dest_attr[idx]->dest_reformat->dest =
11348 					sample_act->dr_port_id_action;
11349 			break;
11350 		case MLX5_FLOW_ACTION_PORT_ID:
11351 			dest_attr[idx]->dest = sample_act->dr_port_id_action;
11352 			break;
11353 		case MLX5_FLOW_ACTION_JUMP:
11354 			dest_attr[idx]->dest = sample_act->dr_jump_action;
11355 			break;
11356 		default:
11357 			rte_flow_error_set(error, EINVAL,
11358 					   RTE_FLOW_ERROR_TYPE_ACTION,
11359 					   NULL,
11360 					   "unsupported actions type");
11361 			goto error;
11362 		}
11363 	}
11364 	/* create a dest array actioin */
11365 	ret = mlx5_os_flow_dr_create_flow_action_dest_array
11366 						(domain,
11367 						 resource->num_of_dest,
11368 						 dest_attr,
11369 						 &resource->action);
11370 	if (ret) {
11371 		rte_flow_error_set(error, ENOMEM,
11372 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11373 				   NULL,
11374 				   "cannot create destination array action");
11375 		goto error;
11376 	}
11377 	resource->idx = res_idx;
11378 	resource->dev = dev;
11379 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11380 		mlx5_free(dest_attr[idx]);
11381 	return &resource->entry;
11382 error:
11383 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11384 		flow_dv_sample_sub_actions_release(dev,
11385 						   &resource->sample_idx[idx]);
11386 		if (dest_attr[idx])
11387 			mlx5_free(dest_attr[idx]);
11388 	}
11389 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx);
11390 	return NULL;
11391 }
11392 
11393 struct mlx5_list_entry *
11394 flow_dv_dest_array_clone_cb(void *tool_ctx __rte_unused,
11395 			    struct mlx5_list_entry *entry __rte_unused,
11396 			    void *cb_ctx)
11397 {
11398 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11399 	struct rte_eth_dev *dev = ctx->dev;
11400 	struct mlx5_flow_dv_dest_array_resource *resource;
11401 	struct mlx5_priv *priv = dev->data->dev_private;
11402 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11403 	uint32_t res_idx = 0;
11404 	struct rte_flow_error *error = ctx->error;
11405 
11406 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11407 				      &res_idx);
11408 	if (!resource) {
11409 		rte_flow_error_set(error, ENOMEM,
11410 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11411 					  NULL,
11412 					  "cannot allocate dest-array memory");
11413 		return NULL;
11414 	}
11415 	memcpy(resource, entry, sizeof(*resource));
11416 	resource->idx = res_idx;
11417 	resource->dev = dev;
11418 	return &resource->entry;
11419 }
11420 
11421 void
11422 flow_dv_dest_array_clone_free_cb(void *tool_ctx __rte_unused,
11423 				 struct mlx5_list_entry *entry)
11424 {
11425 	struct mlx5_flow_dv_dest_array_resource *resource =
11426 			container_of(entry, typeof(*resource), entry);
11427 	struct rte_eth_dev *dev = resource->dev;
11428 	struct mlx5_priv *priv = dev->data->dev_private;
11429 
11430 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
11431 }
11432 
11433 /**
11434  * Find existing destination array resource or create and register a new one.
11435  *
11436  * @param[in, out] dev
11437  *   Pointer to rte_eth_dev structure.
11438  * @param[in] ref
11439  *   Pointer to destination array resource reference.
11440  * @parm[in, out] dev_flow
11441  *   Pointer to the dev_flow.
11442  * @param[out] error
11443  *   pointer to error structure.
11444  *
11445  * @return
11446  *   0 on success otherwise -errno and errno is set.
11447  */
11448 static int
11449 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev,
11450 			 struct mlx5_flow_dv_dest_array_resource *ref,
11451 			 struct mlx5_flow *dev_flow,
11452 			 struct rte_flow_error *error)
11453 {
11454 	struct mlx5_flow_dv_dest_array_resource *resource;
11455 	struct mlx5_priv *priv = dev->data->dev_private;
11456 	struct mlx5_list_entry *entry;
11457 	struct mlx5_flow_cb_ctx ctx = {
11458 		.dev = dev,
11459 		.error = error,
11460 		.data = ref,
11461 	};
11462 
11463 	entry = mlx5_list_register(priv->sh->dest_array_list, &ctx);
11464 	if (!entry)
11465 		return -rte_errno;
11466 	resource = container_of(entry, typeof(*resource), entry);
11467 	dev_flow->handle->dvh.rix_dest_array = resource->idx;
11468 	dev_flow->dv.dest_array_res = resource;
11469 	return 0;
11470 }
11471 
11472 /**
11473  * Convert Sample action to DV specification.
11474  *
11475  * @param[in] dev
11476  *   Pointer to rte_eth_dev structure.
11477  * @param[in] action
11478  *   Pointer to sample action structure.
11479  * @param[in, out] dev_flow
11480  *   Pointer to the mlx5_flow.
11481  * @param[in] attr
11482  *   Pointer to the flow attributes.
11483  * @param[in, out] num_of_dest
11484  *   Pointer to the num of destination.
11485  * @param[in, out] sample_actions
11486  *   Pointer to sample actions list.
11487  * @param[in, out] res
11488  *   Pointer to sample resource.
11489  * @param[out] error
11490  *   Pointer to the error structure.
11491  *
11492  * @return
11493  *   0 on success, a negative errno value otherwise and rte_errno is set.
11494  */
11495 static int
11496 flow_dv_translate_action_sample(struct rte_eth_dev *dev,
11497 				const struct rte_flow_action_sample *action,
11498 				struct mlx5_flow *dev_flow,
11499 				const struct rte_flow_attr *attr,
11500 				uint32_t *num_of_dest,
11501 				void **sample_actions,
11502 				struct mlx5_flow_dv_sample_resource *res,
11503 				struct rte_flow_error *error)
11504 {
11505 	struct mlx5_priv *priv = dev->data->dev_private;
11506 	const struct rte_flow_action *sub_actions;
11507 	struct mlx5_flow_sub_actions_list *sample_act;
11508 	struct mlx5_flow_sub_actions_idx *sample_idx;
11509 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
11510 	struct rte_flow *flow = dev_flow->flow;
11511 	struct mlx5_flow_rss_desc *rss_desc;
11512 	uint64_t action_flags = 0;
11513 
11514 	MLX5_ASSERT(wks);
11515 	rss_desc = &wks->rss_desc;
11516 	sample_act = &res->sample_act;
11517 	sample_idx = &res->sample_idx;
11518 	res->ratio = action->ratio;
11519 	sub_actions = action->actions;
11520 	for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) {
11521 		int type = sub_actions->type;
11522 		uint32_t pre_rix = 0;
11523 		void *pre_r;
11524 		switch (type) {
11525 		case RTE_FLOW_ACTION_TYPE_QUEUE:
11526 		{
11527 			const struct rte_flow_action_queue *queue;
11528 			struct mlx5_hrxq *hrxq;
11529 			uint32_t hrxq_idx;
11530 
11531 			queue = sub_actions->conf;
11532 			rss_desc->queue_num = 1;
11533 			rss_desc->queue[0] = queue->index;
11534 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11535 						    rss_desc, &hrxq_idx);
11536 			if (!hrxq)
11537 				return rte_flow_error_set
11538 					(error, rte_errno,
11539 					 RTE_FLOW_ERROR_TYPE_ACTION,
11540 					 NULL,
11541 					 "cannot create fate queue");
11542 			sample_act->dr_queue_action = hrxq->action;
11543 			sample_idx->rix_hrxq = hrxq_idx;
11544 			sample_actions[sample_act->actions_num++] =
11545 						hrxq->action;
11546 			(*num_of_dest)++;
11547 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
11548 			if (action_flags & MLX5_FLOW_ACTION_MARK)
11549 				dev_flow->handle->rix_hrxq = hrxq_idx;
11550 			dev_flow->handle->fate_action =
11551 					MLX5_FLOW_FATE_QUEUE;
11552 			break;
11553 		}
11554 		case RTE_FLOW_ACTION_TYPE_RSS:
11555 		{
11556 			struct mlx5_hrxq *hrxq;
11557 			uint32_t hrxq_idx;
11558 			const struct rte_flow_action_rss *rss;
11559 			const uint8_t *rss_key;
11560 
11561 			rss = sub_actions->conf;
11562 			memcpy(rss_desc->queue, rss->queue,
11563 			       rss->queue_num * sizeof(uint16_t));
11564 			rss_desc->queue_num = rss->queue_num;
11565 			/* NULL RSS key indicates default RSS key. */
11566 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
11567 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
11568 			/*
11569 			 * rss->level and rss.types should be set in advance
11570 			 * when expanding items for RSS.
11571 			 */
11572 			flow_dv_hashfields_set(dev_flow, rss_desc);
11573 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11574 						    rss_desc, &hrxq_idx);
11575 			if (!hrxq)
11576 				return rte_flow_error_set
11577 					(error, rte_errno,
11578 					 RTE_FLOW_ERROR_TYPE_ACTION,
11579 					 NULL,
11580 					 "cannot create fate queue");
11581 			sample_act->dr_queue_action = hrxq->action;
11582 			sample_idx->rix_hrxq = hrxq_idx;
11583 			sample_actions[sample_act->actions_num++] =
11584 						hrxq->action;
11585 			(*num_of_dest)++;
11586 			action_flags |= MLX5_FLOW_ACTION_RSS;
11587 			if (action_flags & MLX5_FLOW_ACTION_MARK)
11588 				dev_flow->handle->rix_hrxq = hrxq_idx;
11589 			dev_flow->handle->fate_action =
11590 					MLX5_FLOW_FATE_QUEUE;
11591 			break;
11592 		}
11593 		case RTE_FLOW_ACTION_TYPE_MARK:
11594 		{
11595 			uint32_t tag_be = mlx5_flow_mark_set
11596 				(((const struct rte_flow_action_mark *)
11597 				(sub_actions->conf))->id);
11598 
11599 			dev_flow->handle->mark = 1;
11600 			pre_rix = dev_flow->handle->dvh.rix_tag;
11601 			/* Save the mark resource before sample */
11602 			pre_r = dev_flow->dv.tag_resource;
11603 			if (flow_dv_tag_resource_register(dev, tag_be,
11604 						  dev_flow, error))
11605 				return -rte_errno;
11606 			MLX5_ASSERT(dev_flow->dv.tag_resource);
11607 			sample_act->dr_tag_action =
11608 				dev_flow->dv.tag_resource->action;
11609 			sample_idx->rix_tag =
11610 				dev_flow->handle->dvh.rix_tag;
11611 			sample_actions[sample_act->actions_num++] =
11612 						sample_act->dr_tag_action;
11613 			/* Recover the mark resource after sample */
11614 			dev_flow->dv.tag_resource = pre_r;
11615 			dev_flow->handle->dvh.rix_tag = pre_rix;
11616 			action_flags |= MLX5_FLOW_ACTION_MARK;
11617 			break;
11618 		}
11619 		case RTE_FLOW_ACTION_TYPE_COUNT:
11620 		{
11621 			if (!flow->counter) {
11622 				flow->counter =
11623 					flow_dv_translate_create_counter(dev,
11624 						dev_flow, sub_actions->conf,
11625 						0);
11626 				if (!flow->counter)
11627 					return rte_flow_error_set
11628 						(error, rte_errno,
11629 						RTE_FLOW_ERROR_TYPE_ACTION,
11630 						NULL,
11631 						"cannot create counter"
11632 						" object.");
11633 			}
11634 			sample_act->dr_cnt_action =
11635 				  (flow_dv_counter_get_by_idx(dev,
11636 				  flow->counter, NULL))->action;
11637 			sample_actions[sample_act->actions_num++] =
11638 						sample_act->dr_cnt_action;
11639 			action_flags |= MLX5_FLOW_ACTION_COUNT;
11640 			break;
11641 		}
11642 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
11643 		{
11644 			struct mlx5_flow_dv_port_id_action_resource
11645 					port_id_resource;
11646 			uint32_t port_id = 0;
11647 
11648 			memset(&port_id_resource, 0, sizeof(port_id_resource));
11649 			/* Save the port id resource before sample */
11650 			pre_rix = dev_flow->handle->rix_port_id_action;
11651 			pre_r = dev_flow->dv.port_id_action;
11652 			if (flow_dv_translate_action_port_id(dev, sub_actions,
11653 							     &port_id, error))
11654 				return -rte_errno;
11655 			port_id_resource.port_id = port_id;
11656 			if (flow_dv_port_id_action_resource_register
11657 			    (dev, &port_id_resource, dev_flow, error))
11658 				return -rte_errno;
11659 			sample_act->dr_port_id_action =
11660 				dev_flow->dv.port_id_action->action;
11661 			sample_idx->rix_port_id_action =
11662 				dev_flow->handle->rix_port_id_action;
11663 			sample_actions[sample_act->actions_num++] =
11664 						sample_act->dr_port_id_action;
11665 			/* Recover the port id resource after sample */
11666 			dev_flow->dv.port_id_action = pre_r;
11667 			dev_flow->handle->rix_port_id_action = pre_rix;
11668 			(*num_of_dest)++;
11669 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
11670 			break;
11671 		}
11672 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
11673 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
11674 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
11675 			/* Save the encap resource before sample */
11676 			pre_rix = dev_flow->handle->dvh.rix_encap_decap;
11677 			pre_r = dev_flow->dv.encap_decap;
11678 			if (flow_dv_create_action_l2_encap(dev, sub_actions,
11679 							   dev_flow,
11680 							   attr->transfer,
11681 							   error))
11682 				return -rte_errno;
11683 			sample_act->dr_encap_action =
11684 				dev_flow->dv.encap_decap->action;
11685 			sample_idx->rix_encap_decap =
11686 				dev_flow->handle->dvh.rix_encap_decap;
11687 			sample_actions[sample_act->actions_num++] =
11688 						sample_act->dr_encap_action;
11689 			/* Recover the encap resource after sample */
11690 			dev_flow->dv.encap_decap = pre_r;
11691 			dev_flow->handle->dvh.rix_encap_decap = pre_rix;
11692 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
11693 			break;
11694 		default:
11695 			return rte_flow_error_set(error, EINVAL,
11696 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11697 				NULL,
11698 				"Not support for sampler action");
11699 		}
11700 	}
11701 	sample_act->action_flags = action_flags;
11702 	res->ft_id = dev_flow->dv.group;
11703 	if (attr->transfer) {
11704 		union {
11705 			uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)];
11706 			uint64_t set_action;
11707 		} action_ctx = { .set_action = 0 };
11708 
11709 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
11710 		MLX5_SET(set_action_in, action_ctx.action_in, action_type,
11711 			 MLX5_MODIFICATION_TYPE_SET);
11712 		MLX5_SET(set_action_in, action_ctx.action_in, field,
11713 			 MLX5_MODI_META_REG_C_0);
11714 		MLX5_SET(set_action_in, action_ctx.action_in, data,
11715 			 priv->vport_meta_tag);
11716 		res->set_action = action_ctx.set_action;
11717 	} else if (attr->ingress) {
11718 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
11719 	} else {
11720 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
11721 	}
11722 	return 0;
11723 }
11724 
11725 /**
11726  * Convert Sample action to DV specification.
11727  *
11728  * @param[in] dev
11729  *   Pointer to rte_eth_dev structure.
11730  * @param[in, out] dev_flow
11731  *   Pointer to the mlx5_flow.
11732  * @param[in] num_of_dest
11733  *   The num of destination.
11734  * @param[in, out] res
11735  *   Pointer to sample resource.
11736  * @param[in, out] mdest_res
11737  *   Pointer to destination array resource.
11738  * @param[in] sample_actions
11739  *   Pointer to sample path actions list.
11740  * @param[in] action_flags
11741  *   Holds the actions detected until now.
11742  * @param[out] error
11743  *   Pointer to the error structure.
11744  *
11745  * @return
11746  *   0 on success, a negative errno value otherwise and rte_errno is set.
11747  */
11748 static int
11749 flow_dv_create_action_sample(struct rte_eth_dev *dev,
11750 			     struct mlx5_flow *dev_flow,
11751 			     uint32_t num_of_dest,
11752 			     struct mlx5_flow_dv_sample_resource *res,
11753 			     struct mlx5_flow_dv_dest_array_resource *mdest_res,
11754 			     void **sample_actions,
11755 			     uint64_t action_flags,
11756 			     struct rte_flow_error *error)
11757 {
11758 	/* update normal path action resource into last index of array */
11759 	uint32_t dest_index = MLX5_MAX_DEST_NUM - 1;
11760 	struct mlx5_flow_sub_actions_list *sample_act =
11761 					&mdest_res->sample_act[dest_index];
11762 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
11763 	struct mlx5_flow_rss_desc *rss_desc;
11764 	uint32_t normal_idx = 0;
11765 	struct mlx5_hrxq *hrxq;
11766 	uint32_t hrxq_idx;
11767 
11768 	MLX5_ASSERT(wks);
11769 	rss_desc = &wks->rss_desc;
11770 	if (num_of_dest > 1) {
11771 		if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) {
11772 			/* Handle QP action for mirroring */
11773 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11774 						    rss_desc, &hrxq_idx);
11775 			if (!hrxq)
11776 				return rte_flow_error_set
11777 				     (error, rte_errno,
11778 				      RTE_FLOW_ERROR_TYPE_ACTION,
11779 				      NULL,
11780 				      "cannot create rx queue");
11781 			normal_idx++;
11782 			mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx;
11783 			sample_act->dr_queue_action = hrxq->action;
11784 			if (action_flags & MLX5_FLOW_ACTION_MARK)
11785 				dev_flow->handle->rix_hrxq = hrxq_idx;
11786 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
11787 		}
11788 		if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) {
11789 			normal_idx++;
11790 			mdest_res->sample_idx[dest_index].rix_encap_decap =
11791 				dev_flow->handle->dvh.rix_encap_decap;
11792 			sample_act->dr_encap_action =
11793 				dev_flow->dv.encap_decap->action;
11794 			dev_flow->handle->dvh.rix_encap_decap = 0;
11795 		}
11796 		if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) {
11797 			normal_idx++;
11798 			mdest_res->sample_idx[dest_index].rix_port_id_action =
11799 				dev_flow->handle->rix_port_id_action;
11800 			sample_act->dr_port_id_action =
11801 				dev_flow->dv.port_id_action->action;
11802 			dev_flow->handle->rix_port_id_action = 0;
11803 		}
11804 		if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) {
11805 			normal_idx++;
11806 			mdest_res->sample_idx[dest_index].rix_jump =
11807 				dev_flow->handle->rix_jump;
11808 			sample_act->dr_jump_action =
11809 				dev_flow->dv.jump->action;
11810 			dev_flow->handle->rix_jump = 0;
11811 		}
11812 		sample_act->actions_num = normal_idx;
11813 		/* update sample action resource into first index of array */
11814 		mdest_res->ft_type = res->ft_type;
11815 		memcpy(&mdest_res->sample_idx[0], &res->sample_idx,
11816 				sizeof(struct mlx5_flow_sub_actions_idx));
11817 		memcpy(&mdest_res->sample_act[0], &res->sample_act,
11818 				sizeof(struct mlx5_flow_sub_actions_list));
11819 		mdest_res->num_of_dest = num_of_dest;
11820 		if (flow_dv_dest_array_resource_register(dev, mdest_res,
11821 							 dev_flow, error))
11822 			return rte_flow_error_set(error, EINVAL,
11823 						  RTE_FLOW_ERROR_TYPE_ACTION,
11824 						  NULL, "can't create sample "
11825 						  "action");
11826 	} else {
11827 		res->sub_actions = sample_actions;
11828 		if (flow_dv_sample_resource_register(dev, res, dev_flow, error))
11829 			return rte_flow_error_set(error, EINVAL,
11830 						  RTE_FLOW_ERROR_TYPE_ACTION,
11831 						  NULL,
11832 						  "can't create sample action");
11833 	}
11834 	return 0;
11835 }
11836 
11837 /**
11838  * Remove an ASO age action from age actions list.
11839  *
11840  * @param[in] dev
11841  *   Pointer to the Ethernet device structure.
11842  * @param[in] age
11843  *   Pointer to the aso age action handler.
11844  */
11845 static void
11846 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev,
11847 				struct mlx5_aso_age_action *age)
11848 {
11849 	struct mlx5_age_info *age_info;
11850 	struct mlx5_age_param *age_param = &age->age_params;
11851 	struct mlx5_priv *priv = dev->data->dev_private;
11852 	uint16_t expected = AGE_CANDIDATE;
11853 
11854 	age_info = GET_PORT_AGE_INFO(priv);
11855 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
11856 					 AGE_FREE, false, __ATOMIC_RELAXED,
11857 					 __ATOMIC_RELAXED)) {
11858 		/**
11859 		 * We need the lock even it is age timeout,
11860 		 * since age action may still in process.
11861 		 */
11862 		rte_spinlock_lock(&age_info->aged_sl);
11863 		LIST_REMOVE(age, next);
11864 		rte_spinlock_unlock(&age_info->aged_sl);
11865 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
11866 	}
11867 }
11868 
11869 /**
11870  * Release an ASO age action.
11871  *
11872  * @param[in] dev
11873  *   Pointer to the Ethernet device structure.
11874  * @param[in] age_idx
11875  *   Index of ASO age action to release.
11876  * @param[in] flow
11877  *   True if the release operation is during flow destroy operation.
11878  *   False if the release operation is during action destroy operation.
11879  *
11880  * @return
11881  *   0 when age action was removed, otherwise the number of references.
11882  */
11883 static int
11884 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx)
11885 {
11886 	struct mlx5_priv *priv = dev->data->dev_private;
11887 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11888 	struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx);
11889 	uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED);
11890 
11891 	if (!ret) {
11892 		flow_dv_aso_age_remove_from_age(dev, age);
11893 		rte_spinlock_lock(&mng->free_sl);
11894 		LIST_INSERT_HEAD(&mng->free, age, next);
11895 		rte_spinlock_unlock(&mng->free_sl);
11896 	}
11897 	return ret;
11898 }
11899 
11900 /**
11901  * Resize the ASO age pools array by MLX5_CNT_CONTAINER_RESIZE pools.
11902  *
11903  * @param[in] dev
11904  *   Pointer to the Ethernet device structure.
11905  *
11906  * @return
11907  *   0 on success, otherwise negative errno value and rte_errno is set.
11908  */
11909 static int
11910 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev)
11911 {
11912 	struct mlx5_priv *priv = dev->data->dev_private;
11913 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11914 	void *old_pools = mng->pools;
11915 	uint32_t resize = mng->n + MLX5_CNT_CONTAINER_RESIZE;
11916 	uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize;
11917 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
11918 
11919 	if (!pools) {
11920 		rte_errno = ENOMEM;
11921 		return -ENOMEM;
11922 	}
11923 	if (old_pools) {
11924 		memcpy(pools, old_pools,
11925 		       mng->n * sizeof(struct mlx5_flow_counter_pool *));
11926 		mlx5_free(old_pools);
11927 	} else {
11928 		/* First ASO flow hit allocation - starting ASO data-path. */
11929 		int ret = mlx5_aso_flow_hit_queue_poll_start(priv->sh);
11930 
11931 		if (ret) {
11932 			mlx5_free(pools);
11933 			return ret;
11934 		}
11935 	}
11936 	mng->n = resize;
11937 	mng->pools = pools;
11938 	return 0;
11939 }
11940 
11941 /**
11942  * Create and initialize a new ASO aging pool.
11943  *
11944  * @param[in] dev
11945  *   Pointer to the Ethernet device structure.
11946  * @param[out] age_free
11947  *   Where to put the pointer of a new age action.
11948  *
11949  * @return
11950  *   The age actions pool pointer and @p age_free is set on success,
11951  *   NULL otherwise and rte_errno is set.
11952  */
11953 static struct mlx5_aso_age_pool *
11954 flow_dv_age_pool_create(struct rte_eth_dev *dev,
11955 			struct mlx5_aso_age_action **age_free)
11956 {
11957 	struct mlx5_priv *priv = dev->data->dev_private;
11958 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11959 	struct mlx5_aso_age_pool *pool = NULL;
11960 	struct mlx5_devx_obj *obj = NULL;
11961 	uint32_t i;
11962 
11963 	obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->ctx,
11964 						    priv->sh->pdn);
11965 	if (!obj) {
11966 		rte_errno = ENODATA;
11967 		DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX.");
11968 		return NULL;
11969 	}
11970 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
11971 	if (!pool) {
11972 		claim_zero(mlx5_devx_cmd_destroy(obj));
11973 		rte_errno = ENOMEM;
11974 		return NULL;
11975 	}
11976 	pool->flow_hit_aso_obj = obj;
11977 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
11978 	rte_spinlock_lock(&mng->resize_sl);
11979 	pool->index = mng->next;
11980 	/* Resize pools array if there is no room for the new pool in it. */
11981 	if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) {
11982 		claim_zero(mlx5_devx_cmd_destroy(obj));
11983 		mlx5_free(pool);
11984 		rte_spinlock_unlock(&mng->resize_sl);
11985 		return NULL;
11986 	}
11987 	mng->pools[pool->index] = pool;
11988 	mng->next++;
11989 	rte_spinlock_unlock(&mng->resize_sl);
11990 	/* Assign the first action in the new pool, the rest go to free list. */
11991 	*age_free = &pool->actions[0];
11992 	for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) {
11993 		pool->actions[i].offset = i;
11994 		LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next);
11995 	}
11996 	return pool;
11997 }
11998 
11999 /**
12000  * Allocate a ASO aging bit.
12001  *
12002  * @param[in] dev
12003  *   Pointer to the Ethernet device structure.
12004  * @param[out] error
12005  *   Pointer to the error structure.
12006  *
12007  * @return
12008  *   Index to ASO age action on success, 0 otherwise and rte_errno is set.
12009  */
12010 static uint32_t
12011 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
12012 {
12013 	struct mlx5_priv *priv = dev->data->dev_private;
12014 	const struct mlx5_aso_age_pool *pool;
12015 	struct mlx5_aso_age_action *age_free = NULL;
12016 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
12017 
12018 	MLX5_ASSERT(mng);
12019 	/* Try to get the next free age action bit. */
12020 	rte_spinlock_lock(&mng->free_sl);
12021 	age_free = LIST_FIRST(&mng->free);
12022 	if (age_free) {
12023 		LIST_REMOVE(age_free, next);
12024 	} else if (!flow_dv_age_pool_create(dev, &age_free)) {
12025 		rte_spinlock_unlock(&mng->free_sl);
12026 		rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
12027 				   NULL, "failed to create ASO age pool");
12028 		return 0; /* 0 is an error. */
12029 	}
12030 	rte_spinlock_unlock(&mng->free_sl);
12031 	pool = container_of
12032 	  ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL])
12033 		  (age_free - age_free->offset), const struct mlx5_aso_age_pool,
12034 								       actions);
12035 	if (!age_free->dr_action) {
12036 		int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0,
12037 						 error);
12038 
12039 		if (reg_c < 0) {
12040 			rte_flow_error_set(error, rte_errno,
12041 					   RTE_FLOW_ERROR_TYPE_ACTION,
12042 					   NULL, "failed to get reg_c "
12043 					   "for ASO flow hit");
12044 			return 0; /* 0 is an error. */
12045 		}
12046 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
12047 		age_free->dr_action = mlx5_glue->dv_create_flow_action_aso
12048 				(priv->sh->rx_domain,
12049 				 pool->flow_hit_aso_obj->obj, age_free->offset,
12050 				 MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET,
12051 				 (reg_c - REG_C_0));
12052 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
12053 		if (!age_free->dr_action) {
12054 			rte_errno = errno;
12055 			rte_spinlock_lock(&mng->free_sl);
12056 			LIST_INSERT_HEAD(&mng->free, age_free, next);
12057 			rte_spinlock_unlock(&mng->free_sl);
12058 			rte_flow_error_set(error, rte_errno,
12059 					   RTE_FLOW_ERROR_TYPE_ACTION,
12060 					   NULL, "failed to create ASO "
12061 					   "flow hit action");
12062 			return 0; /* 0 is an error. */
12063 		}
12064 	}
12065 	__atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED);
12066 	return pool->index | ((age_free->offset + 1) << 16);
12067 }
12068 
12069 /**
12070  * Initialize flow ASO age parameters.
12071  *
12072  * @param[in] dev
12073  *   Pointer to rte_eth_dev structure.
12074  * @param[in] age_idx
12075  *   Index of ASO age action.
12076  * @param[in] context
12077  *   Pointer to flow counter age context.
12078  * @param[in] timeout
12079  *   Aging timeout in seconds.
12080  *
12081  */
12082 static void
12083 flow_dv_aso_age_params_init(struct rte_eth_dev *dev,
12084 			    uint32_t age_idx,
12085 			    void *context,
12086 			    uint32_t timeout)
12087 {
12088 	struct mlx5_aso_age_action *aso_age;
12089 
12090 	aso_age = flow_aso_age_get_by_idx(dev, age_idx);
12091 	MLX5_ASSERT(aso_age);
12092 	aso_age->age_params.context = context;
12093 	aso_age->age_params.timeout = timeout;
12094 	aso_age->age_params.port_id = dev->data->port_id;
12095 	__atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0,
12096 			 __ATOMIC_RELAXED);
12097 	__atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE,
12098 			 __ATOMIC_RELAXED);
12099 }
12100 
12101 static void
12102 flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask,
12103 			       const struct rte_flow_item_integrity *value,
12104 			       void *headers_m, void *headers_v)
12105 {
12106 	if (mask->l4_ok) {
12107 		/* application l4_ok filter aggregates all hardware l4 filters
12108 		 * therefore hw l4_checksum_ok must be implicitly added here.
12109 		 */
12110 		struct rte_flow_item_integrity local_item;
12111 
12112 		local_item.l4_csum_ok = 1;
12113 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok,
12114 			 local_item.l4_csum_ok);
12115 		if (value->l4_ok) {
12116 			/* application l4_ok = 1 matches sets both hw flags
12117 			 * l4_ok and l4_checksum_ok flags to 1.
12118 			 */
12119 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12120 				 l4_checksum_ok, local_item.l4_csum_ok);
12121 			MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_ok,
12122 				 mask->l4_ok);
12123 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_ok,
12124 				 value->l4_ok);
12125 		} else {
12126 			/* application l4_ok = 0 matches on hw flag
12127 			 * l4_checksum_ok = 0 only.
12128 			 */
12129 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12130 				 l4_checksum_ok, 0);
12131 		}
12132 	} else if (mask->l4_csum_ok) {
12133 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok,
12134 			 mask->l4_csum_ok);
12135 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok,
12136 			 value->l4_csum_ok);
12137 	}
12138 }
12139 
12140 static void
12141 flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask,
12142 			       const struct rte_flow_item_integrity *value,
12143 			       void *headers_m, void *headers_v,
12144 			       bool is_ipv4)
12145 {
12146 	if (mask->l3_ok) {
12147 		/* application l3_ok filter aggregates all hardware l3 filters
12148 		 * therefore hw ipv4_checksum_ok must be implicitly added here.
12149 		 */
12150 		struct rte_flow_item_integrity local_item;
12151 
12152 		local_item.ipv4_csum_ok = !!is_ipv4;
12153 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok,
12154 			 local_item.ipv4_csum_ok);
12155 		if (value->l3_ok) {
12156 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12157 				 ipv4_checksum_ok, local_item.ipv4_csum_ok);
12158 			MLX5_SET(fte_match_set_lyr_2_4, headers_m, l3_ok,
12159 				 mask->l3_ok);
12160 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, l3_ok,
12161 				 value->l3_ok);
12162 		} else {
12163 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12164 				 ipv4_checksum_ok, 0);
12165 		}
12166 	} else if (mask->ipv4_csum_ok) {
12167 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok,
12168 			 mask->ipv4_csum_ok);
12169 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_checksum_ok,
12170 			 value->ipv4_csum_ok);
12171 	}
12172 }
12173 
12174 static void
12175 flow_dv_translate_item_integrity(void *matcher, void *key,
12176 				 const struct rte_flow_item *head_item,
12177 				 const struct rte_flow_item *integrity_item)
12178 {
12179 	const struct rte_flow_item_integrity *mask = integrity_item->mask;
12180 	const struct rte_flow_item_integrity *value = integrity_item->spec;
12181 	const struct rte_flow_item *tunnel_item, *end_item, *item;
12182 	void *headers_m;
12183 	void *headers_v;
12184 	uint32_t l3_protocol;
12185 
12186 	if (!value)
12187 		return;
12188 	if (!mask)
12189 		mask = &rte_flow_item_integrity_mask;
12190 	if (value->level > 1) {
12191 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
12192 					 inner_headers);
12193 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
12194 	} else {
12195 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
12196 					 outer_headers);
12197 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
12198 	}
12199 	tunnel_item = mlx5_flow_find_tunnel_item(head_item);
12200 	if (value->level > 1) {
12201 		/* tunnel item was verified during the item validation */
12202 		item = tunnel_item;
12203 		end_item = mlx5_find_end_item(tunnel_item);
12204 	} else {
12205 		item = head_item;
12206 		end_item = tunnel_item ? tunnel_item :
12207 			   mlx5_find_end_item(integrity_item);
12208 	}
12209 	l3_protocol = mask->l3_ok ?
12210 		      mlx5_flow_locate_proto_l3(&item, end_item) : 0;
12211 	flow_dv_translate_integrity_l3(mask, value, headers_m, headers_v,
12212 				       l3_protocol == RTE_ETHER_TYPE_IPV4);
12213 	flow_dv_translate_integrity_l4(mask, value, headers_m, headers_v);
12214 }
12215 
12216 /**
12217  * Prepares DV flow counter with aging configuration.
12218  * Gets it by index when exists, creates a new one when doesn't.
12219  *
12220  * @param[in] dev
12221  *   Pointer to rte_eth_dev structure.
12222  * @param[in] dev_flow
12223  *   Pointer to the mlx5_flow.
12224  * @param[in, out] flow
12225  *   Pointer to the sub flow.
12226  * @param[in] count
12227  *   Pointer to the counter action configuration.
12228  * @param[in] age
12229  *   Pointer to the aging action configuration.
12230  * @param[out] error
12231  *   Pointer to the error structure.
12232  *
12233  * @return
12234  *   Pointer to the counter, NULL otherwise.
12235  */
12236 static struct mlx5_flow_counter *
12237 flow_dv_prepare_counter(struct rte_eth_dev *dev,
12238 			struct mlx5_flow *dev_flow,
12239 			struct rte_flow *flow,
12240 			const struct rte_flow_action_count *count,
12241 			const struct rte_flow_action_age *age,
12242 			struct rte_flow_error *error)
12243 {
12244 	if (!flow->counter) {
12245 		flow->counter = flow_dv_translate_create_counter(dev, dev_flow,
12246 								 count, age);
12247 		if (!flow->counter) {
12248 			rte_flow_error_set(error, rte_errno,
12249 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12250 					   "cannot create counter object.");
12251 			return NULL;
12252 		}
12253 	}
12254 	return flow_dv_counter_get_by_idx(dev, flow->counter, NULL);
12255 }
12256 
12257 /*
12258  * Release an ASO CT action by its own device.
12259  *
12260  * @param[in] dev
12261  *   Pointer to the Ethernet device structure.
12262  * @param[in] idx
12263  *   Index of ASO CT action to release.
12264  *
12265  * @return
12266  *   0 when CT action was removed, otherwise the number of references.
12267  */
12268 static inline int
12269 flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx)
12270 {
12271 	struct mlx5_priv *priv = dev->data->dev_private;
12272 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12273 	uint32_t ret;
12274 	struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx);
12275 	enum mlx5_aso_ct_state state =
12276 			__atomic_load_n(&ct->state, __ATOMIC_RELAXED);
12277 
12278 	/* Cannot release when CT is in the ASO SQ. */
12279 	if (state == ASO_CONNTRACK_WAIT || state == ASO_CONNTRACK_QUERY)
12280 		return -1;
12281 	ret = __atomic_sub_fetch(&ct->refcnt, 1, __ATOMIC_RELAXED);
12282 	if (!ret) {
12283 		if (ct->dr_action_orig) {
12284 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12285 			claim_zero(mlx5_glue->destroy_flow_action
12286 					(ct->dr_action_orig));
12287 #endif
12288 			ct->dr_action_orig = NULL;
12289 		}
12290 		if (ct->dr_action_rply) {
12291 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12292 			claim_zero(mlx5_glue->destroy_flow_action
12293 					(ct->dr_action_rply));
12294 #endif
12295 			ct->dr_action_rply = NULL;
12296 		}
12297 		/* Clear the state to free, no need in 1st allocation. */
12298 		MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_FREE);
12299 		rte_spinlock_lock(&mng->ct_sl);
12300 		LIST_INSERT_HEAD(&mng->free_cts, ct, next);
12301 		rte_spinlock_unlock(&mng->ct_sl);
12302 	}
12303 	return (int)ret;
12304 }
12305 
12306 static inline int
12307 flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx)
12308 {
12309 	uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx);
12310 	uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx);
12311 	struct rte_eth_dev *owndev = &rte_eth_devices[owner];
12312 	RTE_SET_USED(dev);
12313 
12314 	MLX5_ASSERT(owner < RTE_MAX_ETHPORTS);
12315 	if (dev->data->dev_started != 1)
12316 		return -1;
12317 	return flow_dv_aso_ct_dev_release(owndev, idx);
12318 }
12319 
12320 /*
12321  * Resize the ASO CT pools array by 64 pools.
12322  *
12323  * @param[in] dev
12324  *   Pointer to the Ethernet device structure.
12325  *
12326  * @return
12327  *   0 on success, otherwise negative errno value and rte_errno is set.
12328  */
12329 static int
12330 flow_dv_aso_ct_pools_resize(struct rte_eth_dev *dev)
12331 {
12332 	struct mlx5_priv *priv = dev->data->dev_private;
12333 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12334 	void *old_pools = mng->pools;
12335 	/* Magic number now, need a macro. */
12336 	uint32_t resize = mng->n + 64;
12337 	uint32_t mem_size = sizeof(struct mlx5_aso_ct_pool *) * resize;
12338 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
12339 
12340 	if (!pools) {
12341 		rte_errno = ENOMEM;
12342 		return -rte_errno;
12343 	}
12344 	rte_rwlock_write_lock(&mng->resize_rwl);
12345 	/* ASO SQ/QP was already initialized in the startup. */
12346 	if (old_pools) {
12347 		/* Realloc could be an alternative choice. */
12348 		rte_memcpy(pools, old_pools,
12349 			   mng->n * sizeof(struct mlx5_aso_ct_pool *));
12350 		mlx5_free(old_pools);
12351 	}
12352 	mng->n = resize;
12353 	mng->pools = pools;
12354 	rte_rwlock_write_unlock(&mng->resize_rwl);
12355 	return 0;
12356 }
12357 
12358 /*
12359  * Create and initialize a new ASO CT pool.
12360  *
12361  * @param[in] dev
12362  *   Pointer to the Ethernet device structure.
12363  * @param[out] ct_free
12364  *   Where to put the pointer of a new CT action.
12365  *
12366  * @return
12367  *   The CT actions pool pointer and @p ct_free is set on success,
12368  *   NULL otherwise and rte_errno is set.
12369  */
12370 static struct mlx5_aso_ct_pool *
12371 flow_dv_ct_pool_create(struct rte_eth_dev *dev,
12372 		       struct mlx5_aso_ct_action **ct_free)
12373 {
12374 	struct mlx5_priv *priv = dev->data->dev_private;
12375 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12376 	struct mlx5_aso_ct_pool *pool = NULL;
12377 	struct mlx5_devx_obj *obj = NULL;
12378 	uint32_t i;
12379 	uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL);
12380 
12381 	obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->ctx,
12382 						priv->sh->pdn, log_obj_size);
12383 	if (!obj) {
12384 		rte_errno = ENODATA;
12385 		DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX.");
12386 		return NULL;
12387 	}
12388 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
12389 	if (!pool) {
12390 		rte_errno = ENOMEM;
12391 		claim_zero(mlx5_devx_cmd_destroy(obj));
12392 		return NULL;
12393 	}
12394 	pool->devx_obj = obj;
12395 	pool->index = mng->next;
12396 	/* Resize pools array if there is no room for the new pool in it. */
12397 	if (pool->index == mng->n && flow_dv_aso_ct_pools_resize(dev)) {
12398 		claim_zero(mlx5_devx_cmd_destroy(obj));
12399 		mlx5_free(pool);
12400 		return NULL;
12401 	}
12402 	mng->pools[pool->index] = pool;
12403 	mng->next++;
12404 	/* Assign the first action in the new pool, the rest go to free list. */
12405 	*ct_free = &pool->actions[0];
12406 	/* Lock outside, the list operation is safe here. */
12407 	for (i = 1; i < MLX5_ASO_CT_ACTIONS_PER_POOL; i++) {
12408 		/* refcnt is 0 when allocating the memory. */
12409 		pool->actions[i].offset = i;
12410 		LIST_INSERT_HEAD(&mng->free_cts, &pool->actions[i], next);
12411 	}
12412 	return pool;
12413 }
12414 
12415 /*
12416  * Allocate a ASO CT action from free list.
12417  *
12418  * @param[in] dev
12419  *   Pointer to the Ethernet device structure.
12420  * @param[out] error
12421  *   Pointer to the error structure.
12422  *
12423  * @return
12424  *   Index to ASO CT action on success, 0 otherwise and rte_errno is set.
12425  */
12426 static uint32_t
12427 flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
12428 {
12429 	struct mlx5_priv *priv = dev->data->dev_private;
12430 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12431 	struct mlx5_aso_ct_action *ct = NULL;
12432 	struct mlx5_aso_ct_pool *pool;
12433 	uint8_t reg_c;
12434 	uint32_t ct_idx;
12435 
12436 	MLX5_ASSERT(mng);
12437 	if (!priv->config.devx) {
12438 		rte_errno = ENOTSUP;
12439 		return 0;
12440 	}
12441 	/* Get a free CT action, if no, a new pool will be created. */
12442 	rte_spinlock_lock(&mng->ct_sl);
12443 	ct = LIST_FIRST(&mng->free_cts);
12444 	if (ct) {
12445 		LIST_REMOVE(ct, next);
12446 	} else if (!flow_dv_ct_pool_create(dev, &ct)) {
12447 		rte_spinlock_unlock(&mng->ct_sl);
12448 		rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
12449 				   NULL, "failed to create ASO CT pool");
12450 		return 0;
12451 	}
12452 	rte_spinlock_unlock(&mng->ct_sl);
12453 	pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]);
12454 	ct_idx = MLX5_MAKE_CT_IDX(pool->index, ct->offset);
12455 	/* 0: inactive, 1: created, 2+: used by flows. */
12456 	__atomic_store_n(&ct->refcnt, 1, __ATOMIC_RELAXED);
12457 	reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, error);
12458 	if (!ct->dr_action_orig) {
12459 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12460 		ct->dr_action_orig = mlx5_glue->dv_create_flow_action_aso
12461 			(priv->sh->rx_domain, pool->devx_obj->obj,
12462 			 ct->offset,
12463 			 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_INITIATOR,
12464 			 reg_c - REG_C_0);
12465 #else
12466 		RTE_SET_USED(reg_c);
12467 #endif
12468 		if (!ct->dr_action_orig) {
12469 			flow_dv_aso_ct_dev_release(dev, ct_idx);
12470 			rte_flow_error_set(error, rte_errno,
12471 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12472 					   "failed to create ASO CT action");
12473 			return 0;
12474 		}
12475 	}
12476 	if (!ct->dr_action_rply) {
12477 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12478 		ct->dr_action_rply = mlx5_glue->dv_create_flow_action_aso
12479 			(priv->sh->rx_domain, pool->devx_obj->obj,
12480 			 ct->offset,
12481 			 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_RESPONDER,
12482 			 reg_c - REG_C_0);
12483 #endif
12484 		if (!ct->dr_action_rply) {
12485 			flow_dv_aso_ct_dev_release(dev, ct_idx);
12486 			rte_flow_error_set(error, rte_errno,
12487 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12488 					   "failed to create ASO CT action");
12489 			return 0;
12490 		}
12491 	}
12492 	return ct_idx;
12493 }
12494 
12495 /*
12496  * Create a conntrack object with context and actions by using ASO mechanism.
12497  *
12498  * @param[in] dev
12499  *   Pointer to rte_eth_dev structure.
12500  * @param[in] pro
12501  *   Pointer to conntrack information profile.
12502  * @param[out] error
12503  *   Pointer to the error structure.
12504  *
12505  * @return
12506  *   Index to conntrack object on success, 0 otherwise.
12507  */
12508 static uint32_t
12509 flow_dv_translate_create_conntrack(struct rte_eth_dev *dev,
12510 				   const struct rte_flow_action_conntrack *pro,
12511 				   struct rte_flow_error *error)
12512 {
12513 	struct mlx5_priv *priv = dev->data->dev_private;
12514 	struct mlx5_dev_ctx_shared *sh = priv->sh;
12515 	struct mlx5_aso_ct_action *ct;
12516 	uint32_t idx;
12517 
12518 	if (!sh->ct_aso_en)
12519 		return rte_flow_error_set(error, ENOTSUP,
12520 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12521 					  "Connection is not supported");
12522 	idx = flow_dv_aso_ct_alloc(dev, error);
12523 	if (!idx)
12524 		return rte_flow_error_set(error, rte_errno,
12525 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12526 					  "Failed to allocate CT object");
12527 	ct = flow_aso_ct_get_by_dev_idx(dev, idx);
12528 	if (mlx5_aso_ct_update_by_wqe(sh, ct, pro))
12529 		return rte_flow_error_set(error, EBUSY,
12530 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12531 					  "Failed to update CT");
12532 	ct->is_original = !!pro->is_original_dir;
12533 	ct->peer = pro->peer_port;
12534 	return idx;
12535 }
12536 
12537 /**
12538  * Fill the flow with DV spec, lock free
12539  * (mutex should be acquired by caller).
12540  *
12541  * @param[in] dev
12542  *   Pointer to rte_eth_dev structure.
12543  * @param[in, out] dev_flow
12544  *   Pointer to the sub flow.
12545  * @param[in] attr
12546  *   Pointer to the flow attributes.
12547  * @param[in] items
12548  *   Pointer to the list of items.
12549  * @param[in] actions
12550  *   Pointer to the list of actions.
12551  * @param[out] error
12552  *   Pointer to the error structure.
12553  *
12554  * @return
12555  *   0 on success, a negative errno value otherwise and rte_errno is set.
12556  */
12557 static int
12558 flow_dv_translate(struct rte_eth_dev *dev,
12559 		  struct mlx5_flow *dev_flow,
12560 		  const struct rte_flow_attr *attr,
12561 		  const struct rte_flow_item items[],
12562 		  const struct rte_flow_action actions[],
12563 		  struct rte_flow_error *error)
12564 {
12565 	struct mlx5_priv *priv = dev->data->dev_private;
12566 	struct mlx5_dev_config *dev_conf = &priv->config;
12567 	struct rte_flow *flow = dev_flow->flow;
12568 	struct mlx5_flow_handle *handle = dev_flow->handle;
12569 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
12570 	struct mlx5_flow_rss_desc *rss_desc;
12571 	uint64_t item_flags = 0;
12572 	uint64_t last_item = 0;
12573 	uint64_t action_flags = 0;
12574 	struct mlx5_flow_dv_matcher matcher = {
12575 		.mask = {
12576 			.size = sizeof(matcher.mask.buf),
12577 		},
12578 	};
12579 	int actions_n = 0;
12580 	bool actions_end = false;
12581 	union {
12582 		struct mlx5_flow_dv_modify_hdr_resource res;
12583 		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
12584 			    sizeof(struct mlx5_modification_cmd) *
12585 			    (MLX5_MAX_MODIFY_NUM + 1)];
12586 	} mhdr_dummy;
12587 	struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
12588 	const struct rte_flow_action_count *count = NULL;
12589 	const struct rte_flow_action_age *non_shared_age = NULL;
12590 	union flow_dv_attr flow_attr = { .attr = 0 };
12591 	uint32_t tag_be;
12592 	union mlx5_flow_tbl_key tbl_key;
12593 	uint32_t modify_action_position = UINT32_MAX;
12594 	void *match_mask = matcher.mask.buf;
12595 	void *match_value = dev_flow->dv.value.buf;
12596 	uint8_t next_protocol = 0xff;
12597 	struct rte_vlan_hdr vlan = { 0 };
12598 	struct mlx5_flow_dv_dest_array_resource mdest_res;
12599 	struct mlx5_flow_dv_sample_resource sample_res;
12600 	void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
12601 	const struct rte_flow_action_sample *sample = NULL;
12602 	struct mlx5_flow_sub_actions_list *sample_act;
12603 	uint32_t sample_act_pos = UINT32_MAX;
12604 	uint32_t age_act_pos = UINT32_MAX;
12605 	uint32_t num_of_dest = 0;
12606 	int tmp_actions_n = 0;
12607 	uint32_t table;
12608 	int ret = 0;
12609 	const struct mlx5_flow_tunnel *tunnel = NULL;
12610 	struct flow_grp_info grp_info = {
12611 		.external = !!dev_flow->external,
12612 		.transfer = !!attr->transfer,
12613 		.fdb_def_rule = !!priv->fdb_def_rule,
12614 		.skip_scale = dev_flow->skip_scale &
12615 			(1 << MLX5_SCALE_FLOW_GROUP_BIT),
12616 		.std_tbl_fix = true,
12617 	};
12618 	const struct rte_flow_item *head_item = items;
12619 
12620 	if (!wks)
12621 		return rte_flow_error_set(error, ENOMEM,
12622 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12623 					  NULL,
12624 					  "failed to push flow workspace");
12625 	rss_desc = &wks->rss_desc;
12626 	memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource));
12627 	memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource));
12628 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
12629 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
12630 	/* update normal path action resource into last index of array */
12631 	sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1];
12632 	if (is_tunnel_offload_active(dev)) {
12633 		if (dev_flow->tunnel) {
12634 			RTE_VERIFY(dev_flow->tof_type ==
12635 				   MLX5_TUNNEL_OFFLOAD_MISS_RULE);
12636 			tunnel = dev_flow->tunnel;
12637 		} else {
12638 			tunnel = mlx5_get_tof(items, actions,
12639 					      &dev_flow->tof_type);
12640 			dev_flow->tunnel = tunnel;
12641 		}
12642 		grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
12643 					(dev, attr, tunnel, dev_flow->tof_type);
12644 	}
12645 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
12646 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
12647 	ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table,
12648 				       &grp_info, error);
12649 	if (ret)
12650 		return ret;
12651 	dev_flow->dv.group = table;
12652 	if (attr->transfer)
12653 		mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
12654 	/* number of actions must be set to 0 in case of dirty stack. */
12655 	mhdr_res->actions_num = 0;
12656 	if (is_flow_tunnel_match_rule(dev_flow->tof_type)) {
12657 		/*
12658 		 * do not add decap action if match rule drops packet
12659 		 * HW rejects rules with decap & drop
12660 		 *
12661 		 * if tunnel match rule was inserted before matching tunnel set
12662 		 * rule flow table used in the match rule must be registered.
12663 		 * current implementation handles that in the
12664 		 * flow_dv_match_register() at the function end.
12665 		 */
12666 		bool add_decap = true;
12667 		const struct rte_flow_action *ptr = actions;
12668 
12669 		for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) {
12670 			if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) {
12671 				add_decap = false;
12672 				break;
12673 			}
12674 		}
12675 		if (add_decap) {
12676 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
12677 							   attr->transfer,
12678 							   error))
12679 				return -rte_errno;
12680 			dev_flow->dv.actions[actions_n++] =
12681 					dev_flow->dv.encap_decap->action;
12682 			action_flags |= MLX5_FLOW_ACTION_DECAP;
12683 		}
12684 	}
12685 	for (; !actions_end ; actions++) {
12686 		const struct rte_flow_action_queue *queue;
12687 		const struct rte_flow_action_rss *rss;
12688 		const struct rte_flow_action *action = actions;
12689 		const uint8_t *rss_key;
12690 		struct mlx5_flow_tbl_resource *tbl;
12691 		struct mlx5_aso_age_action *age_act;
12692 		struct mlx5_flow_counter *cnt_act;
12693 		uint32_t port_id = 0;
12694 		struct mlx5_flow_dv_port_id_action_resource port_id_resource;
12695 		int action_type = actions->type;
12696 		const struct rte_flow_action *found_action = NULL;
12697 		uint32_t jump_group = 0;
12698 		uint32_t owner_idx;
12699 		struct mlx5_aso_ct_action *ct;
12700 
12701 		if (!mlx5_flow_os_action_supported(action_type))
12702 			return rte_flow_error_set(error, ENOTSUP,
12703 						  RTE_FLOW_ERROR_TYPE_ACTION,
12704 						  actions,
12705 						  "action not supported");
12706 		switch (action_type) {
12707 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
12708 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
12709 			break;
12710 		case RTE_FLOW_ACTION_TYPE_VOID:
12711 			break;
12712 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
12713 			if (flow_dv_translate_action_port_id(dev, action,
12714 							     &port_id, error))
12715 				return -rte_errno;
12716 			port_id_resource.port_id = port_id;
12717 			MLX5_ASSERT(!handle->rix_port_id_action);
12718 			if (flow_dv_port_id_action_resource_register
12719 			    (dev, &port_id_resource, dev_flow, error))
12720 				return -rte_errno;
12721 			dev_flow->dv.actions[actions_n++] =
12722 					dev_flow->dv.port_id_action->action;
12723 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
12724 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID;
12725 			sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID;
12726 			num_of_dest++;
12727 			break;
12728 		case RTE_FLOW_ACTION_TYPE_FLAG:
12729 			action_flags |= MLX5_FLOW_ACTION_FLAG;
12730 			dev_flow->handle->mark = 1;
12731 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
12732 				struct rte_flow_action_mark mark = {
12733 					.id = MLX5_FLOW_MARK_DEFAULT,
12734 				};
12735 
12736 				if (flow_dv_convert_action_mark(dev, &mark,
12737 								mhdr_res,
12738 								error))
12739 					return -rte_errno;
12740 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
12741 				break;
12742 			}
12743 			tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
12744 			/*
12745 			 * Only one FLAG or MARK is supported per device flow
12746 			 * right now. So the pointer to the tag resource must be
12747 			 * zero before the register process.
12748 			 */
12749 			MLX5_ASSERT(!handle->dvh.rix_tag);
12750 			if (flow_dv_tag_resource_register(dev, tag_be,
12751 							  dev_flow, error))
12752 				return -rte_errno;
12753 			MLX5_ASSERT(dev_flow->dv.tag_resource);
12754 			dev_flow->dv.actions[actions_n++] =
12755 					dev_flow->dv.tag_resource->action;
12756 			break;
12757 		case RTE_FLOW_ACTION_TYPE_MARK:
12758 			action_flags |= MLX5_FLOW_ACTION_MARK;
12759 			dev_flow->handle->mark = 1;
12760 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
12761 				const struct rte_flow_action_mark *mark =
12762 					(const struct rte_flow_action_mark *)
12763 						actions->conf;
12764 
12765 				if (flow_dv_convert_action_mark(dev, mark,
12766 								mhdr_res,
12767 								error))
12768 					return -rte_errno;
12769 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
12770 				break;
12771 			}
12772 			/* Fall-through */
12773 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
12774 			/* Legacy (non-extensive) MARK action. */
12775 			tag_be = mlx5_flow_mark_set
12776 			      (((const struct rte_flow_action_mark *)
12777 			       (actions->conf))->id);
12778 			MLX5_ASSERT(!handle->dvh.rix_tag);
12779 			if (flow_dv_tag_resource_register(dev, tag_be,
12780 							  dev_flow, error))
12781 				return -rte_errno;
12782 			MLX5_ASSERT(dev_flow->dv.tag_resource);
12783 			dev_flow->dv.actions[actions_n++] =
12784 					dev_flow->dv.tag_resource->action;
12785 			break;
12786 		case RTE_FLOW_ACTION_TYPE_SET_META:
12787 			if (flow_dv_convert_action_set_meta
12788 				(dev, mhdr_res, attr,
12789 				 (const struct rte_flow_action_set_meta *)
12790 				  actions->conf, error))
12791 				return -rte_errno;
12792 			action_flags |= MLX5_FLOW_ACTION_SET_META;
12793 			break;
12794 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
12795 			if (flow_dv_convert_action_set_tag
12796 				(dev, mhdr_res,
12797 				 (const struct rte_flow_action_set_tag *)
12798 				  actions->conf, error))
12799 				return -rte_errno;
12800 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
12801 			break;
12802 		case RTE_FLOW_ACTION_TYPE_DROP:
12803 			action_flags |= MLX5_FLOW_ACTION_DROP;
12804 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
12805 			break;
12806 		case RTE_FLOW_ACTION_TYPE_QUEUE:
12807 			queue = actions->conf;
12808 			rss_desc->queue_num = 1;
12809 			rss_desc->queue[0] = queue->index;
12810 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
12811 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
12812 			sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE;
12813 			num_of_dest++;
12814 			break;
12815 		case RTE_FLOW_ACTION_TYPE_RSS:
12816 			rss = actions->conf;
12817 			memcpy(rss_desc->queue, rss->queue,
12818 			       rss->queue_num * sizeof(uint16_t));
12819 			rss_desc->queue_num = rss->queue_num;
12820 			/* NULL RSS key indicates default RSS key. */
12821 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
12822 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
12823 			/*
12824 			 * rss->level and rss.types should be set in advance
12825 			 * when expanding items for RSS.
12826 			 */
12827 			action_flags |= MLX5_FLOW_ACTION_RSS;
12828 			dev_flow->handle->fate_action = rss_desc->shared_rss ?
12829 				MLX5_FLOW_FATE_SHARED_RSS :
12830 				MLX5_FLOW_FATE_QUEUE;
12831 			break;
12832 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
12833 			flow->age = (uint32_t)(uintptr_t)(action->conf);
12834 			age_act = flow_aso_age_get_by_idx(dev, flow->age);
12835 			__atomic_fetch_add(&age_act->refcnt, 1,
12836 					   __ATOMIC_RELAXED);
12837 			age_act_pos = actions_n++;
12838 			action_flags |= MLX5_FLOW_ACTION_AGE;
12839 			break;
12840 		case RTE_FLOW_ACTION_TYPE_AGE:
12841 			non_shared_age = action->conf;
12842 			age_act_pos = actions_n++;
12843 			action_flags |= MLX5_FLOW_ACTION_AGE;
12844 			break;
12845 		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
12846 			cnt_act = flow_dv_counter_get_by_idx(dev,
12847 					(uint32_t)(uintptr_t)action->conf,
12848 					NULL);
12849 			MLX5_ASSERT(cnt_act != NULL);
12850 			/**
12851 			 * When creating meter drop flow in drop table, the
12852 			 * counter should not overwrite the rte flow counter.
12853 			 */
12854 			if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
12855 			    dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) {
12856 				dev_flow->dv.actions[actions_n++] =
12857 							cnt_act->action;
12858 			} else {
12859 				flow->counter =
12860 					(uint32_t)(uintptr_t)(action->conf);
12861 				__atomic_fetch_add(&cnt_act->shared_info.refcnt,
12862 						1, __ATOMIC_RELAXED);
12863 				/* Save information first, will apply later. */
12864 				action_flags |= MLX5_FLOW_ACTION_COUNT;
12865 			}
12866 			break;
12867 		case RTE_FLOW_ACTION_TYPE_COUNT:
12868 			if (!dev_conf->devx) {
12869 				return rte_flow_error_set
12870 					      (error, ENOTSUP,
12871 					       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12872 					       NULL,
12873 					       "count action not supported");
12874 			}
12875 			/* Save information first, will apply later. */
12876 			count = action->conf;
12877 			action_flags |= MLX5_FLOW_ACTION_COUNT;
12878 			break;
12879 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
12880 			dev_flow->dv.actions[actions_n++] =
12881 						priv->sh->pop_vlan_action;
12882 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
12883 			break;
12884 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
12885 			if (!(action_flags &
12886 			      MLX5_FLOW_ACTION_OF_SET_VLAN_VID))
12887 				flow_dev_get_vlan_info_from_items(items, &vlan);
12888 			vlan.eth_proto = rte_be_to_cpu_16
12889 			     ((((const struct rte_flow_action_of_push_vlan *)
12890 						   actions->conf)->ethertype));
12891 			found_action = mlx5_flow_find_action
12892 					(actions + 1,
12893 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID);
12894 			if (found_action)
12895 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
12896 			found_action = mlx5_flow_find_action
12897 					(actions + 1,
12898 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP);
12899 			if (found_action)
12900 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
12901 			if (flow_dv_create_action_push_vlan
12902 					    (dev, attr, &vlan, dev_flow, error))
12903 				return -rte_errno;
12904 			dev_flow->dv.actions[actions_n++] =
12905 					dev_flow->dv.push_vlan_res->action;
12906 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
12907 			break;
12908 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
12909 			/* of_vlan_push action handled this action */
12910 			MLX5_ASSERT(action_flags &
12911 				    MLX5_FLOW_ACTION_OF_PUSH_VLAN);
12912 			break;
12913 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
12914 			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
12915 				break;
12916 			flow_dev_get_vlan_info_from_items(items, &vlan);
12917 			mlx5_update_vlan_vid_pcp(actions, &vlan);
12918 			/* If no VLAN push - this is a modify header action */
12919 			if (flow_dv_convert_action_modify_vlan_vid
12920 						(mhdr_res, actions, error))
12921 				return -rte_errno;
12922 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
12923 			break;
12924 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
12925 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
12926 			if (flow_dv_create_action_l2_encap(dev, actions,
12927 							   dev_flow,
12928 							   attr->transfer,
12929 							   error))
12930 				return -rte_errno;
12931 			dev_flow->dv.actions[actions_n++] =
12932 					dev_flow->dv.encap_decap->action;
12933 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
12934 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
12935 				sample_act->action_flags |=
12936 							MLX5_FLOW_ACTION_ENCAP;
12937 			break;
12938 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
12939 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
12940 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
12941 							   attr->transfer,
12942 							   error))
12943 				return -rte_errno;
12944 			dev_flow->dv.actions[actions_n++] =
12945 					dev_flow->dv.encap_decap->action;
12946 			action_flags |= MLX5_FLOW_ACTION_DECAP;
12947 			break;
12948 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
12949 			/* Handle encap with preceding decap. */
12950 			if (action_flags & MLX5_FLOW_ACTION_DECAP) {
12951 				if (flow_dv_create_action_raw_encap
12952 					(dev, actions, dev_flow, attr, error))
12953 					return -rte_errno;
12954 				dev_flow->dv.actions[actions_n++] =
12955 					dev_flow->dv.encap_decap->action;
12956 			} else {
12957 				/* Handle encap without preceding decap. */
12958 				if (flow_dv_create_action_l2_encap
12959 				    (dev, actions, dev_flow, attr->transfer,
12960 				     error))
12961 					return -rte_errno;
12962 				dev_flow->dv.actions[actions_n++] =
12963 					dev_flow->dv.encap_decap->action;
12964 			}
12965 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
12966 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
12967 				sample_act->action_flags |=
12968 							MLX5_FLOW_ACTION_ENCAP;
12969 			break;
12970 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
12971 			while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID)
12972 				;
12973 			if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
12974 				if (flow_dv_create_action_l2_decap
12975 				    (dev, dev_flow, attr->transfer, error))
12976 					return -rte_errno;
12977 				dev_flow->dv.actions[actions_n++] =
12978 					dev_flow->dv.encap_decap->action;
12979 			}
12980 			/* If decap is followed by encap, handle it at encap. */
12981 			action_flags |= MLX5_FLOW_ACTION_DECAP;
12982 			break;
12983 		case MLX5_RTE_FLOW_ACTION_TYPE_JUMP:
12984 			dev_flow->dv.actions[actions_n++] =
12985 				(void *)(uintptr_t)action->conf;
12986 			action_flags |= MLX5_FLOW_ACTION_JUMP;
12987 			break;
12988 		case RTE_FLOW_ACTION_TYPE_JUMP:
12989 			jump_group = ((const struct rte_flow_action_jump *)
12990 							action->conf)->group;
12991 			grp_info.std_tbl_fix = 0;
12992 			if (dev_flow->skip_scale &
12993 				(1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT))
12994 				grp_info.skip_scale = 1;
12995 			else
12996 				grp_info.skip_scale = 0;
12997 			ret = mlx5_flow_group_to_table(dev, tunnel,
12998 						       jump_group,
12999 						       &table,
13000 						       &grp_info, error);
13001 			if (ret)
13002 				return ret;
13003 			tbl = flow_dv_tbl_resource_get(dev, table, attr->egress,
13004 						       attr->transfer,
13005 						       !!dev_flow->external,
13006 						       tunnel, jump_group, 0,
13007 						       0, error);
13008 			if (!tbl)
13009 				return rte_flow_error_set
13010 						(error, errno,
13011 						 RTE_FLOW_ERROR_TYPE_ACTION,
13012 						 NULL,
13013 						 "cannot create jump action.");
13014 			if (flow_dv_jump_tbl_resource_register
13015 			    (dev, tbl, dev_flow, error)) {
13016 				flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
13017 				return rte_flow_error_set
13018 						(error, errno,
13019 						 RTE_FLOW_ERROR_TYPE_ACTION,
13020 						 NULL,
13021 						 "cannot create jump action.");
13022 			}
13023 			dev_flow->dv.actions[actions_n++] =
13024 					dev_flow->dv.jump->action;
13025 			action_flags |= MLX5_FLOW_ACTION_JUMP;
13026 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP;
13027 			sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP;
13028 			num_of_dest++;
13029 			break;
13030 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
13031 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
13032 			if (flow_dv_convert_action_modify_mac
13033 					(mhdr_res, actions, error))
13034 				return -rte_errno;
13035 			action_flags |= actions->type ==
13036 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
13037 					MLX5_FLOW_ACTION_SET_MAC_SRC :
13038 					MLX5_FLOW_ACTION_SET_MAC_DST;
13039 			break;
13040 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
13041 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
13042 			if (flow_dv_convert_action_modify_ipv4
13043 					(mhdr_res, actions, error))
13044 				return -rte_errno;
13045 			action_flags |= actions->type ==
13046 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
13047 					MLX5_FLOW_ACTION_SET_IPV4_SRC :
13048 					MLX5_FLOW_ACTION_SET_IPV4_DST;
13049 			break;
13050 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
13051 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
13052 			if (flow_dv_convert_action_modify_ipv6
13053 					(mhdr_res, actions, error))
13054 				return -rte_errno;
13055 			action_flags |= actions->type ==
13056 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
13057 					MLX5_FLOW_ACTION_SET_IPV6_SRC :
13058 					MLX5_FLOW_ACTION_SET_IPV6_DST;
13059 			break;
13060 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
13061 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
13062 			if (flow_dv_convert_action_modify_tp
13063 					(mhdr_res, actions, items,
13064 					 &flow_attr, dev_flow, !!(action_flags &
13065 					 MLX5_FLOW_ACTION_DECAP), error))
13066 				return -rte_errno;
13067 			action_flags |= actions->type ==
13068 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
13069 					MLX5_FLOW_ACTION_SET_TP_SRC :
13070 					MLX5_FLOW_ACTION_SET_TP_DST;
13071 			break;
13072 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
13073 			if (flow_dv_convert_action_modify_dec_ttl
13074 					(mhdr_res, items, &flow_attr, dev_flow,
13075 					 !!(action_flags &
13076 					 MLX5_FLOW_ACTION_DECAP), error))
13077 				return -rte_errno;
13078 			action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
13079 			break;
13080 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
13081 			if (flow_dv_convert_action_modify_ttl
13082 					(mhdr_res, actions, items, &flow_attr,
13083 					 dev_flow, !!(action_flags &
13084 					 MLX5_FLOW_ACTION_DECAP), error))
13085 				return -rte_errno;
13086 			action_flags |= MLX5_FLOW_ACTION_SET_TTL;
13087 			break;
13088 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
13089 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
13090 			if (flow_dv_convert_action_modify_tcp_seq
13091 					(mhdr_res, actions, error))
13092 				return -rte_errno;
13093 			action_flags |= actions->type ==
13094 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
13095 					MLX5_FLOW_ACTION_INC_TCP_SEQ :
13096 					MLX5_FLOW_ACTION_DEC_TCP_SEQ;
13097 			break;
13098 
13099 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
13100 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
13101 			if (flow_dv_convert_action_modify_tcp_ack
13102 					(mhdr_res, actions, error))
13103 				return -rte_errno;
13104 			action_flags |= actions->type ==
13105 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
13106 					MLX5_FLOW_ACTION_INC_TCP_ACK :
13107 					MLX5_FLOW_ACTION_DEC_TCP_ACK;
13108 			break;
13109 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
13110 			if (flow_dv_convert_action_set_reg
13111 					(mhdr_res, actions, error))
13112 				return -rte_errno;
13113 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
13114 			break;
13115 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
13116 			if (flow_dv_convert_action_copy_mreg
13117 					(dev, mhdr_res, actions, error))
13118 				return -rte_errno;
13119 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
13120 			break;
13121 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
13122 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
13123 			dev_flow->handle->fate_action =
13124 					MLX5_FLOW_FATE_DEFAULT_MISS;
13125 			break;
13126 		case RTE_FLOW_ACTION_TYPE_METER:
13127 			if (!wks->fm)
13128 				return rte_flow_error_set(error, rte_errno,
13129 					RTE_FLOW_ERROR_TYPE_ACTION,
13130 					NULL, "Failed to get meter in flow.");
13131 			/* Set the meter action. */
13132 			dev_flow->dv.actions[actions_n++] =
13133 				wks->fm->meter_action;
13134 			action_flags |= MLX5_FLOW_ACTION_METER;
13135 			break;
13136 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
13137 			if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res,
13138 							      actions, error))
13139 				return -rte_errno;
13140 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
13141 			break;
13142 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
13143 			if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res,
13144 							      actions, error))
13145 				return -rte_errno;
13146 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
13147 			break;
13148 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
13149 			sample_act_pos = actions_n;
13150 			sample = (const struct rte_flow_action_sample *)
13151 				 action->conf;
13152 			actions_n++;
13153 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
13154 			/* put encap action into group if work with port id */
13155 			if ((action_flags & MLX5_FLOW_ACTION_ENCAP) &&
13156 			    (action_flags & MLX5_FLOW_ACTION_PORT_ID))
13157 				sample_act->action_flags |=
13158 							MLX5_FLOW_ACTION_ENCAP;
13159 			break;
13160 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
13161 			if (flow_dv_convert_action_modify_field
13162 					(dev, mhdr_res, actions, attr, error))
13163 				return -rte_errno;
13164 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
13165 			break;
13166 		case RTE_FLOW_ACTION_TYPE_CONNTRACK:
13167 			owner_idx = (uint32_t)(uintptr_t)action->conf;
13168 			ct = flow_aso_ct_get_by_idx(dev, owner_idx);
13169 			if (!ct)
13170 				return rte_flow_error_set(error, EINVAL,
13171 						RTE_FLOW_ERROR_TYPE_ACTION,
13172 						NULL,
13173 						"Failed to get CT object.");
13174 			if (mlx5_aso_ct_available(priv->sh, ct))
13175 				return rte_flow_error_set(error, rte_errno,
13176 						RTE_FLOW_ERROR_TYPE_ACTION,
13177 						NULL,
13178 						"CT is unavailable.");
13179 			if (ct->is_original)
13180 				dev_flow->dv.actions[actions_n] =
13181 							ct->dr_action_orig;
13182 			else
13183 				dev_flow->dv.actions[actions_n] =
13184 							ct->dr_action_rply;
13185 			flow->indirect_type = MLX5_INDIRECT_ACTION_TYPE_CT;
13186 			flow->ct = owner_idx;
13187 			__atomic_fetch_add(&ct->refcnt, 1, __ATOMIC_RELAXED);
13188 			actions_n++;
13189 			action_flags |= MLX5_FLOW_ACTION_CT;
13190 			break;
13191 		case RTE_FLOW_ACTION_TYPE_END:
13192 			actions_end = true;
13193 			if (mhdr_res->actions_num) {
13194 				/* create modify action if needed. */
13195 				if (flow_dv_modify_hdr_resource_register
13196 					(dev, mhdr_res, dev_flow, error))
13197 					return -rte_errno;
13198 				dev_flow->dv.actions[modify_action_position] =
13199 					handle->dvh.modify_hdr->action;
13200 			}
13201 			/*
13202 			 * Handle AGE and COUNT action by single HW counter
13203 			 * when they are not shared.
13204 			 */
13205 			if (action_flags & MLX5_FLOW_ACTION_AGE) {
13206 				if ((non_shared_age &&
13207 				     count && !count->shared) ||
13208 				    !(priv->sh->flow_hit_aso_en &&
13209 				      (attr->group || attr->transfer))) {
13210 					/* Creates age by counters. */
13211 					cnt_act = flow_dv_prepare_counter
13212 								(dev, dev_flow,
13213 								 flow, count,
13214 								 non_shared_age,
13215 								 error);
13216 					if (!cnt_act)
13217 						return -rte_errno;
13218 					dev_flow->dv.actions[age_act_pos] =
13219 								cnt_act->action;
13220 					break;
13221 				}
13222 				if (!flow->age && non_shared_age) {
13223 					flow->age = flow_dv_aso_age_alloc
13224 								(dev, error);
13225 					if (!flow->age)
13226 						return -rte_errno;
13227 					flow_dv_aso_age_params_init
13228 						    (dev, flow->age,
13229 						     non_shared_age->context ?
13230 						     non_shared_age->context :
13231 						     (void *)(uintptr_t)
13232 						     (dev_flow->flow_idx),
13233 						     non_shared_age->timeout);
13234 				}
13235 				age_act = flow_aso_age_get_by_idx(dev,
13236 								  flow->age);
13237 				dev_flow->dv.actions[age_act_pos] =
13238 							     age_act->dr_action;
13239 			}
13240 			if (action_flags & MLX5_FLOW_ACTION_COUNT) {
13241 				/*
13242 				 * Create one count action, to be used
13243 				 * by all sub-flows.
13244 				 */
13245 				cnt_act = flow_dv_prepare_counter(dev, dev_flow,
13246 								  flow, count,
13247 								  NULL, error);
13248 				if (!cnt_act)
13249 					return -rte_errno;
13250 				dev_flow->dv.actions[actions_n++] =
13251 								cnt_act->action;
13252 			}
13253 		default:
13254 			break;
13255 		}
13256 		if (mhdr_res->actions_num &&
13257 		    modify_action_position == UINT32_MAX)
13258 			modify_action_position = actions_n++;
13259 	}
13260 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
13261 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
13262 		int item_type = items->type;
13263 
13264 		if (!mlx5_flow_os_item_supported(item_type))
13265 			return rte_flow_error_set(error, ENOTSUP,
13266 						  RTE_FLOW_ERROR_TYPE_ITEM,
13267 						  NULL, "item not supported");
13268 		switch (item_type) {
13269 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
13270 			flow_dv_translate_item_port_id
13271 				(dev, match_mask, match_value, items, attr);
13272 			last_item = MLX5_FLOW_ITEM_PORT_ID;
13273 			break;
13274 		case RTE_FLOW_ITEM_TYPE_ETH:
13275 			flow_dv_translate_item_eth(match_mask, match_value,
13276 						   items, tunnel,
13277 						   dev_flow->dv.group);
13278 			matcher.priority = action_flags &
13279 					MLX5_FLOW_ACTION_DEFAULT_MISS &&
13280 					!dev_flow->external ?
13281 					MLX5_PRIORITY_MAP_L3 :
13282 					MLX5_PRIORITY_MAP_L2;
13283 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
13284 					     MLX5_FLOW_LAYER_OUTER_L2;
13285 			break;
13286 		case RTE_FLOW_ITEM_TYPE_VLAN:
13287 			flow_dv_translate_item_vlan(dev_flow,
13288 						    match_mask, match_value,
13289 						    items, tunnel,
13290 						    dev_flow->dv.group);
13291 			matcher.priority = MLX5_PRIORITY_MAP_L2;
13292 			last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
13293 					      MLX5_FLOW_LAYER_INNER_VLAN) :
13294 					     (MLX5_FLOW_LAYER_OUTER_L2 |
13295 					      MLX5_FLOW_LAYER_OUTER_VLAN);
13296 			break;
13297 		case RTE_FLOW_ITEM_TYPE_IPV4:
13298 			mlx5_flow_tunnel_ip_check(items, next_protocol,
13299 						  &item_flags, &tunnel);
13300 			flow_dv_translate_item_ipv4(match_mask, match_value,
13301 						    items, tunnel,
13302 						    dev_flow->dv.group);
13303 			matcher.priority = MLX5_PRIORITY_MAP_L3;
13304 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
13305 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
13306 			if (items->mask != NULL &&
13307 			    ((const struct rte_flow_item_ipv4 *)
13308 			     items->mask)->hdr.next_proto_id) {
13309 				next_protocol =
13310 					((const struct rte_flow_item_ipv4 *)
13311 					 (items->spec))->hdr.next_proto_id;
13312 				next_protocol &=
13313 					((const struct rte_flow_item_ipv4 *)
13314 					 (items->mask))->hdr.next_proto_id;
13315 			} else {
13316 				/* Reset for inner layer. */
13317 				next_protocol = 0xff;
13318 			}
13319 			break;
13320 		case RTE_FLOW_ITEM_TYPE_IPV6:
13321 			mlx5_flow_tunnel_ip_check(items, next_protocol,
13322 						  &item_flags, &tunnel);
13323 			flow_dv_translate_item_ipv6(match_mask, match_value,
13324 						    items, tunnel,
13325 						    dev_flow->dv.group);
13326 			matcher.priority = MLX5_PRIORITY_MAP_L3;
13327 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
13328 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
13329 			if (items->mask != NULL &&
13330 			    ((const struct rte_flow_item_ipv6 *)
13331 			     items->mask)->hdr.proto) {
13332 				next_protocol =
13333 					((const struct rte_flow_item_ipv6 *)
13334 					 items->spec)->hdr.proto;
13335 				next_protocol &=
13336 					((const struct rte_flow_item_ipv6 *)
13337 					 items->mask)->hdr.proto;
13338 			} else {
13339 				/* Reset for inner layer. */
13340 				next_protocol = 0xff;
13341 			}
13342 			break;
13343 		case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
13344 			flow_dv_translate_item_ipv6_frag_ext(match_mask,
13345 							     match_value,
13346 							     items, tunnel);
13347 			last_item = tunnel ?
13348 					MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
13349 					MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
13350 			if (items->mask != NULL &&
13351 			    ((const struct rte_flow_item_ipv6_frag_ext *)
13352 			     items->mask)->hdr.next_header) {
13353 				next_protocol =
13354 				((const struct rte_flow_item_ipv6_frag_ext *)
13355 				 items->spec)->hdr.next_header;
13356 				next_protocol &=
13357 				((const struct rte_flow_item_ipv6_frag_ext *)
13358 				 items->mask)->hdr.next_header;
13359 			} else {
13360 				/* Reset for inner layer. */
13361 				next_protocol = 0xff;
13362 			}
13363 			break;
13364 		case RTE_FLOW_ITEM_TYPE_TCP:
13365 			flow_dv_translate_item_tcp(match_mask, match_value,
13366 						   items, tunnel);
13367 			matcher.priority = MLX5_PRIORITY_MAP_L4;
13368 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
13369 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
13370 			break;
13371 		case RTE_FLOW_ITEM_TYPE_UDP:
13372 			flow_dv_translate_item_udp(match_mask, match_value,
13373 						   items, tunnel);
13374 			matcher.priority = MLX5_PRIORITY_MAP_L4;
13375 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
13376 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
13377 			break;
13378 		case RTE_FLOW_ITEM_TYPE_GRE:
13379 			flow_dv_translate_item_gre(match_mask, match_value,
13380 						   items, tunnel);
13381 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13382 			last_item = MLX5_FLOW_LAYER_GRE;
13383 			break;
13384 		case RTE_FLOW_ITEM_TYPE_GRE_KEY:
13385 			flow_dv_translate_item_gre_key(match_mask,
13386 						       match_value, items);
13387 			last_item = MLX5_FLOW_LAYER_GRE_KEY;
13388 			break;
13389 		case RTE_FLOW_ITEM_TYPE_NVGRE:
13390 			flow_dv_translate_item_nvgre(match_mask, match_value,
13391 						     items, tunnel);
13392 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13393 			last_item = MLX5_FLOW_LAYER_GRE;
13394 			break;
13395 		case RTE_FLOW_ITEM_TYPE_VXLAN:
13396 			flow_dv_translate_item_vxlan(dev, attr,
13397 						     match_mask, match_value,
13398 						     items, tunnel);
13399 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13400 			last_item = MLX5_FLOW_LAYER_VXLAN;
13401 			break;
13402 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
13403 			flow_dv_translate_item_vxlan_gpe(match_mask,
13404 							 match_value, items,
13405 							 tunnel);
13406 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13407 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
13408 			break;
13409 		case RTE_FLOW_ITEM_TYPE_GENEVE:
13410 			flow_dv_translate_item_geneve(match_mask, match_value,
13411 						      items, tunnel);
13412 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13413 			last_item = MLX5_FLOW_LAYER_GENEVE;
13414 			break;
13415 		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
13416 			ret = flow_dv_translate_item_geneve_opt(dev, match_mask,
13417 							  match_value,
13418 							  items, error);
13419 			if (ret)
13420 				return rte_flow_error_set(error, -ret,
13421 					RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13422 					"cannot create GENEVE TLV option");
13423 			flow->geneve_tlv_option = 1;
13424 			last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
13425 			break;
13426 		case RTE_FLOW_ITEM_TYPE_MPLS:
13427 			flow_dv_translate_item_mpls(match_mask, match_value,
13428 						    items, last_item, tunnel);
13429 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13430 			last_item = MLX5_FLOW_LAYER_MPLS;
13431 			break;
13432 		case RTE_FLOW_ITEM_TYPE_MARK:
13433 			flow_dv_translate_item_mark(dev, match_mask,
13434 						    match_value, items);
13435 			last_item = MLX5_FLOW_ITEM_MARK;
13436 			break;
13437 		case RTE_FLOW_ITEM_TYPE_META:
13438 			flow_dv_translate_item_meta(dev, match_mask,
13439 						    match_value, attr, items);
13440 			last_item = MLX5_FLOW_ITEM_METADATA;
13441 			break;
13442 		case RTE_FLOW_ITEM_TYPE_ICMP:
13443 			flow_dv_translate_item_icmp(match_mask, match_value,
13444 						    items, tunnel);
13445 			last_item = MLX5_FLOW_LAYER_ICMP;
13446 			break;
13447 		case RTE_FLOW_ITEM_TYPE_ICMP6:
13448 			flow_dv_translate_item_icmp6(match_mask, match_value,
13449 						      items, tunnel);
13450 			last_item = MLX5_FLOW_LAYER_ICMP6;
13451 			break;
13452 		case RTE_FLOW_ITEM_TYPE_TAG:
13453 			flow_dv_translate_item_tag(dev, match_mask,
13454 						   match_value, items);
13455 			last_item = MLX5_FLOW_ITEM_TAG;
13456 			break;
13457 		case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
13458 			flow_dv_translate_mlx5_item_tag(dev, match_mask,
13459 							match_value, items);
13460 			last_item = MLX5_FLOW_ITEM_TAG;
13461 			break;
13462 		case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
13463 			flow_dv_translate_item_tx_queue(dev, match_mask,
13464 							match_value,
13465 							items);
13466 			last_item = MLX5_FLOW_ITEM_TX_QUEUE;
13467 			break;
13468 		case RTE_FLOW_ITEM_TYPE_GTP:
13469 			flow_dv_translate_item_gtp(match_mask, match_value,
13470 						   items, tunnel);
13471 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13472 			last_item = MLX5_FLOW_LAYER_GTP;
13473 			break;
13474 		case RTE_FLOW_ITEM_TYPE_GTP_PSC:
13475 			ret = flow_dv_translate_item_gtp_psc(match_mask,
13476 							  match_value,
13477 							  items);
13478 			if (ret)
13479 				return rte_flow_error_set(error, -ret,
13480 					RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13481 					"cannot create GTP PSC item");
13482 			last_item = MLX5_FLOW_LAYER_GTP_PSC;
13483 			break;
13484 		case RTE_FLOW_ITEM_TYPE_ECPRI:
13485 			if (!mlx5_flex_parser_ecpri_exist(dev)) {
13486 				/* Create it only the first time to be used. */
13487 				ret = mlx5_flex_parser_ecpri_alloc(dev);
13488 				if (ret)
13489 					return rte_flow_error_set
13490 						(error, -ret,
13491 						RTE_FLOW_ERROR_TYPE_ITEM,
13492 						NULL,
13493 						"cannot create eCPRI parser");
13494 			}
13495 			flow_dv_translate_item_ecpri(dev, match_mask,
13496 						     match_value, items,
13497 						     last_item);
13498 			/* No other protocol should follow eCPRI layer. */
13499 			last_item = MLX5_FLOW_LAYER_ECPRI;
13500 			break;
13501 		case RTE_FLOW_ITEM_TYPE_INTEGRITY:
13502 			flow_dv_translate_item_integrity(match_mask,
13503 							 match_value,
13504 							 head_item, items);
13505 			break;
13506 		case RTE_FLOW_ITEM_TYPE_CONNTRACK:
13507 			flow_dv_translate_item_aso_ct(dev, match_mask,
13508 						      match_value, items);
13509 			break;
13510 		default:
13511 			break;
13512 		}
13513 		item_flags |= last_item;
13514 	}
13515 	/*
13516 	 * When E-Switch mode is enabled, we have two cases where we need to
13517 	 * set the source port manually.
13518 	 * The first one, is in case of Nic steering rule, and the second is
13519 	 * E-Switch rule where no port_id item was found. In both cases
13520 	 * the source port is set according the current port in use.
13521 	 */
13522 	if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) &&
13523 	    (priv->representor || priv->master)) {
13524 		if (flow_dv_translate_item_port_id(dev, match_mask,
13525 						   match_value, NULL, attr))
13526 			return -rte_errno;
13527 	}
13528 #ifdef RTE_LIBRTE_MLX5_DEBUG
13529 	MLX5_ASSERT(!flow_dv_check_valid_spec(matcher.mask.buf,
13530 					      dev_flow->dv.value.buf));
13531 #endif
13532 	/*
13533 	 * Layers may be already initialized from prefix flow if this dev_flow
13534 	 * is the suffix flow.
13535 	 */
13536 	handle->layers |= item_flags;
13537 	if (action_flags & MLX5_FLOW_ACTION_RSS)
13538 		flow_dv_hashfields_set(dev_flow, rss_desc);
13539 	/* If has RSS action in the sample action, the Sample/Mirror resource
13540 	 * should be registered after the hash filed be update.
13541 	 */
13542 	if (action_flags & MLX5_FLOW_ACTION_SAMPLE) {
13543 		ret = flow_dv_translate_action_sample(dev,
13544 						      sample,
13545 						      dev_flow, attr,
13546 						      &num_of_dest,
13547 						      sample_actions,
13548 						      &sample_res,
13549 						      error);
13550 		if (ret < 0)
13551 			return ret;
13552 		ret = flow_dv_create_action_sample(dev,
13553 						   dev_flow,
13554 						   num_of_dest,
13555 						   &sample_res,
13556 						   &mdest_res,
13557 						   sample_actions,
13558 						   action_flags,
13559 						   error);
13560 		if (ret < 0)
13561 			return rte_flow_error_set
13562 						(error, rte_errno,
13563 						RTE_FLOW_ERROR_TYPE_ACTION,
13564 						NULL,
13565 						"cannot create sample action");
13566 		if (num_of_dest > 1) {
13567 			dev_flow->dv.actions[sample_act_pos] =
13568 			dev_flow->dv.dest_array_res->action;
13569 		} else {
13570 			dev_flow->dv.actions[sample_act_pos] =
13571 			dev_flow->dv.sample_res->verbs_action;
13572 		}
13573 	}
13574 	/*
13575 	 * For multiple destination (sample action with ratio=1), the encap
13576 	 * action and port id action will be combined into group action.
13577 	 * So need remove the original these actions in the flow and only
13578 	 * use the sample action instead of.
13579 	 */
13580 	if (num_of_dest > 1 &&
13581 	    (sample_act->dr_port_id_action || sample_act->dr_jump_action)) {
13582 		int i;
13583 		void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
13584 
13585 		for (i = 0; i < actions_n; i++) {
13586 			if ((sample_act->dr_encap_action &&
13587 				sample_act->dr_encap_action ==
13588 				dev_flow->dv.actions[i]) ||
13589 				(sample_act->dr_port_id_action &&
13590 				sample_act->dr_port_id_action ==
13591 				dev_flow->dv.actions[i]) ||
13592 				(sample_act->dr_jump_action &&
13593 				sample_act->dr_jump_action ==
13594 				dev_flow->dv.actions[i]))
13595 				continue;
13596 			temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];
13597 		}
13598 		memcpy((void *)dev_flow->dv.actions,
13599 				(void *)temp_actions,
13600 				tmp_actions_n * sizeof(void *));
13601 		actions_n = tmp_actions_n;
13602 	}
13603 	dev_flow->dv.actions_n = actions_n;
13604 	dev_flow->act_flags = action_flags;
13605 	if (wks->skip_matcher_reg)
13606 		return 0;
13607 	/* Register matcher. */
13608 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
13609 				    matcher.mask.size);
13610 	matcher.priority = mlx5_get_matcher_priority(dev, attr,
13611 					matcher.priority);
13612 	/**
13613 	 * When creating meter drop flow in drop table, using original
13614 	 * 5-tuple match, the matcher priority should be lower than
13615 	 * mtr_id matcher.
13616 	 */
13617 	if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
13618 	    dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP &&
13619 	    matcher.priority <= MLX5_REG_BITS)
13620 		matcher.priority += MLX5_REG_BITS;
13621 	/* reserved field no needs to be set to 0 here. */
13622 	tbl_key.is_fdb = attr->transfer;
13623 	tbl_key.is_egress = attr->egress;
13624 	tbl_key.level = dev_flow->dv.group;
13625 	tbl_key.id = dev_flow->dv.table_id;
13626 	if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow,
13627 				     tunnel, attr->group, error))
13628 		return -rte_errno;
13629 	return 0;
13630 }
13631 
13632 /**
13633  * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields)
13634  * and tunnel.
13635  *
13636  * @param[in, out] action
13637  *   Shred RSS action holding hash RX queue objects.
13638  * @param[in] hash_fields
13639  *   Defines combination of packet fields to participate in RX hash.
13640  * @param[in] tunnel
13641  *   Tunnel type
13642  * @param[in] hrxq_idx
13643  *   Hash RX queue index to set.
13644  *
13645  * @return
13646  *   0 on success, otherwise negative errno value.
13647  */
13648 static int
13649 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action,
13650 			      const uint64_t hash_fields,
13651 			      uint32_t hrxq_idx)
13652 {
13653 	uint32_t *hrxqs = action->hrxq;
13654 
13655 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
13656 	case MLX5_RSS_HASH_IPV4:
13657 		/* fall-through. */
13658 	case MLX5_RSS_HASH_IPV4_DST_ONLY:
13659 		/* fall-through. */
13660 	case MLX5_RSS_HASH_IPV4_SRC_ONLY:
13661 		hrxqs[0] = hrxq_idx;
13662 		return 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 		hrxqs[1] = hrxq_idx;
13669 		return 0;
13670 	case MLX5_RSS_HASH_IPV4_UDP:
13671 		/* fall-through. */
13672 	case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
13673 		/* fall-through. */
13674 	case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
13675 		hrxqs[2] = hrxq_idx;
13676 		return 0;
13677 	case MLX5_RSS_HASH_IPV6:
13678 		/* fall-through. */
13679 	case MLX5_RSS_HASH_IPV6_DST_ONLY:
13680 		/* fall-through. */
13681 	case MLX5_RSS_HASH_IPV6_SRC_ONLY:
13682 		hrxqs[3] = hrxq_idx;
13683 		return 0;
13684 	case MLX5_RSS_HASH_IPV6_TCP:
13685 		/* fall-through. */
13686 	case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
13687 		/* fall-through. */
13688 	case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
13689 		hrxqs[4] = hrxq_idx;
13690 		return 0;
13691 	case MLX5_RSS_HASH_IPV6_UDP:
13692 		/* fall-through. */
13693 	case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
13694 		/* fall-through. */
13695 	case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
13696 		hrxqs[5] = hrxq_idx;
13697 		return 0;
13698 	case MLX5_RSS_HASH_NONE:
13699 		hrxqs[6] = hrxq_idx;
13700 		return 0;
13701 	default:
13702 		return -1;
13703 	}
13704 }
13705 
13706 /**
13707  * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields)
13708  * and tunnel.
13709  *
13710  * @param[in] dev
13711  *   Pointer to the Ethernet device structure.
13712  * @param[in] idx
13713  *   Shared RSS action ID holding hash RX queue objects.
13714  * @param[in] hash_fields
13715  *   Defines combination of packet fields to participate in RX hash.
13716  * @param[in] tunnel
13717  *   Tunnel type
13718  *
13719  * @return
13720  *   Valid hash RX queue index, otherwise 0.
13721  */
13722 static uint32_t
13723 __flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx,
13724 				 const uint64_t hash_fields)
13725 {
13726 	struct mlx5_priv *priv = dev->data->dev_private;
13727 	struct mlx5_shared_action_rss *shared_rss =
13728 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
13729 	const uint32_t *hrxqs = shared_rss->hrxq;
13730 
13731 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
13732 	case MLX5_RSS_HASH_IPV4:
13733 		/* fall-through. */
13734 	case MLX5_RSS_HASH_IPV4_DST_ONLY:
13735 		/* fall-through. */
13736 	case MLX5_RSS_HASH_IPV4_SRC_ONLY:
13737 		return hrxqs[0];
13738 	case MLX5_RSS_HASH_IPV4_TCP:
13739 		/* fall-through. */
13740 	case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY:
13741 		/* fall-through. */
13742 	case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY:
13743 		return hrxqs[1];
13744 	case MLX5_RSS_HASH_IPV4_UDP:
13745 		/* fall-through. */
13746 	case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
13747 		/* fall-through. */
13748 	case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
13749 		return hrxqs[2];
13750 	case MLX5_RSS_HASH_IPV6:
13751 		/* fall-through. */
13752 	case MLX5_RSS_HASH_IPV6_DST_ONLY:
13753 		/* fall-through. */
13754 	case MLX5_RSS_HASH_IPV6_SRC_ONLY:
13755 		return hrxqs[3];
13756 	case MLX5_RSS_HASH_IPV6_TCP:
13757 		/* fall-through. */
13758 	case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
13759 		/* fall-through. */
13760 	case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
13761 		return hrxqs[4];
13762 	case MLX5_RSS_HASH_IPV6_UDP:
13763 		/* fall-through. */
13764 	case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
13765 		/* fall-through. */
13766 	case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
13767 		return hrxqs[5];
13768 	case MLX5_RSS_HASH_NONE:
13769 		return hrxqs[6];
13770 	default:
13771 		return 0;
13772 	}
13773 
13774 }
13775 
13776 /**
13777  * Apply the flow to the NIC, lock free,
13778  * (mutex should be acquired by caller).
13779  *
13780  * @param[in] dev
13781  *   Pointer to the Ethernet device structure.
13782  * @param[in, out] flow
13783  *   Pointer to flow structure.
13784  * @param[out] error
13785  *   Pointer to error structure.
13786  *
13787  * @return
13788  *   0 on success, a negative errno value otherwise and rte_errno is set.
13789  */
13790 static int
13791 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
13792 	      struct rte_flow_error *error)
13793 {
13794 	struct mlx5_flow_dv_workspace *dv;
13795 	struct mlx5_flow_handle *dh;
13796 	struct mlx5_flow_handle_dv *dv_h;
13797 	struct mlx5_flow *dev_flow;
13798 	struct mlx5_priv *priv = dev->data->dev_private;
13799 	uint32_t handle_idx;
13800 	int n;
13801 	int err;
13802 	int idx;
13803 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
13804 	struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc;
13805 	uint8_t misc_mask;
13806 
13807 	MLX5_ASSERT(wks);
13808 	for (idx = wks->flow_idx - 1; idx >= 0; idx--) {
13809 		dev_flow = &wks->flows[idx];
13810 		dv = &dev_flow->dv;
13811 		dh = dev_flow->handle;
13812 		dv_h = &dh->dvh;
13813 		n = dv->actions_n;
13814 		if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
13815 			if (dv->transfer) {
13816 				MLX5_ASSERT(priv->sh->dr_drop_action);
13817 				dv->actions[n++] = priv->sh->dr_drop_action;
13818 			} else {
13819 #ifdef HAVE_MLX5DV_DR
13820 				/* DR supports drop action placeholder. */
13821 				MLX5_ASSERT(priv->sh->dr_drop_action);
13822 				dv->actions[n++] = dv->group ?
13823 					priv->sh->dr_drop_action :
13824 					priv->root_drop_action;
13825 #else
13826 				/* For DV we use the explicit drop queue. */
13827 				MLX5_ASSERT(priv->drop_queue.hrxq);
13828 				dv->actions[n++] =
13829 						priv->drop_queue.hrxq->action;
13830 #endif
13831 			}
13832 		} else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE &&
13833 			   !dv_h->rix_sample && !dv_h->rix_dest_array)) {
13834 			struct mlx5_hrxq *hrxq;
13835 			uint32_t hrxq_idx;
13836 
13837 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc,
13838 						    &hrxq_idx);
13839 			if (!hrxq) {
13840 				rte_flow_error_set
13841 					(error, rte_errno,
13842 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13843 					 "cannot get hash queue");
13844 				goto error;
13845 			}
13846 			dh->rix_hrxq = hrxq_idx;
13847 			dv->actions[n++] = hrxq->action;
13848 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
13849 			struct mlx5_hrxq *hrxq = NULL;
13850 			uint32_t hrxq_idx;
13851 
13852 			hrxq_idx = __flow_dv_action_rss_hrxq_lookup(dev,
13853 						rss_desc->shared_rss,
13854 						dev_flow->hash_fields);
13855 			if (hrxq_idx)
13856 				hrxq = mlx5_ipool_get
13857 					(priv->sh->ipool[MLX5_IPOOL_HRXQ],
13858 					 hrxq_idx);
13859 			if (!hrxq) {
13860 				rte_flow_error_set
13861 					(error, rte_errno,
13862 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13863 					 "cannot get hash queue");
13864 				goto error;
13865 			}
13866 			dh->rix_srss = rss_desc->shared_rss;
13867 			dv->actions[n++] = hrxq->action;
13868 		} else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) {
13869 			if (!priv->sh->default_miss_action) {
13870 				rte_flow_error_set
13871 					(error, rte_errno,
13872 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13873 					 "default miss action not be created.");
13874 				goto error;
13875 			}
13876 			dv->actions[n++] = priv->sh->default_miss_action;
13877 		}
13878 		misc_mask = flow_dv_matcher_enable(dv->value.buf);
13879 		__flow_dv_adjust_buf_size(&dv->value.size, misc_mask);
13880 		err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object,
13881 					       (void *)&dv->value, n,
13882 					       dv->actions, &dh->drv_flow);
13883 		if (err) {
13884 			rte_flow_error_set
13885 				(error, errno,
13886 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13887 				NULL,
13888 				(!priv->config.allow_duplicate_pattern &&
13889 				errno == EEXIST) ?
13890 				"duplicating pattern is not allowed" :
13891 				"hardware refuses to create flow");
13892 			goto error;
13893 		}
13894 		if (priv->vmwa_context &&
13895 		    dh->vf_vlan.tag && !dh->vf_vlan.created) {
13896 			/*
13897 			 * The rule contains the VLAN pattern.
13898 			 * For VF we are going to create VLAN
13899 			 * interface to make hypervisor set correct
13900 			 * e-Switch vport context.
13901 			 */
13902 			mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan);
13903 		}
13904 	}
13905 	return 0;
13906 error:
13907 	err = rte_errno; /* Save rte_errno before cleanup. */
13908 	SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
13909 		       handle_idx, dh, next) {
13910 		/* hrxq is union, don't clear it if the flag is not set. */
13911 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) {
13912 			mlx5_hrxq_release(dev, dh->rix_hrxq);
13913 			dh->rix_hrxq = 0;
13914 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
13915 			dh->rix_srss = 0;
13916 		}
13917 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
13918 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
13919 	}
13920 	rte_errno = err; /* Restore rte_errno. */
13921 	return -rte_errno;
13922 }
13923 
13924 void
13925 flow_dv_matcher_remove_cb(void *tool_ctx __rte_unused,
13926 			  struct mlx5_list_entry *entry)
13927 {
13928 	struct mlx5_flow_dv_matcher *resource = container_of(entry,
13929 							     typeof(*resource),
13930 							     entry);
13931 
13932 	claim_zero(mlx5_flow_os_destroy_flow_matcher(resource->matcher_object));
13933 	mlx5_free(resource);
13934 }
13935 
13936 /**
13937  * Release the flow matcher.
13938  *
13939  * @param dev
13940  *   Pointer to Ethernet device.
13941  * @param port_id
13942  *   Index to port ID action resource.
13943  *
13944  * @return
13945  *   1 while a reference on it exists, 0 when freed.
13946  */
13947 static int
13948 flow_dv_matcher_release(struct rte_eth_dev *dev,
13949 			struct mlx5_flow_handle *handle)
13950 {
13951 	struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher;
13952 	struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl,
13953 							    typeof(*tbl), tbl);
13954 	int ret;
13955 
13956 	MLX5_ASSERT(matcher->matcher_object);
13957 	ret = mlx5_list_unregister(tbl->matchers, &matcher->entry);
13958 	flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl);
13959 	return ret;
13960 }
13961 
13962 void
13963 flow_dv_encap_decap_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
13964 {
13965 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
13966 	struct mlx5_flow_dv_encap_decap_resource *res =
13967 				       container_of(entry, typeof(*res), entry);
13968 
13969 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
13970 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
13971 }
13972 
13973 /**
13974  * Release an encap/decap resource.
13975  *
13976  * @param dev
13977  *   Pointer to Ethernet device.
13978  * @param encap_decap_idx
13979  *   Index of encap decap resource.
13980  *
13981  * @return
13982  *   1 while a reference on it exists, 0 when freed.
13983  */
13984 static int
13985 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
13986 				     uint32_t encap_decap_idx)
13987 {
13988 	struct mlx5_priv *priv = dev->data->dev_private;
13989 	struct mlx5_flow_dv_encap_decap_resource *resource;
13990 
13991 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
13992 				  encap_decap_idx);
13993 	if (!resource)
13994 		return 0;
13995 	MLX5_ASSERT(resource->action);
13996 	return mlx5_hlist_unregister(priv->sh->encaps_decaps, &resource->entry);
13997 }
13998 
13999 /**
14000  * Release an jump to table action resource.
14001  *
14002  * @param dev
14003  *   Pointer to Ethernet device.
14004  * @param rix_jump
14005  *   Index to the jump action resource.
14006  *
14007  * @return
14008  *   1 while a reference on it exists, 0 when freed.
14009  */
14010 static int
14011 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
14012 				  uint32_t rix_jump)
14013 {
14014 	struct mlx5_priv *priv = dev->data->dev_private;
14015 	struct mlx5_flow_tbl_data_entry *tbl_data;
14016 
14017 	tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP],
14018 				  rix_jump);
14019 	if (!tbl_data)
14020 		return 0;
14021 	return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl);
14022 }
14023 
14024 void
14025 flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14026 {
14027 	struct mlx5_flow_dv_modify_hdr_resource *res =
14028 		container_of(entry, typeof(*res), entry);
14029 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14030 
14031 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
14032 	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
14033 }
14034 
14035 /**
14036  * Release a modify-header resource.
14037  *
14038  * @param dev
14039  *   Pointer to Ethernet device.
14040  * @param handle
14041  *   Pointer to mlx5_flow_handle.
14042  *
14043  * @return
14044  *   1 while a reference on it exists, 0 when freed.
14045  */
14046 static int
14047 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev,
14048 				    struct mlx5_flow_handle *handle)
14049 {
14050 	struct mlx5_priv *priv = dev->data->dev_private;
14051 	struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr;
14052 
14053 	MLX5_ASSERT(entry->action);
14054 	return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry);
14055 }
14056 
14057 void
14058 flow_dv_port_id_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14059 {
14060 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14061 	struct mlx5_flow_dv_port_id_action_resource *resource =
14062 				  container_of(entry, typeof(*resource), entry);
14063 
14064 	claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14065 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
14066 }
14067 
14068 /**
14069  * Release port ID action resource.
14070  *
14071  * @param dev
14072  *   Pointer to Ethernet device.
14073  * @param handle
14074  *   Pointer to mlx5_flow_handle.
14075  *
14076  * @return
14077  *   1 while a reference on it exists, 0 when freed.
14078  */
14079 static int
14080 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
14081 					uint32_t port_id)
14082 {
14083 	struct mlx5_priv *priv = dev->data->dev_private;
14084 	struct mlx5_flow_dv_port_id_action_resource *resource;
14085 
14086 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id);
14087 	if (!resource)
14088 		return 0;
14089 	MLX5_ASSERT(resource->action);
14090 	return mlx5_list_unregister(priv->sh->port_id_action_list,
14091 				    &resource->entry);
14092 }
14093 
14094 /**
14095  * Release shared RSS action resource.
14096  *
14097  * @param dev
14098  *   Pointer to Ethernet device.
14099  * @param srss
14100  *   Shared RSS action index.
14101  */
14102 static void
14103 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss)
14104 {
14105 	struct mlx5_priv *priv = dev->data->dev_private;
14106 	struct mlx5_shared_action_rss *shared_rss;
14107 
14108 	shared_rss = mlx5_ipool_get
14109 			(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss);
14110 	__atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
14111 }
14112 
14113 void
14114 flow_dv_push_vlan_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14115 {
14116 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14117 	struct mlx5_flow_dv_push_vlan_action_resource *resource =
14118 			container_of(entry, typeof(*resource), entry);
14119 
14120 	claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14121 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
14122 }
14123 
14124 /**
14125  * Release push vlan action resource.
14126  *
14127  * @param dev
14128  *   Pointer to Ethernet device.
14129  * @param handle
14130  *   Pointer to mlx5_flow_handle.
14131  *
14132  * @return
14133  *   1 while a reference on it exists, 0 when freed.
14134  */
14135 static int
14136 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev,
14137 					  struct mlx5_flow_handle *handle)
14138 {
14139 	struct mlx5_priv *priv = dev->data->dev_private;
14140 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
14141 	uint32_t idx = handle->dvh.rix_push_vlan;
14142 
14143 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
14144 	if (!resource)
14145 		return 0;
14146 	MLX5_ASSERT(resource->action);
14147 	return mlx5_list_unregister(priv->sh->push_vlan_action_list,
14148 				    &resource->entry);
14149 }
14150 
14151 /**
14152  * Release the fate resource.
14153  *
14154  * @param dev
14155  *   Pointer to Ethernet device.
14156  * @param handle
14157  *   Pointer to mlx5_flow_handle.
14158  */
14159 static void
14160 flow_dv_fate_resource_release(struct rte_eth_dev *dev,
14161 			       struct mlx5_flow_handle *handle)
14162 {
14163 	if (!handle->rix_fate)
14164 		return;
14165 	switch (handle->fate_action) {
14166 	case MLX5_FLOW_FATE_QUEUE:
14167 		if (!handle->dvh.rix_sample && !handle->dvh.rix_dest_array)
14168 			mlx5_hrxq_release(dev, handle->rix_hrxq);
14169 		break;
14170 	case MLX5_FLOW_FATE_JUMP:
14171 		flow_dv_jump_tbl_resource_release(dev, handle->rix_jump);
14172 		break;
14173 	case MLX5_FLOW_FATE_PORT_ID:
14174 		flow_dv_port_id_action_resource_release(dev,
14175 				handle->rix_port_id_action);
14176 		break;
14177 	default:
14178 		DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action);
14179 		break;
14180 	}
14181 	handle->rix_fate = 0;
14182 }
14183 
14184 void
14185 flow_dv_sample_remove_cb(void *tool_ctx __rte_unused,
14186 			 struct mlx5_list_entry *entry)
14187 {
14188 	struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
14189 							      typeof(*resource),
14190 							      entry);
14191 	struct rte_eth_dev *dev = resource->dev;
14192 	struct mlx5_priv *priv = dev->data->dev_private;
14193 
14194 	if (resource->verbs_action)
14195 		claim_zero(mlx5_flow_os_destroy_flow_action
14196 						      (resource->verbs_action));
14197 	if (resource->normal_path_tbl)
14198 		flow_dv_tbl_resource_release(MLX5_SH(dev),
14199 					     resource->normal_path_tbl);
14200 	flow_dv_sample_sub_actions_release(dev, &resource->sample_idx);
14201 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
14202 	DRV_LOG(DEBUG, "sample resource %p: removed", (void *)resource);
14203 }
14204 
14205 /**
14206  * Release an sample resource.
14207  *
14208  * @param dev
14209  *   Pointer to Ethernet device.
14210  * @param handle
14211  *   Pointer to mlx5_flow_handle.
14212  *
14213  * @return
14214  *   1 while a reference on it exists, 0 when freed.
14215  */
14216 static int
14217 flow_dv_sample_resource_release(struct rte_eth_dev *dev,
14218 				     struct mlx5_flow_handle *handle)
14219 {
14220 	struct mlx5_priv *priv = dev->data->dev_private;
14221 	struct mlx5_flow_dv_sample_resource *resource;
14222 
14223 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE],
14224 				  handle->dvh.rix_sample);
14225 	if (!resource)
14226 		return 0;
14227 	MLX5_ASSERT(resource->verbs_action);
14228 	return mlx5_list_unregister(priv->sh->sample_action_list,
14229 				    &resource->entry);
14230 }
14231 
14232 void
14233 flow_dv_dest_array_remove_cb(void *tool_ctx __rte_unused,
14234 			     struct mlx5_list_entry *entry)
14235 {
14236 	struct mlx5_flow_dv_dest_array_resource *resource =
14237 			container_of(entry, typeof(*resource), entry);
14238 	struct rte_eth_dev *dev = resource->dev;
14239 	struct mlx5_priv *priv = dev->data->dev_private;
14240 	uint32_t i = 0;
14241 
14242 	MLX5_ASSERT(resource->action);
14243 	if (resource->action)
14244 		claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14245 	for (; i < resource->num_of_dest; i++)
14246 		flow_dv_sample_sub_actions_release(dev,
14247 						   &resource->sample_idx[i]);
14248 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
14249 	DRV_LOG(DEBUG, "destination array resource %p: removed",
14250 		(void *)resource);
14251 }
14252 
14253 /**
14254  * Release an destination array resource.
14255  *
14256  * @param dev
14257  *   Pointer to Ethernet device.
14258  * @param handle
14259  *   Pointer to mlx5_flow_handle.
14260  *
14261  * @return
14262  *   1 while a reference on it exists, 0 when freed.
14263  */
14264 static int
14265 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev,
14266 				    struct mlx5_flow_handle *handle)
14267 {
14268 	struct mlx5_priv *priv = dev->data->dev_private;
14269 	struct mlx5_flow_dv_dest_array_resource *resource;
14270 
14271 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY],
14272 				  handle->dvh.rix_dest_array);
14273 	if (!resource)
14274 		return 0;
14275 	MLX5_ASSERT(resource->action);
14276 	return mlx5_list_unregister(priv->sh->dest_array_list,
14277 				    &resource->entry);
14278 }
14279 
14280 static void
14281 flow_dv_geneve_tlv_option_resource_release(struct rte_eth_dev *dev)
14282 {
14283 	struct mlx5_priv *priv = dev->data->dev_private;
14284 	struct mlx5_dev_ctx_shared *sh = priv->sh;
14285 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
14286 				sh->geneve_tlv_option_resource;
14287 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
14288 	if (geneve_opt_resource) {
14289 		if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1,
14290 					 __ATOMIC_RELAXED))) {
14291 			claim_zero(mlx5_devx_cmd_destroy
14292 					(geneve_opt_resource->obj));
14293 			mlx5_free(sh->geneve_tlv_option_resource);
14294 			sh->geneve_tlv_option_resource = NULL;
14295 		}
14296 	}
14297 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
14298 }
14299 
14300 /**
14301  * Remove the flow from the NIC but keeps it in memory.
14302  * Lock free, (mutex should be acquired by caller).
14303  *
14304  * @param[in] dev
14305  *   Pointer to Ethernet device.
14306  * @param[in, out] flow
14307  *   Pointer to flow structure.
14308  */
14309 static void
14310 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
14311 {
14312 	struct mlx5_flow_handle *dh;
14313 	uint32_t handle_idx;
14314 	struct mlx5_priv *priv = dev->data->dev_private;
14315 
14316 	if (!flow)
14317 		return;
14318 	handle_idx = flow->dev_handles;
14319 	while (handle_idx) {
14320 		dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
14321 				    handle_idx);
14322 		if (!dh)
14323 			return;
14324 		if (dh->drv_flow) {
14325 			claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow));
14326 			dh->drv_flow = NULL;
14327 		}
14328 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE)
14329 			flow_dv_fate_resource_release(dev, dh);
14330 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
14331 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
14332 		handle_idx = dh->next.next;
14333 	}
14334 }
14335 
14336 /**
14337  * Remove the flow from the NIC and the memory.
14338  * Lock free, (mutex should be acquired by caller).
14339  *
14340  * @param[in] dev
14341  *   Pointer to the Ethernet device structure.
14342  * @param[in, out] flow
14343  *   Pointer to flow structure.
14344  */
14345 static void
14346 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
14347 {
14348 	struct mlx5_flow_handle *dev_handle;
14349 	struct mlx5_priv *priv = dev->data->dev_private;
14350 	struct mlx5_flow_meter_info *fm = NULL;
14351 	uint32_t srss = 0;
14352 
14353 	if (!flow)
14354 		return;
14355 	flow_dv_remove(dev, flow);
14356 	if (flow->counter) {
14357 		flow_dv_counter_free(dev, flow->counter);
14358 		flow->counter = 0;
14359 	}
14360 	if (flow->meter) {
14361 		fm = flow_dv_meter_find_by_idx(priv, flow->meter);
14362 		if (fm)
14363 			mlx5_flow_meter_detach(priv, fm);
14364 		flow->meter = 0;
14365 	}
14366 	/* Keep the current age handling by default. */
14367 	if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct)
14368 		flow_dv_aso_ct_release(dev, flow->ct);
14369 	else if (flow->age)
14370 		flow_dv_aso_age_release(dev, flow->age);
14371 	if (flow->geneve_tlv_option) {
14372 		flow_dv_geneve_tlv_option_resource_release(dev);
14373 		flow->geneve_tlv_option = 0;
14374 	}
14375 	while (flow->dev_handles) {
14376 		uint32_t tmp_idx = flow->dev_handles;
14377 
14378 		dev_handle = mlx5_ipool_get(priv->sh->ipool
14379 					    [MLX5_IPOOL_MLX5_FLOW], tmp_idx);
14380 		if (!dev_handle)
14381 			return;
14382 		flow->dev_handles = dev_handle->next.next;
14383 		if (dev_handle->dvh.matcher)
14384 			flow_dv_matcher_release(dev, dev_handle);
14385 		if (dev_handle->dvh.rix_sample)
14386 			flow_dv_sample_resource_release(dev, dev_handle);
14387 		if (dev_handle->dvh.rix_dest_array)
14388 			flow_dv_dest_array_resource_release(dev, dev_handle);
14389 		if (dev_handle->dvh.rix_encap_decap)
14390 			flow_dv_encap_decap_resource_release(dev,
14391 				dev_handle->dvh.rix_encap_decap);
14392 		if (dev_handle->dvh.modify_hdr)
14393 			flow_dv_modify_hdr_resource_release(dev, dev_handle);
14394 		if (dev_handle->dvh.rix_push_vlan)
14395 			flow_dv_push_vlan_action_resource_release(dev,
14396 								  dev_handle);
14397 		if (dev_handle->dvh.rix_tag)
14398 			flow_dv_tag_release(dev,
14399 					    dev_handle->dvh.rix_tag);
14400 		if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS)
14401 			flow_dv_fate_resource_release(dev, dev_handle);
14402 		else if (!srss)
14403 			srss = dev_handle->rix_srss;
14404 		if (fm && dev_handle->is_meter_flow_id &&
14405 		    dev_handle->split_flow_id)
14406 			mlx5_ipool_free(fm->flow_ipool,
14407 					dev_handle->split_flow_id);
14408 		else if (dev_handle->split_flow_id &&
14409 		    !dev_handle->is_meter_flow_id)
14410 			mlx5_ipool_free(priv->sh->ipool
14411 					[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID],
14412 					dev_handle->split_flow_id);
14413 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
14414 			   tmp_idx);
14415 	}
14416 	if (srss)
14417 		flow_dv_shared_rss_action_release(dev, srss);
14418 }
14419 
14420 /**
14421  * Release array of hash RX queue objects.
14422  * Helper function.
14423  *
14424  * @param[in] dev
14425  *   Pointer to the Ethernet device structure.
14426  * @param[in, out] hrxqs
14427  *   Array of hash RX queue objects.
14428  *
14429  * @return
14430  *   Total number of references to hash RX queue objects in *hrxqs* array
14431  *   after this operation.
14432  */
14433 static int
14434 __flow_dv_hrxqs_release(struct rte_eth_dev *dev,
14435 			uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN])
14436 {
14437 	size_t i;
14438 	int remaining = 0;
14439 
14440 	for (i = 0; i < RTE_DIM(*hrxqs); i++) {
14441 		int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]);
14442 
14443 		if (!ret)
14444 			(*hrxqs)[i] = 0;
14445 		remaining += ret;
14446 	}
14447 	return remaining;
14448 }
14449 
14450 /**
14451  * Release all hash RX queue objects representing shared RSS action.
14452  *
14453  * @param[in] dev
14454  *   Pointer to the Ethernet device structure.
14455  * @param[in, out] action
14456  *   Shared RSS action to remove hash RX queue objects from.
14457  *
14458  * @return
14459  *   Total number of references to hash RX queue objects stored in *action*
14460  *   after this operation.
14461  *   Expected to be 0 if no external references held.
14462  */
14463 static int
14464 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev,
14465 				 struct mlx5_shared_action_rss *shared_rss)
14466 {
14467 	return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq);
14468 }
14469 
14470 /**
14471  * Adjust L3/L4 hash value of pre-created shared RSS hrxq according to
14472  * user input.
14473  *
14474  * Only one hash value is available for one L3+L4 combination:
14475  * for example:
14476  * MLX5_RSS_HASH_IPV4, MLX5_RSS_HASH_IPV4_SRC_ONLY, and
14477  * MLX5_RSS_HASH_IPV4_DST_ONLY are mutually exclusive so they can share
14478  * same slot in mlx5_rss_hash_fields.
14479  *
14480  * @param[in] rss
14481  *   Pointer to the shared action RSS conf.
14482  * @param[in, out] hash_field
14483  *   hash_field variable needed to be adjusted.
14484  *
14485  * @return
14486  *   void
14487  */
14488 static void
14489 __flow_dv_action_rss_l34_hash_adjust(struct mlx5_shared_action_rss *rss,
14490 				     uint64_t *hash_field)
14491 {
14492 	uint64_t rss_types = rss->origin.types;
14493 
14494 	switch (*hash_field & ~IBV_RX_HASH_INNER) {
14495 	case MLX5_RSS_HASH_IPV4:
14496 		if (rss_types & MLX5_IPV4_LAYER_TYPES) {
14497 			*hash_field &= ~MLX5_RSS_HASH_IPV4;
14498 			if (rss_types & ETH_RSS_L3_DST_ONLY)
14499 				*hash_field |= IBV_RX_HASH_DST_IPV4;
14500 			else if (rss_types & ETH_RSS_L3_SRC_ONLY)
14501 				*hash_field |= IBV_RX_HASH_SRC_IPV4;
14502 			else
14503 				*hash_field |= MLX5_RSS_HASH_IPV4;
14504 		}
14505 		return;
14506 	case MLX5_RSS_HASH_IPV6:
14507 		if (rss_types & MLX5_IPV6_LAYER_TYPES) {
14508 			*hash_field &= ~MLX5_RSS_HASH_IPV6;
14509 			if (rss_types & ETH_RSS_L3_DST_ONLY)
14510 				*hash_field |= IBV_RX_HASH_DST_IPV6;
14511 			else if (rss_types & ETH_RSS_L3_SRC_ONLY)
14512 				*hash_field |= IBV_RX_HASH_SRC_IPV6;
14513 			else
14514 				*hash_field |= MLX5_RSS_HASH_IPV6;
14515 		}
14516 		return;
14517 	case MLX5_RSS_HASH_IPV4_UDP:
14518 		/* fall-through. */
14519 	case MLX5_RSS_HASH_IPV6_UDP:
14520 		if (rss_types & ETH_RSS_UDP) {
14521 			*hash_field &= ~MLX5_UDP_IBV_RX_HASH;
14522 			if (rss_types & ETH_RSS_L4_DST_ONLY)
14523 				*hash_field |= IBV_RX_HASH_DST_PORT_UDP;
14524 			else if (rss_types & ETH_RSS_L4_SRC_ONLY)
14525 				*hash_field |= IBV_RX_HASH_SRC_PORT_UDP;
14526 			else
14527 				*hash_field |= MLX5_UDP_IBV_RX_HASH;
14528 		}
14529 		return;
14530 	case MLX5_RSS_HASH_IPV4_TCP:
14531 		/* fall-through. */
14532 	case MLX5_RSS_HASH_IPV6_TCP:
14533 		if (rss_types & ETH_RSS_TCP) {
14534 			*hash_field &= ~MLX5_TCP_IBV_RX_HASH;
14535 			if (rss_types & ETH_RSS_L4_DST_ONLY)
14536 				*hash_field |= IBV_RX_HASH_DST_PORT_TCP;
14537 			else if (rss_types & ETH_RSS_L4_SRC_ONLY)
14538 				*hash_field |= IBV_RX_HASH_SRC_PORT_TCP;
14539 			else
14540 				*hash_field |= MLX5_TCP_IBV_RX_HASH;
14541 		}
14542 		return;
14543 	default:
14544 		return;
14545 	}
14546 }
14547 
14548 /**
14549  * Setup shared RSS action.
14550  * Prepare set of hash RX queue objects sufficient to handle all valid
14551  * hash_fields combinations (see enum ibv_rx_hash_fields).
14552  *
14553  * @param[in] dev
14554  *   Pointer to the Ethernet device structure.
14555  * @param[in] action_idx
14556  *   Shared RSS action ipool index.
14557  * @param[in, out] action
14558  *   Partially initialized shared RSS action.
14559  * @param[out] error
14560  *   Perform verbose error reporting if not NULL. Initialized in case of
14561  *   error only.
14562  *
14563  * @return
14564  *   0 on success, otherwise negative errno value.
14565  */
14566 static int
14567 __flow_dv_action_rss_setup(struct rte_eth_dev *dev,
14568 			   uint32_t action_idx,
14569 			   struct mlx5_shared_action_rss *shared_rss,
14570 			   struct rte_flow_error *error)
14571 {
14572 	struct mlx5_flow_rss_desc rss_desc = { 0 };
14573 	size_t i;
14574 	int err;
14575 
14576 	if (mlx5_ind_table_obj_setup(dev, shared_rss->ind_tbl)) {
14577 		return rte_flow_error_set(error, rte_errno,
14578 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14579 					  "cannot setup indirection table");
14580 	}
14581 	memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN);
14582 	rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN;
14583 	rss_desc.const_q = shared_rss->origin.queue;
14584 	rss_desc.queue_num = shared_rss->origin.queue_num;
14585 	/* Set non-zero value to indicate a shared RSS. */
14586 	rss_desc.shared_rss = action_idx;
14587 	rss_desc.ind_tbl = shared_rss->ind_tbl;
14588 	for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) {
14589 		uint32_t hrxq_idx;
14590 		uint64_t hash_fields = mlx5_rss_hash_fields[i];
14591 		int tunnel = 0;
14592 
14593 		__flow_dv_action_rss_l34_hash_adjust(shared_rss, &hash_fields);
14594 		if (shared_rss->origin.level > 1) {
14595 			hash_fields |= IBV_RX_HASH_INNER;
14596 			tunnel = 1;
14597 		}
14598 		rss_desc.tunnel = tunnel;
14599 		rss_desc.hash_fields = hash_fields;
14600 		hrxq_idx = mlx5_hrxq_get(dev, &rss_desc);
14601 		if (!hrxq_idx) {
14602 			rte_flow_error_set
14603 				(error, rte_errno,
14604 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14605 				 "cannot get hash queue");
14606 			goto error_hrxq_new;
14607 		}
14608 		err = __flow_dv_action_rss_hrxq_set
14609 			(shared_rss, hash_fields, hrxq_idx);
14610 		MLX5_ASSERT(!err);
14611 	}
14612 	return 0;
14613 error_hrxq_new:
14614 	err = rte_errno;
14615 	__flow_dv_action_rss_hrxqs_release(dev, shared_rss);
14616 	if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true))
14617 		shared_rss->ind_tbl = NULL;
14618 	rte_errno = err;
14619 	return -rte_errno;
14620 }
14621 
14622 /**
14623  * Create shared RSS action.
14624  *
14625  * @param[in] dev
14626  *   Pointer to the Ethernet device structure.
14627  * @param[in] conf
14628  *   Shared action configuration.
14629  * @param[in] rss
14630  *   RSS action specification used to create shared action.
14631  * @param[out] error
14632  *   Perform verbose error reporting if not NULL. Initialized in case of
14633  *   error only.
14634  *
14635  * @return
14636  *   A valid shared action ID in case of success, 0 otherwise and
14637  *   rte_errno is set.
14638  */
14639 static uint32_t
14640 __flow_dv_action_rss_create(struct rte_eth_dev *dev,
14641 			    const struct rte_flow_indir_action_conf *conf,
14642 			    const struct rte_flow_action_rss *rss,
14643 			    struct rte_flow_error *error)
14644 {
14645 	struct mlx5_priv *priv = dev->data->dev_private;
14646 	struct mlx5_shared_action_rss *shared_rss = NULL;
14647 	void *queue = NULL;
14648 	struct rte_flow_action_rss *origin;
14649 	const uint8_t *rss_key;
14650 	uint32_t queue_size = rss->queue_num * sizeof(uint16_t);
14651 	uint32_t idx;
14652 
14653 	RTE_SET_USED(conf);
14654 	queue = mlx5_malloc(0, RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
14655 			    0, SOCKET_ID_ANY);
14656 	shared_rss = mlx5_ipool_zmalloc
14657 			 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx);
14658 	if (!shared_rss || !queue) {
14659 		rte_flow_error_set(error, ENOMEM,
14660 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14661 				   "cannot allocate resource memory");
14662 		goto error_rss_init;
14663 	}
14664 	if (idx > (1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET)) {
14665 		rte_flow_error_set(error, E2BIG,
14666 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14667 				   "rss action number out of range");
14668 		goto error_rss_init;
14669 	}
14670 	shared_rss->ind_tbl = mlx5_malloc(MLX5_MEM_ZERO,
14671 					  sizeof(*shared_rss->ind_tbl),
14672 					  0, SOCKET_ID_ANY);
14673 	if (!shared_rss->ind_tbl) {
14674 		rte_flow_error_set(error, ENOMEM,
14675 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14676 				   "cannot allocate resource memory");
14677 		goto error_rss_init;
14678 	}
14679 	memcpy(queue, rss->queue, queue_size);
14680 	shared_rss->ind_tbl->queues = queue;
14681 	shared_rss->ind_tbl->queues_n = rss->queue_num;
14682 	origin = &shared_rss->origin;
14683 	origin->func = rss->func;
14684 	origin->level = rss->level;
14685 	/* RSS type 0 indicates default RSS type (ETH_RSS_IP). */
14686 	origin->types = !rss->types ? ETH_RSS_IP : rss->types;
14687 	/* NULL RSS key indicates default RSS key. */
14688 	rss_key = !rss->key ? rss_hash_default_key : rss->key;
14689 	memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
14690 	origin->key = &shared_rss->key[0];
14691 	origin->key_len = MLX5_RSS_HASH_KEY_LEN;
14692 	origin->queue = queue;
14693 	origin->queue_num = rss->queue_num;
14694 	if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error))
14695 		goto error_rss_init;
14696 	rte_spinlock_init(&shared_rss->action_rss_sl);
14697 	__atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
14698 	rte_spinlock_lock(&priv->shared_act_sl);
14699 	ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14700 		     &priv->rss_shared_actions, idx, shared_rss, next);
14701 	rte_spinlock_unlock(&priv->shared_act_sl);
14702 	return idx;
14703 error_rss_init:
14704 	if (shared_rss) {
14705 		if (shared_rss->ind_tbl)
14706 			mlx5_free(shared_rss->ind_tbl);
14707 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14708 				idx);
14709 	}
14710 	if (queue)
14711 		mlx5_free(queue);
14712 	return 0;
14713 }
14714 
14715 /**
14716  * Destroy the shared RSS action.
14717  * Release related hash RX queue objects.
14718  *
14719  * @param[in] dev
14720  *   Pointer to the Ethernet device structure.
14721  * @param[in] idx
14722  *   The shared RSS action object ID to be removed.
14723  * @param[out] error
14724  *   Perform verbose error reporting if not NULL. Initialized in case of
14725  *   error only.
14726  *
14727  * @return
14728  *   0 on success, otherwise negative errno value.
14729  */
14730 static int
14731 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx,
14732 			     struct rte_flow_error *error)
14733 {
14734 	struct mlx5_priv *priv = dev->data->dev_private;
14735 	struct mlx5_shared_action_rss *shared_rss =
14736 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
14737 	uint32_t old_refcnt = 1;
14738 	int remaining;
14739 	uint16_t *queue = NULL;
14740 
14741 	if (!shared_rss)
14742 		return rte_flow_error_set(error, EINVAL,
14743 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14744 					  "invalid shared action");
14745 	remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss);
14746 	if (remaining)
14747 		return rte_flow_error_set(error, EBUSY,
14748 					  RTE_FLOW_ERROR_TYPE_ACTION,
14749 					  NULL,
14750 					  "shared rss hrxq has references");
14751 	if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt,
14752 					 0, 0, __ATOMIC_ACQUIRE,
14753 					 __ATOMIC_RELAXED))
14754 		return rte_flow_error_set(error, EBUSY,
14755 					  RTE_FLOW_ERROR_TYPE_ACTION,
14756 					  NULL,
14757 					  "shared rss has references");
14758 	queue = shared_rss->ind_tbl->queues;
14759 	remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true);
14760 	if (remaining)
14761 		return rte_flow_error_set(error, EBUSY,
14762 					  RTE_FLOW_ERROR_TYPE_ACTION,
14763 					  NULL,
14764 					  "shared rss indirection table has"
14765 					  " references");
14766 	mlx5_free(queue);
14767 	rte_spinlock_lock(&priv->shared_act_sl);
14768 	ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14769 		     &priv->rss_shared_actions, idx, shared_rss, next);
14770 	rte_spinlock_unlock(&priv->shared_act_sl);
14771 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14772 			idx);
14773 	return 0;
14774 }
14775 
14776 /**
14777  * Create indirect action, lock free,
14778  * (mutex should be acquired by caller).
14779  * Dispatcher for action type specific call.
14780  *
14781  * @param[in] dev
14782  *   Pointer to the Ethernet device structure.
14783  * @param[in] conf
14784  *   Shared action configuration.
14785  * @param[in] action
14786  *   Action specification used to create indirect action.
14787  * @param[out] error
14788  *   Perform verbose error reporting if not NULL. Initialized in case of
14789  *   error only.
14790  *
14791  * @return
14792  *   A valid shared action handle in case of success, NULL otherwise and
14793  *   rte_errno is set.
14794  */
14795 static struct rte_flow_action_handle *
14796 flow_dv_action_create(struct rte_eth_dev *dev,
14797 		      const struct rte_flow_indir_action_conf *conf,
14798 		      const struct rte_flow_action *action,
14799 		      struct rte_flow_error *err)
14800 {
14801 	struct mlx5_priv *priv = dev->data->dev_private;
14802 	uint32_t age_idx = 0;
14803 	uint32_t idx = 0;
14804 	uint32_t ret = 0;
14805 
14806 	switch (action->type) {
14807 	case RTE_FLOW_ACTION_TYPE_RSS:
14808 		ret = __flow_dv_action_rss_create(dev, conf, action->conf, err);
14809 		idx = (MLX5_INDIRECT_ACTION_TYPE_RSS <<
14810 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
14811 		break;
14812 	case RTE_FLOW_ACTION_TYPE_AGE:
14813 		age_idx = flow_dv_aso_age_alloc(dev, err);
14814 		if (!age_idx) {
14815 			ret = -rte_errno;
14816 			break;
14817 		}
14818 		idx = (MLX5_INDIRECT_ACTION_TYPE_AGE <<
14819 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx;
14820 		flow_dv_aso_age_params_init(dev, age_idx,
14821 					((const struct rte_flow_action_age *)
14822 						action->conf)->context ?
14823 					((const struct rte_flow_action_age *)
14824 						action->conf)->context :
14825 					(void *)(uintptr_t)idx,
14826 					((const struct rte_flow_action_age *)
14827 						action->conf)->timeout);
14828 		ret = age_idx;
14829 		break;
14830 	case RTE_FLOW_ACTION_TYPE_COUNT:
14831 		ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL);
14832 		idx = (MLX5_INDIRECT_ACTION_TYPE_COUNT <<
14833 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
14834 		break;
14835 	case RTE_FLOW_ACTION_TYPE_CONNTRACK:
14836 		ret = flow_dv_translate_create_conntrack(dev, action->conf,
14837 							 err);
14838 		idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret);
14839 		break;
14840 	default:
14841 		rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
14842 				   NULL, "action type not supported");
14843 		break;
14844 	}
14845 	return ret ? (struct rte_flow_action_handle *)(uintptr_t)idx : NULL;
14846 }
14847 
14848 /**
14849  * Destroy the indirect action.
14850  * Release action related resources on the NIC and the memory.
14851  * Lock free, (mutex should be acquired by caller).
14852  * Dispatcher for action type specific call.
14853  *
14854  * @param[in] dev
14855  *   Pointer to the Ethernet device structure.
14856  * @param[in] handle
14857  *   The indirect action object handle to be removed.
14858  * @param[out] error
14859  *   Perform verbose error reporting if not NULL. Initialized in case of
14860  *   error only.
14861  *
14862  * @return
14863  *   0 on success, otherwise negative errno value.
14864  */
14865 static int
14866 flow_dv_action_destroy(struct rte_eth_dev *dev,
14867 		       struct rte_flow_action_handle *handle,
14868 		       struct rte_flow_error *error)
14869 {
14870 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
14871 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
14872 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
14873 	struct mlx5_flow_counter *cnt;
14874 	uint32_t no_flow_refcnt = 1;
14875 	int ret;
14876 
14877 	switch (type) {
14878 	case MLX5_INDIRECT_ACTION_TYPE_RSS:
14879 		return __flow_dv_action_rss_release(dev, idx, error);
14880 	case MLX5_INDIRECT_ACTION_TYPE_COUNT:
14881 		cnt = flow_dv_counter_get_by_idx(dev, idx, NULL);
14882 		if (!__atomic_compare_exchange_n(&cnt->shared_info.refcnt,
14883 						 &no_flow_refcnt, 1, false,
14884 						 __ATOMIC_ACQUIRE,
14885 						 __ATOMIC_RELAXED))
14886 			return rte_flow_error_set(error, EBUSY,
14887 						  RTE_FLOW_ERROR_TYPE_ACTION,
14888 						  NULL,
14889 						  "Indirect count action has references");
14890 		flow_dv_counter_free(dev, idx);
14891 		return 0;
14892 	case MLX5_INDIRECT_ACTION_TYPE_AGE:
14893 		ret = flow_dv_aso_age_release(dev, idx);
14894 		if (ret)
14895 			/*
14896 			 * In this case, the last flow has a reference will
14897 			 * actually release the age action.
14898 			 */
14899 			DRV_LOG(DEBUG, "Indirect age action %" PRIu32 " was"
14900 				" released with references %d.", idx, ret);
14901 		return 0;
14902 	case MLX5_INDIRECT_ACTION_TYPE_CT:
14903 		ret = flow_dv_aso_ct_release(dev, idx);
14904 		if (ret < 0)
14905 			return ret;
14906 		if (ret > 0)
14907 			DRV_LOG(DEBUG, "Connection tracking object %u still "
14908 				"has references %d.", idx, ret);
14909 		return 0;
14910 	default:
14911 		return rte_flow_error_set(error, ENOTSUP,
14912 					  RTE_FLOW_ERROR_TYPE_ACTION,
14913 					  NULL,
14914 					  "action type not supported");
14915 	}
14916 }
14917 
14918 /**
14919  * Updates in place shared RSS action configuration.
14920  *
14921  * @param[in] dev
14922  *   Pointer to the Ethernet device structure.
14923  * @param[in] idx
14924  *   The shared RSS action object ID to be updated.
14925  * @param[in] action_conf
14926  *   RSS action specification used to modify *shared_rss*.
14927  * @param[out] error
14928  *   Perform verbose error reporting if not NULL. Initialized in case of
14929  *   error only.
14930  *
14931  * @return
14932  *   0 on success, otherwise negative errno value.
14933  * @note: currently only support update of RSS queues.
14934  */
14935 static int
14936 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx,
14937 			    const struct rte_flow_action_rss *action_conf,
14938 			    struct rte_flow_error *error)
14939 {
14940 	struct mlx5_priv *priv = dev->data->dev_private;
14941 	struct mlx5_shared_action_rss *shared_rss =
14942 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
14943 	int ret = 0;
14944 	void *queue = NULL;
14945 	uint16_t *queue_old = NULL;
14946 	uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t);
14947 
14948 	if (!shared_rss)
14949 		return rte_flow_error_set(error, EINVAL,
14950 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14951 					  "invalid shared action to update");
14952 	if (priv->obj_ops.ind_table_modify == NULL)
14953 		return rte_flow_error_set(error, ENOTSUP,
14954 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14955 					  "cannot modify indirection table");
14956 	queue = mlx5_malloc(MLX5_MEM_ZERO,
14957 			    RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
14958 			    0, SOCKET_ID_ANY);
14959 	if (!queue)
14960 		return rte_flow_error_set(error, ENOMEM,
14961 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14962 					  NULL,
14963 					  "cannot allocate resource memory");
14964 	memcpy(queue, action_conf->queue, queue_size);
14965 	MLX5_ASSERT(shared_rss->ind_tbl);
14966 	rte_spinlock_lock(&shared_rss->action_rss_sl);
14967 	queue_old = shared_rss->ind_tbl->queues;
14968 	ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl,
14969 					queue, action_conf->queue_num, true);
14970 	if (ret) {
14971 		mlx5_free(queue);
14972 		ret = rte_flow_error_set(error, rte_errno,
14973 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14974 					  "cannot update indirection table");
14975 	} else {
14976 		mlx5_free(queue_old);
14977 		shared_rss->origin.queue = queue;
14978 		shared_rss->origin.queue_num = action_conf->queue_num;
14979 	}
14980 	rte_spinlock_unlock(&shared_rss->action_rss_sl);
14981 	return ret;
14982 }
14983 
14984 /*
14985  * Updates in place conntrack context or direction.
14986  * Context update should be synchronized.
14987  *
14988  * @param[in] dev
14989  *   Pointer to the Ethernet device structure.
14990  * @param[in] idx
14991  *   The conntrack object ID to be updated.
14992  * @param[in] update
14993  *   Pointer to the structure of information to update.
14994  * @param[out] error
14995  *   Perform verbose error reporting if not NULL. Initialized in case of
14996  *   error only.
14997  *
14998  * @return
14999  *   0 on success, otherwise negative errno value.
15000  */
15001 static int
15002 __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx,
15003 			   const struct rte_flow_modify_conntrack *update,
15004 			   struct rte_flow_error *error)
15005 {
15006 	struct mlx5_priv *priv = dev->data->dev_private;
15007 	struct mlx5_aso_ct_action *ct;
15008 	const struct rte_flow_action_conntrack *new_prf;
15009 	int ret = 0;
15010 	uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
15011 	uint32_t dev_idx;
15012 
15013 	if (PORT_ID(priv) != owner)
15014 		return rte_flow_error_set(error, EACCES,
15015 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15016 					  NULL,
15017 					  "CT object owned by another port");
15018 	dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
15019 	ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
15020 	if (!ct->refcnt)
15021 		return rte_flow_error_set(error, ENOMEM,
15022 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15023 					  NULL,
15024 					  "CT object is inactive");
15025 	new_prf = &update->new_ct;
15026 	if (update->direction)
15027 		ct->is_original = !!new_prf->is_original_dir;
15028 	if (update->state) {
15029 		/* Only validate the profile when it needs to be updated. */
15030 		ret = mlx5_validate_action_ct(dev, new_prf, error);
15031 		if (ret)
15032 			return ret;
15033 		ret = mlx5_aso_ct_update_by_wqe(priv->sh, ct, new_prf);
15034 		if (ret)
15035 			return rte_flow_error_set(error, EIO,
15036 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15037 					NULL,
15038 					"Failed to send CT context update WQE");
15039 		/* Block until ready or a failure. */
15040 		ret = mlx5_aso_ct_available(priv->sh, ct);
15041 		if (ret)
15042 			rte_flow_error_set(error, rte_errno,
15043 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15044 					   NULL,
15045 					   "Timeout to get the CT update");
15046 	}
15047 	return ret;
15048 }
15049 
15050 /**
15051  * Updates in place shared action configuration, lock free,
15052  * (mutex should be acquired by caller).
15053  *
15054  * @param[in] dev
15055  *   Pointer to the Ethernet device structure.
15056  * @param[in] handle
15057  *   The indirect action object handle to be updated.
15058  * @param[in] update
15059  *   Action specification used to modify the action pointed by *handle*.
15060  *   *update* could be of same type with the action pointed by the *handle*
15061  *   handle argument, or some other structures like a wrapper, depending on
15062  *   the indirect action type.
15063  * @param[out] error
15064  *   Perform verbose error reporting if not NULL. Initialized in case of
15065  *   error only.
15066  *
15067  * @return
15068  *   0 on success, otherwise negative errno value.
15069  */
15070 static int
15071 flow_dv_action_update(struct rte_eth_dev *dev,
15072 			struct rte_flow_action_handle *handle,
15073 			const void *update,
15074 			struct rte_flow_error *err)
15075 {
15076 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15077 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15078 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15079 	const void *action_conf;
15080 
15081 	switch (type) {
15082 	case MLX5_INDIRECT_ACTION_TYPE_RSS:
15083 		action_conf = ((const struct rte_flow_action *)update)->conf;
15084 		return __flow_dv_action_rss_update(dev, idx, action_conf, err);
15085 	case MLX5_INDIRECT_ACTION_TYPE_CT:
15086 		return __flow_dv_action_ct_update(dev, idx, update, err);
15087 	default:
15088 		return rte_flow_error_set(err, ENOTSUP,
15089 					  RTE_FLOW_ERROR_TYPE_ACTION,
15090 					  NULL,
15091 					  "action type update not supported");
15092 	}
15093 }
15094 
15095 /**
15096  * Destroy the meter sub policy table rules.
15097  * Lock free, (mutex should be acquired by caller).
15098  *
15099  * @param[in] dev
15100  *   Pointer to Ethernet device.
15101  * @param[in] sub_policy
15102  *   Pointer to meter sub policy table.
15103  */
15104 static void
15105 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
15106 			     struct mlx5_flow_meter_sub_policy *sub_policy)
15107 {
15108 	struct mlx5_priv *priv = dev->data->dev_private;
15109 	struct mlx5_flow_tbl_data_entry *tbl;
15110 	struct mlx5_flow_meter_policy *policy = sub_policy->main_policy;
15111 	struct mlx5_flow_meter_info *next_fm;
15112 	struct mlx5_sub_policy_color_rule *color_rule;
15113 	void *tmp;
15114 	uint32_t i;
15115 
15116 	for (i = 0; i < RTE_COLORS; i++) {
15117 		next_fm = NULL;
15118 		if (i == RTE_COLOR_GREEN && policy &&
15119 		    policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
15120 			next_fm = mlx5_flow_meter_find(priv,
15121 					policy->act_cnt[i].next_mtr_id, NULL);
15122 		TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i],
15123 				   next_port, tmp) {
15124 			claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule));
15125 			tbl = container_of(color_rule->matcher->tbl,
15126 					   typeof(*tbl), tbl);
15127 			mlx5_list_unregister(tbl->matchers,
15128 					     &color_rule->matcher->entry);
15129 			TAILQ_REMOVE(&sub_policy->color_rules[i],
15130 				     color_rule, next_port);
15131 			mlx5_free(color_rule);
15132 			if (next_fm)
15133 				mlx5_flow_meter_detach(priv, next_fm);
15134 		}
15135 	}
15136 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
15137 		if (sub_policy->rix_hrxq[i]) {
15138 			if (policy && !policy->is_hierarchy)
15139 				mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
15140 			sub_policy->rix_hrxq[i] = 0;
15141 		}
15142 		if (sub_policy->jump_tbl[i]) {
15143 			flow_dv_tbl_resource_release(MLX5_SH(dev),
15144 						     sub_policy->jump_tbl[i]);
15145 			sub_policy->jump_tbl[i] = NULL;
15146 		}
15147 	}
15148 	if (sub_policy->tbl_rsc) {
15149 		flow_dv_tbl_resource_release(MLX5_SH(dev),
15150 					     sub_policy->tbl_rsc);
15151 		sub_policy->tbl_rsc = NULL;
15152 	}
15153 }
15154 
15155 /**
15156  * Destroy policy rules, lock free,
15157  * (mutex should be acquired by caller).
15158  * Dispatcher for action type specific call.
15159  *
15160  * @param[in] dev
15161  *   Pointer to the Ethernet device structure.
15162  * @param[in] mtr_policy
15163  *   Meter policy struct.
15164  */
15165 static void
15166 flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
15167 			     struct mlx5_flow_meter_policy *mtr_policy)
15168 {
15169 	uint32_t i, j;
15170 	struct mlx5_flow_meter_sub_policy *sub_policy;
15171 	uint16_t sub_policy_num;
15172 
15173 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15174 		sub_policy_num = (mtr_policy->sub_policy_num >>
15175 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
15176 			MLX5_MTR_SUB_POLICY_NUM_MASK;
15177 		for (j = 0; j < sub_policy_num; j++) {
15178 			sub_policy = mtr_policy->sub_policys[i][j];
15179 			if (sub_policy)
15180 				__flow_dv_destroy_sub_policy_rules(dev,
15181 								   sub_policy);
15182 		}
15183 	}
15184 }
15185 
15186 /**
15187  * Destroy policy action, lock free,
15188  * (mutex should be acquired by caller).
15189  * Dispatcher for action type specific call.
15190  *
15191  * @param[in] dev
15192  *   Pointer to the Ethernet device structure.
15193  * @param[in] mtr_policy
15194  *   Meter policy struct.
15195  */
15196 static void
15197 flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
15198 		      struct mlx5_flow_meter_policy *mtr_policy)
15199 {
15200 	struct rte_flow_action *rss_action;
15201 	struct mlx5_flow_handle dev_handle;
15202 	uint32_t i, j;
15203 
15204 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
15205 		if (mtr_policy->act_cnt[i].rix_mark) {
15206 			flow_dv_tag_release(dev,
15207 				mtr_policy->act_cnt[i].rix_mark);
15208 			mtr_policy->act_cnt[i].rix_mark = 0;
15209 		}
15210 		if (mtr_policy->act_cnt[i].modify_hdr) {
15211 			dev_handle.dvh.modify_hdr =
15212 				mtr_policy->act_cnt[i].modify_hdr;
15213 			flow_dv_modify_hdr_resource_release(dev, &dev_handle);
15214 		}
15215 		switch (mtr_policy->act_cnt[i].fate_action) {
15216 		case MLX5_FLOW_FATE_SHARED_RSS:
15217 			rss_action = mtr_policy->act_cnt[i].rss;
15218 			mlx5_free(rss_action);
15219 			break;
15220 		case MLX5_FLOW_FATE_PORT_ID:
15221 			if (mtr_policy->act_cnt[i].rix_port_id_action) {
15222 				flow_dv_port_id_action_resource_release(dev,
15223 				mtr_policy->act_cnt[i].rix_port_id_action);
15224 				mtr_policy->act_cnt[i].rix_port_id_action = 0;
15225 			}
15226 			break;
15227 		case MLX5_FLOW_FATE_DROP:
15228 		case MLX5_FLOW_FATE_JUMP:
15229 			for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
15230 				mtr_policy->act_cnt[i].dr_jump_action[j] =
15231 						NULL;
15232 			break;
15233 		default:
15234 			/*Queue action do nothing*/
15235 			break;
15236 		}
15237 	}
15238 	for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
15239 		mtr_policy->dr_drop_action[j] = NULL;
15240 }
15241 
15242 /**
15243  * Create policy action per domain, lock free,
15244  * (mutex should be acquired by caller).
15245  * Dispatcher for action type specific call.
15246  *
15247  * @param[in] dev
15248  *   Pointer to the Ethernet device structure.
15249  * @param[in] mtr_policy
15250  *   Meter policy struct.
15251  * @param[in] action
15252  *   Action specification used to create meter actions.
15253  * @param[out] error
15254  *   Perform verbose error reporting if not NULL. Initialized in case of
15255  *   error only.
15256  *
15257  * @return
15258  *   0 on success, otherwise negative errno value.
15259  */
15260 static int
15261 __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
15262 			struct mlx5_flow_meter_policy *mtr_policy,
15263 			const struct rte_flow_action *actions[RTE_COLORS],
15264 			enum mlx5_meter_domain domain,
15265 			struct rte_mtr_error *error)
15266 {
15267 	struct mlx5_priv *priv = dev->data->dev_private;
15268 	struct rte_flow_error flow_err;
15269 	const struct rte_flow_action *act;
15270 	uint64_t action_flags;
15271 	struct mlx5_flow_handle dh;
15272 	struct mlx5_flow dev_flow;
15273 	struct mlx5_flow_dv_port_id_action_resource port_id_action;
15274 	int i, ret;
15275 	uint8_t egress, transfer;
15276 	struct mlx5_meter_policy_action_container *act_cnt = NULL;
15277 	union {
15278 		struct mlx5_flow_dv_modify_hdr_resource res;
15279 		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
15280 			    sizeof(struct mlx5_modification_cmd) *
15281 			    (MLX5_MAX_MODIFY_NUM + 1)];
15282 	} mhdr_dummy;
15283 	struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
15284 
15285 	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
15286 	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
15287 	memset(&dh, 0, sizeof(struct mlx5_flow_handle));
15288 	memset(&dev_flow, 0, sizeof(struct mlx5_flow));
15289 	memset(&port_id_action, 0,
15290 	       sizeof(struct mlx5_flow_dv_port_id_action_resource));
15291 	memset(mhdr_res, 0, sizeof(*mhdr_res));
15292 	mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
15293 				       (egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
15294 					MLX5DV_FLOW_TABLE_TYPE_NIC_RX);
15295 	dev_flow.handle = &dh;
15296 	dev_flow.dv.port_id_action = &port_id_action;
15297 	dev_flow.external = true;
15298 	for (i = 0; i < RTE_COLORS; i++) {
15299 		if (i < MLX5_MTR_RTE_COLORS)
15300 			act_cnt = &mtr_policy->act_cnt[i];
15301 		/* Skip the color policy actions creation. */
15302 		if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) ||
15303 		    (i == RTE_COLOR_GREEN && mtr_policy->skip_g))
15304 			continue;
15305 		action_flags = 0;
15306 		for (act = actions[i];
15307 		     act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
15308 			switch (act->type) {
15309 			case RTE_FLOW_ACTION_TYPE_MARK:
15310 			{
15311 				uint32_t tag_be = mlx5_flow_mark_set
15312 					(((const struct rte_flow_action_mark *)
15313 					(act->conf))->id);
15314 
15315 				if (i >= MLX5_MTR_RTE_COLORS)
15316 					return -rte_mtr_error_set(error,
15317 					  ENOTSUP,
15318 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15319 					  NULL,
15320 					  "cannot create policy "
15321 					  "mark action for this color");
15322 				dev_flow.handle->mark = 1;
15323 				if (flow_dv_tag_resource_register(dev, tag_be,
15324 						  &dev_flow, &flow_err))
15325 					return -rte_mtr_error_set(error,
15326 					ENOTSUP,
15327 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15328 					NULL,
15329 					"cannot setup policy mark action");
15330 				MLX5_ASSERT(dev_flow.dv.tag_resource);
15331 				act_cnt->rix_mark =
15332 					dev_flow.handle->dvh.rix_tag;
15333 				action_flags |= MLX5_FLOW_ACTION_MARK;
15334 				break;
15335 			}
15336 			case RTE_FLOW_ACTION_TYPE_SET_TAG:
15337 				if (i >= MLX5_MTR_RTE_COLORS)
15338 					return -rte_mtr_error_set(error,
15339 					  ENOTSUP,
15340 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15341 					  NULL,
15342 					  "cannot create policy "
15343 					  "set tag action for this color");
15344 				if (flow_dv_convert_action_set_tag
15345 				(dev, mhdr_res,
15346 				(const struct rte_flow_action_set_tag *)
15347 				act->conf,  &flow_err))
15348 					return -rte_mtr_error_set(error,
15349 					ENOTSUP,
15350 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15351 					NULL, "cannot convert policy "
15352 					"set tag action");
15353 				if (!mhdr_res->actions_num)
15354 					return -rte_mtr_error_set(error,
15355 					ENOTSUP,
15356 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15357 					NULL, "cannot find policy "
15358 					"set tag action");
15359 				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
15360 				break;
15361 			case RTE_FLOW_ACTION_TYPE_DROP:
15362 			{
15363 				struct mlx5_flow_mtr_mng *mtrmng =
15364 						priv->sh->mtrmng;
15365 				struct mlx5_flow_tbl_data_entry *tbl_data;
15366 
15367 				/*
15368 				 * Create the drop table with
15369 				 * METER DROP level.
15370 				 */
15371 				if (!mtrmng->drop_tbl[domain]) {
15372 					mtrmng->drop_tbl[domain] =
15373 					flow_dv_tbl_resource_get(dev,
15374 					MLX5_FLOW_TABLE_LEVEL_METER,
15375 					egress, transfer, false, NULL, 0,
15376 					0, MLX5_MTR_TABLE_ID_DROP, &flow_err);
15377 					if (!mtrmng->drop_tbl[domain])
15378 						return -rte_mtr_error_set
15379 					(error, ENOTSUP,
15380 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15381 					NULL,
15382 					"Failed to create meter drop table");
15383 				}
15384 				tbl_data = container_of
15385 				(mtrmng->drop_tbl[domain],
15386 				struct mlx5_flow_tbl_data_entry, tbl);
15387 				if (i < MLX5_MTR_RTE_COLORS) {
15388 					act_cnt->dr_jump_action[domain] =
15389 						tbl_data->jump.action;
15390 					act_cnt->fate_action =
15391 						MLX5_FLOW_FATE_DROP;
15392 				}
15393 				if (i == RTE_COLOR_RED)
15394 					mtr_policy->dr_drop_action[domain] =
15395 						tbl_data->jump.action;
15396 				action_flags |= MLX5_FLOW_ACTION_DROP;
15397 				break;
15398 			}
15399 			case RTE_FLOW_ACTION_TYPE_QUEUE:
15400 			{
15401 				if (i >= MLX5_MTR_RTE_COLORS)
15402 					return -rte_mtr_error_set(error,
15403 					ENOTSUP,
15404 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15405 					NULL, "cannot create policy "
15406 					"fate queue for this color");
15407 				act_cnt->queue =
15408 				((const struct rte_flow_action_queue *)
15409 					(act->conf))->index;
15410 				act_cnt->fate_action =
15411 					MLX5_FLOW_FATE_QUEUE;
15412 				dev_flow.handle->fate_action =
15413 					MLX5_FLOW_FATE_QUEUE;
15414 				mtr_policy->is_queue = 1;
15415 				action_flags |= MLX5_FLOW_ACTION_QUEUE;
15416 				break;
15417 			}
15418 			case RTE_FLOW_ACTION_TYPE_RSS:
15419 			{
15420 				int rss_size;
15421 
15422 				if (i >= MLX5_MTR_RTE_COLORS)
15423 					return -rte_mtr_error_set(error,
15424 					  ENOTSUP,
15425 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15426 					  NULL,
15427 					  "cannot create policy "
15428 					  "rss action for this color");
15429 				/*
15430 				 * Save RSS conf into policy struct
15431 				 * for translate stage.
15432 				 */
15433 				rss_size = (int)rte_flow_conv
15434 					(RTE_FLOW_CONV_OP_ACTION,
15435 					NULL, 0, act, &flow_err);
15436 				if (rss_size <= 0)
15437 					return -rte_mtr_error_set(error,
15438 					  ENOTSUP,
15439 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15440 					  NULL, "Get the wrong "
15441 					  "rss action struct size");
15442 				act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
15443 						rss_size, 0, SOCKET_ID_ANY);
15444 				if (!act_cnt->rss)
15445 					return -rte_mtr_error_set(error,
15446 					  ENOTSUP,
15447 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15448 					  NULL,
15449 					  "Fail to malloc rss action memory");
15450 				ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
15451 					act_cnt->rss, rss_size,
15452 					act, &flow_err);
15453 				if (ret < 0)
15454 					return -rte_mtr_error_set(error,
15455 					  ENOTSUP,
15456 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15457 					  NULL, "Fail to save "
15458 					  "rss action into policy struct");
15459 				act_cnt->fate_action =
15460 					MLX5_FLOW_FATE_SHARED_RSS;
15461 				action_flags |= MLX5_FLOW_ACTION_RSS;
15462 				break;
15463 			}
15464 			case RTE_FLOW_ACTION_TYPE_PORT_ID:
15465 			{
15466 				struct mlx5_flow_dv_port_id_action_resource
15467 					port_id_resource;
15468 				uint32_t port_id = 0;
15469 
15470 				if (i >= MLX5_MTR_RTE_COLORS)
15471 					return -rte_mtr_error_set(error,
15472 					ENOTSUP,
15473 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15474 					NULL, "cannot create policy "
15475 					"port action for this color");
15476 				memset(&port_id_resource, 0,
15477 					sizeof(port_id_resource));
15478 				if (flow_dv_translate_action_port_id(dev, act,
15479 						&port_id, &flow_err))
15480 					return -rte_mtr_error_set(error,
15481 					ENOTSUP,
15482 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15483 					NULL, "cannot translate "
15484 					"policy port action");
15485 				port_id_resource.port_id = port_id;
15486 				if (flow_dv_port_id_action_resource_register
15487 					(dev, &port_id_resource,
15488 					&dev_flow, &flow_err))
15489 					return -rte_mtr_error_set(error,
15490 					ENOTSUP,
15491 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15492 					NULL, "cannot setup "
15493 					"policy port action");
15494 				act_cnt->rix_port_id_action =
15495 					dev_flow.handle->rix_port_id_action;
15496 				act_cnt->fate_action =
15497 					MLX5_FLOW_FATE_PORT_ID;
15498 				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
15499 				break;
15500 			}
15501 			case RTE_FLOW_ACTION_TYPE_JUMP:
15502 			{
15503 				uint32_t jump_group = 0;
15504 				uint32_t table = 0;
15505 				struct mlx5_flow_tbl_data_entry *tbl_data;
15506 				struct flow_grp_info grp_info = {
15507 					.external = !!dev_flow.external,
15508 					.transfer = !!transfer,
15509 					.fdb_def_rule = !!priv->fdb_def_rule,
15510 					.std_tbl_fix = 0,
15511 					.skip_scale = dev_flow.skip_scale &
15512 					(1 << MLX5_SCALE_FLOW_GROUP_BIT),
15513 				};
15514 				struct mlx5_flow_meter_sub_policy *sub_policy =
15515 					mtr_policy->sub_policys[domain][0];
15516 
15517 				if (i >= MLX5_MTR_RTE_COLORS)
15518 					return -rte_mtr_error_set(error,
15519 					  ENOTSUP,
15520 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15521 					  NULL,
15522 					  "cannot create policy "
15523 					  "jump action for this color");
15524 				jump_group =
15525 				((const struct rte_flow_action_jump *)
15526 							act->conf)->group;
15527 				if (mlx5_flow_group_to_table(dev, NULL,
15528 						       jump_group,
15529 						       &table,
15530 						       &grp_info, &flow_err))
15531 					return -rte_mtr_error_set(error,
15532 					ENOTSUP,
15533 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15534 					NULL, "cannot setup "
15535 					"policy jump action");
15536 				sub_policy->jump_tbl[i] =
15537 				flow_dv_tbl_resource_get(dev,
15538 					table, egress,
15539 					transfer,
15540 					!!dev_flow.external,
15541 					NULL, jump_group, 0,
15542 					0, &flow_err);
15543 				if
15544 				(!sub_policy->jump_tbl[i])
15545 					return  -rte_mtr_error_set(error,
15546 					ENOTSUP,
15547 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15548 					NULL, "cannot create jump action.");
15549 				tbl_data = container_of
15550 				(sub_policy->jump_tbl[i],
15551 				struct mlx5_flow_tbl_data_entry, tbl);
15552 				act_cnt->dr_jump_action[domain] =
15553 					tbl_data->jump.action;
15554 				act_cnt->fate_action =
15555 					MLX5_FLOW_FATE_JUMP;
15556 				action_flags |= MLX5_FLOW_ACTION_JUMP;
15557 				break;
15558 			}
15559 			/*
15560 			 * No need to check meter hierarchy for Y or R colors
15561 			 * here since it is done in the validation stage.
15562 			 */
15563 			case RTE_FLOW_ACTION_TYPE_METER:
15564 			{
15565 				const struct rte_flow_action_meter *mtr;
15566 				struct mlx5_flow_meter_info *next_fm;
15567 				struct mlx5_flow_meter_policy *next_policy;
15568 				struct rte_flow_action tag_action;
15569 				struct mlx5_rte_flow_action_set_tag set_tag;
15570 				uint32_t next_mtr_idx = 0;
15571 
15572 				mtr = act->conf;
15573 				next_fm = mlx5_flow_meter_find(priv,
15574 							mtr->mtr_id,
15575 							&next_mtr_idx);
15576 				if (!next_fm)
15577 					return -rte_mtr_error_set(error, EINVAL,
15578 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
15579 						"Fail to find next meter.");
15580 				if (next_fm->def_policy)
15581 					return -rte_mtr_error_set(error, EINVAL,
15582 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
15583 				"Hierarchy only supports termination meter.");
15584 				next_policy = mlx5_flow_meter_policy_find(dev,
15585 						next_fm->policy_id, NULL);
15586 				MLX5_ASSERT(next_policy);
15587 				if (next_fm->drop_cnt) {
15588 					set_tag.id =
15589 						(enum modify_reg)
15590 						mlx5_flow_get_reg_id(dev,
15591 						MLX5_MTR_ID,
15592 						0,
15593 						(struct rte_flow_error *)error);
15594 					set_tag.offset = (priv->mtr_reg_share ?
15595 						MLX5_MTR_COLOR_BITS : 0);
15596 					set_tag.length = (priv->mtr_reg_share ?
15597 					       MLX5_MTR_IDLE_BITS_IN_COLOR_REG :
15598 					       MLX5_REG_BITS);
15599 					set_tag.data = next_mtr_idx;
15600 					tag_action.type =
15601 						(enum rte_flow_action_type)
15602 						MLX5_RTE_FLOW_ACTION_TYPE_TAG;
15603 					tag_action.conf = &set_tag;
15604 					if (flow_dv_convert_action_set_reg
15605 						(mhdr_res, &tag_action,
15606 						(struct rte_flow_error *)error))
15607 						return -rte_errno;
15608 					action_flags |=
15609 						MLX5_FLOW_ACTION_SET_TAG;
15610 				}
15611 				act_cnt->fate_action = MLX5_FLOW_FATE_MTR;
15612 				act_cnt->next_mtr_id = next_fm->meter_id;
15613 				act_cnt->next_sub_policy = NULL;
15614 				mtr_policy->is_hierarchy = 1;
15615 				mtr_policy->dev = next_policy->dev;
15616 				action_flags |=
15617 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
15618 				break;
15619 			}
15620 			default:
15621 				return -rte_mtr_error_set(error, ENOTSUP,
15622 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15623 					  NULL, "action type not supported");
15624 			}
15625 			if (action_flags & MLX5_FLOW_ACTION_SET_TAG) {
15626 				/* create modify action if needed. */
15627 				dev_flow.dv.group = 1;
15628 				if (flow_dv_modify_hdr_resource_register
15629 					(dev, mhdr_res, &dev_flow, &flow_err))
15630 					return -rte_mtr_error_set(error,
15631 						ENOTSUP,
15632 						RTE_MTR_ERROR_TYPE_METER_POLICY,
15633 						NULL, "cannot register policy "
15634 						"set tag action");
15635 				act_cnt->modify_hdr =
15636 					dev_flow.handle->dvh.modify_hdr;
15637 			}
15638 		}
15639 	}
15640 	return 0;
15641 }
15642 
15643 /**
15644  * Create policy action per domain, lock free,
15645  * (mutex should be acquired by caller).
15646  * Dispatcher for action type specific call.
15647  *
15648  * @param[in] dev
15649  *   Pointer to the Ethernet device structure.
15650  * @param[in] mtr_policy
15651  *   Meter policy struct.
15652  * @param[in] action
15653  *   Action specification used to create meter actions.
15654  * @param[out] error
15655  *   Perform verbose error reporting if not NULL. Initialized in case of
15656  *   error only.
15657  *
15658  * @return
15659  *   0 on success, otherwise negative errno value.
15660  */
15661 static int
15662 flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
15663 		      struct mlx5_flow_meter_policy *mtr_policy,
15664 		      const struct rte_flow_action *actions[RTE_COLORS],
15665 		      struct rte_mtr_error *error)
15666 {
15667 	int ret, i;
15668 	uint16_t sub_policy_num;
15669 
15670 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15671 		sub_policy_num = (mtr_policy->sub_policy_num >>
15672 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
15673 			MLX5_MTR_SUB_POLICY_NUM_MASK;
15674 		if (sub_policy_num) {
15675 			ret = __flow_dv_create_domain_policy_acts(dev,
15676 				mtr_policy, actions,
15677 				(enum mlx5_meter_domain)i, error);
15678 			/* Cleaning resource is done in the caller level. */
15679 			if (ret)
15680 				return ret;
15681 		}
15682 	}
15683 	return 0;
15684 }
15685 
15686 /**
15687  * Query a DV flow rule for its statistics via DevX.
15688  *
15689  * @param[in] dev
15690  *   Pointer to Ethernet device.
15691  * @param[in] cnt_idx
15692  *   Index to the flow counter.
15693  * @param[out] data
15694  *   Data retrieved by the query.
15695  * @param[out] error
15696  *   Perform verbose error reporting if not NULL.
15697  *
15698  * @return
15699  *   0 on success, a negative errno value otherwise and rte_errno is set.
15700  */
15701 static int
15702 flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data,
15703 		    struct rte_flow_error *error)
15704 {
15705 	struct mlx5_priv *priv = dev->data->dev_private;
15706 	struct rte_flow_query_count *qc = data;
15707 
15708 	if (!priv->config.devx)
15709 		return rte_flow_error_set(error, ENOTSUP,
15710 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15711 					  NULL,
15712 					  "counters are not supported");
15713 	if (cnt_idx) {
15714 		uint64_t pkts, bytes;
15715 		struct mlx5_flow_counter *cnt;
15716 		int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes);
15717 
15718 		if (err)
15719 			return rte_flow_error_set(error, -err,
15720 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15721 					NULL, "cannot read counters");
15722 		cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL);
15723 		qc->hits_set = 1;
15724 		qc->bytes_set = 1;
15725 		qc->hits = pkts - cnt->hits;
15726 		qc->bytes = bytes - cnt->bytes;
15727 		if (qc->reset) {
15728 			cnt->hits = pkts;
15729 			cnt->bytes = bytes;
15730 		}
15731 		return 0;
15732 	}
15733 	return rte_flow_error_set(error, EINVAL,
15734 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15735 				  NULL,
15736 				  "counters are not available");
15737 }
15738 
15739 static int
15740 flow_dv_action_query(struct rte_eth_dev *dev,
15741 		     const struct rte_flow_action_handle *handle, void *data,
15742 		     struct rte_flow_error *error)
15743 {
15744 	struct mlx5_age_param *age_param;
15745 	struct rte_flow_query_age *resp;
15746 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15747 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15748 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15749 	struct mlx5_priv *priv = dev->data->dev_private;
15750 	struct mlx5_aso_ct_action *ct;
15751 	uint16_t owner;
15752 	uint32_t dev_idx;
15753 
15754 	switch (type) {
15755 	case MLX5_INDIRECT_ACTION_TYPE_AGE:
15756 		age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params;
15757 		resp = data;
15758 		resp->aged = __atomic_load_n(&age_param->state,
15759 					      __ATOMIC_RELAXED) == AGE_TMOUT ?
15760 									  1 : 0;
15761 		resp->sec_since_last_hit_valid = !resp->aged;
15762 		if (resp->sec_since_last_hit_valid)
15763 			resp->sec_since_last_hit = __atomic_load_n
15764 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
15765 		return 0;
15766 	case MLX5_INDIRECT_ACTION_TYPE_COUNT:
15767 		return flow_dv_query_count(dev, idx, data, error);
15768 	case MLX5_INDIRECT_ACTION_TYPE_CT:
15769 		owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
15770 		if (owner != PORT_ID(priv))
15771 			return rte_flow_error_set(error, EACCES,
15772 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15773 					NULL,
15774 					"CT object owned by another port");
15775 		dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
15776 		ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
15777 		MLX5_ASSERT(ct);
15778 		if (!ct->refcnt)
15779 			return rte_flow_error_set(error, EFAULT,
15780 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15781 					NULL,
15782 					"CT object is inactive");
15783 		((struct rte_flow_action_conntrack *)data)->peer_port =
15784 							ct->peer;
15785 		((struct rte_flow_action_conntrack *)data)->is_original_dir =
15786 							ct->is_original;
15787 		if (mlx5_aso_ct_query_by_wqe(priv->sh, ct, data))
15788 			return rte_flow_error_set(error, EIO,
15789 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15790 					NULL,
15791 					"Failed to query CT context");
15792 		return 0;
15793 	default:
15794 		return rte_flow_error_set(error, ENOTSUP,
15795 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15796 					  "action type query not supported");
15797 	}
15798 }
15799 
15800 /**
15801  * Query a flow rule AGE action for aging information.
15802  *
15803  * @param[in] dev
15804  *   Pointer to Ethernet device.
15805  * @param[in] flow
15806  *   Pointer to the sub flow.
15807  * @param[out] data
15808  *   data retrieved by the query.
15809  * @param[out] error
15810  *   Perform verbose error reporting if not NULL.
15811  *
15812  * @return
15813  *   0 on success, a negative errno value otherwise and rte_errno is set.
15814  */
15815 static int
15816 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow,
15817 		  void *data, struct rte_flow_error *error)
15818 {
15819 	struct rte_flow_query_age *resp = data;
15820 	struct mlx5_age_param *age_param;
15821 
15822 	if (flow->age) {
15823 		struct mlx5_aso_age_action *act =
15824 				     flow_aso_age_get_by_idx(dev, flow->age);
15825 
15826 		age_param = &act->age_params;
15827 	} else if (flow->counter) {
15828 		age_param = flow_dv_counter_idx_get_age(dev, flow->counter);
15829 
15830 		if (!age_param || !age_param->timeout)
15831 			return rte_flow_error_set
15832 					(error, EINVAL,
15833 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15834 					 NULL, "cannot read age data");
15835 	} else {
15836 		return rte_flow_error_set(error, EINVAL,
15837 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15838 					  NULL, "age data not available");
15839 	}
15840 	resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) ==
15841 				     AGE_TMOUT ? 1 : 0;
15842 	resp->sec_since_last_hit_valid = !resp->aged;
15843 	if (resp->sec_since_last_hit_valid)
15844 		resp->sec_since_last_hit = __atomic_load_n
15845 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
15846 	return 0;
15847 }
15848 
15849 /**
15850  * Query a flow.
15851  *
15852  * @see rte_flow_query()
15853  * @see rte_flow_ops
15854  */
15855 static int
15856 flow_dv_query(struct rte_eth_dev *dev,
15857 	      struct rte_flow *flow __rte_unused,
15858 	      const struct rte_flow_action *actions __rte_unused,
15859 	      void *data __rte_unused,
15860 	      struct rte_flow_error *error __rte_unused)
15861 {
15862 	int ret = -EINVAL;
15863 
15864 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
15865 		switch (actions->type) {
15866 		case RTE_FLOW_ACTION_TYPE_VOID:
15867 			break;
15868 		case RTE_FLOW_ACTION_TYPE_COUNT:
15869 			ret = flow_dv_query_count(dev, flow->counter, data,
15870 						  error);
15871 			break;
15872 		case RTE_FLOW_ACTION_TYPE_AGE:
15873 			ret = flow_dv_query_age(dev, flow, data, error);
15874 			break;
15875 		default:
15876 			return rte_flow_error_set(error, ENOTSUP,
15877 						  RTE_FLOW_ERROR_TYPE_ACTION,
15878 						  actions,
15879 						  "action not supported");
15880 		}
15881 	}
15882 	return ret;
15883 }
15884 
15885 /**
15886  * Destroy the meter table set.
15887  * Lock free, (mutex should be acquired by caller).
15888  *
15889  * @param[in] dev
15890  *   Pointer to Ethernet device.
15891  * @param[in] fm
15892  *   Meter information table.
15893  */
15894 static void
15895 flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
15896 			struct mlx5_flow_meter_info *fm)
15897 {
15898 	struct mlx5_priv *priv = dev->data->dev_private;
15899 	int i;
15900 
15901 	if (!fm || !priv->config.dv_flow_en)
15902 		return;
15903 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15904 		if (fm->drop_rule[i]) {
15905 			claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
15906 			fm->drop_rule[i] = NULL;
15907 		}
15908 	}
15909 }
15910 
15911 static void
15912 flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
15913 {
15914 	struct mlx5_priv *priv = dev->data->dev_private;
15915 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
15916 	struct mlx5_flow_tbl_data_entry *tbl;
15917 	int i, j;
15918 
15919 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15920 		if (mtrmng->def_rule[i]) {
15921 			claim_zero(mlx5_flow_os_destroy_flow
15922 					(mtrmng->def_rule[i]));
15923 			mtrmng->def_rule[i] = NULL;
15924 		}
15925 		if (mtrmng->def_matcher[i]) {
15926 			tbl = container_of(mtrmng->def_matcher[i]->tbl,
15927 				struct mlx5_flow_tbl_data_entry, tbl);
15928 			mlx5_list_unregister(tbl->matchers,
15929 					     &mtrmng->def_matcher[i]->entry);
15930 			mtrmng->def_matcher[i] = NULL;
15931 		}
15932 		for (j = 0; j < MLX5_REG_BITS; j++) {
15933 			if (mtrmng->drop_matcher[i][j]) {
15934 				tbl =
15935 				container_of(mtrmng->drop_matcher[i][j]->tbl,
15936 					     struct mlx5_flow_tbl_data_entry,
15937 					     tbl);
15938 				mlx5_list_unregister(tbl->matchers,
15939 					    &mtrmng->drop_matcher[i][j]->entry);
15940 				mtrmng->drop_matcher[i][j] = NULL;
15941 			}
15942 		}
15943 		if (mtrmng->drop_tbl[i]) {
15944 			flow_dv_tbl_resource_release(MLX5_SH(dev),
15945 				mtrmng->drop_tbl[i]);
15946 			mtrmng->drop_tbl[i] = NULL;
15947 		}
15948 	}
15949 }
15950 
15951 /* Number of meter flow actions, count and jump or count and drop. */
15952 #define METER_ACTIONS 2
15953 
15954 static void
15955 __flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
15956 				    enum mlx5_meter_domain domain)
15957 {
15958 	struct mlx5_priv *priv = dev->data->dev_private;
15959 	struct mlx5_flow_meter_def_policy *def_policy =
15960 			priv->sh->mtrmng->def_policy[domain];
15961 
15962 	__flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
15963 	mlx5_free(def_policy);
15964 	priv->sh->mtrmng->def_policy[domain] = NULL;
15965 }
15966 
15967 /**
15968  * Destroy the default policy table set.
15969  *
15970  * @param[in] dev
15971  *   Pointer to Ethernet device.
15972  */
15973 static void
15974 flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
15975 {
15976 	struct mlx5_priv *priv = dev->data->dev_private;
15977 	int i;
15978 
15979 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
15980 		if (priv->sh->mtrmng->def_policy[i])
15981 			__flow_dv_destroy_domain_def_policy(dev,
15982 					(enum mlx5_meter_domain)i);
15983 	priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
15984 }
15985 
15986 static int
15987 __flow_dv_create_policy_flow(struct rte_eth_dev *dev,
15988 			uint32_t color_reg_c_idx,
15989 			enum rte_color color, void *matcher_object,
15990 			int actions_n, void *actions,
15991 			bool match_src_port, const struct rte_flow_item *item,
15992 			void **rule, const struct rte_flow_attr *attr)
15993 {
15994 	int ret;
15995 	struct mlx5_flow_dv_match_params value = {
15996 		.size = sizeof(value.buf),
15997 	};
15998 	struct mlx5_flow_dv_match_params matcher = {
15999 		.size = sizeof(matcher.buf),
16000 	};
16001 	struct mlx5_priv *priv = dev->data->dev_private;
16002 	uint8_t misc_mask;
16003 
16004 	if (match_src_port && (priv->representor || priv->master)) {
16005 		if (flow_dv_translate_item_port_id(dev, matcher.buf,
16006 						   value.buf, item, attr)) {
16007 			DRV_LOG(ERR, "Failed to create meter policy%d flow's"
16008 				" value with port.", color);
16009 			return -1;
16010 		}
16011 	}
16012 	flow_dv_match_meta_reg(matcher.buf, value.buf,
16013 			       (enum modify_reg)color_reg_c_idx,
16014 			       rte_col_2_mlx5_col(color), UINT32_MAX);
16015 	misc_mask = flow_dv_matcher_enable(value.buf);
16016 	__flow_dv_adjust_buf_size(&value.size, misc_mask);
16017 	ret = mlx5_flow_os_create_flow(matcher_object, (void *)&value,
16018 				       actions_n, actions, rule);
16019 	if (ret) {
16020 		DRV_LOG(ERR, "Failed to create meter policy%d flow.", color);
16021 		return -1;
16022 	}
16023 	return 0;
16024 }
16025 
16026 static int
16027 __flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
16028 			uint32_t color_reg_c_idx,
16029 			uint16_t priority,
16030 			struct mlx5_flow_meter_sub_policy *sub_policy,
16031 			const struct rte_flow_attr *attr,
16032 			bool match_src_port,
16033 			const struct rte_flow_item *item,
16034 			struct mlx5_flow_dv_matcher **policy_matcher,
16035 			struct rte_flow_error *error)
16036 {
16037 	struct mlx5_list_entry *entry;
16038 	struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
16039 	struct mlx5_flow_dv_matcher matcher = {
16040 		.mask = {
16041 			.size = sizeof(matcher.mask.buf),
16042 		},
16043 		.tbl = tbl_rsc,
16044 	};
16045 	struct mlx5_flow_dv_match_params value = {
16046 		.size = sizeof(value.buf),
16047 	};
16048 	struct mlx5_flow_cb_ctx ctx = {
16049 		.error = error,
16050 		.data = &matcher,
16051 	};
16052 	struct mlx5_flow_tbl_data_entry *tbl_data;
16053 	struct mlx5_priv *priv = dev->data->dev_private;
16054 	const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
16055 
16056 	if (match_src_port && (priv->representor || priv->master)) {
16057 		if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
16058 						   value.buf, item, attr)) {
16059 			DRV_LOG(ERR, "Failed to register meter policy%d matcher"
16060 				" with port.", priority);
16061 			return -1;
16062 		}
16063 	}
16064 	tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
16065 	if (priority < RTE_COLOR_RED)
16066 		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16067 			(enum modify_reg)color_reg_c_idx, 0, color_mask);
16068 	matcher.priority = priority;
16069 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
16070 				    matcher.mask.size);
16071 	entry = mlx5_list_register(tbl_data->matchers, &ctx);
16072 	if (!entry) {
16073 		DRV_LOG(ERR, "Failed to register meter drop matcher.");
16074 		return -1;
16075 	}
16076 	*policy_matcher =
16077 		container_of(entry, struct mlx5_flow_dv_matcher, entry);
16078 	return 0;
16079 }
16080 
16081 /**
16082  * Create the policy rules per domain.
16083  *
16084  * @param[in] dev
16085  *   Pointer to Ethernet device.
16086  * @param[in] sub_policy
16087  *    Pointer to sub policy table..
16088  * @param[in] egress
16089  *   Direction of the table.
16090  * @param[in] transfer
16091  *   E-Switch or NIC flow.
16092  * @param[in] acts
16093  *   Pointer to policy action list per color.
16094  *
16095  * @return
16096  *   0 on success, -1 otherwise.
16097  */
16098 static int
16099 __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
16100 		struct mlx5_flow_meter_sub_policy *sub_policy,
16101 		uint8_t egress, uint8_t transfer, bool match_src_port,
16102 		struct mlx5_meter_policy_acts acts[RTE_COLORS])
16103 {
16104 	struct mlx5_priv *priv = dev->data->dev_private;
16105 	struct rte_flow_error flow_err;
16106 	uint32_t color_reg_c_idx;
16107 	struct rte_flow_attr attr = {
16108 		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
16109 		.priority = 0,
16110 		.ingress = 0,
16111 		.egress = !!egress,
16112 		.transfer = !!transfer,
16113 		.reserved = 0,
16114 	};
16115 	int i;
16116 	int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
16117 	struct mlx5_sub_policy_color_rule *color_rule;
16118 	bool svport_match;
16119 	struct mlx5_sub_policy_color_rule *tmp_rules[RTE_COLORS] = {NULL};
16120 
16121 	if (ret < 0)
16122 		return -1;
16123 	/* Create policy table with POLICY level. */
16124 	if (!sub_policy->tbl_rsc)
16125 		sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
16126 				MLX5_FLOW_TABLE_LEVEL_POLICY,
16127 				egress, transfer, false, NULL, 0, 0,
16128 				sub_policy->idx, &flow_err);
16129 	if (!sub_policy->tbl_rsc) {
16130 		DRV_LOG(ERR,
16131 			"Failed to create meter sub policy table.");
16132 		return -1;
16133 	}
16134 	/* Prepare matchers. */
16135 	color_reg_c_idx = ret;
16136 	for (i = 0; i < RTE_COLORS; i++) {
16137 		TAILQ_INIT(&sub_policy->color_rules[i]);
16138 		if (!acts[i].actions_n)
16139 			continue;
16140 		color_rule = mlx5_malloc(MLX5_MEM_ZERO,
16141 				sizeof(struct mlx5_sub_policy_color_rule),
16142 				0, SOCKET_ID_ANY);
16143 		if (!color_rule) {
16144 			DRV_LOG(ERR, "No memory to create color rule.");
16145 			goto err_exit;
16146 		}
16147 		tmp_rules[i] = color_rule;
16148 		TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
16149 				  color_rule, next_port);
16150 		color_rule->src_port = priv->representor_id;
16151 		/* No use. */
16152 		attr.priority = i;
16153 		/* Create matchers for colors. */
16154 		svport_match = (i != RTE_COLOR_RED) ? match_src_port : false;
16155 		if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
16156 				MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
16157 				&attr, svport_match, NULL,
16158 				&color_rule->matcher, &flow_err)) {
16159 			DRV_LOG(ERR, "Failed to create color%u matcher.", i);
16160 			goto err_exit;
16161 		}
16162 		/* Create flow, matching color. */
16163 		if (__flow_dv_create_policy_flow(dev,
16164 				color_reg_c_idx, (enum rte_color)i,
16165 				color_rule->matcher->matcher_object,
16166 				acts[i].actions_n, acts[i].dv_actions,
16167 				svport_match, NULL, &color_rule->rule,
16168 				&attr)) {
16169 			DRV_LOG(ERR, "Failed to create color%u rule.", i);
16170 			goto err_exit;
16171 		}
16172 	}
16173 	return 0;
16174 err_exit:
16175 	/* All the policy rules will be cleared. */
16176 	do {
16177 		color_rule = tmp_rules[i];
16178 		if (color_rule) {
16179 			if (color_rule->rule)
16180 				mlx5_flow_os_destroy_flow(color_rule->rule);
16181 			if (color_rule->matcher) {
16182 				struct mlx5_flow_tbl_data_entry *tbl =
16183 					container_of(color_rule->matcher->tbl,
16184 						     typeof(*tbl), tbl);
16185 				mlx5_list_unregister(tbl->matchers,
16186 						&color_rule->matcher->entry);
16187 			}
16188 			TAILQ_REMOVE(&sub_policy->color_rules[i],
16189 				     color_rule, next_port);
16190 			mlx5_free(color_rule);
16191 		}
16192 	} while (i--);
16193 	return -1;
16194 }
16195 
16196 static int
16197 __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
16198 			struct mlx5_flow_meter_policy *mtr_policy,
16199 			struct mlx5_flow_meter_sub_policy *sub_policy,
16200 			uint32_t domain)
16201 {
16202 	struct mlx5_priv *priv = dev->data->dev_private;
16203 	struct mlx5_meter_policy_acts acts[RTE_COLORS];
16204 	struct mlx5_flow_dv_tag_resource *tag;
16205 	struct mlx5_flow_dv_port_id_action_resource *port_action;
16206 	struct mlx5_hrxq *hrxq;
16207 	struct mlx5_flow_meter_info *next_fm = NULL;
16208 	struct mlx5_flow_meter_policy *next_policy;
16209 	struct mlx5_flow_meter_sub_policy *next_sub_policy;
16210 	struct mlx5_flow_tbl_data_entry *tbl_data;
16211 	struct rte_flow_error error;
16212 	uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16213 	uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16214 	bool mtr_first = egress || (transfer && priv->representor_id != UINT16_MAX);
16215 	bool match_src_port = false;
16216 	int i;
16217 
16218 	/* If RSS or Queue, no previous actions / rules is created. */
16219 	for (i = 0; i < RTE_COLORS; i++) {
16220 		acts[i].actions_n = 0;
16221 		if (i == RTE_COLOR_RED) {
16222 			/* Only support drop on red. */
16223 			acts[i].dv_actions[0] =
16224 				mtr_policy->dr_drop_action[domain];
16225 			acts[i].actions_n = 1;
16226 			continue;
16227 		}
16228 		if (i == RTE_COLOR_GREEN &&
16229 		    mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) {
16230 			struct rte_flow_attr attr = {
16231 				.transfer = transfer
16232 			};
16233 
16234 			next_fm = mlx5_flow_meter_find(priv,
16235 					mtr_policy->act_cnt[i].next_mtr_id,
16236 					NULL);
16237 			if (!next_fm) {
16238 				DRV_LOG(ERR,
16239 					"Failed to get next hierarchy meter.");
16240 				goto err_exit;
16241 			}
16242 			if (mlx5_flow_meter_attach(priv, next_fm,
16243 						   &attr, &error)) {
16244 				DRV_LOG(ERR, "%s", error.message);
16245 				next_fm = NULL;
16246 				goto err_exit;
16247 			}
16248 			/* Meter action must be the first for TX. */
16249 			if (mtr_first) {
16250 				acts[i].dv_actions[acts[i].actions_n] =
16251 					next_fm->meter_action;
16252 				acts[i].actions_n++;
16253 			}
16254 		}
16255 		if (mtr_policy->act_cnt[i].rix_mark) {
16256 			tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
16257 					mtr_policy->act_cnt[i].rix_mark);
16258 			if (!tag) {
16259 				DRV_LOG(ERR, "Failed to find "
16260 				"mark action for policy.");
16261 				goto err_exit;
16262 			}
16263 			acts[i].dv_actions[acts[i].actions_n] = tag->action;
16264 			acts[i].actions_n++;
16265 		}
16266 		if (mtr_policy->act_cnt[i].modify_hdr) {
16267 			acts[i].dv_actions[acts[i].actions_n] =
16268 				mtr_policy->act_cnt[i].modify_hdr->action;
16269 			acts[i].actions_n++;
16270 		}
16271 		if (mtr_policy->act_cnt[i].fate_action) {
16272 			switch (mtr_policy->act_cnt[i].fate_action) {
16273 			case MLX5_FLOW_FATE_PORT_ID:
16274 				port_action = mlx5_ipool_get
16275 					(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
16276 				mtr_policy->act_cnt[i].rix_port_id_action);
16277 				if (!port_action) {
16278 					DRV_LOG(ERR, "Failed to find "
16279 						"port action for policy.");
16280 					goto err_exit;
16281 				}
16282 				acts[i].dv_actions[acts[i].actions_n] =
16283 					port_action->action;
16284 				acts[i].actions_n++;
16285 				mtr_policy->dev = dev;
16286 				match_src_port = true;
16287 				break;
16288 			case MLX5_FLOW_FATE_DROP:
16289 			case MLX5_FLOW_FATE_JUMP:
16290 				acts[i].dv_actions[acts[i].actions_n] =
16291 				mtr_policy->act_cnt[i].dr_jump_action[domain];
16292 				acts[i].actions_n++;
16293 				break;
16294 			case MLX5_FLOW_FATE_SHARED_RSS:
16295 			case MLX5_FLOW_FATE_QUEUE:
16296 				hrxq = mlx5_ipool_get
16297 					(priv->sh->ipool[MLX5_IPOOL_HRXQ],
16298 					 sub_policy->rix_hrxq[i]);
16299 				if (!hrxq) {
16300 					DRV_LOG(ERR, "Failed to find "
16301 						"queue action for policy.");
16302 					goto err_exit;
16303 				}
16304 				acts[i].dv_actions[acts[i].actions_n] =
16305 					hrxq->action;
16306 				acts[i].actions_n++;
16307 				break;
16308 			case MLX5_FLOW_FATE_MTR:
16309 				if (!next_fm) {
16310 					DRV_LOG(ERR,
16311 						"No next hierarchy meter.");
16312 					goto err_exit;
16313 				}
16314 				if (!mtr_first) {
16315 					acts[i].dv_actions[acts[i].actions_n] =
16316 							next_fm->meter_action;
16317 					acts[i].actions_n++;
16318 				}
16319 				if (mtr_policy->act_cnt[i].next_sub_policy) {
16320 					next_sub_policy =
16321 					mtr_policy->act_cnt[i].next_sub_policy;
16322 				} else {
16323 					next_policy =
16324 						mlx5_flow_meter_policy_find(dev,
16325 						next_fm->policy_id, NULL);
16326 					MLX5_ASSERT(next_policy);
16327 					next_sub_policy =
16328 					next_policy->sub_policys[domain][0];
16329 				}
16330 				tbl_data =
16331 					container_of(next_sub_policy->tbl_rsc,
16332 					struct mlx5_flow_tbl_data_entry, tbl);
16333 				acts[i].dv_actions[acts[i].actions_n++] =
16334 							tbl_data->jump.action;
16335 				if (mtr_policy->act_cnt[i].modify_hdr)
16336 					match_src_port = !!transfer;
16337 				break;
16338 			default:
16339 				/*Queue action do nothing*/
16340 				break;
16341 			}
16342 		}
16343 	}
16344 	if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
16345 				egress, transfer, match_src_port, acts)) {
16346 		DRV_LOG(ERR,
16347 			"Failed to create policy rules per domain.");
16348 		goto err_exit;
16349 	}
16350 	return 0;
16351 err_exit:
16352 	if (next_fm)
16353 		mlx5_flow_meter_detach(priv, next_fm);
16354 	return -1;
16355 }
16356 
16357 /**
16358  * Create the policy rules.
16359  *
16360  * @param[in] dev
16361  *   Pointer to Ethernet device.
16362  * @param[in,out] mtr_policy
16363  *   Pointer to meter policy table.
16364  *
16365  * @return
16366  *   0 on success, -1 otherwise.
16367  */
16368 static int
16369 flow_dv_create_policy_rules(struct rte_eth_dev *dev,
16370 			     struct mlx5_flow_meter_policy *mtr_policy)
16371 {
16372 	int i;
16373 	uint16_t sub_policy_num;
16374 
16375 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16376 		sub_policy_num = (mtr_policy->sub_policy_num >>
16377 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
16378 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16379 		if (!sub_policy_num)
16380 			continue;
16381 		/* Prepare actions list and create policy rules. */
16382 		if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
16383 			mtr_policy->sub_policys[i][0], i)) {
16384 			DRV_LOG(ERR, "Failed to create policy action "
16385 				"list per domain.");
16386 			return -1;
16387 		}
16388 	}
16389 	return 0;
16390 }
16391 
16392 static int
16393 __flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
16394 {
16395 	struct mlx5_priv *priv = dev->data->dev_private;
16396 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16397 	struct mlx5_flow_meter_def_policy *def_policy;
16398 	struct mlx5_flow_tbl_resource *jump_tbl;
16399 	struct mlx5_flow_tbl_data_entry *tbl_data;
16400 	uint8_t egress, transfer;
16401 	struct rte_flow_error error;
16402 	struct mlx5_meter_policy_acts acts[RTE_COLORS];
16403 	int ret;
16404 
16405 	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16406 	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16407 	def_policy = mtrmng->def_policy[domain];
16408 	if (!def_policy) {
16409 		def_policy = mlx5_malloc(MLX5_MEM_ZERO,
16410 			sizeof(struct mlx5_flow_meter_def_policy),
16411 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
16412 		if (!def_policy) {
16413 			DRV_LOG(ERR, "Failed to alloc default policy table.");
16414 			goto def_policy_error;
16415 		}
16416 		mtrmng->def_policy[domain] = def_policy;
16417 		/* Create the meter suffix table with SUFFIX level. */
16418 		jump_tbl = flow_dv_tbl_resource_get(dev,
16419 				MLX5_FLOW_TABLE_LEVEL_METER,
16420 				egress, transfer, false, NULL, 0,
16421 				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
16422 		if (!jump_tbl) {
16423 			DRV_LOG(ERR,
16424 				"Failed to create meter suffix table.");
16425 			goto def_policy_error;
16426 		}
16427 		def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
16428 		tbl_data = container_of(jump_tbl,
16429 					struct mlx5_flow_tbl_data_entry, tbl);
16430 		def_policy->dr_jump_action[RTE_COLOR_GREEN] =
16431 						tbl_data->jump.action;
16432 		acts[RTE_COLOR_GREEN].dv_actions[0] = tbl_data->jump.action;
16433 		acts[RTE_COLOR_GREEN].actions_n = 1;
16434 		/*
16435 		 * YELLOW has the same default policy as GREEN does.
16436 		 * G & Y share the same table and action. The 2nd time of table
16437 		 * resource getting is just to update the reference count for
16438 		 * the releasing stage.
16439 		 */
16440 		jump_tbl = flow_dv_tbl_resource_get(dev,
16441 				MLX5_FLOW_TABLE_LEVEL_METER,
16442 				egress, transfer, false, NULL, 0,
16443 				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
16444 		if (!jump_tbl) {
16445 			DRV_LOG(ERR,
16446 				"Failed to get meter suffix table.");
16447 			goto def_policy_error;
16448 		}
16449 		def_policy->sub_policy.jump_tbl[RTE_COLOR_YELLOW] = jump_tbl;
16450 		tbl_data = container_of(jump_tbl,
16451 					struct mlx5_flow_tbl_data_entry, tbl);
16452 		def_policy->dr_jump_action[RTE_COLOR_YELLOW] =
16453 						tbl_data->jump.action;
16454 		acts[RTE_COLOR_YELLOW].dv_actions[0] = tbl_data->jump.action;
16455 		acts[RTE_COLOR_YELLOW].actions_n = 1;
16456 		/* Create jump action to the drop table. */
16457 		if (!mtrmng->drop_tbl[domain]) {
16458 			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
16459 				(dev, MLX5_FLOW_TABLE_LEVEL_METER,
16460 				 egress, transfer, false, NULL, 0,
16461 				 0, MLX5_MTR_TABLE_ID_DROP, &error);
16462 			if (!mtrmng->drop_tbl[domain]) {
16463 				DRV_LOG(ERR, "Failed to create meter "
16464 					"drop table for default policy.");
16465 				goto def_policy_error;
16466 			}
16467 		}
16468 		/* all RED: unique Drop table for jump action. */
16469 		tbl_data = container_of(mtrmng->drop_tbl[domain],
16470 					struct mlx5_flow_tbl_data_entry, tbl);
16471 		def_policy->dr_jump_action[RTE_COLOR_RED] =
16472 						tbl_data->jump.action;
16473 		acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
16474 		acts[RTE_COLOR_RED].actions_n = 1;
16475 		/* Create default policy rules. */
16476 		ret = __flow_dv_create_domain_policy_rules(dev,
16477 					&def_policy->sub_policy,
16478 					egress, transfer, false, acts);
16479 		if (ret) {
16480 			DRV_LOG(ERR, "Failed to create default policy rules.");
16481 			goto def_policy_error;
16482 		}
16483 	}
16484 	return 0;
16485 def_policy_error:
16486 	__flow_dv_destroy_domain_def_policy(dev,
16487 					    (enum mlx5_meter_domain)domain);
16488 	return -1;
16489 }
16490 
16491 /**
16492  * Create the default policy table set.
16493  *
16494  * @param[in] dev
16495  *   Pointer to Ethernet device.
16496  * @return
16497  *   0 on success, -1 otherwise.
16498  */
16499 static int
16500 flow_dv_create_def_policy(struct rte_eth_dev *dev)
16501 {
16502 	struct mlx5_priv *priv = dev->data->dev_private;
16503 	int i;
16504 
16505 	/* Non-termination policy table. */
16506 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16507 		if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER)
16508 			continue;
16509 		if (__flow_dv_create_domain_def_policy(dev, i)) {
16510 			DRV_LOG(ERR, "Failed to create default policy");
16511 			/* Rollback the created default policies for others. */
16512 			flow_dv_destroy_def_policy(dev);
16513 			return -1;
16514 		}
16515 	}
16516 	return 0;
16517 }
16518 
16519 /**
16520  * Create the needed meter tables.
16521  * Lock free, (mutex should be acquired by caller).
16522  *
16523  * @param[in] dev
16524  *   Pointer to Ethernet device.
16525  * @param[in] fm
16526  *   Meter information table.
16527  * @param[in] mtr_idx
16528  *   Meter index.
16529  * @param[in] domain_bitmap
16530  *   Domain bitmap.
16531  * @return
16532  *   0 on success, -1 otherwise.
16533  */
16534 static int
16535 flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
16536 			struct mlx5_flow_meter_info *fm,
16537 			uint32_t mtr_idx,
16538 			uint8_t domain_bitmap)
16539 {
16540 	struct mlx5_priv *priv = dev->data->dev_private;
16541 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16542 	struct rte_flow_error error;
16543 	struct mlx5_flow_tbl_data_entry *tbl_data;
16544 	uint8_t egress, transfer;
16545 	void *actions[METER_ACTIONS];
16546 	int domain, ret, i;
16547 	struct mlx5_flow_counter *cnt;
16548 	struct mlx5_flow_dv_match_params value = {
16549 		.size = sizeof(value.buf),
16550 	};
16551 	struct mlx5_flow_dv_match_params matcher_para = {
16552 		.size = sizeof(matcher_para.buf),
16553 	};
16554 	int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
16555 						     0, &error);
16556 	uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1;
16557 	uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
16558 	struct mlx5_list_entry *entry;
16559 	struct mlx5_flow_dv_matcher matcher = {
16560 		.mask = {
16561 			.size = sizeof(matcher.mask.buf),
16562 		},
16563 	};
16564 	struct mlx5_flow_dv_matcher *drop_matcher;
16565 	struct mlx5_flow_cb_ctx ctx = {
16566 		.error = &error,
16567 		.data = &matcher,
16568 	};
16569 	uint8_t misc_mask;
16570 
16571 	if (!priv->mtr_en || mtr_id_reg_c < 0) {
16572 		rte_errno = ENOTSUP;
16573 		return -1;
16574 	}
16575 	for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
16576 		if (!(domain_bitmap & (1 << domain)) ||
16577 			(mtrmng->def_rule[domain] && !fm->drop_cnt))
16578 			continue;
16579 		egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16580 		transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16581 		/* Create the drop table with METER DROP level. */
16582 		if (!mtrmng->drop_tbl[domain]) {
16583 			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev,
16584 					MLX5_FLOW_TABLE_LEVEL_METER,
16585 					egress, transfer, false, NULL, 0,
16586 					0, MLX5_MTR_TABLE_ID_DROP, &error);
16587 			if (!mtrmng->drop_tbl[domain]) {
16588 				DRV_LOG(ERR, "Failed to create meter drop table.");
16589 				goto policy_error;
16590 			}
16591 		}
16592 		/* Create default matcher in drop table. */
16593 		matcher.tbl = mtrmng->drop_tbl[domain],
16594 		tbl_data = container_of(mtrmng->drop_tbl[domain],
16595 				struct mlx5_flow_tbl_data_entry, tbl);
16596 		if (!mtrmng->def_matcher[domain]) {
16597 			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16598 				       (enum modify_reg)mtr_id_reg_c,
16599 				       0, 0);
16600 			matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
16601 			matcher.crc = rte_raw_cksum
16602 					((const void *)matcher.mask.buf,
16603 					matcher.mask.size);
16604 			entry = mlx5_list_register(tbl_data->matchers, &ctx);
16605 			if (!entry) {
16606 				DRV_LOG(ERR, "Failed to register meter "
16607 				"drop default matcher.");
16608 				goto policy_error;
16609 			}
16610 			mtrmng->def_matcher[domain] = container_of(entry,
16611 			struct mlx5_flow_dv_matcher, entry);
16612 		}
16613 		/* Create default rule in drop table. */
16614 		if (!mtrmng->def_rule[domain]) {
16615 			i = 0;
16616 			actions[i++] = priv->sh->dr_drop_action;
16617 			flow_dv_match_meta_reg(matcher_para.buf, value.buf,
16618 				(enum modify_reg)mtr_id_reg_c, 0, 0);
16619 			misc_mask = flow_dv_matcher_enable(value.buf);
16620 			__flow_dv_adjust_buf_size(&value.size, misc_mask);
16621 			ret = mlx5_flow_os_create_flow
16622 				(mtrmng->def_matcher[domain]->matcher_object,
16623 				(void *)&value, i, actions,
16624 				&mtrmng->def_rule[domain]);
16625 			if (ret) {
16626 				DRV_LOG(ERR, "Failed to create meter "
16627 				"default drop rule for drop table.");
16628 				goto policy_error;
16629 			}
16630 		}
16631 		if (!fm->drop_cnt)
16632 			continue;
16633 		MLX5_ASSERT(mtrmng->max_mtr_bits);
16634 		if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) {
16635 			/* Create matchers for Drop. */
16636 			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16637 					(enum modify_reg)mtr_id_reg_c, 0,
16638 					(mtr_id_mask << mtr_id_offset));
16639 			matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
16640 			matcher.crc = rte_raw_cksum
16641 					((const void *)matcher.mask.buf,
16642 					matcher.mask.size);
16643 			entry = mlx5_list_register(tbl_data->matchers, &ctx);
16644 			if (!entry) {
16645 				DRV_LOG(ERR,
16646 				"Failed to register meter drop matcher.");
16647 				goto policy_error;
16648 			}
16649 			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] =
16650 				container_of(entry, struct mlx5_flow_dv_matcher,
16651 					     entry);
16652 		}
16653 		drop_matcher =
16654 			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1];
16655 		/* Create drop rule, matching meter_id only. */
16656 		flow_dv_match_meta_reg(matcher_para.buf, value.buf,
16657 				(enum modify_reg)mtr_id_reg_c,
16658 				(mtr_idx << mtr_id_offset), UINT32_MAX);
16659 		i = 0;
16660 		cnt = flow_dv_counter_get_by_idx(dev,
16661 					fm->drop_cnt, NULL);
16662 		actions[i++] = cnt->action;
16663 		actions[i++] = priv->sh->dr_drop_action;
16664 		misc_mask = flow_dv_matcher_enable(value.buf);
16665 		__flow_dv_adjust_buf_size(&value.size, misc_mask);
16666 		ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
16667 					       (void *)&value, i, actions,
16668 					       &fm->drop_rule[domain]);
16669 		if (ret) {
16670 			DRV_LOG(ERR, "Failed to create meter "
16671 				"drop rule for drop table.");
16672 				goto policy_error;
16673 		}
16674 	}
16675 	return 0;
16676 policy_error:
16677 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16678 		if (fm->drop_rule[i]) {
16679 			claim_zero(mlx5_flow_os_destroy_flow
16680 				(fm->drop_rule[i]));
16681 			fm->drop_rule[i] = NULL;
16682 		}
16683 	}
16684 	return -1;
16685 }
16686 
16687 static struct mlx5_flow_meter_sub_policy *
16688 __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev,
16689 		struct mlx5_flow_meter_policy *mtr_policy,
16690 		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS],
16691 		struct mlx5_flow_meter_sub_policy *next_sub_policy,
16692 		bool *is_reuse)
16693 {
16694 	struct mlx5_priv *priv = dev->data->dev_private;
16695 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
16696 	uint32_t sub_policy_idx = 0;
16697 	uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
16698 	uint32_t i, j;
16699 	struct mlx5_hrxq *hrxq;
16700 	struct mlx5_flow_handle dh;
16701 	struct mlx5_meter_policy_action_container *act_cnt;
16702 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
16703 	uint16_t sub_policy_num;
16704 
16705 	rte_spinlock_lock(&mtr_policy->sl);
16706 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16707 		if (!rss_desc[i])
16708 			continue;
16709 		hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]);
16710 		if (!hrxq_idx[i]) {
16711 			rte_spinlock_unlock(&mtr_policy->sl);
16712 			return NULL;
16713 		}
16714 	}
16715 	sub_policy_num = (mtr_policy->sub_policy_num >>
16716 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16717 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16718 	for (j = 0; j < sub_policy_num; j++) {
16719 		for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16720 			if (rss_desc[i] &&
16721 			    hrxq_idx[i] !=
16722 			    mtr_policy->sub_policys[domain][j]->rix_hrxq[i])
16723 				break;
16724 		}
16725 		if (i >= MLX5_MTR_RTE_COLORS) {
16726 			/*
16727 			 * Found the sub policy table with
16728 			 * the same queue per color.
16729 			 */
16730 			rte_spinlock_unlock(&mtr_policy->sl);
16731 			for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
16732 				mlx5_hrxq_release(dev, hrxq_idx[i]);
16733 			*is_reuse = true;
16734 			return mtr_policy->sub_policys[domain][j];
16735 		}
16736 	}
16737 	/* Create sub policy. */
16738 	if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) {
16739 		/* Reuse the first pre-allocated sub_policy. */
16740 		sub_policy = mtr_policy->sub_policys[domain][0];
16741 		sub_policy_idx = sub_policy->idx;
16742 	} else {
16743 		sub_policy = mlx5_ipool_zmalloc
16744 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16745 				 &sub_policy_idx);
16746 		if (!sub_policy ||
16747 		    sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) {
16748 			for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
16749 				mlx5_hrxq_release(dev, hrxq_idx[i]);
16750 			goto rss_sub_policy_error;
16751 		}
16752 		sub_policy->idx = sub_policy_idx;
16753 		sub_policy->main_policy = mtr_policy;
16754 	}
16755 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16756 		if (!rss_desc[i])
16757 			continue;
16758 		sub_policy->rix_hrxq[i] = hrxq_idx[i];
16759 		if (mtr_policy->is_hierarchy) {
16760 			act_cnt = &mtr_policy->act_cnt[i];
16761 			act_cnt->next_sub_policy = next_sub_policy;
16762 			mlx5_hrxq_release(dev, hrxq_idx[i]);
16763 		} else {
16764 			/*
16765 			 * Overwrite the last action from
16766 			 * RSS action to Queue action.
16767 			 */
16768 			hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
16769 					      hrxq_idx[i]);
16770 			if (!hrxq) {
16771 				DRV_LOG(ERR, "Failed to get policy hrxq");
16772 				goto rss_sub_policy_error;
16773 			}
16774 			act_cnt = &mtr_policy->act_cnt[i];
16775 			if (act_cnt->rix_mark || act_cnt->modify_hdr) {
16776 				memset(&dh, 0, sizeof(struct mlx5_flow_handle));
16777 				if (act_cnt->rix_mark)
16778 					dh.mark = 1;
16779 				dh.fate_action = MLX5_FLOW_FATE_QUEUE;
16780 				dh.rix_hrxq = hrxq_idx[i];
16781 				flow_drv_rxq_flags_set(dev, &dh);
16782 			}
16783 		}
16784 	}
16785 	if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
16786 					       sub_policy, domain)) {
16787 		DRV_LOG(ERR, "Failed to create policy "
16788 			"rules for ingress domain.");
16789 		goto rss_sub_policy_error;
16790 	}
16791 	if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16792 		i = (mtr_policy->sub_policy_num >>
16793 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16794 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16795 		if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) {
16796 			DRV_LOG(ERR, "No free sub-policy slot.");
16797 			goto rss_sub_policy_error;
16798 		}
16799 		mtr_policy->sub_policys[domain][i] = sub_policy;
16800 		i++;
16801 		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
16802 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
16803 		mtr_policy->sub_policy_num |=
16804 			(i & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
16805 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
16806 	}
16807 	rte_spinlock_unlock(&mtr_policy->sl);
16808 	*is_reuse = false;
16809 	return sub_policy;
16810 rss_sub_policy_error:
16811 	if (sub_policy) {
16812 		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
16813 		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16814 			i = (mtr_policy->sub_policy_num >>
16815 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16816 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16817 			mtr_policy->sub_policys[domain][i] = NULL;
16818 			mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16819 					sub_policy->idx);
16820 		}
16821 	}
16822 	rte_spinlock_unlock(&mtr_policy->sl);
16823 	return NULL;
16824 }
16825 
16826 /**
16827  * Find the policy table for prefix table with RSS.
16828  *
16829  * @param[in] dev
16830  *   Pointer to Ethernet device.
16831  * @param[in] mtr_policy
16832  *   Pointer to meter policy table.
16833  * @param[in] rss_desc
16834  *   Pointer to rss_desc
16835  * @return
16836  *   Pointer to table set on success, NULL otherwise and rte_errno is set.
16837  */
16838 static struct mlx5_flow_meter_sub_policy *
16839 flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
16840 		struct mlx5_flow_meter_policy *mtr_policy,
16841 		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
16842 {
16843 	struct mlx5_priv *priv = dev->data->dev_private;
16844 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
16845 	struct mlx5_flow_meter_info *next_fm;
16846 	struct mlx5_flow_meter_policy *next_policy;
16847 	struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL;
16848 	struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM];
16849 	struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM];
16850 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
16851 	bool reuse_sub_policy;
16852 	uint32_t i = 0;
16853 	uint32_t j = 0;
16854 
16855 	while (true) {
16856 		/* Iterate hierarchy to get all policies in this hierarchy. */
16857 		policies[i++] = mtr_policy;
16858 		if (!mtr_policy->is_hierarchy)
16859 			break;
16860 		if (i >= MLX5_MTR_CHAIN_MAX_NUM) {
16861 			DRV_LOG(ERR, "Exceed max meter number in hierarchy.");
16862 			return NULL;
16863 		}
16864 		next_fm = mlx5_flow_meter_find(priv,
16865 			mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
16866 		if (!next_fm) {
16867 			DRV_LOG(ERR, "Failed to get next meter in hierarchy.");
16868 			return NULL;
16869 		}
16870 		next_policy =
16871 			mlx5_flow_meter_policy_find(dev, next_fm->policy_id,
16872 						    NULL);
16873 		MLX5_ASSERT(next_policy);
16874 		mtr_policy = next_policy;
16875 	}
16876 	while (i) {
16877 		/**
16878 		 * From last policy to the first one in hierarchy,
16879 		 * create / get the sub policy for each of them.
16880 		 */
16881 		sub_policy = __flow_dv_meter_get_rss_sub_policy(dev,
16882 							policies[--i],
16883 							rss_desc,
16884 							next_sub_policy,
16885 							&reuse_sub_policy);
16886 		if (!sub_policy) {
16887 			DRV_LOG(ERR, "Failed to get the sub policy.");
16888 			goto err_exit;
16889 		}
16890 		if (!reuse_sub_policy)
16891 			sub_policies[j++] = sub_policy;
16892 		next_sub_policy = sub_policy;
16893 	}
16894 	return sub_policy;
16895 err_exit:
16896 	while (j) {
16897 		uint16_t sub_policy_num;
16898 
16899 		sub_policy = sub_policies[--j];
16900 		mtr_policy = sub_policy->main_policy;
16901 		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
16902 		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16903 			sub_policy_num = (mtr_policy->sub_policy_num >>
16904 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16905 				MLX5_MTR_SUB_POLICY_NUM_MASK;
16906 			mtr_policy->sub_policys[domain][sub_policy_num - 1] =
16907 									NULL;
16908 			sub_policy_num--;
16909 			mtr_policy->sub_policy_num &=
16910 				~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
16911 				  (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
16912 			mtr_policy->sub_policy_num |=
16913 			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
16914 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
16915 			mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16916 					sub_policy->idx);
16917 		}
16918 	}
16919 	return NULL;
16920 }
16921 
16922 /**
16923  * Create the sub policy tag rule for all meters in hierarchy.
16924  *
16925  * @param[in] dev
16926  *   Pointer to Ethernet device.
16927  * @param[in] fm
16928  *   Meter information table.
16929  * @param[in] src_port
16930  *   The src port this extra rule should use.
16931  * @param[in] item
16932  *   The src port match item.
16933  * @param[out] error
16934  *   Perform verbose error reporting if not NULL.
16935  * @return
16936  *   0 on success, a negative errno value otherwise and rte_errno is set.
16937  */
16938 static int
16939 flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev,
16940 				struct mlx5_flow_meter_info *fm,
16941 				int32_t src_port,
16942 				const struct rte_flow_item *item,
16943 				struct rte_flow_error *error)
16944 {
16945 	struct mlx5_priv *priv = dev->data->dev_private;
16946 	struct mlx5_flow_meter_policy *mtr_policy;
16947 	struct mlx5_flow_meter_sub_policy *sub_policy;
16948 	struct mlx5_flow_meter_info *next_fm = NULL;
16949 	struct mlx5_flow_meter_policy *next_policy;
16950 	struct mlx5_flow_meter_sub_policy *next_sub_policy;
16951 	struct mlx5_flow_tbl_data_entry *tbl_data;
16952 	struct mlx5_sub_policy_color_rule *color_rule;
16953 	struct mlx5_meter_policy_acts acts;
16954 	uint32_t color_reg_c_idx;
16955 	bool mtr_first = (src_port != UINT16_MAX) ? true : false;
16956 	struct rte_flow_attr attr = {
16957 		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
16958 		.priority = 0,
16959 		.ingress = 0,
16960 		.egress = 0,
16961 		.transfer = 1,
16962 		.reserved = 0,
16963 	};
16964 	uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER;
16965 	int i;
16966 
16967 	mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
16968 	MLX5_ASSERT(mtr_policy);
16969 	if (!mtr_policy->is_hierarchy)
16970 		return 0;
16971 	next_fm = mlx5_flow_meter_find(priv,
16972 			mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
16973 	if (!next_fm) {
16974 		return rte_flow_error_set(error, EINVAL,
16975 				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
16976 				"Failed to find next meter in hierarchy.");
16977 	}
16978 	if (!next_fm->drop_cnt)
16979 		goto exit;
16980 	color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error);
16981 	sub_policy = mtr_policy->sub_policys[domain][0];
16982 	for (i = 0; i < RTE_COLORS; i++) {
16983 		bool rule_exist = false;
16984 		struct mlx5_meter_policy_action_container *act_cnt;
16985 
16986 		if (i >= RTE_COLOR_YELLOW)
16987 			break;
16988 		TAILQ_FOREACH(color_rule,
16989 			      &sub_policy->color_rules[i], next_port)
16990 			if (color_rule->src_port == src_port) {
16991 				rule_exist = true;
16992 				break;
16993 			}
16994 		if (rule_exist)
16995 			continue;
16996 		color_rule = mlx5_malloc(MLX5_MEM_ZERO,
16997 				sizeof(struct mlx5_sub_policy_color_rule),
16998 				0, SOCKET_ID_ANY);
16999 		if (!color_rule)
17000 			return rte_flow_error_set(error, ENOMEM,
17001 				RTE_FLOW_ERROR_TYPE_ACTION,
17002 				NULL, "No memory to create tag color rule.");
17003 		color_rule->src_port = src_port;
17004 		attr.priority = i;
17005 		next_policy = mlx5_flow_meter_policy_find(dev,
17006 						next_fm->policy_id, NULL);
17007 		MLX5_ASSERT(next_policy);
17008 		next_sub_policy = next_policy->sub_policys[domain][0];
17009 		tbl_data = container_of(next_sub_policy->tbl_rsc,
17010 					struct mlx5_flow_tbl_data_entry, tbl);
17011 		act_cnt = &mtr_policy->act_cnt[i];
17012 		if (mtr_first) {
17013 			acts.dv_actions[0] = next_fm->meter_action;
17014 			acts.dv_actions[1] = act_cnt->modify_hdr->action;
17015 		} else {
17016 			acts.dv_actions[0] = act_cnt->modify_hdr->action;
17017 			acts.dv_actions[1] = next_fm->meter_action;
17018 		}
17019 		acts.dv_actions[2] = tbl_data->jump.action;
17020 		acts.actions_n = 3;
17021 		if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) {
17022 			next_fm = NULL;
17023 			goto err_exit;
17024 		}
17025 		if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
17026 				MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
17027 				&attr, true, item,
17028 				&color_rule->matcher, error)) {
17029 			rte_flow_error_set(error, errno,
17030 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
17031 				"Failed to create hierarchy meter matcher.");
17032 			goto err_exit;
17033 		}
17034 		if (__flow_dv_create_policy_flow(dev, color_reg_c_idx,
17035 					(enum rte_color)i,
17036 					color_rule->matcher->matcher_object,
17037 					acts.actions_n, acts.dv_actions,
17038 					true, item,
17039 					&color_rule->rule, &attr)) {
17040 			rte_flow_error_set(error, errno,
17041 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
17042 				"Failed to create hierarchy meter rule.");
17043 			goto err_exit;
17044 		}
17045 		TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
17046 				  color_rule, next_port);
17047 	}
17048 exit:
17049 	/**
17050 	 * Recursive call to iterate all meters in hierarchy and
17051 	 * create needed rules.
17052 	 */
17053 	return flow_dv_meter_hierarchy_rule_create(dev, next_fm,
17054 						src_port, item, error);
17055 err_exit:
17056 	if (color_rule) {
17057 		if (color_rule->rule)
17058 			mlx5_flow_os_destroy_flow(color_rule->rule);
17059 		if (color_rule->matcher) {
17060 			struct mlx5_flow_tbl_data_entry *tbl =
17061 				container_of(color_rule->matcher->tbl,
17062 						typeof(*tbl), tbl);
17063 			mlx5_list_unregister(tbl->matchers,
17064 						&color_rule->matcher->entry);
17065 		}
17066 		mlx5_free(color_rule);
17067 	}
17068 	if (next_fm)
17069 		mlx5_flow_meter_detach(priv, next_fm);
17070 	return -rte_errno;
17071 }
17072 
17073 /**
17074  * Destroy the sub policy table with RX queue.
17075  *
17076  * @param[in] dev
17077  *   Pointer to Ethernet device.
17078  * @param[in] mtr_policy
17079  *   Pointer to meter policy table.
17080  */
17081 static void
17082 flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev,
17083 				    struct mlx5_flow_meter_policy *mtr_policy)
17084 {
17085 	struct mlx5_priv *priv = dev->data->dev_private;
17086 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
17087 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
17088 	uint32_t i, j;
17089 	uint16_t sub_policy_num, new_policy_num;
17090 
17091 	rte_spinlock_lock(&mtr_policy->sl);
17092 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
17093 		switch (mtr_policy->act_cnt[i].fate_action) {
17094 		case MLX5_FLOW_FATE_SHARED_RSS:
17095 			sub_policy_num = (mtr_policy->sub_policy_num >>
17096 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
17097 			MLX5_MTR_SUB_POLICY_NUM_MASK;
17098 			new_policy_num = sub_policy_num;
17099 			for (j = 0; j < sub_policy_num; j++) {
17100 				sub_policy =
17101 					mtr_policy->sub_policys[domain][j];
17102 				if (sub_policy) {
17103 					__flow_dv_destroy_sub_policy_rules(dev,
17104 						sub_policy);
17105 				if (sub_policy !=
17106 					mtr_policy->sub_policys[domain][0]) {
17107 					mtr_policy->sub_policys[domain][j] =
17108 								NULL;
17109 					mlx5_ipool_free
17110 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
17111 						sub_policy->idx);
17112 						new_policy_num--;
17113 					}
17114 				}
17115 			}
17116 			if (new_policy_num != sub_policy_num) {
17117 				mtr_policy->sub_policy_num &=
17118 				~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
17119 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
17120 				mtr_policy->sub_policy_num |=
17121 				(new_policy_num &
17122 					MLX5_MTR_SUB_POLICY_NUM_MASK) <<
17123 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
17124 			}
17125 			break;
17126 		case MLX5_FLOW_FATE_QUEUE:
17127 			sub_policy = mtr_policy->sub_policys[domain][0];
17128 			__flow_dv_destroy_sub_policy_rules(dev,
17129 							   sub_policy);
17130 			break;
17131 		default:
17132 			/*Other actions without queue and do nothing*/
17133 			break;
17134 		}
17135 	}
17136 	rte_spinlock_unlock(&mtr_policy->sl);
17137 }
17138 /**
17139  * Check whether the DR drop action is supported on the root table or not.
17140  *
17141  * Create a simple flow with DR drop action on root table to validate
17142  * if DR drop action on root table is supported or not.
17143  *
17144  * @param[in] dev
17145  *   Pointer to rte_eth_dev structure.
17146  *
17147  * @return
17148  *   0 on success, a negative errno value otherwise and rte_errno is set.
17149  */
17150 int
17151 mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev)
17152 {
17153 	struct mlx5_priv *priv = dev->data->dev_private;
17154 	struct mlx5_dev_ctx_shared *sh = priv->sh;
17155 	struct mlx5_flow_dv_match_params mask = {
17156 		.size = sizeof(mask.buf),
17157 	};
17158 	struct mlx5_flow_dv_match_params value = {
17159 		.size = sizeof(value.buf),
17160 	};
17161 	struct mlx5dv_flow_matcher_attr dv_attr = {
17162 		.type = IBV_FLOW_ATTR_NORMAL,
17163 		.priority = 0,
17164 		.match_criteria_enable = 0,
17165 		.match_mask = (void *)&mask,
17166 	};
17167 	struct mlx5_flow_tbl_resource *tbl = NULL;
17168 	void *matcher = NULL;
17169 	void *flow = NULL;
17170 	int ret = -1;
17171 
17172 	tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL,
17173 					0, 0, 0, NULL);
17174 	if (!tbl)
17175 		goto err;
17176 	dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
17177 	__flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
17178 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj,
17179 					       &matcher);
17180 	if (ret)
17181 		goto err;
17182 	__flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
17183 	ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
17184 				       &sh->dr_drop_action, &flow);
17185 err:
17186 	/*
17187 	 * If DR drop action is not supported on root table, flow create will
17188 	 * be failed with EOPNOTSUPP or EPROTONOSUPPORT.
17189 	 */
17190 	if (!flow) {
17191 		if (matcher &&
17192 		    (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP))
17193 			DRV_LOG(INFO, "DR drop action is not supported in root table.");
17194 		else
17195 			DRV_LOG(ERR, "Unexpected error in DR drop action support detection");
17196 		ret = -1;
17197 	} else {
17198 		claim_zero(mlx5_flow_os_destroy_flow(flow));
17199 	}
17200 	if (matcher)
17201 		claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
17202 	if (tbl)
17203 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
17204 	return ret;
17205 }
17206 
17207 /**
17208  * Validate the batch counter support in root table.
17209  *
17210  * Create a simple flow with invalid counter and drop action on root table to
17211  * validate if batch counter with offset on root table is supported or not.
17212  *
17213  * @param[in] dev
17214  *   Pointer to rte_eth_dev structure.
17215  *
17216  * @return
17217  *   0 on success, a negative errno value otherwise and rte_errno is set.
17218  */
17219 int
17220 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev)
17221 {
17222 	struct mlx5_priv *priv = dev->data->dev_private;
17223 	struct mlx5_dev_ctx_shared *sh = priv->sh;
17224 	struct mlx5_flow_dv_match_params mask = {
17225 		.size = sizeof(mask.buf),
17226 	};
17227 	struct mlx5_flow_dv_match_params value = {
17228 		.size = sizeof(value.buf),
17229 	};
17230 	struct mlx5dv_flow_matcher_attr dv_attr = {
17231 		.type = IBV_FLOW_ATTR_NORMAL | IBV_FLOW_ATTR_FLAGS_EGRESS,
17232 		.priority = 0,
17233 		.match_criteria_enable = 0,
17234 		.match_mask = (void *)&mask,
17235 	};
17236 	void *actions[2] = { 0 };
17237 	struct mlx5_flow_tbl_resource *tbl = NULL;
17238 	struct mlx5_devx_obj *dcs = NULL;
17239 	void *matcher = NULL;
17240 	void *flow = NULL;
17241 	int ret = -1;
17242 
17243 	tbl = flow_dv_tbl_resource_get(dev, 0, 1, 0, false, NULL,
17244 					0, 0, 0, NULL);
17245 	if (!tbl)
17246 		goto err;
17247 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4);
17248 	if (!dcs)
17249 		goto err;
17250 	ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX,
17251 						    &actions[0]);
17252 	if (ret)
17253 		goto err;
17254 	dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
17255 	__flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
17256 	ret = mlx5_flow_os_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj,
17257 					       &matcher);
17258 	if (ret)
17259 		goto err;
17260 	__flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
17261 	ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
17262 				       actions, &flow);
17263 err:
17264 	/*
17265 	 * If batch counter with offset is not supported, the driver will not
17266 	 * validate the invalid offset value, flow create should success.
17267 	 * In this case, it means batch counter is not supported in root table.
17268 	 *
17269 	 * Otherwise, if flow create is failed, counter offset is supported.
17270 	 */
17271 	if (flow) {
17272 		DRV_LOG(INFO, "Batch counter is not supported in root "
17273 			      "table. Switch to fallback mode.");
17274 		rte_errno = ENOTSUP;
17275 		ret = -rte_errno;
17276 		claim_zero(mlx5_flow_os_destroy_flow(flow));
17277 	} else {
17278 		/* Check matcher to make sure validate fail at flow create. */
17279 		if (!matcher || (matcher && errno != EINVAL))
17280 			DRV_LOG(ERR, "Unexpected error in counter offset "
17281 				     "support detection");
17282 		ret = 0;
17283 	}
17284 	if (actions[0])
17285 		claim_zero(mlx5_flow_os_destroy_flow_action(actions[0]));
17286 	if (matcher)
17287 		claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
17288 	if (tbl)
17289 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
17290 	if (dcs)
17291 		claim_zero(mlx5_devx_cmd_destroy(dcs));
17292 	return ret;
17293 }
17294 
17295 /**
17296  * Query a devx counter.
17297  *
17298  * @param[in] dev
17299  *   Pointer to the Ethernet device structure.
17300  * @param[in] cnt
17301  *   Index to the flow counter.
17302  * @param[in] clear
17303  *   Set to clear the counter statistics.
17304  * @param[out] pkts
17305  *   The statistics value of packets.
17306  * @param[out] bytes
17307  *   The statistics value of bytes.
17308  *
17309  * @return
17310  *   0 on success, otherwise return -1.
17311  */
17312 static int
17313 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear,
17314 		      uint64_t *pkts, uint64_t *bytes)
17315 {
17316 	struct mlx5_priv *priv = dev->data->dev_private;
17317 	struct mlx5_flow_counter *cnt;
17318 	uint64_t inn_pkts, inn_bytes;
17319 	int ret;
17320 
17321 	if (!priv->config.devx)
17322 		return -1;
17323 
17324 	ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes);
17325 	if (ret)
17326 		return -1;
17327 	cnt = flow_dv_counter_get_by_idx(dev, counter, NULL);
17328 	*pkts = inn_pkts - cnt->hits;
17329 	*bytes = inn_bytes - cnt->bytes;
17330 	if (clear) {
17331 		cnt->hits = inn_pkts;
17332 		cnt->bytes = inn_bytes;
17333 	}
17334 	return 0;
17335 }
17336 
17337 /**
17338  * Get aged-out flows.
17339  *
17340  * @param[in] dev
17341  *   Pointer to the Ethernet device structure.
17342  * @param[in] context
17343  *   The address of an array of pointers to the aged-out flows contexts.
17344  * @param[in] nb_contexts
17345  *   The length of context array pointers.
17346  * @param[out] error
17347  *   Perform verbose error reporting if not NULL. Initialized in case of
17348  *   error only.
17349  *
17350  * @return
17351  *   how many contexts get in success, otherwise negative errno value.
17352  *   if nb_contexts is 0, return the amount of all aged contexts.
17353  *   if nb_contexts is not 0 , return the amount of aged flows reported
17354  *   in the context array.
17355  * @note: only stub for now
17356  */
17357 static int
17358 flow_dv_get_aged_flows(struct rte_eth_dev *dev,
17359 		    void **context,
17360 		    uint32_t nb_contexts,
17361 		    struct rte_flow_error *error)
17362 {
17363 	struct mlx5_priv *priv = dev->data->dev_private;
17364 	struct mlx5_age_info *age_info;
17365 	struct mlx5_age_param *age_param;
17366 	struct mlx5_flow_counter *counter;
17367 	struct mlx5_aso_age_action *act;
17368 	int nb_flows = 0;
17369 
17370 	if (nb_contexts && !context)
17371 		return rte_flow_error_set(error, EINVAL,
17372 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
17373 					  NULL, "empty context");
17374 	age_info = GET_PORT_AGE_INFO(priv);
17375 	rte_spinlock_lock(&age_info->aged_sl);
17376 	LIST_FOREACH(act, &age_info->aged_aso, next) {
17377 		nb_flows++;
17378 		if (nb_contexts) {
17379 			context[nb_flows - 1] =
17380 						act->age_params.context;
17381 			if (!(--nb_contexts))
17382 				break;
17383 		}
17384 	}
17385 	TAILQ_FOREACH(counter, &age_info->aged_counters, next) {
17386 		nb_flows++;
17387 		if (nb_contexts) {
17388 			age_param = MLX5_CNT_TO_AGE(counter);
17389 			context[nb_flows - 1] = age_param->context;
17390 			if (!(--nb_contexts))
17391 				break;
17392 		}
17393 	}
17394 	rte_spinlock_unlock(&age_info->aged_sl);
17395 	MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER);
17396 	return nb_flows;
17397 }
17398 
17399 /*
17400  * Mutex-protected thunk to lock-free flow_dv_counter_alloc().
17401  */
17402 static uint32_t
17403 flow_dv_counter_allocate(struct rte_eth_dev *dev)
17404 {
17405 	return flow_dv_counter_alloc(dev, 0);
17406 }
17407 
17408 /**
17409  * Validate indirect action.
17410  * Dispatcher for action type specific validation.
17411  *
17412  * @param[in] dev
17413  *   Pointer to the Ethernet device structure.
17414  * @param[in] conf
17415  *   Indirect action configuration.
17416  * @param[in] action
17417  *   The indirect action object to validate.
17418  * @param[out] error
17419  *   Perform verbose error reporting if not NULL. Initialized in case of
17420  *   error only.
17421  *
17422  * @return
17423  *   0 on success, otherwise negative errno value.
17424  */
17425 static int
17426 flow_dv_action_validate(struct rte_eth_dev *dev,
17427 			const struct rte_flow_indir_action_conf *conf,
17428 			const struct rte_flow_action *action,
17429 			struct rte_flow_error *err)
17430 {
17431 	struct mlx5_priv *priv = dev->data->dev_private;
17432 
17433 	RTE_SET_USED(conf);
17434 	switch (action->type) {
17435 	case RTE_FLOW_ACTION_TYPE_RSS:
17436 		/*
17437 		 * priv->obj_ops is set according to driver capabilities.
17438 		 * When DevX capabilities are
17439 		 * sufficient, it is set to devx_obj_ops.
17440 		 * Otherwise, it is set to ibv_obj_ops.
17441 		 * ibv_obj_ops doesn't support ind_table_modify operation.
17442 		 * In this case the indirect RSS action can't be used.
17443 		 */
17444 		if (priv->obj_ops.ind_table_modify == NULL)
17445 			return rte_flow_error_set
17446 					(err, ENOTSUP,
17447 					 RTE_FLOW_ERROR_TYPE_ACTION,
17448 					 NULL,
17449 					 "Indirect RSS action not supported");
17450 		return mlx5_validate_action_rss(dev, action, err);
17451 	case RTE_FLOW_ACTION_TYPE_AGE:
17452 		if (!priv->sh->aso_age_mng)
17453 			return rte_flow_error_set(err, ENOTSUP,
17454 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
17455 						NULL,
17456 						"Indirect age action not supported");
17457 		return flow_dv_validate_action_age(0, action, dev, err);
17458 	case RTE_FLOW_ACTION_TYPE_COUNT:
17459 		/*
17460 		 * There are two mechanisms to share the action count.
17461 		 * The old mechanism uses the shared field to share, while the
17462 		 * new mechanism uses the indirect action API.
17463 		 * This validation comes to make sure that the two mechanisms
17464 		 * are not combined.
17465 		 */
17466 		if (is_shared_action_count(action))
17467 			return rte_flow_error_set(err, ENOTSUP,
17468 						  RTE_FLOW_ERROR_TYPE_ACTION,
17469 						  NULL,
17470 						  "Mix shared and indirect counter is not supported");
17471 		return flow_dv_validate_action_count(dev, true, 0, err);
17472 	case RTE_FLOW_ACTION_TYPE_CONNTRACK:
17473 		if (!priv->sh->ct_aso_en)
17474 			return rte_flow_error_set(err, ENOTSUP,
17475 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
17476 					"ASO CT is not supported");
17477 		return mlx5_validate_action_ct(dev, action->conf, err);
17478 	default:
17479 		return rte_flow_error_set(err, ENOTSUP,
17480 					  RTE_FLOW_ERROR_TYPE_ACTION,
17481 					  NULL,
17482 					  "action type not supported");
17483 	}
17484 }
17485 
17486 /*
17487  * Check if the RSS configurations for colors of a meter policy match
17488  * each other, except the queues.
17489  *
17490  * @param[in] r1
17491  *   Pointer to the first RSS flow action.
17492  * @param[in] r2
17493  *   Pointer to the second RSS flow action.
17494  *
17495  * @return
17496  *   0 on match, 1 on conflict.
17497  */
17498 static inline int
17499 flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1,
17500 			       const struct rte_flow_action_rss *r2)
17501 {
17502 	if (!r1 || !r2)
17503 		return 0;
17504 	if (r1->func != r2->func || r1->level != r2->level ||
17505 	    r1->types != r2->types || r1->key_len != r2->key_len ||
17506 	    memcmp(r1->key, r2->key, r1->key_len))
17507 		return 1;
17508 	return 0;
17509 }
17510 
17511 /**
17512  * Validate the meter hierarchy chain for meter policy.
17513  *
17514  * @param[in] dev
17515  *   Pointer to the Ethernet device structure.
17516  * @param[in] meter_id
17517  *   Meter id.
17518  * @param[in] action_flags
17519  *   Holds the actions detected until now.
17520  * @param[out] is_rss
17521  *   Is RSS or not.
17522  * @param[out] hierarchy_domain
17523  *   The domain bitmap for hierarchy policy.
17524  * @param[out] error
17525  *   Perform verbose error reporting if not NULL. Initialized in case of
17526  *   error only.
17527  *
17528  * @return
17529  *   0 on success, otherwise negative errno value with error set.
17530  */
17531 static int
17532 flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev,
17533 				  uint32_t meter_id,
17534 				  uint64_t action_flags,
17535 				  bool *is_rss,
17536 				  uint8_t *hierarchy_domain,
17537 				  struct rte_mtr_error *error)
17538 {
17539 	struct mlx5_priv *priv = dev->data->dev_private;
17540 	struct mlx5_flow_meter_info *fm;
17541 	struct mlx5_flow_meter_policy *policy;
17542 	uint8_t cnt = 1;
17543 
17544 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
17545 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
17546 		return -rte_mtr_error_set(error, EINVAL,
17547 					RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN,
17548 					NULL,
17549 					"Multiple fate actions not supported.");
17550 	*hierarchy_domain = 0;
17551 	while (true) {
17552 		fm = mlx5_flow_meter_find(priv, meter_id, NULL);
17553 		if (!fm)
17554 			return -rte_mtr_error_set(error, EINVAL,
17555 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
17556 					"Meter not found in meter hierarchy.");
17557 		if (fm->def_policy)
17558 			return -rte_mtr_error_set(error, EINVAL,
17559 					RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
17560 			"Non termination meter not supported in hierarchy.");
17561 		policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
17562 		MLX5_ASSERT(policy);
17563 		/**
17564 		 * Only inherit the supported domains of the first meter in
17565 		 * hierarchy.
17566 		 * One meter supports at least one domain.
17567 		 */
17568 		if (!*hierarchy_domain) {
17569 			if (policy->transfer)
17570 				*hierarchy_domain |=
17571 						MLX5_MTR_DOMAIN_TRANSFER_BIT;
17572 			if (policy->ingress)
17573 				*hierarchy_domain |=
17574 						MLX5_MTR_DOMAIN_INGRESS_BIT;
17575 			if (policy->egress)
17576 				*hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT;
17577 		}
17578 		if (!policy->is_hierarchy) {
17579 			*is_rss = policy->is_rss;
17580 			break;
17581 		}
17582 		meter_id = policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id;
17583 		if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM)
17584 			return -rte_mtr_error_set(error, EINVAL,
17585 					RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
17586 					"Exceed max hierarchy meter number.");
17587 	}
17588 	return 0;
17589 }
17590 
17591 /**
17592  * Validate meter policy actions.
17593  * Dispatcher for action type specific validation.
17594  *
17595  * @param[in] dev
17596  *   Pointer to the Ethernet device structure.
17597  * @param[in] action
17598  *   The meter policy action object to validate.
17599  * @param[in] attr
17600  *   Attributes of flow to determine steering domain.
17601  * @param[out] error
17602  *   Perform verbose error reporting if not NULL. Initialized in case of
17603  *   error only.
17604  *
17605  * @return
17606  *   0 on success, otherwise negative errno value.
17607  */
17608 static int
17609 flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
17610 			const struct rte_flow_action *actions[RTE_COLORS],
17611 			struct rte_flow_attr *attr,
17612 			bool *is_rss,
17613 			uint8_t *domain_bitmap,
17614 			uint8_t *policy_mode,
17615 			struct rte_mtr_error *error)
17616 {
17617 	struct mlx5_priv *priv = dev->data->dev_private;
17618 	struct mlx5_dev_config *dev_conf = &priv->config;
17619 	const struct rte_flow_action *act;
17620 	uint64_t action_flags[RTE_COLORS] = {0};
17621 	int actions_n;
17622 	int i, ret;
17623 	struct rte_flow_error flow_err;
17624 	uint8_t domain_color[RTE_COLORS] = {0};
17625 	uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
17626 	uint8_t hierarchy_domain = 0;
17627 	const struct rte_flow_action_meter *mtr;
17628 	bool def_green = false;
17629 	bool def_yellow = false;
17630 	const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL};
17631 
17632 	if (!priv->config.dv_esw_en)
17633 		def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
17634 	*domain_bitmap = def_domain;
17635 	/* Red color could only support DROP action. */
17636 	if (!actions[RTE_COLOR_RED] ||
17637 	    actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP)
17638 		return -rte_mtr_error_set(error, ENOTSUP,
17639 				RTE_MTR_ERROR_TYPE_METER_POLICY,
17640 				NULL, "Red color only supports drop action.");
17641 	/*
17642 	 * Check default policy actions:
17643 	 * Green / Yellow: no action, Red: drop action
17644 	 * Either G or Y will trigger default policy actions to be created.
17645 	 */
17646 	if (!actions[RTE_COLOR_GREEN] ||
17647 	    actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END)
17648 		def_green = true;
17649 	if (!actions[RTE_COLOR_YELLOW] ||
17650 	    actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END)
17651 		def_yellow = true;
17652 	if (def_green && def_yellow) {
17653 		*policy_mode = MLX5_MTR_POLICY_MODE_DEF;
17654 		return 0;
17655 	} else if (!def_green && def_yellow) {
17656 		*policy_mode = MLX5_MTR_POLICY_MODE_OG;
17657 	} else if (def_green && !def_yellow) {
17658 		*policy_mode = MLX5_MTR_POLICY_MODE_OY;
17659 	}
17660 	/* Set to empty string in case of NULL pointer access by user. */
17661 	flow_err.message = "";
17662 	for (i = 0; i < RTE_COLORS; i++) {
17663 		act = actions[i];
17664 		for (action_flags[i] = 0, actions_n = 0;
17665 		     act && act->type != RTE_FLOW_ACTION_TYPE_END;
17666 		     act++) {
17667 			if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
17668 				return -rte_mtr_error_set(error, ENOTSUP,
17669 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17670 					  NULL, "too many actions");
17671 			switch (act->type) {
17672 			case RTE_FLOW_ACTION_TYPE_PORT_ID:
17673 				if (!priv->config.dv_esw_en)
17674 					return -rte_mtr_error_set(error,
17675 					ENOTSUP,
17676 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17677 					NULL, "PORT action validate check"
17678 					" fail for ESW disable");
17679 				ret = flow_dv_validate_action_port_id(dev,
17680 						action_flags[i],
17681 						act, attr, &flow_err);
17682 				if (ret)
17683 					return -rte_mtr_error_set(error,
17684 					ENOTSUP,
17685 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17686 					NULL, flow_err.message ?
17687 					flow_err.message :
17688 					"PORT action validate check fail");
17689 				++actions_n;
17690 				action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID;
17691 				break;
17692 			case RTE_FLOW_ACTION_TYPE_MARK:
17693 				ret = flow_dv_validate_action_mark(dev, act,
17694 							   action_flags[i],
17695 							   attr, &flow_err);
17696 				if (ret < 0)
17697 					return -rte_mtr_error_set(error,
17698 					ENOTSUP,
17699 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17700 					NULL, flow_err.message ?
17701 					flow_err.message :
17702 					"Mark action validate check fail");
17703 				if (dev_conf->dv_xmeta_en !=
17704 					MLX5_XMETA_MODE_LEGACY)
17705 					return -rte_mtr_error_set(error,
17706 					ENOTSUP,
17707 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17708 					NULL, "Extend MARK action is "
17709 					"not supported. Please try use "
17710 					"default policy for meter.");
17711 				action_flags[i] |= MLX5_FLOW_ACTION_MARK;
17712 				++actions_n;
17713 				break;
17714 			case RTE_FLOW_ACTION_TYPE_SET_TAG:
17715 				ret = flow_dv_validate_action_set_tag(dev,
17716 							act, action_flags[i],
17717 							attr, &flow_err);
17718 				if (ret)
17719 					return -rte_mtr_error_set(error,
17720 					ENOTSUP,
17721 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17722 					NULL, flow_err.message ?
17723 					flow_err.message :
17724 					"Set tag action validate check fail");
17725 				action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG;
17726 				++actions_n;
17727 				break;
17728 			case RTE_FLOW_ACTION_TYPE_DROP:
17729 				ret = mlx5_flow_validate_action_drop
17730 					(action_flags[i], attr, &flow_err);
17731 				if (ret < 0)
17732 					return -rte_mtr_error_set(error,
17733 					ENOTSUP,
17734 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17735 					NULL, flow_err.message ?
17736 					flow_err.message :
17737 					"Drop action validate check fail");
17738 				action_flags[i] |= MLX5_FLOW_ACTION_DROP;
17739 				++actions_n;
17740 				break;
17741 			case RTE_FLOW_ACTION_TYPE_QUEUE:
17742 				/*
17743 				 * Check whether extensive
17744 				 * metadata feature is engaged.
17745 				 */
17746 				if (dev_conf->dv_flow_en &&
17747 				    (dev_conf->dv_xmeta_en !=
17748 				     MLX5_XMETA_MODE_LEGACY) &&
17749 				    mlx5_flow_ext_mreg_supported(dev))
17750 					return -rte_mtr_error_set(error,
17751 					  ENOTSUP,
17752 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17753 					  NULL, "Queue action with meta "
17754 					  "is not supported. Please try use "
17755 					  "default policy for meter.");
17756 				ret = mlx5_flow_validate_action_queue(act,
17757 							action_flags[i], dev,
17758 							attr, &flow_err);
17759 				if (ret < 0)
17760 					return -rte_mtr_error_set(error,
17761 					  ENOTSUP,
17762 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17763 					  NULL, flow_err.message ?
17764 					  flow_err.message :
17765 					  "Queue action validate check fail");
17766 				action_flags[i] |= MLX5_FLOW_ACTION_QUEUE;
17767 				++actions_n;
17768 				break;
17769 			case RTE_FLOW_ACTION_TYPE_RSS:
17770 				if (dev_conf->dv_flow_en &&
17771 				    (dev_conf->dv_xmeta_en !=
17772 				     MLX5_XMETA_MODE_LEGACY) &&
17773 				    mlx5_flow_ext_mreg_supported(dev))
17774 					return -rte_mtr_error_set(error,
17775 					  ENOTSUP,
17776 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17777 					  NULL, "RSS action with meta "
17778 					  "is not supported. Please try use "
17779 					  "default policy for meter.");
17780 				ret = mlx5_validate_action_rss(dev, act,
17781 							       &flow_err);
17782 				if (ret < 0)
17783 					return -rte_mtr_error_set(error,
17784 					  ENOTSUP,
17785 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17786 					  NULL, flow_err.message ?
17787 					  flow_err.message :
17788 					  "RSS action validate check fail");
17789 				action_flags[i] |= MLX5_FLOW_ACTION_RSS;
17790 				++actions_n;
17791 				/* Either G or Y will set the RSS. */
17792 				rss_color[i] = act->conf;
17793 				break;
17794 			case RTE_FLOW_ACTION_TYPE_JUMP:
17795 				ret = flow_dv_validate_action_jump(dev,
17796 					NULL, act, action_flags[i],
17797 					attr, true, &flow_err);
17798 				if (ret)
17799 					return -rte_mtr_error_set(error,
17800 					  ENOTSUP,
17801 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17802 					  NULL, flow_err.message ?
17803 					  flow_err.message :
17804 					  "Jump action validate check fail");
17805 				++actions_n;
17806 				action_flags[i] |= MLX5_FLOW_ACTION_JUMP;
17807 				break;
17808 			/*
17809 			 * Only the last meter in the hierarchy will support
17810 			 * the YELLOW color steering. Then in the meter policy
17811 			 * actions list, there should be no other meter inside.
17812 			 */
17813 			case RTE_FLOW_ACTION_TYPE_METER:
17814 				if (i != RTE_COLOR_GREEN)
17815 					return -rte_mtr_error_set(error,
17816 						ENOTSUP,
17817 						RTE_MTR_ERROR_TYPE_METER_POLICY,
17818 						NULL,
17819 						"Meter hierarchy only supports GREEN color.");
17820 				if (*policy_mode != MLX5_MTR_POLICY_MODE_OG)
17821 					return -rte_mtr_error_set(error,
17822 						ENOTSUP,
17823 						RTE_MTR_ERROR_TYPE_METER_POLICY,
17824 						NULL,
17825 						"No yellow policy should be provided in meter hierarchy.");
17826 				mtr = act->conf;
17827 				ret = flow_dv_validate_policy_mtr_hierarchy(dev,
17828 							mtr->mtr_id,
17829 							action_flags[i],
17830 							is_rss,
17831 							&hierarchy_domain,
17832 							error);
17833 				if (ret)
17834 					return ret;
17835 				++actions_n;
17836 				action_flags[i] |=
17837 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
17838 				break;
17839 			default:
17840 				return -rte_mtr_error_set(error, ENOTSUP,
17841 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17842 					NULL,
17843 					"Doesn't support optional action");
17844 			}
17845 		}
17846 		if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID)
17847 			domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
17848 		else if ((action_flags[i] &
17849 			  (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
17850 			 (action_flags[i] & MLX5_FLOW_ACTION_MARK))
17851 			/*
17852 			 * Only support MLX5_XMETA_MODE_LEGACY
17853 			 * so MARK action is only in ingress domain.
17854 			 */
17855 			domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
17856 		else
17857 			domain_color[i] = def_domain;
17858 		if (action_flags[i] &
17859 		    MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
17860 			domain_color[i] &= hierarchy_domain;
17861 		/*
17862 		 * Non-termination actions only support NIC Tx domain.
17863 		 * The adjustion should be skipped when there is no
17864 		 * action or only END is provided. The default domains
17865 		 * bit-mask is set to find the MIN intersection.
17866 		 * The action flags checking should also be skipped.
17867 		 */
17868 		if ((def_green && i == RTE_COLOR_GREEN) ||
17869 		    (def_yellow && i == RTE_COLOR_YELLOW))
17870 			continue;
17871 		/*
17872 		 * Validate the drop action mutual exclusion
17873 		 * with other actions. Drop action is mutually-exclusive
17874 		 * with any other action, except for Count action.
17875 		 */
17876 		if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) &&
17877 		    (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) {
17878 			return -rte_mtr_error_set(error, ENOTSUP,
17879 				RTE_MTR_ERROR_TYPE_METER_POLICY,
17880 				NULL, "Drop action is mutually-exclusive "
17881 				"with any other action");
17882 		}
17883 		/* Eswitch has few restrictions on using items and actions */
17884 		if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
17885 			if (!mlx5_flow_ext_mreg_supported(dev) &&
17886 			    action_flags[i] & MLX5_FLOW_ACTION_MARK)
17887 				return -rte_mtr_error_set(error, ENOTSUP,
17888 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17889 					NULL, "unsupported action MARK");
17890 			if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE)
17891 				return -rte_mtr_error_set(error, ENOTSUP,
17892 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17893 					NULL, "unsupported action QUEUE");
17894 			if (action_flags[i] & MLX5_FLOW_ACTION_RSS)
17895 				return -rte_mtr_error_set(error, ENOTSUP,
17896 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17897 					NULL, "unsupported action RSS");
17898 			if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
17899 				return -rte_mtr_error_set(error, ENOTSUP,
17900 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17901 					NULL, "no fate action is found");
17902 		} else {
17903 			if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) &&
17904 			    (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) {
17905 				if ((domain_color[i] &
17906 				     MLX5_MTR_DOMAIN_EGRESS_BIT))
17907 					domain_color[i] =
17908 						MLX5_MTR_DOMAIN_EGRESS_BIT;
17909 				else
17910 					return -rte_mtr_error_set(error,
17911 						ENOTSUP,
17912 						RTE_MTR_ERROR_TYPE_METER_POLICY,
17913 						NULL,
17914 						"no fate action is found");
17915 			}
17916 		}
17917 	}
17918 	/* If both colors have RSS, the attributes should be the same. */
17919 	if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN],
17920 					   rss_color[RTE_COLOR_YELLOW]))
17921 		return -rte_mtr_error_set(error, EINVAL,
17922 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17923 					  NULL, "policy RSS attr conflict");
17924 	if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW])
17925 		*is_rss = true;
17926 	/* "domain_color[C]" is non-zero for each color, default is ALL. */
17927 	if (!def_green && !def_yellow &&
17928 	    domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] &&
17929 	    !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) &&
17930 	    !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP))
17931 		return -rte_mtr_error_set(error, EINVAL,
17932 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17933 					  NULL, "policy domains conflict");
17934 	/*
17935 	 * At least one color policy is listed in the actions, the domains
17936 	 * to be supported should be the intersection.
17937 	 */
17938 	*domain_bitmap = domain_color[RTE_COLOR_GREEN] &
17939 			 domain_color[RTE_COLOR_YELLOW];
17940 	return 0;
17941 }
17942 
17943 static int
17944 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
17945 {
17946 	struct mlx5_priv *priv = dev->data->dev_private;
17947 	int ret = 0;
17948 
17949 	if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) {
17950 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain,
17951 						flags);
17952 		if (ret != 0)
17953 			return ret;
17954 	}
17955 	if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) {
17956 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags);
17957 		if (ret != 0)
17958 			return ret;
17959 	}
17960 	if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) {
17961 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags);
17962 		if (ret != 0)
17963 			return ret;
17964 	}
17965 	return 0;
17966 }
17967 
17968 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
17969 	.validate = flow_dv_validate,
17970 	.prepare = flow_dv_prepare,
17971 	.translate = flow_dv_translate,
17972 	.apply = flow_dv_apply,
17973 	.remove = flow_dv_remove,
17974 	.destroy = flow_dv_destroy,
17975 	.query = flow_dv_query,
17976 	.create_mtr_tbls = flow_dv_create_mtr_tbls,
17977 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
17978 	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
17979 	.create_meter = flow_dv_mtr_alloc,
17980 	.free_meter = flow_dv_aso_mtr_release_to_pool,
17981 	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
17982 	.create_mtr_acts = flow_dv_create_mtr_policy_acts,
17983 	.destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
17984 	.create_policy_rules = flow_dv_create_policy_rules,
17985 	.destroy_policy_rules = flow_dv_destroy_policy_rules,
17986 	.create_def_policy = flow_dv_create_def_policy,
17987 	.destroy_def_policy = flow_dv_destroy_def_policy,
17988 	.meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare,
17989 	.meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create,
17990 	.destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq,
17991 	.counter_alloc = flow_dv_counter_allocate,
17992 	.counter_free = flow_dv_counter_free,
17993 	.counter_query = flow_dv_counter_query,
17994 	.get_aged_flows = flow_dv_get_aged_flows,
17995 	.action_validate = flow_dv_action_validate,
17996 	.action_create = flow_dv_action_create,
17997 	.action_destroy = flow_dv_action_destroy,
17998 	.action_update = flow_dv_action_update,
17999 	.action_query = flow_dv_action_query,
18000 	.sync_domain = flow_dv_sync_domain,
18001 };
18002 
18003 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
18004 
18005