xref: /dpdk/drivers/net/mlx5/mlx5_flow_dv.c (revision b53d106d34b5c638f5a2cbdfee0da5bd42d4383f)
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_bus_pci.h>
19 #include <rte_ip.h>
20 #include <rte_gre.h>
21 #include <rte_vxlan.h>
22 #include <rte_gtp.h>
23 #include <rte_eal_paging.h>
24 #include <rte_mpls.h>
25 #include <rte_mtr.h>
26 #include <rte_mtr_driver.h>
27 #include <rte_tailq.h>
28 
29 #include <mlx5_glue.h>
30 #include <mlx5_devx_cmds.h>
31 #include <mlx5_prm.h>
32 #include <mlx5_malloc.h>
33 
34 #include "mlx5_defs.h"
35 #include "mlx5.h"
36 #include "mlx5_common_os.h"
37 #include "mlx5_flow.h"
38 #include "mlx5_flow_os.h"
39 #include "mlx5_rx.h"
40 #include "mlx5_tx.h"
41 #include "rte_pmd_mlx5.h"
42 
43 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
44 
45 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS
46 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0
47 #endif
48 
49 #ifndef HAVE_MLX5DV_DR_ESWITCH
50 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB
51 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0
52 #endif
53 #endif
54 
55 #ifndef HAVE_MLX5DV_DR
56 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1
57 #endif
58 
59 /* VLAN header definitions */
60 #define MLX5DV_FLOW_VLAN_PCP_SHIFT 13
61 #define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << MLX5DV_FLOW_VLAN_PCP_SHIFT)
62 #define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff
63 #define MLX5DV_FLOW_VLAN_PCP_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK)
64 #define MLX5DV_FLOW_VLAN_VID_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK)
65 
66 union flow_dv_attr {
67 	struct {
68 		uint32_t valid:1;
69 		uint32_t ipv4:1;
70 		uint32_t ipv6:1;
71 		uint32_t tcp:1;
72 		uint32_t udp:1;
73 		uint32_t reserved:27;
74 	};
75 	uint32_t attr;
76 };
77 
78 static int
79 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
80 			     struct mlx5_flow_tbl_resource *tbl);
81 
82 static int
83 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
84 				     uint32_t encap_decap_idx);
85 
86 static int
87 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
88 					uint32_t port_id);
89 static void
90 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss);
91 
92 static int
93 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
94 				  uint32_t rix_jump);
95 
96 static inline uint16_t
97 mlx5_translate_tunnel_etypes(uint64_t pattern_flags)
98 {
99 	if (pattern_flags & MLX5_FLOW_LAYER_INNER_L2)
100 		return RTE_ETHER_TYPE_TEB;
101 	else if (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4)
102 		return RTE_ETHER_TYPE_IPV4;
103 	else if (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)
104 		return RTE_ETHER_TYPE_IPV6;
105 	else if (pattern_flags & MLX5_FLOW_LAYER_MPLS)
106 		return RTE_ETHER_TYPE_MPLS;
107 	return 0;
108 }
109 
110 static int16_t
111 flow_dv_get_esw_manager_vport_id(struct rte_eth_dev *dev)
112 {
113 	struct mlx5_priv *priv = dev->data->dev_private;
114 
115 	if (priv->pci_dev == NULL)
116 		return 0;
117 	switch (priv->pci_dev->id.device_id) {
118 	case PCI_DEVICE_ID_MELLANOX_CONNECTX5BF:
119 	case PCI_DEVICE_ID_MELLANOX_CONNECTX6DXBF:
120 	case PCI_DEVICE_ID_MELLANOX_CONNECTX7BF:
121 		return (int16_t)0xfffe;
122 	default:
123 		return 0;
124 	}
125 }
126 
127 /**
128  * Initialize flow attributes structure according to flow items' types.
129  *
130  * flow_dv_validate() avoids multiple L3/L4 layers cases other than tunnel
131  * mode. For tunnel mode, the items to be modified are the outermost ones.
132  *
133  * @param[in] item
134  *   Pointer to item specification.
135  * @param[out] attr
136  *   Pointer to flow attributes structure.
137  * @param[in] dev_flow
138  *   Pointer to the sub flow.
139  * @param[in] tunnel_decap
140  *   Whether action is after tunnel decapsulation.
141  */
142 static void
143 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
144 		  struct mlx5_flow *dev_flow, bool tunnel_decap)
145 {
146 	uint64_t layers = dev_flow->handle->layers;
147 
148 	/*
149 	 * If layers is already initialized, it means this dev_flow is the
150 	 * suffix flow, the layers flags is set by the prefix flow. Need to
151 	 * use the layer flags from prefix flow as the suffix flow may not
152 	 * have the user defined items as the flow is split.
153 	 */
154 	if (layers) {
155 		if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
156 			attr->ipv4 = 1;
157 		else if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV6)
158 			attr->ipv6 = 1;
159 		if (layers & MLX5_FLOW_LAYER_OUTER_L4_TCP)
160 			attr->tcp = 1;
161 		else if (layers & MLX5_FLOW_LAYER_OUTER_L4_UDP)
162 			attr->udp = 1;
163 		attr->valid = 1;
164 		return;
165 	}
166 	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
167 		uint8_t next_protocol = 0xff;
168 		switch (item->type) {
169 		case RTE_FLOW_ITEM_TYPE_GRE:
170 		case RTE_FLOW_ITEM_TYPE_NVGRE:
171 		case RTE_FLOW_ITEM_TYPE_VXLAN:
172 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
173 		case RTE_FLOW_ITEM_TYPE_GENEVE:
174 		case RTE_FLOW_ITEM_TYPE_MPLS:
175 			if (tunnel_decap)
176 				attr->attr = 0;
177 			break;
178 		case RTE_FLOW_ITEM_TYPE_IPV4:
179 			if (!attr->ipv6)
180 				attr->ipv4 = 1;
181 			if (item->mask != NULL &&
182 			    ((const struct rte_flow_item_ipv4 *)
183 			    item->mask)->hdr.next_proto_id)
184 				next_protocol =
185 				    ((const struct rte_flow_item_ipv4 *)
186 				      (item->spec))->hdr.next_proto_id &
187 				    ((const struct rte_flow_item_ipv4 *)
188 				      (item->mask))->hdr.next_proto_id;
189 			if ((next_protocol == IPPROTO_IPIP ||
190 			    next_protocol == IPPROTO_IPV6) && tunnel_decap)
191 				attr->attr = 0;
192 			break;
193 		case RTE_FLOW_ITEM_TYPE_IPV6:
194 			if (!attr->ipv4)
195 				attr->ipv6 = 1;
196 			if (item->mask != NULL &&
197 			    ((const struct rte_flow_item_ipv6 *)
198 			    item->mask)->hdr.proto)
199 				next_protocol =
200 				    ((const struct rte_flow_item_ipv6 *)
201 				      (item->spec))->hdr.proto &
202 				    ((const struct rte_flow_item_ipv6 *)
203 				      (item->mask))->hdr.proto;
204 			if ((next_protocol == IPPROTO_IPIP ||
205 			    next_protocol == IPPROTO_IPV6) && tunnel_decap)
206 				attr->attr = 0;
207 			break;
208 		case RTE_FLOW_ITEM_TYPE_UDP:
209 			if (!attr->tcp)
210 				attr->udp = 1;
211 			break;
212 		case RTE_FLOW_ITEM_TYPE_TCP:
213 			if (!attr->udp)
214 				attr->tcp = 1;
215 			break;
216 		default:
217 			break;
218 		}
219 	}
220 	attr->valid = 1;
221 }
222 
223 /*
224  * Convert rte_mtr_color to mlx5 color.
225  *
226  * @param[in] rcol
227  *   rte_mtr_color.
228  *
229  * @return
230  *   mlx5 color.
231  */
232 static inline int
233 rte_col_2_mlx5_col(enum rte_color rcol)
234 {
235 	switch (rcol) {
236 	case RTE_COLOR_GREEN:
237 		return MLX5_FLOW_COLOR_GREEN;
238 	case RTE_COLOR_YELLOW:
239 		return MLX5_FLOW_COLOR_YELLOW;
240 	case RTE_COLOR_RED:
241 		return MLX5_FLOW_COLOR_RED;
242 	default:
243 		break;
244 	}
245 	return MLX5_FLOW_COLOR_UNDEFINED;
246 }
247 
248 struct field_modify_info {
249 	uint32_t size; /* Size of field in protocol header, in bytes. */
250 	uint32_t offset; /* Offset of field in protocol header, in bytes. */
251 	enum mlx5_modification_field id;
252 };
253 
254 struct field_modify_info modify_eth[] = {
255 	{4,  0, MLX5_MODI_OUT_DMAC_47_16},
256 	{2,  4, MLX5_MODI_OUT_DMAC_15_0},
257 	{4,  6, MLX5_MODI_OUT_SMAC_47_16},
258 	{2, 10, MLX5_MODI_OUT_SMAC_15_0},
259 	{0, 0, 0},
260 };
261 
262 struct field_modify_info modify_vlan_out_first_vid[] = {
263 	/* Size in bits !!! */
264 	{12, 0, MLX5_MODI_OUT_FIRST_VID},
265 	{0, 0, 0},
266 };
267 
268 struct field_modify_info modify_ipv4[] = {
269 	{1,  1, MLX5_MODI_OUT_IP_DSCP},
270 	{1,  8, MLX5_MODI_OUT_IPV4_TTL},
271 	{4, 12, MLX5_MODI_OUT_SIPV4},
272 	{4, 16, MLX5_MODI_OUT_DIPV4},
273 	{0, 0, 0},
274 };
275 
276 struct field_modify_info modify_ipv6[] = {
277 	{1,  0, MLX5_MODI_OUT_IP_DSCP},
278 	{1,  7, MLX5_MODI_OUT_IPV6_HOPLIMIT},
279 	{4,  8, MLX5_MODI_OUT_SIPV6_127_96},
280 	{4, 12, MLX5_MODI_OUT_SIPV6_95_64},
281 	{4, 16, MLX5_MODI_OUT_SIPV6_63_32},
282 	{4, 20, MLX5_MODI_OUT_SIPV6_31_0},
283 	{4, 24, MLX5_MODI_OUT_DIPV6_127_96},
284 	{4, 28, MLX5_MODI_OUT_DIPV6_95_64},
285 	{4, 32, MLX5_MODI_OUT_DIPV6_63_32},
286 	{4, 36, MLX5_MODI_OUT_DIPV6_31_0},
287 	{0, 0, 0},
288 };
289 
290 struct field_modify_info modify_udp[] = {
291 	{2, 0, MLX5_MODI_OUT_UDP_SPORT},
292 	{2, 2, MLX5_MODI_OUT_UDP_DPORT},
293 	{0, 0, 0},
294 };
295 
296 struct field_modify_info modify_tcp[] = {
297 	{2, 0, MLX5_MODI_OUT_TCP_SPORT},
298 	{2, 2, MLX5_MODI_OUT_TCP_DPORT},
299 	{4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM},
300 	{4, 8, MLX5_MODI_OUT_TCP_ACK_NUM},
301 	{0, 0, 0},
302 };
303 
304 static void
305 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused,
306 			  uint8_t next_protocol, uint64_t *item_flags,
307 			  int *tunnel)
308 {
309 	MLX5_ASSERT(item->type == RTE_FLOW_ITEM_TYPE_IPV4 ||
310 		    item->type == RTE_FLOW_ITEM_TYPE_IPV6);
311 	if (next_protocol == IPPROTO_IPIP) {
312 		*item_flags |= MLX5_FLOW_LAYER_IPIP;
313 		*tunnel = 1;
314 	}
315 	if (next_protocol == IPPROTO_IPV6) {
316 		*item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP;
317 		*tunnel = 1;
318 	}
319 }
320 
321 static inline struct mlx5_hlist *
322 flow_dv_hlist_prepare(struct mlx5_dev_ctx_shared *sh, struct mlx5_hlist **phl,
323 		     const char *name, uint32_t size, bool direct_key,
324 		     bool lcores_share, void *ctx,
325 		     mlx5_list_create_cb cb_create,
326 		     mlx5_list_match_cb cb_match,
327 		     mlx5_list_remove_cb cb_remove,
328 		     mlx5_list_clone_cb cb_clone,
329 		     mlx5_list_clone_free_cb cb_clone_free)
330 {
331 	struct mlx5_hlist *hl;
332 	struct mlx5_hlist *expected = NULL;
333 	char s[MLX5_NAME_SIZE];
334 
335 	hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST);
336 	if (likely(hl))
337 		return hl;
338 	snprintf(s, sizeof(s), "%s_%s", sh->ibdev_name, name);
339 	hl = mlx5_hlist_create(s, size, direct_key, lcores_share,
340 			ctx, cb_create, cb_match, cb_remove, cb_clone,
341 			cb_clone_free);
342 	if (!hl) {
343 		DRV_LOG(ERR, "%s hash creation failed", name);
344 		rte_errno = ENOMEM;
345 		return NULL;
346 	}
347 	if (!__atomic_compare_exchange_n(phl, &expected, hl, false,
348 					 __ATOMIC_SEQ_CST,
349 					 __ATOMIC_SEQ_CST)) {
350 		mlx5_hlist_destroy(hl);
351 		hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST);
352 	}
353 	return hl;
354 }
355 
356 /* Update VLAN's VID/PCP based on input rte_flow_action.
357  *
358  * @param[in] action
359  *   Pointer to struct rte_flow_action.
360  * @param[out] vlan
361  *   Pointer to struct rte_vlan_hdr.
362  */
363 static void
364 mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action,
365 			 struct rte_vlan_hdr *vlan)
366 {
367 	uint16_t vlan_tci;
368 	if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) {
369 		vlan_tci =
370 		    ((const struct rte_flow_action_of_set_vlan_pcp *)
371 					       action->conf)->vlan_pcp;
372 		vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT;
373 		vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
374 		vlan->vlan_tci |= vlan_tci;
375 	} else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) {
376 		vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
377 		vlan->vlan_tci |= rte_be_to_cpu_16
378 		    (((const struct rte_flow_action_of_set_vlan_vid *)
379 					     action->conf)->vlan_vid);
380 	}
381 }
382 
383 /**
384  * Fetch 1, 2, 3 or 4 byte field from the byte array
385  * and return as unsigned integer in host-endian format.
386  *
387  * @param[in] data
388  *   Pointer to data array.
389  * @param[in] size
390  *   Size of field to extract.
391  *
392  * @return
393  *   converted field in host endian format.
394  */
395 static inline uint32_t
396 flow_dv_fetch_field(const uint8_t *data, uint32_t size)
397 {
398 	uint32_t ret;
399 
400 	switch (size) {
401 	case 1:
402 		ret = *data;
403 		break;
404 	case 2:
405 		ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);
406 		break;
407 	case 3:
408 		ret = rte_be_to_cpu_16(*(const unaligned_uint16_t *)data);
409 		ret = (ret << 8) | *(data + sizeof(uint16_t));
410 		break;
411 	case 4:
412 		ret = rte_be_to_cpu_32(*(const unaligned_uint32_t *)data);
413 		break;
414 	default:
415 		MLX5_ASSERT(false);
416 		ret = 0;
417 		break;
418 	}
419 	return ret;
420 }
421 
422 /**
423  * Convert modify-header action to DV specification.
424  *
425  * Data length of each action is determined by provided field description
426  * and the item mask. Data bit offset and width of each action is determined
427  * by provided item mask.
428  *
429  * @param[in] item
430  *   Pointer to item specification.
431  * @param[in] field
432  *   Pointer to field modification information.
433  *     For MLX5_MODIFICATION_TYPE_SET specifies destination field.
434  *     For MLX5_MODIFICATION_TYPE_ADD specifies destination field.
435  *     For MLX5_MODIFICATION_TYPE_COPY specifies source field.
436  * @param[in] dcopy
437  *   Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type.
438  *   Negative offset value sets the same offset as source offset.
439  *   size field is ignored, value is taken from source field.
440  * @param[in,out] resource
441  *   Pointer to the modify-header resource.
442  * @param[in] type
443  *   Type of modification.
444  * @param[out] error
445  *   Pointer to the error structure.
446  *
447  * @return
448  *   0 on success, a negative errno value otherwise and rte_errno is set.
449  */
450 static int
451 flow_dv_convert_modify_action(struct rte_flow_item *item,
452 			      struct field_modify_info *field,
453 			      struct field_modify_info *dcopy,
454 			      struct mlx5_flow_dv_modify_hdr_resource *resource,
455 			      uint32_t type, struct rte_flow_error *error)
456 {
457 	uint32_t i = resource->actions_num;
458 	struct mlx5_modification_cmd *actions = resource->actions;
459 	uint32_t carry_b = 0;
460 
461 	/*
462 	 * The item and mask are provided in big-endian format.
463 	 * The fields should be presented as in big-endian format either.
464 	 * Mask must be always present, it defines the actual field width.
465 	 */
466 	MLX5_ASSERT(item->mask);
467 	MLX5_ASSERT(field->size);
468 	do {
469 		uint32_t size_b;
470 		uint32_t off_b;
471 		uint32_t mask;
472 		uint32_t data;
473 		bool next_field = true;
474 		bool next_dcopy = true;
475 
476 		if (i >= MLX5_MAX_MODIFY_NUM)
477 			return rte_flow_error_set(error, EINVAL,
478 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
479 				 "too many items to modify");
480 		/* Fetch variable byte size mask from the array. */
481 		mask = flow_dv_fetch_field((const uint8_t *)item->mask +
482 					   field->offset, field->size);
483 		if (!mask) {
484 			++field;
485 			continue;
486 		}
487 		/* Deduce actual data width in bits from mask value. */
488 		off_b = rte_bsf32(mask) + carry_b;
489 		size_b = sizeof(uint32_t) * CHAR_BIT -
490 			 off_b - __builtin_clz(mask);
491 		MLX5_ASSERT(size_b);
492 		actions[i] = (struct mlx5_modification_cmd) {
493 			.action_type = type,
494 			.field = field->id,
495 			.offset = off_b,
496 			.length = (size_b == sizeof(uint32_t) * CHAR_BIT) ?
497 				0 : size_b,
498 		};
499 		if (type == MLX5_MODIFICATION_TYPE_COPY) {
500 			MLX5_ASSERT(dcopy);
501 			actions[i].dst_field = dcopy->id;
502 			actions[i].dst_offset =
503 				(int)dcopy->offset < 0 ? off_b : dcopy->offset;
504 			/* Convert entire record to big-endian format. */
505 			actions[i].data1 = rte_cpu_to_be_32(actions[i].data1);
506 			/*
507 			 * Destination field overflow. Copy leftovers of
508 			 * a source field to the next destination field.
509 			 */
510 			carry_b = 0;
511 			if ((size_b > dcopy->size * CHAR_BIT - dcopy->offset) &&
512 			    dcopy->size != 0) {
513 				actions[i].length =
514 					dcopy->size * CHAR_BIT - dcopy->offset;
515 				carry_b = actions[i].length;
516 				next_field = false;
517 			}
518 			/*
519 			 * Not enough bits in a source filed to fill a
520 			 * destination field. Switch to the next source.
521 			 */
522 			if ((size_b < dcopy->size * CHAR_BIT - dcopy->offset) &&
523 			    (size_b == field->size * CHAR_BIT - off_b)) {
524 				actions[i].length =
525 					field->size * CHAR_BIT - off_b;
526 				dcopy->offset += actions[i].length;
527 				next_dcopy = false;
528 			}
529 			if (next_dcopy)
530 				++dcopy;
531 		} else {
532 			MLX5_ASSERT(item->spec);
533 			data = flow_dv_fetch_field((const uint8_t *)item->spec +
534 						   field->offset, field->size);
535 			/* Shift out the trailing masked bits from data. */
536 			data = (data & mask) >> off_b;
537 			actions[i].data1 = rte_cpu_to_be_32(data);
538 		}
539 		/* Convert entire record to expected big-endian format. */
540 		actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
541 		if (next_field)
542 			++field;
543 		++i;
544 	} while (field->size);
545 	if (resource->actions_num == i)
546 		return rte_flow_error_set(error, EINVAL,
547 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
548 					  "invalid modification flow item");
549 	resource->actions_num = i;
550 	return 0;
551 }
552 
553 /**
554  * Convert modify-header set IPv4 address action to DV specification.
555  *
556  * @param[in,out] resource
557  *   Pointer to the modify-header resource.
558  * @param[in] action
559  *   Pointer to action specification.
560  * @param[out] error
561  *   Pointer to the error structure.
562  *
563  * @return
564  *   0 on success, a negative errno value otherwise and rte_errno is set.
565  */
566 static int
567 flow_dv_convert_action_modify_ipv4
568 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
569 			 const struct rte_flow_action *action,
570 			 struct rte_flow_error *error)
571 {
572 	const struct rte_flow_action_set_ipv4 *conf =
573 		(const struct rte_flow_action_set_ipv4 *)(action->conf);
574 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
575 	struct rte_flow_item_ipv4 ipv4;
576 	struct rte_flow_item_ipv4 ipv4_mask;
577 
578 	memset(&ipv4, 0, sizeof(ipv4));
579 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
580 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) {
581 		ipv4.hdr.src_addr = conf->ipv4_addr;
582 		ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr;
583 	} else {
584 		ipv4.hdr.dst_addr = conf->ipv4_addr;
585 		ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr;
586 	}
587 	item.spec = &ipv4;
588 	item.mask = &ipv4_mask;
589 	return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
590 					     MLX5_MODIFICATION_TYPE_SET, error);
591 }
592 
593 /**
594  * Convert modify-header set IPv6 address action to DV specification.
595  *
596  * @param[in,out] resource
597  *   Pointer to the modify-header resource.
598  * @param[in] action
599  *   Pointer to action specification.
600  * @param[out] error
601  *   Pointer to the error structure.
602  *
603  * @return
604  *   0 on success, a negative errno value otherwise and rte_errno is set.
605  */
606 static int
607 flow_dv_convert_action_modify_ipv6
608 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
609 			 const struct rte_flow_action *action,
610 			 struct rte_flow_error *error)
611 {
612 	const struct rte_flow_action_set_ipv6 *conf =
613 		(const struct rte_flow_action_set_ipv6 *)(action->conf);
614 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
615 	struct rte_flow_item_ipv6 ipv6;
616 	struct rte_flow_item_ipv6 ipv6_mask;
617 
618 	memset(&ipv6, 0, sizeof(ipv6));
619 	memset(&ipv6_mask, 0, sizeof(ipv6_mask));
620 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) {
621 		memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr,
622 		       sizeof(ipv6.hdr.src_addr));
623 		memcpy(&ipv6_mask.hdr.src_addr,
624 		       &rte_flow_item_ipv6_mask.hdr.src_addr,
625 		       sizeof(ipv6.hdr.src_addr));
626 	} else {
627 		memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr,
628 		       sizeof(ipv6.hdr.dst_addr));
629 		memcpy(&ipv6_mask.hdr.dst_addr,
630 		       &rte_flow_item_ipv6_mask.hdr.dst_addr,
631 		       sizeof(ipv6.hdr.dst_addr));
632 	}
633 	item.spec = &ipv6;
634 	item.mask = &ipv6_mask;
635 	return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
636 					     MLX5_MODIFICATION_TYPE_SET, error);
637 }
638 
639 /**
640  * Convert modify-header set MAC address action to DV specification.
641  *
642  * @param[in,out] resource
643  *   Pointer to the modify-header resource.
644  * @param[in] action
645  *   Pointer to action specification.
646  * @param[out] error
647  *   Pointer to the error structure.
648  *
649  * @return
650  *   0 on success, a negative errno value otherwise and rte_errno is set.
651  */
652 static int
653 flow_dv_convert_action_modify_mac
654 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
655 			 const struct rte_flow_action *action,
656 			 struct rte_flow_error *error)
657 {
658 	const struct rte_flow_action_set_mac *conf =
659 		(const struct rte_flow_action_set_mac *)(action->conf);
660 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH };
661 	struct rte_flow_item_eth eth;
662 	struct rte_flow_item_eth eth_mask;
663 
664 	memset(&eth, 0, sizeof(eth));
665 	memset(&eth_mask, 0, sizeof(eth_mask));
666 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) {
667 		memcpy(&eth.src.addr_bytes, &conf->mac_addr,
668 		       sizeof(eth.src.addr_bytes));
669 		memcpy(&eth_mask.src.addr_bytes,
670 		       &rte_flow_item_eth_mask.src.addr_bytes,
671 		       sizeof(eth_mask.src.addr_bytes));
672 	} else {
673 		memcpy(&eth.dst.addr_bytes, &conf->mac_addr,
674 		       sizeof(eth.dst.addr_bytes));
675 		memcpy(&eth_mask.dst.addr_bytes,
676 		       &rte_flow_item_eth_mask.dst.addr_bytes,
677 		       sizeof(eth_mask.dst.addr_bytes));
678 	}
679 	item.spec = &eth;
680 	item.mask = &eth_mask;
681 	return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource,
682 					     MLX5_MODIFICATION_TYPE_SET, error);
683 }
684 
685 /**
686  * Convert modify-header set VLAN VID action to DV specification.
687  *
688  * @param[in,out] resource
689  *   Pointer to the modify-header resource.
690  * @param[in] action
691  *   Pointer to action specification.
692  * @param[out] error
693  *   Pointer to the error structure.
694  *
695  * @return
696  *   0 on success, a negative errno value otherwise and rte_errno is set.
697  */
698 static int
699 flow_dv_convert_action_modify_vlan_vid
700 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
701 			 const struct rte_flow_action *action,
702 			 struct rte_flow_error *error)
703 {
704 	const struct rte_flow_action_of_set_vlan_vid *conf =
705 		(const struct rte_flow_action_of_set_vlan_vid *)(action->conf);
706 	int i = resource->actions_num;
707 	struct mlx5_modification_cmd *actions = resource->actions;
708 	struct field_modify_info *field = modify_vlan_out_first_vid;
709 
710 	if (i >= MLX5_MAX_MODIFY_NUM)
711 		return rte_flow_error_set(error, EINVAL,
712 			 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
713 			 "too many items to modify");
714 	actions[i] = (struct mlx5_modification_cmd) {
715 		.action_type = MLX5_MODIFICATION_TYPE_SET,
716 		.field = field->id,
717 		.length = field->size,
718 		.offset = field->offset,
719 	};
720 	actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
721 	actions[i].data1 = conf->vlan_vid;
722 	actions[i].data1 = actions[i].data1 << 16;
723 	resource->actions_num = ++i;
724 	return 0;
725 }
726 
727 /**
728  * Convert modify-header set TP action to DV specification.
729  *
730  * @param[in,out] resource
731  *   Pointer to the modify-header resource.
732  * @param[in] action
733  *   Pointer to action specification.
734  * @param[in] items
735  *   Pointer to rte_flow_item objects list.
736  * @param[in] attr
737  *   Pointer to flow attributes structure.
738  * @param[in] dev_flow
739  *   Pointer to the sub flow.
740  * @param[in] tunnel_decap
741  *   Whether action is after tunnel decapsulation.
742  * @param[out] error
743  *   Pointer to the error structure.
744  *
745  * @return
746  *   0 on success, a negative errno value otherwise and rte_errno is set.
747  */
748 static int
749 flow_dv_convert_action_modify_tp
750 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
751 			 const struct rte_flow_action *action,
752 			 const struct rte_flow_item *items,
753 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
754 			 bool tunnel_decap, struct rte_flow_error *error)
755 {
756 	const struct rte_flow_action_set_tp *conf =
757 		(const struct rte_flow_action_set_tp *)(action->conf);
758 	struct rte_flow_item item;
759 	struct rte_flow_item_udp udp;
760 	struct rte_flow_item_udp udp_mask;
761 	struct rte_flow_item_tcp tcp;
762 	struct rte_flow_item_tcp tcp_mask;
763 	struct field_modify_info *field;
764 
765 	if (!attr->valid)
766 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
767 	if (attr->udp) {
768 		memset(&udp, 0, sizeof(udp));
769 		memset(&udp_mask, 0, sizeof(udp_mask));
770 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
771 			udp.hdr.src_port = conf->port;
772 			udp_mask.hdr.src_port =
773 					rte_flow_item_udp_mask.hdr.src_port;
774 		} else {
775 			udp.hdr.dst_port = conf->port;
776 			udp_mask.hdr.dst_port =
777 					rte_flow_item_udp_mask.hdr.dst_port;
778 		}
779 		item.type = RTE_FLOW_ITEM_TYPE_UDP;
780 		item.spec = &udp;
781 		item.mask = &udp_mask;
782 		field = modify_udp;
783 	} else {
784 		MLX5_ASSERT(attr->tcp);
785 		memset(&tcp, 0, sizeof(tcp));
786 		memset(&tcp_mask, 0, sizeof(tcp_mask));
787 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
788 			tcp.hdr.src_port = conf->port;
789 			tcp_mask.hdr.src_port =
790 					rte_flow_item_tcp_mask.hdr.src_port;
791 		} else {
792 			tcp.hdr.dst_port = conf->port;
793 			tcp_mask.hdr.dst_port =
794 					rte_flow_item_tcp_mask.hdr.dst_port;
795 		}
796 		item.type = RTE_FLOW_ITEM_TYPE_TCP;
797 		item.spec = &tcp;
798 		item.mask = &tcp_mask;
799 		field = modify_tcp;
800 	}
801 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
802 					     MLX5_MODIFICATION_TYPE_SET, error);
803 }
804 
805 /**
806  * Convert modify-header set TTL action to DV specification.
807  *
808  * @param[in,out] resource
809  *   Pointer to the modify-header resource.
810  * @param[in] action
811  *   Pointer to action specification.
812  * @param[in] items
813  *   Pointer to rte_flow_item objects list.
814  * @param[in] attr
815  *   Pointer to flow attributes structure.
816  * @param[in] dev_flow
817  *   Pointer to the sub flow.
818  * @param[in] tunnel_decap
819  *   Whether action is after tunnel decapsulation.
820  * @param[out] error
821  *   Pointer to the error structure.
822  *
823  * @return
824  *   0 on success, a negative errno value otherwise and rte_errno is set.
825  */
826 static int
827 flow_dv_convert_action_modify_ttl
828 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
829 			 const struct rte_flow_action *action,
830 			 const struct rte_flow_item *items,
831 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
832 			 bool tunnel_decap, struct rte_flow_error *error)
833 {
834 	const struct rte_flow_action_set_ttl *conf =
835 		(const struct rte_flow_action_set_ttl *)(action->conf);
836 	struct rte_flow_item item;
837 	struct rte_flow_item_ipv4 ipv4;
838 	struct rte_flow_item_ipv4 ipv4_mask;
839 	struct rte_flow_item_ipv6 ipv6;
840 	struct rte_flow_item_ipv6 ipv6_mask;
841 	struct field_modify_info *field;
842 
843 	if (!attr->valid)
844 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
845 	if (attr->ipv4) {
846 		memset(&ipv4, 0, sizeof(ipv4));
847 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
848 		ipv4.hdr.time_to_live = conf->ttl_value;
849 		ipv4_mask.hdr.time_to_live = 0xFF;
850 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
851 		item.spec = &ipv4;
852 		item.mask = &ipv4_mask;
853 		field = modify_ipv4;
854 	} else {
855 		MLX5_ASSERT(attr->ipv6);
856 		memset(&ipv6, 0, sizeof(ipv6));
857 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
858 		ipv6.hdr.hop_limits = conf->ttl_value;
859 		ipv6_mask.hdr.hop_limits = 0xFF;
860 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
861 		item.spec = &ipv6;
862 		item.mask = &ipv6_mask;
863 		field = modify_ipv6;
864 	}
865 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
866 					     MLX5_MODIFICATION_TYPE_SET, error);
867 }
868 
869 /**
870  * Convert modify-header decrement TTL action to DV specification.
871  *
872  * @param[in,out] resource
873  *   Pointer to the modify-header resource.
874  * @param[in] action
875  *   Pointer to action specification.
876  * @param[in] items
877  *   Pointer to rte_flow_item objects list.
878  * @param[in] attr
879  *   Pointer to flow attributes structure.
880  * @param[in] dev_flow
881  *   Pointer to the sub flow.
882  * @param[in] tunnel_decap
883  *   Whether action is after tunnel decapsulation.
884  * @param[out] error
885  *   Pointer to the error structure.
886  *
887  * @return
888  *   0 on success, a negative errno value otherwise and rte_errno is set.
889  */
890 static int
891 flow_dv_convert_action_modify_dec_ttl
892 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
893 			 const struct rte_flow_item *items,
894 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
895 			 bool tunnel_decap, struct rte_flow_error *error)
896 {
897 	struct rte_flow_item item;
898 	struct rte_flow_item_ipv4 ipv4;
899 	struct rte_flow_item_ipv4 ipv4_mask;
900 	struct rte_flow_item_ipv6 ipv6;
901 	struct rte_flow_item_ipv6 ipv6_mask;
902 	struct field_modify_info *field;
903 
904 	if (!attr->valid)
905 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
906 	if (attr->ipv4) {
907 		memset(&ipv4, 0, sizeof(ipv4));
908 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
909 		ipv4.hdr.time_to_live = 0xFF;
910 		ipv4_mask.hdr.time_to_live = 0xFF;
911 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
912 		item.spec = &ipv4;
913 		item.mask = &ipv4_mask;
914 		field = modify_ipv4;
915 	} else {
916 		MLX5_ASSERT(attr->ipv6);
917 		memset(&ipv6, 0, sizeof(ipv6));
918 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
919 		ipv6.hdr.hop_limits = 0xFF;
920 		ipv6_mask.hdr.hop_limits = 0xFF;
921 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
922 		item.spec = &ipv6;
923 		item.mask = &ipv6_mask;
924 		field = modify_ipv6;
925 	}
926 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
927 					     MLX5_MODIFICATION_TYPE_ADD, error);
928 }
929 
930 /**
931  * Convert modify-header increment/decrement TCP Sequence number
932  * to DV specification.
933  *
934  * @param[in,out] resource
935  *   Pointer to the modify-header resource.
936  * @param[in] action
937  *   Pointer to action specification.
938  * @param[out] error
939  *   Pointer to the error structure.
940  *
941  * @return
942  *   0 on success, a negative errno value otherwise and rte_errno is set.
943  */
944 static int
945 flow_dv_convert_action_modify_tcp_seq
946 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
947 			 const struct rte_flow_action *action,
948 			 struct rte_flow_error *error)
949 {
950 	const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
951 	uint64_t value = rte_be_to_cpu_32(*conf);
952 	struct rte_flow_item item;
953 	struct rte_flow_item_tcp tcp;
954 	struct rte_flow_item_tcp tcp_mask;
955 
956 	memset(&tcp, 0, sizeof(tcp));
957 	memset(&tcp_mask, 0, sizeof(tcp_mask));
958 	if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ)
959 		/*
960 		 * The HW has no decrement operation, only increment operation.
961 		 * To simulate decrement X from Y using increment operation
962 		 * we need to add UINT32_MAX X times to Y.
963 		 * Each adding of UINT32_MAX decrements Y by 1.
964 		 */
965 		value *= UINT32_MAX;
966 	tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value);
967 	tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX);
968 	item.type = RTE_FLOW_ITEM_TYPE_TCP;
969 	item.spec = &tcp;
970 	item.mask = &tcp_mask;
971 	return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
972 					     MLX5_MODIFICATION_TYPE_ADD, error);
973 }
974 
975 /**
976  * Convert modify-header increment/decrement TCP Acknowledgment number
977  * to DV specification.
978  *
979  * @param[in,out] resource
980  *   Pointer to the modify-header resource.
981  * @param[in] action
982  *   Pointer to action specification.
983  * @param[out] error
984  *   Pointer to the error structure.
985  *
986  * @return
987  *   0 on success, a negative errno value otherwise and rte_errno is set.
988  */
989 static int
990 flow_dv_convert_action_modify_tcp_ack
991 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
992 			 const struct rte_flow_action *action,
993 			 struct rte_flow_error *error)
994 {
995 	const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
996 	uint64_t value = rte_be_to_cpu_32(*conf);
997 	struct rte_flow_item item;
998 	struct rte_flow_item_tcp tcp;
999 	struct rte_flow_item_tcp tcp_mask;
1000 
1001 	memset(&tcp, 0, sizeof(tcp));
1002 	memset(&tcp_mask, 0, sizeof(tcp_mask));
1003 	if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK)
1004 		/*
1005 		 * The HW has no decrement operation, only increment operation.
1006 		 * To simulate decrement X from Y using increment operation
1007 		 * we need to add UINT32_MAX X times to Y.
1008 		 * Each adding of UINT32_MAX decrements Y by 1.
1009 		 */
1010 		value *= UINT32_MAX;
1011 	tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value);
1012 	tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX);
1013 	item.type = RTE_FLOW_ITEM_TYPE_TCP;
1014 	item.spec = &tcp;
1015 	item.mask = &tcp_mask;
1016 	return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
1017 					     MLX5_MODIFICATION_TYPE_ADD, error);
1018 }
1019 
1020 static enum mlx5_modification_field reg_to_field[] = {
1021 	[REG_NON] = MLX5_MODI_OUT_NONE,
1022 	[REG_A] = MLX5_MODI_META_DATA_REG_A,
1023 	[REG_B] = MLX5_MODI_META_DATA_REG_B,
1024 	[REG_C_0] = MLX5_MODI_META_REG_C_0,
1025 	[REG_C_1] = MLX5_MODI_META_REG_C_1,
1026 	[REG_C_2] = MLX5_MODI_META_REG_C_2,
1027 	[REG_C_3] = MLX5_MODI_META_REG_C_3,
1028 	[REG_C_4] = MLX5_MODI_META_REG_C_4,
1029 	[REG_C_5] = MLX5_MODI_META_REG_C_5,
1030 	[REG_C_6] = MLX5_MODI_META_REG_C_6,
1031 	[REG_C_7] = MLX5_MODI_META_REG_C_7,
1032 };
1033 
1034 /**
1035  * Convert register set to DV specification.
1036  *
1037  * @param[in,out] resource
1038  *   Pointer to the modify-header resource.
1039  * @param[in] action
1040  *   Pointer to action specification.
1041  * @param[out] error
1042  *   Pointer to the error structure.
1043  *
1044  * @return
1045  *   0 on success, a negative errno value otherwise and rte_errno is set.
1046  */
1047 static int
1048 flow_dv_convert_action_set_reg
1049 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1050 			 const struct rte_flow_action *action,
1051 			 struct rte_flow_error *error)
1052 {
1053 	const struct mlx5_rte_flow_action_set_tag *conf = action->conf;
1054 	struct mlx5_modification_cmd *actions = resource->actions;
1055 	uint32_t i = resource->actions_num;
1056 
1057 	if (i >= MLX5_MAX_MODIFY_NUM)
1058 		return rte_flow_error_set(error, EINVAL,
1059 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1060 					  "too many items to modify");
1061 	MLX5_ASSERT(conf->id != REG_NON);
1062 	MLX5_ASSERT(conf->id < (enum modify_reg)RTE_DIM(reg_to_field));
1063 	actions[i] = (struct mlx5_modification_cmd) {
1064 		.action_type = MLX5_MODIFICATION_TYPE_SET,
1065 		.field = reg_to_field[conf->id],
1066 		.offset = conf->offset,
1067 		.length = conf->length,
1068 	};
1069 	actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
1070 	actions[i].data1 = rte_cpu_to_be_32(conf->data);
1071 	++i;
1072 	resource->actions_num = i;
1073 	return 0;
1074 }
1075 
1076 /**
1077  * Convert SET_TAG action to DV specification.
1078  *
1079  * @param[in] dev
1080  *   Pointer to the rte_eth_dev structure.
1081  * @param[in,out] resource
1082  *   Pointer to the modify-header resource.
1083  * @param[in] conf
1084  *   Pointer to action specification.
1085  * @param[out] error
1086  *   Pointer to the error structure.
1087  *
1088  * @return
1089  *   0 on success, a negative errno value otherwise and rte_errno is set.
1090  */
1091 static int
1092 flow_dv_convert_action_set_tag
1093 			(struct rte_eth_dev *dev,
1094 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1095 			 const struct rte_flow_action_set_tag *conf,
1096 			 struct rte_flow_error *error)
1097 {
1098 	rte_be32_t data = rte_cpu_to_be_32(conf->data);
1099 	rte_be32_t mask = rte_cpu_to_be_32(conf->mask);
1100 	struct rte_flow_item item = {
1101 		.spec = &data,
1102 		.mask = &mask,
1103 	};
1104 	struct field_modify_info reg_c_x[] = {
1105 		[1] = {0, 0, 0},
1106 	};
1107 	enum mlx5_modification_field reg_type;
1108 	int ret;
1109 
1110 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
1111 	if (ret < 0)
1112 		return ret;
1113 	MLX5_ASSERT(ret != REG_NON);
1114 	MLX5_ASSERT((unsigned int)ret < RTE_DIM(reg_to_field));
1115 	reg_type = reg_to_field[ret];
1116 	MLX5_ASSERT(reg_type > 0);
1117 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_type};
1118 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1119 					     MLX5_MODIFICATION_TYPE_SET, error);
1120 }
1121 
1122 /**
1123  * Convert internal COPY_REG action to DV specification.
1124  *
1125  * @param[in] dev
1126  *   Pointer to the rte_eth_dev structure.
1127  * @param[in,out] res
1128  *   Pointer to the modify-header resource.
1129  * @param[in] action
1130  *   Pointer to action specification.
1131  * @param[out] error
1132  *   Pointer to the error structure.
1133  *
1134  * @return
1135  *   0 on success, a negative errno value otherwise and rte_errno is set.
1136  */
1137 static int
1138 flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev,
1139 				 struct mlx5_flow_dv_modify_hdr_resource *res,
1140 				 const struct rte_flow_action *action,
1141 				 struct rte_flow_error *error)
1142 {
1143 	const struct mlx5_flow_action_copy_mreg *conf = action->conf;
1144 	rte_be32_t mask = RTE_BE32(UINT32_MAX);
1145 	struct rte_flow_item item = {
1146 		.spec = NULL,
1147 		.mask = &mask,
1148 	};
1149 	struct field_modify_info reg_src[] = {
1150 		{4, 0, reg_to_field[conf->src]},
1151 		{0, 0, 0},
1152 	};
1153 	struct field_modify_info reg_dst = {
1154 		.offset = 0,
1155 		.id = reg_to_field[conf->dst],
1156 	};
1157 	/* Adjust reg_c[0] usage according to reported mask. */
1158 	if (conf->dst == REG_C_0 || conf->src == REG_C_0) {
1159 		struct mlx5_priv *priv = dev->data->dev_private;
1160 		uint32_t reg_c0 = priv->sh->dv_regc0_mask;
1161 
1162 		MLX5_ASSERT(reg_c0);
1163 		MLX5_ASSERT(priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY);
1164 		if (conf->dst == REG_C_0) {
1165 			/* Copy to reg_c[0], within mask only. */
1166 			reg_dst.offset = rte_bsf32(reg_c0);
1167 			mask = rte_cpu_to_be_32(reg_c0 >> reg_dst.offset);
1168 		} else {
1169 			reg_dst.offset = 0;
1170 			mask = rte_cpu_to_be_32(reg_c0);
1171 		}
1172 	}
1173 	return flow_dv_convert_modify_action(&item,
1174 					     reg_src, &reg_dst, res,
1175 					     MLX5_MODIFICATION_TYPE_COPY,
1176 					     error);
1177 }
1178 
1179 /**
1180  * Convert MARK action to DV specification. This routine is used
1181  * in extensive metadata only and requires metadata register to be
1182  * handled. In legacy mode hardware tag resource is engaged.
1183  *
1184  * @param[in] dev
1185  *   Pointer to the rte_eth_dev structure.
1186  * @param[in] conf
1187  *   Pointer to MARK action specification.
1188  * @param[in,out] resource
1189  *   Pointer to the modify-header resource.
1190  * @param[out] error
1191  *   Pointer to the error structure.
1192  *
1193  * @return
1194  *   0 on success, a negative errno value otherwise and rte_errno is set.
1195  */
1196 static int
1197 flow_dv_convert_action_mark(struct rte_eth_dev *dev,
1198 			    const struct rte_flow_action_mark *conf,
1199 			    struct mlx5_flow_dv_modify_hdr_resource *resource,
1200 			    struct rte_flow_error *error)
1201 {
1202 	struct mlx5_priv *priv = dev->data->dev_private;
1203 	rte_be32_t mask = rte_cpu_to_be_32(MLX5_FLOW_MARK_MASK &
1204 					   priv->sh->dv_mark_mask);
1205 	rte_be32_t data = rte_cpu_to_be_32(conf->id) & mask;
1206 	struct rte_flow_item item = {
1207 		.spec = &data,
1208 		.mask = &mask,
1209 	};
1210 	struct field_modify_info reg_c_x[] = {
1211 		[1] = {0, 0, 0},
1212 	};
1213 	int reg;
1214 
1215 	if (!mask)
1216 		return rte_flow_error_set(error, EINVAL,
1217 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1218 					  NULL, "zero mark action mask");
1219 	reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
1220 	if (reg < 0)
1221 		return reg;
1222 	MLX5_ASSERT(reg > 0);
1223 	if (reg == REG_C_0) {
1224 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1225 		uint32_t shl_c0 = rte_bsf32(msk_c0);
1226 
1227 		data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0);
1228 		mask = rte_cpu_to_be_32(mask) & msk_c0;
1229 		mask = rte_cpu_to_be_32(mask << shl_c0);
1230 	}
1231 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1232 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1233 					     MLX5_MODIFICATION_TYPE_SET, error);
1234 }
1235 
1236 /**
1237  * Get metadata register index for specified steering domain.
1238  *
1239  * @param[in] dev
1240  *   Pointer to the rte_eth_dev structure.
1241  * @param[in] attr
1242  *   Attributes of flow to determine steering domain.
1243  * @param[out] error
1244  *   Pointer to the error structure.
1245  *
1246  * @return
1247  *   positive index on success, a negative errno value otherwise
1248  *   and rte_errno is set.
1249  */
1250 static enum modify_reg
1251 flow_dv_get_metadata_reg(struct rte_eth_dev *dev,
1252 			 const struct rte_flow_attr *attr,
1253 			 struct rte_flow_error *error)
1254 {
1255 	int reg =
1256 		mlx5_flow_get_reg_id(dev, attr->transfer ?
1257 					  MLX5_METADATA_FDB :
1258 					    attr->egress ?
1259 					    MLX5_METADATA_TX :
1260 					    MLX5_METADATA_RX, 0, error);
1261 	if (reg < 0)
1262 		return rte_flow_error_set(error,
1263 					  ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
1264 					  NULL, "unavailable "
1265 					  "metadata register");
1266 	return reg;
1267 }
1268 
1269 /**
1270  * Convert SET_META action to DV specification.
1271  *
1272  * @param[in] dev
1273  *   Pointer to the rte_eth_dev structure.
1274  * @param[in,out] resource
1275  *   Pointer to the modify-header resource.
1276  * @param[in] attr
1277  *   Attributes of flow that includes this item.
1278  * @param[in] conf
1279  *   Pointer to action specification.
1280  * @param[out] error
1281  *   Pointer to the error structure.
1282  *
1283  * @return
1284  *   0 on success, a negative errno value otherwise and rte_errno is set.
1285  */
1286 static int
1287 flow_dv_convert_action_set_meta
1288 			(struct rte_eth_dev *dev,
1289 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1290 			 const struct rte_flow_attr *attr,
1291 			 const struct rte_flow_action_set_meta *conf,
1292 			 struct rte_flow_error *error)
1293 {
1294 	uint32_t mask = rte_cpu_to_be_32(conf->mask);
1295 	uint32_t data = rte_cpu_to_be_32(conf->data) & mask;
1296 	struct rte_flow_item item = {
1297 		.spec = &data,
1298 		.mask = &mask,
1299 	};
1300 	struct field_modify_info reg_c_x[] = {
1301 		[1] = {0, 0, 0},
1302 	};
1303 	int reg = flow_dv_get_metadata_reg(dev, attr, error);
1304 
1305 	if (reg < 0)
1306 		return reg;
1307 	MLX5_ASSERT(reg != REG_NON);
1308 	if (reg == REG_C_0) {
1309 		struct mlx5_priv *priv = dev->data->dev_private;
1310 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1311 		uint32_t shl_c0 = rte_bsf32(msk_c0);
1312 
1313 		data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0);
1314 		mask = rte_cpu_to_be_32(mask) & msk_c0;
1315 		mask = rte_cpu_to_be_32(mask << shl_c0);
1316 	}
1317 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1318 	/* The routine expects parameters in memory as big-endian ones. */
1319 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1320 					     MLX5_MODIFICATION_TYPE_SET, error);
1321 }
1322 
1323 /**
1324  * Convert modify-header set IPv4 DSCP action to DV specification.
1325  *
1326  * @param[in,out] resource
1327  *   Pointer to the modify-header resource.
1328  * @param[in] action
1329  *   Pointer to action specification.
1330  * @param[out] error
1331  *   Pointer to the error structure.
1332  *
1333  * @return
1334  *   0 on success, a negative errno value otherwise and rte_errno is set.
1335  */
1336 static int
1337 flow_dv_convert_action_modify_ipv4_dscp
1338 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1339 			 const struct rte_flow_action *action,
1340 			 struct rte_flow_error *error)
1341 {
1342 	const struct rte_flow_action_set_dscp *conf =
1343 		(const struct rte_flow_action_set_dscp *)(action->conf);
1344 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
1345 	struct rte_flow_item_ipv4 ipv4;
1346 	struct rte_flow_item_ipv4 ipv4_mask;
1347 
1348 	memset(&ipv4, 0, sizeof(ipv4));
1349 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
1350 	ipv4.hdr.type_of_service = conf->dscp;
1351 	ipv4_mask.hdr.type_of_service = RTE_IPV4_HDR_DSCP_MASK >> 2;
1352 	item.spec = &ipv4;
1353 	item.mask = &ipv4_mask;
1354 	return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
1355 					     MLX5_MODIFICATION_TYPE_SET, error);
1356 }
1357 
1358 /**
1359  * Convert modify-header set IPv6 DSCP action to DV specification.
1360  *
1361  * @param[in,out] resource
1362  *   Pointer to the modify-header resource.
1363  * @param[in] action
1364  *   Pointer to action specification.
1365  * @param[out] error
1366  *   Pointer to the error structure.
1367  *
1368  * @return
1369  *   0 on success, a negative errno value otherwise and rte_errno is set.
1370  */
1371 static int
1372 flow_dv_convert_action_modify_ipv6_dscp
1373 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1374 			 const struct rte_flow_action *action,
1375 			 struct rte_flow_error *error)
1376 {
1377 	const struct rte_flow_action_set_dscp *conf =
1378 		(const struct rte_flow_action_set_dscp *)(action->conf);
1379 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
1380 	struct rte_flow_item_ipv6 ipv6;
1381 	struct rte_flow_item_ipv6 ipv6_mask;
1382 
1383 	memset(&ipv6, 0, sizeof(ipv6));
1384 	memset(&ipv6_mask, 0, sizeof(ipv6_mask));
1385 	/*
1386 	 * Even though the DSCP bits offset of IPv6 is not byte aligned,
1387 	 * rdma-core only accept the DSCP bits byte aligned start from
1388 	 * bit 0 to 5 as to be compatible with IPv4. No need to shift the
1389 	 * bits in IPv6 case as rdma-core requires byte aligned value.
1390 	 */
1391 	ipv6.hdr.vtc_flow = conf->dscp;
1392 	ipv6_mask.hdr.vtc_flow = RTE_IPV6_HDR_DSCP_MASK >> 22;
1393 	item.spec = &ipv6;
1394 	item.mask = &ipv6_mask;
1395 	return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
1396 					     MLX5_MODIFICATION_TYPE_SET, error);
1397 }
1398 
1399 static int
1400 mlx5_flow_item_field_width(struct rte_eth_dev *dev,
1401 			   enum rte_flow_field_id field, int inherit,
1402 			   const struct rte_flow_attr *attr,
1403 			   struct rte_flow_error *error)
1404 {
1405 	struct mlx5_priv *priv = dev->data->dev_private;
1406 
1407 	switch (field) {
1408 	case RTE_FLOW_FIELD_START:
1409 		return 32;
1410 	case RTE_FLOW_FIELD_MAC_DST:
1411 	case RTE_FLOW_FIELD_MAC_SRC:
1412 		return 48;
1413 	case RTE_FLOW_FIELD_VLAN_TYPE:
1414 		return 16;
1415 	case RTE_FLOW_FIELD_VLAN_ID:
1416 		return 12;
1417 	case RTE_FLOW_FIELD_MAC_TYPE:
1418 		return 16;
1419 	case RTE_FLOW_FIELD_IPV4_DSCP:
1420 		return 6;
1421 	case RTE_FLOW_FIELD_IPV4_TTL:
1422 		return 8;
1423 	case RTE_FLOW_FIELD_IPV4_SRC:
1424 	case RTE_FLOW_FIELD_IPV4_DST:
1425 		return 32;
1426 	case RTE_FLOW_FIELD_IPV6_DSCP:
1427 		return 6;
1428 	case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
1429 		return 8;
1430 	case RTE_FLOW_FIELD_IPV6_SRC:
1431 	case RTE_FLOW_FIELD_IPV6_DST:
1432 		return 128;
1433 	case RTE_FLOW_FIELD_TCP_PORT_SRC:
1434 	case RTE_FLOW_FIELD_TCP_PORT_DST:
1435 		return 16;
1436 	case RTE_FLOW_FIELD_TCP_SEQ_NUM:
1437 	case RTE_FLOW_FIELD_TCP_ACK_NUM:
1438 		return 32;
1439 	case RTE_FLOW_FIELD_TCP_FLAGS:
1440 		return 9;
1441 	case RTE_FLOW_FIELD_UDP_PORT_SRC:
1442 	case RTE_FLOW_FIELD_UDP_PORT_DST:
1443 		return 16;
1444 	case RTE_FLOW_FIELD_VXLAN_VNI:
1445 	case RTE_FLOW_FIELD_GENEVE_VNI:
1446 		return 24;
1447 	case RTE_FLOW_FIELD_GTP_TEID:
1448 	case RTE_FLOW_FIELD_TAG:
1449 		return 32;
1450 	case RTE_FLOW_FIELD_MARK:
1451 		return __builtin_popcount(priv->sh->dv_mark_mask);
1452 	case RTE_FLOW_FIELD_META:
1453 		return (flow_dv_get_metadata_reg(dev, attr, error) == REG_C_0) ?
1454 			__builtin_popcount(priv->sh->dv_meta_mask) : 32;
1455 	case RTE_FLOW_FIELD_POINTER:
1456 	case RTE_FLOW_FIELD_VALUE:
1457 		return inherit < 0 ? 0 : inherit;
1458 	default:
1459 		MLX5_ASSERT(false);
1460 	}
1461 	return 0;
1462 }
1463 
1464 static void
1465 mlx5_flow_field_id_to_modify_info
1466 		(const struct rte_flow_action_modify_data *data,
1467 		 struct field_modify_info *info, uint32_t *mask,
1468 		 uint32_t width, uint32_t *shift, struct rte_eth_dev *dev,
1469 		 const struct rte_flow_attr *attr, struct rte_flow_error *error)
1470 {
1471 	struct mlx5_priv *priv = dev->data->dev_private;
1472 	uint32_t idx = 0;
1473 	uint32_t off = 0;
1474 
1475 	switch (data->field) {
1476 	case RTE_FLOW_FIELD_START:
1477 		/* not supported yet */
1478 		MLX5_ASSERT(false);
1479 		break;
1480 	case RTE_FLOW_FIELD_MAC_DST:
1481 		off = data->offset > 16 ? data->offset - 16 : 0;
1482 		if (mask) {
1483 			if (data->offset < 16) {
1484 				info[idx] = (struct field_modify_info){2, 4,
1485 						MLX5_MODI_OUT_DMAC_15_0};
1486 				if (width < 16) {
1487 					mask[1] = rte_cpu_to_be_16(0xffff >>
1488 								 (16 - width));
1489 					width = 0;
1490 				} else {
1491 					mask[1] = RTE_BE16(0xffff);
1492 					width -= 16;
1493 				}
1494 				if (!width)
1495 					break;
1496 				++idx;
1497 			}
1498 			info[idx] = (struct field_modify_info){4, 0,
1499 						MLX5_MODI_OUT_DMAC_47_16};
1500 			mask[0] = rte_cpu_to_be_32((0xffffffff >>
1501 						    (32 - width)) << off);
1502 		} else {
1503 			if (data->offset < 16)
1504 				info[idx++] = (struct field_modify_info){2, 0,
1505 						MLX5_MODI_OUT_DMAC_15_0};
1506 			info[idx] = (struct field_modify_info){4, 0,
1507 						MLX5_MODI_OUT_DMAC_47_16};
1508 		}
1509 		break;
1510 	case RTE_FLOW_FIELD_MAC_SRC:
1511 		off = data->offset > 16 ? data->offset - 16 : 0;
1512 		if (mask) {
1513 			if (data->offset < 16) {
1514 				info[idx] = (struct field_modify_info){2, 4,
1515 						MLX5_MODI_OUT_SMAC_15_0};
1516 				if (width < 16) {
1517 					mask[1] = rte_cpu_to_be_16(0xffff >>
1518 								 (16 - width));
1519 					width = 0;
1520 				} else {
1521 					mask[1] = RTE_BE16(0xffff);
1522 					width -= 16;
1523 				}
1524 				if (!width)
1525 					break;
1526 				++idx;
1527 			}
1528 			info[idx] = (struct field_modify_info){4, 0,
1529 						MLX5_MODI_OUT_SMAC_47_16};
1530 			mask[0] = rte_cpu_to_be_32((0xffffffff >>
1531 						    (32 - width)) << off);
1532 		} else {
1533 			if (data->offset < 16)
1534 				info[idx++] = (struct field_modify_info){2, 0,
1535 						MLX5_MODI_OUT_SMAC_15_0};
1536 			info[idx] = (struct field_modify_info){4, 0,
1537 						MLX5_MODI_OUT_SMAC_47_16};
1538 		}
1539 		break;
1540 	case RTE_FLOW_FIELD_VLAN_TYPE:
1541 		/* not supported yet */
1542 		break;
1543 	case RTE_FLOW_FIELD_VLAN_ID:
1544 		info[idx] = (struct field_modify_info){2, 0,
1545 					MLX5_MODI_OUT_FIRST_VID};
1546 		if (mask)
1547 			mask[idx] = rte_cpu_to_be_16(0x0fff >> (12 - width));
1548 		break;
1549 	case RTE_FLOW_FIELD_MAC_TYPE:
1550 		info[idx] = (struct field_modify_info){2, 0,
1551 					MLX5_MODI_OUT_ETHERTYPE};
1552 		if (mask)
1553 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1554 		break;
1555 	case RTE_FLOW_FIELD_IPV4_DSCP:
1556 		info[idx] = (struct field_modify_info){1, 0,
1557 					MLX5_MODI_OUT_IP_DSCP};
1558 		if (mask)
1559 			mask[idx] = 0x3f >> (6 - width);
1560 		break;
1561 	case RTE_FLOW_FIELD_IPV4_TTL:
1562 		info[idx] = (struct field_modify_info){1, 0,
1563 					MLX5_MODI_OUT_IPV4_TTL};
1564 		if (mask)
1565 			mask[idx] = 0xff >> (8 - width);
1566 		break;
1567 	case RTE_FLOW_FIELD_IPV4_SRC:
1568 		info[idx] = (struct field_modify_info){4, 0,
1569 					MLX5_MODI_OUT_SIPV4};
1570 		if (mask)
1571 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1572 						     (32 - width));
1573 		break;
1574 	case RTE_FLOW_FIELD_IPV4_DST:
1575 		info[idx] = (struct field_modify_info){4, 0,
1576 					MLX5_MODI_OUT_DIPV4};
1577 		if (mask)
1578 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1579 						     (32 - width));
1580 		break;
1581 	case RTE_FLOW_FIELD_IPV6_DSCP:
1582 		info[idx] = (struct field_modify_info){1, 0,
1583 					MLX5_MODI_OUT_IP_DSCP};
1584 		if (mask)
1585 			mask[idx] = 0x3f >> (6 - width);
1586 		break;
1587 	case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
1588 		info[idx] = (struct field_modify_info){1, 0,
1589 					MLX5_MODI_OUT_IPV6_HOPLIMIT};
1590 		if (mask)
1591 			mask[idx] = 0xff >> (8 - width);
1592 		break;
1593 	case RTE_FLOW_FIELD_IPV6_SRC:
1594 		if (mask) {
1595 			if (data->offset < 32) {
1596 				info[idx] = (struct field_modify_info){4, 12,
1597 						MLX5_MODI_OUT_SIPV6_31_0};
1598 				if (width < 32) {
1599 					mask[3] =
1600 						rte_cpu_to_be_32(0xffffffff >>
1601 								 (32 - width));
1602 					width = 0;
1603 				} else {
1604 					mask[3] = RTE_BE32(0xffffffff);
1605 					width -= 32;
1606 				}
1607 				if (!width)
1608 					break;
1609 				++idx;
1610 			}
1611 			if (data->offset < 64) {
1612 				info[idx] = (struct field_modify_info){4, 8,
1613 						MLX5_MODI_OUT_SIPV6_63_32};
1614 				if (width < 32) {
1615 					mask[2] =
1616 						rte_cpu_to_be_32(0xffffffff >>
1617 								 (32 - width));
1618 					width = 0;
1619 				} else {
1620 					mask[2] = RTE_BE32(0xffffffff);
1621 					width -= 32;
1622 				}
1623 				if (!width)
1624 					break;
1625 				++idx;
1626 			}
1627 			if (data->offset < 96) {
1628 				info[idx] = (struct field_modify_info){4, 4,
1629 						MLX5_MODI_OUT_SIPV6_95_64};
1630 				if (width < 32) {
1631 					mask[1] =
1632 						rte_cpu_to_be_32(0xffffffff >>
1633 								 (32 - width));
1634 					width = 0;
1635 				} else {
1636 					mask[1] = RTE_BE32(0xffffffff);
1637 					width -= 32;
1638 				}
1639 				if (!width)
1640 					break;
1641 				++idx;
1642 			}
1643 			info[idx] = (struct field_modify_info){4, 0,
1644 						MLX5_MODI_OUT_SIPV6_127_96};
1645 			mask[0] = rte_cpu_to_be_32(0xffffffff >> (32 - width));
1646 		} else {
1647 			if (data->offset < 32)
1648 				info[idx++] = (struct field_modify_info){4, 0,
1649 						MLX5_MODI_OUT_SIPV6_31_0};
1650 			if (data->offset < 64)
1651 				info[idx++] = (struct field_modify_info){4, 0,
1652 						MLX5_MODI_OUT_SIPV6_63_32};
1653 			if (data->offset < 96)
1654 				info[idx++] = (struct field_modify_info){4, 0,
1655 						MLX5_MODI_OUT_SIPV6_95_64};
1656 			if (data->offset < 128)
1657 				info[idx++] = (struct field_modify_info){4, 0,
1658 						MLX5_MODI_OUT_SIPV6_127_96};
1659 		}
1660 		break;
1661 	case RTE_FLOW_FIELD_IPV6_DST:
1662 		if (mask) {
1663 			if (data->offset < 32) {
1664 				info[idx] = (struct field_modify_info){4, 12,
1665 						MLX5_MODI_OUT_DIPV6_31_0};
1666 				if (width < 32) {
1667 					mask[3] =
1668 						rte_cpu_to_be_32(0xffffffff >>
1669 								 (32 - width));
1670 					width = 0;
1671 				} else {
1672 					mask[3] = RTE_BE32(0xffffffff);
1673 					width -= 32;
1674 				}
1675 				if (!width)
1676 					break;
1677 				++idx;
1678 			}
1679 			if (data->offset < 64) {
1680 				info[idx] = (struct field_modify_info){4, 8,
1681 						MLX5_MODI_OUT_DIPV6_63_32};
1682 				if (width < 32) {
1683 					mask[2] =
1684 						rte_cpu_to_be_32(0xffffffff >>
1685 								 (32 - width));
1686 					width = 0;
1687 				} else {
1688 					mask[2] = RTE_BE32(0xffffffff);
1689 					width -= 32;
1690 				}
1691 				if (!width)
1692 					break;
1693 				++idx;
1694 			}
1695 			if (data->offset < 96) {
1696 				info[idx] = (struct field_modify_info){4, 4,
1697 						MLX5_MODI_OUT_DIPV6_95_64};
1698 				if (width < 32) {
1699 					mask[1] =
1700 						rte_cpu_to_be_32(0xffffffff >>
1701 								 (32 - width));
1702 					width = 0;
1703 				} else {
1704 					mask[1] = RTE_BE32(0xffffffff);
1705 					width -= 32;
1706 				}
1707 				if (!width)
1708 					break;
1709 				++idx;
1710 			}
1711 			info[idx] = (struct field_modify_info){4, 0,
1712 						MLX5_MODI_OUT_DIPV6_127_96};
1713 			mask[0] = rte_cpu_to_be_32(0xffffffff >> (32 - width));
1714 		} else {
1715 			if (data->offset < 32)
1716 				info[idx++] = (struct field_modify_info){4, 0,
1717 						MLX5_MODI_OUT_DIPV6_31_0};
1718 			if (data->offset < 64)
1719 				info[idx++] = (struct field_modify_info){4, 0,
1720 						MLX5_MODI_OUT_DIPV6_63_32};
1721 			if (data->offset < 96)
1722 				info[idx++] = (struct field_modify_info){4, 0,
1723 						MLX5_MODI_OUT_DIPV6_95_64};
1724 			if (data->offset < 128)
1725 				info[idx++] = (struct field_modify_info){4, 0,
1726 						MLX5_MODI_OUT_DIPV6_127_96};
1727 		}
1728 		break;
1729 	case RTE_FLOW_FIELD_TCP_PORT_SRC:
1730 		info[idx] = (struct field_modify_info){2, 0,
1731 					MLX5_MODI_OUT_TCP_SPORT};
1732 		if (mask)
1733 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1734 		break;
1735 	case RTE_FLOW_FIELD_TCP_PORT_DST:
1736 		info[idx] = (struct field_modify_info){2, 0,
1737 					MLX5_MODI_OUT_TCP_DPORT};
1738 		if (mask)
1739 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1740 		break;
1741 	case RTE_FLOW_FIELD_TCP_SEQ_NUM:
1742 		info[idx] = (struct field_modify_info){4, 0,
1743 					MLX5_MODI_OUT_TCP_SEQ_NUM};
1744 		if (mask)
1745 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1746 						     (32 - width));
1747 		break;
1748 	case RTE_FLOW_FIELD_TCP_ACK_NUM:
1749 		info[idx] = (struct field_modify_info){4, 0,
1750 					MLX5_MODI_OUT_TCP_ACK_NUM};
1751 		if (mask)
1752 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1753 						     (32 - width));
1754 		break;
1755 	case RTE_FLOW_FIELD_TCP_FLAGS:
1756 		info[idx] = (struct field_modify_info){2, 0,
1757 					MLX5_MODI_OUT_TCP_FLAGS};
1758 		if (mask)
1759 			mask[idx] = rte_cpu_to_be_16(0x1ff >> (9 - width));
1760 		break;
1761 	case RTE_FLOW_FIELD_UDP_PORT_SRC:
1762 		info[idx] = (struct field_modify_info){2, 0,
1763 					MLX5_MODI_OUT_UDP_SPORT};
1764 		if (mask)
1765 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1766 		break;
1767 	case RTE_FLOW_FIELD_UDP_PORT_DST:
1768 		info[idx] = (struct field_modify_info){2, 0,
1769 					MLX5_MODI_OUT_UDP_DPORT};
1770 		if (mask)
1771 			mask[idx] = rte_cpu_to_be_16(0xffff >> (16 - width));
1772 		break;
1773 	case RTE_FLOW_FIELD_VXLAN_VNI:
1774 		/* not supported yet */
1775 		break;
1776 	case RTE_FLOW_FIELD_GENEVE_VNI:
1777 		/* not supported yet*/
1778 		break;
1779 	case RTE_FLOW_FIELD_GTP_TEID:
1780 		info[idx] = (struct field_modify_info){4, 0,
1781 					MLX5_MODI_GTP_TEID};
1782 		if (mask)
1783 			mask[idx] = rte_cpu_to_be_32(0xffffffff >>
1784 						     (32 - width));
1785 		break;
1786 	case RTE_FLOW_FIELD_TAG:
1787 		{
1788 			int reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG,
1789 						   data->level, error);
1790 			if (reg < 0)
1791 				return;
1792 			MLX5_ASSERT(reg != REG_NON);
1793 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1794 			info[idx] = (struct field_modify_info){4, 0,
1795 						reg_to_field[reg]};
1796 			if (mask)
1797 				mask[idx] =
1798 					rte_cpu_to_be_32(0xffffffff >>
1799 							 (32 - width));
1800 		}
1801 		break;
1802 	case RTE_FLOW_FIELD_MARK:
1803 		{
1804 			uint32_t mark_mask = priv->sh->dv_mark_mask;
1805 			uint32_t mark_count = __builtin_popcount(mark_mask);
1806 			int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK,
1807 						       0, error);
1808 			if (reg < 0)
1809 				return;
1810 			MLX5_ASSERT(reg != REG_NON);
1811 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1812 			info[idx] = (struct field_modify_info){4, 0,
1813 						reg_to_field[reg]};
1814 			if (mask)
1815 				mask[idx] = rte_cpu_to_be_32((mark_mask >>
1816 					 (mark_count - width)) & mark_mask);
1817 		}
1818 		break;
1819 	case RTE_FLOW_FIELD_META:
1820 		{
1821 			uint32_t meta_mask = priv->sh->dv_meta_mask;
1822 			uint32_t meta_count = __builtin_popcount(meta_mask);
1823 			uint32_t msk_c0 =
1824 				rte_cpu_to_be_32(priv->sh->dv_regc0_mask);
1825 			uint32_t shl_c0 = rte_bsf32(msk_c0);
1826 			int reg = flow_dv_get_metadata_reg(dev, attr, error);
1827 			if (reg < 0)
1828 				return;
1829 			MLX5_ASSERT(reg != REG_NON);
1830 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1831 			if (reg == REG_C_0)
1832 				*shift = shl_c0;
1833 			info[idx] = (struct field_modify_info){4, 0,
1834 						reg_to_field[reg]};
1835 			if (mask)
1836 				mask[idx] = rte_cpu_to_be_32((meta_mask >>
1837 					(meta_count - width)) & meta_mask);
1838 		}
1839 		break;
1840 	case RTE_FLOW_FIELD_POINTER:
1841 	case RTE_FLOW_FIELD_VALUE:
1842 	default:
1843 		MLX5_ASSERT(false);
1844 		break;
1845 	}
1846 }
1847 
1848 /**
1849  * Convert modify_field action to DV specification.
1850  *
1851  * @param[in] dev
1852  *   Pointer to the rte_eth_dev structure.
1853  * @param[in,out] resource
1854  *   Pointer to the modify-header resource.
1855  * @param[in] action
1856  *   Pointer to action specification.
1857  * @param[in] attr
1858  *   Attributes of flow that includes this item.
1859  * @param[out] error
1860  *   Pointer to the error structure.
1861  *
1862  * @return
1863  *   0 on success, a negative errno value otherwise and rte_errno is set.
1864  */
1865 static int
1866 flow_dv_convert_action_modify_field
1867 			(struct rte_eth_dev *dev,
1868 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1869 			 const struct rte_flow_action *action,
1870 			 const struct rte_flow_attr *attr,
1871 			 struct rte_flow_error *error)
1872 {
1873 	const struct rte_flow_action_modify_field *conf =
1874 		(const struct rte_flow_action_modify_field *)(action->conf);
1875 	struct rte_flow_item item = {
1876 		.spec = NULL,
1877 		.mask = NULL
1878 	};
1879 	struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = {
1880 								{0, 0, 0} };
1881 	struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = {
1882 								{0, 0, 0} };
1883 	uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0};
1884 	uint32_t type;
1885 	uint32_t shift = 0;
1886 
1887 	if (conf->src.field == RTE_FLOW_FIELD_POINTER ||
1888 	    conf->src.field == RTE_FLOW_FIELD_VALUE) {
1889 		type = MLX5_MODIFICATION_TYPE_SET;
1890 		/** For SET fill the destination field (field) first. */
1891 		mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask,
1892 						  conf->width, &shift, dev,
1893 						  attr, error);
1894 		item.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ?
1895 					(void *)(uintptr_t)conf->src.pvalue :
1896 					(void *)(uintptr_t)&conf->src.value;
1897 	} else {
1898 		type = MLX5_MODIFICATION_TYPE_COPY;
1899 		/** For COPY fill the destination field (dcopy) without mask. */
1900 		mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL,
1901 						  conf->width, &shift, dev,
1902 						  attr, error);
1903 		/** Then construct the source field (field) with mask. */
1904 		mlx5_flow_field_id_to_modify_info(&conf->src, field, mask,
1905 						  conf->width, &shift,
1906 						  dev, attr, error);
1907 	}
1908 	item.mask = &mask;
1909 	return flow_dv_convert_modify_action(&item,
1910 			field, dcopy, resource, type, error);
1911 }
1912 
1913 /**
1914  * Validate MARK item.
1915  *
1916  * @param[in] dev
1917  *   Pointer to the rte_eth_dev structure.
1918  * @param[in] item
1919  *   Item specification.
1920  * @param[in] attr
1921  *   Attributes of flow that includes this item.
1922  * @param[out] error
1923  *   Pointer to error structure.
1924  *
1925  * @return
1926  *   0 on success, a negative errno value otherwise and rte_errno is set.
1927  */
1928 static int
1929 flow_dv_validate_item_mark(struct rte_eth_dev *dev,
1930 			   const struct rte_flow_item *item,
1931 			   const struct rte_flow_attr *attr __rte_unused,
1932 			   struct rte_flow_error *error)
1933 {
1934 	struct mlx5_priv *priv = dev->data->dev_private;
1935 	struct mlx5_dev_config *config = &priv->config;
1936 	const struct rte_flow_item_mark *spec = item->spec;
1937 	const struct rte_flow_item_mark *mask = item->mask;
1938 	const struct rte_flow_item_mark nic_mask = {
1939 		.id = priv->sh->dv_mark_mask,
1940 	};
1941 	int ret;
1942 
1943 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
1944 		return rte_flow_error_set(error, ENOTSUP,
1945 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1946 					  "extended metadata feature"
1947 					  " isn't enabled");
1948 	if (!mlx5_flow_ext_mreg_supported(dev))
1949 		return rte_flow_error_set(error, ENOTSUP,
1950 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1951 					  "extended metadata register"
1952 					  " isn't supported");
1953 	if (!nic_mask.id)
1954 		return rte_flow_error_set(error, ENOTSUP,
1955 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1956 					  "extended metadata register"
1957 					  " isn't available");
1958 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
1959 	if (ret < 0)
1960 		return ret;
1961 	if (!spec)
1962 		return rte_flow_error_set(error, EINVAL,
1963 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
1964 					  item->spec,
1965 					  "data cannot be empty");
1966 	if (spec->id >= (MLX5_FLOW_MARK_MAX & nic_mask.id))
1967 		return rte_flow_error_set(error, EINVAL,
1968 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1969 					  &spec->id,
1970 					  "mark id exceeds the limit");
1971 	if (!mask)
1972 		mask = &nic_mask;
1973 	if (!mask->id)
1974 		return rte_flow_error_set(error, EINVAL,
1975 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
1976 					"mask cannot be zero");
1977 
1978 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
1979 					(const uint8_t *)&nic_mask,
1980 					sizeof(struct rte_flow_item_mark),
1981 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
1982 	if (ret < 0)
1983 		return ret;
1984 	return 0;
1985 }
1986 
1987 /**
1988  * Validate META item.
1989  *
1990  * @param[in] dev
1991  *   Pointer to the rte_eth_dev structure.
1992  * @param[in] item
1993  *   Item specification.
1994  * @param[in] attr
1995  *   Attributes of flow that includes this item.
1996  * @param[out] error
1997  *   Pointer to error structure.
1998  *
1999  * @return
2000  *   0 on success, a negative errno value otherwise and rte_errno is set.
2001  */
2002 static int
2003 flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused,
2004 			   const struct rte_flow_item *item,
2005 			   const struct rte_flow_attr *attr,
2006 			   struct rte_flow_error *error)
2007 {
2008 	struct mlx5_priv *priv = dev->data->dev_private;
2009 	struct mlx5_dev_config *config = &priv->config;
2010 	const struct rte_flow_item_meta *spec = item->spec;
2011 	const struct rte_flow_item_meta *mask = item->mask;
2012 	struct rte_flow_item_meta nic_mask = {
2013 		.data = UINT32_MAX
2014 	};
2015 	int reg;
2016 	int ret;
2017 
2018 	if (!spec)
2019 		return rte_flow_error_set(error, EINVAL,
2020 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2021 					  item->spec,
2022 					  "data cannot be empty");
2023 	if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
2024 		if (!mlx5_flow_ext_mreg_supported(dev))
2025 			return rte_flow_error_set(error, ENOTSUP,
2026 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2027 					  "extended metadata register"
2028 					  " isn't supported");
2029 		reg = flow_dv_get_metadata_reg(dev, attr, error);
2030 		if (reg < 0)
2031 			return reg;
2032 		if (reg == REG_NON)
2033 			return rte_flow_error_set(error, ENOTSUP,
2034 					RTE_FLOW_ERROR_TYPE_ITEM, item,
2035 					"unavalable extended metadata register");
2036 		if (reg == REG_B)
2037 			return rte_flow_error_set(error, ENOTSUP,
2038 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2039 					  "match on reg_b "
2040 					  "isn't supported");
2041 		if (reg != REG_A)
2042 			nic_mask.data = priv->sh->dv_meta_mask;
2043 	} else {
2044 		if (attr->transfer)
2045 			return rte_flow_error_set(error, ENOTSUP,
2046 					RTE_FLOW_ERROR_TYPE_ITEM, item,
2047 					"extended metadata feature "
2048 					"should be enabled when "
2049 					"meta item is requested "
2050 					"with e-switch mode ");
2051 		if (attr->ingress)
2052 			return rte_flow_error_set(error, ENOTSUP,
2053 					RTE_FLOW_ERROR_TYPE_ITEM, item,
2054 					"match on metadata for ingress "
2055 					"is not supported in legacy "
2056 					"metadata mode");
2057 	}
2058 	if (!mask)
2059 		mask = &rte_flow_item_meta_mask;
2060 	if (!mask->data)
2061 		return rte_flow_error_set(error, EINVAL,
2062 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2063 					"mask cannot be zero");
2064 
2065 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2066 					(const uint8_t *)&nic_mask,
2067 					sizeof(struct rte_flow_item_meta),
2068 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2069 	return ret;
2070 }
2071 
2072 /**
2073  * Validate TAG item.
2074  *
2075  * @param[in] dev
2076  *   Pointer to the rte_eth_dev structure.
2077  * @param[in] item
2078  *   Item specification.
2079  * @param[in] attr
2080  *   Attributes of flow that includes this item.
2081  * @param[out] error
2082  *   Pointer to error structure.
2083  *
2084  * @return
2085  *   0 on success, a negative errno value otherwise and rte_errno is set.
2086  */
2087 static int
2088 flow_dv_validate_item_tag(struct rte_eth_dev *dev,
2089 			  const struct rte_flow_item *item,
2090 			  const struct rte_flow_attr *attr __rte_unused,
2091 			  struct rte_flow_error *error)
2092 {
2093 	const struct rte_flow_item_tag *spec = item->spec;
2094 	const struct rte_flow_item_tag *mask = item->mask;
2095 	const struct rte_flow_item_tag nic_mask = {
2096 		.data = RTE_BE32(UINT32_MAX),
2097 		.index = 0xff,
2098 	};
2099 	int ret;
2100 
2101 	if (!mlx5_flow_ext_mreg_supported(dev))
2102 		return rte_flow_error_set(error, ENOTSUP,
2103 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2104 					  "extensive metadata register"
2105 					  " isn't supported");
2106 	if (!spec)
2107 		return rte_flow_error_set(error, EINVAL,
2108 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2109 					  item->spec,
2110 					  "data cannot be empty");
2111 	if (!mask)
2112 		mask = &rte_flow_item_tag_mask;
2113 	if (!mask->data)
2114 		return rte_flow_error_set(error, EINVAL,
2115 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2116 					"mask cannot be zero");
2117 
2118 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2119 					(const uint8_t *)&nic_mask,
2120 					sizeof(struct rte_flow_item_tag),
2121 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2122 	if (ret < 0)
2123 		return ret;
2124 	if (mask->index != 0xff)
2125 		return rte_flow_error_set(error, EINVAL,
2126 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2127 					  "partial mask for tag index"
2128 					  " is not supported");
2129 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, spec->index, error);
2130 	if (ret < 0)
2131 		return ret;
2132 	MLX5_ASSERT(ret != REG_NON);
2133 	return 0;
2134 }
2135 
2136 /**
2137  * Validate vport item.
2138  *
2139  * @param[in] dev
2140  *   Pointer to the rte_eth_dev structure.
2141  * @param[in] item
2142  *   Item specification.
2143  * @param[in] attr
2144  *   Attributes of flow that includes this item.
2145  * @param[in] item_flags
2146  *   Bit-fields that holds the items detected until now.
2147  * @param[out] error
2148  *   Pointer to error structure.
2149  *
2150  * @return
2151  *   0 on success, a negative errno value otherwise and rte_errno is set.
2152  */
2153 static int
2154 flow_dv_validate_item_port_id(struct rte_eth_dev *dev,
2155 			      const struct rte_flow_item *item,
2156 			      const struct rte_flow_attr *attr,
2157 			      uint64_t item_flags,
2158 			      struct rte_flow_error *error)
2159 {
2160 	const struct rte_flow_item_port_id *spec = item->spec;
2161 	const struct rte_flow_item_port_id *mask = item->mask;
2162 	const struct rte_flow_item_port_id switch_mask = {
2163 			.id = 0xffffffff,
2164 	};
2165 	struct mlx5_priv *esw_priv;
2166 	struct mlx5_priv *dev_priv;
2167 	int ret;
2168 
2169 	if (!attr->transfer)
2170 		return rte_flow_error_set(error, EINVAL,
2171 					  RTE_FLOW_ERROR_TYPE_ITEM,
2172 					  NULL,
2173 					  "match on port id is valid only"
2174 					  " when transfer flag is enabled");
2175 	if (item_flags & MLX5_FLOW_ITEM_PORT_ID)
2176 		return rte_flow_error_set(error, ENOTSUP,
2177 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2178 					  "multiple source ports are not"
2179 					  " supported");
2180 	if (!mask)
2181 		mask = &switch_mask;
2182 	if (mask->id != 0xffffffff)
2183 		return rte_flow_error_set(error, ENOTSUP,
2184 					   RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2185 					   mask,
2186 					   "no support for partial mask on"
2187 					   " \"id\" field");
2188 	ret = mlx5_flow_item_acceptable
2189 				(item, (const uint8_t *)mask,
2190 				 (const uint8_t *)&rte_flow_item_port_id_mask,
2191 				 sizeof(struct rte_flow_item_port_id),
2192 				 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2193 	if (ret)
2194 		return ret;
2195 	if (!spec)
2196 		return 0;
2197 	if (spec->id == MLX5_PORT_ESW_MGR)
2198 		return 0;
2199 	esw_priv = mlx5_port_to_eswitch_info(spec->id, false);
2200 	if (!esw_priv)
2201 		return rte_flow_error_set(error, rte_errno,
2202 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2203 					  "failed to obtain E-Switch info for"
2204 					  " port");
2205 	dev_priv = mlx5_dev_to_eswitch_info(dev);
2206 	if (!dev_priv)
2207 		return rte_flow_error_set(error, rte_errno,
2208 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2209 					  NULL,
2210 					  "failed to obtain E-Switch info");
2211 	if (esw_priv->domain_id != dev_priv->domain_id)
2212 		return rte_flow_error_set(error, EINVAL,
2213 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2214 					  "cannot match on a port from a"
2215 					  " different E-Switch");
2216 	return 0;
2217 }
2218 
2219 /**
2220  * Validate VLAN item.
2221  *
2222  * @param[in] item
2223  *   Item specification.
2224  * @param[in] item_flags
2225  *   Bit-fields that holds the items detected until now.
2226  * @param[in] dev
2227  *   Ethernet device flow is being created on.
2228  * @param[out] error
2229  *   Pointer to error structure.
2230  *
2231  * @return
2232  *   0 on success, a negative errno value otherwise and rte_errno is set.
2233  */
2234 static int
2235 flow_dv_validate_item_vlan(const struct rte_flow_item *item,
2236 			   uint64_t item_flags,
2237 			   struct rte_eth_dev *dev,
2238 			   struct rte_flow_error *error)
2239 {
2240 	const struct rte_flow_item_vlan *mask = item->mask;
2241 	const struct rte_flow_item_vlan nic_mask = {
2242 		.tci = RTE_BE16(UINT16_MAX),
2243 		.inner_type = RTE_BE16(UINT16_MAX),
2244 		.has_more_vlan = 1,
2245 	};
2246 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2247 	int ret;
2248 	const uint64_t l34m = tunnel ? (MLX5_FLOW_LAYER_INNER_L3 |
2249 					MLX5_FLOW_LAYER_INNER_L4) :
2250 				       (MLX5_FLOW_LAYER_OUTER_L3 |
2251 					MLX5_FLOW_LAYER_OUTER_L4);
2252 	const uint64_t vlanm = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
2253 					MLX5_FLOW_LAYER_OUTER_VLAN;
2254 
2255 	if (item_flags & vlanm)
2256 		return rte_flow_error_set(error, EINVAL,
2257 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2258 					  "multiple VLAN layers not supported");
2259 	else if ((item_flags & l34m) != 0)
2260 		return rte_flow_error_set(error, EINVAL,
2261 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2262 					  "VLAN cannot follow L3/L4 layer");
2263 	if (!mask)
2264 		mask = &rte_flow_item_vlan_mask;
2265 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2266 					(const uint8_t *)&nic_mask,
2267 					sizeof(struct rte_flow_item_vlan),
2268 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2269 	if (ret)
2270 		return ret;
2271 	if (!tunnel && mask->tci != RTE_BE16(0x0fff)) {
2272 		struct mlx5_priv *priv = dev->data->dev_private;
2273 
2274 		if (priv->vmwa_context) {
2275 			/*
2276 			 * Non-NULL context means we have a virtual machine
2277 			 * and SR-IOV enabled, we have to create VLAN interface
2278 			 * to make hypervisor to setup E-Switch vport
2279 			 * context correctly. We avoid creating the multiple
2280 			 * VLAN interfaces, so we cannot support VLAN tag mask.
2281 			 */
2282 			return rte_flow_error_set(error, EINVAL,
2283 						  RTE_FLOW_ERROR_TYPE_ITEM,
2284 						  item,
2285 						  "VLAN tag mask is not"
2286 						  " supported in virtual"
2287 						  " environment");
2288 		}
2289 	}
2290 	return 0;
2291 }
2292 
2293 /*
2294  * GTP flags are contained in 1 byte of the format:
2295  * -------------------------------------------
2296  * | bit   | 0 - 2   | 3  | 4   | 5 | 6 | 7  |
2297  * |-----------------------------------------|
2298  * | value | Version | PT | Res | E | S | PN |
2299  * -------------------------------------------
2300  *
2301  * Matching is supported only for GTP flags E, S, PN.
2302  */
2303 #define MLX5_GTP_FLAGS_MASK	0x07
2304 
2305 /**
2306  * Validate GTP item.
2307  *
2308  * @param[in] dev
2309  *   Pointer to the rte_eth_dev structure.
2310  * @param[in] item
2311  *   Item specification.
2312  * @param[in] item_flags
2313  *   Bit-fields that holds the items detected until now.
2314  * @param[out] error
2315  *   Pointer to error structure.
2316  *
2317  * @return
2318  *   0 on success, a negative errno value otherwise and rte_errno is set.
2319  */
2320 static int
2321 flow_dv_validate_item_gtp(struct rte_eth_dev *dev,
2322 			  const struct rte_flow_item *item,
2323 			  uint64_t item_flags,
2324 			  struct rte_flow_error *error)
2325 {
2326 	struct mlx5_priv *priv = dev->data->dev_private;
2327 	const struct rte_flow_item_gtp *spec = item->spec;
2328 	const struct rte_flow_item_gtp *mask = item->mask;
2329 	const struct rte_flow_item_gtp nic_mask = {
2330 		.v_pt_rsv_flags = MLX5_GTP_FLAGS_MASK,
2331 		.msg_type = 0xff,
2332 		.teid = RTE_BE32(0xffffffff),
2333 	};
2334 
2335 	if (!priv->config.hca_attr.tunnel_stateless_gtp)
2336 		return rte_flow_error_set(error, ENOTSUP,
2337 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2338 					  "GTP support is not enabled");
2339 	if (item_flags & MLX5_FLOW_LAYER_TUNNEL)
2340 		return rte_flow_error_set(error, ENOTSUP,
2341 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2342 					  "multiple tunnel layers not"
2343 					  " supported");
2344 	if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP))
2345 		return rte_flow_error_set(error, EINVAL,
2346 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2347 					  "no outer UDP layer found");
2348 	if (!mask)
2349 		mask = &rte_flow_item_gtp_mask;
2350 	if (spec && spec->v_pt_rsv_flags & ~MLX5_GTP_FLAGS_MASK)
2351 		return rte_flow_error_set(error, ENOTSUP,
2352 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2353 					  "Match is supported for GTP"
2354 					  " flags only");
2355 	return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2356 					 (const uint8_t *)&nic_mask,
2357 					 sizeof(struct rte_flow_item_gtp),
2358 					 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2359 }
2360 
2361 /**
2362  * Validate GTP PSC item.
2363  *
2364  * @param[in] item
2365  *   Item specification.
2366  * @param[in] last_item
2367  *   Previous validated item in the pattern items.
2368  * @param[in] gtp_item
2369  *   Previous GTP item specification.
2370  * @param[in] attr
2371  *   Pointer to flow attributes.
2372  * @param[out] error
2373  *   Pointer to error structure.
2374  *
2375  * @return
2376  *   0 on success, a negative errno value otherwise and rte_errno is set.
2377  */
2378 static int
2379 flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item,
2380 			      uint64_t last_item,
2381 			      const struct rte_flow_item *gtp_item,
2382 			      const struct rte_flow_attr *attr,
2383 			      struct rte_flow_error *error)
2384 {
2385 	const struct rte_flow_item_gtp *gtp_spec;
2386 	const struct rte_flow_item_gtp *gtp_mask;
2387 	const struct rte_flow_item_gtp_psc *mask;
2388 	const struct rte_flow_item_gtp_psc nic_mask = {
2389 		.hdr.type = 0xF,
2390 		.hdr.qfi = 0x3F,
2391 	};
2392 
2393 	if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP))
2394 		return rte_flow_error_set
2395 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2396 			 "GTP PSC item must be preceded with GTP item");
2397 	gtp_spec = gtp_item->spec;
2398 	gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask;
2399 	/* GTP spec and E flag is requested to match zero. */
2400 	if (gtp_spec &&
2401 		(gtp_mask->v_pt_rsv_flags &
2402 		~gtp_spec->v_pt_rsv_flags & MLX5_GTP_EXT_HEADER_FLAG))
2403 		return rte_flow_error_set
2404 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2405 			 "GTP E flag must be 1 to match GTP PSC");
2406 	/* Check the flow is not created in group zero. */
2407 	if (!attr->transfer && !attr->group)
2408 		return rte_flow_error_set
2409 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2410 			 "GTP PSC is not supported for group 0");
2411 	/* GTP spec is here and E flag is requested to match zero. */
2412 	if (!item->spec)
2413 		return 0;
2414 	mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask;
2415 	return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2416 					 (const uint8_t *)&nic_mask,
2417 					 sizeof(struct rte_flow_item_gtp_psc),
2418 					 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2419 }
2420 
2421 /**
2422  * Validate IPV4 item.
2423  * Use existing validation function mlx5_flow_validate_item_ipv4(), and
2424  * add specific validation of fragment_offset field,
2425  *
2426  * @param[in] item
2427  *   Item specification.
2428  * @param[in] item_flags
2429  *   Bit-fields that holds the items detected until now.
2430  * @param[out] error
2431  *   Pointer to error structure.
2432  *
2433  * @return
2434  *   0 on success, a negative errno value otherwise and rte_errno is set.
2435  */
2436 static int
2437 flow_dv_validate_item_ipv4(struct rte_eth_dev *dev,
2438 			   const struct rte_flow_item *item,
2439 			   uint64_t item_flags, uint64_t last_item,
2440 			   uint16_t ether_type, struct rte_flow_error *error)
2441 {
2442 	int ret;
2443 	struct mlx5_priv *priv = dev->data->dev_private;
2444 	const struct rte_flow_item_ipv4 *spec = item->spec;
2445 	const struct rte_flow_item_ipv4 *last = item->last;
2446 	const struct rte_flow_item_ipv4 *mask = item->mask;
2447 	rte_be16_t fragment_offset_spec = 0;
2448 	rte_be16_t fragment_offset_last = 0;
2449 	struct rte_flow_item_ipv4 nic_ipv4_mask = {
2450 		.hdr = {
2451 			.src_addr = RTE_BE32(0xffffffff),
2452 			.dst_addr = RTE_BE32(0xffffffff),
2453 			.type_of_service = 0xff,
2454 			.fragment_offset = RTE_BE16(0xffff),
2455 			.next_proto_id = 0xff,
2456 			.time_to_live = 0xff,
2457 		},
2458 	};
2459 
2460 	if (mask && (mask->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK)) {
2461 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2462 		bool ihl_cap = !tunnel ? priv->config.hca_attr.outer_ipv4_ihl :
2463 			       priv->config.hca_attr.inner_ipv4_ihl;
2464 		if (!ihl_cap)
2465 			return rte_flow_error_set(error, ENOTSUP,
2466 						  RTE_FLOW_ERROR_TYPE_ITEM,
2467 						  item,
2468 						  "IPV4 ihl offload not supported");
2469 		nic_ipv4_mask.hdr.version_ihl = mask->hdr.version_ihl;
2470 	}
2471 	ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item,
2472 					   ether_type, &nic_ipv4_mask,
2473 					   MLX5_ITEM_RANGE_ACCEPTED, error);
2474 	if (ret < 0)
2475 		return ret;
2476 	if (spec && mask)
2477 		fragment_offset_spec = spec->hdr.fragment_offset &
2478 				       mask->hdr.fragment_offset;
2479 	if (!fragment_offset_spec)
2480 		return 0;
2481 	/*
2482 	 * spec and mask are valid, enforce using full mask to make sure the
2483 	 * complete value is used correctly.
2484 	 */
2485 	if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2486 			!= RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2487 		return rte_flow_error_set(error, EINVAL,
2488 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2489 					  item, "must use full mask for"
2490 					  " fragment_offset");
2491 	/*
2492 	 * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0,
2493 	 * indicating this is 1st fragment of fragmented packet.
2494 	 * This is not yet supported in MLX5, return appropriate error message.
2495 	 */
2496 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG))
2497 		return rte_flow_error_set(error, ENOTSUP,
2498 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2499 					  "match on first fragment not "
2500 					  "supported");
2501 	if (fragment_offset_spec && !last)
2502 		return rte_flow_error_set(error, ENOTSUP,
2503 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2504 					  "specified value not supported");
2505 	/* spec and last are valid, validate the specified range. */
2506 	fragment_offset_last = last->hdr.fragment_offset &
2507 			       mask->hdr.fragment_offset;
2508 	/*
2509 	 * Match on fragment_offset spec 0x2001 and last 0x3fff
2510 	 * means MF is 1 and frag-offset is > 0.
2511 	 * This packet is fragment 2nd and onward, excluding last.
2512 	 * This is not yet supported in MLX5, return appropriate
2513 	 * error message.
2514 	 */
2515 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) &&
2516 	    fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2517 		return rte_flow_error_set(error, ENOTSUP,
2518 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2519 					  last, "match on following "
2520 					  "fragments not supported");
2521 	/*
2522 	 * Match on fragment_offset spec 0x0001 and last 0x1fff
2523 	 * means MF is 0 and frag-offset is > 0.
2524 	 * This packet is last fragment of fragmented packet.
2525 	 * This is not yet supported in MLX5, return appropriate
2526 	 * error message.
2527 	 */
2528 	if (fragment_offset_spec == RTE_BE16(1) &&
2529 	    fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK))
2530 		return rte_flow_error_set(error, ENOTSUP,
2531 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2532 					  last, "match on last "
2533 					  "fragment not supported");
2534 	/*
2535 	 * Match on fragment_offset spec 0x0001 and last 0x3fff
2536 	 * means MF and/or frag-offset is not 0.
2537 	 * This is a fragmented packet.
2538 	 * Other range values are invalid and rejected.
2539 	 */
2540 	if (!(fragment_offset_spec == RTE_BE16(1) &&
2541 	      fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)))
2542 		return rte_flow_error_set(error, ENOTSUP,
2543 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2544 					  "specified range not supported");
2545 	return 0;
2546 }
2547 
2548 /**
2549  * Validate IPV6 fragment extension item.
2550  *
2551  * @param[in] item
2552  *   Item specification.
2553  * @param[in] item_flags
2554  *   Bit-fields that holds the items detected until now.
2555  * @param[out] error
2556  *   Pointer to error structure.
2557  *
2558  * @return
2559  *   0 on success, a negative errno value otherwise and rte_errno is set.
2560  */
2561 static int
2562 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item,
2563 				    uint64_t item_flags,
2564 				    struct rte_flow_error *error)
2565 {
2566 	const struct rte_flow_item_ipv6_frag_ext *spec = item->spec;
2567 	const struct rte_flow_item_ipv6_frag_ext *last = item->last;
2568 	const struct rte_flow_item_ipv6_frag_ext *mask = item->mask;
2569 	rte_be16_t frag_data_spec = 0;
2570 	rte_be16_t frag_data_last = 0;
2571 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2572 	const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 :
2573 				      MLX5_FLOW_LAYER_OUTER_L4;
2574 	int ret = 0;
2575 	struct rte_flow_item_ipv6_frag_ext nic_mask = {
2576 		.hdr = {
2577 			.next_header = 0xff,
2578 			.frag_data = RTE_BE16(0xffff),
2579 		},
2580 	};
2581 
2582 	if (item_flags & l4m)
2583 		return rte_flow_error_set(error, EINVAL,
2584 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2585 					  "ipv6 fragment extension item cannot "
2586 					  "follow L4 item.");
2587 	if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
2588 	    (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6)))
2589 		return rte_flow_error_set(error, EINVAL,
2590 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2591 					  "ipv6 fragment extension item must "
2592 					  "follow ipv6 item");
2593 	if (spec && mask)
2594 		frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data;
2595 	if (!frag_data_spec)
2596 		return 0;
2597 	/*
2598 	 * spec and mask are valid, enforce using full mask to make sure the
2599 	 * complete value is used correctly.
2600 	 */
2601 	if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) !=
2602 				RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2603 		return rte_flow_error_set(error, EINVAL,
2604 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2605 					  item, "must use full mask for"
2606 					  " frag_data");
2607 	/*
2608 	 * Match on frag_data 0x00001 means M is 1 and frag-offset is 0.
2609 	 * This is 1st fragment of fragmented packet.
2610 	 */
2611 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK))
2612 		return rte_flow_error_set(error, ENOTSUP,
2613 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2614 					  "match on first fragment not "
2615 					  "supported");
2616 	if (frag_data_spec && !last)
2617 		return rte_flow_error_set(error, EINVAL,
2618 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2619 					  "specified value not supported");
2620 	ret = mlx5_flow_item_acceptable
2621 				(item, (const uint8_t *)mask,
2622 				 (const uint8_t *)&nic_mask,
2623 				 sizeof(struct rte_flow_item_ipv6_frag_ext),
2624 				 MLX5_ITEM_RANGE_ACCEPTED, error);
2625 	if (ret)
2626 		return ret;
2627 	/* spec and last are valid, validate the specified range. */
2628 	frag_data_last = last->hdr.frag_data & mask->hdr.frag_data;
2629 	/*
2630 	 * Match on frag_data spec 0x0009 and last 0xfff9
2631 	 * means M is 1 and frag-offset is > 0.
2632 	 * This packet is fragment 2nd and onward, excluding last.
2633 	 * This is not yet supported in MLX5, return appropriate
2634 	 * error message.
2635 	 */
2636 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN |
2637 				       RTE_IPV6_EHDR_MF_MASK) &&
2638 	    frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2639 		return rte_flow_error_set(error, ENOTSUP,
2640 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2641 					  last, "match on following "
2642 					  "fragments not supported");
2643 	/*
2644 	 * Match on frag_data spec 0x0008 and last 0xfff8
2645 	 * means M is 0 and frag-offset is > 0.
2646 	 * This packet is last fragment of fragmented packet.
2647 	 * This is not yet supported in MLX5, return appropriate
2648 	 * error message.
2649 	 */
2650 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) &&
2651 	    frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK))
2652 		return rte_flow_error_set(error, ENOTSUP,
2653 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2654 					  last, "match on last "
2655 					  "fragment not supported");
2656 	/* Other range values are invalid and rejected. */
2657 	return rte_flow_error_set(error, EINVAL,
2658 				  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2659 				  "specified range not supported");
2660 }
2661 
2662 /*
2663  * Validate ASO CT item.
2664  *
2665  * @param[in] dev
2666  *   Pointer to the rte_eth_dev structure.
2667  * @param[in] item
2668  *   Item specification.
2669  * @param[in] item_flags
2670  *   Pointer to bit-fields that holds the items detected until now.
2671  * @param[out] error
2672  *   Pointer to error structure.
2673  *
2674  * @return
2675  *   0 on success, a negative errno value otherwise and rte_errno is set.
2676  */
2677 static int
2678 flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev,
2679 			     const struct rte_flow_item *item,
2680 			     uint64_t *item_flags,
2681 			     struct rte_flow_error *error)
2682 {
2683 	const struct rte_flow_item_conntrack *spec = item->spec;
2684 	const struct rte_flow_item_conntrack *mask = item->mask;
2685 	RTE_SET_USED(dev);
2686 	uint32_t flags;
2687 
2688 	if (*item_flags & MLX5_FLOW_LAYER_ASO_CT)
2689 		return rte_flow_error_set(error, EINVAL,
2690 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2691 					  "Only one CT is supported");
2692 	if (!mask)
2693 		mask = &rte_flow_item_conntrack_mask;
2694 	flags = spec->flags & mask->flags;
2695 	if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) &&
2696 	    ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) ||
2697 	     (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) ||
2698 	     (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)))
2699 		return rte_flow_error_set(error, EINVAL,
2700 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2701 					  "Conflict status bits");
2702 	/* State change also needs to be considered. */
2703 	*item_flags |= MLX5_FLOW_LAYER_ASO_CT;
2704 	return 0;
2705 }
2706 
2707 /**
2708  * Validate the pop VLAN action.
2709  *
2710  * @param[in] dev
2711  *   Pointer to the rte_eth_dev structure.
2712  * @param[in] action_flags
2713  *   Holds the actions detected until now.
2714  * @param[in] action
2715  *   Pointer to the pop vlan action.
2716  * @param[in] item_flags
2717  *   The items found in this flow rule.
2718  * @param[in] attr
2719  *   Pointer to flow attributes.
2720  * @param[out] error
2721  *   Pointer to error structure.
2722  *
2723  * @return
2724  *   0 on success, a negative errno value otherwise and rte_errno is set.
2725  */
2726 static int
2727 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev,
2728 				 uint64_t action_flags,
2729 				 const struct rte_flow_action *action,
2730 				 uint64_t item_flags,
2731 				 const struct rte_flow_attr *attr,
2732 				 struct rte_flow_error *error)
2733 {
2734 	const struct mlx5_priv *priv = dev->data->dev_private;
2735 	struct mlx5_dev_ctx_shared *sh = priv->sh;
2736 	bool direction_error = false;
2737 
2738 	if (!priv->sh->pop_vlan_action)
2739 		return rte_flow_error_set(error, ENOTSUP,
2740 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2741 					  NULL,
2742 					  "pop vlan action is not supported");
2743 	/* Pop VLAN is not supported in egress except for CX6 FDB mode. */
2744 	if (attr->transfer) {
2745 		bool fdb_tx = priv->representor_id != UINT16_MAX;
2746 		bool is_cx5 = sh->steering_format_version ==
2747 		    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
2748 
2749 		if (fdb_tx && is_cx5)
2750 			direction_error = true;
2751 	} else if (attr->egress) {
2752 		direction_error = true;
2753 	}
2754 	if (direction_error)
2755 		return rte_flow_error_set(error, ENOTSUP,
2756 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
2757 					  NULL,
2758 					  "pop vlan action not supported for egress");
2759 	if (action_flags & MLX5_FLOW_VLAN_ACTIONS)
2760 		return rte_flow_error_set(error, ENOTSUP,
2761 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2762 					  "no support for multiple VLAN "
2763 					  "actions");
2764 	/* Pop VLAN with preceding Decap requires inner header with VLAN. */
2765 	if ((action_flags & MLX5_FLOW_ACTION_DECAP) &&
2766 	    !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN))
2767 		return rte_flow_error_set(error, ENOTSUP,
2768 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2769 					  NULL,
2770 					  "cannot pop vlan after decap without "
2771 					  "match on inner vlan in the flow");
2772 	/* Pop VLAN without preceding Decap requires outer header with VLAN. */
2773 	if (!(action_flags & MLX5_FLOW_ACTION_DECAP) &&
2774 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
2775 		return rte_flow_error_set(error, ENOTSUP,
2776 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2777 					  NULL,
2778 					  "cannot pop vlan without a "
2779 					  "match on (outer) vlan in the flow");
2780 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2781 		return rte_flow_error_set(error, EINVAL,
2782 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2783 					  "wrong action order, port_id should "
2784 					  "be after pop VLAN action");
2785 	if (!attr->transfer && priv->representor)
2786 		return rte_flow_error_set(error, ENOTSUP,
2787 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2788 					  "pop vlan action for VF representor "
2789 					  "not supported on NIC table");
2790 	return 0;
2791 }
2792 
2793 /**
2794  * Get VLAN default info from vlan match info.
2795  *
2796  * @param[in] items
2797  *   the list of item specifications.
2798  * @param[out] vlan
2799  *   pointer VLAN info to fill to.
2800  *
2801  * @return
2802  *   0 on success, a negative errno value otherwise and rte_errno is set.
2803  */
2804 static void
2805 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items,
2806 				  struct rte_vlan_hdr *vlan)
2807 {
2808 	const struct rte_flow_item_vlan nic_mask = {
2809 		.tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK |
2810 				MLX5DV_FLOW_VLAN_VID_MASK),
2811 		.inner_type = RTE_BE16(0xffff),
2812 	};
2813 
2814 	if (items == NULL)
2815 		return;
2816 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
2817 		int type = items->type;
2818 
2819 		if (type == RTE_FLOW_ITEM_TYPE_VLAN ||
2820 		    type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN)
2821 			break;
2822 	}
2823 	if (items->type != RTE_FLOW_ITEM_TYPE_END) {
2824 		const struct rte_flow_item_vlan *vlan_m = items->mask;
2825 		const struct rte_flow_item_vlan *vlan_v = items->spec;
2826 
2827 		/* If VLAN item in pattern doesn't contain data, return here. */
2828 		if (!vlan_v)
2829 			return;
2830 		if (!vlan_m)
2831 			vlan_m = &nic_mask;
2832 		/* Only full match values are accepted */
2833 		if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) ==
2834 		     MLX5DV_FLOW_VLAN_PCP_MASK_BE) {
2835 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
2836 			vlan->vlan_tci |=
2837 				rte_be_to_cpu_16(vlan_v->tci &
2838 						 MLX5DV_FLOW_VLAN_PCP_MASK_BE);
2839 		}
2840 		if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) ==
2841 		     MLX5DV_FLOW_VLAN_VID_MASK_BE) {
2842 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
2843 			vlan->vlan_tci |=
2844 				rte_be_to_cpu_16(vlan_v->tci &
2845 						 MLX5DV_FLOW_VLAN_VID_MASK_BE);
2846 		}
2847 		if (vlan_m->inner_type == nic_mask.inner_type)
2848 			vlan->eth_proto = rte_be_to_cpu_16(vlan_v->inner_type &
2849 							   vlan_m->inner_type);
2850 	}
2851 }
2852 
2853 /**
2854  * Validate the push VLAN action.
2855  *
2856  * @param[in] dev
2857  *   Pointer to the rte_eth_dev structure.
2858  * @param[in] action_flags
2859  *   Holds the actions detected until now.
2860  * @param[in] item_flags
2861  *   The items found in this flow rule.
2862  * @param[in] action
2863  *   Pointer to the action structure.
2864  * @param[in] attr
2865  *   Pointer to flow attributes
2866  * @param[out] error
2867  *   Pointer to error structure.
2868  *
2869  * @return
2870  *   0 on success, a negative errno value otherwise and rte_errno is set.
2871  */
2872 static int
2873 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev,
2874 				  uint64_t action_flags,
2875 				  const struct rte_flow_item_vlan *vlan_m,
2876 				  const struct rte_flow_action *action,
2877 				  const struct rte_flow_attr *attr,
2878 				  struct rte_flow_error *error)
2879 {
2880 	const struct rte_flow_action_of_push_vlan *push_vlan = action->conf;
2881 	const struct mlx5_priv *priv = dev->data->dev_private;
2882 	struct mlx5_dev_ctx_shared *sh = priv->sh;
2883 	bool direction_error = false;
2884 
2885 	if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) &&
2886 	    push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ))
2887 		return rte_flow_error_set(error, EINVAL,
2888 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2889 					  "invalid vlan ethertype");
2890 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2891 		return rte_flow_error_set(error, EINVAL,
2892 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2893 					  "wrong action order, port_id should "
2894 					  "be after push VLAN");
2895 	/* Push VLAN is not supported in ingress except for CX6 FDB mode. */
2896 	if (attr->transfer) {
2897 		bool fdb_tx = priv->representor_id != UINT16_MAX;
2898 		bool is_cx5 = sh->steering_format_version ==
2899 		    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
2900 
2901 		if (!fdb_tx && is_cx5)
2902 			direction_error = true;
2903 	} else if (attr->ingress) {
2904 		direction_error = true;
2905 	}
2906 	if (direction_error)
2907 		return rte_flow_error_set(error, ENOTSUP,
2908 					  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
2909 					  NULL,
2910 					  "push vlan action not supported for ingress");
2911 	if (!attr->transfer && priv->representor)
2912 		return rte_flow_error_set(error, ENOTSUP,
2913 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2914 					  "push vlan action for VF representor "
2915 					  "not supported on NIC table");
2916 	if (vlan_m &&
2917 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) &&
2918 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) !=
2919 		MLX5DV_FLOW_VLAN_PCP_MASK_BE &&
2920 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) &&
2921 	    !(mlx5_flow_find_action
2922 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP)))
2923 		return rte_flow_error_set(error, EINVAL,
2924 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2925 					  "not full match mask on VLAN PCP and "
2926 					  "there is no of_set_vlan_pcp action, "
2927 					  "push VLAN action cannot figure out "
2928 					  "PCP value");
2929 	if (vlan_m &&
2930 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) &&
2931 	    (vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) !=
2932 		MLX5DV_FLOW_VLAN_VID_MASK_BE &&
2933 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) &&
2934 	    !(mlx5_flow_find_action
2935 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)))
2936 		return rte_flow_error_set(error, EINVAL,
2937 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2938 					  "not full match mask on VLAN VID and "
2939 					  "there is no of_set_vlan_vid action, "
2940 					  "push VLAN action cannot figure out "
2941 					  "VID value");
2942 	(void)attr;
2943 	return 0;
2944 }
2945 
2946 /**
2947  * Validate the set VLAN PCP.
2948  *
2949  * @param[in] action_flags
2950  *   Holds the actions detected until now.
2951  * @param[in] actions
2952  *   Pointer to the list of actions remaining in the flow rule.
2953  * @param[out] error
2954  *   Pointer to error structure.
2955  *
2956  * @return
2957  *   0 on success, a negative errno value otherwise and rte_errno is set.
2958  */
2959 static int
2960 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags,
2961 				     const struct rte_flow_action actions[],
2962 				     struct rte_flow_error *error)
2963 {
2964 	const struct rte_flow_action *action = actions;
2965 	const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf;
2966 
2967 	if (conf->vlan_pcp > 7)
2968 		return rte_flow_error_set(error, EINVAL,
2969 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2970 					  "VLAN PCP value is too big");
2971 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN))
2972 		return rte_flow_error_set(error, ENOTSUP,
2973 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2974 					  "set VLAN PCP action must follow "
2975 					  "the push VLAN action");
2976 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
2977 		return rte_flow_error_set(error, ENOTSUP,
2978 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2979 					  "Multiple VLAN PCP modification are "
2980 					  "not supported");
2981 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2982 		return rte_flow_error_set(error, EINVAL,
2983 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2984 					  "wrong action order, port_id should "
2985 					  "be after set VLAN PCP");
2986 	return 0;
2987 }
2988 
2989 /**
2990  * Validate the set VLAN VID.
2991  *
2992  * @param[in] item_flags
2993  *   Holds the items detected in this rule.
2994  * @param[in] action_flags
2995  *   Holds the actions detected until now.
2996  * @param[in] actions
2997  *   Pointer to the list of actions remaining in the flow rule.
2998  * @param[out] error
2999  *   Pointer to error structure.
3000  *
3001  * @return
3002  *   0 on success, a negative errno value otherwise and rte_errno is set.
3003  */
3004 static int
3005 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
3006 				     uint64_t action_flags,
3007 				     const struct rte_flow_action actions[],
3008 				     struct rte_flow_error *error)
3009 {
3010 	const struct rte_flow_action *action = actions;
3011 	const struct rte_flow_action_of_set_vlan_vid *conf = action->conf;
3012 
3013 	if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE)
3014 		return rte_flow_error_set(error, EINVAL,
3015 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3016 					  "VLAN VID value is too big");
3017 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) &&
3018 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
3019 		return rte_flow_error_set(error, ENOTSUP,
3020 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3021 					  "set VLAN VID action must follow push"
3022 					  " VLAN action or match on VLAN item");
3023 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID)
3024 		return rte_flow_error_set(error, ENOTSUP,
3025 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3026 					  "Multiple VLAN VID modifications are "
3027 					  "not supported");
3028 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
3029 		return rte_flow_error_set(error, EINVAL,
3030 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3031 					  "wrong action order, port_id should "
3032 					  "be after set VLAN VID");
3033 	return 0;
3034 }
3035 
3036 /*
3037  * Validate the FLAG action.
3038  *
3039  * @param[in] dev
3040  *   Pointer to the rte_eth_dev structure.
3041  * @param[in] action_flags
3042  *   Holds the actions detected until now.
3043  * @param[in] attr
3044  *   Pointer to flow attributes
3045  * @param[out] error
3046  *   Pointer to error structure.
3047  *
3048  * @return
3049  *   0 on success, a negative errno value otherwise and rte_errno is set.
3050  */
3051 static int
3052 flow_dv_validate_action_flag(struct rte_eth_dev *dev,
3053 			     uint64_t action_flags,
3054 			     const struct rte_flow_attr *attr,
3055 			     struct rte_flow_error *error)
3056 {
3057 	struct mlx5_priv *priv = dev->data->dev_private;
3058 	struct mlx5_dev_config *config = &priv->config;
3059 	int ret;
3060 
3061 	/* Fall back if no extended metadata register support. */
3062 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3063 		return mlx5_flow_validate_action_flag(action_flags, attr,
3064 						      error);
3065 	/* Extensive metadata mode requires registers. */
3066 	if (!mlx5_flow_ext_mreg_supported(dev))
3067 		return rte_flow_error_set(error, ENOTSUP,
3068 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3069 					  "no metadata registers "
3070 					  "to support flag action");
3071 	if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT))
3072 		return rte_flow_error_set(error, ENOTSUP,
3073 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3074 					  "extended metadata register"
3075 					  " isn't available");
3076 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3077 	if (ret < 0)
3078 		return ret;
3079 	MLX5_ASSERT(ret > 0);
3080 	if (action_flags & MLX5_FLOW_ACTION_MARK)
3081 		return rte_flow_error_set(error, EINVAL,
3082 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3083 					  "can't mark and flag in same flow");
3084 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
3085 		return rte_flow_error_set(error, EINVAL,
3086 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3087 					  "can't have 2 flag"
3088 					  " actions in same flow");
3089 	return 0;
3090 }
3091 
3092 /**
3093  * Validate MARK action.
3094  *
3095  * @param[in] dev
3096  *   Pointer to the rte_eth_dev structure.
3097  * @param[in] action
3098  *   Pointer to action.
3099  * @param[in] action_flags
3100  *   Holds the actions detected until now.
3101  * @param[in] attr
3102  *   Pointer to flow attributes
3103  * @param[out] error
3104  *   Pointer to error structure.
3105  *
3106  * @return
3107  *   0 on success, a negative errno value otherwise and rte_errno is set.
3108  */
3109 static int
3110 flow_dv_validate_action_mark(struct rte_eth_dev *dev,
3111 			     const struct rte_flow_action *action,
3112 			     uint64_t action_flags,
3113 			     const struct rte_flow_attr *attr,
3114 			     struct rte_flow_error *error)
3115 {
3116 	struct mlx5_priv *priv = dev->data->dev_private;
3117 	struct mlx5_dev_config *config = &priv->config;
3118 	const struct rte_flow_action_mark *mark = action->conf;
3119 	int ret;
3120 
3121 	if (is_tunnel_offload_active(dev))
3122 		return rte_flow_error_set(error, ENOTSUP,
3123 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3124 					  "no mark action "
3125 					  "if tunnel offload active");
3126 	/* Fall back if no extended metadata register support. */
3127 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3128 		return mlx5_flow_validate_action_mark(action, action_flags,
3129 						      attr, error);
3130 	/* Extensive metadata mode requires registers. */
3131 	if (!mlx5_flow_ext_mreg_supported(dev))
3132 		return rte_flow_error_set(error, ENOTSUP,
3133 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3134 					  "no metadata registers "
3135 					  "to support mark action");
3136 	if (!priv->sh->dv_mark_mask)
3137 		return rte_flow_error_set(error, ENOTSUP,
3138 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3139 					  "extended metadata register"
3140 					  " isn't available");
3141 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3142 	if (ret < 0)
3143 		return ret;
3144 	MLX5_ASSERT(ret > 0);
3145 	if (!mark)
3146 		return rte_flow_error_set(error, EINVAL,
3147 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3148 					  "configuration cannot be null");
3149 	if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask))
3150 		return rte_flow_error_set(error, EINVAL,
3151 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
3152 					  &mark->id,
3153 					  "mark id exceeds the limit");
3154 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
3155 		return rte_flow_error_set(error, EINVAL,
3156 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3157 					  "can't flag and mark in same flow");
3158 	if (action_flags & MLX5_FLOW_ACTION_MARK)
3159 		return rte_flow_error_set(error, EINVAL,
3160 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3161 					  "can't have 2 mark actions in same"
3162 					  " flow");
3163 	return 0;
3164 }
3165 
3166 /**
3167  * Validate SET_META action.
3168  *
3169  * @param[in] dev
3170  *   Pointer to the rte_eth_dev structure.
3171  * @param[in] action
3172  *   Pointer to the action structure.
3173  * @param[in] action_flags
3174  *   Holds the actions detected until now.
3175  * @param[in] attr
3176  *   Pointer to flow attributes
3177  * @param[out] error
3178  *   Pointer to error structure.
3179  *
3180  * @return
3181  *   0 on success, a negative errno value otherwise and rte_errno is set.
3182  */
3183 static int
3184 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev,
3185 				 const struct rte_flow_action *action,
3186 				 uint64_t action_flags __rte_unused,
3187 				 const struct rte_flow_attr *attr,
3188 				 struct rte_flow_error *error)
3189 {
3190 	struct mlx5_priv *priv = dev->data->dev_private;
3191 	struct mlx5_dev_config *config = &priv->config;
3192 	const struct rte_flow_action_set_meta *conf;
3193 	uint32_t nic_mask = UINT32_MAX;
3194 	int reg;
3195 
3196 	if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
3197 	    !mlx5_flow_ext_mreg_supported(dev))
3198 		return rte_flow_error_set(error, ENOTSUP,
3199 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3200 					  "extended metadata register"
3201 					  " isn't supported");
3202 	reg = flow_dv_get_metadata_reg(dev, attr, error);
3203 	if (reg < 0)
3204 		return reg;
3205 	if (reg == REG_NON)
3206 		return rte_flow_error_set(error, ENOTSUP,
3207 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3208 					  "unavalable extended metadata register");
3209 	if (reg != REG_A && reg != REG_B) {
3210 		struct mlx5_priv *priv = dev->data->dev_private;
3211 
3212 		nic_mask = priv->sh->dv_meta_mask;
3213 	}
3214 	if (!(action->conf))
3215 		return rte_flow_error_set(error, EINVAL,
3216 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3217 					  "configuration cannot be null");
3218 	conf = (const struct rte_flow_action_set_meta *)action->conf;
3219 	if (!conf->mask)
3220 		return rte_flow_error_set(error, EINVAL,
3221 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3222 					  "zero mask doesn't have any effect");
3223 	if (conf->mask & ~nic_mask)
3224 		return rte_flow_error_set(error, EINVAL,
3225 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3226 					  "meta data must be within reg C0");
3227 	return 0;
3228 }
3229 
3230 /**
3231  * Validate SET_TAG action.
3232  *
3233  * @param[in] dev
3234  *   Pointer to the rte_eth_dev structure.
3235  * @param[in] action
3236  *   Pointer to the action structure.
3237  * @param[in] action_flags
3238  *   Holds the actions detected until now.
3239  * @param[in] attr
3240  *   Pointer to flow attributes
3241  * @param[out] error
3242  *   Pointer to error structure.
3243  *
3244  * @return
3245  *   0 on success, a negative errno value otherwise and rte_errno is set.
3246  */
3247 static int
3248 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev,
3249 				const struct rte_flow_action *action,
3250 				uint64_t action_flags,
3251 				const struct rte_flow_attr *attr,
3252 				struct rte_flow_error *error)
3253 {
3254 	const struct rte_flow_action_set_tag *conf;
3255 	const uint64_t terminal_action_flags =
3256 		MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE |
3257 		MLX5_FLOW_ACTION_RSS;
3258 	int ret;
3259 
3260 	if (!mlx5_flow_ext_mreg_supported(dev))
3261 		return rte_flow_error_set(error, ENOTSUP,
3262 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3263 					  "extensive metadata register"
3264 					  " isn't supported");
3265 	if (!(action->conf))
3266 		return rte_flow_error_set(error, EINVAL,
3267 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3268 					  "configuration cannot be null");
3269 	conf = (const struct rte_flow_action_set_tag *)action->conf;
3270 	if (!conf->mask)
3271 		return rte_flow_error_set(error, EINVAL,
3272 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3273 					  "zero mask doesn't have any effect");
3274 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
3275 	if (ret < 0)
3276 		return ret;
3277 	if (!attr->transfer && attr->ingress &&
3278 	    (action_flags & terminal_action_flags))
3279 		return rte_flow_error_set(error, EINVAL,
3280 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3281 					  "set_tag has no effect"
3282 					  " with terminal actions");
3283 	return 0;
3284 }
3285 
3286 /**
3287  * Validate count action.
3288  *
3289  * @param[in] dev
3290  *   Pointer to rte_eth_dev structure.
3291  * @param[in] shared
3292  *   Indicator if action is shared.
3293  * @param[in] action_flags
3294  *   Holds the actions detected until now.
3295  * @param[out] error
3296  *   Pointer to error structure.
3297  *
3298  * @return
3299  *   0 on success, a negative errno value otherwise and rte_errno is set.
3300  */
3301 static int
3302 flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared,
3303 			      uint64_t action_flags,
3304 			      struct rte_flow_error *error)
3305 {
3306 	struct mlx5_priv *priv = dev->data->dev_private;
3307 
3308 	if (!priv->sh->devx)
3309 		goto notsup_err;
3310 	if (action_flags & MLX5_FLOW_ACTION_COUNT)
3311 		return rte_flow_error_set(error, EINVAL,
3312 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3313 					  "duplicate count actions set");
3314 	if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) &&
3315 	    !priv->sh->flow_hit_aso_en)
3316 		return rte_flow_error_set(error, EINVAL,
3317 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3318 					  "old age and shared count combination is not supported");
3319 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
3320 	return 0;
3321 #endif
3322 notsup_err:
3323 	return rte_flow_error_set
3324 		      (error, ENOTSUP,
3325 		       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3326 		       NULL,
3327 		       "count action not supported");
3328 }
3329 
3330 /**
3331  * Validate the L2 encap action.
3332  *
3333  * @param[in] dev
3334  *   Pointer to the rte_eth_dev structure.
3335  * @param[in] action_flags
3336  *   Holds the actions detected until now.
3337  * @param[in] action
3338  *   Pointer to the action structure.
3339  * @param[in] attr
3340  *   Pointer to flow attributes.
3341  * @param[out] error
3342  *   Pointer to error structure.
3343  *
3344  * @return
3345  *   0 on success, a negative errno value otherwise and rte_errno is set.
3346  */
3347 static int
3348 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev,
3349 				 uint64_t action_flags,
3350 				 const struct rte_flow_action *action,
3351 				 const struct rte_flow_attr *attr,
3352 				 struct rte_flow_error *error)
3353 {
3354 	const struct mlx5_priv *priv = dev->data->dev_private;
3355 
3356 	if (!(action->conf))
3357 		return rte_flow_error_set(error, EINVAL,
3358 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3359 					  "configuration cannot be null");
3360 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3361 		return rte_flow_error_set(error, EINVAL,
3362 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3363 					  "can only have a single encap action "
3364 					  "in a flow");
3365 	if (!attr->transfer && priv->representor)
3366 		return rte_flow_error_set(error, ENOTSUP,
3367 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3368 					  "encap action for VF representor "
3369 					  "not supported on NIC table");
3370 	return 0;
3371 }
3372 
3373 /**
3374  * Validate a decap action.
3375  *
3376  * @param[in] dev
3377  *   Pointer to the rte_eth_dev structure.
3378  * @param[in] action_flags
3379  *   Holds the actions detected until now.
3380  * @param[in] action
3381  *   Pointer to the action structure.
3382  * @param[in] item_flags
3383  *   Holds the items detected.
3384  * @param[in] attr
3385  *   Pointer to flow attributes
3386  * @param[out] error
3387  *   Pointer to error structure.
3388  *
3389  * @return
3390  *   0 on success, a negative errno value otherwise and rte_errno is set.
3391  */
3392 static int
3393 flow_dv_validate_action_decap(struct rte_eth_dev *dev,
3394 			      uint64_t action_flags,
3395 			      const struct rte_flow_action *action,
3396 			      const uint64_t item_flags,
3397 			      const struct rte_flow_attr *attr,
3398 			      struct rte_flow_error *error)
3399 {
3400 	const struct mlx5_priv *priv = dev->data->dev_private;
3401 
3402 	if (priv->config.hca_attr.scatter_fcs_w_decap_disable &&
3403 	    !priv->config.decap_en)
3404 		return rte_flow_error_set(error, ENOTSUP,
3405 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3406 					  "decap is not enabled");
3407 	if (action_flags & MLX5_FLOW_XCAP_ACTIONS)
3408 		return rte_flow_error_set(error, ENOTSUP,
3409 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3410 					  action_flags &
3411 					  MLX5_FLOW_ACTION_DECAP ? "can only "
3412 					  "have a single decap action" : "decap "
3413 					  "after encap is not supported");
3414 	if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
3415 		return rte_flow_error_set(error, EINVAL,
3416 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3417 					  "can't have decap action after"
3418 					  " modify action");
3419 	if (attr->egress)
3420 		return rte_flow_error_set(error, ENOTSUP,
3421 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
3422 					  NULL,
3423 					  "decap action not supported for "
3424 					  "egress");
3425 	if (!attr->transfer && priv->representor)
3426 		return rte_flow_error_set(error, ENOTSUP,
3427 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3428 					  "decap action for VF representor "
3429 					  "not supported on NIC table");
3430 	if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP &&
3431 	    !(item_flags & MLX5_FLOW_LAYER_VXLAN))
3432 		return rte_flow_error_set(error, ENOTSUP,
3433 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3434 				"VXLAN item should be present for VXLAN decap");
3435 	return 0;
3436 }
3437 
3438 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,};
3439 
3440 /**
3441  * Validate the raw encap and decap actions.
3442  *
3443  * @param[in] dev
3444  *   Pointer to the rte_eth_dev structure.
3445  * @param[in] decap
3446  *   Pointer to the decap action.
3447  * @param[in] encap
3448  *   Pointer to the encap action.
3449  * @param[in] attr
3450  *   Pointer to flow attributes
3451  * @param[in/out] action_flags
3452  *   Holds the actions detected until now.
3453  * @param[out] actions_n
3454  *   pointer to the number of actions counter.
3455  * @param[in] action
3456  *   Pointer to the action structure.
3457  * @param[in] item_flags
3458  *   Holds the items detected.
3459  * @param[out] error
3460  *   Pointer to error structure.
3461  *
3462  * @return
3463  *   0 on success, a negative errno value otherwise and rte_errno is set.
3464  */
3465 static int
3466 flow_dv_validate_action_raw_encap_decap
3467 	(struct rte_eth_dev *dev,
3468 	 const struct rte_flow_action_raw_decap *decap,
3469 	 const struct rte_flow_action_raw_encap *encap,
3470 	 const struct rte_flow_attr *attr, uint64_t *action_flags,
3471 	 int *actions_n, const struct rte_flow_action *action,
3472 	 uint64_t item_flags, struct rte_flow_error *error)
3473 {
3474 	const struct mlx5_priv *priv = dev->data->dev_private;
3475 	int ret;
3476 
3477 	if (encap && (!encap->size || !encap->data))
3478 		return rte_flow_error_set(error, EINVAL,
3479 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3480 					  "raw encap data cannot be empty");
3481 	if (decap && encap) {
3482 		if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE &&
3483 		    encap->size > MLX5_ENCAPSULATION_DECISION_SIZE)
3484 			/* L3 encap. */
3485 			decap = NULL;
3486 		else if (encap->size <=
3487 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3488 			   decap->size >
3489 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3490 			/* L3 decap. */
3491 			encap = NULL;
3492 		else if (encap->size >
3493 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3494 			   decap->size >
3495 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3496 			/* 2 L2 actions: encap and decap. */
3497 			;
3498 		else
3499 			return rte_flow_error_set(error,
3500 				ENOTSUP,
3501 				RTE_FLOW_ERROR_TYPE_ACTION,
3502 				NULL, "unsupported too small "
3503 				"raw decap and too small raw "
3504 				"encap combination");
3505 	}
3506 	if (decap) {
3507 		ret = flow_dv_validate_action_decap(dev, *action_flags, action,
3508 						    item_flags, attr, error);
3509 		if (ret < 0)
3510 			return ret;
3511 		*action_flags |= MLX5_FLOW_ACTION_DECAP;
3512 		++(*actions_n);
3513 	}
3514 	if (encap) {
3515 		if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE)
3516 			return rte_flow_error_set(error, ENOTSUP,
3517 						  RTE_FLOW_ERROR_TYPE_ACTION,
3518 						  NULL,
3519 						  "small raw encap size");
3520 		if (*action_flags & MLX5_FLOW_ACTION_ENCAP)
3521 			return rte_flow_error_set(error, EINVAL,
3522 						  RTE_FLOW_ERROR_TYPE_ACTION,
3523 						  NULL,
3524 						  "more than one encap action");
3525 		if (!attr->transfer && priv->representor)
3526 			return rte_flow_error_set
3527 					(error, ENOTSUP,
3528 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3529 					 "encap action for VF representor "
3530 					 "not supported on NIC table");
3531 		*action_flags |= MLX5_FLOW_ACTION_ENCAP;
3532 		++(*actions_n);
3533 	}
3534 	return 0;
3535 }
3536 
3537 /*
3538  * Validate the ASO CT action.
3539  *
3540  * @param[in] dev
3541  *   Pointer to the rte_eth_dev structure.
3542  * @param[in] action_flags
3543  *   Holds the actions detected until now.
3544  * @param[in] item_flags
3545  *   The items found in this flow rule.
3546  * @param[in] attr
3547  *   Pointer to flow attributes.
3548  * @param[out] error
3549  *   Pointer to error structure.
3550  *
3551  * @return
3552  *   0 on success, a negative errno value otherwise and rte_errno is set.
3553  */
3554 static int
3555 flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev,
3556 			       uint64_t action_flags,
3557 			       uint64_t item_flags,
3558 			       const struct rte_flow_attr *attr,
3559 			       struct rte_flow_error *error)
3560 {
3561 	RTE_SET_USED(dev);
3562 
3563 	if (attr->group == 0 && !attr->transfer)
3564 		return rte_flow_error_set(error, ENOTSUP,
3565 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3566 					  NULL,
3567 					  "Only support non-root table");
3568 	if (action_flags & MLX5_FLOW_FATE_ACTIONS)
3569 		return rte_flow_error_set(error, ENOTSUP,
3570 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3571 					  "CT cannot follow a fate action");
3572 	if ((action_flags & MLX5_FLOW_ACTION_METER) ||
3573 	    (action_flags & MLX5_FLOW_ACTION_AGE))
3574 		return rte_flow_error_set(error, EINVAL,
3575 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3576 					  "Only one ASO action is supported");
3577 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3578 		return rte_flow_error_set(error, EINVAL,
3579 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3580 					  "Encap cannot exist before CT");
3581 	if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP))
3582 		return rte_flow_error_set(error, EINVAL,
3583 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3584 					  "Not a outer TCP packet");
3585 	return 0;
3586 }
3587 
3588 int
3589 flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused,
3590 			     struct mlx5_list_entry *entry, void *cb_ctx)
3591 {
3592 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3593 	struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3594 	struct mlx5_flow_dv_encap_decap_resource *resource;
3595 
3596 	resource = container_of(entry, struct mlx5_flow_dv_encap_decap_resource,
3597 				entry);
3598 	if (resource->reformat_type == ctx_resource->reformat_type &&
3599 	    resource->ft_type == ctx_resource->ft_type &&
3600 	    resource->flags == ctx_resource->flags &&
3601 	    resource->size == ctx_resource->size &&
3602 	    !memcmp((const void *)resource->buf,
3603 		    (const void *)ctx_resource->buf,
3604 		    resource->size))
3605 		return 0;
3606 	return -1;
3607 }
3608 
3609 struct mlx5_list_entry *
3610 flow_dv_encap_decap_create_cb(void *tool_ctx, void *cb_ctx)
3611 {
3612 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3613 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3614 	struct mlx5dv_dr_domain *domain;
3615 	struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3616 	struct mlx5_flow_dv_encap_decap_resource *resource;
3617 	uint32_t idx;
3618 	int ret;
3619 
3620 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3621 		domain = sh->fdb_domain;
3622 	else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3623 		domain = sh->rx_domain;
3624 	else
3625 		domain = sh->tx_domain;
3626 	/* Register new encap/decap resource. */
3627 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &idx);
3628 	if (!resource) {
3629 		rte_flow_error_set(ctx->error, ENOMEM,
3630 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3631 				   "cannot allocate resource memory");
3632 		return NULL;
3633 	}
3634 	*resource = *ctx_resource;
3635 	resource->idx = idx;
3636 	ret = mlx5_flow_os_create_flow_action_packet_reformat(sh->cdev->ctx,
3637 							      domain, resource,
3638 							     &resource->action);
3639 	if (ret) {
3640 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx);
3641 		rte_flow_error_set(ctx->error, ENOMEM,
3642 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3643 				   NULL, "cannot create action");
3644 		return NULL;
3645 	}
3646 
3647 	return &resource->entry;
3648 }
3649 
3650 struct mlx5_list_entry *
3651 flow_dv_encap_decap_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
3652 			     void *cb_ctx)
3653 {
3654 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3655 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3656 	struct mlx5_flow_dv_encap_decap_resource *cache_resource;
3657 	uint32_t idx;
3658 
3659 	cache_resource = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
3660 					   &idx);
3661 	if (!cache_resource) {
3662 		rte_flow_error_set(ctx->error, ENOMEM,
3663 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3664 				   "cannot allocate resource memory");
3665 		return NULL;
3666 	}
3667 	memcpy(cache_resource, oentry, sizeof(*cache_resource));
3668 	cache_resource->idx = idx;
3669 	return &cache_resource->entry;
3670 }
3671 
3672 void
3673 flow_dv_encap_decap_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3674 {
3675 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3676 	struct mlx5_flow_dv_encap_decap_resource *res =
3677 				       container_of(entry, typeof(*res), entry);
3678 
3679 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
3680 }
3681 
3682 /**
3683  * Find existing encap/decap resource or create and register a new one.
3684  *
3685  * @param[in, out] dev
3686  *   Pointer to rte_eth_dev structure.
3687  * @param[in, out] resource
3688  *   Pointer to encap/decap resource.
3689  * @parm[in, out] dev_flow
3690  *   Pointer to the dev_flow.
3691  * @param[out] error
3692  *   pointer to error structure.
3693  *
3694  * @return
3695  *   0 on success otherwise -errno and errno is set.
3696  */
3697 static int
3698 flow_dv_encap_decap_resource_register
3699 			(struct rte_eth_dev *dev,
3700 			 struct mlx5_flow_dv_encap_decap_resource *resource,
3701 			 struct mlx5_flow *dev_flow,
3702 			 struct rte_flow_error *error)
3703 {
3704 	struct mlx5_priv *priv = dev->data->dev_private;
3705 	struct mlx5_dev_ctx_shared *sh = priv->sh;
3706 	struct mlx5_list_entry *entry;
3707 	union {
3708 		struct {
3709 			uint32_t ft_type:8;
3710 			uint32_t refmt_type:8;
3711 			/*
3712 			 * Header reformat actions can be shared between
3713 			 * non-root tables. One bit to indicate non-root
3714 			 * table or not.
3715 			 */
3716 			uint32_t is_root:1;
3717 			uint32_t reserve:15;
3718 		};
3719 		uint32_t v32;
3720 	} encap_decap_key = {
3721 		{
3722 			.ft_type = resource->ft_type,
3723 			.refmt_type = resource->reformat_type,
3724 			.is_root = !!dev_flow->dv.group,
3725 			.reserve = 0,
3726 		}
3727 	};
3728 	struct mlx5_flow_cb_ctx ctx = {
3729 		.error = error,
3730 		.data = resource,
3731 	};
3732 	struct mlx5_hlist *encaps_decaps;
3733 	uint64_t key64;
3734 
3735 	encaps_decaps = flow_dv_hlist_prepare(sh, &sh->encaps_decaps,
3736 				"encaps_decaps",
3737 				MLX5_FLOW_ENCAP_DECAP_HTABLE_SZ,
3738 				true, true, sh,
3739 				flow_dv_encap_decap_create_cb,
3740 				flow_dv_encap_decap_match_cb,
3741 				flow_dv_encap_decap_remove_cb,
3742 				flow_dv_encap_decap_clone_cb,
3743 				flow_dv_encap_decap_clone_free_cb);
3744 	if (unlikely(!encaps_decaps))
3745 		return -rte_errno;
3746 	resource->flags = dev_flow->dv.group ? 0 : 1;
3747 	key64 =  __rte_raw_cksum(&encap_decap_key.v32,
3748 				 sizeof(encap_decap_key.v32), 0);
3749 	if (resource->reformat_type !=
3750 	    MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 &&
3751 	    resource->size)
3752 		key64 = __rte_raw_cksum(resource->buf, resource->size, key64);
3753 	entry = mlx5_hlist_register(encaps_decaps, key64, &ctx);
3754 	if (!entry)
3755 		return -rte_errno;
3756 	resource = container_of(entry, typeof(*resource), entry);
3757 	dev_flow->dv.encap_decap = resource;
3758 	dev_flow->handle->dvh.rix_encap_decap = resource->idx;
3759 	return 0;
3760 }
3761 
3762 /**
3763  * Find existing table jump resource or create and register a new one.
3764  *
3765  * @param[in, out] dev
3766  *   Pointer to rte_eth_dev structure.
3767  * @param[in, out] tbl
3768  *   Pointer to flow table resource.
3769  * @parm[in, out] dev_flow
3770  *   Pointer to the dev_flow.
3771  * @param[out] error
3772  *   pointer to error structure.
3773  *
3774  * @return
3775  *   0 on success otherwise -errno and errno is set.
3776  */
3777 static int
3778 flow_dv_jump_tbl_resource_register
3779 			(struct rte_eth_dev *dev __rte_unused,
3780 			 struct mlx5_flow_tbl_resource *tbl,
3781 			 struct mlx5_flow *dev_flow,
3782 			 struct rte_flow_error *error __rte_unused)
3783 {
3784 	struct mlx5_flow_tbl_data_entry *tbl_data =
3785 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
3786 
3787 	MLX5_ASSERT(tbl);
3788 	MLX5_ASSERT(tbl_data->jump.action);
3789 	dev_flow->handle->rix_jump = tbl_data->idx;
3790 	dev_flow->dv.jump = &tbl_data->jump;
3791 	return 0;
3792 }
3793 
3794 int
3795 flow_dv_port_id_match_cb(void *tool_ctx __rte_unused,
3796 			 struct mlx5_list_entry *entry, void *cb_ctx)
3797 {
3798 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3799 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3800 	struct mlx5_flow_dv_port_id_action_resource *res =
3801 				       container_of(entry, typeof(*res), entry);
3802 
3803 	return ref->port_id != res->port_id;
3804 }
3805 
3806 struct mlx5_list_entry *
3807 flow_dv_port_id_create_cb(void *tool_ctx, void *cb_ctx)
3808 {
3809 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3810 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3811 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3812 	struct mlx5_flow_dv_port_id_action_resource *resource;
3813 	uint32_t idx;
3814 	int ret;
3815 
3816 	/* Register new port id action resource. */
3817 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3818 	if (!resource) {
3819 		rte_flow_error_set(ctx->error, ENOMEM,
3820 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3821 				   "cannot allocate port_id action memory");
3822 		return NULL;
3823 	}
3824 	*resource = *ref;
3825 	ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain,
3826 							ref->port_id,
3827 							&resource->action);
3828 	if (ret) {
3829 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx);
3830 		rte_flow_error_set(ctx->error, ENOMEM,
3831 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3832 				   "cannot create action");
3833 		return NULL;
3834 	}
3835 	resource->idx = idx;
3836 	return &resource->entry;
3837 }
3838 
3839 struct mlx5_list_entry *
3840 flow_dv_port_id_clone_cb(void *tool_ctx,
3841 			 struct mlx5_list_entry *entry __rte_unused,
3842 			 void *cb_ctx)
3843 {
3844 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3845 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3846 	struct mlx5_flow_dv_port_id_action_resource *resource;
3847 	uint32_t idx;
3848 
3849 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3850 	if (!resource) {
3851 		rte_flow_error_set(ctx->error, ENOMEM,
3852 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3853 				   "cannot allocate port_id action memory");
3854 		return NULL;
3855 	}
3856 	memcpy(resource, entry, sizeof(*resource));
3857 	resource->idx = idx;
3858 	return &resource->entry;
3859 }
3860 
3861 void
3862 flow_dv_port_id_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3863 {
3864 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3865 	struct mlx5_flow_dv_port_id_action_resource *resource =
3866 				  container_of(entry, typeof(*resource), entry);
3867 
3868 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
3869 }
3870 
3871 /**
3872  * Find existing table port ID resource or create and register a new one.
3873  *
3874  * @param[in, out] dev
3875  *   Pointer to rte_eth_dev structure.
3876  * @param[in, out] ref
3877  *   Pointer to port ID action resource reference.
3878  * @parm[in, out] dev_flow
3879  *   Pointer to the dev_flow.
3880  * @param[out] error
3881  *   pointer to error structure.
3882  *
3883  * @return
3884  *   0 on success otherwise -errno and errno is set.
3885  */
3886 static int
3887 flow_dv_port_id_action_resource_register
3888 			(struct rte_eth_dev *dev,
3889 			 struct mlx5_flow_dv_port_id_action_resource *ref,
3890 			 struct mlx5_flow *dev_flow,
3891 			 struct rte_flow_error *error)
3892 {
3893 	struct mlx5_priv *priv = dev->data->dev_private;
3894 	struct mlx5_list_entry *entry;
3895 	struct mlx5_flow_dv_port_id_action_resource *resource;
3896 	struct mlx5_flow_cb_ctx ctx = {
3897 		.error = error,
3898 		.data = ref,
3899 	};
3900 
3901 	entry = mlx5_list_register(priv->sh->port_id_action_list, &ctx);
3902 	if (!entry)
3903 		return -rte_errno;
3904 	resource = container_of(entry, typeof(*resource), entry);
3905 	dev_flow->dv.port_id_action = resource;
3906 	dev_flow->handle->rix_port_id_action = resource->idx;
3907 	return 0;
3908 }
3909 
3910 int
3911 flow_dv_push_vlan_match_cb(void *tool_ctx __rte_unused,
3912 			   struct mlx5_list_entry *entry, void *cb_ctx)
3913 {
3914 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3915 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3916 	struct mlx5_flow_dv_push_vlan_action_resource *res =
3917 				       container_of(entry, typeof(*res), entry);
3918 
3919 	return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type;
3920 }
3921 
3922 struct mlx5_list_entry *
3923 flow_dv_push_vlan_create_cb(void *tool_ctx, void *cb_ctx)
3924 {
3925 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3926 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3927 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
3928 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
3929 	struct mlx5dv_dr_domain *domain;
3930 	uint32_t idx;
3931 	int ret;
3932 
3933 	/* Register new port id action resource. */
3934 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
3935 	if (!resource) {
3936 		rte_flow_error_set(ctx->error, ENOMEM,
3937 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3938 				   "cannot allocate push_vlan action memory");
3939 		return NULL;
3940 	}
3941 	*resource = *ref;
3942 	if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3943 		domain = sh->fdb_domain;
3944 	else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3945 		domain = sh->rx_domain;
3946 	else
3947 		domain = sh->tx_domain;
3948 	ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag,
3949 							&resource->action);
3950 	if (ret) {
3951 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
3952 		rte_flow_error_set(ctx->error, ENOMEM,
3953 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3954 				   "cannot create push vlan action");
3955 		return NULL;
3956 	}
3957 	resource->idx = idx;
3958 	return &resource->entry;
3959 }
3960 
3961 struct mlx5_list_entry *
3962 flow_dv_push_vlan_clone_cb(void *tool_ctx,
3963 			   struct mlx5_list_entry *entry __rte_unused,
3964 			   void *cb_ctx)
3965 {
3966 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3967 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3968 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
3969 	uint32_t idx;
3970 
3971 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
3972 	if (!resource) {
3973 		rte_flow_error_set(ctx->error, ENOMEM,
3974 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3975 				   "cannot allocate push_vlan action memory");
3976 		return NULL;
3977 	}
3978 	memcpy(resource, entry, sizeof(*resource));
3979 	resource->idx = idx;
3980 	return &resource->entry;
3981 }
3982 
3983 void
3984 flow_dv_push_vlan_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3985 {
3986 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3987 	struct mlx5_flow_dv_push_vlan_action_resource *resource =
3988 				  container_of(entry, typeof(*resource), entry);
3989 
3990 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
3991 }
3992 
3993 /**
3994  * Find existing push vlan resource or create and register a new one.
3995  *
3996  * @param [in, out] dev
3997  *   Pointer to rte_eth_dev structure.
3998  * @param[in, out] ref
3999  *   Pointer to port ID action resource reference.
4000  * @parm[in, out] dev_flow
4001  *   Pointer to the dev_flow.
4002  * @param[out] error
4003  *   pointer to error structure.
4004  *
4005  * @return
4006  *   0 on success otherwise -errno and errno is set.
4007  */
4008 static int
4009 flow_dv_push_vlan_action_resource_register
4010 		       (struct rte_eth_dev *dev,
4011 			struct mlx5_flow_dv_push_vlan_action_resource *ref,
4012 			struct mlx5_flow *dev_flow,
4013 			struct rte_flow_error *error)
4014 {
4015 	struct mlx5_priv *priv = dev->data->dev_private;
4016 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
4017 	struct mlx5_list_entry *entry;
4018 	struct mlx5_flow_cb_ctx ctx = {
4019 		.error = error,
4020 		.data = ref,
4021 	};
4022 
4023 	entry = mlx5_list_register(priv->sh->push_vlan_action_list, &ctx);
4024 	if (!entry)
4025 		return -rte_errno;
4026 	resource = container_of(entry, typeof(*resource), entry);
4027 
4028 	dev_flow->handle->dvh.rix_push_vlan = resource->idx;
4029 	dev_flow->dv.push_vlan_res = resource;
4030 	return 0;
4031 }
4032 
4033 /**
4034  * Get the size of specific rte_flow_item_type hdr size
4035  *
4036  * @param[in] item_type
4037  *   Tested rte_flow_item_type.
4038  *
4039  * @return
4040  *   sizeof struct item_type, 0 if void or irrelevant.
4041  */
4042 static size_t
4043 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type)
4044 {
4045 	size_t retval;
4046 
4047 	switch (item_type) {
4048 	case RTE_FLOW_ITEM_TYPE_ETH:
4049 		retval = sizeof(struct rte_ether_hdr);
4050 		break;
4051 	case RTE_FLOW_ITEM_TYPE_VLAN:
4052 		retval = sizeof(struct rte_vlan_hdr);
4053 		break;
4054 	case RTE_FLOW_ITEM_TYPE_IPV4:
4055 		retval = sizeof(struct rte_ipv4_hdr);
4056 		break;
4057 	case RTE_FLOW_ITEM_TYPE_IPV6:
4058 		retval = sizeof(struct rte_ipv6_hdr);
4059 		break;
4060 	case RTE_FLOW_ITEM_TYPE_UDP:
4061 		retval = sizeof(struct rte_udp_hdr);
4062 		break;
4063 	case RTE_FLOW_ITEM_TYPE_TCP:
4064 		retval = sizeof(struct rte_tcp_hdr);
4065 		break;
4066 	case RTE_FLOW_ITEM_TYPE_VXLAN:
4067 	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4068 		retval = sizeof(struct rte_vxlan_hdr);
4069 		break;
4070 	case RTE_FLOW_ITEM_TYPE_GRE:
4071 	case RTE_FLOW_ITEM_TYPE_NVGRE:
4072 		retval = sizeof(struct rte_gre_hdr);
4073 		break;
4074 	case RTE_FLOW_ITEM_TYPE_MPLS:
4075 		retval = sizeof(struct rte_mpls_hdr);
4076 		break;
4077 	case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */
4078 	default:
4079 		retval = 0;
4080 		break;
4081 	}
4082 	return retval;
4083 }
4084 
4085 #define MLX5_ENCAP_IPV4_VERSION		0x40
4086 #define MLX5_ENCAP_IPV4_IHL_MIN		0x05
4087 #define MLX5_ENCAP_IPV4_TTL_DEF		0x40
4088 #define MLX5_ENCAP_IPV6_VTC_FLOW	0x60000000
4089 #define MLX5_ENCAP_IPV6_HOP_LIMIT	0xff
4090 #define MLX5_ENCAP_VXLAN_FLAGS		0x08000000
4091 #define MLX5_ENCAP_VXLAN_GPE_FLAGS	0x04
4092 
4093 /**
4094  * Convert the encap action data from list of rte_flow_item to raw buffer
4095  *
4096  * @param[in] items
4097  *   Pointer to rte_flow_item objects list.
4098  * @param[out] buf
4099  *   Pointer to the output buffer.
4100  * @param[out] size
4101  *   Pointer to the output buffer size.
4102  * @param[out] error
4103  *   Pointer to the error structure.
4104  *
4105  * @return
4106  *   0 on success, a negative errno value otherwise and rte_errno is set.
4107  */
4108 static int
4109 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf,
4110 			   size_t *size, struct rte_flow_error *error)
4111 {
4112 	struct rte_ether_hdr *eth = NULL;
4113 	struct rte_vlan_hdr *vlan = NULL;
4114 	struct rte_ipv4_hdr *ipv4 = NULL;
4115 	struct rte_ipv6_hdr *ipv6 = NULL;
4116 	struct rte_udp_hdr *udp = NULL;
4117 	struct rte_vxlan_hdr *vxlan = NULL;
4118 	struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL;
4119 	struct rte_gre_hdr *gre = NULL;
4120 	size_t len;
4121 	size_t temp_size = 0;
4122 
4123 	if (!items)
4124 		return rte_flow_error_set(error, EINVAL,
4125 					  RTE_FLOW_ERROR_TYPE_ACTION,
4126 					  NULL, "invalid empty data");
4127 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
4128 		len = flow_dv_get_item_hdr_len(items->type);
4129 		if (len + temp_size > MLX5_ENCAP_MAX_LEN)
4130 			return rte_flow_error_set(error, EINVAL,
4131 						  RTE_FLOW_ERROR_TYPE_ACTION,
4132 						  (void *)items->type,
4133 						  "items total size is too big"
4134 						  " for encap action");
4135 		rte_memcpy((void *)&buf[temp_size], items->spec, len);
4136 		switch (items->type) {
4137 		case RTE_FLOW_ITEM_TYPE_ETH:
4138 			eth = (struct rte_ether_hdr *)&buf[temp_size];
4139 			break;
4140 		case RTE_FLOW_ITEM_TYPE_VLAN:
4141 			vlan = (struct rte_vlan_hdr *)&buf[temp_size];
4142 			if (!eth)
4143 				return rte_flow_error_set(error, EINVAL,
4144 						RTE_FLOW_ERROR_TYPE_ACTION,
4145 						(void *)items->type,
4146 						"eth header not found");
4147 			if (!eth->ether_type)
4148 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN);
4149 			break;
4150 		case RTE_FLOW_ITEM_TYPE_IPV4:
4151 			ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size];
4152 			if (!vlan && !eth)
4153 				return rte_flow_error_set(error, EINVAL,
4154 						RTE_FLOW_ERROR_TYPE_ACTION,
4155 						(void *)items->type,
4156 						"neither eth nor vlan"
4157 						" header found");
4158 			if (vlan && !vlan->eth_proto)
4159 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4160 			else if (eth && !eth->ether_type)
4161 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4162 			if (!ipv4->version_ihl)
4163 				ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION |
4164 						    MLX5_ENCAP_IPV4_IHL_MIN;
4165 			if (!ipv4->time_to_live)
4166 				ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF;
4167 			break;
4168 		case RTE_FLOW_ITEM_TYPE_IPV6:
4169 			ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size];
4170 			if (!vlan && !eth)
4171 				return rte_flow_error_set(error, EINVAL,
4172 						RTE_FLOW_ERROR_TYPE_ACTION,
4173 						(void *)items->type,
4174 						"neither eth nor vlan"
4175 						" header found");
4176 			if (vlan && !vlan->eth_proto)
4177 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4178 			else if (eth && !eth->ether_type)
4179 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4180 			if (!ipv6->vtc_flow)
4181 				ipv6->vtc_flow =
4182 					RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW);
4183 			if (!ipv6->hop_limits)
4184 				ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT;
4185 			break;
4186 		case RTE_FLOW_ITEM_TYPE_UDP:
4187 			udp = (struct rte_udp_hdr *)&buf[temp_size];
4188 			if (!ipv4 && !ipv6)
4189 				return rte_flow_error_set(error, EINVAL,
4190 						RTE_FLOW_ERROR_TYPE_ACTION,
4191 						(void *)items->type,
4192 						"ip header not found");
4193 			if (ipv4 && !ipv4->next_proto_id)
4194 				ipv4->next_proto_id = IPPROTO_UDP;
4195 			else if (ipv6 && !ipv6->proto)
4196 				ipv6->proto = IPPROTO_UDP;
4197 			break;
4198 		case RTE_FLOW_ITEM_TYPE_VXLAN:
4199 			vxlan = (struct rte_vxlan_hdr *)&buf[temp_size];
4200 			if (!udp)
4201 				return rte_flow_error_set(error, EINVAL,
4202 						RTE_FLOW_ERROR_TYPE_ACTION,
4203 						(void *)items->type,
4204 						"udp header not found");
4205 			if (!udp->dst_port)
4206 				udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN);
4207 			if (!vxlan->vx_flags)
4208 				vxlan->vx_flags =
4209 					RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS);
4210 			break;
4211 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4212 			vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size];
4213 			if (!udp)
4214 				return rte_flow_error_set(error, EINVAL,
4215 						RTE_FLOW_ERROR_TYPE_ACTION,
4216 						(void *)items->type,
4217 						"udp header not found");
4218 			if (!vxlan_gpe->proto)
4219 				return rte_flow_error_set(error, EINVAL,
4220 						RTE_FLOW_ERROR_TYPE_ACTION,
4221 						(void *)items->type,
4222 						"next protocol not found");
4223 			if (!udp->dst_port)
4224 				udp->dst_port =
4225 					RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE);
4226 			if (!vxlan_gpe->vx_flags)
4227 				vxlan_gpe->vx_flags =
4228 						MLX5_ENCAP_VXLAN_GPE_FLAGS;
4229 			break;
4230 		case RTE_FLOW_ITEM_TYPE_GRE:
4231 		case RTE_FLOW_ITEM_TYPE_NVGRE:
4232 			gre = (struct rte_gre_hdr *)&buf[temp_size];
4233 			if (!gre->proto)
4234 				return rte_flow_error_set(error, EINVAL,
4235 						RTE_FLOW_ERROR_TYPE_ACTION,
4236 						(void *)items->type,
4237 						"next protocol not found");
4238 			if (!ipv4 && !ipv6)
4239 				return rte_flow_error_set(error, EINVAL,
4240 						RTE_FLOW_ERROR_TYPE_ACTION,
4241 						(void *)items->type,
4242 						"ip header not found");
4243 			if (ipv4 && !ipv4->next_proto_id)
4244 				ipv4->next_proto_id = IPPROTO_GRE;
4245 			else if (ipv6 && !ipv6->proto)
4246 				ipv6->proto = IPPROTO_GRE;
4247 			break;
4248 		case RTE_FLOW_ITEM_TYPE_VOID:
4249 			break;
4250 		default:
4251 			return rte_flow_error_set(error, EINVAL,
4252 						  RTE_FLOW_ERROR_TYPE_ACTION,
4253 						  (void *)items->type,
4254 						  "unsupported item type");
4255 			break;
4256 		}
4257 		temp_size += len;
4258 	}
4259 	*size = temp_size;
4260 	return 0;
4261 }
4262 
4263 static int
4264 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error)
4265 {
4266 	struct rte_ether_hdr *eth = NULL;
4267 	struct rte_vlan_hdr *vlan = NULL;
4268 	struct rte_ipv6_hdr *ipv6 = NULL;
4269 	struct rte_udp_hdr *udp = NULL;
4270 	char *next_hdr;
4271 	uint16_t proto;
4272 
4273 	eth = (struct rte_ether_hdr *)data;
4274 	next_hdr = (char *)(eth + 1);
4275 	proto = RTE_BE16(eth->ether_type);
4276 
4277 	/* VLAN skipping */
4278 	while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) {
4279 		vlan = (struct rte_vlan_hdr *)next_hdr;
4280 		proto = RTE_BE16(vlan->eth_proto);
4281 		next_hdr += sizeof(struct rte_vlan_hdr);
4282 	}
4283 
4284 	/* HW calculates IPv4 csum. no need to proceed */
4285 	if (proto == RTE_ETHER_TYPE_IPV4)
4286 		return 0;
4287 
4288 	/* non IPv4/IPv6 header. not supported */
4289 	if (proto != RTE_ETHER_TYPE_IPV6) {
4290 		return rte_flow_error_set(error, ENOTSUP,
4291 					  RTE_FLOW_ERROR_TYPE_ACTION,
4292 					  NULL, "Cannot offload non IPv4/IPv6");
4293 	}
4294 
4295 	ipv6 = (struct rte_ipv6_hdr *)next_hdr;
4296 
4297 	/* ignore non UDP */
4298 	if (ipv6->proto != IPPROTO_UDP)
4299 		return 0;
4300 
4301 	udp = (struct rte_udp_hdr *)(ipv6 + 1);
4302 	udp->dgram_cksum = 0;
4303 
4304 	return 0;
4305 }
4306 
4307 /**
4308  * Convert L2 encap action to DV specification.
4309  *
4310  * @param[in] dev
4311  *   Pointer to rte_eth_dev structure.
4312  * @param[in] action
4313  *   Pointer to action structure.
4314  * @param[in, out] dev_flow
4315  *   Pointer to the mlx5_flow.
4316  * @param[in] transfer
4317  *   Mark if the flow is E-Switch flow.
4318  * @param[out] error
4319  *   Pointer to the error structure.
4320  *
4321  * @return
4322  *   0 on success, a negative errno value otherwise and rte_errno is set.
4323  */
4324 static int
4325 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev,
4326 			       const struct rte_flow_action *action,
4327 			       struct mlx5_flow *dev_flow,
4328 			       uint8_t transfer,
4329 			       struct rte_flow_error *error)
4330 {
4331 	const struct rte_flow_item *encap_data;
4332 	const struct rte_flow_action_raw_encap *raw_encap_data;
4333 	struct mlx5_flow_dv_encap_decap_resource res = {
4334 		.reformat_type =
4335 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL,
4336 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4337 				      MLX5DV_FLOW_TABLE_TYPE_NIC_TX,
4338 	};
4339 
4340 	if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
4341 		raw_encap_data =
4342 			(const struct rte_flow_action_raw_encap *)action->conf;
4343 		res.size = raw_encap_data->size;
4344 		memcpy(res.buf, raw_encap_data->data, res.size);
4345 	} else {
4346 		if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
4347 			encap_data =
4348 				((const struct rte_flow_action_vxlan_encap *)
4349 						action->conf)->definition;
4350 		else
4351 			encap_data =
4352 				((const struct rte_flow_action_nvgre_encap *)
4353 						action->conf)->definition;
4354 		if (flow_dv_convert_encap_data(encap_data, res.buf,
4355 					       &res.size, error))
4356 			return -rte_errno;
4357 	}
4358 	if (flow_dv_zero_encap_udp_csum(res.buf, error))
4359 		return -rte_errno;
4360 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4361 		return rte_flow_error_set(error, EINVAL,
4362 					  RTE_FLOW_ERROR_TYPE_ACTION,
4363 					  NULL, "can't create L2 encap action");
4364 	return 0;
4365 }
4366 
4367 /**
4368  * Convert L2 decap action to DV specification.
4369  *
4370  * @param[in] dev
4371  *   Pointer to rte_eth_dev structure.
4372  * @param[in, out] dev_flow
4373  *   Pointer to the mlx5_flow.
4374  * @param[in] transfer
4375  *   Mark if the flow is E-Switch flow.
4376  * @param[out] error
4377  *   Pointer to the error structure.
4378  *
4379  * @return
4380  *   0 on success, a negative errno value otherwise and rte_errno is set.
4381  */
4382 static int
4383 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev,
4384 			       struct mlx5_flow *dev_flow,
4385 			       uint8_t transfer,
4386 			       struct rte_flow_error *error)
4387 {
4388 	struct mlx5_flow_dv_encap_decap_resource res = {
4389 		.size = 0,
4390 		.reformat_type =
4391 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2,
4392 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4393 				      MLX5DV_FLOW_TABLE_TYPE_NIC_RX,
4394 	};
4395 
4396 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4397 		return rte_flow_error_set(error, EINVAL,
4398 					  RTE_FLOW_ERROR_TYPE_ACTION,
4399 					  NULL, "can't create L2 decap action");
4400 	return 0;
4401 }
4402 
4403 /**
4404  * Convert raw decap/encap (L3 tunnel) action to DV specification.
4405  *
4406  * @param[in] dev
4407  *   Pointer to rte_eth_dev structure.
4408  * @param[in] action
4409  *   Pointer to action structure.
4410  * @param[in, out] dev_flow
4411  *   Pointer to the mlx5_flow.
4412  * @param[in] attr
4413  *   Pointer to the flow attributes.
4414  * @param[out] error
4415  *   Pointer to the error structure.
4416  *
4417  * @return
4418  *   0 on success, a negative errno value otherwise and rte_errno is set.
4419  */
4420 static int
4421 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
4422 				const struct rte_flow_action *action,
4423 				struct mlx5_flow *dev_flow,
4424 				const struct rte_flow_attr *attr,
4425 				struct rte_flow_error *error)
4426 {
4427 	const struct rte_flow_action_raw_encap *encap_data;
4428 	struct mlx5_flow_dv_encap_decap_resource res;
4429 
4430 	memset(&res, 0, sizeof(res));
4431 	encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
4432 	res.size = encap_data->size;
4433 	memcpy(res.buf, encap_data->data, res.size);
4434 	res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ?
4435 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 :
4436 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
4437 	if (attr->transfer)
4438 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4439 	else
4440 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4441 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4442 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4443 		return rte_flow_error_set(error, EINVAL,
4444 					  RTE_FLOW_ERROR_TYPE_ACTION,
4445 					  NULL, "can't create encap action");
4446 	return 0;
4447 }
4448 
4449 /**
4450  * Create action push VLAN.
4451  *
4452  * @param[in] dev
4453  *   Pointer to rte_eth_dev structure.
4454  * @param[in] attr
4455  *   Pointer to the flow attributes.
4456  * @param[in] vlan
4457  *   Pointer to the vlan to push to the Ethernet header.
4458  * @param[in, out] dev_flow
4459  *   Pointer to the mlx5_flow.
4460  * @param[out] error
4461  *   Pointer to the error structure.
4462  *
4463  * @return
4464  *   0 on success, a negative errno value otherwise and rte_errno is set.
4465  */
4466 static int
4467 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
4468 				const struct rte_flow_attr *attr,
4469 				const struct rte_vlan_hdr *vlan,
4470 				struct mlx5_flow *dev_flow,
4471 				struct rte_flow_error *error)
4472 {
4473 	struct mlx5_flow_dv_push_vlan_action_resource res;
4474 
4475 	memset(&res, 0, sizeof(res));
4476 	res.vlan_tag =
4477 		rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 |
4478 				 vlan->vlan_tci);
4479 	if (attr->transfer)
4480 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4481 	else
4482 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4483 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4484 	return flow_dv_push_vlan_action_resource_register
4485 					    (dev, &res, dev_flow, error);
4486 }
4487 
4488 /**
4489  * Validate the modify-header actions.
4490  *
4491  * @param[in] action_flags
4492  *   Holds the actions detected until now.
4493  * @param[in] action
4494  *   Pointer to the modify action.
4495  * @param[out] error
4496  *   Pointer to error structure.
4497  *
4498  * @return
4499  *   0 on success, a negative errno value otherwise and rte_errno is set.
4500  */
4501 static int
4502 flow_dv_validate_action_modify_hdr(const uint64_t action_flags,
4503 				   const struct rte_flow_action *action,
4504 				   struct rte_flow_error *error)
4505 {
4506 	if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf)
4507 		return rte_flow_error_set(error, EINVAL,
4508 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
4509 					  NULL, "action configuration not set");
4510 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
4511 		return rte_flow_error_set(error, EINVAL,
4512 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4513 					  "can't have encap action before"
4514 					  " modify action");
4515 	return 0;
4516 }
4517 
4518 /**
4519  * Validate the modify-header MAC address actions.
4520  *
4521  * @param[in] action_flags
4522  *   Holds the actions detected until now.
4523  * @param[in] action
4524  *   Pointer to the modify action.
4525  * @param[in] item_flags
4526  *   Holds the items detected.
4527  * @param[out] error
4528  *   Pointer to error structure.
4529  *
4530  * @return
4531  *   0 on success, a negative errno value otherwise and rte_errno is set.
4532  */
4533 static int
4534 flow_dv_validate_action_modify_mac(const uint64_t action_flags,
4535 				   const struct rte_flow_action *action,
4536 				   const uint64_t item_flags,
4537 				   struct rte_flow_error *error)
4538 {
4539 	int ret = 0;
4540 
4541 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4542 	if (!ret) {
4543 		if (!(item_flags & MLX5_FLOW_LAYER_L2))
4544 			return rte_flow_error_set(error, EINVAL,
4545 						  RTE_FLOW_ERROR_TYPE_ACTION,
4546 						  NULL,
4547 						  "no L2 item in pattern");
4548 	}
4549 	return ret;
4550 }
4551 
4552 /**
4553  * Validate the modify-header IPv4 address actions.
4554  *
4555  * @param[in] action_flags
4556  *   Holds the actions detected until now.
4557  * @param[in] action
4558  *   Pointer to the modify action.
4559  * @param[in] item_flags
4560  *   Holds the items detected.
4561  * @param[out] error
4562  *   Pointer to error structure.
4563  *
4564  * @return
4565  *   0 on success, a negative errno value otherwise and rte_errno is set.
4566  */
4567 static int
4568 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags,
4569 				    const struct rte_flow_action *action,
4570 				    const uint64_t item_flags,
4571 				    struct rte_flow_error *error)
4572 {
4573 	int ret = 0;
4574 	uint64_t layer;
4575 
4576 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4577 	if (!ret) {
4578 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4579 				 MLX5_FLOW_LAYER_INNER_L3_IPV4 :
4580 				 MLX5_FLOW_LAYER_OUTER_L3_IPV4;
4581 		if (!(item_flags & layer))
4582 			return rte_flow_error_set(error, EINVAL,
4583 						  RTE_FLOW_ERROR_TYPE_ACTION,
4584 						  NULL,
4585 						  "no ipv4 item in pattern");
4586 	}
4587 	return ret;
4588 }
4589 
4590 /**
4591  * Validate the modify-header IPv6 address actions.
4592  *
4593  * @param[in] action_flags
4594  *   Holds the actions detected until now.
4595  * @param[in] action
4596  *   Pointer to the modify action.
4597  * @param[in] item_flags
4598  *   Holds the items detected.
4599  * @param[out] error
4600  *   Pointer to error structure.
4601  *
4602  * @return
4603  *   0 on success, a negative errno value otherwise and rte_errno is set.
4604  */
4605 static int
4606 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags,
4607 				    const struct rte_flow_action *action,
4608 				    const uint64_t item_flags,
4609 				    struct rte_flow_error *error)
4610 {
4611 	int ret = 0;
4612 	uint64_t layer;
4613 
4614 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4615 	if (!ret) {
4616 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4617 				 MLX5_FLOW_LAYER_INNER_L3_IPV6 :
4618 				 MLX5_FLOW_LAYER_OUTER_L3_IPV6;
4619 		if (!(item_flags & layer))
4620 			return rte_flow_error_set(error, EINVAL,
4621 						  RTE_FLOW_ERROR_TYPE_ACTION,
4622 						  NULL,
4623 						  "no ipv6 item in pattern");
4624 	}
4625 	return ret;
4626 }
4627 
4628 /**
4629  * Validate the modify-header TP actions.
4630  *
4631  * @param[in] action_flags
4632  *   Holds the actions detected until now.
4633  * @param[in] action
4634  *   Pointer to the modify action.
4635  * @param[in] item_flags
4636  *   Holds the items detected.
4637  * @param[out] error
4638  *   Pointer to error structure.
4639  *
4640  * @return
4641  *   0 on success, a negative errno value otherwise and rte_errno is set.
4642  */
4643 static int
4644 flow_dv_validate_action_modify_tp(const uint64_t action_flags,
4645 				  const struct rte_flow_action *action,
4646 				  const uint64_t item_flags,
4647 				  struct rte_flow_error *error)
4648 {
4649 	int ret = 0;
4650 	uint64_t layer;
4651 
4652 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4653 	if (!ret) {
4654 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4655 				 MLX5_FLOW_LAYER_INNER_L4 :
4656 				 MLX5_FLOW_LAYER_OUTER_L4;
4657 		if (!(item_flags & layer))
4658 			return rte_flow_error_set(error, EINVAL,
4659 						  RTE_FLOW_ERROR_TYPE_ACTION,
4660 						  NULL, "no transport layer "
4661 						  "in pattern");
4662 	}
4663 	return ret;
4664 }
4665 
4666 /**
4667  * Validate the modify-header actions of increment/decrement
4668  * TCP Sequence-number.
4669  *
4670  * @param[in] action_flags
4671  *   Holds the actions detected until now.
4672  * @param[in] action
4673  *   Pointer to the modify action.
4674  * @param[in] item_flags
4675  *   Holds the items detected.
4676  * @param[out] error
4677  *   Pointer to error structure.
4678  *
4679  * @return
4680  *   0 on success, a negative errno value otherwise and rte_errno is set.
4681  */
4682 static int
4683 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags,
4684 				       const struct rte_flow_action *action,
4685 				       const uint64_t item_flags,
4686 				       struct rte_flow_error *error)
4687 {
4688 	int ret = 0;
4689 	uint64_t layer;
4690 
4691 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4692 	if (!ret) {
4693 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4694 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4695 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4696 		if (!(item_flags & layer))
4697 			return rte_flow_error_set(error, EINVAL,
4698 						  RTE_FLOW_ERROR_TYPE_ACTION,
4699 						  NULL, "no TCP item in"
4700 						  " pattern");
4701 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ &&
4702 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) ||
4703 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ &&
4704 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ)))
4705 			return rte_flow_error_set(error, EINVAL,
4706 						  RTE_FLOW_ERROR_TYPE_ACTION,
4707 						  NULL,
4708 						  "cannot decrease and increase"
4709 						  " TCP sequence number"
4710 						  " at the same time");
4711 	}
4712 	return ret;
4713 }
4714 
4715 /**
4716  * Validate the modify-header actions of increment/decrement
4717  * TCP Acknowledgment number.
4718  *
4719  * @param[in] action_flags
4720  *   Holds the actions detected until now.
4721  * @param[in] action
4722  *   Pointer to the modify action.
4723  * @param[in] item_flags
4724  *   Holds the items detected.
4725  * @param[out] error
4726  *   Pointer to error structure.
4727  *
4728  * @return
4729  *   0 on success, a negative errno value otherwise and rte_errno is set.
4730  */
4731 static int
4732 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags,
4733 				       const struct rte_flow_action *action,
4734 				       const uint64_t item_flags,
4735 				       struct rte_flow_error *error)
4736 {
4737 	int ret = 0;
4738 	uint64_t layer;
4739 
4740 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4741 	if (!ret) {
4742 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4743 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4744 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4745 		if (!(item_flags & layer))
4746 			return rte_flow_error_set(error, EINVAL,
4747 						  RTE_FLOW_ERROR_TYPE_ACTION,
4748 						  NULL, "no TCP item in"
4749 						  " pattern");
4750 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK &&
4751 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) ||
4752 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK &&
4753 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK)))
4754 			return rte_flow_error_set(error, EINVAL,
4755 						  RTE_FLOW_ERROR_TYPE_ACTION,
4756 						  NULL,
4757 						  "cannot decrease and increase"
4758 						  " TCP acknowledgment number"
4759 						  " at the same time");
4760 	}
4761 	return ret;
4762 }
4763 
4764 /**
4765  * Validate the modify-header TTL actions.
4766  *
4767  * @param[in] action_flags
4768  *   Holds the actions detected until now.
4769  * @param[in] action
4770  *   Pointer to the modify action.
4771  * @param[in] item_flags
4772  *   Holds the items detected.
4773  * @param[out] error
4774  *   Pointer to error structure.
4775  *
4776  * @return
4777  *   0 on success, a negative errno value otherwise and rte_errno is set.
4778  */
4779 static int
4780 flow_dv_validate_action_modify_ttl(const uint64_t action_flags,
4781 				   const struct rte_flow_action *action,
4782 				   const uint64_t item_flags,
4783 				   struct rte_flow_error *error)
4784 {
4785 	int ret = 0;
4786 	uint64_t layer;
4787 
4788 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4789 	if (!ret) {
4790 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4791 				 MLX5_FLOW_LAYER_INNER_L3 :
4792 				 MLX5_FLOW_LAYER_OUTER_L3;
4793 		if (!(item_flags & layer))
4794 			return rte_flow_error_set(error, EINVAL,
4795 						  RTE_FLOW_ERROR_TYPE_ACTION,
4796 						  NULL,
4797 						  "no IP protocol in pattern");
4798 	}
4799 	return ret;
4800 }
4801 
4802 /**
4803  * Validate the generic modify field actions.
4804  * @param[in] dev
4805  *   Pointer to the rte_eth_dev structure.
4806  * @param[in] action_flags
4807  *   Holds the actions detected until now.
4808  * @param[in] action
4809  *   Pointer to the modify action.
4810  * @param[in] attr
4811  *   Pointer to the flow attributes.
4812  * @param[out] error
4813  *   Pointer to error structure.
4814  *
4815  * @return
4816  *   Number of header fields to modify (0 or more) on success,
4817  *   a negative errno value otherwise and rte_errno is set.
4818  */
4819 static int
4820 flow_dv_validate_action_modify_field(struct rte_eth_dev *dev,
4821 				   const uint64_t action_flags,
4822 				   const struct rte_flow_action *action,
4823 				   const struct rte_flow_attr *attr,
4824 				   struct rte_flow_error *error)
4825 {
4826 	int ret = 0;
4827 	struct mlx5_priv *priv = dev->data->dev_private;
4828 	struct mlx5_dev_config *config = &priv->config;
4829 	const struct rte_flow_action_modify_field *action_modify_field =
4830 		action->conf;
4831 	uint32_t dst_width = mlx5_flow_item_field_width(dev,
4832 				action_modify_field->dst.field,
4833 				-1, attr, error);
4834 	uint32_t src_width = mlx5_flow_item_field_width(dev,
4835 				action_modify_field->src.field,
4836 				dst_width, attr, error);
4837 
4838 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4839 	if (ret)
4840 		return ret;
4841 
4842 	if (action_modify_field->width == 0)
4843 		return rte_flow_error_set(error, EINVAL,
4844 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4845 				"no bits are requested to be modified");
4846 	else if (action_modify_field->width > dst_width ||
4847 		 action_modify_field->width > src_width)
4848 		return rte_flow_error_set(error, EINVAL,
4849 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4850 				"cannot modify more bits than"
4851 				" the width of a field");
4852 	if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE &&
4853 	    action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) {
4854 		if ((action_modify_field->dst.offset +
4855 		     action_modify_field->width > dst_width) ||
4856 		    (action_modify_field->dst.offset % 32))
4857 			return rte_flow_error_set(error, EINVAL,
4858 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4859 					"destination offset is too big"
4860 					" or not aligned to 4 bytes");
4861 		if (action_modify_field->dst.level &&
4862 		    action_modify_field->dst.field != RTE_FLOW_FIELD_TAG)
4863 			return rte_flow_error_set(error, ENOTSUP,
4864 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4865 					"inner header fields modification"
4866 					" is not supported");
4867 	}
4868 	if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE &&
4869 	    action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) {
4870 		if (!attr->transfer && !attr->group)
4871 			return rte_flow_error_set(error, ENOTSUP,
4872 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4873 					"modify field action is not"
4874 					" supported for group 0");
4875 		if ((action_modify_field->src.offset +
4876 		     action_modify_field->width > src_width) ||
4877 		    (action_modify_field->src.offset % 32))
4878 			return rte_flow_error_set(error, EINVAL,
4879 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4880 					"source offset is too big"
4881 					" or not aligned to 4 bytes");
4882 		if (action_modify_field->src.level &&
4883 		    action_modify_field->src.field != RTE_FLOW_FIELD_TAG)
4884 			return rte_flow_error_set(error, ENOTSUP,
4885 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4886 					"inner header fields modification"
4887 					" is not supported");
4888 	}
4889 	if ((action_modify_field->dst.field ==
4890 	     action_modify_field->src.field) &&
4891 	    (action_modify_field->dst.level ==
4892 	     action_modify_field->src.level))
4893 		return rte_flow_error_set(error, EINVAL,
4894 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4895 				"source and destination fields"
4896 				" cannot be the same");
4897 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE ||
4898 	    action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER ||
4899 	    action_modify_field->dst.field == RTE_FLOW_FIELD_MARK)
4900 		return rte_flow_error_set(error, EINVAL,
4901 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4902 				"mark, immediate value or a pointer to it"
4903 				" cannot be used as a destination");
4904 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_START ||
4905 	    action_modify_field->src.field == RTE_FLOW_FIELD_START)
4906 		return rte_flow_error_set(error, ENOTSUP,
4907 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4908 				"modifications of an arbitrary"
4909 				" place in a packet is not supported");
4910 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VLAN_TYPE ||
4911 	    action_modify_field->src.field == RTE_FLOW_FIELD_VLAN_TYPE)
4912 		return rte_flow_error_set(error, ENOTSUP,
4913 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4914 				"modifications of the 802.1Q Tag"
4915 				" Identifier is not supported");
4916 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VXLAN_VNI ||
4917 	    action_modify_field->src.field == RTE_FLOW_FIELD_VXLAN_VNI)
4918 		return rte_flow_error_set(error, ENOTSUP,
4919 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4920 				"modifications of the VXLAN Network"
4921 				" Identifier is not supported");
4922 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_GENEVE_VNI ||
4923 	    action_modify_field->src.field == RTE_FLOW_FIELD_GENEVE_VNI)
4924 		return rte_flow_error_set(error, ENOTSUP,
4925 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4926 				"modifications of the GENEVE Network"
4927 				" Identifier is not supported");
4928 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_MARK ||
4929 	    action_modify_field->src.field == RTE_FLOW_FIELD_MARK)
4930 		if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||
4931 		    !mlx5_flow_ext_mreg_supported(dev))
4932 			return rte_flow_error_set(error, ENOTSUP,
4933 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4934 					"cannot modify mark in legacy mode"
4935 					" or without extensive registers");
4936 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_META ||
4937 	    action_modify_field->src.field == RTE_FLOW_FIELD_META) {
4938 		if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
4939 		    !mlx5_flow_ext_mreg_supported(dev))
4940 			return rte_flow_error_set(error, ENOTSUP,
4941 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4942 					"cannot modify meta without"
4943 					" extensive registers support");
4944 		ret = flow_dv_get_metadata_reg(dev, attr, error);
4945 		if (ret < 0 || ret == REG_NON)
4946 			return rte_flow_error_set(error, ENOTSUP,
4947 					RTE_FLOW_ERROR_TYPE_ACTION, action,
4948 					"cannot modify meta without"
4949 					" extensive registers available");
4950 	}
4951 	if (action_modify_field->operation != RTE_FLOW_MODIFY_SET)
4952 		return rte_flow_error_set(error, ENOTSUP,
4953 				RTE_FLOW_ERROR_TYPE_ACTION, action,
4954 				"add and sub operations"
4955 				" are not supported");
4956 	return (action_modify_field->width / 32) +
4957 	       !!(action_modify_field->width % 32);
4958 }
4959 
4960 /**
4961  * Validate jump action.
4962  *
4963  * @param[in] action
4964  *   Pointer to the jump action.
4965  * @param[in] action_flags
4966  *   Holds the actions detected until now.
4967  * @param[in] attributes
4968  *   Pointer to flow attributes
4969  * @param[in] external
4970  *   Action belongs to flow rule created by request external to PMD.
4971  * @param[out] error
4972  *   Pointer to error structure.
4973  *
4974  * @return
4975  *   0 on success, a negative errno value otherwise and rte_errno is set.
4976  */
4977 static int
4978 flow_dv_validate_action_jump(struct rte_eth_dev *dev,
4979 			     const struct mlx5_flow_tunnel *tunnel,
4980 			     const struct rte_flow_action *action,
4981 			     uint64_t action_flags,
4982 			     const struct rte_flow_attr *attributes,
4983 			     bool external, struct rte_flow_error *error)
4984 {
4985 	uint32_t target_group, table;
4986 	int ret = 0;
4987 	struct flow_grp_info grp_info = {
4988 		.external = !!external,
4989 		.transfer = !!attributes->transfer,
4990 		.fdb_def_rule = 1,
4991 		.std_tbl_fix = 0
4992 	};
4993 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
4994 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
4995 		return rte_flow_error_set(error, EINVAL,
4996 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4997 					  "can't have 2 fate actions in"
4998 					  " same flow");
4999 	if (!action->conf)
5000 		return rte_flow_error_set(error, EINVAL,
5001 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5002 					  NULL, "action configuration not set");
5003 	target_group =
5004 		((const struct rte_flow_action_jump *)action->conf)->group;
5005 	ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table,
5006 				       &grp_info, error);
5007 	if (ret)
5008 		return ret;
5009 	if (attributes->group == target_group &&
5010 	    !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET |
5011 			      MLX5_FLOW_ACTION_TUNNEL_MATCH)))
5012 		return rte_flow_error_set(error, EINVAL,
5013 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5014 					  "target group must be other than"
5015 					  " the current flow group");
5016 	return 0;
5017 }
5018 
5019 /*
5020  * Validate action PORT_ID / REPRESENTED_PORT.
5021  *
5022  * @param[in] dev
5023  *   Pointer to rte_eth_dev structure.
5024  * @param[in] action_flags
5025  *   Bit-fields that holds the actions detected until now.
5026  * @param[in] action
5027  *   PORT_ID / REPRESENTED_PORT action structure.
5028  * @param[in] attr
5029  *   Attributes of flow that includes this action.
5030  * @param[out] error
5031  *   Pointer to error structure.
5032  *
5033  * @return
5034  *   0 on success, a negative errno value otherwise and rte_errno is set.
5035  */
5036 static int
5037 flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
5038 				uint64_t action_flags,
5039 				const struct rte_flow_action *action,
5040 				const struct rte_flow_attr *attr,
5041 				struct rte_flow_error *error)
5042 {
5043 	const struct rte_flow_action_port_id *port_id;
5044 	const struct rte_flow_action_ethdev *ethdev;
5045 	struct mlx5_priv *act_priv;
5046 	struct mlx5_priv *dev_priv;
5047 	uint16_t port;
5048 
5049 	if (!attr->transfer)
5050 		return rte_flow_error_set(error, ENOTSUP,
5051 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5052 					  NULL,
5053 					  "port action is valid in transfer"
5054 					  " mode only");
5055 	if (!action || !action->conf)
5056 		return rte_flow_error_set(error, ENOTSUP,
5057 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5058 					  NULL,
5059 					  "port action parameters must be"
5060 					  " specified");
5061 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
5062 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
5063 		return rte_flow_error_set(error, EINVAL,
5064 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5065 					  "can have only one fate actions in"
5066 					  " a flow");
5067 	dev_priv = mlx5_dev_to_eswitch_info(dev);
5068 	if (!dev_priv)
5069 		return rte_flow_error_set(error, rte_errno,
5070 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5071 					  NULL,
5072 					  "failed to obtain E-Switch info");
5073 	switch (action->type) {
5074 	case RTE_FLOW_ACTION_TYPE_PORT_ID:
5075 		port_id = action->conf;
5076 		port = port_id->original ? dev->data->port_id : port_id->id;
5077 		break;
5078 	case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
5079 		ethdev = action->conf;
5080 		port = ethdev->port_id;
5081 		break;
5082 	default:
5083 		MLX5_ASSERT(false);
5084 		return rte_flow_error_set
5085 				(error, EINVAL,
5086 				 RTE_FLOW_ERROR_TYPE_ACTION, action,
5087 				 "unknown E-Switch action");
5088 	}
5089 	act_priv = mlx5_port_to_eswitch_info(port, false);
5090 	if (!act_priv)
5091 		return rte_flow_error_set
5092 				(error, rte_errno,
5093 				 RTE_FLOW_ERROR_TYPE_ACTION_CONF, action->conf,
5094 				 "failed to obtain E-Switch port id for port");
5095 	if (act_priv->domain_id != dev_priv->domain_id)
5096 		return rte_flow_error_set
5097 				(error, EINVAL,
5098 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5099 				 "port does not belong to"
5100 				 " E-Switch being configured");
5101 	return 0;
5102 }
5103 
5104 /**
5105  * Get the maximum number of modify header actions.
5106  *
5107  * @param dev
5108  *   Pointer to rte_eth_dev structure.
5109  * @param root
5110  *   Whether action is on root table.
5111  *
5112  * @return
5113  *   Max number of modify header actions device can support.
5114  */
5115 static inline unsigned int
5116 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused,
5117 			      bool root)
5118 {
5119 	/*
5120 	 * There's no way to directly query the max capacity from FW.
5121 	 * The maximal value on root table should be assumed to be supported.
5122 	 */
5123 	if (!root)
5124 		return MLX5_MAX_MODIFY_NUM;
5125 	else
5126 		return MLX5_ROOT_TBL_MODIFY_NUM;
5127 }
5128 
5129 /**
5130  * Validate the meter action.
5131  *
5132  * @param[in] dev
5133  *   Pointer to rte_eth_dev structure.
5134  * @param[in] action_flags
5135  *   Bit-fields that holds the actions detected until now.
5136  * @param[in] item_flags
5137  *   Holds the items detected.
5138  * @param[in] action
5139  *   Pointer to the meter action.
5140  * @param[in] attr
5141  *   Attributes of flow that includes this action.
5142  * @param[in] port_id_item
5143  *   Pointer to item indicating port id.
5144  * @param[out] error
5145  *   Pointer to error structure.
5146  *
5147  * @return
5148  *   0 on success, a negative errno value otherwise and rte_ernno is set.
5149  */
5150 static int
5151 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
5152 				uint64_t action_flags, uint64_t item_flags,
5153 				const struct rte_flow_action *action,
5154 				const struct rte_flow_attr *attr,
5155 				const struct rte_flow_item *port_id_item,
5156 				bool *def_policy,
5157 				struct rte_flow_error *error)
5158 {
5159 	struct mlx5_priv *priv = dev->data->dev_private;
5160 	const struct rte_flow_action_meter *am = action->conf;
5161 	struct mlx5_flow_meter_info *fm;
5162 	struct mlx5_flow_meter_policy *mtr_policy;
5163 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
5164 
5165 	if (!am)
5166 		return rte_flow_error_set(error, EINVAL,
5167 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5168 					  "meter action conf is NULL");
5169 
5170 	if (action_flags & MLX5_FLOW_ACTION_METER)
5171 		return rte_flow_error_set(error, ENOTSUP,
5172 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5173 					  "meter chaining not support");
5174 	if (action_flags & MLX5_FLOW_ACTION_JUMP)
5175 		return rte_flow_error_set(error, ENOTSUP,
5176 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5177 					  "meter with jump not support");
5178 	if (!priv->mtr_en)
5179 		return rte_flow_error_set(error, ENOTSUP,
5180 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5181 					  NULL,
5182 					  "meter action not supported");
5183 	fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL);
5184 	if (!fm)
5185 		return rte_flow_error_set(error, EINVAL,
5186 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5187 					  "Meter not found");
5188 	/* aso meter can always be shared by different domains */
5189 	if (fm->ref_cnt && !priv->sh->meter_aso_en &&
5190 	    !(fm->transfer == attr->transfer ||
5191 	      (!fm->ingress && !attr->ingress && attr->egress) ||
5192 	      (!fm->egress && !attr->egress && attr->ingress)))
5193 		return rte_flow_error_set(error, EINVAL,
5194 			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5195 			"Flow attributes domain are either invalid "
5196 			"or have a domain conflict with current "
5197 			"meter attributes");
5198 	if (fm->def_policy) {
5199 		if (!((attr->transfer &&
5200 			mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
5201 			(attr->egress &&
5202 			mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
5203 			(attr->ingress &&
5204 			mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
5205 			return rte_flow_error_set(error, EINVAL,
5206 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5207 					  "Flow attributes domain "
5208 					  "have a conflict with current "
5209 					  "meter domain attributes");
5210 		*def_policy = true;
5211 	} else {
5212 		mtr_policy = mlx5_flow_meter_policy_find(dev,
5213 						fm->policy_id, NULL);
5214 		if (!mtr_policy)
5215 			return rte_flow_error_set(error, EINVAL,
5216 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5217 					  "Invalid policy id for meter ");
5218 		if (!((attr->transfer && mtr_policy->transfer) ||
5219 			(attr->egress && mtr_policy->egress) ||
5220 			(attr->ingress && mtr_policy->ingress)))
5221 			return rte_flow_error_set(error, EINVAL,
5222 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5223 					  "Flow attributes domain "
5224 					  "have a conflict with current "
5225 					  "meter domain attributes");
5226 		if (attr->transfer && mtr_policy->dev) {
5227 			/**
5228 			 * When policy has fate action of port_id,
5229 			 * the flow should have the same src port as policy.
5230 			 */
5231 			struct mlx5_priv *policy_port_priv =
5232 					mtr_policy->dev->data->dev_private;
5233 			int32_t flow_src_port = priv->representor_id;
5234 
5235 			if (port_id_item) {
5236 				const struct rte_flow_item_port_id *spec =
5237 							port_id_item->spec;
5238 				struct mlx5_priv *port_priv =
5239 					mlx5_port_to_eswitch_info(spec->id,
5240 								  false);
5241 				if (!port_priv)
5242 					return rte_flow_error_set(error,
5243 						rte_errno,
5244 						RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
5245 						spec,
5246 						"Failed to get port info.");
5247 				flow_src_port = port_priv->representor_id;
5248 			}
5249 			if (flow_src_port != policy_port_priv->representor_id)
5250 				return rte_flow_error_set(error,
5251 						rte_errno,
5252 						RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
5253 						NULL,
5254 						"Flow and meter policy "
5255 						"have different src port.");
5256 		} else if (mtr_policy->is_rss) {
5257 			struct mlx5_flow_meter_policy *fp;
5258 			struct mlx5_meter_policy_action_container *acg;
5259 			struct mlx5_meter_policy_action_container *acy;
5260 			const struct rte_flow_action *rss_act;
5261 			int ret;
5262 
5263 			fp = mlx5_flow_meter_hierarchy_get_final_policy(dev,
5264 								mtr_policy);
5265 			if (fp == NULL)
5266 				return rte_flow_error_set(error, EINVAL,
5267 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5268 						  "Unable to get the final "
5269 						  "policy in the hierarchy");
5270 			acg = &fp->act_cnt[RTE_COLOR_GREEN];
5271 			acy = &fp->act_cnt[RTE_COLOR_YELLOW];
5272 			MLX5_ASSERT(acg->fate_action ==
5273 				    MLX5_FLOW_FATE_SHARED_RSS ||
5274 				    acy->fate_action ==
5275 				    MLX5_FLOW_FATE_SHARED_RSS);
5276 			if (acg->fate_action == MLX5_FLOW_FATE_SHARED_RSS)
5277 				rss_act = acg->rss;
5278 			else
5279 				rss_act = acy->rss;
5280 			ret = mlx5_flow_validate_action_rss(rss_act,
5281 					action_flags, dev, attr,
5282 					item_flags, error);
5283 			if (ret)
5284 				return ret;
5285 		}
5286 		*def_policy = false;
5287 	}
5288 	return 0;
5289 }
5290 
5291 /**
5292  * Validate the age action.
5293  *
5294  * @param[in] action_flags
5295  *   Holds the actions detected until now.
5296  * @param[in] action
5297  *   Pointer to the age action.
5298  * @param[in] dev
5299  *   Pointer to the Ethernet device structure.
5300  * @param[out] error
5301  *   Pointer to error structure.
5302  *
5303  * @return
5304  *   0 on success, a negative errno value otherwise and rte_errno is set.
5305  */
5306 static int
5307 flow_dv_validate_action_age(uint64_t action_flags,
5308 			    const struct rte_flow_action *action,
5309 			    struct rte_eth_dev *dev,
5310 			    struct rte_flow_error *error)
5311 {
5312 	struct mlx5_priv *priv = dev->data->dev_private;
5313 	const struct rte_flow_action_age *age = action->conf;
5314 
5315 	if (!priv->sh->devx || (priv->sh->cmng.counter_fallback &&
5316 	    !priv->sh->aso_age_mng))
5317 		return rte_flow_error_set(error, ENOTSUP,
5318 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5319 					  NULL,
5320 					  "age action not supported");
5321 	if (!(action->conf))
5322 		return rte_flow_error_set(error, EINVAL,
5323 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5324 					  "configuration cannot be null");
5325 	if (!(age->timeout))
5326 		return rte_flow_error_set(error, EINVAL,
5327 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5328 					  "invalid timeout value 0");
5329 	if (action_flags & MLX5_FLOW_ACTION_AGE)
5330 		return rte_flow_error_set(error, EINVAL,
5331 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5332 					  "duplicate age actions set");
5333 	return 0;
5334 }
5335 
5336 /**
5337  * Validate the modify-header IPv4 DSCP actions.
5338  *
5339  * @param[in] action_flags
5340  *   Holds the actions detected until now.
5341  * @param[in] action
5342  *   Pointer to the modify action.
5343  * @param[in] item_flags
5344  *   Holds the items detected.
5345  * @param[out] error
5346  *   Pointer to error structure.
5347  *
5348  * @return
5349  *   0 on success, a negative errno value otherwise and rte_errno is set.
5350  */
5351 static int
5352 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags,
5353 					 const struct rte_flow_action *action,
5354 					 const uint64_t item_flags,
5355 					 struct rte_flow_error *error)
5356 {
5357 	int ret = 0;
5358 
5359 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5360 	if (!ret) {
5361 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4))
5362 			return rte_flow_error_set(error, EINVAL,
5363 						  RTE_FLOW_ERROR_TYPE_ACTION,
5364 						  NULL,
5365 						  "no ipv4 item in pattern");
5366 	}
5367 	return ret;
5368 }
5369 
5370 /**
5371  * Validate the modify-header IPv6 DSCP actions.
5372  *
5373  * @param[in] action_flags
5374  *   Holds the actions detected until now.
5375  * @param[in] action
5376  *   Pointer to the modify action.
5377  * @param[in] item_flags
5378  *   Holds the items detected.
5379  * @param[out] error
5380  *   Pointer to error structure.
5381  *
5382  * @return
5383  *   0 on success, a negative errno value otherwise and rte_errno is set.
5384  */
5385 static int
5386 flow_dv_validate_action_modify_ipv6_dscp(const uint64_t action_flags,
5387 					 const struct rte_flow_action *action,
5388 					 const uint64_t item_flags,
5389 					 struct rte_flow_error *error)
5390 {
5391 	int ret = 0;
5392 
5393 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5394 	if (!ret) {
5395 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6))
5396 			return rte_flow_error_set(error, EINVAL,
5397 						  RTE_FLOW_ERROR_TYPE_ACTION,
5398 						  NULL,
5399 						  "no ipv6 item in pattern");
5400 	}
5401 	return ret;
5402 }
5403 
5404 int
5405 flow_dv_modify_match_cb(void *tool_ctx __rte_unused,
5406 			struct mlx5_list_entry *entry, void *cb_ctx)
5407 {
5408 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5409 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5410 	struct mlx5_flow_dv_modify_hdr_resource *resource =
5411 				  container_of(entry, typeof(*resource), entry);
5412 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5413 
5414 	key_len += ref->actions_num * sizeof(ref->actions[0]);
5415 	return ref->actions_num != resource->actions_num ||
5416 	       memcmp(&ref->ft_type, &resource->ft_type, key_len);
5417 }
5418 
5419 static struct mlx5_indexed_pool *
5420 flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index)
5421 {
5422 	struct mlx5_indexed_pool *ipool = __atomic_load_n
5423 				     (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST);
5424 
5425 	if (!ipool) {
5426 		struct mlx5_indexed_pool *expected = NULL;
5427 		struct mlx5_indexed_pool_config cfg =
5428 		    (struct mlx5_indexed_pool_config) {
5429 		       .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
5430 								   (index + 1) *
5431 					   sizeof(struct mlx5_modification_cmd),
5432 		       .trunk_size = 64,
5433 		       .grow_trunk = 3,
5434 		       .grow_shift = 2,
5435 		       .need_lock = 1,
5436 		       .release_mem_en = !!sh->reclaim_mode,
5437 		       .per_core_cache = sh->reclaim_mode ? 0 : (1 << 16),
5438 		       .malloc = mlx5_malloc,
5439 		       .free = mlx5_free,
5440 		       .type = "mlx5_modify_action_resource",
5441 		};
5442 
5443 		cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool));
5444 		ipool = mlx5_ipool_create(&cfg);
5445 		if (!ipool)
5446 			return NULL;
5447 		if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index],
5448 						 &expected, ipool, false,
5449 						 __ATOMIC_SEQ_CST,
5450 						 __ATOMIC_SEQ_CST)) {
5451 			mlx5_ipool_destroy(ipool);
5452 			ipool = __atomic_load_n(&sh->mdh_ipools[index],
5453 						__ATOMIC_SEQ_CST);
5454 		}
5455 	}
5456 	return ipool;
5457 }
5458 
5459 struct mlx5_list_entry *
5460 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx)
5461 {
5462 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5463 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5464 	struct mlx5dv_dr_domain *ns;
5465 	struct mlx5_flow_dv_modify_hdr_resource *entry;
5466 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5467 	struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh,
5468 							  ref->actions_num - 1);
5469 	int ret;
5470 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5471 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5472 	uint32_t idx;
5473 
5474 	if (unlikely(!ipool)) {
5475 		rte_flow_error_set(ctx->error, ENOMEM,
5476 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5477 				   NULL, "cannot allocate modify ipool");
5478 		return NULL;
5479 	}
5480 	entry = mlx5_ipool_zmalloc(ipool, &idx);
5481 	if (!entry) {
5482 		rte_flow_error_set(ctx->error, ENOMEM,
5483 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5484 				   "cannot allocate resource memory");
5485 		return NULL;
5486 	}
5487 	rte_memcpy(&entry->ft_type,
5488 		   RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)),
5489 		   key_len + data_len);
5490 	if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
5491 		ns = sh->fdb_domain;
5492 	else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
5493 		ns = sh->tx_domain;
5494 	else
5495 		ns = sh->rx_domain;
5496 	ret = mlx5_flow_os_create_flow_action_modify_header
5497 					(sh->cdev->ctx, ns, entry,
5498 					 data_len, &entry->action);
5499 	if (ret) {
5500 		mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx);
5501 		rte_flow_error_set(ctx->error, ENOMEM,
5502 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5503 				   NULL, "cannot create modification action");
5504 		return NULL;
5505 	}
5506 	entry->idx = idx;
5507 	return &entry->entry;
5508 }
5509 
5510 struct mlx5_list_entry *
5511 flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
5512 			void *cb_ctx)
5513 {
5514 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5515 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5516 	struct mlx5_flow_dv_modify_hdr_resource *entry;
5517 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5518 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5519 	uint32_t idx;
5520 
5521 	entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1],
5522 				  &idx);
5523 	if (!entry) {
5524 		rte_flow_error_set(ctx->error, ENOMEM,
5525 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5526 				   "cannot allocate resource memory");
5527 		return NULL;
5528 	}
5529 	memcpy(entry, oentry, sizeof(*entry) + data_len);
5530 	entry->idx = idx;
5531 	return &entry->entry;
5532 }
5533 
5534 void
5535 flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
5536 {
5537 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5538 	struct mlx5_flow_dv_modify_hdr_resource *res =
5539 		container_of(entry, typeof(*res), entry);
5540 
5541 	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
5542 }
5543 
5544 /**
5545  * Validate the sample action.
5546  *
5547  * @param[in, out] action_flags
5548  *   Holds the actions detected until now.
5549  * @param[in] action
5550  *   Pointer to the sample action.
5551  * @param[in] dev
5552  *   Pointer to the Ethernet device structure.
5553  * @param[in] attr
5554  *   Attributes of flow that includes this action.
5555  * @param[in] item_flags
5556  *   Holds the items detected.
5557  * @param[in] rss
5558  *   Pointer to the RSS action.
5559  * @param[out] sample_rss
5560  *   Pointer to the RSS action in sample action list.
5561  * @param[out] count
5562  *   Pointer to the COUNT action in sample action list.
5563  * @param[out] fdb_mirror_limit
5564  *   Pointer to the FDB mirror limitation flag.
5565  * @param[out] error
5566  *   Pointer to error structure.
5567  *
5568  * @return
5569  *   0 on success, a negative errno value otherwise and rte_errno is set.
5570  */
5571 static int
5572 flow_dv_validate_action_sample(uint64_t *action_flags,
5573 			       const struct rte_flow_action *action,
5574 			       struct rte_eth_dev *dev,
5575 			       const struct rte_flow_attr *attr,
5576 			       uint64_t item_flags,
5577 			       const struct rte_flow_action_rss *rss,
5578 			       const struct rte_flow_action_rss **sample_rss,
5579 			       const struct rte_flow_action_count **count,
5580 			       int *fdb_mirror_limit,
5581 			       struct rte_flow_error *error)
5582 {
5583 	struct mlx5_priv *priv = dev->data->dev_private;
5584 	struct mlx5_dev_config *dev_conf = &priv->config;
5585 	const struct rte_flow_action_sample *sample = action->conf;
5586 	const struct rte_flow_action *act;
5587 	uint64_t sub_action_flags = 0;
5588 	uint16_t queue_index = 0xFFFF;
5589 	int actions_n = 0;
5590 	int ret;
5591 
5592 	if (!sample)
5593 		return rte_flow_error_set(error, EINVAL,
5594 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5595 					  "configuration cannot be NULL");
5596 	if (sample->ratio == 0)
5597 		return rte_flow_error_set(error, EINVAL,
5598 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5599 					  "ratio value starts from 1");
5600 	if (!priv->sh->devx || (sample->ratio > 0 && !priv->sampler_en))
5601 		return rte_flow_error_set(error, ENOTSUP,
5602 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5603 					  NULL,
5604 					  "sample action not supported");
5605 	if (*action_flags & MLX5_FLOW_ACTION_SAMPLE)
5606 		return rte_flow_error_set(error, EINVAL,
5607 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5608 					  "Multiple sample actions not "
5609 					  "supported");
5610 	if (*action_flags & MLX5_FLOW_ACTION_METER)
5611 		return rte_flow_error_set(error, EINVAL,
5612 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5613 					  "wrong action order, meter should "
5614 					  "be after sample action");
5615 	if (*action_flags & MLX5_FLOW_ACTION_JUMP)
5616 		return rte_flow_error_set(error, EINVAL,
5617 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5618 					  "wrong action order, jump should "
5619 					  "be after sample action");
5620 	if (*action_flags & MLX5_FLOW_ACTION_CT)
5621 		return rte_flow_error_set(error, EINVAL,
5622 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5623 					  "Sample after CT not supported");
5624 	act = sample->actions;
5625 	for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
5626 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
5627 			return rte_flow_error_set(error, ENOTSUP,
5628 						  RTE_FLOW_ERROR_TYPE_ACTION,
5629 						  act, "too many actions");
5630 		switch (act->type) {
5631 		case RTE_FLOW_ACTION_TYPE_QUEUE:
5632 			ret = mlx5_flow_validate_action_queue(act,
5633 							      sub_action_flags,
5634 							      dev,
5635 							      attr, error);
5636 			if (ret < 0)
5637 				return ret;
5638 			queue_index = ((const struct rte_flow_action_queue *)
5639 							(act->conf))->index;
5640 			sub_action_flags |= MLX5_FLOW_ACTION_QUEUE;
5641 			++actions_n;
5642 			break;
5643 		case RTE_FLOW_ACTION_TYPE_RSS:
5644 			*sample_rss = act->conf;
5645 			ret = mlx5_flow_validate_action_rss(act,
5646 							    sub_action_flags,
5647 							    dev, attr,
5648 							    item_flags,
5649 							    error);
5650 			if (ret < 0)
5651 				return ret;
5652 			if (rss && *sample_rss &&
5653 			    ((*sample_rss)->level != rss->level ||
5654 			    (*sample_rss)->types != rss->types))
5655 				return rte_flow_error_set(error, ENOTSUP,
5656 					RTE_FLOW_ERROR_TYPE_ACTION,
5657 					NULL,
5658 					"Can't use the different RSS types "
5659 					"or level in the same flow");
5660 			if (*sample_rss != NULL && (*sample_rss)->queue_num)
5661 				queue_index = (*sample_rss)->queue[0];
5662 			sub_action_flags |= MLX5_FLOW_ACTION_RSS;
5663 			++actions_n;
5664 			break;
5665 		case RTE_FLOW_ACTION_TYPE_MARK:
5666 			ret = flow_dv_validate_action_mark(dev, act,
5667 							   sub_action_flags,
5668 							   attr, error);
5669 			if (ret < 0)
5670 				return ret;
5671 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)
5672 				sub_action_flags |= MLX5_FLOW_ACTION_MARK |
5673 						MLX5_FLOW_ACTION_MARK_EXT;
5674 			else
5675 				sub_action_flags |= MLX5_FLOW_ACTION_MARK;
5676 			++actions_n;
5677 			break;
5678 		case RTE_FLOW_ACTION_TYPE_COUNT:
5679 			ret = flow_dv_validate_action_count
5680 				(dev, false, *action_flags | sub_action_flags,
5681 				 error);
5682 			if (ret < 0)
5683 				return ret;
5684 			*count = act->conf;
5685 			sub_action_flags |= MLX5_FLOW_ACTION_COUNT;
5686 			*action_flags |= MLX5_FLOW_ACTION_COUNT;
5687 			++actions_n;
5688 			break;
5689 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
5690 		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
5691 			ret = flow_dv_validate_action_port_id(dev,
5692 							      sub_action_flags,
5693 							      act,
5694 							      attr,
5695 							      error);
5696 			if (ret)
5697 				return ret;
5698 			sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID;
5699 			++actions_n;
5700 			break;
5701 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
5702 			ret = flow_dv_validate_action_raw_encap_decap
5703 				(dev, NULL, act->conf, attr, &sub_action_flags,
5704 				 &actions_n, action, item_flags, error);
5705 			if (ret < 0)
5706 				return ret;
5707 			++actions_n;
5708 			break;
5709 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5710 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
5711 			ret = flow_dv_validate_action_l2_encap(dev,
5712 							       sub_action_flags,
5713 							       act, attr,
5714 							       error);
5715 			if (ret < 0)
5716 				return ret;
5717 			sub_action_flags |= MLX5_FLOW_ACTION_ENCAP;
5718 			++actions_n;
5719 			break;
5720 		default:
5721 			return rte_flow_error_set(error, ENOTSUP,
5722 						  RTE_FLOW_ERROR_TYPE_ACTION,
5723 						  NULL,
5724 						  "Doesn't support optional "
5725 						  "action");
5726 		}
5727 	}
5728 	if (attr->ingress && !attr->transfer) {
5729 		if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE |
5730 					  MLX5_FLOW_ACTION_RSS)))
5731 			return rte_flow_error_set(error, EINVAL,
5732 						  RTE_FLOW_ERROR_TYPE_ACTION,
5733 						  NULL,
5734 						  "Ingress must has a dest "
5735 						  "QUEUE for Sample");
5736 	} else if (attr->egress && !attr->transfer) {
5737 		return rte_flow_error_set(error, ENOTSUP,
5738 					  RTE_FLOW_ERROR_TYPE_ACTION,
5739 					  NULL,
5740 					  "Sample Only support Ingress "
5741 					  "or E-Switch");
5742 	} else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) {
5743 		MLX5_ASSERT(attr->transfer);
5744 		if (sample->ratio > 1)
5745 			return rte_flow_error_set(error, ENOTSUP,
5746 						  RTE_FLOW_ERROR_TYPE_ACTION,
5747 						  NULL,
5748 						  "E-Switch doesn't support "
5749 						  "any optional action "
5750 						  "for sampling");
5751 		if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE)
5752 			return rte_flow_error_set(error, ENOTSUP,
5753 						  RTE_FLOW_ERROR_TYPE_ACTION,
5754 						  NULL,
5755 						  "unsupported action QUEUE");
5756 		if (sub_action_flags & MLX5_FLOW_ACTION_RSS)
5757 			return rte_flow_error_set(error, ENOTSUP,
5758 						  RTE_FLOW_ERROR_TYPE_ACTION,
5759 						  NULL,
5760 						  "unsupported action QUEUE");
5761 		if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID))
5762 			return rte_flow_error_set(error, EINVAL,
5763 						  RTE_FLOW_ERROR_TYPE_ACTION,
5764 						  NULL,
5765 						  "E-Switch must has a dest "
5766 						  "port for mirroring");
5767 		if (!priv->config.hca_attr.reg_c_preserve &&
5768 		     priv->representor_id != UINT16_MAX)
5769 			*fdb_mirror_limit = 1;
5770 	}
5771 	/* Continue validation for Xcap actions.*/
5772 	if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) &&
5773 	    (queue_index == 0xFFFF ||
5774 	     mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN)) {
5775 		if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
5776 		     MLX5_FLOW_XCAP_ACTIONS)
5777 			return rte_flow_error_set(error, ENOTSUP,
5778 						  RTE_FLOW_ERROR_TYPE_ACTION,
5779 						  NULL, "encap and decap "
5780 						  "combination aren't "
5781 						  "supported");
5782 		if (!attr->transfer && attr->ingress && (sub_action_flags &
5783 							MLX5_FLOW_ACTION_ENCAP))
5784 			return rte_flow_error_set(error, ENOTSUP,
5785 						  RTE_FLOW_ERROR_TYPE_ACTION,
5786 						  NULL, "encap is not supported"
5787 						  " for ingress traffic");
5788 	}
5789 	return 0;
5790 }
5791 
5792 /**
5793  * Find existing modify-header resource or create and register a new one.
5794  *
5795  * @param dev[in, out]
5796  *   Pointer to rte_eth_dev structure.
5797  * @param[in, out] resource
5798  *   Pointer to modify-header resource.
5799  * @parm[in, out] dev_flow
5800  *   Pointer to the dev_flow.
5801  * @param[out] error
5802  *   pointer to error structure.
5803  *
5804  * @return
5805  *   0 on success otherwise -errno and errno is set.
5806  */
5807 static int
5808 flow_dv_modify_hdr_resource_register
5809 			(struct rte_eth_dev *dev,
5810 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
5811 			 struct mlx5_flow *dev_flow,
5812 			 struct rte_flow_error *error)
5813 {
5814 	struct mlx5_priv *priv = dev->data->dev_private;
5815 	struct mlx5_dev_ctx_shared *sh = priv->sh;
5816 	uint32_t key_len = sizeof(*resource) -
5817 			   offsetof(typeof(*resource), ft_type) +
5818 			   resource->actions_num * sizeof(resource->actions[0]);
5819 	struct mlx5_list_entry *entry;
5820 	struct mlx5_flow_cb_ctx ctx = {
5821 		.error = error,
5822 		.data = resource,
5823 	};
5824 	struct mlx5_hlist *modify_cmds;
5825 	uint64_t key64;
5826 
5827 	modify_cmds = flow_dv_hlist_prepare(sh, &sh->modify_cmds,
5828 				"hdr_modify",
5829 				MLX5_FLOW_HDR_MODIFY_HTABLE_SZ,
5830 				true, false, sh,
5831 				flow_dv_modify_create_cb,
5832 				flow_dv_modify_match_cb,
5833 				flow_dv_modify_remove_cb,
5834 				flow_dv_modify_clone_cb,
5835 				flow_dv_modify_clone_free_cb);
5836 	if (unlikely(!modify_cmds))
5837 		return -rte_errno;
5838 	resource->root = !dev_flow->dv.group;
5839 	if (resource->actions_num > flow_dv_modify_hdr_action_max(dev,
5840 								resource->root))
5841 		return rte_flow_error_set(error, EOVERFLOW,
5842 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5843 					  "too many modify header items");
5844 	key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0);
5845 	entry = mlx5_hlist_register(modify_cmds, key64, &ctx);
5846 	if (!entry)
5847 		return -rte_errno;
5848 	resource = container_of(entry, typeof(*resource), entry);
5849 	dev_flow->handle->dvh.modify_hdr = resource;
5850 	return 0;
5851 }
5852 
5853 /**
5854  * Get DV flow counter by index.
5855  *
5856  * @param[in] dev
5857  *   Pointer to the Ethernet device structure.
5858  * @param[in] idx
5859  *   mlx5 flow counter index in the container.
5860  * @param[out] ppool
5861  *   mlx5 flow counter pool in the container.
5862  *
5863  * @return
5864  *   Pointer to the counter, NULL otherwise.
5865  */
5866 static struct mlx5_flow_counter *
5867 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev,
5868 			   uint32_t idx,
5869 			   struct mlx5_flow_counter_pool **ppool)
5870 {
5871 	struct mlx5_priv *priv = dev->data->dev_private;
5872 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5873 	struct mlx5_flow_counter_pool *pool;
5874 
5875 	/* Decrease to original index and clear shared bit. */
5876 	idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
5877 	MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < cmng->n);
5878 	pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
5879 	MLX5_ASSERT(pool);
5880 	if (ppool)
5881 		*ppool = pool;
5882 	return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
5883 }
5884 
5885 /**
5886  * Check the devx counter belongs to the pool.
5887  *
5888  * @param[in] pool
5889  *   Pointer to the counter pool.
5890  * @param[in] id
5891  *   The counter devx ID.
5892  *
5893  * @return
5894  *   True if counter belongs to the pool, false otherwise.
5895  */
5896 static bool
5897 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id)
5898 {
5899 	int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) *
5900 		   MLX5_COUNTERS_PER_POOL;
5901 
5902 	if (id >= base && id < base + MLX5_COUNTERS_PER_POOL)
5903 		return true;
5904 	return false;
5905 }
5906 
5907 /**
5908  * Get a pool by devx counter ID.
5909  *
5910  * @param[in] cmng
5911  *   Pointer to the counter management.
5912  * @param[in] id
5913  *   The counter devx ID.
5914  *
5915  * @return
5916  *   The counter pool pointer if exists, NULL otherwise,
5917  */
5918 static struct mlx5_flow_counter_pool *
5919 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id)
5920 {
5921 	uint32_t i;
5922 	struct mlx5_flow_counter_pool *pool = NULL;
5923 
5924 	rte_spinlock_lock(&cmng->pool_update_sl);
5925 	/* Check last used pool. */
5926 	if (cmng->last_pool_idx != POOL_IDX_INVALID &&
5927 	    flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) {
5928 		pool = cmng->pools[cmng->last_pool_idx];
5929 		goto out;
5930 	}
5931 	/* ID out of range means no suitable pool in the container. */
5932 	if (id > cmng->max_id || id < cmng->min_id)
5933 		goto out;
5934 	/*
5935 	 * Find the pool from the end of the container, since mostly counter
5936 	 * ID is sequence increasing, and the last pool should be the needed
5937 	 * one.
5938 	 */
5939 	i = cmng->n_valid;
5940 	while (i--) {
5941 		struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i];
5942 
5943 		if (flow_dv_is_counter_in_pool(pool_tmp, id)) {
5944 			pool = pool_tmp;
5945 			break;
5946 		}
5947 	}
5948 out:
5949 	rte_spinlock_unlock(&cmng->pool_update_sl);
5950 	return pool;
5951 }
5952 
5953 /**
5954  * Resize a counter container.
5955  *
5956  * @param[in] dev
5957  *   Pointer to the Ethernet device structure.
5958  *
5959  * @return
5960  *   0 on success, otherwise negative errno value and rte_errno is set.
5961  */
5962 static int
5963 flow_dv_container_resize(struct rte_eth_dev *dev)
5964 {
5965 	struct mlx5_priv *priv = dev->data->dev_private;
5966 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
5967 	void *old_pools = cmng->pools;
5968 	uint32_t resize = cmng->n + MLX5_CNT_CONTAINER_RESIZE;
5969 	uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize;
5970 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
5971 
5972 	if (!pools) {
5973 		rte_errno = ENOMEM;
5974 		return -ENOMEM;
5975 	}
5976 	if (old_pools)
5977 		memcpy(pools, old_pools, cmng->n *
5978 				       sizeof(struct mlx5_flow_counter_pool *));
5979 	cmng->n = resize;
5980 	cmng->pools = pools;
5981 	if (old_pools)
5982 		mlx5_free(old_pools);
5983 	return 0;
5984 }
5985 
5986 /**
5987  * Query a devx flow counter.
5988  *
5989  * @param[in] dev
5990  *   Pointer to the Ethernet device structure.
5991  * @param[in] counter
5992  *   Index to the flow counter.
5993  * @param[out] pkts
5994  *   The statistics value of packets.
5995  * @param[out] bytes
5996  *   The statistics value of bytes.
5997  *
5998  * @return
5999  *   0 on success, otherwise a negative errno value and rte_errno is set.
6000  */
6001 static inline int
6002 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts,
6003 		     uint64_t *bytes)
6004 {
6005 	struct mlx5_priv *priv = dev->data->dev_private;
6006 	struct mlx5_flow_counter_pool *pool = NULL;
6007 	struct mlx5_flow_counter *cnt;
6008 	int offset;
6009 
6010 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
6011 	MLX5_ASSERT(pool);
6012 	if (priv->sh->cmng.counter_fallback)
6013 		return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0,
6014 					0, pkts, bytes, 0, NULL, NULL, 0);
6015 	rte_spinlock_lock(&pool->sl);
6016 	if (!pool->raw) {
6017 		*pkts = 0;
6018 		*bytes = 0;
6019 	} else {
6020 		offset = MLX5_CNT_ARRAY_IDX(pool, cnt);
6021 		*pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits);
6022 		*bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes);
6023 	}
6024 	rte_spinlock_unlock(&pool->sl);
6025 	return 0;
6026 }
6027 
6028 /**
6029  * Create and initialize a new counter pool.
6030  *
6031  * @param[in] dev
6032  *   Pointer to the Ethernet device structure.
6033  * @param[out] dcs
6034  *   The devX counter handle.
6035  * @param[in] age
6036  *   Whether the pool is for counter that was allocated for aging.
6037  * @param[in/out] cont_cur
6038  *   Pointer to the container pointer, it will be update in pool resize.
6039  *
6040  * @return
6041  *   The pool container pointer on success, NULL otherwise and rte_errno is set.
6042  */
6043 static struct mlx5_flow_counter_pool *
6044 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
6045 		    uint32_t age)
6046 {
6047 	struct mlx5_priv *priv = dev->data->dev_private;
6048 	struct mlx5_flow_counter_pool *pool;
6049 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6050 	bool fallback = priv->sh->cmng.counter_fallback;
6051 	uint32_t size = sizeof(*pool);
6052 
6053 	size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE;
6054 	size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE);
6055 	pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
6056 	if (!pool) {
6057 		rte_errno = ENOMEM;
6058 		return NULL;
6059 	}
6060 	pool->raw = NULL;
6061 	pool->is_aged = !!age;
6062 	pool->query_gen = 0;
6063 	pool->min_dcs = dcs;
6064 	rte_spinlock_init(&pool->sl);
6065 	rte_spinlock_init(&pool->csl);
6066 	TAILQ_INIT(&pool->counters[0]);
6067 	TAILQ_INIT(&pool->counters[1]);
6068 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
6069 	rte_spinlock_lock(&cmng->pool_update_sl);
6070 	pool->index = cmng->n_valid;
6071 	if (pool->index == cmng->n && flow_dv_container_resize(dev)) {
6072 		mlx5_free(pool);
6073 		rte_spinlock_unlock(&cmng->pool_update_sl);
6074 		return NULL;
6075 	}
6076 	cmng->pools[pool->index] = pool;
6077 	cmng->n_valid++;
6078 	if (unlikely(fallback)) {
6079 		int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL);
6080 
6081 		if (base < cmng->min_id)
6082 			cmng->min_id = base;
6083 		if (base > cmng->max_id)
6084 			cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1;
6085 		cmng->last_pool_idx = pool->index;
6086 	}
6087 	rte_spinlock_unlock(&cmng->pool_update_sl);
6088 	return pool;
6089 }
6090 
6091 /**
6092  * Prepare a new counter and/or a new counter pool.
6093  *
6094  * @param[in] dev
6095  *   Pointer to the Ethernet device structure.
6096  * @param[out] cnt_free
6097  *   Where to put the pointer of a new counter.
6098  * @param[in] age
6099  *   Whether the pool is for counter that was allocated for aging.
6100  *
6101  * @return
6102  *   The counter pool pointer and @p cnt_free is set on success,
6103  *   NULL otherwise and rte_errno is set.
6104  */
6105 static struct mlx5_flow_counter_pool *
6106 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev,
6107 			     struct mlx5_flow_counter **cnt_free,
6108 			     uint32_t age)
6109 {
6110 	struct mlx5_priv *priv = dev->data->dev_private;
6111 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6112 	struct mlx5_flow_counter_pool *pool;
6113 	struct mlx5_counters tmp_tq;
6114 	struct mlx5_devx_obj *dcs = NULL;
6115 	struct mlx5_flow_counter *cnt;
6116 	enum mlx5_counter_type cnt_type =
6117 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6118 	bool fallback = priv->sh->cmng.counter_fallback;
6119 	uint32_t i;
6120 
6121 	if (fallback) {
6122 		/* bulk_bitmap must be 0 for single counter allocation. */
6123 		dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0);
6124 		if (!dcs)
6125 			return NULL;
6126 		pool = flow_dv_find_pool_by_id(cmng, dcs->id);
6127 		if (!pool) {
6128 			pool = flow_dv_pool_create(dev, dcs, age);
6129 			if (!pool) {
6130 				mlx5_devx_cmd_destroy(dcs);
6131 				return NULL;
6132 			}
6133 		}
6134 		i = dcs->id % MLX5_COUNTERS_PER_POOL;
6135 		cnt = MLX5_POOL_GET_CNT(pool, i);
6136 		cnt->pool = pool;
6137 		cnt->dcs_when_free = dcs;
6138 		*cnt_free = cnt;
6139 		return pool;
6140 	}
6141 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4);
6142 	if (!dcs) {
6143 		rte_errno = ENODATA;
6144 		return NULL;
6145 	}
6146 	pool = flow_dv_pool_create(dev, dcs, age);
6147 	if (!pool) {
6148 		mlx5_devx_cmd_destroy(dcs);
6149 		return NULL;
6150 	}
6151 	TAILQ_INIT(&tmp_tq);
6152 	for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) {
6153 		cnt = MLX5_POOL_GET_CNT(pool, i);
6154 		cnt->pool = pool;
6155 		TAILQ_INSERT_HEAD(&tmp_tq, cnt, next);
6156 	}
6157 	rte_spinlock_lock(&cmng->csl[cnt_type]);
6158 	TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next);
6159 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
6160 	*cnt_free = MLX5_POOL_GET_CNT(pool, 0);
6161 	(*cnt_free)->pool = pool;
6162 	return pool;
6163 }
6164 
6165 /**
6166  * Allocate a flow counter.
6167  *
6168  * @param[in] dev
6169  *   Pointer to the Ethernet device structure.
6170  * @param[in] age
6171  *   Whether the counter was allocated for aging.
6172  *
6173  * @return
6174  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
6175  */
6176 static uint32_t
6177 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age)
6178 {
6179 	struct mlx5_priv *priv = dev->data->dev_private;
6180 	struct mlx5_flow_counter_pool *pool = NULL;
6181 	struct mlx5_flow_counter *cnt_free = NULL;
6182 	bool fallback = priv->sh->cmng.counter_fallback;
6183 	struct mlx5_flow_counter_mng *cmng = &priv->sh->cmng;
6184 	enum mlx5_counter_type cnt_type =
6185 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6186 	uint32_t cnt_idx;
6187 
6188 	if (!priv->sh->devx) {
6189 		rte_errno = ENOTSUP;
6190 		return 0;
6191 	}
6192 	/* Get free counters from container. */
6193 	rte_spinlock_lock(&cmng->csl[cnt_type]);
6194 	cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]);
6195 	if (cnt_free)
6196 		TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next);
6197 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
6198 	if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age))
6199 		goto err;
6200 	pool = cnt_free->pool;
6201 	if (fallback)
6202 		cnt_free->dcs_when_active = cnt_free->dcs_when_free;
6203 	/* Create a DV counter action only in the first time usage. */
6204 	if (!cnt_free->action) {
6205 		uint16_t offset;
6206 		struct mlx5_devx_obj *dcs;
6207 		int ret;
6208 
6209 		if (!fallback) {
6210 			offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free);
6211 			dcs = pool->min_dcs;
6212 		} else {
6213 			offset = 0;
6214 			dcs = cnt_free->dcs_when_free;
6215 		}
6216 		ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset,
6217 							    &cnt_free->action);
6218 		if (ret) {
6219 			rte_errno = errno;
6220 			goto err;
6221 		}
6222 	}
6223 	cnt_idx = MLX5_MAKE_CNT_IDX(pool->index,
6224 				MLX5_CNT_ARRAY_IDX(pool, cnt_free));
6225 	/* Update the counter reset values. */
6226 	if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits,
6227 				 &cnt_free->bytes))
6228 		goto err;
6229 	if (!fallback && !priv->sh->cmng.query_thread_on)
6230 		/* Start the asynchronous batch query by the host thread. */
6231 		mlx5_set_query_alarm(priv->sh);
6232 	/*
6233 	 * When the count action isn't shared (by ID), shared_info field is
6234 	 * used for indirect action API's refcnt.
6235 	 * When the counter action is not shared neither by ID nor by indirect
6236 	 * action API, shared info must be 1.
6237 	 */
6238 	cnt_free->shared_info.refcnt = 1;
6239 	return cnt_idx;
6240 err:
6241 	if (cnt_free) {
6242 		cnt_free->pool = pool;
6243 		if (fallback)
6244 			cnt_free->dcs_when_free = cnt_free->dcs_when_active;
6245 		rte_spinlock_lock(&cmng->csl[cnt_type]);
6246 		TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next);
6247 		rte_spinlock_unlock(&cmng->csl[cnt_type]);
6248 	}
6249 	return 0;
6250 }
6251 
6252 /**
6253  * Get age param from counter index.
6254  *
6255  * @param[in] dev
6256  *   Pointer to the Ethernet device structure.
6257  * @param[in] counter
6258  *   Index to the counter handler.
6259  *
6260  * @return
6261  *   The aging parameter specified for the counter index.
6262  */
6263 static struct mlx5_age_param*
6264 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev,
6265 				uint32_t counter)
6266 {
6267 	struct mlx5_flow_counter *cnt;
6268 	struct mlx5_flow_counter_pool *pool = NULL;
6269 
6270 	flow_dv_counter_get_by_idx(dev, counter, &pool);
6271 	counter = (counter - 1) % MLX5_COUNTERS_PER_POOL;
6272 	cnt = MLX5_POOL_GET_CNT(pool, counter);
6273 	return MLX5_CNT_TO_AGE(cnt);
6274 }
6275 
6276 /**
6277  * Remove a flow counter from aged counter list.
6278  *
6279  * @param[in] dev
6280  *   Pointer to the Ethernet device structure.
6281  * @param[in] counter
6282  *   Index to the counter handler.
6283  * @param[in] cnt
6284  *   Pointer to the counter handler.
6285  */
6286 static void
6287 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev,
6288 				uint32_t counter, struct mlx5_flow_counter *cnt)
6289 {
6290 	struct mlx5_age_info *age_info;
6291 	struct mlx5_age_param *age_param;
6292 	struct mlx5_priv *priv = dev->data->dev_private;
6293 	uint16_t expected = AGE_CANDIDATE;
6294 
6295 	age_info = GET_PORT_AGE_INFO(priv);
6296 	age_param = flow_dv_counter_idx_get_age(dev, counter);
6297 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
6298 					 AGE_FREE, false, __ATOMIC_RELAXED,
6299 					 __ATOMIC_RELAXED)) {
6300 		/**
6301 		 * We need the lock even it is age timeout,
6302 		 * since counter may still in process.
6303 		 */
6304 		rte_spinlock_lock(&age_info->aged_sl);
6305 		TAILQ_REMOVE(&age_info->aged_counters, cnt, next);
6306 		rte_spinlock_unlock(&age_info->aged_sl);
6307 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
6308 	}
6309 }
6310 
6311 /**
6312  * Release a flow counter.
6313  *
6314  * @param[in] dev
6315  *   Pointer to the Ethernet device structure.
6316  * @param[in] counter
6317  *   Index to the counter handler.
6318  */
6319 static void
6320 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter)
6321 {
6322 	struct mlx5_priv *priv = dev->data->dev_private;
6323 	struct mlx5_flow_counter_pool *pool = NULL;
6324 	struct mlx5_flow_counter *cnt;
6325 	enum mlx5_counter_type cnt_type;
6326 
6327 	if (!counter)
6328 		return;
6329 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
6330 	MLX5_ASSERT(pool);
6331 	if (pool->is_aged) {
6332 		flow_dv_counter_remove_from_age(dev, counter, cnt);
6333 	} else {
6334 		/*
6335 		 * If the counter action is shared by indirect action API,
6336 		 * the atomic function reduces its references counter.
6337 		 * If after the reduction the action is still referenced, the
6338 		 * function returns here and does not release it.
6339 		 * When the counter action is not shared by
6340 		 * indirect action API, shared info is 1 before the reduction,
6341 		 * so this condition is failed and function doesn't return here.
6342 		 */
6343 		if (__atomic_sub_fetch(&cnt->shared_info.refcnt, 1,
6344 				       __ATOMIC_RELAXED))
6345 			return;
6346 	}
6347 	cnt->pool = pool;
6348 	/*
6349 	 * Put the counter back to list to be updated in none fallback mode.
6350 	 * Currently, we are using two list alternately, while one is in query,
6351 	 * add the freed counter to the other list based on the pool query_gen
6352 	 * value. After query finishes, add counter the list to the global
6353 	 * container counter list. The list changes while query starts. In
6354 	 * this case, lock will not be needed as query callback and release
6355 	 * function both operate with the different list.
6356 	 */
6357 	if (!priv->sh->cmng.counter_fallback) {
6358 		rte_spinlock_lock(&pool->csl);
6359 		TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next);
6360 		rte_spinlock_unlock(&pool->csl);
6361 	} else {
6362 		cnt->dcs_when_free = cnt->dcs_when_active;
6363 		cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE :
6364 					   MLX5_COUNTER_TYPE_ORIGIN;
6365 		rte_spinlock_lock(&priv->sh->cmng.csl[cnt_type]);
6366 		TAILQ_INSERT_TAIL(&priv->sh->cmng.counters[cnt_type],
6367 				  cnt, next);
6368 		rte_spinlock_unlock(&priv->sh->cmng.csl[cnt_type]);
6369 	}
6370 }
6371 
6372 /**
6373  * Resize a meter id container.
6374  *
6375  * @param[in] dev
6376  *   Pointer to the Ethernet device structure.
6377  *
6378  * @return
6379  *   0 on success, otherwise negative errno value and rte_errno is set.
6380  */
6381 static int
6382 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
6383 {
6384 	struct mlx5_priv *priv = dev->data->dev_private;
6385 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6386 				&priv->sh->mtrmng->pools_mng;
6387 	void *old_pools = pools_mng->pools;
6388 	uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
6389 	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
6390 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
6391 
6392 	if (!pools) {
6393 		rte_errno = ENOMEM;
6394 		return -ENOMEM;
6395 	}
6396 	if (!pools_mng->n)
6397 		if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {
6398 			mlx5_free(pools);
6399 			return -ENOMEM;
6400 		}
6401 	if (old_pools)
6402 		memcpy(pools, old_pools, pools_mng->n *
6403 				       sizeof(struct mlx5_aso_mtr_pool *));
6404 	pools_mng->n = resize;
6405 	pools_mng->pools = pools;
6406 	if (old_pools)
6407 		mlx5_free(old_pools);
6408 	return 0;
6409 }
6410 
6411 /**
6412  * Prepare a new meter and/or a new meter pool.
6413  *
6414  * @param[in] dev
6415  *   Pointer to the Ethernet device structure.
6416  * @param[out] mtr_free
6417  *   Where to put the pointer of a new meter.g.
6418  *
6419  * @return
6420  *   The meter pool pointer and @mtr_free is set on success,
6421  *   NULL otherwise and rte_errno is set.
6422  */
6423 static struct mlx5_aso_mtr_pool *
6424 flow_dv_mtr_pool_create(struct rte_eth_dev *dev, struct mlx5_aso_mtr **mtr_free)
6425 {
6426 	struct mlx5_priv *priv = dev->data->dev_private;
6427 	struct mlx5_aso_mtr_pools_mng *pools_mng = &priv->sh->mtrmng->pools_mng;
6428 	struct mlx5_aso_mtr_pool *pool = NULL;
6429 	struct mlx5_devx_obj *dcs = NULL;
6430 	uint32_t i;
6431 	uint32_t log_obj_size;
6432 
6433 	log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1);
6434 	dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->cdev->ctx,
6435 						      priv->sh->cdev->pdn,
6436 						      log_obj_size);
6437 	if (!dcs) {
6438 		rte_errno = ENODATA;
6439 		return NULL;
6440 	}
6441 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
6442 	if (!pool) {
6443 		rte_errno = ENOMEM;
6444 		claim_zero(mlx5_devx_cmd_destroy(dcs));
6445 		return NULL;
6446 	}
6447 	pool->devx_obj = dcs;
6448 	rte_rwlock_write_lock(&pools_mng->resize_mtrwl);
6449 	pool->index = pools_mng->n_valid;
6450 	if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
6451 		mlx5_free(pool);
6452 		claim_zero(mlx5_devx_cmd_destroy(dcs));
6453 		rte_rwlock_write_unlock(&pools_mng->resize_mtrwl);
6454 		return NULL;
6455 	}
6456 	pools_mng->pools[pool->index] = pool;
6457 	pools_mng->n_valid++;
6458 	rte_rwlock_write_unlock(&pools_mng->resize_mtrwl);
6459 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
6460 		pool->mtrs[i].offset = i;
6461 		LIST_INSERT_HEAD(&pools_mng->meters, &pool->mtrs[i], next);
6462 	}
6463 	pool->mtrs[0].offset = 0;
6464 	*mtr_free = &pool->mtrs[0];
6465 	return pool;
6466 }
6467 
6468 /**
6469  * Release a flow meter into pool.
6470  *
6471  * @param[in] dev
6472  *   Pointer to the Ethernet device structure.
6473  * @param[in] mtr_idx
6474  *   Index to aso flow meter.
6475  */
6476 static void
6477 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
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 *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
6483 
6484 	MLX5_ASSERT(aso_mtr);
6485 	rte_spinlock_lock(&pools_mng->mtrsl);
6486 	memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
6487 	aso_mtr->state = ASO_METER_FREE;
6488 	LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
6489 	rte_spinlock_unlock(&pools_mng->mtrsl);
6490 }
6491 
6492 /**
6493  * Allocate a aso flow meter.
6494  *
6495  * @param[in] dev
6496  *   Pointer to the Ethernet device structure.
6497  *
6498  * @return
6499  *   Index to aso flow meter on success, 0 otherwise and rte_errno is set.
6500  */
6501 static uint32_t
6502 flow_dv_mtr_alloc(struct rte_eth_dev *dev)
6503 {
6504 	struct mlx5_priv *priv = dev->data->dev_private;
6505 	struct mlx5_aso_mtr *mtr_free = NULL;
6506 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6507 				&priv->sh->mtrmng->pools_mng;
6508 	struct mlx5_aso_mtr_pool *pool;
6509 	uint32_t mtr_idx = 0;
6510 
6511 	if (!priv->sh->devx) {
6512 		rte_errno = ENOTSUP;
6513 		return 0;
6514 	}
6515 	/* Allocate the flow meter memory. */
6516 	/* Get free meters from management. */
6517 	rte_spinlock_lock(&pools_mng->mtrsl);
6518 	mtr_free = LIST_FIRST(&pools_mng->meters);
6519 	if (mtr_free)
6520 		LIST_REMOVE(mtr_free, next);
6521 	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
6522 		rte_spinlock_unlock(&pools_mng->mtrsl);
6523 		return 0;
6524 	}
6525 	mtr_free->state = ASO_METER_WAIT;
6526 	rte_spinlock_unlock(&pools_mng->mtrsl);
6527 	pool = container_of(mtr_free,
6528 			struct mlx5_aso_mtr_pool,
6529 			mtrs[mtr_free->offset]);
6530 	mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
6531 	if (!mtr_free->fm.meter_action) {
6532 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
6533 		struct rte_flow_error error;
6534 		uint8_t reg_id;
6535 
6536 		reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error);
6537 		mtr_free->fm.meter_action =
6538 			mlx5_glue->dv_create_flow_action_aso
6539 						(priv->sh->rx_domain,
6540 						 pool->devx_obj->obj,
6541 						 mtr_free->offset,
6542 						 (1 << MLX5_FLOW_COLOR_GREEN),
6543 						 reg_id - REG_C_0);
6544 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
6545 		if (!mtr_free->fm.meter_action) {
6546 			flow_dv_aso_mtr_release_to_pool(dev, mtr_idx);
6547 			return 0;
6548 		}
6549 	}
6550 	return mtr_idx;
6551 }
6552 
6553 /**
6554  * Verify the @p attributes will be correctly understood by the NIC and store
6555  * them in the @p flow if everything is correct.
6556  *
6557  * @param[in] dev
6558  *   Pointer to dev struct.
6559  * @param[in] attributes
6560  *   Pointer to flow attributes
6561  * @param[in] external
6562  *   This flow rule is created by request external to PMD.
6563  * @param[out] error
6564  *   Pointer to error structure.
6565  *
6566  * @return
6567  *   - 0 on success and non root table.
6568  *   - 1 on success and root table.
6569  *   - a negative errno value otherwise and rte_errno is set.
6570  */
6571 static int
6572 flow_dv_validate_attributes(struct rte_eth_dev *dev,
6573 			    const struct mlx5_flow_tunnel *tunnel,
6574 			    const struct rte_flow_attr *attributes,
6575 			    const struct flow_grp_info *grp_info,
6576 			    struct rte_flow_error *error)
6577 {
6578 	struct mlx5_priv *priv = dev->data->dev_private;
6579 	uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes);
6580 	int ret = 0;
6581 
6582 #ifndef HAVE_MLX5DV_DR
6583 	RTE_SET_USED(tunnel);
6584 	RTE_SET_USED(grp_info);
6585 	if (attributes->group)
6586 		return rte_flow_error_set(error, ENOTSUP,
6587 					  RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
6588 					  NULL,
6589 					  "groups are not supported");
6590 #else
6591 	uint32_t table = 0;
6592 
6593 	ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table,
6594 				       grp_info, error);
6595 	if (ret)
6596 		return ret;
6597 	if (!table)
6598 		ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
6599 #endif
6600 	if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR &&
6601 	    attributes->priority > lowest_priority)
6602 		return rte_flow_error_set(error, ENOTSUP,
6603 					  RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
6604 					  NULL,
6605 					  "priority out of range");
6606 	if (attributes->transfer) {
6607 		if (!priv->config.dv_esw_en)
6608 			return rte_flow_error_set
6609 				(error, ENOTSUP,
6610 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
6611 				 "E-Switch dr is not supported");
6612 		if (!(priv->representor || priv->master))
6613 			return rte_flow_error_set
6614 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6615 				 NULL, "E-Switch configuration can only be"
6616 				 " done by a master or a representor device");
6617 		if (attributes->egress)
6618 			return rte_flow_error_set
6619 				(error, ENOTSUP,
6620 				 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes,
6621 				 "egress is not supported");
6622 	}
6623 	if (!(attributes->egress ^ attributes->ingress))
6624 		return rte_flow_error_set(error, ENOTSUP,
6625 					  RTE_FLOW_ERROR_TYPE_ATTR, NULL,
6626 					  "must specify exactly one of "
6627 					  "ingress or egress");
6628 	return ret;
6629 }
6630 
6631 static int
6632 validate_integrity_bits(const struct rte_flow_item_integrity *mask,
6633 			int64_t pattern_flags, uint64_t l3_flags,
6634 			uint64_t l4_flags, uint64_t ip4_flag,
6635 			struct rte_flow_error *error)
6636 {
6637 	if (mask->l3_ok && !(pattern_flags & l3_flags))
6638 		return rte_flow_error_set(error, EINVAL,
6639 					  RTE_FLOW_ERROR_TYPE_ITEM,
6640 					  NULL, "missing L3 protocol");
6641 
6642 	if (mask->ipv4_csum_ok && !(pattern_flags & ip4_flag))
6643 		return rte_flow_error_set(error, EINVAL,
6644 					  RTE_FLOW_ERROR_TYPE_ITEM,
6645 					  NULL, "missing IPv4 protocol");
6646 
6647 	if ((mask->l4_ok || mask->l4_csum_ok) && !(pattern_flags & l4_flags))
6648 		return rte_flow_error_set(error, EINVAL,
6649 					  RTE_FLOW_ERROR_TYPE_ITEM,
6650 					  NULL, "missing L4 protocol");
6651 
6652 	return 0;
6653 }
6654 
6655 static int
6656 flow_dv_validate_item_integrity_post(const struct
6657 				     rte_flow_item *integrity_items[2],
6658 				     int64_t pattern_flags,
6659 				     struct rte_flow_error *error)
6660 {
6661 	const struct rte_flow_item_integrity *mask;
6662 	int ret;
6663 
6664 	if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) {
6665 		mask = (typeof(mask))integrity_items[0]->mask;
6666 		ret = validate_integrity_bits(mask, pattern_flags,
6667 					      MLX5_FLOW_LAYER_OUTER_L3,
6668 					      MLX5_FLOW_LAYER_OUTER_L4,
6669 					      MLX5_FLOW_LAYER_OUTER_L3_IPV4,
6670 					      error);
6671 		if (ret)
6672 			return ret;
6673 	}
6674 	if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) {
6675 		mask = (typeof(mask))integrity_items[1]->mask;
6676 		ret = validate_integrity_bits(mask, pattern_flags,
6677 					      MLX5_FLOW_LAYER_INNER_L3,
6678 					      MLX5_FLOW_LAYER_INNER_L4,
6679 					      MLX5_FLOW_LAYER_INNER_L3_IPV4,
6680 					      error);
6681 		if (ret)
6682 			return ret;
6683 	}
6684 	return 0;
6685 }
6686 
6687 static int
6688 flow_dv_validate_item_integrity(struct rte_eth_dev *dev,
6689 				const struct rte_flow_item *integrity_item,
6690 				uint64_t pattern_flags, uint64_t *last_item,
6691 				const struct rte_flow_item *integrity_items[2],
6692 				struct rte_flow_error *error)
6693 {
6694 	struct mlx5_priv *priv = dev->data->dev_private;
6695 	const struct rte_flow_item_integrity *mask = (typeof(mask))
6696 						     integrity_item->mask;
6697 	const struct rte_flow_item_integrity *spec = (typeof(spec))
6698 						     integrity_item->spec;
6699 
6700 	if (!priv->config.hca_attr.pkt_integrity_match)
6701 		return rte_flow_error_set(error, ENOTSUP,
6702 					  RTE_FLOW_ERROR_TYPE_ITEM,
6703 					  integrity_item,
6704 					  "packet integrity integrity_item not supported");
6705 	if (!spec)
6706 		return rte_flow_error_set(error, ENOTSUP,
6707 					  RTE_FLOW_ERROR_TYPE_ITEM,
6708 					  integrity_item,
6709 					  "no spec for integrity item");
6710 	if (!mask)
6711 		mask = &rte_flow_item_integrity_mask;
6712 	if (!mlx5_validate_integrity_item(mask))
6713 		return rte_flow_error_set(error, ENOTSUP,
6714 					  RTE_FLOW_ERROR_TYPE_ITEM,
6715 					  integrity_item,
6716 					  "unsupported integrity filter");
6717 	if (spec->level > 1) {
6718 		if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY)
6719 			return rte_flow_error_set
6720 				(error, ENOTSUP,
6721 				 RTE_FLOW_ERROR_TYPE_ITEM,
6722 				 NULL, "multiple inner integrity items not supported");
6723 		integrity_items[1] = integrity_item;
6724 		*last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY;
6725 	} else {
6726 		if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY)
6727 			return rte_flow_error_set
6728 				(error, ENOTSUP,
6729 				 RTE_FLOW_ERROR_TYPE_ITEM,
6730 				 NULL, "multiple outer integrity items not supported");
6731 		integrity_items[0] = integrity_item;
6732 		*last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY;
6733 	}
6734 	return 0;
6735 }
6736 
6737 static int
6738 flow_dv_validate_item_flex(struct rte_eth_dev *dev,
6739 			   const struct rte_flow_item *item,
6740 			   uint64_t item_flags,
6741 			   uint64_t *last_item,
6742 			   bool is_inner,
6743 			   struct rte_flow_error *error)
6744 {
6745 	const struct rte_flow_item_flex *flow_spec = item->spec;
6746 	const struct rte_flow_item_flex *flow_mask = item->mask;
6747 	struct mlx5_flex_item *flex;
6748 
6749 	if (!flow_spec)
6750 		return rte_flow_error_set(error, EINVAL,
6751 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
6752 					  "flex flow item spec cannot be NULL");
6753 	if (!flow_mask)
6754 		return rte_flow_error_set(error, EINVAL,
6755 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
6756 					  "flex flow item mask cannot be NULL");
6757 	if (item->last)
6758 		return rte_flow_error_set(error, ENOTSUP,
6759 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
6760 					  "flex flow item last not supported");
6761 	if (mlx5_flex_acquire_index(dev, flow_spec->handle, false) < 0)
6762 		return rte_flow_error_set(error, EINVAL,
6763 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
6764 					  "invalid flex flow item handle");
6765 	flex = (struct mlx5_flex_item *)flow_spec->handle;
6766 	switch (flex->tunnel_mode) {
6767 	case FLEX_TUNNEL_MODE_SINGLE:
6768 		if (item_flags &
6769 		    (MLX5_FLOW_ITEM_OUTER_FLEX | MLX5_FLOW_ITEM_INNER_FLEX))
6770 			rte_flow_error_set(error, EINVAL,
6771 					   RTE_FLOW_ERROR_TYPE_ITEM,
6772 					   NULL, "multiple flex items not supported");
6773 		break;
6774 	case FLEX_TUNNEL_MODE_OUTER:
6775 		if (is_inner)
6776 			rte_flow_error_set(error, EINVAL,
6777 					   RTE_FLOW_ERROR_TYPE_ITEM,
6778 					   NULL, "inner flex item was not configured");
6779 		if (item_flags & MLX5_FLOW_ITEM_OUTER_FLEX)
6780 			rte_flow_error_set(error, ENOTSUP,
6781 					   RTE_FLOW_ERROR_TYPE_ITEM,
6782 					   NULL, "multiple flex items not supported");
6783 		break;
6784 	case FLEX_TUNNEL_MODE_INNER:
6785 		if (!is_inner)
6786 			rte_flow_error_set(error, EINVAL,
6787 					   RTE_FLOW_ERROR_TYPE_ITEM,
6788 					   NULL, "outer flex item was not configured");
6789 		if (item_flags & MLX5_FLOW_ITEM_INNER_FLEX)
6790 			rte_flow_error_set(error, EINVAL,
6791 					   RTE_FLOW_ERROR_TYPE_ITEM,
6792 					   NULL, "multiple flex items not supported");
6793 		break;
6794 	case FLEX_TUNNEL_MODE_MULTI:
6795 		if ((is_inner && (item_flags & MLX5_FLOW_ITEM_INNER_FLEX)) ||
6796 		    (!is_inner && (item_flags & MLX5_FLOW_ITEM_OUTER_FLEX))) {
6797 			rte_flow_error_set(error, EINVAL,
6798 					   RTE_FLOW_ERROR_TYPE_ITEM,
6799 					   NULL, "multiple flex items not supported");
6800 		}
6801 		break;
6802 	case FLEX_TUNNEL_MODE_TUNNEL:
6803 		if (is_inner || (item_flags & MLX5_FLOW_ITEM_FLEX_TUNNEL))
6804 			rte_flow_error_set(error, EINVAL,
6805 					   RTE_FLOW_ERROR_TYPE_ITEM,
6806 					   NULL, "multiple flex tunnel items not supported");
6807 		break;
6808 	default:
6809 		rte_flow_error_set(error, EINVAL,
6810 				   RTE_FLOW_ERROR_TYPE_ITEM,
6811 				   NULL, "invalid flex item configuration");
6812 	}
6813 	*last_item = flex->tunnel_mode == FLEX_TUNNEL_MODE_TUNNEL ?
6814 		     MLX5_FLOW_ITEM_FLEX_TUNNEL : is_inner ?
6815 		     MLX5_FLOW_ITEM_INNER_FLEX : MLX5_FLOW_ITEM_OUTER_FLEX;
6816 	return 0;
6817 }
6818 
6819 /**
6820  * Internal validation function. For validating both actions and items.
6821  *
6822  * @param[in] dev
6823  *   Pointer to the rte_eth_dev structure.
6824  * @param[in] attr
6825  *   Pointer to the flow attributes.
6826  * @param[in] items
6827  *   Pointer to the list of items.
6828  * @param[in] actions
6829  *   Pointer to the list of actions.
6830  * @param[in] external
6831  *   This flow rule is created by request external to PMD.
6832  * @param[in] hairpin
6833  *   Number of hairpin TX actions, 0 means classic flow.
6834  * @param[out] error
6835  *   Pointer to the error structure.
6836  *
6837  * @return
6838  *   0 on success, a negative errno value otherwise and rte_errno is set.
6839  */
6840 static int
6841 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
6842 		 const struct rte_flow_item items[],
6843 		 const struct rte_flow_action actions[],
6844 		 bool external, int hairpin, struct rte_flow_error *error)
6845 {
6846 	int ret;
6847 	uint64_t action_flags = 0;
6848 	uint64_t item_flags = 0;
6849 	uint64_t last_item = 0;
6850 	uint8_t next_protocol = 0xff;
6851 	uint16_t ether_type = 0;
6852 	int actions_n = 0;
6853 	uint8_t item_ipv6_proto = 0;
6854 	int fdb_mirror_limit = 0;
6855 	int modify_after_mirror = 0;
6856 	const struct rte_flow_item *geneve_item = NULL;
6857 	const struct rte_flow_item *gre_item = NULL;
6858 	const struct rte_flow_item *gtp_item = NULL;
6859 	const struct rte_flow_action_raw_decap *decap;
6860 	const struct rte_flow_action_raw_encap *encap;
6861 	const struct rte_flow_action_rss *rss = NULL;
6862 	const struct rte_flow_action_rss *sample_rss = NULL;
6863 	const struct rte_flow_action_count *sample_count = NULL;
6864 	const struct rte_flow_item_tcp nic_tcp_mask = {
6865 		.hdr = {
6866 			.tcp_flags = 0xFF,
6867 			.src_port = RTE_BE16(UINT16_MAX),
6868 			.dst_port = RTE_BE16(UINT16_MAX),
6869 		}
6870 	};
6871 	const struct rte_flow_item_ipv6 nic_ipv6_mask = {
6872 		.hdr = {
6873 			.src_addr =
6874 			"\xff\xff\xff\xff\xff\xff\xff\xff"
6875 			"\xff\xff\xff\xff\xff\xff\xff\xff",
6876 			.dst_addr =
6877 			"\xff\xff\xff\xff\xff\xff\xff\xff"
6878 			"\xff\xff\xff\xff\xff\xff\xff\xff",
6879 			.vtc_flow = RTE_BE32(0xffffffff),
6880 			.proto = 0xff,
6881 			.hop_limits = 0xff,
6882 		},
6883 		.has_frag_ext = 1,
6884 	};
6885 	const struct rte_flow_item_ecpri nic_ecpri_mask = {
6886 		.hdr = {
6887 			.common = {
6888 				.u32 =
6889 				RTE_BE32(((const struct rte_ecpri_common_hdr) {
6890 					.type = 0xFF,
6891 					}).u32),
6892 			},
6893 			.dummy[0] = 0xffffffff,
6894 		},
6895 	};
6896 	struct mlx5_priv *priv = dev->data->dev_private;
6897 	struct mlx5_dev_config *dev_conf = &priv->config;
6898 	uint16_t queue_index = 0xFFFF;
6899 	const struct rte_flow_item_vlan *vlan_m = NULL;
6900 	uint32_t rw_act_num = 0;
6901 	uint64_t is_root;
6902 	const struct mlx5_flow_tunnel *tunnel;
6903 	enum mlx5_tof_rule_type tof_rule_type;
6904 	struct flow_grp_info grp_info = {
6905 		.external = !!external,
6906 		.transfer = !!attr->transfer,
6907 		.fdb_def_rule = !!priv->fdb_def_rule,
6908 		.std_tbl_fix = true,
6909 	};
6910 	const struct rte_eth_hairpin_conf *conf;
6911 	const struct rte_flow_item *integrity_items[2] = {NULL, NULL};
6912 	const struct rte_flow_item *port_id_item = NULL;
6913 	bool def_policy = false;
6914 	uint16_t udp_dport = 0;
6915 
6916 	if (items == NULL)
6917 		return -1;
6918 	tunnel = is_tunnel_offload_active(dev) ?
6919 		 mlx5_get_tof(items, actions, &tof_rule_type) : NULL;
6920 	if (tunnel) {
6921 		if (!priv->config.dv_flow_en)
6922 			return rte_flow_error_set
6923 				(error, ENOTSUP,
6924 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6925 				 NULL, "tunnel offload requires DV flow interface");
6926 		if (priv->representor)
6927 			return rte_flow_error_set
6928 				(error, ENOTSUP,
6929 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6930 				 NULL, "decap not supported for VF representor");
6931 		if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE)
6932 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
6933 		else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE)
6934 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH |
6935 					MLX5_FLOW_ACTION_DECAP;
6936 		grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
6937 					(dev, attr, tunnel, tof_rule_type);
6938 	}
6939 	ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error);
6940 	if (ret < 0)
6941 		return ret;
6942 	is_root = (uint64_t)ret;
6943 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
6944 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
6945 		int type = items->type;
6946 
6947 		if (!mlx5_flow_os_item_supported(type))
6948 			return rte_flow_error_set(error, ENOTSUP,
6949 						  RTE_FLOW_ERROR_TYPE_ITEM,
6950 						  NULL, "item not supported");
6951 		switch (type) {
6952 		case RTE_FLOW_ITEM_TYPE_VOID:
6953 			break;
6954 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
6955 			ret = flow_dv_validate_item_port_id
6956 					(dev, items, attr, item_flags, error);
6957 			if (ret < 0)
6958 				return ret;
6959 			last_item = MLX5_FLOW_ITEM_PORT_ID;
6960 			port_id_item = items;
6961 			break;
6962 		case RTE_FLOW_ITEM_TYPE_ETH:
6963 			ret = mlx5_flow_validate_item_eth(items, item_flags,
6964 							  true, error);
6965 			if (ret < 0)
6966 				return ret;
6967 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
6968 					     MLX5_FLOW_LAYER_OUTER_L2;
6969 			if (items->mask != NULL && items->spec != NULL) {
6970 				ether_type =
6971 					((const struct rte_flow_item_eth *)
6972 					 items->spec)->type;
6973 				ether_type &=
6974 					((const struct rte_flow_item_eth *)
6975 					 items->mask)->type;
6976 				ether_type = rte_be_to_cpu_16(ether_type);
6977 			} else {
6978 				ether_type = 0;
6979 			}
6980 			break;
6981 		case RTE_FLOW_ITEM_TYPE_VLAN:
6982 			ret = flow_dv_validate_item_vlan(items, item_flags,
6983 							 dev, error);
6984 			if (ret < 0)
6985 				return ret;
6986 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
6987 					     MLX5_FLOW_LAYER_OUTER_VLAN;
6988 			if (items->mask != NULL && items->spec != NULL) {
6989 				ether_type =
6990 					((const struct rte_flow_item_vlan *)
6991 					 items->spec)->inner_type;
6992 				ether_type &=
6993 					((const struct rte_flow_item_vlan *)
6994 					 items->mask)->inner_type;
6995 				ether_type = rte_be_to_cpu_16(ether_type);
6996 			} else {
6997 				ether_type = 0;
6998 			}
6999 			/* Store outer VLAN mask for of_push_vlan action. */
7000 			if (!tunnel)
7001 				vlan_m = items->mask;
7002 			break;
7003 		case RTE_FLOW_ITEM_TYPE_IPV4:
7004 			mlx5_flow_tunnel_ip_check(items, next_protocol,
7005 						  &item_flags, &tunnel);
7006 			ret = flow_dv_validate_item_ipv4(dev, items, item_flags,
7007 							 last_item, ether_type,
7008 							 error);
7009 			if (ret < 0)
7010 				return ret;
7011 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
7012 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
7013 			if (items->mask != NULL &&
7014 			    ((const struct rte_flow_item_ipv4 *)
7015 			     items->mask)->hdr.next_proto_id) {
7016 				next_protocol =
7017 					((const struct rte_flow_item_ipv4 *)
7018 					 (items->spec))->hdr.next_proto_id;
7019 				next_protocol &=
7020 					((const struct rte_flow_item_ipv4 *)
7021 					 (items->mask))->hdr.next_proto_id;
7022 			} else {
7023 				/* Reset for inner layer. */
7024 				next_protocol = 0xff;
7025 			}
7026 			break;
7027 		case RTE_FLOW_ITEM_TYPE_IPV6:
7028 			mlx5_flow_tunnel_ip_check(items, next_protocol,
7029 						  &item_flags, &tunnel);
7030 			ret = mlx5_flow_validate_item_ipv6(items, item_flags,
7031 							   last_item,
7032 							   ether_type,
7033 							   &nic_ipv6_mask,
7034 							   error);
7035 			if (ret < 0)
7036 				return ret;
7037 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
7038 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
7039 			if (items->mask != NULL &&
7040 			    ((const struct rte_flow_item_ipv6 *)
7041 			     items->mask)->hdr.proto) {
7042 				item_ipv6_proto =
7043 					((const struct rte_flow_item_ipv6 *)
7044 					 items->spec)->hdr.proto;
7045 				next_protocol =
7046 					((const struct rte_flow_item_ipv6 *)
7047 					 items->spec)->hdr.proto;
7048 				next_protocol &=
7049 					((const struct rte_flow_item_ipv6 *)
7050 					 items->mask)->hdr.proto;
7051 			} else {
7052 				/* Reset for inner layer. */
7053 				next_protocol = 0xff;
7054 			}
7055 			break;
7056 		case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
7057 			ret = flow_dv_validate_item_ipv6_frag_ext(items,
7058 								  item_flags,
7059 								  error);
7060 			if (ret < 0)
7061 				return ret;
7062 			last_item = tunnel ?
7063 					MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
7064 					MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
7065 			if (items->mask != NULL &&
7066 			    ((const struct rte_flow_item_ipv6_frag_ext *)
7067 			     items->mask)->hdr.next_header) {
7068 				next_protocol =
7069 				((const struct rte_flow_item_ipv6_frag_ext *)
7070 				 items->spec)->hdr.next_header;
7071 				next_protocol &=
7072 				((const struct rte_flow_item_ipv6_frag_ext *)
7073 				 items->mask)->hdr.next_header;
7074 			} else {
7075 				/* Reset for inner layer. */
7076 				next_protocol = 0xff;
7077 			}
7078 			break;
7079 		case RTE_FLOW_ITEM_TYPE_TCP:
7080 			ret = mlx5_flow_validate_item_tcp
7081 						(items, item_flags,
7082 						 next_protocol,
7083 						 &nic_tcp_mask,
7084 						 error);
7085 			if (ret < 0)
7086 				return ret;
7087 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
7088 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
7089 			break;
7090 		case RTE_FLOW_ITEM_TYPE_UDP:
7091 			ret = mlx5_flow_validate_item_udp(items, item_flags,
7092 							  next_protocol,
7093 							  error);
7094 			const struct rte_flow_item_udp *spec = items->spec;
7095 			const struct rte_flow_item_udp *mask = items->mask;
7096 			if (!mask)
7097 				mask = &rte_flow_item_udp_mask;
7098 			if (spec != NULL)
7099 				udp_dport = rte_be_to_cpu_16
7100 						(spec->hdr.dst_port &
7101 						 mask->hdr.dst_port);
7102 			if (ret < 0)
7103 				return ret;
7104 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
7105 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
7106 			break;
7107 		case RTE_FLOW_ITEM_TYPE_GRE:
7108 			ret = mlx5_flow_validate_item_gre(items, item_flags,
7109 							  next_protocol, error);
7110 			if (ret < 0)
7111 				return ret;
7112 			gre_item = items;
7113 			last_item = MLX5_FLOW_LAYER_GRE;
7114 			break;
7115 		case RTE_FLOW_ITEM_TYPE_NVGRE:
7116 			ret = mlx5_flow_validate_item_nvgre(items, item_flags,
7117 							    next_protocol,
7118 							    error);
7119 			if (ret < 0)
7120 				return ret;
7121 			last_item = MLX5_FLOW_LAYER_NVGRE;
7122 			break;
7123 		case RTE_FLOW_ITEM_TYPE_GRE_KEY:
7124 			ret = mlx5_flow_validate_item_gre_key
7125 				(items, item_flags, gre_item, error);
7126 			if (ret < 0)
7127 				return ret;
7128 			last_item = MLX5_FLOW_LAYER_GRE_KEY;
7129 			break;
7130 		case RTE_FLOW_ITEM_TYPE_VXLAN:
7131 			ret = mlx5_flow_validate_item_vxlan(dev, udp_dport,
7132 							    items, item_flags,
7133 							    attr, error);
7134 			if (ret < 0)
7135 				return ret;
7136 			last_item = MLX5_FLOW_LAYER_VXLAN;
7137 			break;
7138 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
7139 			ret = mlx5_flow_validate_item_vxlan_gpe(items,
7140 								item_flags, dev,
7141 								error);
7142 			if (ret < 0)
7143 				return ret;
7144 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
7145 			break;
7146 		case RTE_FLOW_ITEM_TYPE_GENEVE:
7147 			ret = mlx5_flow_validate_item_geneve(items,
7148 							     item_flags, dev,
7149 							     error);
7150 			if (ret < 0)
7151 				return ret;
7152 			geneve_item = items;
7153 			last_item = MLX5_FLOW_LAYER_GENEVE;
7154 			break;
7155 		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
7156 			ret = mlx5_flow_validate_item_geneve_opt(items,
7157 								 last_item,
7158 								 geneve_item,
7159 								 dev,
7160 								 error);
7161 			if (ret < 0)
7162 				return ret;
7163 			last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
7164 			break;
7165 		case RTE_FLOW_ITEM_TYPE_MPLS:
7166 			ret = mlx5_flow_validate_item_mpls(dev, items,
7167 							   item_flags,
7168 							   last_item, error);
7169 			if (ret < 0)
7170 				return ret;
7171 			last_item = MLX5_FLOW_LAYER_MPLS;
7172 			break;
7173 
7174 		case RTE_FLOW_ITEM_TYPE_MARK:
7175 			ret = flow_dv_validate_item_mark(dev, items, attr,
7176 							 error);
7177 			if (ret < 0)
7178 				return ret;
7179 			last_item = MLX5_FLOW_ITEM_MARK;
7180 			break;
7181 		case RTE_FLOW_ITEM_TYPE_META:
7182 			ret = flow_dv_validate_item_meta(dev, items, attr,
7183 							 error);
7184 			if (ret < 0)
7185 				return ret;
7186 			last_item = MLX5_FLOW_ITEM_METADATA;
7187 			break;
7188 		case RTE_FLOW_ITEM_TYPE_ICMP:
7189 			ret = mlx5_flow_validate_item_icmp(items, item_flags,
7190 							   next_protocol,
7191 							   error);
7192 			if (ret < 0)
7193 				return ret;
7194 			last_item = MLX5_FLOW_LAYER_ICMP;
7195 			break;
7196 		case RTE_FLOW_ITEM_TYPE_ICMP6:
7197 			ret = mlx5_flow_validate_item_icmp6(items, item_flags,
7198 							    next_protocol,
7199 							    error);
7200 			if (ret < 0)
7201 				return ret;
7202 			item_ipv6_proto = IPPROTO_ICMPV6;
7203 			last_item = MLX5_FLOW_LAYER_ICMP6;
7204 			break;
7205 		case RTE_FLOW_ITEM_TYPE_TAG:
7206 			ret = flow_dv_validate_item_tag(dev, items,
7207 							attr, error);
7208 			if (ret < 0)
7209 				return ret;
7210 			last_item = MLX5_FLOW_ITEM_TAG;
7211 			break;
7212 		case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
7213 		case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
7214 			break;
7215 		case RTE_FLOW_ITEM_TYPE_GTP:
7216 			ret = flow_dv_validate_item_gtp(dev, items, item_flags,
7217 							error);
7218 			if (ret < 0)
7219 				return ret;
7220 			gtp_item = items;
7221 			last_item = MLX5_FLOW_LAYER_GTP;
7222 			break;
7223 		case RTE_FLOW_ITEM_TYPE_GTP_PSC:
7224 			ret = flow_dv_validate_item_gtp_psc(items, last_item,
7225 							    gtp_item, attr,
7226 							    error);
7227 			if (ret < 0)
7228 				return ret;
7229 			last_item = MLX5_FLOW_LAYER_GTP_PSC;
7230 			break;
7231 		case RTE_FLOW_ITEM_TYPE_ECPRI:
7232 			/* Capacity will be checked in the translate stage. */
7233 			ret = mlx5_flow_validate_item_ecpri(items, item_flags,
7234 							    last_item,
7235 							    ether_type,
7236 							    &nic_ecpri_mask,
7237 							    error);
7238 			if (ret < 0)
7239 				return ret;
7240 			last_item = MLX5_FLOW_LAYER_ECPRI;
7241 			break;
7242 		case RTE_FLOW_ITEM_TYPE_INTEGRITY:
7243 			ret = flow_dv_validate_item_integrity(dev, items,
7244 							      item_flags,
7245 							      &last_item,
7246 							      integrity_items,
7247 							      error);
7248 			if (ret < 0)
7249 				return ret;
7250 			break;
7251 		case RTE_FLOW_ITEM_TYPE_CONNTRACK:
7252 			ret = flow_dv_validate_item_aso_ct(dev, items,
7253 							   &item_flags, error);
7254 			if (ret < 0)
7255 				return ret;
7256 			break;
7257 		case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL:
7258 			/* tunnel offload item was processed before
7259 			 * list it here as a supported type
7260 			 */
7261 			break;
7262 		case RTE_FLOW_ITEM_TYPE_FLEX:
7263 			ret = flow_dv_validate_item_flex(dev, items, item_flags,
7264 							 &last_item,
7265 							 tunnel != 0, error);
7266 			if (ret < 0)
7267 				return ret;
7268 			break;
7269 		default:
7270 			return rte_flow_error_set(error, ENOTSUP,
7271 						  RTE_FLOW_ERROR_TYPE_ITEM,
7272 						  NULL, "item not supported");
7273 		}
7274 		item_flags |= last_item;
7275 	}
7276 	if (item_flags & MLX5_FLOW_ITEM_INTEGRITY) {
7277 		ret = flow_dv_validate_item_integrity_post(integrity_items,
7278 							   item_flags, error);
7279 		if (ret)
7280 			return ret;
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 		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
7306 			ret = flow_dv_validate_action_port_id(dev,
7307 							      action_flags,
7308 							      actions,
7309 							      attr,
7310 							      error);
7311 			if (ret)
7312 				return ret;
7313 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
7314 			++actions_n;
7315 			break;
7316 		case RTE_FLOW_ACTION_TYPE_FLAG:
7317 			ret = flow_dv_validate_action_flag(dev, action_flags,
7318 							   attr, error);
7319 			if (ret < 0)
7320 				return ret;
7321 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7322 				/* Count all modify-header actions as one. */
7323 				if (!(action_flags &
7324 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
7325 					++actions_n;
7326 				action_flags |= MLX5_FLOW_ACTION_FLAG |
7327 						MLX5_FLOW_ACTION_MARK_EXT;
7328 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7329 					modify_after_mirror = 1;
7330 
7331 			} else {
7332 				action_flags |= MLX5_FLOW_ACTION_FLAG;
7333 				++actions_n;
7334 			}
7335 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
7336 			break;
7337 		case RTE_FLOW_ACTION_TYPE_MARK:
7338 			ret = flow_dv_validate_action_mark(dev, actions,
7339 							   action_flags,
7340 							   attr, error);
7341 			if (ret < 0)
7342 				return ret;
7343 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7344 				/* Count all modify-header actions as one. */
7345 				if (!(action_flags &
7346 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
7347 					++actions_n;
7348 				action_flags |= MLX5_FLOW_ACTION_MARK |
7349 						MLX5_FLOW_ACTION_MARK_EXT;
7350 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7351 					modify_after_mirror = 1;
7352 			} else {
7353 				action_flags |= MLX5_FLOW_ACTION_MARK;
7354 				++actions_n;
7355 			}
7356 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
7357 			break;
7358 		case RTE_FLOW_ACTION_TYPE_SET_META:
7359 			ret = flow_dv_validate_action_set_meta(dev, actions,
7360 							       action_flags,
7361 							       attr, error);
7362 			if (ret < 0)
7363 				return ret;
7364 			/* Count all modify-header actions as one action. */
7365 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7366 				++actions_n;
7367 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7368 				modify_after_mirror = 1;
7369 			action_flags |= MLX5_FLOW_ACTION_SET_META;
7370 			rw_act_num += MLX5_ACT_NUM_SET_META;
7371 			break;
7372 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
7373 			ret = flow_dv_validate_action_set_tag(dev, actions,
7374 							      action_flags,
7375 							      attr, error);
7376 			if (ret < 0)
7377 				return ret;
7378 			/* Count all modify-header actions as one action. */
7379 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7380 				++actions_n;
7381 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7382 				modify_after_mirror = 1;
7383 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
7384 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7385 			break;
7386 		case RTE_FLOW_ACTION_TYPE_DROP:
7387 			ret = mlx5_flow_validate_action_drop(action_flags,
7388 							     attr, error);
7389 			if (ret < 0)
7390 				return ret;
7391 			action_flags |= MLX5_FLOW_ACTION_DROP;
7392 			++actions_n;
7393 			break;
7394 		case RTE_FLOW_ACTION_TYPE_QUEUE:
7395 			ret = mlx5_flow_validate_action_queue(actions,
7396 							      action_flags, dev,
7397 							      attr, error);
7398 			if (ret < 0)
7399 				return ret;
7400 			queue_index = ((const struct rte_flow_action_queue *)
7401 							(actions->conf))->index;
7402 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
7403 			++actions_n;
7404 			break;
7405 		case RTE_FLOW_ACTION_TYPE_RSS:
7406 			rss = actions->conf;
7407 			ret = mlx5_flow_validate_action_rss(actions,
7408 							    action_flags, dev,
7409 							    attr, item_flags,
7410 							    error);
7411 			if (ret < 0)
7412 				return ret;
7413 			if (rss && sample_rss &&
7414 			    (sample_rss->level != rss->level ||
7415 			    sample_rss->types != rss->types))
7416 				return rte_flow_error_set(error, ENOTSUP,
7417 					RTE_FLOW_ERROR_TYPE_ACTION,
7418 					NULL,
7419 					"Can't use the different RSS types "
7420 					"or level in the same flow");
7421 			if (rss != NULL && rss->queue_num)
7422 				queue_index = rss->queue[0];
7423 			action_flags |= MLX5_FLOW_ACTION_RSS;
7424 			++actions_n;
7425 			break;
7426 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
7427 			ret =
7428 			mlx5_flow_validate_action_default_miss(action_flags,
7429 					attr, error);
7430 			if (ret < 0)
7431 				return ret;
7432 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
7433 			++actions_n;
7434 			break;
7435 		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
7436 			shared_count = true;
7437 			/* fall-through. */
7438 		case RTE_FLOW_ACTION_TYPE_COUNT:
7439 			ret = flow_dv_validate_action_count(dev, shared_count,
7440 							    action_flags,
7441 							    error);
7442 			if (ret < 0)
7443 				return ret;
7444 			action_flags |= MLX5_FLOW_ACTION_COUNT;
7445 			++actions_n;
7446 			break;
7447 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
7448 			if (flow_dv_validate_action_pop_vlan(dev,
7449 							     action_flags,
7450 							     actions,
7451 							     item_flags, attr,
7452 							     error))
7453 				return -rte_errno;
7454 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7455 				modify_after_mirror = 1;
7456 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
7457 			++actions_n;
7458 			break;
7459 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
7460 			ret = flow_dv_validate_action_push_vlan(dev,
7461 								action_flags,
7462 								vlan_m,
7463 								actions, attr,
7464 								error);
7465 			if (ret < 0)
7466 				return ret;
7467 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7468 				modify_after_mirror = 1;
7469 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
7470 			++actions_n;
7471 			break;
7472 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
7473 			ret = flow_dv_validate_action_set_vlan_pcp
7474 						(action_flags, actions, error);
7475 			if (ret < 0)
7476 				return ret;
7477 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7478 				modify_after_mirror = 1;
7479 			/* Count PCP with push_vlan command. */
7480 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP;
7481 			break;
7482 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
7483 			ret = flow_dv_validate_action_set_vlan_vid
7484 						(item_flags, action_flags,
7485 						 actions, error);
7486 			if (ret < 0)
7487 				return ret;
7488 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7489 				modify_after_mirror = 1;
7490 			/* Count VID with push_vlan command. */
7491 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
7492 			rw_act_num += MLX5_ACT_NUM_MDF_VID;
7493 			break;
7494 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
7495 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
7496 			ret = flow_dv_validate_action_l2_encap(dev,
7497 							       action_flags,
7498 							       actions, attr,
7499 							       error);
7500 			if (ret < 0)
7501 				return ret;
7502 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
7503 			++actions_n;
7504 			break;
7505 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
7506 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
7507 			ret = flow_dv_validate_action_decap(dev, action_flags,
7508 							    actions, item_flags,
7509 							    attr, error);
7510 			if (ret < 0)
7511 				return ret;
7512 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7513 				modify_after_mirror = 1;
7514 			action_flags |= MLX5_FLOW_ACTION_DECAP;
7515 			++actions_n;
7516 			break;
7517 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
7518 			ret = flow_dv_validate_action_raw_encap_decap
7519 				(dev, NULL, actions->conf, attr, &action_flags,
7520 				 &actions_n, actions, item_flags, error);
7521 			if (ret < 0)
7522 				return ret;
7523 			break;
7524 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
7525 			decap = actions->conf;
7526 			while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID)
7527 				;
7528 			if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
7529 				encap = NULL;
7530 				actions--;
7531 			} else {
7532 				encap = actions->conf;
7533 			}
7534 			ret = flow_dv_validate_action_raw_encap_decap
7535 					   (dev,
7536 					    decap ? decap : &empty_decap, encap,
7537 					    attr, &action_flags, &actions_n,
7538 					    actions, item_flags, error);
7539 			if (ret < 0)
7540 				return ret;
7541 			if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
7542 			    (action_flags & MLX5_FLOW_ACTION_DECAP))
7543 				modify_after_mirror = 1;
7544 			break;
7545 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
7546 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
7547 			ret = flow_dv_validate_action_modify_mac(action_flags,
7548 								 actions,
7549 								 item_flags,
7550 								 error);
7551 			if (ret < 0)
7552 				return ret;
7553 			/* Count all modify-header actions as one action. */
7554 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7555 				++actions_n;
7556 			action_flags |= actions->type ==
7557 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
7558 						MLX5_FLOW_ACTION_SET_MAC_SRC :
7559 						MLX5_FLOW_ACTION_SET_MAC_DST;
7560 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7561 				modify_after_mirror = 1;
7562 			/*
7563 			 * Even if the source and destination MAC addresses have
7564 			 * overlap in the header with 4B alignment, the convert
7565 			 * function will handle them separately and 4 SW actions
7566 			 * will be created. And 2 actions will be added each
7567 			 * time no matter how many bytes of address will be set.
7568 			 */
7569 			rw_act_num += MLX5_ACT_NUM_MDF_MAC;
7570 			break;
7571 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
7572 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
7573 			ret = flow_dv_validate_action_modify_ipv4(action_flags,
7574 								  actions,
7575 								  item_flags,
7576 								  error);
7577 			if (ret < 0)
7578 				return ret;
7579 			/* Count all modify-header actions as one action. */
7580 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7581 				++actions_n;
7582 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7583 				modify_after_mirror = 1;
7584 			action_flags |= actions->type ==
7585 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
7586 						MLX5_FLOW_ACTION_SET_IPV4_SRC :
7587 						MLX5_FLOW_ACTION_SET_IPV4_DST;
7588 			rw_act_num += MLX5_ACT_NUM_MDF_IPV4;
7589 			break;
7590 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
7591 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
7592 			ret = flow_dv_validate_action_modify_ipv6(action_flags,
7593 								  actions,
7594 								  item_flags,
7595 								  error);
7596 			if (ret < 0)
7597 				return ret;
7598 			if (item_ipv6_proto == IPPROTO_ICMPV6)
7599 				return rte_flow_error_set(error, ENOTSUP,
7600 					RTE_FLOW_ERROR_TYPE_ACTION,
7601 					actions,
7602 					"Can't change header "
7603 					"with ICMPv6 proto");
7604 			/* Count all modify-header actions as one action. */
7605 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7606 				++actions_n;
7607 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7608 				modify_after_mirror = 1;
7609 			action_flags |= actions->type ==
7610 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
7611 						MLX5_FLOW_ACTION_SET_IPV6_SRC :
7612 						MLX5_FLOW_ACTION_SET_IPV6_DST;
7613 			rw_act_num += MLX5_ACT_NUM_MDF_IPV6;
7614 			break;
7615 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
7616 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
7617 			ret = flow_dv_validate_action_modify_tp(action_flags,
7618 								actions,
7619 								item_flags,
7620 								error);
7621 			if (ret < 0)
7622 				return ret;
7623 			/* Count all modify-header actions as one action. */
7624 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7625 				++actions_n;
7626 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7627 				modify_after_mirror = 1;
7628 			action_flags |= actions->type ==
7629 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
7630 						MLX5_FLOW_ACTION_SET_TP_SRC :
7631 						MLX5_FLOW_ACTION_SET_TP_DST;
7632 			rw_act_num += MLX5_ACT_NUM_MDF_PORT;
7633 			break;
7634 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
7635 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
7636 			ret = flow_dv_validate_action_modify_ttl(action_flags,
7637 								 actions,
7638 								 item_flags,
7639 								 error);
7640 			if (ret < 0)
7641 				return ret;
7642 			/* Count all modify-header actions as one action. */
7643 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7644 				++actions_n;
7645 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7646 				modify_after_mirror = 1;
7647 			action_flags |= actions->type ==
7648 					RTE_FLOW_ACTION_TYPE_SET_TTL ?
7649 						MLX5_FLOW_ACTION_SET_TTL :
7650 						MLX5_FLOW_ACTION_DEC_TTL;
7651 			rw_act_num += MLX5_ACT_NUM_MDF_TTL;
7652 			break;
7653 		case RTE_FLOW_ACTION_TYPE_JUMP:
7654 			ret = flow_dv_validate_action_jump(dev, tunnel, actions,
7655 							   action_flags,
7656 							   attr, external,
7657 							   error);
7658 			if (ret)
7659 				return ret;
7660 			if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
7661 			    fdb_mirror_limit)
7662 				return rte_flow_error_set(error, EINVAL,
7663 						  RTE_FLOW_ERROR_TYPE_ACTION,
7664 						  NULL,
7665 						  "sample and jump action combination is not supported");
7666 			++actions_n;
7667 			action_flags |= MLX5_FLOW_ACTION_JUMP;
7668 			break;
7669 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
7670 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
7671 			ret = flow_dv_validate_action_modify_tcp_seq
7672 								(action_flags,
7673 								 actions,
7674 								 item_flags,
7675 								 error);
7676 			if (ret < 0)
7677 				return ret;
7678 			/* Count all modify-header actions as one action. */
7679 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7680 				++actions_n;
7681 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7682 				modify_after_mirror = 1;
7683 			action_flags |= actions->type ==
7684 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
7685 						MLX5_FLOW_ACTION_INC_TCP_SEQ :
7686 						MLX5_FLOW_ACTION_DEC_TCP_SEQ;
7687 			rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ;
7688 			break;
7689 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
7690 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
7691 			ret = flow_dv_validate_action_modify_tcp_ack
7692 								(action_flags,
7693 								 actions,
7694 								 item_flags,
7695 								 error);
7696 			if (ret < 0)
7697 				return ret;
7698 			/* Count all modify-header actions as one action. */
7699 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7700 				++actions_n;
7701 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7702 				modify_after_mirror = 1;
7703 			action_flags |= actions->type ==
7704 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
7705 						MLX5_FLOW_ACTION_INC_TCP_ACK :
7706 						MLX5_FLOW_ACTION_DEC_TCP_ACK;
7707 			rw_act_num += MLX5_ACT_NUM_MDF_TCPACK;
7708 			break;
7709 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
7710 			break;
7711 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
7712 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
7713 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7714 			break;
7715 		case RTE_FLOW_ACTION_TYPE_METER:
7716 			ret = mlx5_flow_validate_action_meter(dev,
7717 							      action_flags,
7718 							      item_flags,
7719 							      actions, attr,
7720 							      port_id_item,
7721 							      &def_policy,
7722 							      error);
7723 			if (ret < 0)
7724 				return ret;
7725 			action_flags |= MLX5_FLOW_ACTION_METER;
7726 			if (!def_policy)
7727 				action_flags |=
7728 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
7729 			++actions_n;
7730 			/* Meter action will add one more TAG action. */
7731 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7732 			break;
7733 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
7734 			if (!attr->transfer && !attr->group)
7735 				return rte_flow_error_set(error, ENOTSUP,
7736 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
7737 									   NULL,
7738 			  "Shared ASO age action is not supported for group 0");
7739 			if (action_flags & MLX5_FLOW_ACTION_AGE)
7740 				return rte_flow_error_set
7741 						  (error, EINVAL,
7742 						   RTE_FLOW_ERROR_TYPE_ACTION,
7743 						   NULL,
7744 						   "duplicate age actions set");
7745 			action_flags |= MLX5_FLOW_ACTION_AGE;
7746 			++actions_n;
7747 			break;
7748 		case RTE_FLOW_ACTION_TYPE_AGE:
7749 			ret = flow_dv_validate_action_age(action_flags,
7750 							  actions, dev,
7751 							  error);
7752 			if (ret < 0)
7753 				return ret;
7754 			/*
7755 			 * Validate the regular AGE action (using counter)
7756 			 * mutual exclusion with share counter actions.
7757 			 */
7758 			if (!priv->sh->flow_hit_aso_en) {
7759 				if (shared_count)
7760 					return rte_flow_error_set
7761 						(error, EINVAL,
7762 						RTE_FLOW_ERROR_TYPE_ACTION,
7763 						NULL,
7764 						"old age and shared count combination is not supported");
7765 				if (sample_count)
7766 					return rte_flow_error_set
7767 						(error, EINVAL,
7768 						RTE_FLOW_ERROR_TYPE_ACTION,
7769 						NULL,
7770 						"old age action and count must be in the same sub flow");
7771 			}
7772 			action_flags |= MLX5_FLOW_ACTION_AGE;
7773 			++actions_n;
7774 			break;
7775 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
7776 			ret = flow_dv_validate_action_modify_ipv4_dscp
7777 							 (action_flags,
7778 							  actions,
7779 							  item_flags,
7780 							  error);
7781 			if (ret < 0)
7782 				return ret;
7783 			/* Count all modify-header actions as one action. */
7784 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7785 				++actions_n;
7786 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7787 				modify_after_mirror = 1;
7788 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
7789 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7790 			break;
7791 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
7792 			ret = flow_dv_validate_action_modify_ipv6_dscp
7793 								(action_flags,
7794 								 actions,
7795 								 item_flags,
7796 								 error);
7797 			if (ret < 0)
7798 				return ret;
7799 			/* Count all modify-header actions as one action. */
7800 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7801 				++actions_n;
7802 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7803 				modify_after_mirror = 1;
7804 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
7805 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7806 			break;
7807 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
7808 			ret = flow_dv_validate_action_sample(&action_flags,
7809 							     actions, dev,
7810 							     attr, item_flags,
7811 							     rss, &sample_rss,
7812 							     &sample_count,
7813 							     &fdb_mirror_limit,
7814 							     error);
7815 			if (ret < 0)
7816 				return ret;
7817 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
7818 			++actions_n;
7819 			break;
7820 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
7821 			ret = flow_dv_validate_action_modify_field(dev,
7822 								   action_flags,
7823 								   actions,
7824 								   attr,
7825 								   error);
7826 			if (ret < 0)
7827 				return ret;
7828 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7829 				modify_after_mirror = 1;
7830 			/* Count all modify-header actions as one action. */
7831 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7832 				++actions_n;
7833 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
7834 			rw_act_num += ret;
7835 			break;
7836 		case RTE_FLOW_ACTION_TYPE_CONNTRACK:
7837 			ret = flow_dv_validate_action_aso_ct(dev, action_flags,
7838 							     item_flags, attr,
7839 							     error);
7840 			if (ret < 0)
7841 				return ret;
7842 			action_flags |= MLX5_FLOW_ACTION_CT;
7843 			break;
7844 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
7845 			/* tunnel offload action was processed before
7846 			 * list it here as a supported type
7847 			 */
7848 			break;
7849 		default:
7850 			return rte_flow_error_set(error, ENOTSUP,
7851 						  RTE_FLOW_ERROR_TYPE_ACTION,
7852 						  actions,
7853 						  "action not supported");
7854 		}
7855 	}
7856 	/*
7857 	 * Validate actions in flow rules
7858 	 * - Explicit decap action is prohibited by the tunnel offload API.
7859 	 * - Drop action in tunnel steer rule is prohibited by the API.
7860 	 * - Application cannot use MARK action because it's value can mask
7861 	 *   tunnel default miss nitification.
7862 	 * - JUMP in tunnel match rule has no support in current PMD
7863 	 *   implementation.
7864 	 * - TAG & META are reserved for future uses.
7865 	 */
7866 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) {
7867 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP    |
7868 					    MLX5_FLOW_ACTION_MARK     |
7869 					    MLX5_FLOW_ACTION_SET_TAG  |
7870 					    MLX5_FLOW_ACTION_SET_META |
7871 					    MLX5_FLOW_ACTION_DROP;
7872 
7873 		if (action_flags & bad_actions_mask)
7874 			return rte_flow_error_set
7875 					(error, EINVAL,
7876 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7877 					"Invalid RTE action in tunnel "
7878 					"set decap rule");
7879 		if (!(action_flags & MLX5_FLOW_ACTION_JUMP))
7880 			return rte_flow_error_set
7881 					(error, EINVAL,
7882 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7883 					"tunnel set decap rule must terminate "
7884 					"with JUMP");
7885 		if (!attr->ingress)
7886 			return rte_flow_error_set
7887 					(error, EINVAL,
7888 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7889 					"tunnel flows for ingress traffic only");
7890 	}
7891 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) {
7892 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP    |
7893 					    MLX5_FLOW_ACTION_MARK    |
7894 					    MLX5_FLOW_ACTION_SET_TAG |
7895 					    MLX5_FLOW_ACTION_SET_META;
7896 
7897 		if (action_flags & bad_actions_mask)
7898 			return rte_flow_error_set
7899 					(error, EINVAL,
7900 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7901 					"Invalid RTE action in tunnel "
7902 					"set match rule");
7903 	}
7904 	/*
7905 	 * Validate the drop action mutual exclusion with other actions.
7906 	 * Drop action is mutually-exclusive with any other action, except for
7907 	 * Count action.
7908 	 * Drop action compatibility with tunnel offload was already validated.
7909 	 */
7910 	if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH |
7911 			    MLX5_FLOW_ACTION_TUNNEL_MATCH));
7912 	else if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
7913 	    (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_COUNT)))
7914 		return rte_flow_error_set(error, EINVAL,
7915 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
7916 					  "Drop action is mutually-exclusive "
7917 					  "with any other action, except for "
7918 					  "Count action");
7919 	/* Eswitch has few restrictions on using items and actions */
7920 	if (attr->transfer) {
7921 		if (!mlx5_flow_ext_mreg_supported(dev) &&
7922 		    action_flags & MLX5_FLOW_ACTION_FLAG)
7923 			return rte_flow_error_set(error, ENOTSUP,
7924 						  RTE_FLOW_ERROR_TYPE_ACTION,
7925 						  NULL,
7926 						  "unsupported action FLAG");
7927 		if (!mlx5_flow_ext_mreg_supported(dev) &&
7928 		    action_flags & MLX5_FLOW_ACTION_MARK)
7929 			return rte_flow_error_set(error, ENOTSUP,
7930 						  RTE_FLOW_ERROR_TYPE_ACTION,
7931 						  NULL,
7932 						  "unsupported action MARK");
7933 		if (action_flags & MLX5_FLOW_ACTION_QUEUE)
7934 			return rte_flow_error_set(error, ENOTSUP,
7935 						  RTE_FLOW_ERROR_TYPE_ACTION,
7936 						  NULL,
7937 						  "unsupported action QUEUE");
7938 		if (action_flags & MLX5_FLOW_ACTION_RSS)
7939 			return rte_flow_error_set(error, ENOTSUP,
7940 						  RTE_FLOW_ERROR_TYPE_ACTION,
7941 						  NULL,
7942 						  "unsupported action RSS");
7943 		if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
7944 			return rte_flow_error_set(error, EINVAL,
7945 						  RTE_FLOW_ERROR_TYPE_ACTION,
7946 						  actions,
7947 						  "no fate action is found");
7948 	} else {
7949 		if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress)
7950 			return rte_flow_error_set(error, EINVAL,
7951 						  RTE_FLOW_ERROR_TYPE_ACTION,
7952 						  actions,
7953 						  "no fate action is found");
7954 	}
7955 	/*
7956 	 * Continue validation for Xcap and VLAN actions.
7957 	 * If hairpin is working in explicit TX rule mode, there is no actions
7958 	 * splitting and the validation of hairpin ingress flow should be the
7959 	 * same as other standard flows.
7960 	 */
7961 	if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS |
7962 			     MLX5_FLOW_VLAN_ACTIONS)) &&
7963 	    (queue_index == 0xFFFF ||
7964 	     mlx5_rxq_get_type(dev, queue_index) != MLX5_RXQ_TYPE_HAIRPIN ||
7965 	     ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL &&
7966 	     conf->tx_explicit != 0))) {
7967 		if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
7968 		    MLX5_FLOW_XCAP_ACTIONS)
7969 			return rte_flow_error_set(error, ENOTSUP,
7970 						  RTE_FLOW_ERROR_TYPE_ACTION,
7971 						  NULL, "encap and decap "
7972 						  "combination aren't supported");
7973 		if (!attr->transfer && attr->ingress) {
7974 			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
7975 				return rte_flow_error_set
7976 						(error, ENOTSUP,
7977 						 RTE_FLOW_ERROR_TYPE_ACTION,
7978 						 NULL, "encap is not supported"
7979 						 " for ingress traffic");
7980 			else if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
7981 				return rte_flow_error_set
7982 						(error, ENOTSUP,
7983 						 RTE_FLOW_ERROR_TYPE_ACTION,
7984 						 NULL, "push VLAN action not "
7985 						 "supported for ingress");
7986 			else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) ==
7987 					MLX5_FLOW_VLAN_ACTIONS)
7988 				return rte_flow_error_set
7989 						(error, ENOTSUP,
7990 						 RTE_FLOW_ERROR_TYPE_ACTION,
7991 						 NULL, "no support for "
7992 						 "multiple VLAN actions");
7993 		}
7994 	}
7995 	if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) {
7996 		if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
7997 			~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) &&
7998 			attr->ingress)
7999 			return rte_flow_error_set
8000 				(error, ENOTSUP,
8001 				RTE_FLOW_ERROR_TYPE_ACTION,
8002 				NULL, "fate action not supported for "
8003 				"meter with policy");
8004 		if (attr->egress) {
8005 			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
8006 				return rte_flow_error_set
8007 					(error, ENOTSUP,
8008 					RTE_FLOW_ERROR_TYPE_ACTION,
8009 					NULL, "modify header action in egress "
8010 					"cannot be done before meter action");
8011 			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
8012 				return rte_flow_error_set
8013 					(error, ENOTSUP,
8014 					RTE_FLOW_ERROR_TYPE_ACTION,
8015 					NULL, "encap action in egress "
8016 					"cannot be done before meter action");
8017 			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
8018 				return rte_flow_error_set
8019 					(error, ENOTSUP,
8020 					RTE_FLOW_ERROR_TYPE_ACTION,
8021 					NULL, "push vlan action in egress "
8022 					"cannot be done before meter action");
8023 		}
8024 	}
8025 	/*
8026 	 * Hairpin flow will add one more TAG action in TX implicit mode.
8027 	 * In TX explicit mode, there will be no hairpin flow ID.
8028 	 */
8029 	if (hairpin > 0)
8030 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
8031 	/* extra metadata enabled: one more TAG action will be add. */
8032 	if (dev_conf->dv_flow_en &&
8033 	    dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
8034 	    mlx5_flow_ext_mreg_supported(dev))
8035 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
8036 	if (rw_act_num >
8037 			flow_dv_modify_hdr_action_max(dev, is_root)) {
8038 		return rte_flow_error_set(error, ENOTSUP,
8039 					  RTE_FLOW_ERROR_TYPE_ACTION,
8040 					  NULL, "too many header modify"
8041 					  " actions to support");
8042 	}
8043 	/* Eswitch egress mirror and modify flow has limitation on CX5 */
8044 	if (fdb_mirror_limit && modify_after_mirror)
8045 		return rte_flow_error_set(error, EINVAL,
8046 				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8047 				"sample before modify action is not supported");
8048 	return 0;
8049 }
8050 
8051 /**
8052  * Internal preparation function. Allocates the DV flow size,
8053  * this size is constant.
8054  *
8055  * @param[in] dev
8056  *   Pointer to the rte_eth_dev structure.
8057  * @param[in] attr
8058  *   Pointer to the flow attributes.
8059  * @param[in] items
8060  *   Pointer to the list of items.
8061  * @param[in] actions
8062  *   Pointer to the list of actions.
8063  * @param[out] error
8064  *   Pointer to the error structure.
8065  *
8066  * @return
8067  *   Pointer to mlx5_flow object on success,
8068  *   otherwise NULL and rte_errno is set.
8069  */
8070 static struct mlx5_flow *
8071 flow_dv_prepare(struct rte_eth_dev *dev,
8072 		const struct rte_flow_attr *attr __rte_unused,
8073 		const struct rte_flow_item items[] __rte_unused,
8074 		const struct rte_flow_action actions[] __rte_unused,
8075 		struct rte_flow_error *error)
8076 {
8077 	uint32_t handle_idx = 0;
8078 	struct mlx5_flow *dev_flow;
8079 	struct mlx5_flow_handle *dev_handle;
8080 	struct mlx5_priv *priv = dev->data->dev_private;
8081 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
8082 
8083 	MLX5_ASSERT(wks);
8084 	wks->skip_matcher_reg = 0;
8085 	wks->policy = NULL;
8086 	wks->final_policy = NULL;
8087 	/* In case of corrupting the memory. */
8088 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
8089 		rte_flow_error_set(error, ENOSPC,
8090 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8091 				   "not free temporary device flow");
8092 		return NULL;
8093 	}
8094 	dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
8095 				   &handle_idx);
8096 	if (!dev_handle) {
8097 		rte_flow_error_set(error, ENOMEM,
8098 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8099 				   "not enough memory to create flow handle");
8100 		return NULL;
8101 	}
8102 	MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows));
8103 	dev_flow = &wks->flows[wks->flow_idx++];
8104 	memset(dev_flow, 0, sizeof(*dev_flow));
8105 	dev_flow->handle = dev_handle;
8106 	dev_flow->handle_idx = handle_idx;
8107 	dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
8108 	dev_flow->ingress = attr->ingress;
8109 	dev_flow->dv.transfer = attr->transfer;
8110 	return dev_flow;
8111 }
8112 
8113 #ifdef RTE_LIBRTE_MLX5_DEBUG
8114 /**
8115  * Sanity check for match mask and value. Similar to check_valid_spec() in
8116  * kernel driver. If unmasked bit is present in value, it returns failure.
8117  *
8118  * @param match_mask
8119  *   pointer to match mask buffer.
8120  * @param match_value
8121  *   pointer to match value buffer.
8122  *
8123  * @return
8124  *   0 if valid, -EINVAL otherwise.
8125  */
8126 static int
8127 flow_dv_check_valid_spec(void *match_mask, void *match_value)
8128 {
8129 	uint8_t *m = match_mask;
8130 	uint8_t *v = match_value;
8131 	unsigned int i;
8132 
8133 	for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) {
8134 		if (v[i] & ~m[i]) {
8135 			DRV_LOG(ERR,
8136 				"match_value differs from match_criteria"
8137 				" %p[%u] != %p[%u]",
8138 				match_value, i, match_mask, i);
8139 			return -EINVAL;
8140 		}
8141 	}
8142 	return 0;
8143 }
8144 #endif
8145 
8146 /**
8147  * Add match of ip_version.
8148  *
8149  * @param[in] group
8150  *   Flow group.
8151  * @param[in] headers_v
8152  *   Values header pointer.
8153  * @param[in] headers_m
8154  *   Masks header pointer.
8155  * @param[in] ip_version
8156  *   The IP version to set.
8157  */
8158 static inline void
8159 flow_dv_set_match_ip_version(uint32_t group,
8160 			     void *headers_v,
8161 			     void *headers_m,
8162 			     uint8_t ip_version)
8163 {
8164 	if (group == 0)
8165 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
8166 	else
8167 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version,
8168 			 ip_version);
8169 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, ip_version);
8170 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0);
8171 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype, 0);
8172 }
8173 
8174 /**
8175  * Add Ethernet item to matcher and to the value.
8176  *
8177  * @param[in, out] matcher
8178  *   Flow matcher.
8179  * @param[in, out] key
8180  *   Flow matcher value.
8181  * @param[in] item
8182  *   Flow pattern to translate.
8183  * @param[in] inner
8184  *   Item is inner pattern.
8185  */
8186 static void
8187 flow_dv_translate_item_eth(void *matcher, void *key,
8188 			   const struct rte_flow_item *item, int inner,
8189 			   uint32_t group)
8190 {
8191 	const struct rte_flow_item_eth *eth_m = item->mask;
8192 	const struct rte_flow_item_eth *eth_v = item->spec;
8193 	const struct rte_flow_item_eth nic_mask = {
8194 		.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8195 		.src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8196 		.type = RTE_BE16(0xffff),
8197 		.has_vlan = 0,
8198 	};
8199 	void *hdrs_m;
8200 	void *hdrs_v;
8201 	char *l24_v;
8202 	unsigned int i;
8203 
8204 	if (!eth_v)
8205 		return;
8206 	if (!eth_m)
8207 		eth_m = &nic_mask;
8208 	if (inner) {
8209 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8210 					 inner_headers);
8211 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8212 	} else {
8213 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8214 					 outer_headers);
8215 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8216 	}
8217 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, dmac_47_16),
8218 	       &eth_m->dst, sizeof(eth_m->dst));
8219 	/* The value must be in the range of the mask. */
8220 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16);
8221 	for (i = 0; i < sizeof(eth_m->dst); ++i)
8222 		l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i];
8223 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, smac_47_16),
8224 	       &eth_m->src, sizeof(eth_m->src));
8225 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16);
8226 	/* The value must be in the range of the mask. */
8227 	for (i = 0; i < sizeof(eth_m->dst); ++i)
8228 		l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i];
8229 	/*
8230 	 * HW supports match on one Ethertype, the Ethertype following the last
8231 	 * VLAN tag of the packet (see PRM).
8232 	 * Set match on ethertype only if ETH header is not followed by VLAN.
8233 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8234 	 * ethertype, and use ip_version field instead.
8235 	 * eCPRI over Ether layer will use type value 0xAEFE.
8236 	 */
8237 	if (eth_m->type == 0xFFFF) {
8238 		/* Set cvlan_tag mask for any single\multi\un-tagged case. */
8239 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8240 		switch (eth_v->type) {
8241 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8242 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8243 			return;
8244 		case RTE_BE16(RTE_ETHER_TYPE_QINQ):
8245 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8246 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8247 			return;
8248 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8249 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
8250 			return;
8251 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8252 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
8253 			return;
8254 		default:
8255 			break;
8256 		}
8257 	}
8258 	if (eth_m->has_vlan) {
8259 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8260 		if (eth_v->has_vlan) {
8261 			/*
8262 			 * Here, when also has_more_vlan field in VLAN item is
8263 			 * not set, only single-tagged packets will be matched.
8264 			 */
8265 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8266 			return;
8267 		}
8268 	}
8269 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
8270 		 rte_be_to_cpu_16(eth_m->type));
8271 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
8272 	*(uint16_t *)(l24_v) = eth_m->type & eth_v->type;
8273 }
8274 
8275 /**
8276  * Add VLAN item to matcher and to the value.
8277  *
8278  * @param[in, out] dev_flow
8279  *   Flow descriptor.
8280  * @param[in, out] matcher
8281  *   Flow matcher.
8282  * @param[in, out] key
8283  *   Flow matcher value.
8284  * @param[in] item
8285  *   Flow pattern to translate.
8286  * @param[in] inner
8287  *   Item is inner pattern.
8288  */
8289 static void
8290 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow,
8291 			    void *matcher, void *key,
8292 			    const struct rte_flow_item *item,
8293 			    int inner, uint32_t group)
8294 {
8295 	const struct rte_flow_item_vlan *vlan_m = item->mask;
8296 	const struct rte_flow_item_vlan *vlan_v = item->spec;
8297 	void *hdrs_m;
8298 	void *hdrs_v;
8299 	uint16_t tci_m;
8300 	uint16_t tci_v;
8301 
8302 	if (inner) {
8303 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8304 					 inner_headers);
8305 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8306 	} else {
8307 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher,
8308 					 outer_headers);
8309 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8310 		/*
8311 		 * This is workaround, masks are not supported,
8312 		 * and pre-validated.
8313 		 */
8314 		if (vlan_v)
8315 			dev_flow->handle->vf_vlan.tag =
8316 					rte_be_to_cpu_16(vlan_v->tci) & 0x0fff;
8317 	}
8318 	/*
8319 	 * When VLAN item exists in flow, mark packet as tagged,
8320 	 * even if TCI is not specified.
8321 	 */
8322 	if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag)) {
8323 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, cvlan_tag, 1);
8324 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8325 	}
8326 	if (!vlan_v)
8327 		return;
8328 	if (!vlan_m)
8329 		vlan_m = &rte_flow_item_vlan_mask;
8330 	tci_m = rte_be_to_cpu_16(vlan_m->tci);
8331 	tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci);
8332 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_vid, tci_m);
8333 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v);
8334 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_cfi, tci_m >> 12);
8335 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12);
8336 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, first_prio, tci_m >> 13);
8337 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13);
8338 	/*
8339 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8340 	 * ethertype, and use ip_version field instead.
8341 	 */
8342 	if (vlan_m->inner_type == 0xFFFF) {
8343 		switch (vlan_v->inner_type) {
8344 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8345 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8346 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8347 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
8348 			return;
8349 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8350 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 4);
8351 			return;
8352 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8353 			flow_dv_set_match_ip_version(group, hdrs_v, hdrs_m, 6);
8354 			return;
8355 		default:
8356 			break;
8357 		}
8358 	}
8359 	if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) {
8360 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, svlan_tag, 1);
8361 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8362 		/* Only one vlan_tag bit can be set. */
8363 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
8364 		return;
8365 	}
8366 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_m, ethertype,
8367 		 rte_be_to_cpu_16(vlan_m->inner_type));
8368 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype,
8369 		 rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type));
8370 }
8371 
8372 /**
8373  * Add IPV4 item to matcher and to the value.
8374  *
8375  * @param[in, out] matcher
8376  *   Flow matcher.
8377  * @param[in, out] key
8378  *   Flow matcher value.
8379  * @param[in] item
8380  *   Flow pattern to translate.
8381  * @param[in] inner
8382  *   Item is inner pattern.
8383  * @param[in] group
8384  *   The group to insert the rule.
8385  */
8386 static void
8387 flow_dv_translate_item_ipv4(void *matcher, void *key,
8388 			    const struct rte_flow_item *item,
8389 			    int inner, uint32_t group)
8390 {
8391 	const struct rte_flow_item_ipv4 *ipv4_m = item->mask;
8392 	const struct rte_flow_item_ipv4 *ipv4_v = item->spec;
8393 	const struct rte_flow_item_ipv4 nic_mask = {
8394 		.hdr = {
8395 			.src_addr = RTE_BE32(0xffffffff),
8396 			.dst_addr = RTE_BE32(0xffffffff),
8397 			.type_of_service = 0xff,
8398 			.next_proto_id = 0xff,
8399 			.time_to_live = 0xff,
8400 		},
8401 	};
8402 	void *headers_m;
8403 	void *headers_v;
8404 	char *l24_m;
8405 	char *l24_v;
8406 	uint8_t tos, ihl_m, ihl_v;
8407 
8408 	if (inner) {
8409 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8410 					 inner_headers);
8411 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8412 	} else {
8413 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8414 					 outer_headers);
8415 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8416 	}
8417 	flow_dv_set_match_ip_version(group, headers_v, headers_m, 4);
8418 	if (!ipv4_v)
8419 		return;
8420 	if (!ipv4_m)
8421 		ipv4_m = &nic_mask;
8422 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8423 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
8424 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8425 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
8426 	*(uint32_t *)l24_m = ipv4_m->hdr.dst_addr;
8427 	*(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr;
8428 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8429 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
8430 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8431 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
8432 	*(uint32_t *)l24_m = ipv4_m->hdr.src_addr;
8433 	*(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr;
8434 	tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service;
8435 	ihl_m = ipv4_m->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK;
8436 	ihl_v = ipv4_v->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK;
8437 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_ihl, ihl_m);
8438 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_ihl, ihl_m & ihl_v);
8439 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn,
8440 		 ipv4_m->hdr.type_of_service);
8441 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos);
8442 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp,
8443 		 ipv4_m->hdr.type_of_service >> 2);
8444 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2);
8445 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8446 		 ipv4_m->hdr.next_proto_id);
8447 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8448 		 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id);
8449 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
8450 		 ipv4_m->hdr.time_to_live);
8451 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8452 		 ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live);
8453 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
8454 		 !!(ipv4_m->hdr.fragment_offset));
8455 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8456 		 !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset));
8457 }
8458 
8459 /**
8460  * Add IPV6 item to matcher and to the value.
8461  *
8462  * @param[in, out] matcher
8463  *   Flow matcher.
8464  * @param[in, out] key
8465  *   Flow matcher value.
8466  * @param[in] item
8467  *   Flow pattern to translate.
8468  * @param[in] inner
8469  *   Item is inner pattern.
8470  * @param[in] group
8471  *   The group to insert the rule.
8472  */
8473 static void
8474 flow_dv_translate_item_ipv6(void *matcher, void *key,
8475 			    const struct rte_flow_item *item,
8476 			    int inner, uint32_t group)
8477 {
8478 	const struct rte_flow_item_ipv6 *ipv6_m = item->mask;
8479 	const struct rte_flow_item_ipv6 *ipv6_v = item->spec;
8480 	const struct rte_flow_item_ipv6 nic_mask = {
8481 		.hdr = {
8482 			.src_addr =
8483 				"\xff\xff\xff\xff\xff\xff\xff\xff"
8484 				"\xff\xff\xff\xff\xff\xff\xff\xff",
8485 			.dst_addr =
8486 				"\xff\xff\xff\xff\xff\xff\xff\xff"
8487 				"\xff\xff\xff\xff\xff\xff\xff\xff",
8488 			.vtc_flow = RTE_BE32(0xffffffff),
8489 			.proto = 0xff,
8490 			.hop_limits = 0xff,
8491 		},
8492 	};
8493 	void *headers_m;
8494 	void *headers_v;
8495 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8496 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8497 	char *l24_m;
8498 	char *l24_v;
8499 	uint32_t vtc_m;
8500 	uint32_t vtc_v;
8501 	int i;
8502 	int size;
8503 
8504 	if (inner) {
8505 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8506 					 inner_headers);
8507 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8508 	} else {
8509 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8510 					 outer_headers);
8511 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8512 	}
8513 	flow_dv_set_match_ip_version(group, headers_v, headers_m, 6);
8514 	if (!ipv6_v)
8515 		return;
8516 	if (!ipv6_m)
8517 		ipv6_m = &nic_mask;
8518 	size = sizeof(ipv6_m->hdr.dst_addr);
8519 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8520 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
8521 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8522 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
8523 	memcpy(l24_m, ipv6_m->hdr.dst_addr, size);
8524 	for (i = 0; i < size; ++i)
8525 		l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i];
8526 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
8527 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
8528 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8529 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
8530 	memcpy(l24_m, ipv6_m->hdr.src_addr, size);
8531 	for (i = 0; i < size; ++i)
8532 		l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i];
8533 	/* TOS. */
8534 	vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow);
8535 	vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow);
8536 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20);
8537 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20);
8538 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22);
8539 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22);
8540 	/* Label. */
8541 	if (inner) {
8542 		MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label,
8543 			 vtc_m);
8544 		MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label,
8545 			 vtc_v);
8546 	} else {
8547 		MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label,
8548 			 vtc_m);
8549 		MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label,
8550 			 vtc_v);
8551 	}
8552 	/* Protocol. */
8553 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8554 		 ipv6_m->hdr.proto);
8555 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8556 		 ipv6_v->hdr.proto & ipv6_m->hdr.proto);
8557 	/* Hop limit. */
8558 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ttl_hoplimit,
8559 		 ipv6_m->hdr.hop_limits);
8560 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8561 		 ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits);
8562 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag,
8563 		 !!(ipv6_m->has_frag_ext));
8564 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8565 		 !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext));
8566 }
8567 
8568 /**
8569  * Add IPV6 fragment extension item to matcher and to the value.
8570  *
8571  * @param[in, out] matcher
8572  *   Flow matcher.
8573  * @param[in, out] key
8574  *   Flow matcher value.
8575  * @param[in] item
8576  *   Flow pattern to translate.
8577  * @param[in] inner
8578  *   Item is inner pattern.
8579  */
8580 static void
8581 flow_dv_translate_item_ipv6_frag_ext(void *matcher, void *key,
8582 				     const struct rte_flow_item *item,
8583 				     int inner)
8584 {
8585 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m = item->mask;
8586 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v = item->spec;
8587 	const struct rte_flow_item_ipv6_frag_ext nic_mask = {
8588 		.hdr = {
8589 			.next_header = 0xff,
8590 			.frag_data = RTE_BE16(0xffff),
8591 		},
8592 	};
8593 	void *headers_m;
8594 	void *headers_v;
8595 
8596 	if (inner) {
8597 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8598 					 inner_headers);
8599 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8600 	} else {
8601 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8602 					 outer_headers);
8603 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8604 	}
8605 	/* IPv6 fragment extension item exists, so packet is IP fragment. */
8606 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, frag, 1);
8607 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1);
8608 	if (!ipv6_frag_ext_v)
8609 		return;
8610 	if (!ipv6_frag_ext_m)
8611 		ipv6_frag_ext_m = &nic_mask;
8612 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
8613 		 ipv6_frag_ext_m->hdr.next_header);
8614 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8615 		 ipv6_frag_ext_v->hdr.next_header &
8616 		 ipv6_frag_ext_m->hdr.next_header);
8617 }
8618 
8619 /**
8620  * Add TCP item to matcher and to the value.
8621  *
8622  * @param[in, out] matcher
8623  *   Flow matcher.
8624  * @param[in, out] key
8625  *   Flow matcher value.
8626  * @param[in] item
8627  *   Flow pattern to translate.
8628  * @param[in] inner
8629  *   Item is inner pattern.
8630  */
8631 static void
8632 flow_dv_translate_item_tcp(void *matcher, void *key,
8633 			   const struct rte_flow_item *item,
8634 			   int inner)
8635 {
8636 	const struct rte_flow_item_tcp *tcp_m = item->mask;
8637 	const struct rte_flow_item_tcp *tcp_v = item->spec;
8638 	void *headers_m;
8639 	void *headers_v;
8640 
8641 	if (inner) {
8642 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8643 					 inner_headers);
8644 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8645 	} else {
8646 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8647 					 outer_headers);
8648 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8649 	}
8650 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8651 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP);
8652 	if (!tcp_v)
8653 		return;
8654 	if (!tcp_m)
8655 		tcp_m = &rte_flow_item_tcp_mask;
8656 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport,
8657 		 rte_be_to_cpu_16(tcp_m->hdr.src_port));
8658 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
8659 		 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port));
8660 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport,
8661 		 rte_be_to_cpu_16(tcp_m->hdr.dst_port));
8662 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
8663 		 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port));
8664 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags,
8665 		 tcp_m->hdr.tcp_flags);
8666 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
8667 		 (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags));
8668 }
8669 
8670 /**
8671  * Add UDP item to matcher and to the value.
8672  *
8673  * @param[in, out] matcher
8674  *   Flow matcher.
8675  * @param[in, out] key
8676  *   Flow matcher value.
8677  * @param[in] item
8678  *   Flow pattern to translate.
8679  * @param[in] inner
8680  *   Item is inner pattern.
8681  */
8682 static void
8683 flow_dv_translate_item_udp(void *matcher, void *key,
8684 			   const struct rte_flow_item *item,
8685 			   int inner)
8686 {
8687 	const struct rte_flow_item_udp *udp_m = item->mask;
8688 	const struct rte_flow_item_udp *udp_v = item->spec;
8689 	void *headers_m;
8690 	void *headers_v;
8691 
8692 	if (inner) {
8693 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8694 					 inner_headers);
8695 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8696 	} else {
8697 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8698 					 outer_headers);
8699 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8700 	}
8701 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8702 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
8703 	if (!udp_v)
8704 		return;
8705 	if (!udp_m)
8706 		udp_m = &rte_flow_item_udp_mask;
8707 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport,
8708 		 rte_be_to_cpu_16(udp_m->hdr.src_port));
8709 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
8710 		 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port));
8711 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport,
8712 		 rte_be_to_cpu_16(udp_m->hdr.dst_port));
8713 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
8714 		 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port));
8715 }
8716 
8717 /**
8718  * Add GRE optional Key item to matcher and to the value.
8719  *
8720  * @param[in, out] matcher
8721  *   Flow matcher.
8722  * @param[in, out] key
8723  *   Flow matcher value.
8724  * @param[in] item
8725  *   Flow pattern to translate.
8726  * @param[in] inner
8727  *   Item is inner pattern.
8728  */
8729 static void
8730 flow_dv_translate_item_gre_key(void *matcher, void *key,
8731 				   const struct rte_flow_item *item)
8732 {
8733 	const rte_be32_t *key_m = item->mask;
8734 	const rte_be32_t *key_v = item->spec;
8735 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8736 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8737 	rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX);
8738 
8739 	/* GRE K bit must be on and should already be validated */
8740 	MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1);
8741 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1);
8742 	if (!key_v)
8743 		return;
8744 	if (!key_m)
8745 		key_m = &gre_key_default_mask;
8746 	MLX5_SET(fte_match_set_misc, misc_m, gre_key_h,
8747 		 rte_be_to_cpu_32(*key_m) >> 8);
8748 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_h,
8749 		 rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8);
8750 	MLX5_SET(fte_match_set_misc, misc_m, gre_key_l,
8751 		 rte_be_to_cpu_32(*key_m) & 0xFF);
8752 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_l,
8753 		 rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF);
8754 }
8755 
8756 /**
8757  * Add GRE item to matcher and to the value.
8758  *
8759  * @param[in, out] matcher
8760  *   Flow matcher.
8761  * @param[in, out] key
8762  *   Flow matcher value.
8763  * @param[in] item
8764  *   Flow pattern to translate.
8765  * @param[in] pattern_flags
8766  *   Accumulated pattern flags.
8767  */
8768 static void
8769 flow_dv_translate_item_gre(void *matcher, void *key,
8770 			   const struct rte_flow_item *item,
8771 			   uint64_t pattern_flags)
8772 {
8773 	static const struct rte_flow_item_gre empty_gre = {0,};
8774 	const struct rte_flow_item_gre *gre_m = item->mask;
8775 	const struct rte_flow_item_gre *gre_v = item->spec;
8776 	void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
8777 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8778 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8779 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8780 	struct {
8781 		union {
8782 			__extension__
8783 			struct {
8784 				uint16_t version:3;
8785 				uint16_t rsvd0:9;
8786 				uint16_t s_present:1;
8787 				uint16_t k_present:1;
8788 				uint16_t rsvd_bit1:1;
8789 				uint16_t c_present:1;
8790 			};
8791 			uint16_t value;
8792 		};
8793 	} gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v;
8794 	uint16_t protocol_m, protocol_v;
8795 
8796 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
8797 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
8798 	if (!gre_v) {
8799 		gre_v = &empty_gre;
8800 		gre_m = &empty_gre;
8801 	} else {
8802 		if (!gre_m)
8803 			gre_m = &rte_flow_item_gre_mask;
8804 	}
8805 	gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver);
8806 	gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver);
8807 	MLX5_SET(fte_match_set_misc, misc_m, gre_c_present,
8808 		 gre_crks_rsvd0_ver_m.c_present);
8809 	MLX5_SET(fte_match_set_misc, misc_v, gre_c_present,
8810 		 gre_crks_rsvd0_ver_v.c_present &
8811 		 gre_crks_rsvd0_ver_m.c_present);
8812 	MLX5_SET(fte_match_set_misc, misc_m, gre_k_present,
8813 		 gre_crks_rsvd0_ver_m.k_present);
8814 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present,
8815 		 gre_crks_rsvd0_ver_v.k_present &
8816 		 gre_crks_rsvd0_ver_m.k_present);
8817 	MLX5_SET(fte_match_set_misc, misc_m, gre_s_present,
8818 		 gre_crks_rsvd0_ver_m.s_present);
8819 	MLX5_SET(fte_match_set_misc, misc_v, gre_s_present,
8820 		 gre_crks_rsvd0_ver_v.s_present &
8821 		 gre_crks_rsvd0_ver_m.s_present);
8822 	protocol_m = rte_be_to_cpu_16(gre_m->protocol);
8823 	protocol_v = rte_be_to_cpu_16(gre_v->protocol);
8824 	if (!protocol_m) {
8825 		/* Force next protocol to prevent matchers duplication */
8826 		protocol_v = mlx5_translate_tunnel_etypes(pattern_flags);
8827 		if (protocol_v)
8828 			protocol_m = 0xFFFF;
8829 	}
8830 	MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, protocol_m);
8831 	MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
8832 		 protocol_m & protocol_v);
8833 }
8834 
8835 /**
8836  * Add NVGRE item to matcher and to the value.
8837  *
8838  * @param[in, out] matcher
8839  *   Flow matcher.
8840  * @param[in, out] key
8841  *   Flow matcher value.
8842  * @param[in] item
8843  *   Flow pattern to translate.
8844  * @param[in] pattern_flags
8845  *   Accumulated pattern flags.
8846  */
8847 static void
8848 flow_dv_translate_item_nvgre(void *matcher, void *key,
8849 			     const struct rte_flow_item *item,
8850 			     unsigned long pattern_flags)
8851 {
8852 	const struct rte_flow_item_nvgre *nvgre_m = item->mask;
8853 	const struct rte_flow_item_nvgre *nvgre_v = item->spec;
8854 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
8855 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8856 	const char *tni_flow_id_m;
8857 	const char *tni_flow_id_v;
8858 	char *gre_key_m;
8859 	char *gre_key_v;
8860 	int size;
8861 	int i;
8862 
8863 	/* For NVGRE, GRE header fields must be set with defined values. */
8864 	const struct rte_flow_item_gre gre_spec = {
8865 		.c_rsvd0_ver = RTE_BE16(0x2000),
8866 		.protocol = RTE_BE16(RTE_ETHER_TYPE_TEB)
8867 	};
8868 	const struct rte_flow_item_gre gre_mask = {
8869 		.c_rsvd0_ver = RTE_BE16(0xB000),
8870 		.protocol = RTE_BE16(UINT16_MAX),
8871 	};
8872 	const struct rte_flow_item gre_item = {
8873 		.spec = &gre_spec,
8874 		.mask = &gre_mask,
8875 		.last = NULL,
8876 	};
8877 	flow_dv_translate_item_gre(matcher, key, &gre_item, pattern_flags);
8878 	if (!nvgre_v)
8879 		return;
8880 	if (!nvgre_m)
8881 		nvgre_m = &rte_flow_item_nvgre_mask;
8882 	tni_flow_id_m = (const char *)nvgre_m->tni;
8883 	tni_flow_id_v = (const char *)nvgre_v->tni;
8884 	size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
8885 	gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h);
8886 	gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
8887 	memcpy(gre_key_m, tni_flow_id_m, size);
8888 	for (i = 0; i < size; ++i)
8889 		gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i];
8890 }
8891 
8892 /**
8893  * Add VXLAN item to matcher and to the value.
8894  *
8895  * @param[in] dev
8896  *   Pointer to the Ethernet device structure.
8897  * @param[in] attr
8898  *   Flow rule attributes.
8899  * @param[in, out] matcher
8900  *   Flow matcher.
8901  * @param[in, out] key
8902  *   Flow matcher value.
8903  * @param[in] item
8904  *   Flow pattern to translate.
8905  * @param[in] inner
8906  *   Item is inner pattern.
8907  */
8908 static void
8909 flow_dv_translate_item_vxlan(struct rte_eth_dev *dev,
8910 			     const struct rte_flow_attr *attr,
8911 			     void *matcher, void *key,
8912 			     const struct rte_flow_item *item,
8913 			     int inner)
8914 {
8915 	const struct rte_flow_item_vxlan *vxlan_m = item->mask;
8916 	const struct rte_flow_item_vxlan *vxlan_v = item->spec;
8917 	void *headers_m;
8918 	void *headers_v;
8919 	void *misc5_m;
8920 	void *misc5_v;
8921 	uint32_t *tunnel_header_v;
8922 	uint32_t *tunnel_header_m;
8923 	uint16_t dport;
8924 	struct mlx5_priv *priv = dev->data->dev_private;
8925 	const struct rte_flow_item_vxlan nic_mask = {
8926 		.vni = "\xff\xff\xff",
8927 		.rsvd1 = 0xff,
8928 	};
8929 
8930 	if (inner) {
8931 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8932 					 inner_headers);
8933 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8934 	} else {
8935 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
8936 					 outer_headers);
8937 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8938 	}
8939 	dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
8940 		MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
8941 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
8942 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
8943 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
8944 	}
8945 	dport = MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport);
8946 	if (!vxlan_v)
8947 		return;
8948 	if (!vxlan_m) {
8949 		if ((!attr->group && !priv->sh->tunnel_header_0_1) ||
8950 		    (attr->group && !priv->sh->misc5_cap))
8951 			vxlan_m = &rte_flow_item_vxlan_mask;
8952 		else
8953 			vxlan_m = &nic_mask;
8954 	}
8955 	if ((priv->sh->steering_format_version ==
8956 	    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 &&
8957 	    dport != MLX5_UDP_PORT_VXLAN) ||
8958 	    (!attr->group && !attr->transfer && !priv->sh->tunnel_header_0_1) ||
8959 	    ((attr->group || attr->transfer) && !priv->sh->misc5_cap)) {
8960 		void *misc_m;
8961 		void *misc_v;
8962 		char *vni_m;
8963 		char *vni_v;
8964 		int size;
8965 		int i;
8966 		misc_m = MLX5_ADDR_OF(fte_match_param,
8967 				      matcher, misc_parameters);
8968 		misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8969 		size = sizeof(vxlan_m->vni);
8970 		vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni);
8971 		vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni);
8972 		memcpy(vni_m, vxlan_m->vni, size);
8973 		for (i = 0; i < size; ++i)
8974 			vni_v[i] = vni_m[i] & vxlan_v->vni[i];
8975 		return;
8976 	}
8977 	misc5_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_5);
8978 	misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5);
8979 	tunnel_header_v = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5,
8980 						   misc5_v,
8981 						   tunnel_header_1);
8982 	tunnel_header_m = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5,
8983 						   misc5_m,
8984 						   tunnel_header_1);
8985 	*tunnel_header_v = (vxlan_v->vni[0] & vxlan_m->vni[0]) |
8986 			   (vxlan_v->vni[1] & vxlan_m->vni[1]) << 8 |
8987 			   (vxlan_v->vni[2] & vxlan_m->vni[2]) << 16;
8988 	if (*tunnel_header_v)
8989 		*tunnel_header_m = vxlan_m->vni[0] |
8990 			vxlan_m->vni[1] << 8 |
8991 			vxlan_m->vni[2] << 16;
8992 	else
8993 		*tunnel_header_m = 0x0;
8994 	*tunnel_header_v |= (vxlan_v->rsvd1 & vxlan_m->rsvd1) << 24;
8995 	if (vxlan_v->rsvd1 & vxlan_m->rsvd1)
8996 		*tunnel_header_m |= vxlan_m->rsvd1 << 24;
8997 }
8998 
8999 /**
9000  * Add VXLAN-GPE item to matcher and to the value.
9001  *
9002  * @param[in, out] matcher
9003  *   Flow matcher.
9004  * @param[in, out] key
9005  *   Flow matcher value.
9006  * @param[in] item
9007  *   Flow pattern to translate.
9008  * @param[in] inner
9009  *   Item is inner pattern.
9010  */
9011 
9012 static void
9013 flow_dv_translate_item_vxlan_gpe(void *matcher, void *key,
9014 				 const struct rte_flow_item *item,
9015 				 const uint64_t pattern_flags)
9016 {
9017 	static const struct rte_flow_item_vxlan_gpe dummy_vxlan_gpe_hdr = {0, };
9018 	const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask;
9019 	const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec;
9020 	/* The item was validated to be on the outer side */
9021 	void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
9022 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9023 	void *misc_m =
9024 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_3);
9025 	void *misc_v =
9026 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9027 	char *vni_m =
9028 		MLX5_ADDR_OF(fte_match_set_misc3, misc_m, outer_vxlan_gpe_vni);
9029 	char *vni_v =
9030 		MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni);
9031 	int i, size = sizeof(vxlan_m->vni);
9032 	uint8_t flags_m = 0xff;
9033 	uint8_t flags_v = 0xc;
9034 	uint8_t m_protocol, v_protocol;
9035 
9036 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9037 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
9038 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9039 			 MLX5_UDP_PORT_VXLAN_GPE);
9040 	}
9041 	if (!vxlan_v) {
9042 		vxlan_v = &dummy_vxlan_gpe_hdr;
9043 		vxlan_m = &dummy_vxlan_gpe_hdr;
9044 	} else {
9045 		if (!vxlan_m)
9046 			vxlan_m = &rte_flow_item_vxlan_gpe_mask;
9047 	}
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 	m_protocol = vxlan_m->protocol;
9058 	v_protocol = vxlan_v->protocol;
9059 	if (!m_protocol) {
9060 		/* Force next protocol to ensure next headers parsing. */
9061 		if (pattern_flags & MLX5_FLOW_LAYER_INNER_L2)
9062 			v_protocol = RTE_VXLAN_GPE_TYPE_ETH;
9063 		else if (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4)
9064 			v_protocol = RTE_VXLAN_GPE_TYPE_IPV4;
9065 		else if (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)
9066 			v_protocol = RTE_VXLAN_GPE_TYPE_IPV6;
9067 		if (v_protocol)
9068 			m_protocol = 0xFF;
9069 	}
9070 	MLX5_SET(fte_match_set_misc3, misc_m,
9071 		 outer_vxlan_gpe_next_protocol, m_protocol);
9072 	MLX5_SET(fte_match_set_misc3, misc_v,
9073 		 outer_vxlan_gpe_next_protocol, m_protocol & v_protocol);
9074 }
9075 
9076 /**
9077  * Add Geneve item to matcher and to the value.
9078  *
9079  * @param[in, out] matcher
9080  *   Flow matcher.
9081  * @param[in, out] key
9082  *   Flow matcher value.
9083  * @param[in] item
9084  *   Flow pattern to translate.
9085  * @param[in] inner
9086  *   Item is inner pattern.
9087  */
9088 
9089 static void
9090 flow_dv_translate_item_geneve(void *matcher, void *key,
9091 			      const struct rte_flow_item *item,
9092 			      uint64_t pattern_flags)
9093 {
9094 	static const struct rte_flow_item_geneve empty_geneve = {0,};
9095 	const struct rte_flow_item_geneve *geneve_m = item->mask;
9096 	const struct rte_flow_item_geneve *geneve_v = item->spec;
9097 	/* GENEVE flow item validation allows single tunnel item */
9098 	void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
9099 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9100 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9101 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9102 	uint16_t gbhdr_m;
9103 	uint16_t gbhdr_v;
9104 	char *vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, geneve_vni);
9105 	char *vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni);
9106 	size_t size = sizeof(geneve_m->vni), i;
9107 	uint16_t protocol_m, protocol_v;
9108 
9109 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9110 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
9111 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9112 			 MLX5_UDP_PORT_GENEVE);
9113 	}
9114 	if (!geneve_v) {
9115 		geneve_v = &empty_geneve;
9116 		geneve_m = &empty_geneve;
9117 	} else {
9118 		if (!geneve_m)
9119 			geneve_m = &rte_flow_item_geneve_mask;
9120 	}
9121 	memcpy(vni_m, geneve_m->vni, size);
9122 	for (i = 0; i < size; ++i)
9123 		vni_v[i] = vni_m[i] & geneve_v->vni[i];
9124 	gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0);
9125 	gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0);
9126 	MLX5_SET(fte_match_set_misc, misc_m, geneve_oam,
9127 		 MLX5_GENEVE_OAMF_VAL(gbhdr_m));
9128 	MLX5_SET(fte_match_set_misc, misc_v, geneve_oam,
9129 		 MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m));
9130 	MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
9131 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
9132 	MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9133 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) &
9134 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
9135 	protocol_m = rte_be_to_cpu_16(geneve_m->protocol);
9136 	protocol_v = rte_be_to_cpu_16(geneve_v->protocol);
9137 	if (!protocol_m) {
9138 		/* Force next protocol to prevent matchers duplication */
9139 		protocol_v = mlx5_translate_tunnel_etypes(pattern_flags);
9140 		if (protocol_v)
9141 			protocol_m = 0xFFFF;
9142 	}
9143 	MLX5_SET(fte_match_set_misc, misc_m, geneve_protocol_type, protocol_m);
9144 	MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type,
9145 		 protocol_m & protocol_v);
9146 }
9147 
9148 /**
9149  * Create Geneve TLV option resource.
9150  *
9151  * @param dev[in, out]
9152  *   Pointer to rte_eth_dev structure.
9153  * @param[in, out] tag_be24
9154  *   Tag value in big endian then R-shift 8.
9155  * @parm[in, out] dev_flow
9156  *   Pointer to the dev_flow.
9157  * @param[out] error
9158  *   pointer to error structure.
9159  *
9160  * @return
9161  *   0 on success otherwise -errno and errno is set.
9162  */
9163 
9164 int
9165 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev,
9166 					     const struct rte_flow_item *item,
9167 					     struct rte_flow_error *error)
9168 {
9169 	struct mlx5_priv *priv = dev->data->dev_private;
9170 	struct mlx5_dev_ctx_shared *sh = priv->sh;
9171 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
9172 			sh->geneve_tlv_option_resource;
9173 	struct mlx5_devx_obj *obj;
9174 	const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
9175 	int ret = 0;
9176 
9177 	if (!geneve_opt_v)
9178 		return -1;
9179 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
9180 	if (geneve_opt_resource != NULL) {
9181 		if (geneve_opt_resource->option_class ==
9182 			geneve_opt_v->option_class &&
9183 			geneve_opt_resource->option_type ==
9184 			geneve_opt_v->option_type &&
9185 			geneve_opt_resource->length ==
9186 			geneve_opt_v->option_len) {
9187 			/* We already have GENVE TLV option obj allocated. */
9188 			__atomic_fetch_add(&geneve_opt_resource->refcnt, 1,
9189 					   __ATOMIC_RELAXED);
9190 		} else {
9191 			ret = rte_flow_error_set(error, ENOMEM,
9192 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9193 				"Only one GENEVE TLV option supported");
9194 			goto exit;
9195 		}
9196 	} else {
9197 		/* Create a GENEVE TLV object and resource. */
9198 		obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->cdev->ctx,
9199 				geneve_opt_v->option_class,
9200 				geneve_opt_v->option_type,
9201 				geneve_opt_v->option_len);
9202 		if (!obj) {
9203 			ret = rte_flow_error_set(error, ENODATA,
9204 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9205 				"Failed to create GENEVE TLV Devx object");
9206 			goto exit;
9207 		}
9208 		sh->geneve_tlv_option_resource =
9209 				mlx5_malloc(MLX5_MEM_ZERO,
9210 						sizeof(*geneve_opt_resource),
9211 						0, SOCKET_ID_ANY);
9212 		if (!sh->geneve_tlv_option_resource) {
9213 			claim_zero(mlx5_devx_cmd_destroy(obj));
9214 			ret = rte_flow_error_set(error, ENOMEM,
9215 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9216 				"GENEVE TLV object memory allocation failed");
9217 			goto exit;
9218 		}
9219 		geneve_opt_resource = sh->geneve_tlv_option_resource;
9220 		geneve_opt_resource->obj = obj;
9221 		geneve_opt_resource->option_class = geneve_opt_v->option_class;
9222 		geneve_opt_resource->option_type = geneve_opt_v->option_type;
9223 		geneve_opt_resource->length = geneve_opt_v->option_len;
9224 		__atomic_store_n(&geneve_opt_resource->refcnt, 1,
9225 				__ATOMIC_RELAXED);
9226 	}
9227 exit:
9228 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
9229 	return ret;
9230 }
9231 
9232 /**
9233  * Add Geneve TLV option item to matcher.
9234  *
9235  * @param[in, out] dev
9236  *   Pointer to rte_eth_dev structure.
9237  * @param[in, out] matcher
9238  *   Flow matcher.
9239  * @param[in, out] key
9240  *   Flow matcher value.
9241  * @param[in] item
9242  *   Flow pattern to translate.
9243  * @param[out] error
9244  *   Pointer to error structure.
9245  */
9246 static int
9247 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *matcher,
9248 				  void *key, const struct rte_flow_item *item,
9249 				  struct rte_flow_error *error)
9250 {
9251 	const struct rte_flow_item_geneve_opt *geneve_opt_m = item->mask;
9252 	const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
9253 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9254 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9255 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9256 			misc_parameters_3);
9257 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9258 	rte_be32_t opt_data_key = 0, opt_data_mask = 0;
9259 	int ret = 0;
9260 
9261 	if (!geneve_opt_v)
9262 		return -1;
9263 	if (!geneve_opt_m)
9264 		geneve_opt_m = &rte_flow_item_geneve_opt_mask;
9265 	ret = flow_dev_geneve_tlv_option_resource_register(dev, item,
9266 							   error);
9267 	if (ret) {
9268 		DRV_LOG(ERR, "Failed to create geneve_tlv_obj");
9269 		return ret;
9270 	}
9271 	/*
9272 	 * Set the option length in GENEVE header if not requested.
9273 	 * The GENEVE TLV option length is expressed by the option length field
9274 	 * in the GENEVE header.
9275 	 * If the option length was not requested but the GENEVE TLV option item
9276 	 * is present we set the option length field implicitly.
9277 	 */
9278 	if (!MLX5_GET16(fte_match_set_misc, misc_m, geneve_opt_len)) {
9279 		MLX5_SET(fte_match_set_misc, misc_m, geneve_opt_len,
9280 			 MLX5_GENEVE_OPTLEN_MASK);
9281 		MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9282 			 geneve_opt_v->option_len + 1);
9283 	}
9284 	MLX5_SET(fte_match_set_misc, misc_m, geneve_tlv_option_0_exist, 1);
9285 	MLX5_SET(fte_match_set_misc, misc_v, geneve_tlv_option_0_exist, 1);
9286 	/* Set the data. */
9287 	if (geneve_opt_v->data) {
9288 		memcpy(&opt_data_key, geneve_opt_v->data,
9289 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9290 				sizeof(opt_data_key)));
9291 		MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
9292 				sizeof(opt_data_key));
9293 		memcpy(&opt_data_mask, geneve_opt_m->data,
9294 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9295 				sizeof(opt_data_mask)));
9296 		MLX5_ASSERT((uint32_t)(geneve_opt_v->option_len * 4) <=
9297 				sizeof(opt_data_mask));
9298 		MLX5_SET(fte_match_set_misc3, misc3_m,
9299 				geneve_tlv_option_0_data,
9300 				rte_be_to_cpu_32(opt_data_mask));
9301 		MLX5_SET(fte_match_set_misc3, misc3_v,
9302 				geneve_tlv_option_0_data,
9303 			rte_be_to_cpu_32(opt_data_key & opt_data_mask));
9304 	}
9305 	return ret;
9306 }
9307 
9308 /**
9309  * Add MPLS item to matcher and to the value.
9310  *
9311  * @param[in, out] matcher
9312  *   Flow matcher.
9313  * @param[in, out] key
9314  *   Flow matcher value.
9315  * @param[in] item
9316  *   Flow pattern to translate.
9317  * @param[in] prev_layer
9318  *   The protocol layer indicated in previous item.
9319  * @param[in] inner
9320  *   Item is inner pattern.
9321  */
9322 static void
9323 flow_dv_translate_item_mpls(void *matcher, void *key,
9324 			    const struct rte_flow_item *item,
9325 			    uint64_t prev_layer,
9326 			    int inner)
9327 {
9328 	const uint32_t *in_mpls_m = item->mask;
9329 	const uint32_t *in_mpls_v = item->spec;
9330 	uint32_t *out_mpls_m = 0;
9331 	uint32_t *out_mpls_v = 0;
9332 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9333 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9334 	void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher,
9335 				     misc_parameters_2);
9336 	void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9337 	void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
9338 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9339 
9340 	switch (prev_layer) {
9341 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9342 		if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9343 			MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport,
9344 				 0xffff);
9345 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9346 				 MLX5_UDP_PORT_MPLS);
9347 		}
9348 		break;
9349 	case MLX5_FLOW_LAYER_GRE:
9350 		/* Fall-through. */
9351 	case MLX5_FLOW_LAYER_GRE_KEY:
9352 		if (!MLX5_GET16(fte_match_set_misc, misc_v, gre_protocol)) {
9353 			MLX5_SET(fte_match_set_misc, misc_m, gre_protocol,
9354 				 0xffff);
9355 			MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
9356 				 RTE_ETHER_TYPE_MPLS);
9357 		}
9358 		break;
9359 	default:
9360 		break;
9361 	}
9362 	if (!in_mpls_v)
9363 		return;
9364 	if (!in_mpls_m)
9365 		in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask;
9366 	switch (prev_layer) {
9367 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9368 		out_mpls_m =
9369 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
9370 						 outer_first_mpls_over_udp);
9371 		out_mpls_v =
9372 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9373 						 outer_first_mpls_over_udp);
9374 		break;
9375 	case MLX5_FLOW_LAYER_GRE:
9376 		out_mpls_m =
9377 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
9378 						 outer_first_mpls_over_gre);
9379 		out_mpls_v =
9380 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9381 						 outer_first_mpls_over_gre);
9382 		break;
9383 	default:
9384 		/* Inner MPLS not over GRE is not supported. */
9385 		if (!inner) {
9386 			out_mpls_m =
9387 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
9388 							 misc2_m,
9389 							 outer_first_mpls);
9390 			out_mpls_v =
9391 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
9392 							 misc2_v,
9393 							 outer_first_mpls);
9394 		}
9395 		break;
9396 	}
9397 	if (out_mpls_m && out_mpls_v) {
9398 		*out_mpls_m = *in_mpls_m;
9399 		*out_mpls_v = *in_mpls_v & *in_mpls_m;
9400 	}
9401 }
9402 
9403 /**
9404  * Add metadata register item to matcher
9405  *
9406  * @param[in, out] matcher
9407  *   Flow matcher.
9408  * @param[in, out] key
9409  *   Flow matcher value.
9410  * @param[in] reg_type
9411  *   Type of device metadata register
9412  * @param[in] value
9413  *   Register value
9414  * @param[in] mask
9415  *   Register mask
9416  */
9417 static void
9418 flow_dv_match_meta_reg(void *matcher, void *key,
9419 		       enum modify_reg reg_type,
9420 		       uint32_t data, uint32_t mask)
9421 {
9422 	void *misc2_m =
9423 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2);
9424 	void *misc2_v =
9425 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9426 	uint32_t temp;
9427 
9428 	data &= mask;
9429 	switch (reg_type) {
9430 	case REG_A:
9431 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a, mask);
9432 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data);
9433 		break;
9434 	case REG_B:
9435 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_b, mask);
9436 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data);
9437 		break;
9438 	case REG_C_0:
9439 		/*
9440 		 * The metadata register C0 field might be divided into
9441 		 * source vport index and META item value, we should set
9442 		 * this field according to specified mask, not as whole one.
9443 		 */
9444 		temp = MLX5_GET(fte_match_set_misc2, misc2_m, metadata_reg_c_0);
9445 		temp |= mask;
9446 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_0, temp);
9447 		temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0);
9448 		temp &= ~mask;
9449 		temp |= data;
9450 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp);
9451 		break;
9452 	case REG_C_1:
9453 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_1, mask);
9454 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data);
9455 		break;
9456 	case REG_C_2:
9457 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_2, mask);
9458 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data);
9459 		break;
9460 	case REG_C_3:
9461 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_3, mask);
9462 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data);
9463 		break;
9464 	case REG_C_4:
9465 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_4, mask);
9466 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data);
9467 		break;
9468 	case REG_C_5:
9469 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_5, mask);
9470 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data);
9471 		break;
9472 	case REG_C_6:
9473 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_6, mask);
9474 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data);
9475 		break;
9476 	case REG_C_7:
9477 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_c_7, mask);
9478 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data);
9479 		break;
9480 	default:
9481 		MLX5_ASSERT(false);
9482 		break;
9483 	}
9484 }
9485 
9486 /**
9487  * Add MARK item to matcher
9488  *
9489  * @param[in] dev
9490  *   The device to configure through.
9491  * @param[in, out] matcher
9492  *   Flow matcher.
9493  * @param[in, out] key
9494  *   Flow matcher value.
9495  * @param[in] item
9496  *   Flow pattern to translate.
9497  */
9498 static void
9499 flow_dv_translate_item_mark(struct rte_eth_dev *dev,
9500 			    void *matcher, void *key,
9501 			    const struct rte_flow_item *item)
9502 {
9503 	struct mlx5_priv *priv = dev->data->dev_private;
9504 	const struct rte_flow_item_mark *mark;
9505 	uint32_t value;
9506 	uint32_t mask;
9507 
9508 	mark = item->mask ? (const void *)item->mask :
9509 			    &rte_flow_item_mark_mask;
9510 	mask = mark->id & priv->sh->dv_mark_mask;
9511 	mark = (const void *)item->spec;
9512 	MLX5_ASSERT(mark);
9513 	value = mark->id & priv->sh->dv_mark_mask & mask;
9514 	if (mask) {
9515 		enum modify_reg reg;
9516 
9517 		/* Get the metadata register index for the mark. */
9518 		reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL);
9519 		MLX5_ASSERT(reg > 0);
9520 		if (reg == REG_C_0) {
9521 			struct mlx5_priv *priv = dev->data->dev_private;
9522 			uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9523 			uint32_t shl_c0 = rte_bsf32(msk_c0);
9524 
9525 			mask &= msk_c0;
9526 			mask <<= shl_c0;
9527 			value <<= shl_c0;
9528 		}
9529 		flow_dv_match_meta_reg(matcher, key, reg, value, mask);
9530 	}
9531 }
9532 
9533 /**
9534  * Add META item to matcher
9535  *
9536  * @param[in] dev
9537  *   The devich to configure through.
9538  * @param[in, out] matcher
9539  *   Flow matcher.
9540  * @param[in, out] key
9541  *   Flow matcher value.
9542  * @param[in] attr
9543  *   Attributes of flow that includes this item.
9544  * @param[in] item
9545  *   Flow pattern to translate.
9546  */
9547 static void
9548 flow_dv_translate_item_meta(struct rte_eth_dev *dev,
9549 			    void *matcher, void *key,
9550 			    const struct rte_flow_attr *attr,
9551 			    const struct rte_flow_item *item)
9552 {
9553 	const struct rte_flow_item_meta *meta_m;
9554 	const struct rte_flow_item_meta *meta_v;
9555 
9556 	meta_m = (const void *)item->mask;
9557 	if (!meta_m)
9558 		meta_m = &rte_flow_item_meta_mask;
9559 	meta_v = (const void *)item->spec;
9560 	if (meta_v) {
9561 		int reg;
9562 		uint32_t value = meta_v->data;
9563 		uint32_t mask = meta_m->data;
9564 
9565 		reg = flow_dv_get_metadata_reg(dev, attr, NULL);
9566 		if (reg < 0)
9567 			return;
9568 		MLX5_ASSERT(reg != REG_NON);
9569 		if (reg == REG_C_0) {
9570 			struct mlx5_priv *priv = dev->data->dev_private;
9571 			uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9572 			uint32_t shl_c0 = rte_bsf32(msk_c0);
9573 
9574 			mask &= msk_c0;
9575 			mask <<= shl_c0;
9576 			value <<= shl_c0;
9577 		}
9578 		flow_dv_match_meta_reg(matcher, key, reg, value, mask);
9579 	}
9580 }
9581 
9582 /**
9583  * Add vport metadata Reg C0 item to matcher
9584  *
9585  * @param[in, out] matcher
9586  *   Flow matcher.
9587  * @param[in, out] key
9588  *   Flow matcher value.
9589  * @param[in] reg
9590  *   Flow pattern to translate.
9591  */
9592 static void
9593 flow_dv_translate_item_meta_vport(void *matcher, void *key,
9594 				  uint32_t value, uint32_t mask)
9595 {
9596 	flow_dv_match_meta_reg(matcher, key, REG_C_0, value, mask);
9597 }
9598 
9599 /**
9600  * Add tag item to matcher
9601  *
9602  * @param[in] dev
9603  *   The devich to configure through.
9604  * @param[in, out] matcher
9605  *   Flow matcher.
9606  * @param[in, out] key
9607  *   Flow matcher value.
9608  * @param[in] item
9609  *   Flow pattern to translate.
9610  */
9611 static void
9612 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev,
9613 				void *matcher, void *key,
9614 				const struct rte_flow_item *item)
9615 {
9616 	const struct mlx5_rte_flow_item_tag *tag_v = item->spec;
9617 	const struct mlx5_rte_flow_item_tag *tag_m = item->mask;
9618 	uint32_t mask, value;
9619 
9620 	MLX5_ASSERT(tag_v);
9621 	value = tag_v->data;
9622 	mask = tag_m ? tag_m->data : UINT32_MAX;
9623 	if (tag_v->id == REG_C_0) {
9624 		struct mlx5_priv *priv = dev->data->dev_private;
9625 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9626 		uint32_t shl_c0 = rte_bsf32(msk_c0);
9627 
9628 		mask &= msk_c0;
9629 		mask <<= shl_c0;
9630 		value <<= shl_c0;
9631 	}
9632 	flow_dv_match_meta_reg(matcher, key, tag_v->id, value, mask);
9633 }
9634 
9635 /**
9636  * Add TAG item to matcher
9637  *
9638  * @param[in] dev
9639  *   The devich to configure through.
9640  * @param[in, out] matcher
9641  *   Flow matcher.
9642  * @param[in, out] key
9643  *   Flow matcher value.
9644  * @param[in] item
9645  *   Flow pattern to translate.
9646  */
9647 static void
9648 flow_dv_translate_item_tag(struct rte_eth_dev *dev,
9649 			   void *matcher, void *key,
9650 			   const struct rte_flow_item *item)
9651 {
9652 	const struct rte_flow_item_tag *tag_v = item->spec;
9653 	const struct rte_flow_item_tag *tag_m = item->mask;
9654 	enum modify_reg reg;
9655 
9656 	MLX5_ASSERT(tag_v);
9657 	tag_m = tag_m ? tag_m : &rte_flow_item_tag_mask;
9658 	/* Get the metadata register index for the tag. */
9659 	reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, tag_v->index, NULL);
9660 	MLX5_ASSERT(reg > 0);
9661 	flow_dv_match_meta_reg(matcher, key, reg, tag_v->data, tag_m->data);
9662 }
9663 
9664 /**
9665  * Add source vport match to the specified matcher.
9666  *
9667  * @param[in, out] matcher
9668  *   Flow matcher.
9669  * @param[in, out] key
9670  *   Flow matcher value.
9671  * @param[in] port
9672  *   Source vport value to match
9673  * @param[in] mask
9674  *   Mask
9675  */
9676 static void
9677 flow_dv_translate_item_source_vport(void *matcher, void *key,
9678 				    int16_t port, uint16_t mask)
9679 {
9680 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
9681 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9682 
9683 	MLX5_SET(fte_match_set_misc, misc_m, source_port, mask);
9684 	MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
9685 }
9686 
9687 /**
9688  * Translate port-id item to eswitch match on  port-id.
9689  *
9690  * @param[in] dev
9691  *   The devich to configure through.
9692  * @param[in, out] matcher
9693  *   Flow matcher.
9694  * @param[in, out] key
9695  *   Flow matcher value.
9696  * @param[in] item
9697  *   Flow pattern to translate.
9698  * @param[in]
9699  *   Flow attributes.
9700  *
9701  * @return
9702  *   0 on success, a negative errno value otherwise.
9703  */
9704 static int
9705 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher,
9706 			       void *key, const struct rte_flow_item *item,
9707 			       const struct rte_flow_attr *attr)
9708 {
9709 	const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL;
9710 	const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL;
9711 	struct mlx5_priv *priv;
9712 	uint16_t mask, id;
9713 
9714 	if (pid_v && pid_v->id == MLX5_PORT_ESW_MGR) {
9715 		flow_dv_translate_item_source_vport(matcher, key,
9716 			flow_dv_get_esw_manager_vport_id(dev), 0xffff);
9717 		return 0;
9718 	}
9719 	mask = pid_m ? pid_m->id : 0xffff;
9720 	id = pid_v ? pid_v->id : dev->data->port_id;
9721 	priv = mlx5_port_to_eswitch_info(id, item == NULL);
9722 	if (!priv)
9723 		return -rte_errno;
9724 	/*
9725 	 * Translate to vport field or to metadata, depending on mode.
9726 	 * Kernel can use either misc.source_port or half of C0 metadata
9727 	 * register.
9728 	 */
9729 	if (priv->vport_meta_mask) {
9730 		/*
9731 		 * Provide the hint for SW steering library
9732 		 * to insert the flow into ingress domain and
9733 		 * save the extra vport match.
9734 		 */
9735 		if (mask == 0xffff && priv->vport_id == 0xffff &&
9736 		    priv->pf_bond < 0 && attr->transfer)
9737 			flow_dv_translate_item_source_vport
9738 				(matcher, key, priv->vport_id, mask);
9739 		/*
9740 		 * We should always set the vport metadata register,
9741 		 * otherwise the SW steering library can drop
9742 		 * the rule if wire vport metadata value is not zero,
9743 		 * it depends on kernel configuration.
9744 		 */
9745 		flow_dv_translate_item_meta_vport(matcher, key,
9746 						  priv->vport_meta_tag,
9747 						  priv->vport_meta_mask);
9748 	} else {
9749 		flow_dv_translate_item_source_vport(matcher, key,
9750 						    priv->vport_id, mask);
9751 	}
9752 	return 0;
9753 }
9754 
9755 /**
9756  * Add ICMP6 item to matcher and to the value.
9757  *
9758  * @param[in, out] matcher
9759  *   Flow matcher.
9760  * @param[in, out] key
9761  *   Flow matcher value.
9762  * @param[in] item
9763  *   Flow pattern to translate.
9764  * @param[in] inner
9765  *   Item is inner pattern.
9766  */
9767 static void
9768 flow_dv_translate_item_icmp6(void *matcher, void *key,
9769 			      const struct rte_flow_item *item,
9770 			      int inner)
9771 {
9772 	const struct rte_flow_item_icmp6 *icmp6_m = item->mask;
9773 	const struct rte_flow_item_icmp6 *icmp6_v = item->spec;
9774 	void *headers_m;
9775 	void *headers_v;
9776 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9777 				     misc_parameters_3);
9778 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9779 	if (inner) {
9780 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9781 					 inner_headers);
9782 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9783 	} else {
9784 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9785 					 outer_headers);
9786 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9787 	}
9788 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
9789 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6);
9790 	if (!icmp6_v)
9791 		return;
9792 	if (!icmp6_m)
9793 		icmp6_m = &rte_flow_item_icmp6_mask;
9794 	MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type);
9795 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type,
9796 		 icmp6_v->type & icmp6_m->type);
9797 	MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code);
9798 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code,
9799 		 icmp6_v->code & icmp6_m->code);
9800 }
9801 
9802 /**
9803  * Add ICMP item to matcher and to the value.
9804  *
9805  * @param[in, out] matcher
9806  *   Flow matcher.
9807  * @param[in, out] key
9808  *   Flow matcher value.
9809  * @param[in] item
9810  *   Flow pattern to translate.
9811  * @param[in] inner
9812  *   Item is inner pattern.
9813  */
9814 static void
9815 flow_dv_translate_item_icmp(void *matcher, void *key,
9816 			    const struct rte_flow_item *item,
9817 			    int inner)
9818 {
9819 	const struct rte_flow_item_icmp *icmp_m = item->mask;
9820 	const struct rte_flow_item_icmp *icmp_v = item->spec;
9821 	uint32_t icmp_header_data_m = 0;
9822 	uint32_t icmp_header_data_v = 0;
9823 	void *headers_m;
9824 	void *headers_v;
9825 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9826 				     misc_parameters_3);
9827 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9828 	if (inner) {
9829 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9830 					 inner_headers);
9831 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9832 	} else {
9833 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9834 					 outer_headers);
9835 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9836 	}
9837 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
9838 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP);
9839 	if (!icmp_v)
9840 		return;
9841 	if (!icmp_m)
9842 		icmp_m = &rte_flow_item_icmp_mask;
9843 	MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type,
9844 		 icmp_m->hdr.icmp_type);
9845 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type,
9846 		 icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type);
9847 	MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code,
9848 		 icmp_m->hdr.icmp_code);
9849 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code,
9850 		 icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code);
9851 	icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb);
9852 	icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16;
9853 	if (icmp_header_data_m) {
9854 		icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb);
9855 		icmp_header_data_v |=
9856 			 rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16;
9857 		MLX5_SET(fte_match_set_misc3, misc3_m, icmp_header_data,
9858 			 icmp_header_data_m);
9859 		MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data,
9860 			 icmp_header_data_v & icmp_header_data_m);
9861 	}
9862 }
9863 
9864 /**
9865  * Add GTP item to matcher and to the value.
9866  *
9867  * @param[in, out] matcher
9868  *   Flow matcher.
9869  * @param[in, out] key
9870  *   Flow matcher value.
9871  * @param[in] item
9872  *   Flow pattern to translate.
9873  * @param[in] inner
9874  *   Item is inner pattern.
9875  */
9876 static void
9877 flow_dv_translate_item_gtp(void *matcher, void *key,
9878 			   const struct rte_flow_item *item, int inner)
9879 {
9880 	const struct rte_flow_item_gtp *gtp_m = item->mask;
9881 	const struct rte_flow_item_gtp *gtp_v = item->spec;
9882 	void *headers_m;
9883 	void *headers_v;
9884 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9885 				     misc_parameters_3);
9886 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9887 	uint16_t dport = RTE_GTPU_UDP_PORT;
9888 
9889 	if (inner) {
9890 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9891 					 inner_headers);
9892 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
9893 	} else {
9894 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
9895 					 outer_headers);
9896 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9897 	}
9898 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9899 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
9900 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
9901 	}
9902 	if (!gtp_v)
9903 		return;
9904 	if (!gtp_m)
9905 		gtp_m = &rte_flow_item_gtp_mask;
9906 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags,
9907 		 gtp_m->v_pt_rsv_flags);
9908 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags,
9909 		 gtp_v->v_pt_rsv_flags & gtp_m->v_pt_rsv_flags);
9910 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_type, gtp_m->msg_type);
9911 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type,
9912 		 gtp_v->msg_type & gtp_m->msg_type);
9913 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_teid,
9914 		 rte_be_to_cpu_32(gtp_m->teid));
9915 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid,
9916 		 rte_be_to_cpu_32(gtp_v->teid & gtp_m->teid));
9917 }
9918 
9919 /**
9920  * Add GTP PSC item to matcher.
9921  *
9922  * @param[in, out] matcher
9923  *   Flow matcher.
9924  * @param[in, out] key
9925  *   Flow matcher value.
9926  * @param[in] item
9927  *   Flow pattern to translate.
9928  */
9929 static int
9930 flow_dv_translate_item_gtp_psc(void *matcher, void *key,
9931 			       const struct rte_flow_item *item)
9932 {
9933 	const struct rte_flow_item_gtp_psc *gtp_psc_m = item->mask;
9934 	const struct rte_flow_item_gtp_psc *gtp_psc_v = item->spec;
9935 	void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
9936 			misc_parameters_3);
9937 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9938 	union {
9939 		uint32_t w32;
9940 		struct {
9941 			uint16_t seq_num;
9942 			uint8_t npdu_num;
9943 			uint8_t next_ext_header_type;
9944 		};
9945 	} dw_2;
9946 	uint8_t gtp_flags;
9947 
9948 	/* Always set E-flag match on one, regardless of GTP item settings. */
9949 	gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_m, gtpu_msg_flags);
9950 	gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
9951 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_msg_flags, gtp_flags);
9952 	gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags);
9953 	gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
9954 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags);
9955 	/*Set next extension header type. */
9956 	dw_2.seq_num = 0;
9957 	dw_2.npdu_num = 0;
9958 	dw_2.next_ext_header_type = 0xff;
9959 	MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_dw_2,
9960 		 rte_cpu_to_be_32(dw_2.w32));
9961 	dw_2.seq_num = 0;
9962 	dw_2.npdu_num = 0;
9963 	dw_2.next_ext_header_type = 0x85;
9964 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2,
9965 		 rte_cpu_to_be_32(dw_2.w32));
9966 	if (gtp_psc_v) {
9967 		union {
9968 			uint32_t w32;
9969 			struct {
9970 				uint8_t len;
9971 				uint8_t type_flags;
9972 				uint8_t qfi;
9973 				uint8_t reserved;
9974 			};
9975 		} dw_0;
9976 
9977 		/*Set extension header PDU type and Qos. */
9978 		if (!gtp_psc_m)
9979 			gtp_psc_m = &rte_flow_item_gtp_psc_mask;
9980 		dw_0.w32 = 0;
9981 		dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_m->hdr.type);
9982 		dw_0.qfi = gtp_psc_m->hdr.qfi;
9983 		MLX5_SET(fte_match_set_misc3, misc3_m, gtpu_first_ext_dw_0,
9984 			 rte_cpu_to_be_32(dw_0.w32));
9985 		dw_0.w32 = 0;
9986 		dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->hdr.type &
9987 							gtp_psc_m->hdr.type);
9988 		dw_0.qfi = gtp_psc_v->hdr.qfi & gtp_psc_m->hdr.qfi;
9989 		MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0,
9990 			 rte_cpu_to_be_32(dw_0.w32));
9991 	}
9992 	return 0;
9993 }
9994 
9995 /**
9996  * Add eCPRI item to matcher and to the value.
9997  *
9998  * @param[in] dev
9999  *   The devich to configure through.
10000  * @param[in, out] matcher
10001  *   Flow matcher.
10002  * @param[in, out] key
10003  *   Flow matcher value.
10004  * @param[in] item
10005  *   Flow pattern to translate.
10006  * @param[in] last_item
10007  *   Last item flags.
10008  */
10009 static void
10010 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *matcher,
10011 			     void *key, const struct rte_flow_item *item,
10012 			     uint64_t last_item)
10013 {
10014 	struct mlx5_priv *priv = dev->data->dev_private;
10015 	const struct rte_flow_item_ecpri *ecpri_m = item->mask;
10016 	const struct rte_flow_item_ecpri *ecpri_v = item->spec;
10017 	struct rte_ecpri_common_hdr common;
10018 	void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher,
10019 				     misc_parameters_4);
10020 	void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4);
10021 	uint32_t *samples;
10022 	void *dw_m;
10023 	void *dw_v;
10024 
10025 	/*
10026 	 * In case of eCPRI over Ethernet, if EtherType is not specified,
10027 	 * match on eCPRI EtherType implicitly.
10028 	 */
10029 	if (last_item & MLX5_FLOW_LAYER_OUTER_L2) {
10030 		void *hdrs_m, *hdrs_v, *l2m, *l2v;
10031 
10032 		hdrs_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
10033 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
10034 		l2m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_m, ethertype);
10035 		l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
10036 		if (*(uint16_t *)l2m == 0 && *(uint16_t *)l2v == 0) {
10037 			*(uint16_t *)l2m = UINT16_MAX;
10038 			*(uint16_t *)l2v = RTE_BE16(RTE_ETHER_TYPE_ECPRI);
10039 		}
10040 	}
10041 	if (!ecpri_v)
10042 		return;
10043 	if (!ecpri_m)
10044 		ecpri_m = &rte_flow_item_ecpri_mask;
10045 	/*
10046 	 * Maximal four DW samples are supported in a single matching now.
10047 	 * Two are used now for a eCPRI matching:
10048 	 * 1. Type: one byte, mask should be 0x00ff0000 in network order
10049 	 * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000
10050 	 *    if any.
10051 	 */
10052 	if (!ecpri_m->hdr.common.u32)
10053 		return;
10054 	samples = priv->sh->ecpri_parser.ids;
10055 	/* Need to take the whole DW as the mask to fill the entry. */
10056 	dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
10057 			    prog_sample_field_value_0);
10058 	dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
10059 			    prog_sample_field_value_0);
10060 	/* Already big endian (network order) in the header. */
10061 	*(uint32_t *)dw_m = ecpri_m->hdr.common.u32;
10062 	*(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32;
10063 	/* Sample#0, used for matching type, offset 0. */
10064 	MLX5_SET(fte_match_set_misc4, misc4_m,
10065 		 prog_sample_field_id_0, samples[0]);
10066 	/* It makes no sense to set the sample ID in the mask field. */
10067 	MLX5_SET(fte_match_set_misc4, misc4_v,
10068 		 prog_sample_field_id_0, samples[0]);
10069 	/*
10070 	 * Checking if message body part needs to be matched.
10071 	 * Some wildcard rules only matching type field should be supported.
10072 	 */
10073 	if (ecpri_m->hdr.dummy[0]) {
10074 		common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32);
10075 		switch (common.type) {
10076 		case RTE_ECPRI_MSG_TYPE_IQ_DATA:
10077 		case RTE_ECPRI_MSG_TYPE_RTC_CTRL:
10078 		case RTE_ECPRI_MSG_TYPE_DLY_MSR:
10079 			dw_m = MLX5_ADDR_OF(fte_match_set_misc4, misc4_m,
10080 					    prog_sample_field_value_1);
10081 			dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
10082 					    prog_sample_field_value_1);
10083 			*(uint32_t *)dw_m = ecpri_m->hdr.dummy[0];
10084 			*(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] &
10085 					    ecpri_m->hdr.dummy[0];
10086 			/* Sample#1, to match message body, offset 4. */
10087 			MLX5_SET(fte_match_set_misc4, misc4_m,
10088 				 prog_sample_field_id_1, samples[1]);
10089 			MLX5_SET(fte_match_set_misc4, misc4_v,
10090 				 prog_sample_field_id_1, samples[1]);
10091 			break;
10092 		default:
10093 			/* Others, do not match any sample ID. */
10094 			break;
10095 		}
10096 	}
10097 }
10098 
10099 /*
10100  * Add connection tracking status item to matcher
10101  *
10102  * @param[in] dev
10103  *   The devich to configure through.
10104  * @param[in, out] matcher
10105  *   Flow matcher.
10106  * @param[in, out] key
10107  *   Flow matcher value.
10108  * @param[in] item
10109  *   Flow pattern to translate.
10110  */
10111 static void
10112 flow_dv_translate_item_aso_ct(struct rte_eth_dev *dev,
10113 			      void *matcher, void *key,
10114 			      const struct rte_flow_item *item)
10115 {
10116 	uint32_t reg_value = 0;
10117 	int reg_id;
10118 	/* 8LSB 0b 11/0000/11, middle 4 bits are reserved. */
10119 	uint32_t reg_mask = 0;
10120 	const struct rte_flow_item_conntrack *spec = item->spec;
10121 	const struct rte_flow_item_conntrack *mask = item->mask;
10122 	uint32_t flags;
10123 	struct rte_flow_error error;
10124 
10125 	if (!mask)
10126 		mask = &rte_flow_item_conntrack_mask;
10127 	if (!spec || !mask->flags)
10128 		return;
10129 	flags = spec->flags & mask->flags;
10130 	/* The conflict should be checked in the validation. */
10131 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID)
10132 		reg_value |= MLX5_CT_SYNDROME_VALID;
10133 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
10134 		reg_value |= MLX5_CT_SYNDROME_STATE_CHANGE;
10135 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID)
10136 		reg_value |= MLX5_CT_SYNDROME_INVALID;
10137 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)
10138 		reg_value |= MLX5_CT_SYNDROME_TRAP;
10139 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
10140 		reg_value |= MLX5_CT_SYNDROME_BAD_PACKET;
10141 	if (mask->flags & (RTE_FLOW_CONNTRACK_PKT_STATE_VALID |
10142 			   RTE_FLOW_CONNTRACK_PKT_STATE_INVALID |
10143 			   RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED))
10144 		reg_mask |= 0xc0;
10145 	if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
10146 		reg_mask |= MLX5_CT_SYNDROME_STATE_CHANGE;
10147 	if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
10148 		reg_mask |= MLX5_CT_SYNDROME_BAD_PACKET;
10149 	/* The REG_C_x value could be saved during startup. */
10150 	reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, &error);
10151 	if (reg_id == REG_NON)
10152 		return;
10153 	flow_dv_match_meta_reg(matcher, key, (enum modify_reg)reg_id,
10154 			       reg_value, reg_mask);
10155 }
10156 
10157 static void
10158 flow_dv_translate_item_flex(struct rte_eth_dev *dev, void *matcher, void *key,
10159 			    const struct rte_flow_item *item,
10160 			    struct mlx5_flow *dev_flow, bool is_inner)
10161 {
10162 	const struct rte_flow_item_flex *spec =
10163 		(const struct rte_flow_item_flex *)item->spec;
10164 	int index = mlx5_flex_acquire_index(dev, spec->handle, false);
10165 
10166 	MLX5_ASSERT(index >= 0 && index <= (int)(sizeof(uint32_t) * CHAR_BIT));
10167 	if (index < 0)
10168 		return;
10169 	if (!(dev_flow->handle->flex_item & RTE_BIT32(index))) {
10170 		/* Don't count both inner and outer flex items in one rule. */
10171 		if (mlx5_flex_acquire_index(dev, spec->handle, true) != index)
10172 			MLX5_ASSERT(false);
10173 		dev_flow->handle->flex_item |= RTE_BIT32(index);
10174 	}
10175 	mlx5_flex_flow_translate_item(dev, matcher, key, item, is_inner);
10176 }
10177 
10178 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
10179 
10180 #define HEADER_IS_ZERO(match_criteria, headers)				     \
10181 	!(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
10182 		 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
10183 
10184 /**
10185  * Calculate flow matcher enable bitmap.
10186  *
10187  * @param match_criteria
10188  *   Pointer to flow matcher criteria.
10189  *
10190  * @return
10191  *   Bitmap of enabled fields.
10192  */
10193 static uint8_t
10194 flow_dv_matcher_enable(uint32_t *match_criteria)
10195 {
10196 	uint8_t match_criteria_enable;
10197 
10198 	match_criteria_enable =
10199 		(!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
10200 		MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
10201 	match_criteria_enable |=
10202 		(!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
10203 		MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
10204 	match_criteria_enable |=
10205 		(!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
10206 		MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
10207 	match_criteria_enable |=
10208 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
10209 		MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
10210 	match_criteria_enable |=
10211 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
10212 		MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
10213 	match_criteria_enable |=
10214 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) <<
10215 		MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT;
10216 	match_criteria_enable |=
10217 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_5)) <<
10218 		MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT;
10219 	return match_criteria_enable;
10220 }
10221 
10222 static void
10223 __flow_dv_adjust_buf_size(size_t *size, uint8_t match_criteria)
10224 {
10225 	/*
10226 	 * Check flow matching criteria first, subtract misc5/4 length if flow
10227 	 * doesn't own misc5/4 parameters. In some old rdma-core releases,
10228 	 * misc5/4 are not supported, and matcher creation failure is expected
10229 	 * w/o subtration. If misc5 is provided, misc4 must be counted in since
10230 	 * misc5 is right after misc4.
10231 	 */
10232 	if (!(match_criteria & (1 << MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT))) {
10233 		*size = MLX5_ST_SZ_BYTES(fte_match_param) -
10234 			MLX5_ST_SZ_BYTES(fte_match_set_misc5);
10235 		if (!(match_criteria & (1 <<
10236 			MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT))) {
10237 			*size -= MLX5_ST_SZ_BYTES(fte_match_set_misc4);
10238 		}
10239 	}
10240 }
10241 
10242 static struct mlx5_list_entry *
10243 flow_dv_matcher_clone_cb(void *tool_ctx __rte_unused,
10244 			 struct mlx5_list_entry *entry, void *cb_ctx)
10245 {
10246 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10247 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10248 	struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
10249 							    typeof(*tbl), tbl);
10250 	struct mlx5_flow_dv_matcher *resource = mlx5_malloc(MLX5_MEM_ANY,
10251 							    sizeof(*resource),
10252 							    0, SOCKET_ID_ANY);
10253 
10254 	if (!resource) {
10255 		rte_flow_error_set(ctx->error, ENOMEM,
10256 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10257 				   "cannot create matcher");
10258 		return NULL;
10259 	}
10260 	memcpy(resource, entry, sizeof(*resource));
10261 	resource->tbl = &tbl->tbl;
10262 	return &resource->entry;
10263 }
10264 
10265 static void
10266 flow_dv_matcher_clone_free_cb(void *tool_ctx __rte_unused,
10267 			     struct mlx5_list_entry *entry)
10268 {
10269 	mlx5_free(entry);
10270 }
10271 
10272 struct mlx5_list_entry *
10273 flow_dv_tbl_create_cb(void *tool_ctx, void *cb_ctx)
10274 {
10275 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10276 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10277 	struct rte_eth_dev *dev = ctx->dev;
10278 	struct mlx5_flow_tbl_data_entry *tbl_data;
10279 	struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data2;
10280 	struct rte_flow_error *error = ctx->error;
10281 	union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) };
10282 	struct mlx5_flow_tbl_resource *tbl;
10283 	void *domain;
10284 	uint32_t idx = 0;
10285 	int ret;
10286 
10287 	tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10288 	if (!tbl_data) {
10289 		rte_flow_error_set(error, ENOMEM,
10290 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10291 				   NULL,
10292 				   "cannot allocate flow table data entry");
10293 		return NULL;
10294 	}
10295 	tbl_data->idx = idx;
10296 	tbl_data->tunnel = tt_prm->tunnel;
10297 	tbl_data->group_id = tt_prm->group_id;
10298 	tbl_data->external = !!tt_prm->external;
10299 	tbl_data->tunnel_offload = is_tunnel_offload_active(dev);
10300 	tbl_data->is_egress = !!key.is_egress;
10301 	tbl_data->is_transfer = !!key.is_fdb;
10302 	tbl_data->dummy = !!key.dummy;
10303 	tbl_data->level = key.level;
10304 	tbl_data->id = key.id;
10305 	tbl = &tbl_data->tbl;
10306 	if (key.dummy)
10307 		return &tbl_data->entry;
10308 	if (key.is_fdb)
10309 		domain = sh->fdb_domain;
10310 	else if (key.is_egress)
10311 		domain = sh->tx_domain;
10312 	else
10313 		domain = sh->rx_domain;
10314 	ret = mlx5_flow_os_create_flow_tbl(domain, key.level, &tbl->obj);
10315 	if (ret) {
10316 		rte_flow_error_set(error, ENOMEM,
10317 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10318 				   NULL, "cannot create flow table object");
10319 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10320 		return NULL;
10321 	}
10322 	if (key.level != 0) {
10323 		ret = mlx5_flow_os_create_flow_action_dest_flow_tbl
10324 					(tbl->obj, &tbl_data->jump.action);
10325 		if (ret) {
10326 			rte_flow_error_set(error, ENOMEM,
10327 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10328 					   NULL,
10329 					   "cannot create flow jump action");
10330 			mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10331 			mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10332 			return NULL;
10333 		}
10334 	}
10335 	MKSTR(matcher_name, "%s_%s_%u_%u_matcher_list",
10336 	      key.is_fdb ? "FDB" : "NIC", key.is_egress ? "egress" : "ingress",
10337 	      key.level, key.id);
10338 	tbl_data->matchers = mlx5_list_create(matcher_name, sh, true,
10339 					      flow_dv_matcher_create_cb,
10340 					      flow_dv_matcher_match_cb,
10341 					      flow_dv_matcher_remove_cb,
10342 					      flow_dv_matcher_clone_cb,
10343 					      flow_dv_matcher_clone_free_cb);
10344 	if (!tbl_data->matchers) {
10345 		rte_flow_error_set(error, ENOMEM,
10346 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10347 				   NULL,
10348 				   "cannot create tbl matcher list");
10349 		mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10350 		mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10351 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10352 		return NULL;
10353 	}
10354 	return &tbl_data->entry;
10355 }
10356 
10357 int
10358 flow_dv_tbl_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
10359 		     void *cb_ctx)
10360 {
10361 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10362 	struct mlx5_flow_tbl_data_entry *tbl_data =
10363 		container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10364 	union mlx5_flow_tbl_key key = { .v64 =  *(uint64_t *)(ctx->data) };
10365 
10366 	return tbl_data->level != key.level ||
10367 	       tbl_data->id != key.id ||
10368 	       tbl_data->dummy != key.dummy ||
10369 	       tbl_data->is_transfer != !!key.is_fdb ||
10370 	       tbl_data->is_egress != !!key.is_egress;
10371 }
10372 
10373 struct mlx5_list_entry *
10374 flow_dv_tbl_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
10375 		      void *cb_ctx)
10376 {
10377 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10378 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10379 	struct mlx5_flow_tbl_data_entry *tbl_data;
10380 	struct rte_flow_error *error = ctx->error;
10381 	uint32_t idx = 0;
10382 
10383 	tbl_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10384 	if (!tbl_data) {
10385 		rte_flow_error_set(error, ENOMEM,
10386 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10387 				   NULL,
10388 				   "cannot allocate flow table data entry");
10389 		return NULL;
10390 	}
10391 	memcpy(tbl_data, oentry, sizeof(*tbl_data));
10392 	tbl_data->idx = idx;
10393 	return &tbl_data->entry;
10394 }
10395 
10396 void
10397 flow_dv_tbl_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10398 {
10399 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10400 	struct mlx5_flow_tbl_data_entry *tbl_data =
10401 		    container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10402 
10403 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10404 }
10405 
10406 /**
10407  * Get a flow table.
10408  *
10409  * @param[in, out] dev
10410  *   Pointer to rte_eth_dev structure.
10411  * @param[in] table_level
10412  *   Table level to use.
10413  * @param[in] egress
10414  *   Direction of the table.
10415  * @param[in] transfer
10416  *   E-Switch or NIC flow.
10417  * @param[in] dummy
10418  *   Dummy entry for dv API.
10419  * @param[in] table_id
10420  *   Table id to use.
10421  * @param[out] error
10422  *   pointer to error structure.
10423  *
10424  * @return
10425  *   Returns tables resource based on the index, NULL in case of failed.
10426  */
10427 struct mlx5_flow_tbl_resource *
10428 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
10429 			 uint32_t table_level, uint8_t egress,
10430 			 uint8_t transfer,
10431 			 bool external,
10432 			 const struct mlx5_flow_tunnel *tunnel,
10433 			 uint32_t group_id, uint8_t dummy,
10434 			 uint32_t table_id,
10435 			 struct rte_flow_error *error)
10436 {
10437 	struct mlx5_priv *priv = dev->data->dev_private;
10438 	union mlx5_flow_tbl_key table_key = {
10439 		{
10440 			.level = table_level,
10441 			.id = table_id,
10442 			.reserved = 0,
10443 			.dummy = !!dummy,
10444 			.is_fdb = !!transfer,
10445 			.is_egress = !!egress,
10446 		}
10447 	};
10448 	struct mlx5_flow_tbl_tunnel_prm tt_prm = {
10449 		.tunnel = tunnel,
10450 		.group_id = group_id,
10451 		.external = external,
10452 	};
10453 	struct mlx5_flow_cb_ctx ctx = {
10454 		.dev = dev,
10455 		.error = error,
10456 		.data = &table_key.v64,
10457 		.data2 = &tt_prm,
10458 	};
10459 	struct mlx5_list_entry *entry;
10460 	struct mlx5_flow_tbl_data_entry *tbl_data;
10461 
10462 	entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx);
10463 	if (!entry) {
10464 		rte_flow_error_set(error, ENOMEM,
10465 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10466 				   "cannot get table");
10467 		return NULL;
10468 	}
10469 	DRV_LOG(DEBUG, "table_level %u table_id %u "
10470 		"tunnel %u group %u registered.",
10471 		table_level, table_id,
10472 		tunnel ? tunnel->tunnel_id : 0, group_id);
10473 	tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10474 	return &tbl_data->tbl;
10475 }
10476 
10477 void
10478 flow_dv_tbl_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10479 {
10480 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10481 	struct mlx5_flow_tbl_data_entry *tbl_data =
10482 		    container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10483 
10484 	MLX5_ASSERT(entry && sh);
10485 	if (tbl_data->jump.action)
10486 		mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10487 	if (tbl_data->tbl.obj)
10488 		mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj);
10489 	if (tbl_data->tunnel_offload && tbl_data->external) {
10490 		struct mlx5_list_entry *he;
10491 		struct mlx5_hlist *tunnel_grp_hash;
10492 		struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;
10493 		union tunnel_tbl_key tunnel_key = {
10494 			.tunnel_id = tbl_data->tunnel ?
10495 					tbl_data->tunnel->tunnel_id : 0,
10496 			.group = tbl_data->group_id
10497 		};
10498 		uint32_t table_level = tbl_data->level;
10499 		struct mlx5_flow_cb_ctx ctx = {
10500 			.data = (void *)&tunnel_key.val,
10501 		};
10502 
10503 		tunnel_grp_hash = tbl_data->tunnel ?
10504 					tbl_data->tunnel->groups :
10505 					thub->groups;
10506 		he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, &ctx);
10507 		if (he)
10508 			mlx5_hlist_unregister(tunnel_grp_hash, he);
10509 		DRV_LOG(DEBUG,
10510 			"table_level %u id %u tunnel %u group %u released.",
10511 			table_level,
10512 			tbl_data->id,
10513 			tbl_data->tunnel ?
10514 			tbl_data->tunnel->tunnel_id : 0,
10515 			tbl_data->group_id);
10516 	}
10517 	mlx5_list_destroy(tbl_data->matchers);
10518 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10519 }
10520 
10521 /**
10522  * Release a flow table.
10523  *
10524  * @param[in] sh
10525  *   Pointer to device shared structure.
10526  * @param[in] tbl
10527  *   Table resource to be released.
10528  *
10529  * @return
10530  *   Returns 0 if table was released, else return 1;
10531  */
10532 static int
10533 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
10534 			     struct mlx5_flow_tbl_resource *tbl)
10535 {
10536 	struct mlx5_flow_tbl_data_entry *tbl_data =
10537 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
10538 
10539 	if (!tbl)
10540 		return 0;
10541 	return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry);
10542 }
10543 
10544 int
10545 flow_dv_matcher_match_cb(void *tool_ctx __rte_unused,
10546 			 struct mlx5_list_entry *entry, void *cb_ctx)
10547 {
10548 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10549 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10550 	struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur),
10551 							entry);
10552 
10553 	return cur->crc != ref->crc ||
10554 	       cur->priority != ref->priority ||
10555 	       memcmp((const void *)cur->mask.buf,
10556 		      (const void *)ref->mask.buf, ref->mask.size);
10557 }
10558 
10559 struct mlx5_list_entry *
10560 flow_dv_matcher_create_cb(void *tool_ctx, void *cb_ctx)
10561 {
10562 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10563 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10564 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10565 	struct mlx5_flow_dv_matcher *resource;
10566 	struct mlx5dv_flow_matcher_attr dv_attr = {
10567 		.type = IBV_FLOW_ATTR_NORMAL,
10568 		.match_mask = (void *)&ref->mask,
10569 	};
10570 	struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
10571 							    typeof(*tbl), tbl);
10572 	int ret;
10573 
10574 	resource = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*resource), 0,
10575 			       SOCKET_ID_ANY);
10576 	if (!resource) {
10577 		rte_flow_error_set(ctx->error, ENOMEM,
10578 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10579 				   "cannot create matcher");
10580 		return NULL;
10581 	}
10582 	*resource = *ref;
10583 	dv_attr.match_criteria_enable =
10584 		flow_dv_matcher_enable(resource->mask.buf);
10585 	__flow_dv_adjust_buf_size(&ref->mask.size,
10586 				  dv_attr.match_criteria_enable);
10587 	dv_attr.priority = ref->priority;
10588 	if (tbl->is_egress)
10589 		dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
10590 	ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr,
10591 					       tbl->tbl.obj,
10592 					       &resource->matcher_object);
10593 	if (ret) {
10594 		mlx5_free(resource);
10595 		rte_flow_error_set(ctx->error, ENOMEM,
10596 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10597 				   "cannot create matcher");
10598 		return NULL;
10599 	}
10600 	return &resource->entry;
10601 }
10602 
10603 /**
10604  * Register the flow matcher.
10605  *
10606  * @param[in, out] dev
10607  *   Pointer to rte_eth_dev structure.
10608  * @param[in, out] matcher
10609  *   Pointer to flow matcher.
10610  * @param[in, out] key
10611  *   Pointer to flow table key.
10612  * @parm[in, out] dev_flow
10613  *   Pointer to the dev_flow.
10614  * @param[out] error
10615  *   pointer to error structure.
10616  *
10617  * @return
10618  *   0 on success otherwise -errno and errno is set.
10619  */
10620 static int
10621 flow_dv_matcher_register(struct rte_eth_dev *dev,
10622 			 struct mlx5_flow_dv_matcher *ref,
10623 			 union mlx5_flow_tbl_key *key,
10624 			 struct mlx5_flow *dev_flow,
10625 			 const struct mlx5_flow_tunnel *tunnel,
10626 			 uint32_t group_id,
10627 			 struct rte_flow_error *error)
10628 {
10629 	struct mlx5_list_entry *entry;
10630 	struct mlx5_flow_dv_matcher *resource;
10631 	struct mlx5_flow_tbl_resource *tbl;
10632 	struct mlx5_flow_tbl_data_entry *tbl_data;
10633 	struct mlx5_flow_cb_ctx ctx = {
10634 		.error = error,
10635 		.data = ref,
10636 	};
10637 	/**
10638 	 * tunnel offload API requires this registration for cases when
10639 	 * tunnel match rule was inserted before tunnel set rule.
10640 	 */
10641 	tbl = flow_dv_tbl_resource_get(dev, key->level,
10642 				       key->is_egress, key->is_fdb,
10643 				       dev_flow->external, tunnel,
10644 				       group_id, 0, key->id, error);
10645 	if (!tbl)
10646 		return -rte_errno;	/* No need to refill the error info */
10647 	tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
10648 	ref->tbl = tbl;
10649 	entry = mlx5_list_register(tbl_data->matchers, &ctx);
10650 	if (!entry) {
10651 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
10652 		return rte_flow_error_set(error, ENOMEM,
10653 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10654 					  "cannot allocate ref memory");
10655 	}
10656 	resource = container_of(entry, typeof(*resource), entry);
10657 	dev_flow->handle->dvh.matcher = resource;
10658 	return 0;
10659 }
10660 
10661 struct mlx5_list_entry *
10662 flow_dv_tag_create_cb(void *tool_ctx, void *cb_ctx)
10663 {
10664 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10665 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10666 	struct mlx5_flow_dv_tag_resource *entry;
10667 	uint32_t idx = 0;
10668 	int ret;
10669 
10670 	entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
10671 	if (!entry) {
10672 		rte_flow_error_set(ctx->error, ENOMEM,
10673 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10674 				   "cannot allocate resource memory");
10675 		return NULL;
10676 	}
10677 	entry->idx = idx;
10678 	entry->tag_id = *(uint32_t *)(ctx->data);
10679 	ret = mlx5_flow_os_create_flow_action_tag(entry->tag_id,
10680 						  &entry->action);
10681 	if (ret) {
10682 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx);
10683 		rte_flow_error_set(ctx->error, ENOMEM,
10684 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10685 				   NULL, "cannot create action");
10686 		return NULL;
10687 	}
10688 	return &entry->entry;
10689 }
10690 
10691 int
10692 flow_dv_tag_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
10693 		     void *cb_ctx)
10694 {
10695 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10696 	struct mlx5_flow_dv_tag_resource *tag =
10697 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10698 
10699 	return *(uint32_t *)(ctx->data) != tag->tag_id;
10700 }
10701 
10702 struct mlx5_list_entry *
10703 flow_dv_tag_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
10704 		     void *cb_ctx)
10705 {
10706 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10707 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10708 	struct mlx5_flow_dv_tag_resource *entry;
10709 	uint32_t idx = 0;
10710 
10711 	entry = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
10712 	if (!entry) {
10713 		rte_flow_error_set(ctx->error, ENOMEM,
10714 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10715 				   "cannot allocate tag resource memory");
10716 		return NULL;
10717 	}
10718 	memcpy(entry, oentry, sizeof(*entry));
10719 	entry->idx = idx;
10720 	return &entry->entry;
10721 }
10722 
10723 void
10724 flow_dv_tag_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10725 {
10726 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10727 	struct mlx5_flow_dv_tag_resource *tag =
10728 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10729 
10730 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
10731 }
10732 
10733 /**
10734  * Find existing tag resource or create and register a new one.
10735  *
10736  * @param dev[in, out]
10737  *   Pointer to rte_eth_dev structure.
10738  * @param[in, out] tag_be24
10739  *   Tag value in big endian then R-shift 8.
10740  * @parm[in, out] dev_flow
10741  *   Pointer to the dev_flow.
10742  * @param[out] error
10743  *   pointer to error structure.
10744  *
10745  * @return
10746  *   0 on success otherwise -errno and errno is set.
10747  */
10748 static int
10749 flow_dv_tag_resource_register
10750 			(struct rte_eth_dev *dev,
10751 			 uint32_t tag_be24,
10752 			 struct mlx5_flow *dev_flow,
10753 			 struct rte_flow_error *error)
10754 {
10755 	struct mlx5_priv *priv = dev->data->dev_private;
10756 	struct mlx5_flow_dv_tag_resource *resource;
10757 	struct mlx5_list_entry *entry;
10758 	struct mlx5_flow_cb_ctx ctx = {
10759 					.error = error,
10760 					.data = &tag_be24,
10761 					};
10762 	struct mlx5_hlist *tag_table;
10763 
10764 	tag_table = flow_dv_hlist_prepare(priv->sh, &priv->sh->tag_table,
10765 				      "tags",
10766 				      MLX5_TAGS_HLIST_ARRAY_SIZE,
10767 				      false, false, priv->sh,
10768 				      flow_dv_tag_create_cb,
10769 				      flow_dv_tag_match_cb,
10770 				      flow_dv_tag_remove_cb,
10771 				      flow_dv_tag_clone_cb,
10772 				      flow_dv_tag_clone_free_cb);
10773 	if (unlikely(!tag_table))
10774 		return -rte_errno;
10775 	entry = mlx5_hlist_register(tag_table, tag_be24, &ctx);
10776 	if (entry) {
10777 		resource = container_of(entry, struct mlx5_flow_dv_tag_resource,
10778 					entry);
10779 		dev_flow->handle->dvh.rix_tag = resource->idx;
10780 		dev_flow->dv.tag_resource = resource;
10781 		return 0;
10782 	}
10783 	return -rte_errno;
10784 }
10785 
10786 void
10787 flow_dv_tag_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10788 {
10789 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10790 	struct mlx5_flow_dv_tag_resource *tag =
10791 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
10792 
10793 	MLX5_ASSERT(tag && sh && tag->action);
10794 	claim_zero(mlx5_flow_os_destroy_flow_action(tag->action));
10795 	DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag);
10796 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
10797 }
10798 
10799 /**
10800  * Release the tag.
10801  *
10802  * @param dev
10803  *   Pointer to Ethernet device.
10804  * @param tag_idx
10805  *   Tag index.
10806  *
10807  * @return
10808  *   1 while a reference on it exists, 0 when freed.
10809  */
10810 static int
10811 flow_dv_tag_release(struct rte_eth_dev *dev,
10812 		    uint32_t tag_idx)
10813 {
10814 	struct mlx5_priv *priv = dev->data->dev_private;
10815 	struct mlx5_flow_dv_tag_resource *tag;
10816 
10817 	tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx);
10818 	if (!tag)
10819 		return 0;
10820 	DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
10821 		dev->data->port_id, (void *)tag, tag->entry.ref_cnt);
10822 	return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry);
10823 }
10824 
10825 /**
10826  * Translate action PORT_ID / REPRESENTED_PORT to vport.
10827  *
10828  * @param[in] dev
10829  *   Pointer to rte_eth_dev structure.
10830  * @param[in] action
10831  *   Pointer to action PORT_ID / REPRESENTED_PORT.
10832  * @param[out] dst_port_id
10833  *   The target port ID.
10834  * @param[out] error
10835  *   Pointer to the error structure.
10836  *
10837  * @return
10838  *   0 on success, a negative errno value otherwise and rte_errno is set.
10839  */
10840 static int
10841 flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
10842 				 const struct rte_flow_action *action,
10843 				 uint32_t *dst_port_id,
10844 				 struct rte_flow_error *error)
10845 {
10846 	uint32_t port;
10847 	struct mlx5_priv *priv;
10848 
10849 	switch (action->type) {
10850 	case RTE_FLOW_ACTION_TYPE_PORT_ID: {
10851 		const struct rte_flow_action_port_id *conf;
10852 
10853 		conf = (const struct rte_flow_action_port_id *)action->conf;
10854 		port = conf->original ? dev->data->port_id : conf->id;
10855 		break;
10856 	}
10857 	case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: {
10858 		const struct rte_flow_action_ethdev *ethdev;
10859 
10860 		ethdev = (const struct rte_flow_action_ethdev *)action->conf;
10861 		port = ethdev->port_id;
10862 		break;
10863 	}
10864 	default:
10865 		MLX5_ASSERT(false);
10866 		return rte_flow_error_set(error, EINVAL,
10867 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
10868 					  "unknown E-Switch action");
10869 	}
10870 
10871 	priv = mlx5_port_to_eswitch_info(port, false);
10872 	if (!priv)
10873 		return rte_flow_error_set(error, -rte_errno,
10874 					  RTE_FLOW_ERROR_TYPE_ACTION,
10875 					  NULL,
10876 					  "No eswitch info was found for port");
10877 #ifdef HAVE_MLX5DV_DR_CREATE_DEST_IB_PORT
10878 	/*
10879 	 * This parameter is transferred to
10880 	 * mlx5dv_dr_action_create_dest_ib_port().
10881 	 */
10882 	*dst_port_id = priv->dev_port;
10883 #else
10884 	/*
10885 	 * Legacy mode, no LAG configurations is supported.
10886 	 * This parameter is transferred to
10887 	 * mlx5dv_dr_action_create_dest_vport().
10888 	 */
10889 	*dst_port_id = priv->vport_id;
10890 #endif
10891 	return 0;
10892 }
10893 
10894 /**
10895  * Create a counter with aging configuration.
10896  *
10897  * @param[in] dev
10898  *   Pointer to rte_eth_dev structure.
10899  * @param[in] dev_flow
10900  *   Pointer to the mlx5_flow.
10901  * @param[out] count
10902  *   Pointer to the counter action configuration.
10903  * @param[in] age
10904  *   Pointer to the aging action configuration.
10905  *
10906  * @return
10907  *   Index to flow counter on success, 0 otherwise.
10908  */
10909 static uint32_t
10910 flow_dv_translate_create_counter(struct rte_eth_dev *dev,
10911 				struct mlx5_flow *dev_flow,
10912 				const struct rte_flow_action_count *count
10913 					__rte_unused,
10914 				const struct rte_flow_action_age *age)
10915 {
10916 	uint32_t counter;
10917 	struct mlx5_age_param *age_param;
10918 
10919 	counter = flow_dv_counter_alloc(dev, !!age);
10920 	if (!counter || age == NULL)
10921 		return counter;
10922 	age_param = flow_dv_counter_idx_get_age(dev, counter);
10923 	age_param->context = age->context ? age->context :
10924 		(void *)(uintptr_t)(dev_flow->flow_idx);
10925 	age_param->timeout = age->timeout;
10926 	age_param->port_id = dev->data->port_id;
10927 	__atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED);
10928 	__atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED);
10929 	return counter;
10930 }
10931 
10932 /**
10933  * Add Tx queue matcher
10934  *
10935  * @param[in] dev
10936  *   Pointer to the dev struct.
10937  * @param[in, out] matcher
10938  *   Flow matcher.
10939  * @param[in, out] key
10940  *   Flow matcher value.
10941  * @param[in] item
10942  *   Flow pattern to translate.
10943  * @param[in] inner
10944  *   Item is inner pattern.
10945  */
10946 static void
10947 flow_dv_translate_item_tx_queue(struct rte_eth_dev *dev,
10948 				void *matcher, void *key,
10949 				const struct rte_flow_item *item)
10950 {
10951 	const struct mlx5_rte_flow_item_tx_queue *queue_m;
10952 	const struct mlx5_rte_flow_item_tx_queue *queue_v;
10953 	void *misc_m =
10954 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
10955 	void *misc_v =
10956 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
10957 	struct mlx5_txq_ctrl *txq;
10958 	uint32_t queue, mask;
10959 
10960 	queue_m = (const void *)item->mask;
10961 	queue_v = (const void *)item->spec;
10962 	if (!queue_v)
10963 		return;
10964 	txq = mlx5_txq_get(dev, queue_v->queue);
10965 	if (!txq)
10966 		return;
10967 	if (txq->type == MLX5_TXQ_TYPE_HAIRPIN)
10968 		queue = txq->obj->sq->id;
10969 	else
10970 		queue = txq->obj->sq_obj.sq->id;
10971 	mask = queue_m == NULL ? UINT32_MAX : queue_m->queue;
10972 	MLX5_SET(fte_match_set_misc, misc_m, source_sqn, mask);
10973 	MLX5_SET(fte_match_set_misc, misc_v, source_sqn, queue & mask);
10974 	mlx5_txq_release(dev, queue_v->queue);
10975 }
10976 
10977 /**
10978  * Set the hash fields according to the @p flow information.
10979  *
10980  * @param[in] dev_flow
10981  *   Pointer to the mlx5_flow.
10982  * @param[in] rss_desc
10983  *   Pointer to the mlx5_flow_rss_desc.
10984  */
10985 static void
10986 flow_dv_hashfields_set(struct mlx5_flow *dev_flow,
10987 		       struct mlx5_flow_rss_desc *rss_desc)
10988 {
10989 	uint64_t items = dev_flow->handle->layers;
10990 	int rss_inner = 0;
10991 	uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types);
10992 
10993 	dev_flow->hash_fields = 0;
10994 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
10995 	if (rss_desc->level >= 2)
10996 		rss_inner = 1;
10997 #endif
10998 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) ||
10999 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) {
11000 		if (rss_types & MLX5_IPV4_LAYER_TYPES) {
11001 			if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY)
11002 				dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV4;
11003 			else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY)
11004 				dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV4;
11005 			else
11006 				dev_flow->hash_fields |= MLX5_IPV4_IBV_RX_HASH;
11007 		}
11008 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
11009 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) {
11010 		if (rss_types & MLX5_IPV6_LAYER_TYPES) {
11011 			if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY)
11012 				dev_flow->hash_fields |= IBV_RX_HASH_SRC_IPV6;
11013 			else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY)
11014 				dev_flow->hash_fields |= IBV_RX_HASH_DST_IPV6;
11015 			else
11016 				dev_flow->hash_fields |= MLX5_IPV6_IBV_RX_HASH;
11017 		}
11018 	}
11019 	if (dev_flow->hash_fields == 0)
11020 		/*
11021 		 * There is no match between the RSS types and the
11022 		 * L3 protocol (IPv4/IPv6) defined in the flow rule.
11023 		 */
11024 		return;
11025 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) ||
11026 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) {
11027 		if (rss_types & RTE_ETH_RSS_UDP) {
11028 			if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY)
11029 				dev_flow->hash_fields |=
11030 						IBV_RX_HASH_SRC_PORT_UDP;
11031 			else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY)
11032 				dev_flow->hash_fields |=
11033 						IBV_RX_HASH_DST_PORT_UDP;
11034 			else
11035 				dev_flow->hash_fields |= MLX5_UDP_IBV_RX_HASH;
11036 		}
11037 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) ||
11038 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) {
11039 		if (rss_types & RTE_ETH_RSS_TCP) {
11040 			if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY)
11041 				dev_flow->hash_fields |=
11042 						IBV_RX_HASH_SRC_PORT_TCP;
11043 			else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY)
11044 				dev_flow->hash_fields |=
11045 						IBV_RX_HASH_DST_PORT_TCP;
11046 			else
11047 				dev_flow->hash_fields |= MLX5_TCP_IBV_RX_HASH;
11048 		}
11049 	}
11050 	if (rss_inner)
11051 		dev_flow->hash_fields |= IBV_RX_HASH_INNER;
11052 }
11053 
11054 /**
11055  * Prepare an Rx Hash queue.
11056  *
11057  * @param dev
11058  *   Pointer to Ethernet device.
11059  * @param[in] dev_flow
11060  *   Pointer to the mlx5_flow.
11061  * @param[in] rss_desc
11062  *   Pointer to the mlx5_flow_rss_desc.
11063  * @param[out] hrxq_idx
11064  *   Hash Rx queue index.
11065  *
11066  * @return
11067  *   The Verbs/DevX object initialised, NULL otherwise and rte_errno is set.
11068  */
11069 static struct mlx5_hrxq *
11070 flow_dv_hrxq_prepare(struct rte_eth_dev *dev,
11071 		     struct mlx5_flow *dev_flow,
11072 		     struct mlx5_flow_rss_desc *rss_desc,
11073 		     uint32_t *hrxq_idx)
11074 {
11075 	struct mlx5_priv *priv = dev->data->dev_private;
11076 	struct mlx5_flow_handle *dh = dev_flow->handle;
11077 	struct mlx5_hrxq *hrxq;
11078 
11079 	MLX5_ASSERT(rss_desc->queue_num);
11080 	rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN;
11081 	rss_desc->hash_fields = dev_flow->hash_fields;
11082 	rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL);
11083 	rss_desc->shared_rss = 0;
11084 	if (rss_desc->hash_fields == 0)
11085 		rss_desc->queue_num = 1;
11086 	*hrxq_idx = mlx5_hrxq_get(dev, rss_desc);
11087 	if (!*hrxq_idx)
11088 		return NULL;
11089 	hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
11090 			      *hrxq_idx);
11091 	return hrxq;
11092 }
11093 
11094 /**
11095  * Release sample sub action resource.
11096  *
11097  * @param[in, out] dev
11098  *   Pointer to rte_eth_dev structure.
11099  * @param[in] act_res
11100  *   Pointer to sample sub action resource.
11101  */
11102 static void
11103 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev,
11104 				   struct mlx5_flow_sub_actions_idx *act_res)
11105 {
11106 	if (act_res->rix_hrxq) {
11107 		mlx5_hrxq_release(dev, act_res->rix_hrxq);
11108 		act_res->rix_hrxq = 0;
11109 	}
11110 	if (act_res->rix_encap_decap) {
11111 		flow_dv_encap_decap_resource_release(dev,
11112 						     act_res->rix_encap_decap);
11113 		act_res->rix_encap_decap = 0;
11114 	}
11115 	if (act_res->rix_port_id_action) {
11116 		flow_dv_port_id_action_resource_release(dev,
11117 						act_res->rix_port_id_action);
11118 		act_res->rix_port_id_action = 0;
11119 	}
11120 	if (act_res->rix_tag) {
11121 		flow_dv_tag_release(dev, act_res->rix_tag);
11122 		act_res->rix_tag = 0;
11123 	}
11124 	if (act_res->rix_jump) {
11125 		flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump);
11126 		act_res->rix_jump = 0;
11127 	}
11128 }
11129 
11130 int
11131 flow_dv_sample_match_cb(void *tool_ctx __rte_unused,
11132 			struct mlx5_list_entry *entry, void *cb_ctx)
11133 {
11134 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11135 	struct rte_eth_dev *dev = ctx->dev;
11136 	struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
11137 	struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
11138 							      typeof(*resource),
11139 							      entry);
11140 
11141 	if (ctx_resource->ratio == resource->ratio &&
11142 	    ctx_resource->ft_type == resource->ft_type &&
11143 	    ctx_resource->ft_id == resource->ft_id &&
11144 	    ctx_resource->set_action == resource->set_action &&
11145 	    !memcmp((void *)&ctx_resource->sample_act,
11146 		    (void *)&resource->sample_act,
11147 		    sizeof(struct mlx5_flow_sub_actions_list))) {
11148 		/*
11149 		 * Existing sample action should release the prepared
11150 		 * sub-actions reference counter.
11151 		 */
11152 		flow_dv_sample_sub_actions_release(dev,
11153 						   &ctx_resource->sample_idx);
11154 		return 0;
11155 	}
11156 	return 1;
11157 }
11158 
11159 struct mlx5_list_entry *
11160 flow_dv_sample_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
11161 {
11162 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11163 	struct rte_eth_dev *dev = ctx->dev;
11164 	struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
11165 	void **sample_dv_actions = ctx_resource->sub_actions;
11166 	struct mlx5_flow_dv_sample_resource *resource;
11167 	struct mlx5dv_dr_flow_sampler_attr sampler_attr;
11168 	struct mlx5_priv *priv = dev->data->dev_private;
11169 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11170 	struct mlx5_flow_tbl_resource *tbl;
11171 	uint32_t idx = 0;
11172 	const uint32_t next_ft_step = 1;
11173 	uint32_t next_ft_id = ctx_resource->ft_id + next_ft_step;
11174 	uint8_t is_egress = 0;
11175 	uint8_t is_transfer = 0;
11176 	struct rte_flow_error *error = ctx->error;
11177 
11178 	/* Register new sample resource. */
11179 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11180 	if (!resource) {
11181 		rte_flow_error_set(error, ENOMEM,
11182 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11183 					  NULL,
11184 					  "cannot allocate resource memory");
11185 		return NULL;
11186 	}
11187 	*resource = *ctx_resource;
11188 	/* Create normal path table level */
11189 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11190 		is_transfer = 1;
11191 	else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
11192 		is_egress = 1;
11193 	tbl = flow_dv_tbl_resource_get(dev, next_ft_id,
11194 					is_egress, is_transfer,
11195 					true, NULL, 0, 0, 0, error);
11196 	if (!tbl) {
11197 		rte_flow_error_set(error, ENOMEM,
11198 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11199 					  NULL,
11200 					  "fail to create normal path table "
11201 					  "for sample");
11202 		goto error;
11203 	}
11204 	resource->normal_path_tbl = tbl;
11205 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) {
11206 		if (!sh->default_miss_action) {
11207 			rte_flow_error_set(error, ENOMEM,
11208 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11209 						NULL,
11210 						"default miss action was not "
11211 						"created");
11212 			goto error;
11213 		}
11214 		sample_dv_actions[ctx_resource->sample_act.actions_num++] =
11215 						sh->default_miss_action;
11216 	}
11217 	/* Create a DR sample action */
11218 	sampler_attr.sample_ratio = resource->ratio;
11219 	sampler_attr.default_next_table = tbl->obj;
11220 	sampler_attr.num_sample_actions = ctx_resource->sample_act.actions_num;
11221 	sampler_attr.sample_actions = (struct mlx5dv_dr_action **)
11222 							&sample_dv_actions[0];
11223 	sampler_attr.action = resource->set_action;
11224 	if (mlx5_os_flow_dr_create_flow_action_sampler
11225 			(&sampler_attr, &resource->verbs_action)) {
11226 		rte_flow_error_set(error, ENOMEM,
11227 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11228 					NULL, "cannot create sample action");
11229 		goto error;
11230 	}
11231 	resource->idx = idx;
11232 	resource->dev = dev;
11233 	return &resource->entry;
11234 error:
11235 	if (resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB)
11236 		flow_dv_sample_sub_actions_release(dev,
11237 						   &resource->sample_idx);
11238 	if (resource->normal_path_tbl)
11239 		flow_dv_tbl_resource_release(MLX5_SH(dev),
11240 				resource->normal_path_tbl);
11241 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx);
11242 	return NULL;
11243 
11244 }
11245 
11246 struct mlx5_list_entry *
11247 flow_dv_sample_clone_cb(void *tool_ctx __rte_unused,
11248 			 struct mlx5_list_entry *entry __rte_unused,
11249 			 void *cb_ctx)
11250 {
11251 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11252 	struct rte_eth_dev *dev = ctx->dev;
11253 	struct mlx5_flow_dv_sample_resource *resource;
11254 	struct mlx5_priv *priv = dev->data->dev_private;
11255 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11256 	uint32_t idx = 0;
11257 
11258 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11259 	if (!resource) {
11260 		rte_flow_error_set(ctx->error, ENOMEM,
11261 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11262 					  NULL,
11263 					  "cannot allocate resource memory");
11264 		return NULL;
11265 	}
11266 	memcpy(resource, entry, sizeof(*resource));
11267 	resource->idx = idx;
11268 	resource->dev = dev;
11269 	return &resource->entry;
11270 }
11271 
11272 void
11273 flow_dv_sample_clone_free_cb(void *tool_ctx __rte_unused,
11274 			     struct mlx5_list_entry *entry)
11275 {
11276 	struct mlx5_flow_dv_sample_resource *resource =
11277 				  container_of(entry, typeof(*resource), entry);
11278 	struct rte_eth_dev *dev = resource->dev;
11279 	struct mlx5_priv *priv = dev->data->dev_private;
11280 
11281 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
11282 }
11283 
11284 /**
11285  * Find existing sample resource or create and register a new one.
11286  *
11287  * @param[in, out] dev
11288  *   Pointer to rte_eth_dev structure.
11289  * @param[in] ref
11290  *   Pointer to sample resource reference.
11291  * @parm[in, out] dev_flow
11292  *   Pointer to the dev_flow.
11293  * @param[out] error
11294  *   pointer to error structure.
11295  *
11296  * @return
11297  *   0 on success otherwise -errno and errno is set.
11298  */
11299 static int
11300 flow_dv_sample_resource_register(struct rte_eth_dev *dev,
11301 			 struct mlx5_flow_dv_sample_resource *ref,
11302 			 struct mlx5_flow *dev_flow,
11303 			 struct rte_flow_error *error)
11304 {
11305 	struct mlx5_flow_dv_sample_resource *resource;
11306 	struct mlx5_list_entry *entry;
11307 	struct mlx5_priv *priv = dev->data->dev_private;
11308 	struct mlx5_flow_cb_ctx ctx = {
11309 		.dev = dev,
11310 		.error = error,
11311 		.data = ref,
11312 	};
11313 
11314 	entry = mlx5_list_register(priv->sh->sample_action_list, &ctx);
11315 	if (!entry)
11316 		return -rte_errno;
11317 	resource = container_of(entry, typeof(*resource), entry);
11318 	dev_flow->handle->dvh.rix_sample = resource->idx;
11319 	dev_flow->dv.sample_res = resource;
11320 	return 0;
11321 }
11322 
11323 int
11324 flow_dv_dest_array_match_cb(void *tool_ctx __rte_unused,
11325 			    struct mlx5_list_entry *entry, void *cb_ctx)
11326 {
11327 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11328 	struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11329 	struct rte_eth_dev *dev = ctx->dev;
11330 	struct mlx5_flow_dv_dest_array_resource *resource =
11331 				  container_of(entry, typeof(*resource), entry);
11332 	uint32_t idx = 0;
11333 
11334 	if (ctx_resource->num_of_dest == resource->num_of_dest &&
11335 	    ctx_resource->ft_type == resource->ft_type &&
11336 	    !memcmp((void *)resource->sample_act,
11337 		    (void *)ctx_resource->sample_act,
11338 		   (ctx_resource->num_of_dest *
11339 		   sizeof(struct mlx5_flow_sub_actions_list)))) {
11340 		/*
11341 		 * Existing sample action should release the prepared
11342 		 * sub-actions reference counter.
11343 		 */
11344 		for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11345 			flow_dv_sample_sub_actions_release(dev,
11346 					&ctx_resource->sample_idx[idx]);
11347 		return 0;
11348 	}
11349 	return 1;
11350 }
11351 
11352 struct mlx5_list_entry *
11353 flow_dv_dest_array_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
11354 {
11355 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11356 	struct rte_eth_dev *dev = ctx->dev;
11357 	struct mlx5_flow_dv_dest_array_resource *resource;
11358 	struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11359 	struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 };
11360 	struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM];
11361 	struct mlx5_priv *priv = dev->data->dev_private;
11362 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11363 	struct mlx5_flow_sub_actions_list *sample_act;
11364 	struct mlx5dv_dr_domain *domain;
11365 	uint32_t idx = 0, res_idx = 0;
11366 	struct rte_flow_error *error = ctx->error;
11367 	uint64_t action_flags;
11368 	int ret;
11369 
11370 	/* Register new destination array resource. */
11371 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11372 					    &res_idx);
11373 	if (!resource) {
11374 		rte_flow_error_set(error, ENOMEM,
11375 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11376 					  NULL,
11377 					  "cannot allocate resource memory");
11378 		return NULL;
11379 	}
11380 	*resource = *ctx_resource;
11381 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11382 		domain = sh->fdb_domain;
11383 	else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
11384 		domain = sh->rx_domain;
11385 	else
11386 		domain = sh->tx_domain;
11387 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11388 		dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *)
11389 				 mlx5_malloc(MLX5_MEM_ZERO,
11390 				 sizeof(struct mlx5dv_dr_action_dest_attr),
11391 				 0, SOCKET_ID_ANY);
11392 		if (!dest_attr[idx]) {
11393 			rte_flow_error_set(error, ENOMEM,
11394 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11395 					   NULL,
11396 					   "cannot allocate resource memory");
11397 			goto error;
11398 		}
11399 		dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST;
11400 		sample_act = &ctx_resource->sample_act[idx];
11401 		action_flags = sample_act->action_flags;
11402 		switch (action_flags) {
11403 		case MLX5_FLOW_ACTION_QUEUE:
11404 			dest_attr[idx]->dest = sample_act->dr_queue_action;
11405 			break;
11406 		case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP):
11407 			dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT;
11408 			dest_attr[idx]->dest_reformat = &dest_reformat[idx];
11409 			dest_attr[idx]->dest_reformat->reformat =
11410 					sample_act->dr_encap_action;
11411 			dest_attr[idx]->dest_reformat->dest =
11412 					sample_act->dr_port_id_action;
11413 			break;
11414 		case MLX5_FLOW_ACTION_PORT_ID:
11415 			dest_attr[idx]->dest = sample_act->dr_port_id_action;
11416 			break;
11417 		case MLX5_FLOW_ACTION_JUMP:
11418 			dest_attr[idx]->dest = sample_act->dr_jump_action;
11419 			break;
11420 		default:
11421 			rte_flow_error_set(error, EINVAL,
11422 					   RTE_FLOW_ERROR_TYPE_ACTION,
11423 					   NULL,
11424 					   "unsupported actions type");
11425 			goto error;
11426 		}
11427 	}
11428 	/* create a dest array actioin */
11429 	ret = mlx5_os_flow_dr_create_flow_action_dest_array
11430 						(domain,
11431 						 resource->num_of_dest,
11432 						 dest_attr,
11433 						 &resource->action);
11434 	if (ret) {
11435 		rte_flow_error_set(error, ENOMEM,
11436 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11437 				   NULL,
11438 				   "cannot create destination array action");
11439 		goto error;
11440 	}
11441 	resource->idx = res_idx;
11442 	resource->dev = dev;
11443 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11444 		mlx5_free(dest_attr[idx]);
11445 	return &resource->entry;
11446 error:
11447 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11448 		flow_dv_sample_sub_actions_release(dev,
11449 						   &resource->sample_idx[idx]);
11450 		if (dest_attr[idx])
11451 			mlx5_free(dest_attr[idx]);
11452 	}
11453 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx);
11454 	return NULL;
11455 }
11456 
11457 struct mlx5_list_entry *
11458 flow_dv_dest_array_clone_cb(void *tool_ctx __rte_unused,
11459 			    struct mlx5_list_entry *entry __rte_unused,
11460 			    void *cb_ctx)
11461 {
11462 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11463 	struct rte_eth_dev *dev = ctx->dev;
11464 	struct mlx5_flow_dv_dest_array_resource *resource;
11465 	struct mlx5_priv *priv = dev->data->dev_private;
11466 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11467 	uint32_t res_idx = 0;
11468 	struct rte_flow_error *error = ctx->error;
11469 
11470 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11471 				      &res_idx);
11472 	if (!resource) {
11473 		rte_flow_error_set(error, ENOMEM,
11474 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11475 					  NULL,
11476 					  "cannot allocate dest-array memory");
11477 		return NULL;
11478 	}
11479 	memcpy(resource, entry, sizeof(*resource));
11480 	resource->idx = res_idx;
11481 	resource->dev = dev;
11482 	return &resource->entry;
11483 }
11484 
11485 void
11486 flow_dv_dest_array_clone_free_cb(void *tool_ctx __rte_unused,
11487 				 struct mlx5_list_entry *entry)
11488 {
11489 	struct mlx5_flow_dv_dest_array_resource *resource =
11490 			container_of(entry, typeof(*resource), entry);
11491 	struct rte_eth_dev *dev = resource->dev;
11492 	struct mlx5_priv *priv = dev->data->dev_private;
11493 
11494 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
11495 }
11496 
11497 /**
11498  * Find existing destination array resource or create and register a new one.
11499  *
11500  * @param[in, out] dev
11501  *   Pointer to rte_eth_dev structure.
11502  * @param[in] ref
11503  *   Pointer to destination array resource reference.
11504  * @parm[in, out] dev_flow
11505  *   Pointer to the dev_flow.
11506  * @param[out] error
11507  *   pointer to error structure.
11508  *
11509  * @return
11510  *   0 on success otherwise -errno and errno is set.
11511  */
11512 static int
11513 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev,
11514 			 struct mlx5_flow_dv_dest_array_resource *ref,
11515 			 struct mlx5_flow *dev_flow,
11516 			 struct rte_flow_error *error)
11517 {
11518 	struct mlx5_flow_dv_dest_array_resource *resource;
11519 	struct mlx5_priv *priv = dev->data->dev_private;
11520 	struct mlx5_list_entry *entry;
11521 	struct mlx5_flow_cb_ctx ctx = {
11522 		.dev = dev,
11523 		.error = error,
11524 		.data = ref,
11525 	};
11526 
11527 	entry = mlx5_list_register(priv->sh->dest_array_list, &ctx);
11528 	if (!entry)
11529 		return -rte_errno;
11530 	resource = container_of(entry, typeof(*resource), entry);
11531 	dev_flow->handle->dvh.rix_dest_array = resource->idx;
11532 	dev_flow->dv.dest_array_res = resource;
11533 	return 0;
11534 }
11535 
11536 /**
11537  * Convert Sample action to DV specification.
11538  *
11539  * @param[in] dev
11540  *   Pointer to rte_eth_dev structure.
11541  * @param[in] action
11542  *   Pointer to sample action structure.
11543  * @param[in, out] dev_flow
11544  *   Pointer to the mlx5_flow.
11545  * @param[in] attr
11546  *   Pointer to the flow attributes.
11547  * @param[in, out] num_of_dest
11548  *   Pointer to the num of destination.
11549  * @param[in, out] sample_actions
11550  *   Pointer to sample actions list.
11551  * @param[in, out] res
11552  *   Pointer to sample resource.
11553  * @param[out] error
11554  *   Pointer to the error structure.
11555  *
11556  * @return
11557  *   0 on success, a negative errno value otherwise and rte_errno is set.
11558  */
11559 static int
11560 flow_dv_translate_action_sample(struct rte_eth_dev *dev,
11561 				const struct rte_flow_action_sample *action,
11562 				struct mlx5_flow *dev_flow,
11563 				const struct rte_flow_attr *attr,
11564 				uint32_t *num_of_dest,
11565 				void **sample_actions,
11566 				struct mlx5_flow_dv_sample_resource *res,
11567 				struct rte_flow_error *error)
11568 {
11569 	struct mlx5_priv *priv = dev->data->dev_private;
11570 	const struct rte_flow_action *sub_actions;
11571 	struct mlx5_flow_sub_actions_list *sample_act;
11572 	struct mlx5_flow_sub_actions_idx *sample_idx;
11573 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
11574 	struct rte_flow *flow = dev_flow->flow;
11575 	struct mlx5_flow_rss_desc *rss_desc;
11576 	uint64_t action_flags = 0;
11577 
11578 	MLX5_ASSERT(wks);
11579 	rss_desc = &wks->rss_desc;
11580 	sample_act = &res->sample_act;
11581 	sample_idx = &res->sample_idx;
11582 	res->ratio = action->ratio;
11583 	sub_actions = action->actions;
11584 	for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) {
11585 		int type = sub_actions->type;
11586 		uint32_t pre_rix = 0;
11587 		void *pre_r;
11588 		switch (type) {
11589 		case RTE_FLOW_ACTION_TYPE_QUEUE:
11590 		{
11591 			const struct rte_flow_action_queue *queue;
11592 			struct mlx5_hrxq *hrxq;
11593 			uint32_t hrxq_idx;
11594 
11595 			queue = sub_actions->conf;
11596 			rss_desc->queue_num = 1;
11597 			rss_desc->queue[0] = queue->index;
11598 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11599 						    rss_desc, &hrxq_idx);
11600 			if (!hrxq)
11601 				return rte_flow_error_set
11602 					(error, rte_errno,
11603 					 RTE_FLOW_ERROR_TYPE_ACTION,
11604 					 NULL,
11605 					 "cannot create fate queue");
11606 			sample_act->dr_queue_action = hrxq->action;
11607 			sample_idx->rix_hrxq = hrxq_idx;
11608 			sample_actions[sample_act->actions_num++] =
11609 						hrxq->action;
11610 			(*num_of_dest)++;
11611 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
11612 			if (action_flags & MLX5_FLOW_ACTION_MARK)
11613 				dev_flow->handle->rix_hrxq = hrxq_idx;
11614 			dev_flow->handle->fate_action =
11615 					MLX5_FLOW_FATE_QUEUE;
11616 			break;
11617 		}
11618 		case RTE_FLOW_ACTION_TYPE_RSS:
11619 		{
11620 			struct mlx5_hrxq *hrxq;
11621 			uint32_t hrxq_idx;
11622 			const struct rte_flow_action_rss *rss;
11623 			const uint8_t *rss_key;
11624 
11625 			rss = sub_actions->conf;
11626 			memcpy(rss_desc->queue, rss->queue,
11627 			       rss->queue_num * sizeof(uint16_t));
11628 			rss_desc->queue_num = rss->queue_num;
11629 			/* NULL RSS key indicates default RSS key. */
11630 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
11631 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
11632 			/*
11633 			 * rss->level and rss.types should be set in advance
11634 			 * when expanding items for RSS.
11635 			 */
11636 			flow_dv_hashfields_set(dev_flow, rss_desc);
11637 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11638 						    rss_desc, &hrxq_idx);
11639 			if (!hrxq)
11640 				return rte_flow_error_set
11641 					(error, rte_errno,
11642 					 RTE_FLOW_ERROR_TYPE_ACTION,
11643 					 NULL,
11644 					 "cannot create fate queue");
11645 			sample_act->dr_queue_action = hrxq->action;
11646 			sample_idx->rix_hrxq = hrxq_idx;
11647 			sample_actions[sample_act->actions_num++] =
11648 						hrxq->action;
11649 			(*num_of_dest)++;
11650 			action_flags |= MLX5_FLOW_ACTION_RSS;
11651 			if (action_flags & MLX5_FLOW_ACTION_MARK)
11652 				dev_flow->handle->rix_hrxq = hrxq_idx;
11653 			dev_flow->handle->fate_action =
11654 					MLX5_FLOW_FATE_QUEUE;
11655 			break;
11656 		}
11657 		case RTE_FLOW_ACTION_TYPE_MARK:
11658 		{
11659 			uint32_t tag_be = mlx5_flow_mark_set
11660 				(((const struct rte_flow_action_mark *)
11661 				(sub_actions->conf))->id);
11662 
11663 			dev_flow->handle->mark = 1;
11664 			pre_rix = dev_flow->handle->dvh.rix_tag;
11665 			/* Save the mark resource before sample */
11666 			pre_r = dev_flow->dv.tag_resource;
11667 			if (flow_dv_tag_resource_register(dev, tag_be,
11668 						  dev_flow, error))
11669 				return -rte_errno;
11670 			MLX5_ASSERT(dev_flow->dv.tag_resource);
11671 			sample_act->dr_tag_action =
11672 				dev_flow->dv.tag_resource->action;
11673 			sample_idx->rix_tag =
11674 				dev_flow->handle->dvh.rix_tag;
11675 			sample_actions[sample_act->actions_num++] =
11676 						sample_act->dr_tag_action;
11677 			/* Recover the mark resource after sample */
11678 			dev_flow->dv.tag_resource = pre_r;
11679 			dev_flow->handle->dvh.rix_tag = pre_rix;
11680 			action_flags |= MLX5_FLOW_ACTION_MARK;
11681 			break;
11682 		}
11683 		case RTE_FLOW_ACTION_TYPE_COUNT:
11684 		{
11685 			if (!flow->counter) {
11686 				flow->counter =
11687 					flow_dv_translate_create_counter(dev,
11688 						dev_flow, sub_actions->conf,
11689 						0);
11690 				if (!flow->counter)
11691 					return rte_flow_error_set
11692 						(error, rte_errno,
11693 						RTE_FLOW_ERROR_TYPE_ACTION,
11694 						NULL,
11695 						"cannot create counter"
11696 						" object.");
11697 			}
11698 			sample_act->dr_cnt_action =
11699 				  (flow_dv_counter_get_by_idx(dev,
11700 				  flow->counter, NULL))->action;
11701 			sample_actions[sample_act->actions_num++] =
11702 						sample_act->dr_cnt_action;
11703 			action_flags |= MLX5_FLOW_ACTION_COUNT;
11704 			break;
11705 		}
11706 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
11707 		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
11708 		{
11709 			struct mlx5_flow_dv_port_id_action_resource
11710 					port_id_resource;
11711 			uint32_t port_id = 0;
11712 
11713 			memset(&port_id_resource, 0, sizeof(port_id_resource));
11714 			/* Save the port id resource before sample */
11715 			pre_rix = dev_flow->handle->rix_port_id_action;
11716 			pre_r = dev_flow->dv.port_id_action;
11717 			if (flow_dv_translate_action_port_id(dev, sub_actions,
11718 							     &port_id, error))
11719 				return -rte_errno;
11720 			port_id_resource.port_id = port_id;
11721 			if (flow_dv_port_id_action_resource_register
11722 			    (dev, &port_id_resource, dev_flow, error))
11723 				return -rte_errno;
11724 			sample_act->dr_port_id_action =
11725 				dev_flow->dv.port_id_action->action;
11726 			sample_idx->rix_port_id_action =
11727 				dev_flow->handle->rix_port_id_action;
11728 			sample_actions[sample_act->actions_num++] =
11729 						sample_act->dr_port_id_action;
11730 			/* Recover the port id resource after sample */
11731 			dev_flow->dv.port_id_action = pre_r;
11732 			dev_flow->handle->rix_port_id_action = pre_rix;
11733 			(*num_of_dest)++;
11734 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
11735 			break;
11736 		}
11737 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
11738 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
11739 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
11740 			/* Save the encap resource before sample */
11741 			pre_rix = dev_flow->handle->dvh.rix_encap_decap;
11742 			pre_r = dev_flow->dv.encap_decap;
11743 			if (flow_dv_create_action_l2_encap(dev, sub_actions,
11744 							   dev_flow,
11745 							   attr->transfer,
11746 							   error))
11747 				return -rte_errno;
11748 			sample_act->dr_encap_action =
11749 				dev_flow->dv.encap_decap->action;
11750 			sample_idx->rix_encap_decap =
11751 				dev_flow->handle->dvh.rix_encap_decap;
11752 			sample_actions[sample_act->actions_num++] =
11753 						sample_act->dr_encap_action;
11754 			/* Recover the encap resource after sample */
11755 			dev_flow->dv.encap_decap = pre_r;
11756 			dev_flow->handle->dvh.rix_encap_decap = pre_rix;
11757 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
11758 			break;
11759 		default:
11760 			return rte_flow_error_set(error, EINVAL,
11761 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11762 				NULL,
11763 				"Not support for sampler action");
11764 		}
11765 	}
11766 	sample_act->action_flags = action_flags;
11767 	res->ft_id = dev_flow->dv.group;
11768 	if (attr->transfer) {
11769 		union {
11770 			uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)];
11771 			uint64_t set_action;
11772 		} action_ctx = { .set_action = 0 };
11773 
11774 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
11775 		MLX5_SET(set_action_in, action_ctx.action_in, action_type,
11776 			 MLX5_MODIFICATION_TYPE_SET);
11777 		MLX5_SET(set_action_in, action_ctx.action_in, field,
11778 			 MLX5_MODI_META_REG_C_0);
11779 		MLX5_SET(set_action_in, action_ctx.action_in, data,
11780 			 priv->vport_meta_tag);
11781 		res->set_action = action_ctx.set_action;
11782 	} else if (attr->ingress) {
11783 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
11784 	} else {
11785 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
11786 	}
11787 	return 0;
11788 }
11789 
11790 /**
11791  * Convert Sample action to DV specification.
11792  *
11793  * @param[in] dev
11794  *   Pointer to rte_eth_dev structure.
11795  * @param[in, out] dev_flow
11796  *   Pointer to the mlx5_flow.
11797  * @param[in] num_of_dest
11798  *   The num of destination.
11799  * @param[in, out] res
11800  *   Pointer to sample resource.
11801  * @param[in, out] mdest_res
11802  *   Pointer to destination array resource.
11803  * @param[in] sample_actions
11804  *   Pointer to sample path actions list.
11805  * @param[in] action_flags
11806  *   Holds the actions detected until now.
11807  * @param[out] error
11808  *   Pointer to the error structure.
11809  *
11810  * @return
11811  *   0 on success, a negative errno value otherwise and rte_errno is set.
11812  */
11813 static int
11814 flow_dv_create_action_sample(struct rte_eth_dev *dev,
11815 			     struct mlx5_flow *dev_flow,
11816 			     uint32_t num_of_dest,
11817 			     struct mlx5_flow_dv_sample_resource *res,
11818 			     struct mlx5_flow_dv_dest_array_resource *mdest_res,
11819 			     void **sample_actions,
11820 			     uint64_t action_flags,
11821 			     struct rte_flow_error *error)
11822 {
11823 	/* update normal path action resource into last index of array */
11824 	uint32_t dest_index = MLX5_MAX_DEST_NUM - 1;
11825 	struct mlx5_flow_sub_actions_list *sample_act =
11826 					&mdest_res->sample_act[dest_index];
11827 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
11828 	struct mlx5_flow_rss_desc *rss_desc;
11829 	uint32_t normal_idx = 0;
11830 	struct mlx5_hrxq *hrxq;
11831 	uint32_t hrxq_idx;
11832 
11833 	MLX5_ASSERT(wks);
11834 	rss_desc = &wks->rss_desc;
11835 	if (num_of_dest > 1) {
11836 		if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) {
11837 			/* Handle QP action for mirroring */
11838 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
11839 						    rss_desc, &hrxq_idx);
11840 			if (!hrxq)
11841 				return rte_flow_error_set
11842 				     (error, rte_errno,
11843 				      RTE_FLOW_ERROR_TYPE_ACTION,
11844 				      NULL,
11845 				      "cannot create rx queue");
11846 			normal_idx++;
11847 			mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx;
11848 			sample_act->dr_queue_action = hrxq->action;
11849 			if (action_flags & MLX5_FLOW_ACTION_MARK)
11850 				dev_flow->handle->rix_hrxq = hrxq_idx;
11851 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
11852 		}
11853 		if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) {
11854 			normal_idx++;
11855 			mdest_res->sample_idx[dest_index].rix_encap_decap =
11856 				dev_flow->handle->dvh.rix_encap_decap;
11857 			sample_act->dr_encap_action =
11858 				dev_flow->dv.encap_decap->action;
11859 			dev_flow->handle->dvh.rix_encap_decap = 0;
11860 		}
11861 		if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) {
11862 			normal_idx++;
11863 			mdest_res->sample_idx[dest_index].rix_port_id_action =
11864 				dev_flow->handle->rix_port_id_action;
11865 			sample_act->dr_port_id_action =
11866 				dev_flow->dv.port_id_action->action;
11867 			dev_flow->handle->rix_port_id_action = 0;
11868 		}
11869 		if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) {
11870 			normal_idx++;
11871 			mdest_res->sample_idx[dest_index].rix_jump =
11872 				dev_flow->handle->rix_jump;
11873 			sample_act->dr_jump_action =
11874 				dev_flow->dv.jump->action;
11875 			dev_flow->handle->rix_jump = 0;
11876 		}
11877 		sample_act->actions_num = normal_idx;
11878 		/* update sample action resource into first index of array */
11879 		mdest_res->ft_type = res->ft_type;
11880 		memcpy(&mdest_res->sample_idx[0], &res->sample_idx,
11881 				sizeof(struct mlx5_flow_sub_actions_idx));
11882 		memcpy(&mdest_res->sample_act[0], &res->sample_act,
11883 				sizeof(struct mlx5_flow_sub_actions_list));
11884 		mdest_res->num_of_dest = num_of_dest;
11885 		if (flow_dv_dest_array_resource_register(dev, mdest_res,
11886 							 dev_flow, error))
11887 			return rte_flow_error_set(error, EINVAL,
11888 						  RTE_FLOW_ERROR_TYPE_ACTION,
11889 						  NULL, "can't create sample "
11890 						  "action");
11891 	} else {
11892 		res->sub_actions = sample_actions;
11893 		if (flow_dv_sample_resource_register(dev, res, dev_flow, error))
11894 			return rte_flow_error_set(error, EINVAL,
11895 						  RTE_FLOW_ERROR_TYPE_ACTION,
11896 						  NULL,
11897 						  "can't create sample action");
11898 	}
11899 	return 0;
11900 }
11901 
11902 /**
11903  * Remove an ASO age action from age actions list.
11904  *
11905  * @param[in] dev
11906  *   Pointer to the Ethernet device structure.
11907  * @param[in] age
11908  *   Pointer to the aso age action handler.
11909  */
11910 static void
11911 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev,
11912 				struct mlx5_aso_age_action *age)
11913 {
11914 	struct mlx5_age_info *age_info;
11915 	struct mlx5_age_param *age_param = &age->age_params;
11916 	struct mlx5_priv *priv = dev->data->dev_private;
11917 	uint16_t expected = AGE_CANDIDATE;
11918 
11919 	age_info = GET_PORT_AGE_INFO(priv);
11920 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
11921 					 AGE_FREE, false, __ATOMIC_RELAXED,
11922 					 __ATOMIC_RELAXED)) {
11923 		/**
11924 		 * We need the lock even it is age timeout,
11925 		 * since age action may still in process.
11926 		 */
11927 		rte_spinlock_lock(&age_info->aged_sl);
11928 		LIST_REMOVE(age, next);
11929 		rte_spinlock_unlock(&age_info->aged_sl);
11930 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
11931 	}
11932 }
11933 
11934 /**
11935  * Release an ASO age action.
11936  *
11937  * @param[in] dev
11938  *   Pointer to the Ethernet device structure.
11939  * @param[in] age_idx
11940  *   Index of ASO age action to release.
11941  * @param[in] flow
11942  *   True if the release operation is during flow destroy operation.
11943  *   False if the release operation is during action destroy operation.
11944  *
11945  * @return
11946  *   0 when age action was removed, otherwise the number of references.
11947  */
11948 static int
11949 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx)
11950 {
11951 	struct mlx5_priv *priv = dev->data->dev_private;
11952 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11953 	struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx);
11954 	uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED);
11955 
11956 	if (!ret) {
11957 		flow_dv_aso_age_remove_from_age(dev, age);
11958 		rte_spinlock_lock(&mng->free_sl);
11959 		LIST_INSERT_HEAD(&mng->free, age, next);
11960 		rte_spinlock_unlock(&mng->free_sl);
11961 	}
11962 	return ret;
11963 }
11964 
11965 /**
11966  * Resize the ASO age pools array by MLX5_CNT_CONTAINER_RESIZE pools.
11967  *
11968  * @param[in] dev
11969  *   Pointer to the Ethernet device structure.
11970  *
11971  * @return
11972  *   0 on success, otherwise negative errno value and rte_errno is set.
11973  */
11974 static int
11975 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev)
11976 {
11977 	struct mlx5_priv *priv = dev->data->dev_private;
11978 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
11979 	void *old_pools = mng->pools;
11980 	uint32_t resize = mng->n + MLX5_CNT_CONTAINER_RESIZE;
11981 	uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize;
11982 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
11983 
11984 	if (!pools) {
11985 		rte_errno = ENOMEM;
11986 		return -ENOMEM;
11987 	}
11988 	if (old_pools) {
11989 		memcpy(pools, old_pools,
11990 		       mng->n * sizeof(struct mlx5_flow_counter_pool *));
11991 		mlx5_free(old_pools);
11992 	} else {
11993 		/* First ASO flow hit allocation - starting ASO data-path. */
11994 		int ret = mlx5_aso_flow_hit_queue_poll_start(priv->sh);
11995 
11996 		if (ret) {
11997 			mlx5_free(pools);
11998 			return ret;
11999 		}
12000 	}
12001 	mng->n = resize;
12002 	mng->pools = pools;
12003 	return 0;
12004 }
12005 
12006 /**
12007  * Create and initialize a new ASO aging pool.
12008  *
12009  * @param[in] dev
12010  *   Pointer to the Ethernet device structure.
12011  * @param[out] age_free
12012  *   Where to put the pointer of a new age action.
12013  *
12014  * @return
12015  *   The age actions pool pointer and @p age_free is set on success,
12016  *   NULL otherwise and rte_errno is set.
12017  */
12018 static struct mlx5_aso_age_pool *
12019 flow_dv_age_pool_create(struct rte_eth_dev *dev,
12020 			struct mlx5_aso_age_action **age_free)
12021 {
12022 	struct mlx5_priv *priv = dev->data->dev_private;
12023 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
12024 	struct mlx5_aso_age_pool *pool = NULL;
12025 	struct mlx5_devx_obj *obj = NULL;
12026 	uint32_t i;
12027 
12028 	obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->cdev->ctx,
12029 						    priv->sh->cdev->pdn);
12030 	if (!obj) {
12031 		rte_errno = ENODATA;
12032 		DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX.");
12033 		return NULL;
12034 	}
12035 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
12036 	if (!pool) {
12037 		claim_zero(mlx5_devx_cmd_destroy(obj));
12038 		rte_errno = ENOMEM;
12039 		return NULL;
12040 	}
12041 	pool->flow_hit_aso_obj = obj;
12042 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
12043 	rte_rwlock_write_lock(&mng->resize_rwl);
12044 	pool->index = mng->next;
12045 	/* Resize pools array if there is no room for the new pool in it. */
12046 	if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) {
12047 		claim_zero(mlx5_devx_cmd_destroy(obj));
12048 		mlx5_free(pool);
12049 		rte_rwlock_write_unlock(&mng->resize_rwl);
12050 		return NULL;
12051 	}
12052 	mng->pools[pool->index] = pool;
12053 	mng->next++;
12054 	rte_rwlock_write_unlock(&mng->resize_rwl);
12055 	/* Assign the first action in the new pool, the rest go to free list. */
12056 	*age_free = &pool->actions[0];
12057 	for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) {
12058 		pool->actions[i].offset = i;
12059 		LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next);
12060 	}
12061 	return pool;
12062 }
12063 
12064 /**
12065  * Allocate a ASO aging bit.
12066  *
12067  * @param[in] dev
12068  *   Pointer to the Ethernet device structure.
12069  * @param[out] error
12070  *   Pointer to the error structure.
12071  *
12072  * @return
12073  *   Index to ASO age action on success, 0 otherwise and rte_errno is set.
12074  */
12075 static uint32_t
12076 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
12077 {
12078 	struct mlx5_priv *priv = dev->data->dev_private;
12079 	const struct mlx5_aso_age_pool *pool;
12080 	struct mlx5_aso_age_action *age_free = NULL;
12081 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
12082 
12083 	MLX5_ASSERT(mng);
12084 	/* Try to get the next free age action bit. */
12085 	rte_spinlock_lock(&mng->free_sl);
12086 	age_free = LIST_FIRST(&mng->free);
12087 	if (age_free) {
12088 		LIST_REMOVE(age_free, next);
12089 	} else if (!flow_dv_age_pool_create(dev, &age_free)) {
12090 		rte_spinlock_unlock(&mng->free_sl);
12091 		rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
12092 				   NULL, "failed to create ASO age pool");
12093 		return 0; /* 0 is an error. */
12094 	}
12095 	rte_spinlock_unlock(&mng->free_sl);
12096 	pool = container_of
12097 	  ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL])
12098 		  (age_free - age_free->offset), const struct mlx5_aso_age_pool,
12099 								       actions);
12100 	if (!age_free->dr_action) {
12101 		int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0,
12102 						 error);
12103 
12104 		if (reg_c < 0) {
12105 			rte_flow_error_set(error, rte_errno,
12106 					   RTE_FLOW_ERROR_TYPE_ACTION,
12107 					   NULL, "failed to get reg_c "
12108 					   "for ASO flow hit");
12109 			return 0; /* 0 is an error. */
12110 		}
12111 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
12112 		age_free->dr_action = mlx5_glue->dv_create_flow_action_aso
12113 				(priv->sh->rx_domain,
12114 				 pool->flow_hit_aso_obj->obj, age_free->offset,
12115 				 MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET,
12116 				 (reg_c - REG_C_0));
12117 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
12118 		if (!age_free->dr_action) {
12119 			rte_errno = errno;
12120 			rte_spinlock_lock(&mng->free_sl);
12121 			LIST_INSERT_HEAD(&mng->free, age_free, next);
12122 			rte_spinlock_unlock(&mng->free_sl);
12123 			rte_flow_error_set(error, rte_errno,
12124 					   RTE_FLOW_ERROR_TYPE_ACTION,
12125 					   NULL, "failed to create ASO "
12126 					   "flow hit action");
12127 			return 0; /* 0 is an error. */
12128 		}
12129 	}
12130 	__atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED);
12131 	return pool->index | ((age_free->offset + 1) << 16);
12132 }
12133 
12134 /**
12135  * Initialize flow ASO age parameters.
12136  *
12137  * @param[in] dev
12138  *   Pointer to rte_eth_dev structure.
12139  * @param[in] age_idx
12140  *   Index of ASO age action.
12141  * @param[in] context
12142  *   Pointer to flow counter age context.
12143  * @param[in] timeout
12144  *   Aging timeout in seconds.
12145  *
12146  */
12147 static void
12148 flow_dv_aso_age_params_init(struct rte_eth_dev *dev,
12149 			    uint32_t age_idx,
12150 			    void *context,
12151 			    uint32_t timeout)
12152 {
12153 	struct mlx5_aso_age_action *aso_age;
12154 
12155 	aso_age = flow_aso_age_get_by_idx(dev, age_idx);
12156 	MLX5_ASSERT(aso_age);
12157 	aso_age->age_params.context = context;
12158 	aso_age->age_params.timeout = timeout;
12159 	aso_age->age_params.port_id = dev->data->port_id;
12160 	__atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0,
12161 			 __ATOMIC_RELAXED);
12162 	__atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE,
12163 			 __ATOMIC_RELAXED);
12164 }
12165 
12166 static void
12167 flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask,
12168 			       const struct rte_flow_item_integrity *value,
12169 			       void *headers_m, void *headers_v)
12170 {
12171 	if (mask->l4_ok) {
12172 		/* RTE l4_ok filter aggregates hardware l4_ok and
12173 		 * l4_checksum_ok filters.
12174 		 * Positive RTE l4_ok match requires hardware match on both L4
12175 		 * hardware integrity bits.
12176 		 * For negative match, check hardware l4_checksum_ok bit only,
12177 		 * because hardware sets that bit to 0 for all packets
12178 		 * with bad L4.
12179 		 */
12180 		if (value->l4_ok) {
12181 			MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_ok, 1);
12182 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_ok, 1);
12183 		}
12184 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 1);
12185 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok,
12186 			 !!value->l4_ok);
12187 	}
12188 	if (mask->l4_csum_ok) {
12189 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, l4_checksum_ok, 1);
12190 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, l4_checksum_ok,
12191 			 value->l4_csum_ok);
12192 	}
12193 }
12194 
12195 static void
12196 flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask,
12197 			       const struct rte_flow_item_integrity *value,
12198 			       void *headers_m, void *headers_v, bool is_ipv4)
12199 {
12200 	if (mask->l3_ok) {
12201 		/* RTE l3_ok filter aggregates for IPv4 hardware l3_ok and
12202 		 * ipv4_csum_ok filters.
12203 		 * Positive RTE l3_ok match requires hardware match on both L3
12204 		 * hardware integrity bits.
12205 		 * For negative match, check hardware l3_csum_ok bit only,
12206 		 * because hardware sets that bit to 0 for all packets
12207 		 * with bad L3.
12208 		 */
12209 		if (is_ipv4) {
12210 			if (value->l3_ok) {
12211 				MLX5_SET(fte_match_set_lyr_2_4, headers_m,
12212 					 l3_ok, 1);
12213 				MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12214 					 l3_ok, 1);
12215 			}
12216 			MLX5_SET(fte_match_set_lyr_2_4, headers_m,
12217 				 ipv4_checksum_ok, 1);
12218 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
12219 				 ipv4_checksum_ok, !!value->l3_ok);
12220 		} else {
12221 			MLX5_SET(fte_match_set_lyr_2_4, headers_m, l3_ok, 1);
12222 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, l3_ok,
12223 				 value->l3_ok);
12224 		}
12225 	}
12226 	if (mask->ipv4_csum_ok) {
12227 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ipv4_checksum_ok, 1);
12228 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_checksum_ok,
12229 			 value->ipv4_csum_ok);
12230 	}
12231 }
12232 
12233 static void
12234 set_integrity_bits(void *headers_m, void *headers_v,
12235 		   const struct rte_flow_item *integrity_item, bool is_l3_ip4)
12236 {
12237 	const struct rte_flow_item_integrity *spec = integrity_item->spec;
12238 	const struct rte_flow_item_integrity *mask = integrity_item->mask;
12239 
12240 	/* Integrity bits validation cleared spec pointer */
12241 	MLX5_ASSERT(spec != NULL);
12242 	if (!mask)
12243 		mask = &rte_flow_item_integrity_mask;
12244 	flow_dv_translate_integrity_l3(mask, spec, headers_m, headers_v,
12245 				       is_l3_ip4);
12246 	flow_dv_translate_integrity_l4(mask, spec, headers_m, headers_v);
12247 }
12248 
12249 static void
12250 flow_dv_translate_item_integrity_post(void *matcher, void *key,
12251 				      const
12252 				      struct rte_flow_item *integrity_items[2],
12253 				      uint64_t pattern_flags)
12254 {
12255 	void *headers_m, *headers_v;
12256 	bool is_l3_ip4;
12257 
12258 	if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) {
12259 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
12260 					 inner_headers);
12261 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
12262 		is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4) !=
12263 			    0;
12264 		set_integrity_bits(headers_m, headers_v,
12265 				   integrity_items[1], is_l3_ip4);
12266 	}
12267 	if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) {
12268 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
12269 					 outer_headers);
12270 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
12271 		is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4) !=
12272 			    0;
12273 		set_integrity_bits(headers_m, headers_v,
12274 				   integrity_items[0], is_l3_ip4);
12275 	}
12276 }
12277 
12278 static void
12279 flow_dv_translate_item_integrity(const struct rte_flow_item *item,
12280 				 const struct rte_flow_item *integrity_items[2],
12281 				 uint64_t *last_item)
12282 {
12283 	const struct rte_flow_item_integrity *spec = (typeof(spec))item->spec;
12284 
12285 	/* integrity bits validation cleared spec pointer */
12286 	MLX5_ASSERT(spec != NULL);
12287 	if (spec->level > 1) {
12288 		integrity_items[1] = item;
12289 		*last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY;
12290 	} else {
12291 		integrity_items[0] = item;
12292 		*last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY;
12293 	}
12294 }
12295 
12296 /**
12297  * Prepares DV flow counter with aging configuration.
12298  * Gets it by index when exists, creates a new one when doesn't.
12299  *
12300  * @param[in] dev
12301  *   Pointer to rte_eth_dev structure.
12302  * @param[in] dev_flow
12303  *   Pointer to the mlx5_flow.
12304  * @param[in, out] flow
12305  *   Pointer to the sub flow.
12306  * @param[in] count
12307  *   Pointer to the counter action configuration.
12308  * @param[in] age
12309  *   Pointer to the aging action configuration.
12310  * @param[out] error
12311  *   Pointer to the error structure.
12312  *
12313  * @return
12314  *   Pointer to the counter, NULL otherwise.
12315  */
12316 static struct mlx5_flow_counter *
12317 flow_dv_prepare_counter(struct rte_eth_dev *dev,
12318 			struct mlx5_flow *dev_flow,
12319 			struct rte_flow *flow,
12320 			const struct rte_flow_action_count *count,
12321 			const struct rte_flow_action_age *age,
12322 			struct rte_flow_error *error)
12323 {
12324 	if (!flow->counter) {
12325 		flow->counter = flow_dv_translate_create_counter(dev, dev_flow,
12326 								 count, age);
12327 		if (!flow->counter) {
12328 			rte_flow_error_set(error, rte_errno,
12329 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12330 					   "cannot create counter object.");
12331 			return NULL;
12332 		}
12333 	}
12334 	return flow_dv_counter_get_by_idx(dev, flow->counter, NULL);
12335 }
12336 
12337 /*
12338  * Release an ASO CT action by its own device.
12339  *
12340  * @param[in] dev
12341  *   Pointer to the Ethernet device structure.
12342  * @param[in] idx
12343  *   Index of ASO CT action to release.
12344  *
12345  * @return
12346  *   0 when CT action was removed, otherwise the number of references.
12347  */
12348 static inline int
12349 flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx)
12350 {
12351 	struct mlx5_priv *priv = dev->data->dev_private;
12352 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12353 	uint32_t ret;
12354 	struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx);
12355 	enum mlx5_aso_ct_state state =
12356 			__atomic_load_n(&ct->state, __ATOMIC_RELAXED);
12357 
12358 	/* Cannot release when CT is in the ASO SQ. */
12359 	if (state == ASO_CONNTRACK_WAIT || state == ASO_CONNTRACK_QUERY)
12360 		return -1;
12361 	ret = __atomic_sub_fetch(&ct->refcnt, 1, __ATOMIC_RELAXED);
12362 	if (!ret) {
12363 		if (ct->dr_action_orig) {
12364 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12365 			claim_zero(mlx5_glue->destroy_flow_action
12366 					(ct->dr_action_orig));
12367 #endif
12368 			ct->dr_action_orig = NULL;
12369 		}
12370 		if (ct->dr_action_rply) {
12371 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12372 			claim_zero(mlx5_glue->destroy_flow_action
12373 					(ct->dr_action_rply));
12374 #endif
12375 			ct->dr_action_rply = NULL;
12376 		}
12377 		/* Clear the state to free, no need in 1st allocation. */
12378 		MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_FREE);
12379 		rte_spinlock_lock(&mng->ct_sl);
12380 		LIST_INSERT_HEAD(&mng->free_cts, ct, next);
12381 		rte_spinlock_unlock(&mng->ct_sl);
12382 	}
12383 	return (int)ret;
12384 }
12385 
12386 static inline int
12387 flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx,
12388 		       struct rte_flow_error *error)
12389 {
12390 	uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx);
12391 	uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx);
12392 	struct rte_eth_dev *owndev = &rte_eth_devices[owner];
12393 	int ret;
12394 
12395 	MLX5_ASSERT(owner < RTE_MAX_ETHPORTS);
12396 	if (dev->data->dev_started != 1)
12397 		return rte_flow_error_set(error, EAGAIN,
12398 					  RTE_FLOW_ERROR_TYPE_ACTION,
12399 					  NULL,
12400 					  "Indirect CT action cannot be destroyed when the port is stopped");
12401 	ret = flow_dv_aso_ct_dev_release(owndev, idx);
12402 	if (ret < 0)
12403 		return rte_flow_error_set(error, EAGAIN,
12404 					  RTE_FLOW_ERROR_TYPE_ACTION,
12405 					  NULL,
12406 					  "Current state prevents indirect CT action from being destroyed");
12407 	return ret;
12408 }
12409 
12410 /*
12411  * Resize the ASO CT pools array by 64 pools.
12412  *
12413  * @param[in] dev
12414  *   Pointer to the Ethernet device structure.
12415  *
12416  * @return
12417  *   0 on success, otherwise negative errno value and rte_errno is set.
12418  */
12419 static int
12420 flow_dv_aso_ct_pools_resize(struct rte_eth_dev *dev)
12421 {
12422 	struct mlx5_priv *priv = dev->data->dev_private;
12423 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12424 	void *old_pools = mng->pools;
12425 	/* Magic number now, need a macro. */
12426 	uint32_t resize = mng->n + 64;
12427 	uint32_t mem_size = sizeof(struct mlx5_aso_ct_pool *) * resize;
12428 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
12429 
12430 	if (!pools) {
12431 		rte_errno = ENOMEM;
12432 		return -rte_errno;
12433 	}
12434 	rte_rwlock_write_lock(&mng->resize_rwl);
12435 	/* ASO SQ/QP was already initialized in the startup. */
12436 	if (old_pools) {
12437 		/* Realloc could be an alternative choice. */
12438 		rte_memcpy(pools, old_pools,
12439 			   mng->n * sizeof(struct mlx5_aso_ct_pool *));
12440 		mlx5_free(old_pools);
12441 	}
12442 	mng->n = resize;
12443 	mng->pools = pools;
12444 	rte_rwlock_write_unlock(&mng->resize_rwl);
12445 	return 0;
12446 }
12447 
12448 /*
12449  * Create and initialize a new ASO CT pool.
12450  *
12451  * @param[in] dev
12452  *   Pointer to the Ethernet device structure.
12453  * @param[out] ct_free
12454  *   Where to put the pointer of a new CT action.
12455  *
12456  * @return
12457  *   The CT actions pool pointer and @p ct_free is set on success,
12458  *   NULL otherwise and rte_errno is set.
12459  */
12460 static struct mlx5_aso_ct_pool *
12461 flow_dv_ct_pool_create(struct rte_eth_dev *dev,
12462 		       struct mlx5_aso_ct_action **ct_free)
12463 {
12464 	struct mlx5_priv *priv = dev->data->dev_private;
12465 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12466 	struct mlx5_aso_ct_pool *pool = NULL;
12467 	struct mlx5_devx_obj *obj = NULL;
12468 	uint32_t i;
12469 	uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL);
12470 
12471 	obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->cdev->ctx,
12472 							  priv->sh->cdev->pdn,
12473 							  log_obj_size);
12474 	if (!obj) {
12475 		rte_errno = ENODATA;
12476 		DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX.");
12477 		return NULL;
12478 	}
12479 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
12480 	if (!pool) {
12481 		rte_errno = ENOMEM;
12482 		claim_zero(mlx5_devx_cmd_destroy(obj));
12483 		return NULL;
12484 	}
12485 	pool->devx_obj = obj;
12486 	pool->index = mng->next;
12487 	/* Resize pools array if there is no room for the new pool in it. */
12488 	if (pool->index == mng->n && flow_dv_aso_ct_pools_resize(dev)) {
12489 		claim_zero(mlx5_devx_cmd_destroy(obj));
12490 		mlx5_free(pool);
12491 		return NULL;
12492 	}
12493 	mng->pools[pool->index] = pool;
12494 	mng->next++;
12495 	/* Assign the first action in the new pool, the rest go to free list. */
12496 	*ct_free = &pool->actions[0];
12497 	/* Lock outside, the list operation is safe here. */
12498 	for (i = 1; i < MLX5_ASO_CT_ACTIONS_PER_POOL; i++) {
12499 		/* refcnt is 0 when allocating the memory. */
12500 		pool->actions[i].offset = i;
12501 		LIST_INSERT_HEAD(&mng->free_cts, &pool->actions[i], next);
12502 	}
12503 	return pool;
12504 }
12505 
12506 /*
12507  * Allocate a ASO CT action from free list.
12508  *
12509  * @param[in] dev
12510  *   Pointer to the Ethernet device structure.
12511  * @param[out] error
12512  *   Pointer to the error structure.
12513  *
12514  * @return
12515  *   Index to ASO CT action on success, 0 otherwise and rte_errno is set.
12516  */
12517 static uint32_t
12518 flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
12519 {
12520 	struct mlx5_priv *priv = dev->data->dev_private;
12521 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12522 	struct mlx5_aso_ct_action *ct = NULL;
12523 	struct mlx5_aso_ct_pool *pool;
12524 	uint8_t reg_c;
12525 	uint32_t ct_idx;
12526 
12527 	MLX5_ASSERT(mng);
12528 	if (!priv->sh->devx) {
12529 		rte_errno = ENOTSUP;
12530 		return 0;
12531 	}
12532 	/* Get a free CT action, if no, a new pool will be created. */
12533 	rte_spinlock_lock(&mng->ct_sl);
12534 	ct = LIST_FIRST(&mng->free_cts);
12535 	if (ct) {
12536 		LIST_REMOVE(ct, next);
12537 	} else if (!flow_dv_ct_pool_create(dev, &ct)) {
12538 		rte_spinlock_unlock(&mng->ct_sl);
12539 		rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
12540 				   NULL, "failed to create ASO CT pool");
12541 		return 0;
12542 	}
12543 	rte_spinlock_unlock(&mng->ct_sl);
12544 	pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]);
12545 	ct_idx = MLX5_MAKE_CT_IDX(pool->index, ct->offset);
12546 	/* 0: inactive, 1: created, 2+: used by flows. */
12547 	__atomic_store_n(&ct->refcnt, 1, __ATOMIC_RELAXED);
12548 	reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, error);
12549 	if (!ct->dr_action_orig) {
12550 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12551 		ct->dr_action_orig = mlx5_glue->dv_create_flow_action_aso
12552 			(priv->sh->rx_domain, pool->devx_obj->obj,
12553 			 ct->offset,
12554 			 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_INITIATOR,
12555 			 reg_c - REG_C_0);
12556 #else
12557 		RTE_SET_USED(reg_c);
12558 #endif
12559 		if (!ct->dr_action_orig) {
12560 			flow_dv_aso_ct_dev_release(dev, ct_idx);
12561 			rte_flow_error_set(error, rte_errno,
12562 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12563 					   "failed to create ASO CT action");
12564 			return 0;
12565 		}
12566 	}
12567 	if (!ct->dr_action_rply) {
12568 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12569 		ct->dr_action_rply = mlx5_glue->dv_create_flow_action_aso
12570 			(priv->sh->rx_domain, pool->devx_obj->obj,
12571 			 ct->offset,
12572 			 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_RESPONDER,
12573 			 reg_c - REG_C_0);
12574 #endif
12575 		if (!ct->dr_action_rply) {
12576 			flow_dv_aso_ct_dev_release(dev, ct_idx);
12577 			rte_flow_error_set(error, rte_errno,
12578 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12579 					   "failed to create ASO CT action");
12580 			return 0;
12581 		}
12582 	}
12583 	return ct_idx;
12584 }
12585 
12586 /*
12587  * Create a conntrack object with context and actions by using ASO mechanism.
12588  *
12589  * @param[in] dev
12590  *   Pointer to rte_eth_dev structure.
12591  * @param[in] pro
12592  *   Pointer to conntrack information profile.
12593  * @param[out] error
12594  *   Pointer to the error structure.
12595  *
12596  * @return
12597  *   Index to conntrack object on success, 0 otherwise.
12598  */
12599 static uint32_t
12600 flow_dv_translate_create_conntrack(struct rte_eth_dev *dev,
12601 				   const struct rte_flow_action_conntrack *pro,
12602 				   struct rte_flow_error *error)
12603 {
12604 	struct mlx5_priv *priv = dev->data->dev_private;
12605 	struct mlx5_dev_ctx_shared *sh = priv->sh;
12606 	struct mlx5_aso_ct_action *ct;
12607 	uint32_t idx;
12608 
12609 	if (!sh->ct_aso_en)
12610 		return rte_flow_error_set(error, ENOTSUP,
12611 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12612 					  "Connection is not supported");
12613 	idx = flow_dv_aso_ct_alloc(dev, error);
12614 	if (!idx)
12615 		return rte_flow_error_set(error, rte_errno,
12616 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12617 					  "Failed to allocate CT object");
12618 	ct = flow_aso_ct_get_by_dev_idx(dev, idx);
12619 	if (mlx5_aso_ct_update_by_wqe(sh, ct, pro))
12620 		return rte_flow_error_set(error, EBUSY,
12621 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12622 					  "Failed to update CT");
12623 	ct->is_original = !!pro->is_original_dir;
12624 	ct->peer = pro->peer_port;
12625 	return idx;
12626 }
12627 
12628 /**
12629  * Fill the flow with DV spec, lock free
12630  * (mutex should be acquired by caller).
12631  *
12632  * @param[in] dev
12633  *   Pointer to rte_eth_dev structure.
12634  * @param[in, out] dev_flow
12635  *   Pointer to the sub flow.
12636  * @param[in] attr
12637  *   Pointer to the flow attributes.
12638  * @param[in] items
12639  *   Pointer to the list of items.
12640  * @param[in] actions
12641  *   Pointer to the list of actions.
12642  * @param[out] error
12643  *   Pointer to the error structure.
12644  *
12645  * @return
12646  *   0 on success, a negative errno value otherwise and rte_errno is set.
12647  */
12648 static int
12649 flow_dv_translate(struct rte_eth_dev *dev,
12650 		  struct mlx5_flow *dev_flow,
12651 		  const struct rte_flow_attr *attr,
12652 		  const struct rte_flow_item items[],
12653 		  const struct rte_flow_action actions[],
12654 		  struct rte_flow_error *error)
12655 {
12656 	struct mlx5_priv *priv = dev->data->dev_private;
12657 	struct mlx5_dev_config *dev_conf = &priv->config;
12658 	struct rte_flow *flow = dev_flow->flow;
12659 	struct mlx5_flow_handle *handle = dev_flow->handle;
12660 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
12661 	struct mlx5_flow_rss_desc *rss_desc;
12662 	uint64_t item_flags = 0;
12663 	uint64_t last_item = 0;
12664 	uint64_t action_flags = 0;
12665 	struct mlx5_flow_dv_matcher matcher = {
12666 		.mask = {
12667 			.size = sizeof(matcher.mask.buf),
12668 		},
12669 	};
12670 	int actions_n = 0;
12671 	bool actions_end = false;
12672 	union {
12673 		struct mlx5_flow_dv_modify_hdr_resource res;
12674 		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
12675 			    sizeof(struct mlx5_modification_cmd) *
12676 			    (MLX5_MAX_MODIFY_NUM + 1)];
12677 	} mhdr_dummy;
12678 	struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
12679 	const struct rte_flow_action_count *count = NULL;
12680 	const struct rte_flow_action_age *non_shared_age = NULL;
12681 	union flow_dv_attr flow_attr = { .attr = 0 };
12682 	uint32_t tag_be;
12683 	union mlx5_flow_tbl_key tbl_key;
12684 	uint32_t modify_action_position = UINT32_MAX;
12685 	void *match_mask = matcher.mask.buf;
12686 	void *match_value = dev_flow->dv.value.buf;
12687 	uint8_t next_protocol = 0xff;
12688 	struct rte_vlan_hdr vlan = { 0 };
12689 	struct mlx5_flow_dv_dest_array_resource mdest_res;
12690 	struct mlx5_flow_dv_sample_resource sample_res;
12691 	void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
12692 	const struct rte_flow_action_sample *sample = NULL;
12693 	struct mlx5_flow_sub_actions_list *sample_act;
12694 	uint32_t sample_act_pos = UINT32_MAX;
12695 	uint32_t age_act_pos = UINT32_MAX;
12696 	uint32_t num_of_dest = 0;
12697 	int tmp_actions_n = 0;
12698 	uint32_t table;
12699 	int ret = 0;
12700 	const struct mlx5_flow_tunnel *tunnel = NULL;
12701 	struct flow_grp_info grp_info = {
12702 		.external = !!dev_flow->external,
12703 		.transfer = !!attr->transfer,
12704 		.fdb_def_rule = !!priv->fdb_def_rule,
12705 		.skip_scale = dev_flow->skip_scale &
12706 			(1 << MLX5_SCALE_FLOW_GROUP_BIT),
12707 		.std_tbl_fix = true,
12708 	};
12709 	const struct rte_flow_item *integrity_items[2] = {NULL, NULL};
12710 	const struct rte_flow_item *tunnel_item = NULL;
12711 
12712 	if (!wks)
12713 		return rte_flow_error_set(error, ENOMEM,
12714 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12715 					  NULL,
12716 					  "failed to push flow workspace");
12717 	rss_desc = &wks->rss_desc;
12718 	memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource));
12719 	memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource));
12720 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
12721 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
12722 	/* update normal path action resource into last index of array */
12723 	sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1];
12724 	if (is_tunnel_offload_active(dev)) {
12725 		if (dev_flow->tunnel) {
12726 			RTE_VERIFY(dev_flow->tof_type ==
12727 				   MLX5_TUNNEL_OFFLOAD_MISS_RULE);
12728 			tunnel = dev_flow->tunnel;
12729 		} else {
12730 			tunnel = mlx5_get_tof(items, actions,
12731 					      &dev_flow->tof_type);
12732 			dev_flow->tunnel = tunnel;
12733 		}
12734 		grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
12735 					(dev, attr, tunnel, dev_flow->tof_type);
12736 	}
12737 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
12738 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
12739 	ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table,
12740 				       &grp_info, error);
12741 	if (ret)
12742 		return ret;
12743 	dev_flow->dv.group = table;
12744 	if (attr->transfer)
12745 		mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
12746 	/* number of actions must be set to 0 in case of dirty stack. */
12747 	mhdr_res->actions_num = 0;
12748 	if (is_flow_tunnel_match_rule(dev_flow->tof_type)) {
12749 		/*
12750 		 * do not add decap action if match rule drops packet
12751 		 * HW rejects rules with decap & drop
12752 		 *
12753 		 * if tunnel match rule was inserted before matching tunnel set
12754 		 * rule flow table used in the match rule must be registered.
12755 		 * current implementation handles that in the
12756 		 * flow_dv_match_register() at the function end.
12757 		 */
12758 		bool add_decap = true;
12759 		const struct rte_flow_action *ptr = actions;
12760 
12761 		for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) {
12762 			if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) {
12763 				add_decap = false;
12764 				break;
12765 			}
12766 		}
12767 		if (add_decap) {
12768 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
12769 							   attr->transfer,
12770 							   error))
12771 				return -rte_errno;
12772 			dev_flow->dv.actions[actions_n++] =
12773 					dev_flow->dv.encap_decap->action;
12774 			action_flags |= MLX5_FLOW_ACTION_DECAP;
12775 		}
12776 	}
12777 	for (; !actions_end ; actions++) {
12778 		const struct rte_flow_action_queue *queue;
12779 		const struct rte_flow_action_rss *rss;
12780 		const struct rte_flow_action *action = actions;
12781 		const uint8_t *rss_key;
12782 		struct mlx5_flow_tbl_resource *tbl;
12783 		struct mlx5_aso_age_action *age_act;
12784 		struct mlx5_flow_counter *cnt_act;
12785 		uint32_t port_id = 0;
12786 		struct mlx5_flow_dv_port_id_action_resource port_id_resource;
12787 		int action_type = actions->type;
12788 		const struct rte_flow_action *found_action = NULL;
12789 		uint32_t jump_group = 0;
12790 		uint32_t owner_idx;
12791 		struct mlx5_aso_ct_action *ct;
12792 
12793 		if (!mlx5_flow_os_action_supported(action_type))
12794 			return rte_flow_error_set(error, ENOTSUP,
12795 						  RTE_FLOW_ERROR_TYPE_ACTION,
12796 						  actions,
12797 						  "action not supported");
12798 		switch (action_type) {
12799 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
12800 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
12801 			break;
12802 		case RTE_FLOW_ACTION_TYPE_VOID:
12803 			break;
12804 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
12805 		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
12806 			if (flow_dv_translate_action_port_id(dev, action,
12807 							     &port_id, error))
12808 				return -rte_errno;
12809 			port_id_resource.port_id = port_id;
12810 			MLX5_ASSERT(!handle->rix_port_id_action);
12811 			if (flow_dv_port_id_action_resource_register
12812 			    (dev, &port_id_resource, dev_flow, error))
12813 				return -rte_errno;
12814 			dev_flow->dv.actions[actions_n++] =
12815 					dev_flow->dv.port_id_action->action;
12816 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
12817 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID;
12818 			sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID;
12819 			num_of_dest++;
12820 			break;
12821 		case RTE_FLOW_ACTION_TYPE_FLAG:
12822 			action_flags |= MLX5_FLOW_ACTION_FLAG;
12823 			dev_flow->handle->mark = 1;
12824 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
12825 				struct rte_flow_action_mark mark = {
12826 					.id = MLX5_FLOW_MARK_DEFAULT,
12827 				};
12828 
12829 				if (flow_dv_convert_action_mark(dev, &mark,
12830 								mhdr_res,
12831 								error))
12832 					return -rte_errno;
12833 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
12834 				break;
12835 			}
12836 			tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
12837 			/*
12838 			 * Only one FLAG or MARK is supported per device flow
12839 			 * right now. So the pointer to the tag resource must be
12840 			 * zero before the register process.
12841 			 */
12842 			MLX5_ASSERT(!handle->dvh.rix_tag);
12843 			if (flow_dv_tag_resource_register(dev, tag_be,
12844 							  dev_flow, error))
12845 				return -rte_errno;
12846 			MLX5_ASSERT(dev_flow->dv.tag_resource);
12847 			dev_flow->dv.actions[actions_n++] =
12848 					dev_flow->dv.tag_resource->action;
12849 			break;
12850 		case RTE_FLOW_ACTION_TYPE_MARK:
12851 			action_flags |= MLX5_FLOW_ACTION_MARK;
12852 			dev_flow->handle->mark = 1;
12853 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
12854 				const struct rte_flow_action_mark *mark =
12855 					(const struct rte_flow_action_mark *)
12856 						actions->conf;
12857 
12858 				if (flow_dv_convert_action_mark(dev, mark,
12859 								mhdr_res,
12860 								error))
12861 					return -rte_errno;
12862 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
12863 				break;
12864 			}
12865 			/* Fall-through */
12866 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
12867 			/* Legacy (non-extensive) MARK action. */
12868 			tag_be = mlx5_flow_mark_set
12869 			      (((const struct rte_flow_action_mark *)
12870 			       (actions->conf))->id);
12871 			MLX5_ASSERT(!handle->dvh.rix_tag);
12872 			if (flow_dv_tag_resource_register(dev, tag_be,
12873 							  dev_flow, error))
12874 				return -rte_errno;
12875 			MLX5_ASSERT(dev_flow->dv.tag_resource);
12876 			dev_flow->dv.actions[actions_n++] =
12877 					dev_flow->dv.tag_resource->action;
12878 			break;
12879 		case RTE_FLOW_ACTION_TYPE_SET_META:
12880 			if (flow_dv_convert_action_set_meta
12881 				(dev, mhdr_res, attr,
12882 				 (const struct rte_flow_action_set_meta *)
12883 				  actions->conf, error))
12884 				return -rte_errno;
12885 			action_flags |= MLX5_FLOW_ACTION_SET_META;
12886 			break;
12887 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
12888 			if (flow_dv_convert_action_set_tag
12889 				(dev, mhdr_res,
12890 				 (const struct rte_flow_action_set_tag *)
12891 				  actions->conf, error))
12892 				return -rte_errno;
12893 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
12894 			break;
12895 		case RTE_FLOW_ACTION_TYPE_DROP:
12896 			action_flags |= MLX5_FLOW_ACTION_DROP;
12897 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
12898 			break;
12899 		case RTE_FLOW_ACTION_TYPE_QUEUE:
12900 			queue = actions->conf;
12901 			rss_desc->queue_num = 1;
12902 			rss_desc->queue[0] = queue->index;
12903 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
12904 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
12905 			sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE;
12906 			num_of_dest++;
12907 			break;
12908 		case RTE_FLOW_ACTION_TYPE_RSS:
12909 			rss = actions->conf;
12910 			memcpy(rss_desc->queue, rss->queue,
12911 			       rss->queue_num * sizeof(uint16_t));
12912 			rss_desc->queue_num = rss->queue_num;
12913 			/* NULL RSS key indicates default RSS key. */
12914 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
12915 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
12916 			/*
12917 			 * rss->level and rss.types should be set in advance
12918 			 * when expanding items for RSS.
12919 			 */
12920 			action_flags |= MLX5_FLOW_ACTION_RSS;
12921 			dev_flow->handle->fate_action = rss_desc->shared_rss ?
12922 				MLX5_FLOW_FATE_SHARED_RSS :
12923 				MLX5_FLOW_FATE_QUEUE;
12924 			break;
12925 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
12926 			owner_idx = (uint32_t)(uintptr_t)action->conf;
12927 			age_act = flow_aso_age_get_by_idx(dev, owner_idx);
12928 			if (flow->age == 0) {
12929 				flow->age = owner_idx;
12930 				__atomic_fetch_add(&age_act->refcnt, 1,
12931 						   __ATOMIC_RELAXED);
12932 			}
12933 			age_act_pos = actions_n++;
12934 			action_flags |= MLX5_FLOW_ACTION_AGE;
12935 			break;
12936 		case RTE_FLOW_ACTION_TYPE_AGE:
12937 			non_shared_age = action->conf;
12938 			age_act_pos = actions_n++;
12939 			action_flags |= MLX5_FLOW_ACTION_AGE;
12940 			break;
12941 		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
12942 			owner_idx = (uint32_t)(uintptr_t)action->conf;
12943 			cnt_act = flow_dv_counter_get_by_idx(dev, owner_idx,
12944 							     NULL);
12945 			MLX5_ASSERT(cnt_act != NULL);
12946 			/**
12947 			 * When creating meter drop flow in drop table, the
12948 			 * counter should not overwrite the rte flow counter.
12949 			 */
12950 			if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
12951 			    dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) {
12952 				dev_flow->dv.actions[actions_n++] =
12953 							cnt_act->action;
12954 			} else {
12955 				if (flow->counter == 0) {
12956 					flow->counter = owner_idx;
12957 					__atomic_fetch_add
12958 						(&cnt_act->shared_info.refcnt,
12959 						 1, __ATOMIC_RELAXED);
12960 				}
12961 				/* Save information first, will apply later. */
12962 				action_flags |= MLX5_FLOW_ACTION_COUNT;
12963 			}
12964 			break;
12965 		case RTE_FLOW_ACTION_TYPE_COUNT:
12966 			if (!priv->sh->devx) {
12967 				return rte_flow_error_set
12968 					      (error, ENOTSUP,
12969 					       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12970 					       NULL,
12971 					       "count action not supported");
12972 			}
12973 			/* Save information first, will apply later. */
12974 			count = action->conf;
12975 			action_flags |= MLX5_FLOW_ACTION_COUNT;
12976 			break;
12977 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
12978 			dev_flow->dv.actions[actions_n++] =
12979 						priv->sh->pop_vlan_action;
12980 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
12981 			break;
12982 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
12983 			if (!(action_flags &
12984 			      MLX5_FLOW_ACTION_OF_SET_VLAN_VID))
12985 				flow_dev_get_vlan_info_from_items(items, &vlan);
12986 			vlan.eth_proto = rte_be_to_cpu_16
12987 			     ((((const struct rte_flow_action_of_push_vlan *)
12988 						   actions->conf)->ethertype));
12989 			found_action = mlx5_flow_find_action
12990 					(actions + 1,
12991 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID);
12992 			if (found_action)
12993 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
12994 			found_action = mlx5_flow_find_action
12995 					(actions + 1,
12996 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP);
12997 			if (found_action)
12998 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
12999 			if (flow_dv_create_action_push_vlan
13000 					    (dev, attr, &vlan, dev_flow, error))
13001 				return -rte_errno;
13002 			dev_flow->dv.actions[actions_n++] =
13003 					dev_flow->dv.push_vlan_res->action;
13004 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
13005 			break;
13006 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
13007 			/* of_vlan_push action handled this action */
13008 			MLX5_ASSERT(action_flags &
13009 				    MLX5_FLOW_ACTION_OF_PUSH_VLAN);
13010 			break;
13011 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
13012 			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
13013 				break;
13014 			flow_dev_get_vlan_info_from_items(items, &vlan);
13015 			mlx5_update_vlan_vid_pcp(actions, &vlan);
13016 			/* If no VLAN push - this is a modify header action */
13017 			if (flow_dv_convert_action_modify_vlan_vid
13018 						(mhdr_res, actions, error))
13019 				return -rte_errno;
13020 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
13021 			break;
13022 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
13023 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
13024 			if (flow_dv_create_action_l2_encap(dev, actions,
13025 							   dev_flow,
13026 							   attr->transfer,
13027 							   error))
13028 				return -rte_errno;
13029 			dev_flow->dv.actions[actions_n++] =
13030 					dev_flow->dv.encap_decap->action;
13031 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
13032 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
13033 				sample_act->action_flags |=
13034 							MLX5_FLOW_ACTION_ENCAP;
13035 			break;
13036 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
13037 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
13038 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
13039 							   attr->transfer,
13040 							   error))
13041 				return -rte_errno;
13042 			dev_flow->dv.actions[actions_n++] =
13043 					dev_flow->dv.encap_decap->action;
13044 			action_flags |= MLX5_FLOW_ACTION_DECAP;
13045 			break;
13046 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
13047 			/* Handle encap with preceding decap. */
13048 			if (action_flags & MLX5_FLOW_ACTION_DECAP) {
13049 				if (flow_dv_create_action_raw_encap
13050 					(dev, actions, dev_flow, attr, error))
13051 					return -rte_errno;
13052 				dev_flow->dv.actions[actions_n++] =
13053 					dev_flow->dv.encap_decap->action;
13054 			} else {
13055 				/* Handle encap without preceding decap. */
13056 				if (flow_dv_create_action_l2_encap
13057 				    (dev, actions, dev_flow, attr->transfer,
13058 				     error))
13059 					return -rte_errno;
13060 				dev_flow->dv.actions[actions_n++] =
13061 					dev_flow->dv.encap_decap->action;
13062 			}
13063 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
13064 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
13065 				sample_act->action_flags |=
13066 							MLX5_FLOW_ACTION_ENCAP;
13067 			break;
13068 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
13069 			while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID)
13070 				;
13071 			if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
13072 				if (flow_dv_create_action_l2_decap
13073 				    (dev, dev_flow, attr->transfer, error))
13074 					return -rte_errno;
13075 				dev_flow->dv.actions[actions_n++] =
13076 					dev_flow->dv.encap_decap->action;
13077 			}
13078 			/* If decap is followed by encap, handle it at encap. */
13079 			action_flags |= MLX5_FLOW_ACTION_DECAP;
13080 			break;
13081 		case MLX5_RTE_FLOW_ACTION_TYPE_JUMP:
13082 			dev_flow->dv.actions[actions_n++] =
13083 				(void *)(uintptr_t)action->conf;
13084 			action_flags |= MLX5_FLOW_ACTION_JUMP;
13085 			break;
13086 		case RTE_FLOW_ACTION_TYPE_JUMP:
13087 			jump_group = ((const struct rte_flow_action_jump *)
13088 							action->conf)->group;
13089 			grp_info.std_tbl_fix = 0;
13090 			if (dev_flow->skip_scale &
13091 				(1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT))
13092 				grp_info.skip_scale = 1;
13093 			else
13094 				grp_info.skip_scale = 0;
13095 			ret = mlx5_flow_group_to_table(dev, tunnel,
13096 						       jump_group,
13097 						       &table,
13098 						       &grp_info, error);
13099 			if (ret)
13100 				return ret;
13101 			tbl = flow_dv_tbl_resource_get(dev, table, attr->egress,
13102 						       attr->transfer,
13103 						       !!dev_flow->external,
13104 						       tunnel, jump_group, 0,
13105 						       0, error);
13106 			if (!tbl)
13107 				return rte_flow_error_set
13108 						(error, errno,
13109 						 RTE_FLOW_ERROR_TYPE_ACTION,
13110 						 NULL,
13111 						 "cannot create jump action.");
13112 			if (flow_dv_jump_tbl_resource_register
13113 			    (dev, tbl, dev_flow, error)) {
13114 				flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
13115 				return rte_flow_error_set
13116 						(error, errno,
13117 						 RTE_FLOW_ERROR_TYPE_ACTION,
13118 						 NULL,
13119 						 "cannot create jump action.");
13120 			}
13121 			dev_flow->dv.actions[actions_n++] =
13122 					dev_flow->dv.jump->action;
13123 			action_flags |= MLX5_FLOW_ACTION_JUMP;
13124 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP;
13125 			sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP;
13126 			num_of_dest++;
13127 			break;
13128 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
13129 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
13130 			if (flow_dv_convert_action_modify_mac
13131 					(mhdr_res, actions, error))
13132 				return -rte_errno;
13133 			action_flags |= actions->type ==
13134 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
13135 					MLX5_FLOW_ACTION_SET_MAC_SRC :
13136 					MLX5_FLOW_ACTION_SET_MAC_DST;
13137 			break;
13138 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
13139 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
13140 			if (flow_dv_convert_action_modify_ipv4
13141 					(mhdr_res, actions, error))
13142 				return -rte_errno;
13143 			action_flags |= actions->type ==
13144 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
13145 					MLX5_FLOW_ACTION_SET_IPV4_SRC :
13146 					MLX5_FLOW_ACTION_SET_IPV4_DST;
13147 			break;
13148 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
13149 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
13150 			if (flow_dv_convert_action_modify_ipv6
13151 					(mhdr_res, actions, error))
13152 				return -rte_errno;
13153 			action_flags |= actions->type ==
13154 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
13155 					MLX5_FLOW_ACTION_SET_IPV6_SRC :
13156 					MLX5_FLOW_ACTION_SET_IPV6_DST;
13157 			break;
13158 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
13159 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
13160 			if (flow_dv_convert_action_modify_tp
13161 					(mhdr_res, actions, items,
13162 					 &flow_attr, dev_flow, !!(action_flags &
13163 					 MLX5_FLOW_ACTION_DECAP), error))
13164 				return -rte_errno;
13165 			action_flags |= actions->type ==
13166 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
13167 					MLX5_FLOW_ACTION_SET_TP_SRC :
13168 					MLX5_FLOW_ACTION_SET_TP_DST;
13169 			break;
13170 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
13171 			if (flow_dv_convert_action_modify_dec_ttl
13172 					(mhdr_res, items, &flow_attr, dev_flow,
13173 					 !!(action_flags &
13174 					 MLX5_FLOW_ACTION_DECAP), error))
13175 				return -rte_errno;
13176 			action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
13177 			break;
13178 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
13179 			if (flow_dv_convert_action_modify_ttl
13180 					(mhdr_res, actions, items, &flow_attr,
13181 					 dev_flow, !!(action_flags &
13182 					 MLX5_FLOW_ACTION_DECAP), error))
13183 				return -rte_errno;
13184 			action_flags |= MLX5_FLOW_ACTION_SET_TTL;
13185 			break;
13186 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
13187 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
13188 			if (flow_dv_convert_action_modify_tcp_seq
13189 					(mhdr_res, actions, error))
13190 				return -rte_errno;
13191 			action_flags |= actions->type ==
13192 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
13193 					MLX5_FLOW_ACTION_INC_TCP_SEQ :
13194 					MLX5_FLOW_ACTION_DEC_TCP_SEQ;
13195 			break;
13196 
13197 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
13198 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
13199 			if (flow_dv_convert_action_modify_tcp_ack
13200 					(mhdr_res, actions, error))
13201 				return -rte_errno;
13202 			action_flags |= actions->type ==
13203 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
13204 					MLX5_FLOW_ACTION_INC_TCP_ACK :
13205 					MLX5_FLOW_ACTION_DEC_TCP_ACK;
13206 			break;
13207 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
13208 			if (flow_dv_convert_action_set_reg
13209 					(mhdr_res, actions, error))
13210 				return -rte_errno;
13211 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
13212 			break;
13213 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
13214 			if (flow_dv_convert_action_copy_mreg
13215 					(dev, mhdr_res, actions, error))
13216 				return -rte_errno;
13217 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
13218 			break;
13219 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
13220 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
13221 			dev_flow->handle->fate_action =
13222 					MLX5_FLOW_FATE_DEFAULT_MISS;
13223 			break;
13224 		case RTE_FLOW_ACTION_TYPE_METER:
13225 			if (!wks->fm)
13226 				return rte_flow_error_set(error, rte_errno,
13227 					RTE_FLOW_ERROR_TYPE_ACTION,
13228 					NULL, "Failed to get meter in flow.");
13229 			/* Set the meter action. */
13230 			dev_flow->dv.actions[actions_n++] =
13231 				wks->fm->meter_action;
13232 			action_flags |= MLX5_FLOW_ACTION_METER;
13233 			break;
13234 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
13235 			if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res,
13236 							      actions, error))
13237 				return -rte_errno;
13238 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
13239 			break;
13240 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
13241 			if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res,
13242 							      actions, error))
13243 				return -rte_errno;
13244 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
13245 			break;
13246 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
13247 			sample_act_pos = actions_n;
13248 			sample = (const struct rte_flow_action_sample *)
13249 				 action->conf;
13250 			actions_n++;
13251 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
13252 			/* put encap action into group if work with port id */
13253 			if ((action_flags & MLX5_FLOW_ACTION_ENCAP) &&
13254 			    (action_flags & MLX5_FLOW_ACTION_PORT_ID))
13255 				sample_act->action_flags |=
13256 							MLX5_FLOW_ACTION_ENCAP;
13257 			break;
13258 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
13259 			if (flow_dv_convert_action_modify_field
13260 					(dev, mhdr_res, actions, attr, error))
13261 				return -rte_errno;
13262 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
13263 			break;
13264 		case RTE_FLOW_ACTION_TYPE_CONNTRACK:
13265 			owner_idx = (uint32_t)(uintptr_t)action->conf;
13266 			ct = flow_aso_ct_get_by_idx(dev, owner_idx);
13267 			if (!ct)
13268 				return rte_flow_error_set(error, EINVAL,
13269 						RTE_FLOW_ERROR_TYPE_ACTION,
13270 						NULL,
13271 						"Failed to get CT object.");
13272 			if (mlx5_aso_ct_available(priv->sh, ct))
13273 				return rte_flow_error_set(error, rte_errno,
13274 						RTE_FLOW_ERROR_TYPE_ACTION,
13275 						NULL,
13276 						"CT is unavailable.");
13277 			if (ct->is_original)
13278 				dev_flow->dv.actions[actions_n] =
13279 							ct->dr_action_orig;
13280 			else
13281 				dev_flow->dv.actions[actions_n] =
13282 							ct->dr_action_rply;
13283 			if (flow->ct == 0) {
13284 				flow->indirect_type =
13285 						MLX5_INDIRECT_ACTION_TYPE_CT;
13286 				flow->ct = owner_idx;
13287 				__atomic_fetch_add(&ct->refcnt, 1,
13288 						   __ATOMIC_RELAXED);
13289 			}
13290 			actions_n++;
13291 			action_flags |= MLX5_FLOW_ACTION_CT;
13292 			break;
13293 		case RTE_FLOW_ACTION_TYPE_END:
13294 			actions_end = true;
13295 			if (mhdr_res->actions_num) {
13296 				/* create modify action if needed. */
13297 				if (flow_dv_modify_hdr_resource_register
13298 					(dev, mhdr_res, dev_flow, error))
13299 					return -rte_errno;
13300 				dev_flow->dv.actions[modify_action_position] =
13301 					handle->dvh.modify_hdr->action;
13302 			}
13303 			/*
13304 			 * Handle AGE and COUNT action by single HW counter
13305 			 * when they are not shared.
13306 			 */
13307 			if (action_flags & MLX5_FLOW_ACTION_AGE) {
13308 				if ((non_shared_age && count) ||
13309 				    !(priv->sh->flow_hit_aso_en &&
13310 				      (attr->group || attr->transfer))) {
13311 					/* Creates age by counters. */
13312 					cnt_act = flow_dv_prepare_counter
13313 								(dev, dev_flow,
13314 								 flow, count,
13315 								 non_shared_age,
13316 								 error);
13317 					if (!cnt_act)
13318 						return -rte_errno;
13319 					dev_flow->dv.actions[age_act_pos] =
13320 								cnt_act->action;
13321 					break;
13322 				}
13323 				if (!flow->age && non_shared_age) {
13324 					flow->age = flow_dv_aso_age_alloc
13325 								(dev, error);
13326 					if (!flow->age)
13327 						return -rte_errno;
13328 					flow_dv_aso_age_params_init
13329 						    (dev, flow->age,
13330 						     non_shared_age->context ?
13331 						     non_shared_age->context :
13332 						     (void *)(uintptr_t)
13333 						     (dev_flow->flow_idx),
13334 						     non_shared_age->timeout);
13335 				}
13336 				age_act = flow_aso_age_get_by_idx(dev,
13337 								  flow->age);
13338 				dev_flow->dv.actions[age_act_pos] =
13339 							     age_act->dr_action;
13340 			}
13341 			if (action_flags & MLX5_FLOW_ACTION_COUNT) {
13342 				/*
13343 				 * Create one count action, to be used
13344 				 * by all sub-flows.
13345 				 */
13346 				cnt_act = flow_dv_prepare_counter(dev, dev_flow,
13347 								  flow, count,
13348 								  NULL, error);
13349 				if (!cnt_act)
13350 					return -rte_errno;
13351 				dev_flow->dv.actions[actions_n++] =
13352 								cnt_act->action;
13353 			}
13354 		default:
13355 			break;
13356 		}
13357 		if (mhdr_res->actions_num &&
13358 		    modify_action_position == UINT32_MAX)
13359 			modify_action_position = actions_n++;
13360 	}
13361 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
13362 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
13363 		int item_type = items->type;
13364 
13365 		if (!mlx5_flow_os_item_supported(item_type))
13366 			return rte_flow_error_set(error, ENOTSUP,
13367 						  RTE_FLOW_ERROR_TYPE_ITEM,
13368 						  NULL, "item not supported");
13369 		switch (item_type) {
13370 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
13371 			flow_dv_translate_item_port_id
13372 				(dev, match_mask, match_value, items, attr);
13373 			last_item = MLX5_FLOW_ITEM_PORT_ID;
13374 			break;
13375 		case RTE_FLOW_ITEM_TYPE_ETH:
13376 			flow_dv_translate_item_eth(match_mask, match_value,
13377 						   items, tunnel,
13378 						   dev_flow->dv.group);
13379 			matcher.priority = action_flags &
13380 					MLX5_FLOW_ACTION_DEFAULT_MISS &&
13381 					!dev_flow->external ?
13382 					MLX5_PRIORITY_MAP_L3 :
13383 					MLX5_PRIORITY_MAP_L2;
13384 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
13385 					     MLX5_FLOW_LAYER_OUTER_L2;
13386 			break;
13387 		case RTE_FLOW_ITEM_TYPE_VLAN:
13388 			flow_dv_translate_item_vlan(dev_flow,
13389 						    match_mask, match_value,
13390 						    items, tunnel,
13391 						    dev_flow->dv.group);
13392 			matcher.priority = MLX5_PRIORITY_MAP_L2;
13393 			last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
13394 					      MLX5_FLOW_LAYER_INNER_VLAN) :
13395 					     (MLX5_FLOW_LAYER_OUTER_L2 |
13396 					      MLX5_FLOW_LAYER_OUTER_VLAN);
13397 			break;
13398 		case RTE_FLOW_ITEM_TYPE_IPV4:
13399 			mlx5_flow_tunnel_ip_check(items, next_protocol,
13400 						  &item_flags, &tunnel);
13401 			flow_dv_translate_item_ipv4(match_mask, match_value,
13402 						    items, tunnel,
13403 						    dev_flow->dv.group);
13404 			matcher.priority = MLX5_PRIORITY_MAP_L3;
13405 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
13406 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
13407 			if (items->mask != NULL &&
13408 			    ((const struct rte_flow_item_ipv4 *)
13409 			     items->mask)->hdr.next_proto_id) {
13410 				next_protocol =
13411 					((const struct rte_flow_item_ipv4 *)
13412 					 (items->spec))->hdr.next_proto_id;
13413 				next_protocol &=
13414 					((const struct rte_flow_item_ipv4 *)
13415 					 (items->mask))->hdr.next_proto_id;
13416 			} else {
13417 				/* Reset for inner layer. */
13418 				next_protocol = 0xff;
13419 			}
13420 			break;
13421 		case RTE_FLOW_ITEM_TYPE_IPV6:
13422 			mlx5_flow_tunnel_ip_check(items, next_protocol,
13423 						  &item_flags, &tunnel);
13424 			flow_dv_translate_item_ipv6(match_mask, match_value,
13425 						    items, tunnel,
13426 						    dev_flow->dv.group);
13427 			matcher.priority = MLX5_PRIORITY_MAP_L3;
13428 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
13429 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
13430 			if (items->mask != NULL &&
13431 			    ((const struct rte_flow_item_ipv6 *)
13432 			     items->mask)->hdr.proto) {
13433 				next_protocol =
13434 					((const struct rte_flow_item_ipv6 *)
13435 					 items->spec)->hdr.proto;
13436 				next_protocol &=
13437 					((const struct rte_flow_item_ipv6 *)
13438 					 items->mask)->hdr.proto;
13439 			} else {
13440 				/* Reset for inner layer. */
13441 				next_protocol = 0xff;
13442 			}
13443 			break;
13444 		case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
13445 			flow_dv_translate_item_ipv6_frag_ext(match_mask,
13446 							     match_value,
13447 							     items, tunnel);
13448 			last_item = tunnel ?
13449 					MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
13450 					MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
13451 			if (items->mask != NULL &&
13452 			    ((const struct rte_flow_item_ipv6_frag_ext *)
13453 			     items->mask)->hdr.next_header) {
13454 				next_protocol =
13455 				((const struct rte_flow_item_ipv6_frag_ext *)
13456 				 items->spec)->hdr.next_header;
13457 				next_protocol &=
13458 				((const struct rte_flow_item_ipv6_frag_ext *)
13459 				 items->mask)->hdr.next_header;
13460 			} else {
13461 				/* Reset for inner layer. */
13462 				next_protocol = 0xff;
13463 			}
13464 			break;
13465 		case RTE_FLOW_ITEM_TYPE_TCP:
13466 			flow_dv_translate_item_tcp(match_mask, match_value,
13467 						   items, tunnel);
13468 			matcher.priority = MLX5_PRIORITY_MAP_L4;
13469 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
13470 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
13471 			break;
13472 		case RTE_FLOW_ITEM_TYPE_UDP:
13473 			flow_dv_translate_item_udp(match_mask, match_value,
13474 						   items, tunnel);
13475 			matcher.priority = MLX5_PRIORITY_MAP_L4;
13476 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
13477 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
13478 			break;
13479 		case RTE_FLOW_ITEM_TYPE_GRE:
13480 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13481 			last_item = MLX5_FLOW_LAYER_GRE;
13482 			tunnel_item = items;
13483 			break;
13484 		case RTE_FLOW_ITEM_TYPE_GRE_KEY:
13485 			flow_dv_translate_item_gre_key(match_mask,
13486 						       match_value, items);
13487 			last_item = MLX5_FLOW_LAYER_GRE_KEY;
13488 			break;
13489 		case RTE_FLOW_ITEM_TYPE_NVGRE:
13490 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13491 			last_item = MLX5_FLOW_LAYER_GRE;
13492 			tunnel_item = items;
13493 			break;
13494 		case RTE_FLOW_ITEM_TYPE_VXLAN:
13495 			flow_dv_translate_item_vxlan(dev, attr,
13496 						     match_mask, match_value,
13497 						     items, tunnel);
13498 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13499 			last_item = MLX5_FLOW_LAYER_VXLAN;
13500 			break;
13501 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
13502 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13503 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
13504 			tunnel_item = items;
13505 			break;
13506 		case RTE_FLOW_ITEM_TYPE_GENEVE:
13507 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13508 			last_item = MLX5_FLOW_LAYER_GENEVE;
13509 			tunnel_item = items;
13510 			break;
13511 		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
13512 			ret = flow_dv_translate_item_geneve_opt(dev, match_mask,
13513 							  match_value,
13514 							  items, error);
13515 			if (ret)
13516 				return rte_flow_error_set(error, -ret,
13517 					RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13518 					"cannot create GENEVE TLV option");
13519 			flow->geneve_tlv_option = 1;
13520 			last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
13521 			break;
13522 		case RTE_FLOW_ITEM_TYPE_MPLS:
13523 			flow_dv_translate_item_mpls(match_mask, match_value,
13524 						    items, last_item, tunnel);
13525 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13526 			last_item = MLX5_FLOW_LAYER_MPLS;
13527 			break;
13528 		case RTE_FLOW_ITEM_TYPE_MARK:
13529 			flow_dv_translate_item_mark(dev, match_mask,
13530 						    match_value, items);
13531 			last_item = MLX5_FLOW_ITEM_MARK;
13532 			break;
13533 		case RTE_FLOW_ITEM_TYPE_META:
13534 			flow_dv_translate_item_meta(dev, match_mask,
13535 						    match_value, attr, items);
13536 			last_item = MLX5_FLOW_ITEM_METADATA;
13537 			break;
13538 		case RTE_FLOW_ITEM_TYPE_ICMP:
13539 			flow_dv_translate_item_icmp(match_mask, match_value,
13540 						    items, tunnel);
13541 			last_item = MLX5_FLOW_LAYER_ICMP;
13542 			break;
13543 		case RTE_FLOW_ITEM_TYPE_ICMP6:
13544 			flow_dv_translate_item_icmp6(match_mask, match_value,
13545 						      items, tunnel);
13546 			last_item = MLX5_FLOW_LAYER_ICMP6;
13547 			break;
13548 		case RTE_FLOW_ITEM_TYPE_TAG:
13549 			flow_dv_translate_item_tag(dev, match_mask,
13550 						   match_value, items);
13551 			last_item = MLX5_FLOW_ITEM_TAG;
13552 			break;
13553 		case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
13554 			flow_dv_translate_mlx5_item_tag(dev, match_mask,
13555 							match_value, items);
13556 			last_item = MLX5_FLOW_ITEM_TAG;
13557 			break;
13558 		case MLX5_RTE_FLOW_ITEM_TYPE_TX_QUEUE:
13559 			flow_dv_translate_item_tx_queue(dev, match_mask,
13560 							match_value,
13561 							items);
13562 			last_item = MLX5_FLOW_ITEM_TX_QUEUE;
13563 			break;
13564 		case RTE_FLOW_ITEM_TYPE_GTP:
13565 			flow_dv_translate_item_gtp(match_mask, match_value,
13566 						   items, tunnel);
13567 			matcher.priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13568 			last_item = MLX5_FLOW_LAYER_GTP;
13569 			break;
13570 		case RTE_FLOW_ITEM_TYPE_GTP_PSC:
13571 			ret = flow_dv_translate_item_gtp_psc(match_mask,
13572 							  match_value,
13573 							  items);
13574 			if (ret)
13575 				return rte_flow_error_set(error, -ret,
13576 					RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13577 					"cannot create GTP PSC item");
13578 			last_item = MLX5_FLOW_LAYER_GTP_PSC;
13579 			break;
13580 		case RTE_FLOW_ITEM_TYPE_ECPRI:
13581 			if (!mlx5_flex_parser_ecpri_exist(dev)) {
13582 				/* Create it only the first time to be used. */
13583 				ret = mlx5_flex_parser_ecpri_alloc(dev);
13584 				if (ret)
13585 					return rte_flow_error_set
13586 						(error, -ret,
13587 						RTE_FLOW_ERROR_TYPE_ITEM,
13588 						NULL,
13589 						"cannot create eCPRI parser");
13590 			}
13591 			flow_dv_translate_item_ecpri(dev, match_mask,
13592 						     match_value, items,
13593 						     last_item);
13594 			/* No other protocol should follow eCPRI layer. */
13595 			last_item = MLX5_FLOW_LAYER_ECPRI;
13596 			break;
13597 		case RTE_FLOW_ITEM_TYPE_INTEGRITY:
13598 			flow_dv_translate_item_integrity(items, integrity_items,
13599 							 &last_item);
13600 			break;
13601 		case RTE_FLOW_ITEM_TYPE_CONNTRACK:
13602 			flow_dv_translate_item_aso_ct(dev, match_mask,
13603 						      match_value, items);
13604 			break;
13605 		case RTE_FLOW_ITEM_TYPE_FLEX:
13606 			flow_dv_translate_item_flex(dev, match_mask,
13607 						    match_value, items,
13608 						    dev_flow, tunnel != 0);
13609 			last_item = tunnel ? MLX5_FLOW_ITEM_INNER_FLEX :
13610 				    MLX5_FLOW_ITEM_OUTER_FLEX;
13611 			break;
13612 		default:
13613 			break;
13614 		}
13615 		item_flags |= last_item;
13616 	}
13617 	/*
13618 	 * When E-Switch mode is enabled, we have two cases where we need to
13619 	 * set the source port manually.
13620 	 * The first one, is in case of Nic steering rule, and the second is
13621 	 * E-Switch rule where no port_id item was found. In both cases
13622 	 * the source port is set according the current port in use.
13623 	 */
13624 	if (!(item_flags & MLX5_FLOW_ITEM_PORT_ID) &&
13625 	    (priv->representor || priv->master)) {
13626 		if (flow_dv_translate_item_port_id(dev, match_mask,
13627 						   match_value, NULL, attr))
13628 			return -rte_errno;
13629 	}
13630 	if (item_flags & MLX5_FLOW_ITEM_INTEGRITY) {
13631 		flow_dv_translate_item_integrity_post(match_mask, match_value,
13632 						      integrity_items,
13633 						      item_flags);
13634 	}
13635 	if (item_flags & MLX5_FLOW_LAYER_VXLAN_GPE)
13636 		flow_dv_translate_item_vxlan_gpe(match_mask, match_value,
13637 						 tunnel_item, item_flags);
13638 	else if (item_flags & MLX5_FLOW_LAYER_GENEVE)
13639 		flow_dv_translate_item_geneve(match_mask, match_value,
13640 					      tunnel_item, item_flags);
13641 	else if (item_flags & MLX5_FLOW_LAYER_GRE) {
13642 		if (tunnel_item->type == RTE_FLOW_ITEM_TYPE_GRE)
13643 			flow_dv_translate_item_gre(match_mask, match_value,
13644 						   tunnel_item, item_flags);
13645 		else if (tunnel_item->type == RTE_FLOW_ITEM_TYPE_NVGRE)
13646 			flow_dv_translate_item_nvgre(match_mask, match_value,
13647 						     tunnel_item, item_flags);
13648 		else
13649 			MLX5_ASSERT(false);
13650 	}
13651 #ifdef RTE_LIBRTE_MLX5_DEBUG
13652 	MLX5_ASSERT(!flow_dv_check_valid_spec(matcher.mask.buf,
13653 					      dev_flow->dv.value.buf));
13654 #endif
13655 	/*
13656 	 * Layers may be already initialized from prefix flow if this dev_flow
13657 	 * is the suffix flow.
13658 	 */
13659 	handle->layers |= item_flags;
13660 	if (action_flags & MLX5_FLOW_ACTION_RSS)
13661 		flow_dv_hashfields_set(dev_flow, rss_desc);
13662 	/* If has RSS action in the sample action, the Sample/Mirror resource
13663 	 * should be registered after the hash filed be update.
13664 	 */
13665 	if (action_flags & MLX5_FLOW_ACTION_SAMPLE) {
13666 		ret = flow_dv_translate_action_sample(dev,
13667 						      sample,
13668 						      dev_flow, attr,
13669 						      &num_of_dest,
13670 						      sample_actions,
13671 						      &sample_res,
13672 						      error);
13673 		if (ret < 0)
13674 			return ret;
13675 		ret = flow_dv_create_action_sample(dev,
13676 						   dev_flow,
13677 						   num_of_dest,
13678 						   &sample_res,
13679 						   &mdest_res,
13680 						   sample_actions,
13681 						   action_flags,
13682 						   error);
13683 		if (ret < 0)
13684 			return rte_flow_error_set
13685 						(error, rte_errno,
13686 						RTE_FLOW_ERROR_TYPE_ACTION,
13687 						NULL,
13688 						"cannot create sample action");
13689 		if (num_of_dest > 1) {
13690 			dev_flow->dv.actions[sample_act_pos] =
13691 			dev_flow->dv.dest_array_res->action;
13692 		} else {
13693 			dev_flow->dv.actions[sample_act_pos] =
13694 			dev_flow->dv.sample_res->verbs_action;
13695 		}
13696 	}
13697 	/*
13698 	 * For multiple destination (sample action with ratio=1), the encap
13699 	 * action and port id action will be combined into group action.
13700 	 * So need remove the original these actions in the flow and only
13701 	 * use the sample action instead of.
13702 	 */
13703 	if (num_of_dest > 1 &&
13704 	    (sample_act->dr_port_id_action || sample_act->dr_jump_action)) {
13705 		int i;
13706 		void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
13707 
13708 		for (i = 0; i < actions_n; i++) {
13709 			if ((sample_act->dr_encap_action &&
13710 				sample_act->dr_encap_action ==
13711 				dev_flow->dv.actions[i]) ||
13712 				(sample_act->dr_port_id_action &&
13713 				sample_act->dr_port_id_action ==
13714 				dev_flow->dv.actions[i]) ||
13715 				(sample_act->dr_jump_action &&
13716 				sample_act->dr_jump_action ==
13717 				dev_flow->dv.actions[i]))
13718 				continue;
13719 			temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];
13720 		}
13721 		memcpy((void *)dev_flow->dv.actions,
13722 				(void *)temp_actions,
13723 				tmp_actions_n * sizeof(void *));
13724 		actions_n = tmp_actions_n;
13725 	}
13726 	dev_flow->dv.actions_n = actions_n;
13727 	dev_flow->act_flags = action_flags;
13728 	if (wks->skip_matcher_reg)
13729 		return 0;
13730 	/* Register matcher. */
13731 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
13732 				    matcher.mask.size);
13733 	matcher.priority = mlx5_get_matcher_priority(dev, attr,
13734 						     matcher.priority,
13735 						     dev_flow->external);
13736 	/**
13737 	 * When creating meter drop flow in drop table, using original
13738 	 * 5-tuple match, the matcher priority should be lower than
13739 	 * mtr_id matcher.
13740 	 */
13741 	if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
13742 	    dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP &&
13743 	    matcher.priority <= MLX5_REG_BITS)
13744 		matcher.priority += MLX5_REG_BITS;
13745 	/* reserved field no needs to be set to 0 here. */
13746 	tbl_key.is_fdb = attr->transfer;
13747 	tbl_key.is_egress = attr->egress;
13748 	tbl_key.level = dev_flow->dv.group;
13749 	tbl_key.id = dev_flow->dv.table_id;
13750 	if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow,
13751 				     tunnel, attr->group, error))
13752 		return -rte_errno;
13753 	return 0;
13754 }
13755 
13756 /**
13757  * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields)
13758  * and tunnel.
13759  *
13760  * @param[in, out] action
13761  *   Shred RSS action holding hash RX queue objects.
13762  * @param[in] hash_fields
13763  *   Defines combination of packet fields to participate in RX hash.
13764  * @param[in] tunnel
13765  *   Tunnel type
13766  * @param[in] hrxq_idx
13767  *   Hash RX queue index to set.
13768  *
13769  * @return
13770  *   0 on success, otherwise negative errno value.
13771  */
13772 static int
13773 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action,
13774 			      const uint64_t hash_fields,
13775 			      uint32_t hrxq_idx)
13776 {
13777 	uint32_t *hrxqs = action->hrxq;
13778 
13779 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
13780 	case MLX5_RSS_HASH_IPV4:
13781 		/* fall-through. */
13782 	case MLX5_RSS_HASH_IPV4_DST_ONLY:
13783 		/* fall-through. */
13784 	case MLX5_RSS_HASH_IPV4_SRC_ONLY:
13785 		hrxqs[0] = hrxq_idx;
13786 		return 0;
13787 	case MLX5_RSS_HASH_IPV4_TCP:
13788 		/* fall-through. */
13789 	case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY:
13790 		/* fall-through. */
13791 	case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY:
13792 		hrxqs[1] = hrxq_idx;
13793 		return 0;
13794 	case MLX5_RSS_HASH_IPV4_UDP:
13795 		/* fall-through. */
13796 	case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
13797 		/* fall-through. */
13798 	case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
13799 		hrxqs[2] = hrxq_idx;
13800 		return 0;
13801 	case MLX5_RSS_HASH_IPV6:
13802 		/* fall-through. */
13803 	case MLX5_RSS_HASH_IPV6_DST_ONLY:
13804 		/* fall-through. */
13805 	case MLX5_RSS_HASH_IPV6_SRC_ONLY:
13806 		hrxqs[3] = hrxq_idx;
13807 		return 0;
13808 	case MLX5_RSS_HASH_IPV6_TCP:
13809 		/* fall-through. */
13810 	case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
13811 		/* fall-through. */
13812 	case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
13813 		hrxqs[4] = hrxq_idx;
13814 		return 0;
13815 	case MLX5_RSS_HASH_IPV6_UDP:
13816 		/* fall-through. */
13817 	case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
13818 		/* fall-through. */
13819 	case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
13820 		hrxqs[5] = hrxq_idx;
13821 		return 0;
13822 	case MLX5_RSS_HASH_NONE:
13823 		hrxqs[6] = hrxq_idx;
13824 		return 0;
13825 	default:
13826 		return -1;
13827 	}
13828 }
13829 
13830 /**
13831  * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields)
13832  * and tunnel.
13833  *
13834  * @param[in] dev
13835  *   Pointer to the Ethernet device structure.
13836  * @param[in] idx
13837  *   Shared RSS action ID holding hash RX queue objects.
13838  * @param[in] hash_fields
13839  *   Defines combination of packet fields to participate in RX hash.
13840  * @param[in] tunnel
13841  *   Tunnel type
13842  *
13843  * @return
13844  *   Valid hash RX queue index, otherwise 0.
13845  */
13846 static uint32_t
13847 __flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx,
13848 				 const uint64_t hash_fields)
13849 {
13850 	struct mlx5_priv *priv = dev->data->dev_private;
13851 	struct mlx5_shared_action_rss *shared_rss =
13852 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
13853 	const uint32_t *hrxqs = shared_rss->hrxq;
13854 
13855 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
13856 	case MLX5_RSS_HASH_IPV4:
13857 		/* fall-through. */
13858 	case MLX5_RSS_HASH_IPV4_DST_ONLY:
13859 		/* fall-through. */
13860 	case MLX5_RSS_HASH_IPV4_SRC_ONLY:
13861 		return hrxqs[0];
13862 	case MLX5_RSS_HASH_IPV4_TCP:
13863 		/* fall-through. */
13864 	case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY:
13865 		/* fall-through. */
13866 	case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY:
13867 		return hrxqs[1];
13868 	case MLX5_RSS_HASH_IPV4_UDP:
13869 		/* fall-through. */
13870 	case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
13871 		/* fall-through. */
13872 	case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
13873 		return hrxqs[2];
13874 	case MLX5_RSS_HASH_IPV6:
13875 		/* fall-through. */
13876 	case MLX5_RSS_HASH_IPV6_DST_ONLY:
13877 		/* fall-through. */
13878 	case MLX5_RSS_HASH_IPV6_SRC_ONLY:
13879 		return hrxqs[3];
13880 	case MLX5_RSS_HASH_IPV6_TCP:
13881 		/* fall-through. */
13882 	case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
13883 		/* fall-through. */
13884 	case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
13885 		return hrxqs[4];
13886 	case MLX5_RSS_HASH_IPV6_UDP:
13887 		/* fall-through. */
13888 	case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
13889 		/* fall-through. */
13890 	case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
13891 		return hrxqs[5];
13892 	case MLX5_RSS_HASH_NONE:
13893 		return hrxqs[6];
13894 	default:
13895 		return 0;
13896 	}
13897 
13898 }
13899 
13900 /**
13901  * Apply the flow to the NIC, lock free,
13902  * (mutex should be acquired by caller).
13903  *
13904  * @param[in] dev
13905  *   Pointer to the Ethernet device structure.
13906  * @param[in, out] flow
13907  *   Pointer to flow structure.
13908  * @param[out] error
13909  *   Pointer to error structure.
13910  *
13911  * @return
13912  *   0 on success, a negative errno value otherwise and rte_errno is set.
13913  */
13914 static int
13915 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
13916 	      struct rte_flow_error *error)
13917 {
13918 	struct mlx5_flow_dv_workspace *dv;
13919 	struct mlx5_flow_handle *dh;
13920 	struct mlx5_flow_handle_dv *dv_h;
13921 	struct mlx5_flow *dev_flow;
13922 	struct mlx5_priv *priv = dev->data->dev_private;
13923 	uint32_t handle_idx;
13924 	int n;
13925 	int err;
13926 	int idx;
13927 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
13928 	struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc;
13929 	uint8_t misc_mask;
13930 
13931 	MLX5_ASSERT(wks);
13932 	for (idx = wks->flow_idx - 1; idx >= 0; idx--) {
13933 		dev_flow = &wks->flows[idx];
13934 		dv = &dev_flow->dv;
13935 		dh = dev_flow->handle;
13936 		dv_h = &dh->dvh;
13937 		n = dv->actions_n;
13938 		if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
13939 			if (dv->transfer) {
13940 				MLX5_ASSERT(priv->sh->dr_drop_action);
13941 				dv->actions[n++] = priv->sh->dr_drop_action;
13942 			} else {
13943 #ifdef HAVE_MLX5DV_DR
13944 				/* DR supports drop action placeholder. */
13945 				MLX5_ASSERT(priv->sh->dr_drop_action);
13946 				dv->actions[n++] = dv->group ?
13947 					priv->sh->dr_drop_action :
13948 					priv->root_drop_action;
13949 #else
13950 				/* For DV we use the explicit drop queue. */
13951 				MLX5_ASSERT(priv->drop_queue.hrxq);
13952 				dv->actions[n++] =
13953 						priv->drop_queue.hrxq->action;
13954 #endif
13955 			}
13956 		} else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE &&
13957 			   !dv_h->rix_sample && !dv_h->rix_dest_array)) {
13958 			struct mlx5_hrxq *hrxq;
13959 			uint32_t hrxq_idx;
13960 
13961 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc,
13962 						    &hrxq_idx);
13963 			if (!hrxq) {
13964 				rte_flow_error_set
13965 					(error, rte_errno,
13966 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13967 					 "cannot get hash queue");
13968 				goto error;
13969 			}
13970 			dh->rix_hrxq = hrxq_idx;
13971 			dv->actions[n++] = hrxq->action;
13972 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
13973 			struct mlx5_hrxq *hrxq = NULL;
13974 			uint32_t hrxq_idx;
13975 
13976 			hrxq_idx = __flow_dv_action_rss_hrxq_lookup(dev,
13977 						rss_desc->shared_rss,
13978 						dev_flow->hash_fields);
13979 			if (hrxq_idx)
13980 				hrxq = mlx5_ipool_get
13981 					(priv->sh->ipool[MLX5_IPOOL_HRXQ],
13982 					 hrxq_idx);
13983 			if (!hrxq) {
13984 				rte_flow_error_set
13985 					(error, rte_errno,
13986 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13987 					 "cannot get hash queue");
13988 				goto error;
13989 			}
13990 			dh->rix_srss = rss_desc->shared_rss;
13991 			dv->actions[n++] = hrxq->action;
13992 		} else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) {
13993 			if (!priv->sh->default_miss_action) {
13994 				rte_flow_error_set
13995 					(error, rte_errno,
13996 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
13997 					 "default miss action not be created.");
13998 				goto error;
13999 			}
14000 			dv->actions[n++] = priv->sh->default_miss_action;
14001 		}
14002 		misc_mask = flow_dv_matcher_enable(dv->value.buf);
14003 		__flow_dv_adjust_buf_size(&dv->value.size, misc_mask);
14004 		err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object,
14005 					       (void *)&dv->value, n,
14006 					       dv->actions, &dh->drv_flow);
14007 		if (err) {
14008 			rte_flow_error_set
14009 				(error, errno,
14010 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14011 				NULL,
14012 				(!priv->config.allow_duplicate_pattern &&
14013 				errno == EEXIST) ?
14014 				"duplicating pattern is not allowed" :
14015 				"hardware refuses to create flow");
14016 			goto error;
14017 		}
14018 		if (priv->vmwa_context &&
14019 		    dh->vf_vlan.tag && !dh->vf_vlan.created) {
14020 			/*
14021 			 * The rule contains the VLAN pattern.
14022 			 * For VF we are going to create VLAN
14023 			 * interface to make hypervisor set correct
14024 			 * e-Switch vport context.
14025 			 */
14026 			mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan);
14027 		}
14028 	}
14029 	return 0;
14030 error:
14031 	err = rte_errno; /* Save rte_errno before cleanup. */
14032 	SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
14033 		       handle_idx, dh, next) {
14034 		/* hrxq is union, don't clear it if the flag is not set. */
14035 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) {
14036 			mlx5_hrxq_release(dev, dh->rix_hrxq);
14037 			dh->rix_hrxq = 0;
14038 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
14039 			dh->rix_srss = 0;
14040 		}
14041 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
14042 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
14043 	}
14044 	rte_errno = err; /* Restore rte_errno. */
14045 	return -rte_errno;
14046 }
14047 
14048 void
14049 flow_dv_matcher_remove_cb(void *tool_ctx __rte_unused,
14050 			  struct mlx5_list_entry *entry)
14051 {
14052 	struct mlx5_flow_dv_matcher *resource = container_of(entry,
14053 							     typeof(*resource),
14054 							     entry);
14055 
14056 	claim_zero(mlx5_flow_os_destroy_flow_matcher(resource->matcher_object));
14057 	mlx5_free(resource);
14058 }
14059 
14060 /**
14061  * Release the flow matcher.
14062  *
14063  * @param dev
14064  *   Pointer to Ethernet device.
14065  * @param port_id
14066  *   Index to port ID action resource.
14067  *
14068  * @return
14069  *   1 while a reference on it exists, 0 when freed.
14070  */
14071 static int
14072 flow_dv_matcher_release(struct rte_eth_dev *dev,
14073 			struct mlx5_flow_handle *handle)
14074 {
14075 	struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher;
14076 	struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl,
14077 							    typeof(*tbl), tbl);
14078 	int ret;
14079 
14080 	MLX5_ASSERT(matcher->matcher_object);
14081 	ret = mlx5_list_unregister(tbl->matchers, &matcher->entry);
14082 	flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl);
14083 	return ret;
14084 }
14085 
14086 void
14087 flow_dv_encap_decap_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14088 {
14089 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14090 	struct mlx5_flow_dv_encap_decap_resource *res =
14091 				       container_of(entry, typeof(*res), entry);
14092 
14093 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
14094 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
14095 }
14096 
14097 /**
14098  * Release an encap/decap resource.
14099  *
14100  * @param dev
14101  *   Pointer to Ethernet device.
14102  * @param encap_decap_idx
14103  *   Index of encap decap resource.
14104  *
14105  * @return
14106  *   1 while a reference on it exists, 0 when freed.
14107  */
14108 static int
14109 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
14110 				     uint32_t encap_decap_idx)
14111 {
14112 	struct mlx5_priv *priv = dev->data->dev_private;
14113 	struct mlx5_flow_dv_encap_decap_resource *resource;
14114 
14115 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
14116 				  encap_decap_idx);
14117 	if (!resource)
14118 		return 0;
14119 	MLX5_ASSERT(resource->action);
14120 	return mlx5_hlist_unregister(priv->sh->encaps_decaps, &resource->entry);
14121 }
14122 
14123 /**
14124  * Release an jump to table action resource.
14125  *
14126  * @param dev
14127  *   Pointer to Ethernet device.
14128  * @param rix_jump
14129  *   Index to the jump action resource.
14130  *
14131  * @return
14132  *   1 while a reference on it exists, 0 when freed.
14133  */
14134 static int
14135 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
14136 				  uint32_t rix_jump)
14137 {
14138 	struct mlx5_priv *priv = dev->data->dev_private;
14139 	struct mlx5_flow_tbl_data_entry *tbl_data;
14140 
14141 	tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP],
14142 				  rix_jump);
14143 	if (!tbl_data)
14144 		return 0;
14145 	return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl);
14146 }
14147 
14148 void
14149 flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14150 {
14151 	struct mlx5_flow_dv_modify_hdr_resource *res =
14152 		container_of(entry, typeof(*res), entry);
14153 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14154 
14155 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
14156 	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
14157 }
14158 
14159 /**
14160  * Release a modify-header resource.
14161  *
14162  * @param dev
14163  *   Pointer to Ethernet device.
14164  * @param handle
14165  *   Pointer to mlx5_flow_handle.
14166  *
14167  * @return
14168  *   1 while a reference on it exists, 0 when freed.
14169  */
14170 static int
14171 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev,
14172 				    struct mlx5_flow_handle *handle)
14173 {
14174 	struct mlx5_priv *priv = dev->data->dev_private;
14175 	struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr;
14176 
14177 	MLX5_ASSERT(entry->action);
14178 	return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry);
14179 }
14180 
14181 void
14182 flow_dv_port_id_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14183 {
14184 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14185 	struct mlx5_flow_dv_port_id_action_resource *resource =
14186 				  container_of(entry, typeof(*resource), entry);
14187 
14188 	claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14189 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
14190 }
14191 
14192 /**
14193  * Release port ID action resource.
14194  *
14195  * @param dev
14196  *   Pointer to Ethernet device.
14197  * @param handle
14198  *   Pointer to mlx5_flow_handle.
14199  *
14200  * @return
14201  *   1 while a reference on it exists, 0 when freed.
14202  */
14203 static int
14204 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
14205 					uint32_t port_id)
14206 {
14207 	struct mlx5_priv *priv = dev->data->dev_private;
14208 	struct mlx5_flow_dv_port_id_action_resource *resource;
14209 
14210 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id);
14211 	if (!resource)
14212 		return 0;
14213 	MLX5_ASSERT(resource->action);
14214 	return mlx5_list_unregister(priv->sh->port_id_action_list,
14215 				    &resource->entry);
14216 }
14217 
14218 /**
14219  * Release shared RSS action resource.
14220  *
14221  * @param dev
14222  *   Pointer to Ethernet device.
14223  * @param srss
14224  *   Shared RSS action index.
14225  */
14226 static void
14227 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss)
14228 {
14229 	struct mlx5_priv *priv = dev->data->dev_private;
14230 	struct mlx5_shared_action_rss *shared_rss;
14231 
14232 	shared_rss = mlx5_ipool_get
14233 			(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss);
14234 	__atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
14235 }
14236 
14237 void
14238 flow_dv_push_vlan_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14239 {
14240 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14241 	struct mlx5_flow_dv_push_vlan_action_resource *resource =
14242 			container_of(entry, typeof(*resource), entry);
14243 
14244 	claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14245 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
14246 }
14247 
14248 /**
14249  * Release push vlan action resource.
14250  *
14251  * @param dev
14252  *   Pointer to Ethernet device.
14253  * @param handle
14254  *   Pointer to mlx5_flow_handle.
14255  *
14256  * @return
14257  *   1 while a reference on it exists, 0 when freed.
14258  */
14259 static int
14260 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev,
14261 					  struct mlx5_flow_handle *handle)
14262 {
14263 	struct mlx5_priv *priv = dev->data->dev_private;
14264 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
14265 	uint32_t idx = handle->dvh.rix_push_vlan;
14266 
14267 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
14268 	if (!resource)
14269 		return 0;
14270 	MLX5_ASSERT(resource->action);
14271 	return mlx5_list_unregister(priv->sh->push_vlan_action_list,
14272 				    &resource->entry);
14273 }
14274 
14275 /**
14276  * Release the fate resource.
14277  *
14278  * @param dev
14279  *   Pointer to Ethernet device.
14280  * @param handle
14281  *   Pointer to mlx5_flow_handle.
14282  */
14283 static void
14284 flow_dv_fate_resource_release(struct rte_eth_dev *dev,
14285 			       struct mlx5_flow_handle *handle)
14286 {
14287 	if (!handle->rix_fate)
14288 		return;
14289 	switch (handle->fate_action) {
14290 	case MLX5_FLOW_FATE_QUEUE:
14291 		if (!handle->dvh.rix_sample && !handle->dvh.rix_dest_array)
14292 			mlx5_hrxq_release(dev, handle->rix_hrxq);
14293 		break;
14294 	case MLX5_FLOW_FATE_JUMP:
14295 		flow_dv_jump_tbl_resource_release(dev, handle->rix_jump);
14296 		break;
14297 	case MLX5_FLOW_FATE_PORT_ID:
14298 		flow_dv_port_id_action_resource_release(dev,
14299 				handle->rix_port_id_action);
14300 		break;
14301 	default:
14302 		DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action);
14303 		break;
14304 	}
14305 	handle->rix_fate = 0;
14306 }
14307 
14308 void
14309 flow_dv_sample_remove_cb(void *tool_ctx __rte_unused,
14310 			 struct mlx5_list_entry *entry)
14311 {
14312 	struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
14313 							      typeof(*resource),
14314 							      entry);
14315 	struct rte_eth_dev *dev = resource->dev;
14316 	struct mlx5_priv *priv = dev->data->dev_private;
14317 
14318 	if (resource->verbs_action)
14319 		claim_zero(mlx5_flow_os_destroy_flow_action
14320 						      (resource->verbs_action));
14321 	if (resource->normal_path_tbl)
14322 		flow_dv_tbl_resource_release(MLX5_SH(dev),
14323 					     resource->normal_path_tbl);
14324 	flow_dv_sample_sub_actions_release(dev, &resource->sample_idx);
14325 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
14326 	DRV_LOG(DEBUG, "sample resource %p: removed", (void *)resource);
14327 }
14328 
14329 /**
14330  * Release an sample resource.
14331  *
14332  * @param dev
14333  *   Pointer to Ethernet device.
14334  * @param handle
14335  *   Pointer to mlx5_flow_handle.
14336  *
14337  * @return
14338  *   1 while a reference on it exists, 0 when freed.
14339  */
14340 static int
14341 flow_dv_sample_resource_release(struct rte_eth_dev *dev,
14342 				     struct mlx5_flow_handle *handle)
14343 {
14344 	struct mlx5_priv *priv = dev->data->dev_private;
14345 	struct mlx5_flow_dv_sample_resource *resource;
14346 
14347 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE],
14348 				  handle->dvh.rix_sample);
14349 	if (!resource)
14350 		return 0;
14351 	MLX5_ASSERT(resource->verbs_action);
14352 	return mlx5_list_unregister(priv->sh->sample_action_list,
14353 				    &resource->entry);
14354 }
14355 
14356 void
14357 flow_dv_dest_array_remove_cb(void *tool_ctx __rte_unused,
14358 			     struct mlx5_list_entry *entry)
14359 {
14360 	struct mlx5_flow_dv_dest_array_resource *resource =
14361 			container_of(entry, typeof(*resource), entry);
14362 	struct rte_eth_dev *dev = resource->dev;
14363 	struct mlx5_priv *priv = dev->data->dev_private;
14364 	uint32_t i = 0;
14365 
14366 	MLX5_ASSERT(resource->action);
14367 	if (resource->action)
14368 		claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
14369 	for (; i < resource->num_of_dest; i++)
14370 		flow_dv_sample_sub_actions_release(dev,
14371 						   &resource->sample_idx[i]);
14372 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
14373 	DRV_LOG(DEBUG, "destination array resource %p: removed",
14374 		(void *)resource);
14375 }
14376 
14377 /**
14378  * Release an destination array resource.
14379  *
14380  * @param dev
14381  *   Pointer to Ethernet device.
14382  * @param handle
14383  *   Pointer to mlx5_flow_handle.
14384  *
14385  * @return
14386  *   1 while a reference on it exists, 0 when freed.
14387  */
14388 static int
14389 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev,
14390 				    struct mlx5_flow_handle *handle)
14391 {
14392 	struct mlx5_priv *priv = dev->data->dev_private;
14393 	struct mlx5_flow_dv_dest_array_resource *resource;
14394 
14395 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY],
14396 				  handle->dvh.rix_dest_array);
14397 	if (!resource)
14398 		return 0;
14399 	MLX5_ASSERT(resource->action);
14400 	return mlx5_list_unregister(priv->sh->dest_array_list,
14401 				    &resource->entry);
14402 }
14403 
14404 static void
14405 flow_dv_geneve_tlv_option_resource_release(struct rte_eth_dev *dev)
14406 {
14407 	struct mlx5_priv *priv = dev->data->dev_private;
14408 	struct mlx5_dev_ctx_shared *sh = priv->sh;
14409 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
14410 				sh->geneve_tlv_option_resource;
14411 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
14412 	if (geneve_opt_resource) {
14413 		if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1,
14414 					 __ATOMIC_RELAXED))) {
14415 			claim_zero(mlx5_devx_cmd_destroy
14416 					(geneve_opt_resource->obj));
14417 			mlx5_free(sh->geneve_tlv_option_resource);
14418 			sh->geneve_tlv_option_resource = NULL;
14419 		}
14420 	}
14421 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
14422 }
14423 
14424 /**
14425  * Remove the flow from the NIC but keeps it in memory.
14426  * Lock free, (mutex should be acquired by caller).
14427  *
14428  * @param[in] dev
14429  *   Pointer to Ethernet device.
14430  * @param[in, out] flow
14431  *   Pointer to flow structure.
14432  */
14433 static void
14434 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
14435 {
14436 	struct mlx5_flow_handle *dh;
14437 	uint32_t handle_idx;
14438 	struct mlx5_priv *priv = dev->data->dev_private;
14439 
14440 	if (!flow)
14441 		return;
14442 	handle_idx = flow->dev_handles;
14443 	while (handle_idx) {
14444 		dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
14445 				    handle_idx);
14446 		if (!dh)
14447 			return;
14448 		if (dh->drv_flow) {
14449 			claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow));
14450 			dh->drv_flow = NULL;
14451 		}
14452 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE)
14453 			flow_dv_fate_resource_release(dev, dh);
14454 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
14455 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
14456 		handle_idx = dh->next.next;
14457 	}
14458 }
14459 
14460 /**
14461  * Remove the flow from the NIC and the memory.
14462  * Lock free, (mutex should be acquired by caller).
14463  *
14464  * @param[in] dev
14465  *   Pointer to the Ethernet device structure.
14466  * @param[in, out] flow
14467  *   Pointer to flow structure.
14468  */
14469 static void
14470 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
14471 {
14472 	struct mlx5_flow_handle *dev_handle;
14473 	struct mlx5_priv *priv = dev->data->dev_private;
14474 	struct mlx5_flow_meter_info *fm = NULL;
14475 	uint32_t srss = 0;
14476 
14477 	if (!flow)
14478 		return;
14479 	flow_dv_remove(dev, flow);
14480 	if (flow->counter) {
14481 		flow_dv_counter_free(dev, flow->counter);
14482 		flow->counter = 0;
14483 	}
14484 	if (flow->meter) {
14485 		fm = flow_dv_meter_find_by_idx(priv, flow->meter);
14486 		if (fm)
14487 			mlx5_flow_meter_detach(priv, fm);
14488 		flow->meter = 0;
14489 	}
14490 	/* Keep the current age handling by default. */
14491 	if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct)
14492 		flow_dv_aso_ct_release(dev, flow->ct, NULL);
14493 	else if (flow->age)
14494 		flow_dv_aso_age_release(dev, flow->age);
14495 	if (flow->geneve_tlv_option) {
14496 		flow_dv_geneve_tlv_option_resource_release(dev);
14497 		flow->geneve_tlv_option = 0;
14498 	}
14499 	while (flow->dev_handles) {
14500 		uint32_t tmp_idx = flow->dev_handles;
14501 
14502 		dev_handle = mlx5_ipool_get(priv->sh->ipool
14503 					    [MLX5_IPOOL_MLX5_FLOW], tmp_idx);
14504 		if (!dev_handle)
14505 			return;
14506 		flow->dev_handles = dev_handle->next.next;
14507 		while (dev_handle->flex_item) {
14508 			int index = rte_bsf32(dev_handle->flex_item);
14509 
14510 			mlx5_flex_release_index(dev, index);
14511 			dev_handle->flex_item &= ~RTE_BIT32(index);
14512 		}
14513 		if (dev_handle->dvh.matcher)
14514 			flow_dv_matcher_release(dev, dev_handle);
14515 		if (dev_handle->dvh.rix_sample)
14516 			flow_dv_sample_resource_release(dev, dev_handle);
14517 		if (dev_handle->dvh.rix_dest_array)
14518 			flow_dv_dest_array_resource_release(dev, dev_handle);
14519 		if (dev_handle->dvh.rix_encap_decap)
14520 			flow_dv_encap_decap_resource_release(dev,
14521 				dev_handle->dvh.rix_encap_decap);
14522 		if (dev_handle->dvh.modify_hdr)
14523 			flow_dv_modify_hdr_resource_release(dev, dev_handle);
14524 		if (dev_handle->dvh.rix_push_vlan)
14525 			flow_dv_push_vlan_action_resource_release(dev,
14526 								  dev_handle);
14527 		if (dev_handle->dvh.rix_tag)
14528 			flow_dv_tag_release(dev,
14529 					    dev_handle->dvh.rix_tag);
14530 		if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS)
14531 			flow_dv_fate_resource_release(dev, dev_handle);
14532 		else if (!srss)
14533 			srss = dev_handle->rix_srss;
14534 		if (fm && dev_handle->is_meter_flow_id &&
14535 		    dev_handle->split_flow_id)
14536 			mlx5_ipool_free(fm->flow_ipool,
14537 					dev_handle->split_flow_id);
14538 		else if (dev_handle->split_flow_id &&
14539 		    !dev_handle->is_meter_flow_id)
14540 			mlx5_ipool_free(priv->sh->ipool
14541 					[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID],
14542 					dev_handle->split_flow_id);
14543 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
14544 			   tmp_idx);
14545 	}
14546 	if (srss)
14547 		flow_dv_shared_rss_action_release(dev, srss);
14548 }
14549 
14550 /**
14551  * Release array of hash RX queue objects.
14552  * Helper function.
14553  *
14554  * @param[in] dev
14555  *   Pointer to the Ethernet device structure.
14556  * @param[in, out] hrxqs
14557  *   Array of hash RX queue objects.
14558  *
14559  * @return
14560  *   Total number of references to hash RX queue objects in *hrxqs* array
14561  *   after this operation.
14562  */
14563 static int
14564 __flow_dv_hrxqs_release(struct rte_eth_dev *dev,
14565 			uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN])
14566 {
14567 	size_t i;
14568 	int remaining = 0;
14569 
14570 	for (i = 0; i < RTE_DIM(*hrxqs); i++) {
14571 		int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]);
14572 
14573 		if (!ret)
14574 			(*hrxqs)[i] = 0;
14575 		remaining += ret;
14576 	}
14577 	return remaining;
14578 }
14579 
14580 /**
14581  * Release all hash RX queue objects representing shared RSS action.
14582  *
14583  * @param[in] dev
14584  *   Pointer to the Ethernet device structure.
14585  * @param[in, out] action
14586  *   Shared RSS action to remove hash RX queue objects from.
14587  *
14588  * @return
14589  *   Total number of references to hash RX queue objects stored in *action*
14590  *   after this operation.
14591  *   Expected to be 0 if no external references held.
14592  */
14593 static int
14594 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev,
14595 				 struct mlx5_shared_action_rss *shared_rss)
14596 {
14597 	return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq);
14598 }
14599 
14600 /**
14601  * Adjust L3/L4 hash value of pre-created shared RSS hrxq according to
14602  * user input.
14603  *
14604  * Only one hash value is available for one L3+L4 combination:
14605  * for example:
14606  * MLX5_RSS_HASH_IPV4, MLX5_RSS_HASH_IPV4_SRC_ONLY, and
14607  * MLX5_RSS_HASH_IPV4_DST_ONLY are mutually exclusive so they can share
14608  * same slot in mlx5_rss_hash_fields.
14609  *
14610  * @param[in] rss
14611  *   Pointer to the shared action RSS conf.
14612  * @param[in, out] hash_field
14613  *   hash_field variable needed to be adjusted.
14614  *
14615  * @return
14616  *   void
14617  */
14618 static void
14619 __flow_dv_action_rss_l34_hash_adjust(struct mlx5_shared_action_rss *rss,
14620 				     uint64_t *hash_field)
14621 {
14622 	uint64_t rss_types = rss->origin.types;
14623 
14624 	switch (*hash_field & ~IBV_RX_HASH_INNER) {
14625 	case MLX5_RSS_HASH_IPV4:
14626 		if (rss_types & MLX5_IPV4_LAYER_TYPES) {
14627 			*hash_field &= ~MLX5_RSS_HASH_IPV4;
14628 			if (rss_types & RTE_ETH_RSS_L3_DST_ONLY)
14629 				*hash_field |= IBV_RX_HASH_DST_IPV4;
14630 			else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY)
14631 				*hash_field |= IBV_RX_HASH_SRC_IPV4;
14632 			else
14633 				*hash_field |= MLX5_RSS_HASH_IPV4;
14634 		}
14635 		return;
14636 	case MLX5_RSS_HASH_IPV6:
14637 		if (rss_types & MLX5_IPV6_LAYER_TYPES) {
14638 			*hash_field &= ~MLX5_RSS_HASH_IPV6;
14639 			if (rss_types & RTE_ETH_RSS_L3_DST_ONLY)
14640 				*hash_field |= IBV_RX_HASH_DST_IPV6;
14641 			else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY)
14642 				*hash_field |= IBV_RX_HASH_SRC_IPV6;
14643 			else
14644 				*hash_field |= MLX5_RSS_HASH_IPV6;
14645 		}
14646 		return;
14647 	case MLX5_RSS_HASH_IPV4_UDP:
14648 		/* fall-through. */
14649 	case MLX5_RSS_HASH_IPV6_UDP:
14650 		if (rss_types & RTE_ETH_RSS_UDP) {
14651 			*hash_field &= ~MLX5_UDP_IBV_RX_HASH;
14652 			if (rss_types & RTE_ETH_RSS_L4_DST_ONLY)
14653 				*hash_field |= IBV_RX_HASH_DST_PORT_UDP;
14654 			else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY)
14655 				*hash_field |= IBV_RX_HASH_SRC_PORT_UDP;
14656 			else
14657 				*hash_field |= MLX5_UDP_IBV_RX_HASH;
14658 		}
14659 		return;
14660 	case MLX5_RSS_HASH_IPV4_TCP:
14661 		/* fall-through. */
14662 	case MLX5_RSS_HASH_IPV6_TCP:
14663 		if (rss_types & RTE_ETH_RSS_TCP) {
14664 			*hash_field &= ~MLX5_TCP_IBV_RX_HASH;
14665 			if (rss_types & RTE_ETH_RSS_L4_DST_ONLY)
14666 				*hash_field |= IBV_RX_HASH_DST_PORT_TCP;
14667 			else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY)
14668 				*hash_field |= IBV_RX_HASH_SRC_PORT_TCP;
14669 			else
14670 				*hash_field |= MLX5_TCP_IBV_RX_HASH;
14671 		}
14672 		return;
14673 	default:
14674 		return;
14675 	}
14676 }
14677 
14678 /**
14679  * Setup shared RSS action.
14680  * Prepare set of hash RX queue objects sufficient to handle all valid
14681  * hash_fields combinations (see enum ibv_rx_hash_fields).
14682  *
14683  * @param[in] dev
14684  *   Pointer to the Ethernet device structure.
14685  * @param[in] action_idx
14686  *   Shared RSS action ipool index.
14687  * @param[in, out] action
14688  *   Partially initialized shared RSS action.
14689  * @param[out] error
14690  *   Perform verbose error reporting if not NULL. Initialized in case of
14691  *   error only.
14692  *
14693  * @return
14694  *   0 on success, otherwise negative errno value.
14695  */
14696 static int
14697 __flow_dv_action_rss_setup(struct rte_eth_dev *dev,
14698 			   uint32_t action_idx,
14699 			   struct mlx5_shared_action_rss *shared_rss,
14700 			   struct rte_flow_error *error)
14701 {
14702 	struct mlx5_flow_rss_desc rss_desc = { 0 };
14703 	size_t i;
14704 	int err;
14705 
14706 	if (mlx5_ind_table_obj_setup(dev, shared_rss->ind_tbl,
14707 				     !!dev->data->dev_started)) {
14708 		return rte_flow_error_set(error, rte_errno,
14709 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14710 					  "cannot setup indirection table");
14711 	}
14712 	memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN);
14713 	rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN;
14714 	rss_desc.const_q = shared_rss->origin.queue;
14715 	rss_desc.queue_num = shared_rss->origin.queue_num;
14716 	/* Set non-zero value to indicate a shared RSS. */
14717 	rss_desc.shared_rss = action_idx;
14718 	rss_desc.ind_tbl = shared_rss->ind_tbl;
14719 	for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) {
14720 		uint32_t hrxq_idx;
14721 		uint64_t hash_fields = mlx5_rss_hash_fields[i];
14722 		int tunnel = 0;
14723 
14724 		__flow_dv_action_rss_l34_hash_adjust(shared_rss, &hash_fields);
14725 		if (shared_rss->origin.level > 1) {
14726 			hash_fields |= IBV_RX_HASH_INNER;
14727 			tunnel = 1;
14728 		}
14729 		rss_desc.tunnel = tunnel;
14730 		rss_desc.hash_fields = hash_fields;
14731 		hrxq_idx = mlx5_hrxq_get(dev, &rss_desc);
14732 		if (!hrxq_idx) {
14733 			rte_flow_error_set
14734 				(error, rte_errno,
14735 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14736 				 "cannot get hash queue");
14737 			goto error_hrxq_new;
14738 		}
14739 		err = __flow_dv_action_rss_hrxq_set
14740 			(shared_rss, hash_fields, hrxq_idx);
14741 		MLX5_ASSERT(!err);
14742 	}
14743 	return 0;
14744 error_hrxq_new:
14745 	err = rte_errno;
14746 	__flow_dv_action_rss_hrxqs_release(dev, shared_rss);
14747 	if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true, true))
14748 		shared_rss->ind_tbl = NULL;
14749 	rte_errno = err;
14750 	return -rte_errno;
14751 }
14752 
14753 /**
14754  * Create shared RSS action.
14755  *
14756  * @param[in] dev
14757  *   Pointer to the Ethernet device structure.
14758  * @param[in] conf
14759  *   Shared action configuration.
14760  * @param[in] rss
14761  *   RSS action specification used to create shared action.
14762  * @param[out] error
14763  *   Perform verbose error reporting if not NULL. Initialized in case of
14764  *   error only.
14765  *
14766  * @return
14767  *   A valid shared action ID in case of success, 0 otherwise and
14768  *   rte_errno is set.
14769  */
14770 static uint32_t
14771 __flow_dv_action_rss_create(struct rte_eth_dev *dev,
14772 			    const struct rte_flow_indir_action_conf *conf,
14773 			    const struct rte_flow_action_rss *rss,
14774 			    struct rte_flow_error *error)
14775 {
14776 	struct mlx5_priv *priv = dev->data->dev_private;
14777 	struct mlx5_shared_action_rss *shared_rss = NULL;
14778 	void *queue = NULL;
14779 	struct rte_flow_action_rss *origin;
14780 	const uint8_t *rss_key;
14781 	uint32_t queue_size = rss->queue_num * sizeof(uint16_t);
14782 	uint32_t idx;
14783 
14784 	RTE_SET_USED(conf);
14785 	queue = mlx5_malloc(0, RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
14786 			    0, SOCKET_ID_ANY);
14787 	shared_rss = mlx5_ipool_zmalloc
14788 			 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx);
14789 	if (!shared_rss || !queue) {
14790 		rte_flow_error_set(error, ENOMEM,
14791 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14792 				   "cannot allocate resource memory");
14793 		goto error_rss_init;
14794 	}
14795 	if (idx > (1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET)) {
14796 		rte_flow_error_set(error, E2BIG,
14797 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14798 				   "rss action number out of range");
14799 		goto error_rss_init;
14800 	}
14801 	shared_rss->ind_tbl = mlx5_malloc(MLX5_MEM_ZERO,
14802 					  sizeof(*shared_rss->ind_tbl),
14803 					  0, SOCKET_ID_ANY);
14804 	if (!shared_rss->ind_tbl) {
14805 		rte_flow_error_set(error, ENOMEM,
14806 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14807 				   "cannot allocate resource memory");
14808 		goto error_rss_init;
14809 	}
14810 	memcpy(queue, rss->queue, queue_size);
14811 	shared_rss->ind_tbl->queues = queue;
14812 	shared_rss->ind_tbl->queues_n = rss->queue_num;
14813 	origin = &shared_rss->origin;
14814 	origin->func = rss->func;
14815 	origin->level = rss->level;
14816 	/* RSS type 0 indicates default RSS type (RTE_ETH_RSS_IP). */
14817 	origin->types = !rss->types ? RTE_ETH_RSS_IP : rss->types;
14818 	/* NULL RSS key indicates default RSS key. */
14819 	rss_key = !rss->key ? rss_hash_default_key : rss->key;
14820 	memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
14821 	origin->key = &shared_rss->key[0];
14822 	origin->key_len = MLX5_RSS_HASH_KEY_LEN;
14823 	origin->queue = queue;
14824 	origin->queue_num = rss->queue_num;
14825 	if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error))
14826 		goto error_rss_init;
14827 	rte_spinlock_init(&shared_rss->action_rss_sl);
14828 	__atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
14829 	rte_spinlock_lock(&priv->shared_act_sl);
14830 	ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14831 		     &priv->rss_shared_actions, idx, shared_rss, next);
14832 	rte_spinlock_unlock(&priv->shared_act_sl);
14833 	return idx;
14834 error_rss_init:
14835 	if (shared_rss) {
14836 		if (shared_rss->ind_tbl)
14837 			mlx5_free(shared_rss->ind_tbl);
14838 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14839 				idx);
14840 	}
14841 	if (queue)
14842 		mlx5_free(queue);
14843 	return 0;
14844 }
14845 
14846 /**
14847  * Destroy the shared RSS action.
14848  * Release related hash RX queue objects.
14849  *
14850  * @param[in] dev
14851  *   Pointer to the Ethernet device structure.
14852  * @param[in] idx
14853  *   The shared RSS action object ID to be removed.
14854  * @param[out] error
14855  *   Perform verbose error reporting if not NULL. Initialized in case of
14856  *   error only.
14857  *
14858  * @return
14859  *   0 on success, otherwise negative errno value.
14860  */
14861 static int
14862 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx,
14863 			     struct rte_flow_error *error)
14864 {
14865 	struct mlx5_priv *priv = dev->data->dev_private;
14866 	struct mlx5_shared_action_rss *shared_rss =
14867 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
14868 	uint32_t old_refcnt = 1;
14869 	int remaining;
14870 	uint16_t *queue = NULL;
14871 
14872 	if (!shared_rss)
14873 		return rte_flow_error_set(error, EINVAL,
14874 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
14875 					  "invalid shared action");
14876 	if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt,
14877 					 0, 0, __ATOMIC_ACQUIRE,
14878 					 __ATOMIC_RELAXED))
14879 		return rte_flow_error_set(error, EBUSY,
14880 					  RTE_FLOW_ERROR_TYPE_ACTION,
14881 					  NULL,
14882 					  "shared rss has references");
14883 	remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss);
14884 	if (remaining)
14885 		return rte_flow_error_set(error, EBUSY,
14886 					  RTE_FLOW_ERROR_TYPE_ACTION,
14887 					  NULL,
14888 					  "shared rss hrxq has references");
14889 	queue = shared_rss->ind_tbl->queues;
14890 	remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true,
14891 					       !!dev->data->dev_started);
14892 	if (remaining)
14893 		return rte_flow_error_set(error, EBUSY,
14894 					  RTE_FLOW_ERROR_TYPE_ACTION,
14895 					  NULL,
14896 					  "shared rss indirection table has"
14897 					  " references");
14898 	mlx5_free(queue);
14899 	rte_spinlock_lock(&priv->shared_act_sl);
14900 	ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14901 		     &priv->rss_shared_actions, idx, shared_rss, next);
14902 	rte_spinlock_unlock(&priv->shared_act_sl);
14903 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
14904 			idx);
14905 	return 0;
14906 }
14907 
14908 /**
14909  * Create indirect action, lock free,
14910  * (mutex should be acquired by caller).
14911  * Dispatcher for action type specific call.
14912  *
14913  * @param[in] dev
14914  *   Pointer to the Ethernet device structure.
14915  * @param[in] conf
14916  *   Shared action configuration.
14917  * @param[in] action
14918  *   Action specification used to create indirect action.
14919  * @param[out] error
14920  *   Perform verbose error reporting if not NULL. Initialized in case of
14921  *   error only.
14922  *
14923  * @return
14924  *   A valid shared action handle in case of success, NULL otherwise and
14925  *   rte_errno is set.
14926  */
14927 static struct rte_flow_action_handle *
14928 flow_dv_action_create(struct rte_eth_dev *dev,
14929 		      const struct rte_flow_indir_action_conf *conf,
14930 		      const struct rte_flow_action *action,
14931 		      struct rte_flow_error *err)
14932 {
14933 	struct mlx5_priv *priv = dev->data->dev_private;
14934 	uint32_t age_idx = 0;
14935 	uint32_t idx = 0;
14936 	uint32_t ret = 0;
14937 
14938 	switch (action->type) {
14939 	case RTE_FLOW_ACTION_TYPE_RSS:
14940 		ret = __flow_dv_action_rss_create(dev, conf, action->conf, err);
14941 		idx = (MLX5_INDIRECT_ACTION_TYPE_RSS <<
14942 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
14943 		break;
14944 	case RTE_FLOW_ACTION_TYPE_AGE:
14945 		age_idx = flow_dv_aso_age_alloc(dev, err);
14946 		if (!age_idx) {
14947 			ret = -rte_errno;
14948 			break;
14949 		}
14950 		idx = (MLX5_INDIRECT_ACTION_TYPE_AGE <<
14951 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx;
14952 		flow_dv_aso_age_params_init(dev, age_idx,
14953 					((const struct rte_flow_action_age *)
14954 						action->conf)->context ?
14955 					((const struct rte_flow_action_age *)
14956 						action->conf)->context :
14957 					(void *)(uintptr_t)idx,
14958 					((const struct rte_flow_action_age *)
14959 						action->conf)->timeout);
14960 		ret = age_idx;
14961 		break;
14962 	case RTE_FLOW_ACTION_TYPE_COUNT:
14963 		ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL);
14964 		idx = (MLX5_INDIRECT_ACTION_TYPE_COUNT <<
14965 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
14966 		break;
14967 	case RTE_FLOW_ACTION_TYPE_CONNTRACK:
14968 		ret = flow_dv_translate_create_conntrack(dev, action->conf,
14969 							 err);
14970 		idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret);
14971 		break;
14972 	default:
14973 		rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
14974 				   NULL, "action type not supported");
14975 		break;
14976 	}
14977 	return ret ? (struct rte_flow_action_handle *)(uintptr_t)idx : NULL;
14978 }
14979 
14980 /**
14981  * Destroy the indirect action.
14982  * Release action related resources on the NIC and the memory.
14983  * Lock free, (mutex should be acquired by caller).
14984  * Dispatcher for action type specific call.
14985  *
14986  * @param[in] dev
14987  *   Pointer to the Ethernet device structure.
14988  * @param[in] handle
14989  *   The indirect action object handle to be removed.
14990  * @param[out] error
14991  *   Perform verbose error reporting if not NULL. Initialized in case of
14992  *   error only.
14993  *
14994  * @return
14995  *   0 on success, otherwise negative errno value.
14996  */
14997 static int
14998 flow_dv_action_destroy(struct rte_eth_dev *dev,
14999 		       struct rte_flow_action_handle *handle,
15000 		       struct rte_flow_error *error)
15001 {
15002 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15003 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15004 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15005 	struct mlx5_flow_counter *cnt;
15006 	uint32_t no_flow_refcnt = 1;
15007 	int ret;
15008 
15009 	switch (type) {
15010 	case MLX5_INDIRECT_ACTION_TYPE_RSS:
15011 		return __flow_dv_action_rss_release(dev, idx, error);
15012 	case MLX5_INDIRECT_ACTION_TYPE_COUNT:
15013 		cnt = flow_dv_counter_get_by_idx(dev, idx, NULL);
15014 		if (!__atomic_compare_exchange_n(&cnt->shared_info.refcnt,
15015 						 &no_flow_refcnt, 1, false,
15016 						 __ATOMIC_ACQUIRE,
15017 						 __ATOMIC_RELAXED))
15018 			return rte_flow_error_set(error, EBUSY,
15019 						  RTE_FLOW_ERROR_TYPE_ACTION,
15020 						  NULL,
15021 						  "Indirect count action has references");
15022 		flow_dv_counter_free(dev, idx);
15023 		return 0;
15024 	case MLX5_INDIRECT_ACTION_TYPE_AGE:
15025 		ret = flow_dv_aso_age_release(dev, idx);
15026 		if (ret)
15027 			/*
15028 			 * In this case, the last flow has a reference will
15029 			 * actually release the age action.
15030 			 */
15031 			DRV_LOG(DEBUG, "Indirect age action %" PRIu32 " was"
15032 				" released with references %d.", idx, ret);
15033 		return 0;
15034 	case MLX5_INDIRECT_ACTION_TYPE_CT:
15035 		ret = flow_dv_aso_ct_release(dev, idx, error);
15036 		if (ret < 0)
15037 			return ret;
15038 		if (ret > 0)
15039 			DRV_LOG(DEBUG, "Connection tracking object %u still "
15040 				"has references %d.", idx, ret);
15041 		return 0;
15042 	default:
15043 		return rte_flow_error_set(error, ENOTSUP,
15044 					  RTE_FLOW_ERROR_TYPE_ACTION,
15045 					  NULL,
15046 					  "action type not supported");
15047 	}
15048 }
15049 
15050 /**
15051  * Updates in place shared RSS action configuration.
15052  *
15053  * @param[in] dev
15054  *   Pointer to the Ethernet device structure.
15055  * @param[in] idx
15056  *   The shared RSS action object ID to be updated.
15057  * @param[in] action_conf
15058  *   RSS action specification used to modify *shared_rss*.
15059  * @param[out] error
15060  *   Perform verbose error reporting if not NULL. Initialized in case of
15061  *   error only.
15062  *
15063  * @return
15064  *   0 on success, otherwise negative errno value.
15065  * @note: currently only support update of RSS queues.
15066  */
15067 static int
15068 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx,
15069 			    const struct rte_flow_action_rss *action_conf,
15070 			    struct rte_flow_error *error)
15071 {
15072 	struct mlx5_priv *priv = dev->data->dev_private;
15073 	struct mlx5_shared_action_rss *shared_rss =
15074 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
15075 	int ret = 0;
15076 	void *queue = NULL;
15077 	uint16_t *queue_old = NULL;
15078 	uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t);
15079 	bool dev_started = !!dev->data->dev_started;
15080 
15081 	if (!shared_rss)
15082 		return rte_flow_error_set(error, EINVAL,
15083 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15084 					  "invalid shared action to update");
15085 	if (priv->obj_ops.ind_table_modify == NULL)
15086 		return rte_flow_error_set(error, ENOTSUP,
15087 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15088 					  "cannot modify indirection table");
15089 	queue = mlx5_malloc(MLX5_MEM_ZERO,
15090 			    RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
15091 			    0, SOCKET_ID_ANY);
15092 	if (!queue)
15093 		return rte_flow_error_set(error, ENOMEM,
15094 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15095 					  NULL,
15096 					  "cannot allocate resource memory");
15097 	memcpy(queue, action_conf->queue, queue_size);
15098 	MLX5_ASSERT(shared_rss->ind_tbl);
15099 	rte_spinlock_lock(&shared_rss->action_rss_sl);
15100 	queue_old = shared_rss->ind_tbl->queues;
15101 	ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl,
15102 					queue, action_conf->queue_num,
15103 					true /* standalone */,
15104 					dev_started /* ref_new_qs */,
15105 					dev_started /* deref_old_qs */);
15106 	if (ret) {
15107 		mlx5_free(queue);
15108 		ret = rte_flow_error_set(error, rte_errno,
15109 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15110 					  "cannot update indirection table");
15111 	} else {
15112 		mlx5_free(queue_old);
15113 		shared_rss->origin.queue = queue;
15114 		shared_rss->origin.queue_num = action_conf->queue_num;
15115 	}
15116 	rte_spinlock_unlock(&shared_rss->action_rss_sl);
15117 	return ret;
15118 }
15119 
15120 /*
15121  * Updates in place conntrack context or direction.
15122  * Context update should be synchronized.
15123  *
15124  * @param[in] dev
15125  *   Pointer to the Ethernet device structure.
15126  * @param[in] idx
15127  *   The conntrack object ID to be updated.
15128  * @param[in] update
15129  *   Pointer to the structure of information to update.
15130  * @param[out] error
15131  *   Perform verbose error reporting if not NULL. Initialized in case of
15132  *   error only.
15133  *
15134  * @return
15135  *   0 on success, otherwise negative errno value.
15136  */
15137 static int
15138 __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx,
15139 			   const struct rte_flow_modify_conntrack *update,
15140 			   struct rte_flow_error *error)
15141 {
15142 	struct mlx5_priv *priv = dev->data->dev_private;
15143 	struct mlx5_aso_ct_action *ct;
15144 	const struct rte_flow_action_conntrack *new_prf;
15145 	int ret = 0;
15146 	uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
15147 	uint32_t dev_idx;
15148 
15149 	if (PORT_ID(priv) != owner)
15150 		return rte_flow_error_set(error, EACCES,
15151 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15152 					  NULL,
15153 					  "CT object owned by another port");
15154 	dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
15155 	ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
15156 	if (!ct->refcnt)
15157 		return rte_flow_error_set(error, ENOMEM,
15158 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15159 					  NULL,
15160 					  "CT object is inactive");
15161 	new_prf = &update->new_ct;
15162 	if (update->direction)
15163 		ct->is_original = !!new_prf->is_original_dir;
15164 	if (update->state) {
15165 		/* Only validate the profile when it needs to be updated. */
15166 		ret = mlx5_validate_action_ct(dev, new_prf, error);
15167 		if (ret)
15168 			return ret;
15169 		ret = mlx5_aso_ct_update_by_wqe(priv->sh, ct, new_prf);
15170 		if (ret)
15171 			return rte_flow_error_set(error, EIO,
15172 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15173 					NULL,
15174 					"Failed to send CT context update WQE");
15175 		/* Block until ready or a failure. */
15176 		ret = mlx5_aso_ct_available(priv->sh, ct);
15177 		if (ret)
15178 			rte_flow_error_set(error, rte_errno,
15179 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15180 					   NULL,
15181 					   "Timeout to get the CT update");
15182 	}
15183 	return ret;
15184 }
15185 
15186 /**
15187  * Updates in place shared action configuration, lock free,
15188  * (mutex should be acquired by caller).
15189  *
15190  * @param[in] dev
15191  *   Pointer to the Ethernet device structure.
15192  * @param[in] handle
15193  *   The indirect action object handle to be updated.
15194  * @param[in] update
15195  *   Action specification used to modify the action pointed by *handle*.
15196  *   *update* could be of same type with the action pointed by the *handle*
15197  *   handle argument, or some other structures like a wrapper, depending on
15198  *   the indirect action type.
15199  * @param[out] error
15200  *   Perform verbose error reporting if not NULL. Initialized in case of
15201  *   error only.
15202  *
15203  * @return
15204  *   0 on success, otherwise negative errno value.
15205  */
15206 static int
15207 flow_dv_action_update(struct rte_eth_dev *dev,
15208 			struct rte_flow_action_handle *handle,
15209 			const void *update,
15210 			struct rte_flow_error *err)
15211 {
15212 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15213 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15214 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15215 	const void *action_conf;
15216 
15217 	switch (type) {
15218 	case MLX5_INDIRECT_ACTION_TYPE_RSS:
15219 		action_conf = ((const struct rte_flow_action *)update)->conf;
15220 		return __flow_dv_action_rss_update(dev, idx, action_conf, err);
15221 	case MLX5_INDIRECT_ACTION_TYPE_CT:
15222 		return __flow_dv_action_ct_update(dev, idx, update, err);
15223 	default:
15224 		return rte_flow_error_set(err, ENOTSUP,
15225 					  RTE_FLOW_ERROR_TYPE_ACTION,
15226 					  NULL,
15227 					  "action type update not supported");
15228 	}
15229 }
15230 
15231 /**
15232  * Destroy the meter sub policy table rules.
15233  * Lock free, (mutex should be acquired by caller).
15234  *
15235  * @param[in] dev
15236  *   Pointer to Ethernet device.
15237  * @param[in] sub_policy
15238  *   Pointer to meter sub policy table.
15239  */
15240 static void
15241 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
15242 			     struct mlx5_flow_meter_sub_policy *sub_policy)
15243 {
15244 	struct mlx5_priv *priv = dev->data->dev_private;
15245 	struct mlx5_flow_tbl_data_entry *tbl;
15246 	struct mlx5_flow_meter_policy *policy = sub_policy->main_policy;
15247 	struct mlx5_flow_meter_info *next_fm;
15248 	struct mlx5_sub_policy_color_rule *color_rule;
15249 	void *tmp;
15250 	uint32_t i;
15251 
15252 	for (i = 0; i < RTE_COLORS; i++) {
15253 		next_fm = NULL;
15254 		if (i == RTE_COLOR_GREEN && policy &&
15255 		    policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
15256 			next_fm = mlx5_flow_meter_find(priv,
15257 					policy->act_cnt[i].next_mtr_id, NULL);
15258 		RTE_TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i],
15259 				   next_port, tmp) {
15260 			claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule));
15261 			tbl = container_of(color_rule->matcher->tbl,
15262 					   typeof(*tbl), tbl);
15263 			mlx5_list_unregister(tbl->matchers,
15264 					     &color_rule->matcher->entry);
15265 			TAILQ_REMOVE(&sub_policy->color_rules[i],
15266 				     color_rule, next_port);
15267 			mlx5_free(color_rule);
15268 			if (next_fm)
15269 				mlx5_flow_meter_detach(priv, next_fm);
15270 		}
15271 	}
15272 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
15273 		if (sub_policy->rix_hrxq[i]) {
15274 			if (policy && !policy->is_hierarchy)
15275 				mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
15276 			sub_policy->rix_hrxq[i] = 0;
15277 		}
15278 		if (sub_policy->jump_tbl[i]) {
15279 			flow_dv_tbl_resource_release(MLX5_SH(dev),
15280 						     sub_policy->jump_tbl[i]);
15281 			sub_policy->jump_tbl[i] = NULL;
15282 		}
15283 	}
15284 	if (sub_policy->tbl_rsc) {
15285 		flow_dv_tbl_resource_release(MLX5_SH(dev),
15286 					     sub_policy->tbl_rsc);
15287 		sub_policy->tbl_rsc = NULL;
15288 	}
15289 }
15290 
15291 /**
15292  * Destroy policy rules, lock free,
15293  * (mutex should be acquired by caller).
15294  * Dispatcher for action type specific call.
15295  *
15296  * @param[in] dev
15297  *   Pointer to the Ethernet device structure.
15298  * @param[in] mtr_policy
15299  *   Meter policy struct.
15300  */
15301 static void
15302 flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
15303 			     struct mlx5_flow_meter_policy *mtr_policy)
15304 {
15305 	uint32_t i, j;
15306 	struct mlx5_flow_meter_sub_policy *sub_policy;
15307 	uint16_t sub_policy_num;
15308 
15309 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15310 		sub_policy_num = (mtr_policy->sub_policy_num >>
15311 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
15312 			MLX5_MTR_SUB_POLICY_NUM_MASK;
15313 		for (j = 0; j < sub_policy_num; j++) {
15314 			sub_policy = mtr_policy->sub_policys[i][j];
15315 			if (sub_policy)
15316 				__flow_dv_destroy_sub_policy_rules(dev,
15317 								   sub_policy);
15318 		}
15319 	}
15320 }
15321 
15322 /**
15323  * Destroy policy action, lock free,
15324  * (mutex should be acquired by caller).
15325  * Dispatcher for action type specific call.
15326  *
15327  * @param[in] dev
15328  *   Pointer to the Ethernet device structure.
15329  * @param[in] mtr_policy
15330  *   Meter policy struct.
15331  */
15332 static void
15333 flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
15334 		      struct mlx5_flow_meter_policy *mtr_policy)
15335 {
15336 	struct rte_flow_action *rss_action;
15337 	struct mlx5_flow_handle dev_handle;
15338 	uint32_t i, j;
15339 
15340 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
15341 		if (mtr_policy->act_cnt[i].rix_mark) {
15342 			flow_dv_tag_release(dev,
15343 				mtr_policy->act_cnt[i].rix_mark);
15344 			mtr_policy->act_cnt[i].rix_mark = 0;
15345 		}
15346 		if (mtr_policy->act_cnt[i].modify_hdr) {
15347 			dev_handle.dvh.modify_hdr =
15348 				mtr_policy->act_cnt[i].modify_hdr;
15349 			flow_dv_modify_hdr_resource_release(dev, &dev_handle);
15350 		}
15351 		switch (mtr_policy->act_cnt[i].fate_action) {
15352 		case MLX5_FLOW_FATE_SHARED_RSS:
15353 			rss_action = mtr_policy->act_cnt[i].rss;
15354 			mlx5_free(rss_action);
15355 			break;
15356 		case MLX5_FLOW_FATE_PORT_ID:
15357 			if (mtr_policy->act_cnt[i].rix_port_id_action) {
15358 				flow_dv_port_id_action_resource_release(dev,
15359 				mtr_policy->act_cnt[i].rix_port_id_action);
15360 				mtr_policy->act_cnt[i].rix_port_id_action = 0;
15361 			}
15362 			break;
15363 		case MLX5_FLOW_FATE_DROP:
15364 		case MLX5_FLOW_FATE_JUMP:
15365 			for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
15366 				mtr_policy->act_cnt[i].dr_jump_action[j] =
15367 						NULL;
15368 			break;
15369 		default:
15370 			/*Queue action do nothing*/
15371 			break;
15372 		}
15373 	}
15374 	for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
15375 		mtr_policy->dr_drop_action[j] = NULL;
15376 }
15377 
15378 /**
15379  * Create policy action per domain, lock free,
15380  * (mutex should be acquired by caller).
15381  * Dispatcher for action type specific call.
15382  *
15383  * @param[in] dev
15384  *   Pointer to the Ethernet device structure.
15385  * @param[in] mtr_policy
15386  *   Meter policy struct.
15387  * @param[in] action
15388  *   Action specification used to create meter actions.
15389  * @param[out] error
15390  *   Perform verbose error reporting if not NULL. Initialized in case of
15391  *   error only.
15392  *
15393  * @return
15394  *   0 on success, otherwise negative errno value.
15395  */
15396 static int
15397 __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
15398 			struct mlx5_flow_meter_policy *mtr_policy,
15399 			const struct rte_flow_action *actions[RTE_COLORS],
15400 			enum mlx5_meter_domain domain,
15401 			struct rte_mtr_error *error)
15402 {
15403 	struct mlx5_priv *priv = dev->data->dev_private;
15404 	struct rte_flow_error flow_err;
15405 	const struct rte_flow_action *act;
15406 	uint64_t action_flags;
15407 	struct mlx5_flow_handle dh;
15408 	struct mlx5_flow dev_flow;
15409 	struct mlx5_flow_dv_port_id_action_resource port_id_action;
15410 	int i, ret;
15411 	uint8_t egress, transfer;
15412 	struct mlx5_meter_policy_action_container *act_cnt = NULL;
15413 	union {
15414 		struct mlx5_flow_dv_modify_hdr_resource res;
15415 		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
15416 			    sizeof(struct mlx5_modification_cmd) *
15417 			    (MLX5_MAX_MODIFY_NUM + 1)];
15418 	} mhdr_dummy;
15419 	struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
15420 
15421 	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
15422 	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
15423 	memset(&dh, 0, sizeof(struct mlx5_flow_handle));
15424 	memset(&dev_flow, 0, sizeof(struct mlx5_flow));
15425 	memset(&port_id_action, 0,
15426 	       sizeof(struct mlx5_flow_dv_port_id_action_resource));
15427 	memset(mhdr_res, 0, sizeof(*mhdr_res));
15428 	mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
15429 				       (egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
15430 					MLX5DV_FLOW_TABLE_TYPE_NIC_RX);
15431 	dev_flow.handle = &dh;
15432 	dev_flow.dv.port_id_action = &port_id_action;
15433 	dev_flow.external = true;
15434 	for (i = 0; i < RTE_COLORS; i++) {
15435 		if (i < MLX5_MTR_RTE_COLORS)
15436 			act_cnt = &mtr_policy->act_cnt[i];
15437 		/* Skip the color policy actions creation. */
15438 		if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) ||
15439 		    (i == RTE_COLOR_GREEN && mtr_policy->skip_g))
15440 			continue;
15441 		action_flags = 0;
15442 		for (act = actions[i];
15443 		     act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
15444 			switch (act->type) {
15445 			case RTE_FLOW_ACTION_TYPE_MARK:
15446 			{
15447 				uint32_t tag_be = mlx5_flow_mark_set
15448 					(((const struct rte_flow_action_mark *)
15449 					(act->conf))->id);
15450 
15451 				if (i >= MLX5_MTR_RTE_COLORS)
15452 					return -rte_mtr_error_set(error,
15453 					  ENOTSUP,
15454 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15455 					  NULL,
15456 					  "cannot create policy "
15457 					  "mark action for this color");
15458 				dev_flow.handle->mark = 1;
15459 				if (flow_dv_tag_resource_register(dev, tag_be,
15460 						  &dev_flow, &flow_err))
15461 					return -rte_mtr_error_set(error,
15462 					ENOTSUP,
15463 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15464 					NULL,
15465 					"cannot setup policy mark action");
15466 				MLX5_ASSERT(dev_flow.dv.tag_resource);
15467 				act_cnt->rix_mark =
15468 					dev_flow.handle->dvh.rix_tag;
15469 				action_flags |= MLX5_FLOW_ACTION_MARK;
15470 				break;
15471 			}
15472 			case RTE_FLOW_ACTION_TYPE_SET_TAG:
15473 				if (i >= MLX5_MTR_RTE_COLORS)
15474 					return -rte_mtr_error_set(error,
15475 					  ENOTSUP,
15476 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15477 					  NULL,
15478 					  "cannot create policy "
15479 					  "set tag action for this color");
15480 				if (flow_dv_convert_action_set_tag
15481 				(dev, mhdr_res,
15482 				(const struct rte_flow_action_set_tag *)
15483 				act->conf,  &flow_err))
15484 					return -rte_mtr_error_set(error,
15485 					ENOTSUP,
15486 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15487 					NULL, "cannot convert policy "
15488 					"set tag action");
15489 				if (!mhdr_res->actions_num)
15490 					return -rte_mtr_error_set(error,
15491 					ENOTSUP,
15492 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15493 					NULL, "cannot find policy "
15494 					"set tag action");
15495 				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
15496 				break;
15497 			case RTE_FLOW_ACTION_TYPE_DROP:
15498 			{
15499 				struct mlx5_flow_mtr_mng *mtrmng =
15500 						priv->sh->mtrmng;
15501 				struct mlx5_flow_tbl_data_entry *tbl_data;
15502 
15503 				/*
15504 				 * Create the drop table with
15505 				 * METER DROP level.
15506 				 */
15507 				if (!mtrmng->drop_tbl[domain]) {
15508 					mtrmng->drop_tbl[domain] =
15509 					flow_dv_tbl_resource_get(dev,
15510 					MLX5_FLOW_TABLE_LEVEL_METER,
15511 					egress, transfer, false, NULL, 0,
15512 					0, MLX5_MTR_TABLE_ID_DROP, &flow_err);
15513 					if (!mtrmng->drop_tbl[domain])
15514 						return -rte_mtr_error_set
15515 					(error, ENOTSUP,
15516 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15517 					NULL,
15518 					"Failed to create meter drop table");
15519 				}
15520 				tbl_data = container_of
15521 				(mtrmng->drop_tbl[domain],
15522 				struct mlx5_flow_tbl_data_entry, tbl);
15523 				if (i < MLX5_MTR_RTE_COLORS) {
15524 					act_cnt->dr_jump_action[domain] =
15525 						tbl_data->jump.action;
15526 					act_cnt->fate_action =
15527 						MLX5_FLOW_FATE_DROP;
15528 				}
15529 				if (i == RTE_COLOR_RED)
15530 					mtr_policy->dr_drop_action[domain] =
15531 						tbl_data->jump.action;
15532 				action_flags |= MLX5_FLOW_ACTION_DROP;
15533 				break;
15534 			}
15535 			case RTE_FLOW_ACTION_TYPE_QUEUE:
15536 			{
15537 				if (i >= MLX5_MTR_RTE_COLORS)
15538 					return -rte_mtr_error_set(error,
15539 					ENOTSUP,
15540 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15541 					NULL, "cannot create policy "
15542 					"fate queue for this color");
15543 				act_cnt->queue =
15544 				((const struct rte_flow_action_queue *)
15545 					(act->conf))->index;
15546 				act_cnt->fate_action =
15547 					MLX5_FLOW_FATE_QUEUE;
15548 				dev_flow.handle->fate_action =
15549 					MLX5_FLOW_FATE_QUEUE;
15550 				mtr_policy->is_queue = 1;
15551 				action_flags |= MLX5_FLOW_ACTION_QUEUE;
15552 				break;
15553 			}
15554 			case RTE_FLOW_ACTION_TYPE_RSS:
15555 			{
15556 				int rss_size;
15557 
15558 				if (i >= MLX5_MTR_RTE_COLORS)
15559 					return -rte_mtr_error_set(error,
15560 					  ENOTSUP,
15561 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15562 					  NULL,
15563 					  "cannot create policy "
15564 					  "rss action for this color");
15565 				/*
15566 				 * Save RSS conf into policy struct
15567 				 * for translate stage.
15568 				 */
15569 				rss_size = (int)rte_flow_conv
15570 					(RTE_FLOW_CONV_OP_ACTION,
15571 					NULL, 0, act, &flow_err);
15572 				if (rss_size <= 0)
15573 					return -rte_mtr_error_set(error,
15574 					  ENOTSUP,
15575 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15576 					  NULL, "Get the wrong "
15577 					  "rss action struct size");
15578 				act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
15579 						rss_size, 0, SOCKET_ID_ANY);
15580 				if (!act_cnt->rss)
15581 					return -rte_mtr_error_set(error,
15582 					  ENOTSUP,
15583 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15584 					  NULL,
15585 					  "Fail to malloc rss action memory");
15586 				ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
15587 					act_cnt->rss, rss_size,
15588 					act, &flow_err);
15589 				if (ret < 0)
15590 					return -rte_mtr_error_set(error,
15591 					  ENOTSUP,
15592 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15593 					  NULL, "Fail to save "
15594 					  "rss action into policy struct");
15595 				act_cnt->fate_action =
15596 					MLX5_FLOW_FATE_SHARED_RSS;
15597 				action_flags |= MLX5_FLOW_ACTION_RSS;
15598 				break;
15599 			}
15600 			case RTE_FLOW_ACTION_TYPE_PORT_ID:
15601 			case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
15602 			{
15603 				struct mlx5_flow_dv_port_id_action_resource
15604 					port_id_resource;
15605 				uint32_t port_id = 0;
15606 
15607 				if (i >= MLX5_MTR_RTE_COLORS)
15608 					return -rte_mtr_error_set(error,
15609 					ENOTSUP,
15610 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15611 					NULL, "cannot create policy "
15612 					"port action for this color");
15613 				memset(&port_id_resource, 0,
15614 					sizeof(port_id_resource));
15615 				if (flow_dv_translate_action_port_id(dev, act,
15616 						&port_id, &flow_err))
15617 					return -rte_mtr_error_set(error,
15618 					ENOTSUP,
15619 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15620 					NULL, "cannot translate "
15621 					"policy port action");
15622 				port_id_resource.port_id = port_id;
15623 				if (flow_dv_port_id_action_resource_register
15624 					(dev, &port_id_resource,
15625 					&dev_flow, &flow_err))
15626 					return -rte_mtr_error_set(error,
15627 					ENOTSUP,
15628 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15629 					NULL, "cannot setup "
15630 					"policy port action");
15631 				act_cnt->rix_port_id_action =
15632 					dev_flow.handle->rix_port_id_action;
15633 				act_cnt->fate_action =
15634 					MLX5_FLOW_FATE_PORT_ID;
15635 				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
15636 				break;
15637 			}
15638 			case RTE_FLOW_ACTION_TYPE_JUMP:
15639 			{
15640 				uint32_t jump_group = 0;
15641 				uint32_t table = 0;
15642 				struct mlx5_flow_tbl_data_entry *tbl_data;
15643 				struct flow_grp_info grp_info = {
15644 					.external = !!dev_flow.external,
15645 					.transfer = !!transfer,
15646 					.fdb_def_rule = !!priv->fdb_def_rule,
15647 					.std_tbl_fix = 0,
15648 					.skip_scale = dev_flow.skip_scale &
15649 					(1 << MLX5_SCALE_FLOW_GROUP_BIT),
15650 				};
15651 				struct mlx5_flow_meter_sub_policy *sub_policy =
15652 					mtr_policy->sub_policys[domain][0];
15653 
15654 				if (i >= MLX5_MTR_RTE_COLORS)
15655 					return -rte_mtr_error_set(error,
15656 					  ENOTSUP,
15657 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15658 					  NULL,
15659 					  "cannot create policy "
15660 					  "jump action for this color");
15661 				jump_group =
15662 				((const struct rte_flow_action_jump *)
15663 							act->conf)->group;
15664 				if (mlx5_flow_group_to_table(dev, NULL,
15665 						       jump_group,
15666 						       &table,
15667 						       &grp_info, &flow_err))
15668 					return -rte_mtr_error_set(error,
15669 					ENOTSUP,
15670 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15671 					NULL, "cannot setup "
15672 					"policy jump action");
15673 				sub_policy->jump_tbl[i] =
15674 				flow_dv_tbl_resource_get(dev,
15675 					table, egress,
15676 					transfer,
15677 					!!dev_flow.external,
15678 					NULL, jump_group, 0,
15679 					0, &flow_err);
15680 				if
15681 				(!sub_policy->jump_tbl[i])
15682 					return  -rte_mtr_error_set(error,
15683 					ENOTSUP,
15684 					RTE_MTR_ERROR_TYPE_METER_POLICY,
15685 					NULL, "cannot create jump action.");
15686 				tbl_data = container_of
15687 				(sub_policy->jump_tbl[i],
15688 				struct mlx5_flow_tbl_data_entry, tbl);
15689 				act_cnt->dr_jump_action[domain] =
15690 					tbl_data->jump.action;
15691 				act_cnt->fate_action =
15692 					MLX5_FLOW_FATE_JUMP;
15693 				action_flags |= MLX5_FLOW_ACTION_JUMP;
15694 				break;
15695 			}
15696 			/*
15697 			 * No need to check meter hierarchy for Y or R colors
15698 			 * here since it is done in the validation stage.
15699 			 */
15700 			case RTE_FLOW_ACTION_TYPE_METER:
15701 			{
15702 				const struct rte_flow_action_meter *mtr;
15703 				struct mlx5_flow_meter_info *next_fm;
15704 				struct mlx5_flow_meter_policy *next_policy;
15705 				struct rte_flow_action tag_action;
15706 				struct mlx5_rte_flow_action_set_tag set_tag;
15707 				uint32_t next_mtr_idx = 0;
15708 
15709 				mtr = act->conf;
15710 				next_fm = mlx5_flow_meter_find(priv,
15711 							mtr->mtr_id,
15712 							&next_mtr_idx);
15713 				if (!next_fm)
15714 					return -rte_mtr_error_set(error, EINVAL,
15715 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
15716 						"Fail to find next meter.");
15717 				if (next_fm->def_policy)
15718 					return -rte_mtr_error_set(error, EINVAL,
15719 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
15720 				"Hierarchy only supports termination meter.");
15721 				next_policy = mlx5_flow_meter_policy_find(dev,
15722 						next_fm->policy_id, NULL);
15723 				MLX5_ASSERT(next_policy);
15724 				if (next_fm->drop_cnt) {
15725 					set_tag.id =
15726 						(enum modify_reg)
15727 						mlx5_flow_get_reg_id(dev,
15728 						MLX5_MTR_ID,
15729 						0,
15730 						(struct rte_flow_error *)error);
15731 					set_tag.offset = (priv->mtr_reg_share ?
15732 						MLX5_MTR_COLOR_BITS : 0);
15733 					set_tag.length = (priv->mtr_reg_share ?
15734 					       MLX5_MTR_IDLE_BITS_IN_COLOR_REG :
15735 					       MLX5_REG_BITS);
15736 					set_tag.data = next_mtr_idx;
15737 					tag_action.type =
15738 						(enum rte_flow_action_type)
15739 						MLX5_RTE_FLOW_ACTION_TYPE_TAG;
15740 					tag_action.conf = &set_tag;
15741 					if (flow_dv_convert_action_set_reg
15742 						(mhdr_res, &tag_action,
15743 						(struct rte_flow_error *)error))
15744 						return -rte_errno;
15745 					action_flags |=
15746 						MLX5_FLOW_ACTION_SET_TAG;
15747 				}
15748 				act_cnt->fate_action = MLX5_FLOW_FATE_MTR;
15749 				act_cnt->next_mtr_id = next_fm->meter_id;
15750 				act_cnt->next_sub_policy = NULL;
15751 				mtr_policy->is_hierarchy = 1;
15752 				mtr_policy->dev = next_policy->dev;
15753 				action_flags |=
15754 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
15755 				break;
15756 			}
15757 			default:
15758 				return -rte_mtr_error_set(error, ENOTSUP,
15759 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
15760 					  NULL, "action type not supported");
15761 			}
15762 			if (action_flags & MLX5_FLOW_ACTION_SET_TAG) {
15763 				/* create modify action if needed. */
15764 				dev_flow.dv.group = 1;
15765 				if (flow_dv_modify_hdr_resource_register
15766 					(dev, mhdr_res, &dev_flow, &flow_err))
15767 					return -rte_mtr_error_set(error,
15768 						ENOTSUP,
15769 						RTE_MTR_ERROR_TYPE_METER_POLICY,
15770 						NULL, "cannot register policy "
15771 						"set tag action");
15772 				act_cnt->modify_hdr =
15773 					dev_flow.handle->dvh.modify_hdr;
15774 			}
15775 		}
15776 	}
15777 	return 0;
15778 }
15779 
15780 /**
15781  * Create policy action per domain, lock free,
15782  * (mutex should be acquired by caller).
15783  * Dispatcher for action type specific call.
15784  *
15785  * @param[in] dev
15786  *   Pointer to the Ethernet device structure.
15787  * @param[in] mtr_policy
15788  *   Meter policy struct.
15789  * @param[in] action
15790  *   Action specification used to create meter actions.
15791  * @param[out] error
15792  *   Perform verbose error reporting if not NULL. Initialized in case of
15793  *   error only.
15794  *
15795  * @return
15796  *   0 on success, otherwise negative errno value.
15797  */
15798 static int
15799 flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
15800 		      struct mlx5_flow_meter_policy *mtr_policy,
15801 		      const struct rte_flow_action *actions[RTE_COLORS],
15802 		      struct rte_mtr_error *error)
15803 {
15804 	int ret, i;
15805 	uint16_t sub_policy_num;
15806 
15807 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
15808 		sub_policy_num = (mtr_policy->sub_policy_num >>
15809 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
15810 			MLX5_MTR_SUB_POLICY_NUM_MASK;
15811 		if (sub_policy_num) {
15812 			ret = __flow_dv_create_domain_policy_acts(dev,
15813 				mtr_policy, actions,
15814 				(enum mlx5_meter_domain)i, error);
15815 			/* Cleaning resource is done in the caller level. */
15816 			if (ret)
15817 				return ret;
15818 		}
15819 	}
15820 	return 0;
15821 }
15822 
15823 /**
15824  * Query a DV flow rule for its statistics via DevX.
15825  *
15826  * @param[in] dev
15827  *   Pointer to Ethernet device.
15828  * @param[in] cnt_idx
15829  *   Index to the flow counter.
15830  * @param[out] data
15831  *   Data retrieved by the query.
15832  * @param[out] error
15833  *   Perform verbose error reporting if not NULL.
15834  *
15835  * @return
15836  *   0 on success, a negative errno value otherwise and rte_errno is set.
15837  */
15838 int
15839 flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data,
15840 		    struct rte_flow_error *error)
15841 {
15842 	struct mlx5_priv *priv = dev->data->dev_private;
15843 	struct rte_flow_query_count *qc = data;
15844 
15845 	if (!priv->sh->devx)
15846 		return rte_flow_error_set(error, ENOTSUP,
15847 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15848 					  NULL,
15849 					  "counters are not supported");
15850 	if (cnt_idx) {
15851 		uint64_t pkts, bytes;
15852 		struct mlx5_flow_counter *cnt;
15853 		int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes);
15854 
15855 		if (err)
15856 			return rte_flow_error_set(error, -err,
15857 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15858 					NULL, "cannot read counters");
15859 		cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL);
15860 		qc->hits_set = 1;
15861 		qc->bytes_set = 1;
15862 		qc->hits = pkts - cnt->hits;
15863 		qc->bytes = bytes - cnt->bytes;
15864 		if (qc->reset) {
15865 			cnt->hits = pkts;
15866 			cnt->bytes = bytes;
15867 		}
15868 		return 0;
15869 	}
15870 	return rte_flow_error_set(error, EINVAL,
15871 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15872 				  NULL,
15873 				  "counters are not available");
15874 }
15875 
15876 
15877 /**
15878  * Query counter's action pointer for a DV flow rule via DevX.
15879  *
15880  * @param[in] dev
15881  *   Pointer to Ethernet device.
15882  * @param[in] cnt_idx
15883  *   Index to the flow counter.
15884  * @param[out] action_ptr
15885  *   Action pointer for counter.
15886  * @param[out] error
15887  *   Perform verbose error reporting if not NULL.
15888  *
15889  * @return
15890  *   0 on success, a negative errno value otherwise and rte_errno is set.
15891  */
15892 int
15893 flow_dv_query_count_ptr(struct rte_eth_dev *dev, uint32_t cnt_idx,
15894 	void **action_ptr, struct rte_flow_error *error)
15895 {
15896 	struct mlx5_priv *priv = dev->data->dev_private;
15897 
15898 	if (!priv->sh->devx || !action_ptr)
15899 		return rte_flow_error_set(error, ENOTSUP,
15900 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15901 					  NULL,
15902 					  "counters are not supported");
15903 
15904 	if (cnt_idx) {
15905 		struct mlx5_flow_counter *cnt = NULL;
15906 		cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL);
15907 		if (cnt) {
15908 			*action_ptr = cnt->action;
15909 			return 0;
15910 		}
15911 	}
15912 	return rte_flow_error_set(error, EINVAL,
15913 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15914 				  NULL,
15915 				  "counters are not available");
15916 }
15917 
15918 static int
15919 flow_dv_action_query(struct rte_eth_dev *dev,
15920 		     const struct rte_flow_action_handle *handle, void *data,
15921 		     struct rte_flow_error *error)
15922 {
15923 	struct mlx5_age_param *age_param;
15924 	struct rte_flow_query_age *resp;
15925 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15926 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15927 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15928 	struct mlx5_priv *priv = dev->data->dev_private;
15929 	struct mlx5_aso_ct_action *ct;
15930 	uint16_t owner;
15931 	uint32_t dev_idx;
15932 
15933 	switch (type) {
15934 	case MLX5_INDIRECT_ACTION_TYPE_AGE:
15935 		age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params;
15936 		resp = data;
15937 		resp->aged = __atomic_load_n(&age_param->state,
15938 					      __ATOMIC_RELAXED) == AGE_TMOUT ?
15939 									  1 : 0;
15940 		resp->sec_since_last_hit_valid = !resp->aged;
15941 		if (resp->sec_since_last_hit_valid)
15942 			resp->sec_since_last_hit = __atomic_load_n
15943 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
15944 		return 0;
15945 	case MLX5_INDIRECT_ACTION_TYPE_COUNT:
15946 		return flow_dv_query_count(dev, idx, data, error);
15947 	case MLX5_INDIRECT_ACTION_TYPE_CT:
15948 		owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
15949 		if (owner != PORT_ID(priv))
15950 			return rte_flow_error_set(error, EACCES,
15951 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15952 					NULL,
15953 					"CT object owned by another port");
15954 		dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
15955 		ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
15956 		MLX5_ASSERT(ct);
15957 		if (!ct->refcnt)
15958 			return rte_flow_error_set(error, EFAULT,
15959 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15960 					NULL,
15961 					"CT object is inactive");
15962 		((struct rte_flow_action_conntrack *)data)->peer_port =
15963 							ct->peer;
15964 		((struct rte_flow_action_conntrack *)data)->is_original_dir =
15965 							ct->is_original;
15966 		if (mlx5_aso_ct_query_by_wqe(priv->sh, ct, data))
15967 			return rte_flow_error_set(error, EIO,
15968 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15969 					NULL,
15970 					"Failed to query CT context");
15971 		return 0;
15972 	default:
15973 		return rte_flow_error_set(error, ENOTSUP,
15974 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15975 					  "action type query not supported");
15976 	}
15977 }
15978 
15979 /**
15980  * Query a flow rule AGE action for aging information.
15981  *
15982  * @param[in] dev
15983  *   Pointer to Ethernet device.
15984  * @param[in] flow
15985  *   Pointer to the sub flow.
15986  * @param[out] data
15987  *   data retrieved by the query.
15988  * @param[out] error
15989  *   Perform verbose error reporting if not NULL.
15990  *
15991  * @return
15992  *   0 on success, a negative errno value otherwise and rte_errno is set.
15993  */
15994 static int
15995 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow,
15996 		  void *data, struct rte_flow_error *error)
15997 {
15998 	struct rte_flow_query_age *resp = data;
15999 	struct mlx5_age_param *age_param;
16000 
16001 	if (flow->age) {
16002 		struct mlx5_aso_age_action *act =
16003 				     flow_aso_age_get_by_idx(dev, flow->age);
16004 
16005 		age_param = &act->age_params;
16006 	} else if (flow->counter) {
16007 		age_param = flow_dv_counter_idx_get_age(dev, flow->counter);
16008 
16009 		if (!age_param || !age_param->timeout)
16010 			return rte_flow_error_set
16011 					(error, EINVAL,
16012 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16013 					 NULL, "cannot read age data");
16014 	} else {
16015 		return rte_flow_error_set(error, EINVAL,
16016 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16017 					  NULL, "age data not available");
16018 	}
16019 	resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) ==
16020 				     AGE_TMOUT ? 1 : 0;
16021 	resp->sec_since_last_hit_valid = !resp->aged;
16022 	if (resp->sec_since_last_hit_valid)
16023 		resp->sec_since_last_hit = __atomic_load_n
16024 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
16025 	return 0;
16026 }
16027 
16028 /**
16029  * Query a flow.
16030  *
16031  * @see rte_flow_query()
16032  * @see rte_flow_ops
16033  */
16034 static int
16035 flow_dv_query(struct rte_eth_dev *dev,
16036 	      struct rte_flow *flow __rte_unused,
16037 	      const struct rte_flow_action *actions __rte_unused,
16038 	      void *data __rte_unused,
16039 	      struct rte_flow_error *error __rte_unused)
16040 {
16041 	int ret = -EINVAL;
16042 
16043 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
16044 		switch (actions->type) {
16045 		case RTE_FLOW_ACTION_TYPE_VOID:
16046 			break;
16047 		case RTE_FLOW_ACTION_TYPE_COUNT:
16048 			ret = flow_dv_query_count(dev, flow->counter, data,
16049 						  error);
16050 			break;
16051 		case RTE_FLOW_ACTION_TYPE_AGE:
16052 			ret = flow_dv_query_age(dev, flow, data, error);
16053 			break;
16054 		default:
16055 			return rte_flow_error_set(error, ENOTSUP,
16056 						  RTE_FLOW_ERROR_TYPE_ACTION,
16057 						  actions,
16058 						  "action not supported");
16059 		}
16060 	}
16061 	return ret;
16062 }
16063 
16064 /**
16065  * Destroy the meter table set.
16066  * Lock free, (mutex should be acquired by caller).
16067  *
16068  * @param[in] dev
16069  *   Pointer to Ethernet device.
16070  * @param[in] fm
16071  *   Meter information table.
16072  */
16073 static void
16074 flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
16075 			struct mlx5_flow_meter_info *fm)
16076 {
16077 	struct mlx5_priv *priv = dev->data->dev_private;
16078 	int i;
16079 
16080 	if (!fm || !priv->config.dv_flow_en)
16081 		return;
16082 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16083 		if (fm->drop_rule[i]) {
16084 			claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
16085 			fm->drop_rule[i] = NULL;
16086 		}
16087 	}
16088 }
16089 
16090 static void
16091 flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
16092 {
16093 	struct mlx5_priv *priv = dev->data->dev_private;
16094 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16095 	struct mlx5_flow_tbl_data_entry *tbl;
16096 	int i, j;
16097 
16098 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16099 		if (mtrmng->def_rule[i]) {
16100 			claim_zero(mlx5_flow_os_destroy_flow
16101 					(mtrmng->def_rule[i]));
16102 			mtrmng->def_rule[i] = NULL;
16103 		}
16104 		if (mtrmng->def_matcher[i]) {
16105 			tbl = container_of(mtrmng->def_matcher[i]->tbl,
16106 				struct mlx5_flow_tbl_data_entry, tbl);
16107 			mlx5_list_unregister(tbl->matchers,
16108 					     &mtrmng->def_matcher[i]->entry);
16109 			mtrmng->def_matcher[i] = NULL;
16110 		}
16111 		for (j = 0; j < MLX5_REG_BITS; j++) {
16112 			if (mtrmng->drop_matcher[i][j]) {
16113 				tbl =
16114 				container_of(mtrmng->drop_matcher[i][j]->tbl,
16115 					     struct mlx5_flow_tbl_data_entry,
16116 					     tbl);
16117 				mlx5_list_unregister(tbl->matchers,
16118 					    &mtrmng->drop_matcher[i][j]->entry);
16119 				mtrmng->drop_matcher[i][j] = NULL;
16120 			}
16121 		}
16122 		if (mtrmng->drop_tbl[i]) {
16123 			flow_dv_tbl_resource_release(MLX5_SH(dev),
16124 				mtrmng->drop_tbl[i]);
16125 			mtrmng->drop_tbl[i] = NULL;
16126 		}
16127 	}
16128 }
16129 
16130 /* Number of meter flow actions, count and jump or count and drop. */
16131 #define METER_ACTIONS 2
16132 
16133 static void
16134 __flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
16135 				    enum mlx5_meter_domain domain)
16136 {
16137 	struct mlx5_priv *priv = dev->data->dev_private;
16138 	struct mlx5_flow_meter_def_policy *def_policy =
16139 			priv->sh->mtrmng->def_policy[domain];
16140 
16141 	__flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
16142 	mlx5_free(def_policy);
16143 	priv->sh->mtrmng->def_policy[domain] = NULL;
16144 }
16145 
16146 /**
16147  * Destroy the default policy table set.
16148  *
16149  * @param[in] dev
16150  *   Pointer to Ethernet device.
16151  */
16152 static void
16153 flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
16154 {
16155 	struct mlx5_priv *priv = dev->data->dev_private;
16156 	int i;
16157 
16158 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
16159 		if (priv->sh->mtrmng->def_policy[i])
16160 			__flow_dv_destroy_domain_def_policy(dev,
16161 					(enum mlx5_meter_domain)i);
16162 	priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
16163 }
16164 
16165 static int
16166 __flow_dv_create_policy_flow(struct rte_eth_dev *dev,
16167 			uint32_t color_reg_c_idx,
16168 			enum rte_color color, void *matcher_object,
16169 			int actions_n, void *actions,
16170 			bool match_src_port, const struct rte_flow_item *item,
16171 			void **rule, const struct rte_flow_attr *attr)
16172 {
16173 	int ret;
16174 	struct mlx5_flow_dv_match_params value = {
16175 		.size = sizeof(value.buf),
16176 	};
16177 	struct mlx5_flow_dv_match_params matcher = {
16178 		.size = sizeof(matcher.buf),
16179 	};
16180 	struct mlx5_priv *priv = dev->data->dev_private;
16181 	uint8_t misc_mask;
16182 
16183 	if (match_src_port && (priv->representor || priv->master)) {
16184 		if (flow_dv_translate_item_port_id(dev, matcher.buf,
16185 						   value.buf, item, attr)) {
16186 			DRV_LOG(ERR, "Failed to create meter policy%d flow's"
16187 				" value with port.", color);
16188 			return -1;
16189 		}
16190 	}
16191 	flow_dv_match_meta_reg(matcher.buf, value.buf,
16192 			       (enum modify_reg)color_reg_c_idx,
16193 			       rte_col_2_mlx5_col(color), UINT32_MAX);
16194 	misc_mask = flow_dv_matcher_enable(value.buf);
16195 	__flow_dv_adjust_buf_size(&value.size, misc_mask);
16196 	ret = mlx5_flow_os_create_flow(matcher_object, (void *)&value,
16197 				       actions_n, actions, rule);
16198 	if (ret) {
16199 		DRV_LOG(ERR, "Failed to create meter policy%d flow.", color);
16200 		return -1;
16201 	}
16202 	return 0;
16203 }
16204 
16205 static int
16206 __flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
16207 			uint32_t color_reg_c_idx,
16208 			uint16_t priority,
16209 			struct mlx5_flow_meter_sub_policy *sub_policy,
16210 			const struct rte_flow_attr *attr,
16211 			bool match_src_port,
16212 			const struct rte_flow_item *item,
16213 			struct mlx5_flow_dv_matcher **policy_matcher,
16214 			struct rte_flow_error *error)
16215 {
16216 	struct mlx5_list_entry *entry;
16217 	struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
16218 	struct mlx5_flow_dv_matcher matcher = {
16219 		.mask = {
16220 			.size = sizeof(matcher.mask.buf),
16221 		},
16222 		.tbl = tbl_rsc,
16223 	};
16224 	struct mlx5_flow_dv_match_params value = {
16225 		.size = sizeof(value.buf),
16226 	};
16227 	struct mlx5_flow_cb_ctx ctx = {
16228 		.error = error,
16229 		.data = &matcher,
16230 	};
16231 	struct mlx5_flow_tbl_data_entry *tbl_data;
16232 	struct mlx5_priv *priv = dev->data->dev_private;
16233 	const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
16234 
16235 	if (match_src_port && (priv->representor || priv->master)) {
16236 		if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
16237 						   value.buf, item, attr)) {
16238 			DRV_LOG(ERR, "Failed to register meter policy%d matcher"
16239 				" with port.", priority);
16240 			return -1;
16241 		}
16242 	}
16243 	tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
16244 	if (priority < RTE_COLOR_RED)
16245 		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16246 			(enum modify_reg)color_reg_c_idx, 0, color_mask);
16247 	matcher.priority = priority;
16248 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
16249 				    matcher.mask.size);
16250 	entry = mlx5_list_register(tbl_data->matchers, &ctx);
16251 	if (!entry) {
16252 		DRV_LOG(ERR, "Failed to register meter drop matcher.");
16253 		return -1;
16254 	}
16255 	*policy_matcher =
16256 		container_of(entry, struct mlx5_flow_dv_matcher, entry);
16257 	return 0;
16258 }
16259 
16260 /**
16261  * Create the policy rules per domain.
16262  *
16263  * @param[in] dev
16264  *   Pointer to Ethernet device.
16265  * @param[in] sub_policy
16266  *    Pointer to sub policy table..
16267  * @param[in] egress
16268  *   Direction of the table.
16269  * @param[in] transfer
16270  *   E-Switch or NIC flow.
16271  * @param[in] acts
16272  *   Pointer to policy action list per color.
16273  *
16274  * @return
16275  *   0 on success, -1 otherwise.
16276  */
16277 static int
16278 __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
16279 		struct mlx5_flow_meter_sub_policy *sub_policy,
16280 		uint8_t egress, uint8_t transfer, bool match_src_port,
16281 		struct mlx5_meter_policy_acts acts[RTE_COLORS])
16282 {
16283 	struct mlx5_priv *priv = dev->data->dev_private;
16284 	struct rte_flow_error flow_err;
16285 	uint32_t color_reg_c_idx;
16286 	struct rte_flow_attr attr = {
16287 		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
16288 		.priority = 0,
16289 		.ingress = 0,
16290 		.egress = !!egress,
16291 		.transfer = !!transfer,
16292 		.reserved = 0,
16293 	};
16294 	int i;
16295 	int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
16296 	struct mlx5_sub_policy_color_rule *color_rule;
16297 	bool svport_match;
16298 	struct mlx5_sub_policy_color_rule *tmp_rules[RTE_COLORS] = {NULL};
16299 
16300 	if (ret < 0)
16301 		return -1;
16302 	/* Create policy table with POLICY level. */
16303 	if (!sub_policy->tbl_rsc)
16304 		sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
16305 				MLX5_FLOW_TABLE_LEVEL_POLICY,
16306 				egress, transfer, false, NULL, 0, 0,
16307 				sub_policy->idx, &flow_err);
16308 	if (!sub_policy->tbl_rsc) {
16309 		DRV_LOG(ERR,
16310 			"Failed to create meter sub policy table.");
16311 		return -1;
16312 	}
16313 	/* Prepare matchers. */
16314 	color_reg_c_idx = ret;
16315 	for (i = 0; i < RTE_COLORS; i++) {
16316 		TAILQ_INIT(&sub_policy->color_rules[i]);
16317 		if (!acts[i].actions_n)
16318 			continue;
16319 		color_rule = mlx5_malloc(MLX5_MEM_ZERO,
16320 				sizeof(struct mlx5_sub_policy_color_rule),
16321 				0, SOCKET_ID_ANY);
16322 		if (!color_rule) {
16323 			DRV_LOG(ERR, "No memory to create color rule.");
16324 			goto err_exit;
16325 		}
16326 		tmp_rules[i] = color_rule;
16327 		TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
16328 				  color_rule, next_port);
16329 		color_rule->src_port = priv->representor_id;
16330 		/* No use. */
16331 		attr.priority = i;
16332 		/* Create matchers for colors. */
16333 		svport_match = (i != RTE_COLOR_RED) ? match_src_port : false;
16334 		if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
16335 				MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
16336 				&attr, svport_match, NULL,
16337 				&color_rule->matcher, &flow_err)) {
16338 			DRV_LOG(ERR, "Failed to create color%u matcher.", i);
16339 			goto err_exit;
16340 		}
16341 		/* Create flow, matching color. */
16342 		if (__flow_dv_create_policy_flow(dev,
16343 				color_reg_c_idx, (enum rte_color)i,
16344 				color_rule->matcher->matcher_object,
16345 				acts[i].actions_n, acts[i].dv_actions,
16346 				svport_match, NULL, &color_rule->rule,
16347 				&attr)) {
16348 			DRV_LOG(ERR, "Failed to create color%u rule.", i);
16349 			goto err_exit;
16350 		}
16351 	}
16352 	return 0;
16353 err_exit:
16354 	/* All the policy rules will be cleared. */
16355 	do {
16356 		color_rule = tmp_rules[i];
16357 		if (color_rule) {
16358 			if (color_rule->rule)
16359 				mlx5_flow_os_destroy_flow(color_rule->rule);
16360 			if (color_rule->matcher) {
16361 				struct mlx5_flow_tbl_data_entry *tbl =
16362 					container_of(color_rule->matcher->tbl,
16363 						     typeof(*tbl), tbl);
16364 				mlx5_list_unregister(tbl->matchers,
16365 						&color_rule->matcher->entry);
16366 			}
16367 			TAILQ_REMOVE(&sub_policy->color_rules[i],
16368 				     color_rule, next_port);
16369 			mlx5_free(color_rule);
16370 		}
16371 	} while (i--);
16372 	return -1;
16373 }
16374 
16375 static int
16376 __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
16377 			struct mlx5_flow_meter_policy *mtr_policy,
16378 			struct mlx5_flow_meter_sub_policy *sub_policy,
16379 			uint32_t domain)
16380 {
16381 	struct mlx5_priv *priv = dev->data->dev_private;
16382 	struct mlx5_meter_policy_acts acts[RTE_COLORS];
16383 	struct mlx5_flow_dv_tag_resource *tag;
16384 	struct mlx5_flow_dv_port_id_action_resource *port_action;
16385 	struct mlx5_hrxq *hrxq;
16386 	struct mlx5_flow_meter_info *next_fm = NULL;
16387 	struct mlx5_flow_meter_policy *next_policy;
16388 	struct mlx5_flow_meter_sub_policy *next_sub_policy;
16389 	struct mlx5_flow_tbl_data_entry *tbl_data;
16390 	struct rte_flow_error error;
16391 	uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16392 	uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16393 	bool mtr_first = egress || (transfer && priv->representor_id != UINT16_MAX);
16394 	bool match_src_port = false;
16395 	int i;
16396 
16397 	/* If RSS or Queue, no previous actions / rules is created. */
16398 	for (i = 0; i < RTE_COLORS; i++) {
16399 		acts[i].actions_n = 0;
16400 		if (i == RTE_COLOR_RED) {
16401 			/* Only support drop on red. */
16402 			acts[i].dv_actions[0] =
16403 				mtr_policy->dr_drop_action[domain];
16404 			acts[i].actions_n = 1;
16405 			continue;
16406 		}
16407 		if (i == RTE_COLOR_GREEN &&
16408 		    mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) {
16409 			struct rte_flow_attr attr = {
16410 				.transfer = transfer
16411 			};
16412 
16413 			next_fm = mlx5_flow_meter_find(priv,
16414 					mtr_policy->act_cnt[i].next_mtr_id,
16415 					NULL);
16416 			if (!next_fm) {
16417 				DRV_LOG(ERR,
16418 					"Failed to get next hierarchy meter.");
16419 				goto err_exit;
16420 			}
16421 			if (mlx5_flow_meter_attach(priv, next_fm,
16422 						   &attr, &error)) {
16423 				DRV_LOG(ERR, "%s", error.message);
16424 				next_fm = NULL;
16425 				goto err_exit;
16426 			}
16427 			/* Meter action must be the first for TX. */
16428 			if (mtr_first) {
16429 				acts[i].dv_actions[acts[i].actions_n] =
16430 					next_fm->meter_action;
16431 				acts[i].actions_n++;
16432 			}
16433 		}
16434 		if (mtr_policy->act_cnt[i].rix_mark) {
16435 			tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
16436 					mtr_policy->act_cnt[i].rix_mark);
16437 			if (!tag) {
16438 				DRV_LOG(ERR, "Failed to find "
16439 				"mark action for policy.");
16440 				goto err_exit;
16441 			}
16442 			acts[i].dv_actions[acts[i].actions_n] = tag->action;
16443 			acts[i].actions_n++;
16444 		}
16445 		if (mtr_policy->act_cnt[i].modify_hdr) {
16446 			acts[i].dv_actions[acts[i].actions_n] =
16447 				mtr_policy->act_cnt[i].modify_hdr->action;
16448 			acts[i].actions_n++;
16449 		}
16450 		if (mtr_policy->act_cnt[i].fate_action) {
16451 			switch (mtr_policy->act_cnt[i].fate_action) {
16452 			case MLX5_FLOW_FATE_PORT_ID:
16453 				port_action = mlx5_ipool_get
16454 					(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
16455 				mtr_policy->act_cnt[i].rix_port_id_action);
16456 				if (!port_action) {
16457 					DRV_LOG(ERR, "Failed to find "
16458 						"port action for policy.");
16459 					goto err_exit;
16460 				}
16461 				acts[i].dv_actions[acts[i].actions_n] =
16462 					port_action->action;
16463 				acts[i].actions_n++;
16464 				mtr_policy->dev = dev;
16465 				match_src_port = true;
16466 				break;
16467 			case MLX5_FLOW_FATE_DROP:
16468 			case MLX5_FLOW_FATE_JUMP:
16469 				acts[i].dv_actions[acts[i].actions_n] =
16470 				mtr_policy->act_cnt[i].dr_jump_action[domain];
16471 				acts[i].actions_n++;
16472 				break;
16473 			case MLX5_FLOW_FATE_SHARED_RSS:
16474 			case MLX5_FLOW_FATE_QUEUE:
16475 				hrxq = mlx5_ipool_get
16476 					(priv->sh->ipool[MLX5_IPOOL_HRXQ],
16477 					 sub_policy->rix_hrxq[i]);
16478 				if (!hrxq) {
16479 					DRV_LOG(ERR, "Failed to find "
16480 						"queue action for policy.");
16481 					goto err_exit;
16482 				}
16483 				acts[i].dv_actions[acts[i].actions_n] =
16484 					hrxq->action;
16485 				acts[i].actions_n++;
16486 				break;
16487 			case MLX5_FLOW_FATE_MTR:
16488 				if (!next_fm) {
16489 					DRV_LOG(ERR,
16490 						"No next hierarchy meter.");
16491 					goto err_exit;
16492 				}
16493 				if (!mtr_first) {
16494 					acts[i].dv_actions[acts[i].actions_n] =
16495 							next_fm->meter_action;
16496 					acts[i].actions_n++;
16497 				}
16498 				if (mtr_policy->act_cnt[i].next_sub_policy) {
16499 					next_sub_policy =
16500 					mtr_policy->act_cnt[i].next_sub_policy;
16501 				} else {
16502 					next_policy =
16503 						mlx5_flow_meter_policy_find(dev,
16504 						next_fm->policy_id, NULL);
16505 					MLX5_ASSERT(next_policy);
16506 					next_sub_policy =
16507 					next_policy->sub_policys[domain][0];
16508 				}
16509 				tbl_data =
16510 					container_of(next_sub_policy->tbl_rsc,
16511 					struct mlx5_flow_tbl_data_entry, tbl);
16512 				acts[i].dv_actions[acts[i].actions_n++] =
16513 							tbl_data->jump.action;
16514 				if (mtr_policy->act_cnt[i].modify_hdr)
16515 					match_src_port = !!transfer;
16516 				break;
16517 			default:
16518 				/*Queue action do nothing*/
16519 				break;
16520 			}
16521 		}
16522 	}
16523 	if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
16524 				egress, transfer, match_src_port, acts)) {
16525 		DRV_LOG(ERR,
16526 			"Failed to create policy rules per domain.");
16527 		goto err_exit;
16528 	}
16529 	return 0;
16530 err_exit:
16531 	if (next_fm)
16532 		mlx5_flow_meter_detach(priv, next_fm);
16533 	return -1;
16534 }
16535 
16536 /**
16537  * Create the policy rules.
16538  *
16539  * @param[in] dev
16540  *   Pointer to Ethernet device.
16541  * @param[in,out] mtr_policy
16542  *   Pointer to meter policy table.
16543  *
16544  * @return
16545  *   0 on success, -1 otherwise.
16546  */
16547 static int
16548 flow_dv_create_policy_rules(struct rte_eth_dev *dev,
16549 			     struct mlx5_flow_meter_policy *mtr_policy)
16550 {
16551 	int i;
16552 	uint16_t sub_policy_num;
16553 
16554 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16555 		sub_policy_num = (mtr_policy->sub_policy_num >>
16556 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
16557 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16558 		if (!sub_policy_num)
16559 			continue;
16560 		/* Prepare actions list and create policy rules. */
16561 		if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
16562 			mtr_policy->sub_policys[i][0], i)) {
16563 			DRV_LOG(ERR, "Failed to create policy action "
16564 				"list per domain.");
16565 			return -1;
16566 		}
16567 	}
16568 	return 0;
16569 }
16570 
16571 static int
16572 __flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
16573 {
16574 	struct mlx5_priv *priv = dev->data->dev_private;
16575 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16576 	struct mlx5_flow_meter_def_policy *def_policy;
16577 	struct mlx5_flow_tbl_resource *jump_tbl;
16578 	struct mlx5_flow_tbl_data_entry *tbl_data;
16579 	uint8_t egress, transfer;
16580 	struct rte_flow_error error;
16581 	struct mlx5_meter_policy_acts acts[RTE_COLORS];
16582 	int ret;
16583 
16584 	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16585 	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16586 	def_policy = mtrmng->def_policy[domain];
16587 	if (!def_policy) {
16588 		def_policy = mlx5_malloc(MLX5_MEM_ZERO,
16589 			sizeof(struct mlx5_flow_meter_def_policy),
16590 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
16591 		if (!def_policy) {
16592 			DRV_LOG(ERR, "Failed to alloc default policy table.");
16593 			goto def_policy_error;
16594 		}
16595 		mtrmng->def_policy[domain] = def_policy;
16596 		/* Create the meter suffix table with SUFFIX level. */
16597 		jump_tbl = flow_dv_tbl_resource_get(dev,
16598 				MLX5_FLOW_TABLE_LEVEL_METER,
16599 				egress, transfer, false, NULL, 0,
16600 				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
16601 		if (!jump_tbl) {
16602 			DRV_LOG(ERR,
16603 				"Failed to create meter suffix table.");
16604 			goto def_policy_error;
16605 		}
16606 		def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
16607 		tbl_data = container_of(jump_tbl,
16608 					struct mlx5_flow_tbl_data_entry, tbl);
16609 		def_policy->dr_jump_action[RTE_COLOR_GREEN] =
16610 						tbl_data->jump.action;
16611 		acts[RTE_COLOR_GREEN].dv_actions[0] = tbl_data->jump.action;
16612 		acts[RTE_COLOR_GREEN].actions_n = 1;
16613 		/*
16614 		 * YELLOW has the same default policy as GREEN does.
16615 		 * G & Y share the same table and action. The 2nd time of table
16616 		 * resource getting is just to update the reference count for
16617 		 * the releasing stage.
16618 		 */
16619 		jump_tbl = flow_dv_tbl_resource_get(dev,
16620 				MLX5_FLOW_TABLE_LEVEL_METER,
16621 				egress, transfer, false, NULL, 0,
16622 				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
16623 		if (!jump_tbl) {
16624 			DRV_LOG(ERR,
16625 				"Failed to get meter suffix table.");
16626 			goto def_policy_error;
16627 		}
16628 		def_policy->sub_policy.jump_tbl[RTE_COLOR_YELLOW] = jump_tbl;
16629 		tbl_data = container_of(jump_tbl,
16630 					struct mlx5_flow_tbl_data_entry, tbl);
16631 		def_policy->dr_jump_action[RTE_COLOR_YELLOW] =
16632 						tbl_data->jump.action;
16633 		acts[RTE_COLOR_YELLOW].dv_actions[0] = tbl_data->jump.action;
16634 		acts[RTE_COLOR_YELLOW].actions_n = 1;
16635 		/* Create jump action to the drop table. */
16636 		if (!mtrmng->drop_tbl[domain]) {
16637 			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
16638 				(dev, MLX5_FLOW_TABLE_LEVEL_METER,
16639 				 egress, transfer, false, NULL, 0,
16640 				 0, MLX5_MTR_TABLE_ID_DROP, &error);
16641 			if (!mtrmng->drop_tbl[domain]) {
16642 				DRV_LOG(ERR, "Failed to create meter "
16643 					"drop table for default policy.");
16644 				goto def_policy_error;
16645 			}
16646 		}
16647 		/* all RED: unique Drop table for jump action. */
16648 		tbl_data = container_of(mtrmng->drop_tbl[domain],
16649 					struct mlx5_flow_tbl_data_entry, tbl);
16650 		def_policy->dr_jump_action[RTE_COLOR_RED] =
16651 						tbl_data->jump.action;
16652 		acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
16653 		acts[RTE_COLOR_RED].actions_n = 1;
16654 		/* Create default policy rules. */
16655 		ret = __flow_dv_create_domain_policy_rules(dev,
16656 					&def_policy->sub_policy,
16657 					egress, transfer, false, acts);
16658 		if (ret) {
16659 			DRV_LOG(ERR, "Failed to create default policy rules.");
16660 			goto def_policy_error;
16661 		}
16662 	}
16663 	return 0;
16664 def_policy_error:
16665 	__flow_dv_destroy_domain_def_policy(dev,
16666 					    (enum mlx5_meter_domain)domain);
16667 	return -1;
16668 }
16669 
16670 /**
16671  * Create the default policy table set.
16672  *
16673  * @param[in] dev
16674  *   Pointer to Ethernet device.
16675  * @return
16676  *   0 on success, -1 otherwise.
16677  */
16678 static int
16679 flow_dv_create_def_policy(struct rte_eth_dev *dev)
16680 {
16681 	struct mlx5_priv *priv = dev->data->dev_private;
16682 	int i;
16683 
16684 	/* Non-termination policy table. */
16685 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16686 		if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER)
16687 			continue;
16688 		if (__flow_dv_create_domain_def_policy(dev, i)) {
16689 			DRV_LOG(ERR, "Failed to create default policy");
16690 			/* Rollback the created default policies for others. */
16691 			flow_dv_destroy_def_policy(dev);
16692 			return -1;
16693 		}
16694 	}
16695 	return 0;
16696 }
16697 
16698 /**
16699  * Create the needed meter tables.
16700  * Lock free, (mutex should be acquired by caller).
16701  *
16702  * @param[in] dev
16703  *   Pointer to Ethernet device.
16704  * @param[in] fm
16705  *   Meter information table.
16706  * @param[in] mtr_idx
16707  *   Meter index.
16708  * @param[in] domain_bitmap
16709  *   Domain bitmap.
16710  * @return
16711  *   0 on success, -1 otherwise.
16712  */
16713 static int
16714 flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
16715 			struct mlx5_flow_meter_info *fm,
16716 			uint32_t mtr_idx,
16717 			uint8_t domain_bitmap)
16718 {
16719 	struct mlx5_priv *priv = dev->data->dev_private;
16720 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16721 	struct rte_flow_error error;
16722 	struct mlx5_flow_tbl_data_entry *tbl_data;
16723 	uint8_t egress, transfer;
16724 	void *actions[METER_ACTIONS];
16725 	int domain, ret, i;
16726 	struct mlx5_flow_counter *cnt;
16727 	struct mlx5_flow_dv_match_params value = {
16728 		.size = sizeof(value.buf),
16729 	};
16730 	struct mlx5_flow_dv_match_params matcher_para = {
16731 		.size = sizeof(matcher_para.buf),
16732 	};
16733 	int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
16734 						     0, &error);
16735 	uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1;
16736 	uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
16737 	struct mlx5_list_entry *entry;
16738 	struct mlx5_flow_dv_matcher matcher = {
16739 		.mask = {
16740 			.size = sizeof(matcher.mask.buf),
16741 		},
16742 	};
16743 	struct mlx5_flow_dv_matcher *drop_matcher;
16744 	struct mlx5_flow_cb_ctx ctx = {
16745 		.error = &error,
16746 		.data = &matcher,
16747 	};
16748 	uint8_t misc_mask;
16749 
16750 	if (!priv->mtr_en || mtr_id_reg_c < 0) {
16751 		rte_errno = ENOTSUP;
16752 		return -1;
16753 	}
16754 	for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
16755 		if (!(domain_bitmap & (1 << domain)) ||
16756 			(mtrmng->def_rule[domain] && !fm->drop_cnt))
16757 			continue;
16758 		egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16759 		transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16760 		/* Create the drop table with METER DROP level. */
16761 		if (!mtrmng->drop_tbl[domain]) {
16762 			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev,
16763 					MLX5_FLOW_TABLE_LEVEL_METER,
16764 					egress, transfer, false, NULL, 0,
16765 					0, MLX5_MTR_TABLE_ID_DROP, &error);
16766 			if (!mtrmng->drop_tbl[domain]) {
16767 				DRV_LOG(ERR, "Failed to create meter drop table.");
16768 				goto policy_error;
16769 			}
16770 		}
16771 		/* Create default matcher in drop table. */
16772 		matcher.tbl = mtrmng->drop_tbl[domain],
16773 		tbl_data = container_of(mtrmng->drop_tbl[domain],
16774 				struct mlx5_flow_tbl_data_entry, tbl);
16775 		if (!mtrmng->def_matcher[domain]) {
16776 			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16777 				       (enum modify_reg)mtr_id_reg_c,
16778 				       0, 0);
16779 			matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
16780 			matcher.crc = rte_raw_cksum
16781 					((const void *)matcher.mask.buf,
16782 					matcher.mask.size);
16783 			entry = mlx5_list_register(tbl_data->matchers, &ctx);
16784 			if (!entry) {
16785 				DRV_LOG(ERR, "Failed to register meter "
16786 				"drop default matcher.");
16787 				goto policy_error;
16788 			}
16789 			mtrmng->def_matcher[domain] = container_of(entry,
16790 			struct mlx5_flow_dv_matcher, entry);
16791 		}
16792 		/* Create default rule in drop table. */
16793 		if (!mtrmng->def_rule[domain]) {
16794 			i = 0;
16795 			actions[i++] = priv->sh->dr_drop_action;
16796 			flow_dv_match_meta_reg(matcher_para.buf, value.buf,
16797 				(enum modify_reg)mtr_id_reg_c, 0, 0);
16798 			misc_mask = flow_dv_matcher_enable(value.buf);
16799 			__flow_dv_adjust_buf_size(&value.size, misc_mask);
16800 			ret = mlx5_flow_os_create_flow
16801 				(mtrmng->def_matcher[domain]->matcher_object,
16802 				(void *)&value, i, actions,
16803 				&mtrmng->def_rule[domain]);
16804 			if (ret) {
16805 				DRV_LOG(ERR, "Failed to create meter "
16806 				"default drop rule for drop table.");
16807 				goto policy_error;
16808 			}
16809 		}
16810 		if (!fm->drop_cnt)
16811 			continue;
16812 		MLX5_ASSERT(mtrmng->max_mtr_bits);
16813 		if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) {
16814 			/* Create matchers for Drop. */
16815 			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
16816 					(enum modify_reg)mtr_id_reg_c, 0,
16817 					(mtr_id_mask << mtr_id_offset));
16818 			matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
16819 			matcher.crc = rte_raw_cksum
16820 					((const void *)matcher.mask.buf,
16821 					matcher.mask.size);
16822 			entry = mlx5_list_register(tbl_data->matchers, &ctx);
16823 			if (!entry) {
16824 				DRV_LOG(ERR,
16825 				"Failed to register meter drop matcher.");
16826 				goto policy_error;
16827 			}
16828 			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] =
16829 				container_of(entry, struct mlx5_flow_dv_matcher,
16830 					     entry);
16831 		}
16832 		drop_matcher =
16833 			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1];
16834 		/* Create drop rule, matching meter_id only. */
16835 		flow_dv_match_meta_reg(matcher_para.buf, value.buf,
16836 				(enum modify_reg)mtr_id_reg_c,
16837 				(mtr_idx << mtr_id_offset), UINT32_MAX);
16838 		i = 0;
16839 		cnt = flow_dv_counter_get_by_idx(dev,
16840 					fm->drop_cnt, NULL);
16841 		actions[i++] = cnt->action;
16842 		actions[i++] = priv->sh->dr_drop_action;
16843 		misc_mask = flow_dv_matcher_enable(value.buf);
16844 		__flow_dv_adjust_buf_size(&value.size, misc_mask);
16845 		ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
16846 					       (void *)&value, i, actions,
16847 					       &fm->drop_rule[domain]);
16848 		if (ret) {
16849 			DRV_LOG(ERR, "Failed to create meter "
16850 				"drop rule for drop table.");
16851 				goto policy_error;
16852 		}
16853 	}
16854 	return 0;
16855 policy_error:
16856 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16857 		if (fm->drop_rule[i]) {
16858 			claim_zero(mlx5_flow_os_destroy_flow
16859 				(fm->drop_rule[i]));
16860 			fm->drop_rule[i] = NULL;
16861 		}
16862 	}
16863 	return -1;
16864 }
16865 
16866 static struct mlx5_flow_meter_sub_policy *
16867 __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev,
16868 		struct mlx5_flow_meter_policy *mtr_policy,
16869 		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS],
16870 		struct mlx5_flow_meter_sub_policy *next_sub_policy,
16871 		bool *is_reuse)
16872 {
16873 	struct mlx5_priv *priv = dev->data->dev_private;
16874 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
16875 	uint32_t sub_policy_idx = 0;
16876 	uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
16877 	uint32_t i, j;
16878 	struct mlx5_hrxq *hrxq;
16879 	struct mlx5_flow_handle dh;
16880 	struct mlx5_meter_policy_action_container *act_cnt;
16881 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
16882 	uint16_t sub_policy_num;
16883 
16884 	rte_spinlock_lock(&mtr_policy->sl);
16885 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16886 		if (!rss_desc[i])
16887 			continue;
16888 		hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]);
16889 		if (!hrxq_idx[i]) {
16890 			rte_spinlock_unlock(&mtr_policy->sl);
16891 			return NULL;
16892 		}
16893 	}
16894 	sub_policy_num = (mtr_policy->sub_policy_num >>
16895 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16896 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16897 	for (j = 0; j < sub_policy_num; j++) {
16898 		for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16899 			if (rss_desc[i] &&
16900 			    hrxq_idx[i] !=
16901 			    mtr_policy->sub_policys[domain][j]->rix_hrxq[i])
16902 				break;
16903 		}
16904 		if (i >= MLX5_MTR_RTE_COLORS) {
16905 			/*
16906 			 * Found the sub policy table with
16907 			 * the same queue per color.
16908 			 */
16909 			rte_spinlock_unlock(&mtr_policy->sl);
16910 			for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
16911 				mlx5_hrxq_release(dev, hrxq_idx[i]);
16912 			*is_reuse = true;
16913 			return mtr_policy->sub_policys[domain][j];
16914 		}
16915 	}
16916 	/* Create sub policy. */
16917 	if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) {
16918 		/* Reuse the first pre-allocated sub_policy. */
16919 		sub_policy = mtr_policy->sub_policys[domain][0];
16920 		sub_policy_idx = sub_policy->idx;
16921 	} else {
16922 		sub_policy = mlx5_ipool_zmalloc
16923 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16924 				 &sub_policy_idx);
16925 		if (!sub_policy ||
16926 		    sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) {
16927 			for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
16928 				mlx5_hrxq_release(dev, hrxq_idx[i]);
16929 			goto rss_sub_policy_error;
16930 		}
16931 		sub_policy->idx = sub_policy_idx;
16932 		sub_policy->main_policy = mtr_policy;
16933 	}
16934 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16935 		if (!rss_desc[i])
16936 			continue;
16937 		sub_policy->rix_hrxq[i] = hrxq_idx[i];
16938 		if (mtr_policy->is_hierarchy) {
16939 			act_cnt = &mtr_policy->act_cnt[i];
16940 			act_cnt->next_sub_policy = next_sub_policy;
16941 			mlx5_hrxq_release(dev, hrxq_idx[i]);
16942 		} else {
16943 			/*
16944 			 * Overwrite the last action from
16945 			 * RSS action to Queue action.
16946 			 */
16947 			hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
16948 					      hrxq_idx[i]);
16949 			if (!hrxq) {
16950 				DRV_LOG(ERR, "Failed to get policy hrxq");
16951 				goto rss_sub_policy_error;
16952 			}
16953 			act_cnt = &mtr_policy->act_cnt[i];
16954 			if (act_cnt->rix_mark || act_cnt->modify_hdr) {
16955 				memset(&dh, 0, sizeof(struct mlx5_flow_handle));
16956 				if (act_cnt->rix_mark)
16957 					dh.mark = 1;
16958 				dh.fate_action = MLX5_FLOW_FATE_QUEUE;
16959 				dh.rix_hrxq = hrxq_idx[i];
16960 				flow_drv_rxq_flags_set(dev, &dh);
16961 			}
16962 		}
16963 	}
16964 	if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
16965 					       sub_policy, domain)) {
16966 		DRV_LOG(ERR, "Failed to create policy "
16967 			"rules for ingress domain.");
16968 		goto rss_sub_policy_error;
16969 	}
16970 	if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16971 		i = (mtr_policy->sub_policy_num >>
16972 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16973 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16974 		if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) {
16975 			DRV_LOG(ERR, "No free sub-policy slot.");
16976 			goto rss_sub_policy_error;
16977 		}
16978 		mtr_policy->sub_policys[domain][i] = sub_policy;
16979 		i++;
16980 		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
16981 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
16982 		mtr_policy->sub_policy_num |=
16983 			(i & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
16984 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
16985 	}
16986 	rte_spinlock_unlock(&mtr_policy->sl);
16987 	*is_reuse = false;
16988 	return sub_policy;
16989 rss_sub_policy_error:
16990 	if (sub_policy) {
16991 		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
16992 		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
16993 			i = (mtr_policy->sub_policy_num >>
16994 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
16995 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16996 			mtr_policy->sub_policys[domain][i] = NULL;
16997 			mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
16998 					sub_policy->idx);
16999 		}
17000 	}
17001 	rte_spinlock_unlock(&mtr_policy->sl);
17002 	return NULL;
17003 }
17004 
17005 /**
17006  * Find the policy table for prefix table with RSS.
17007  *
17008  * @param[in] dev
17009  *   Pointer to Ethernet device.
17010  * @param[in] mtr_policy
17011  *   Pointer to meter policy table.
17012  * @param[in] rss_desc
17013  *   Pointer to rss_desc
17014  * @return
17015  *   Pointer to table set on success, NULL otherwise and rte_errno is set.
17016  */
17017 static struct mlx5_flow_meter_sub_policy *
17018 flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
17019 		struct mlx5_flow_meter_policy *mtr_policy,
17020 		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
17021 {
17022 	struct mlx5_priv *priv = dev->data->dev_private;
17023 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
17024 	struct mlx5_flow_meter_info *next_fm;
17025 	struct mlx5_flow_meter_policy *next_policy;
17026 	struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL;
17027 	struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM];
17028 	struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM];
17029 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
17030 	bool reuse_sub_policy;
17031 	uint32_t i = 0;
17032 	uint32_t j = 0;
17033 
17034 	while (true) {
17035 		/* Iterate hierarchy to get all policies in this hierarchy. */
17036 		policies[i++] = mtr_policy;
17037 		if (!mtr_policy->is_hierarchy)
17038 			break;
17039 		if (i >= MLX5_MTR_CHAIN_MAX_NUM) {
17040 			DRV_LOG(ERR, "Exceed max meter number in hierarchy.");
17041 			return NULL;
17042 		}
17043 		next_fm = mlx5_flow_meter_find(priv,
17044 			mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
17045 		if (!next_fm) {
17046 			DRV_LOG(ERR, "Failed to get next meter in hierarchy.");
17047 			return NULL;
17048 		}
17049 		next_policy =
17050 			mlx5_flow_meter_policy_find(dev, next_fm->policy_id,
17051 						    NULL);
17052 		MLX5_ASSERT(next_policy);
17053 		mtr_policy = next_policy;
17054 	}
17055 	while (i) {
17056 		/**
17057 		 * From last policy to the first one in hierarchy,
17058 		 * create / get the sub policy for each of them.
17059 		 */
17060 		sub_policy = __flow_dv_meter_get_rss_sub_policy(dev,
17061 							policies[--i],
17062 							rss_desc,
17063 							next_sub_policy,
17064 							&reuse_sub_policy);
17065 		if (!sub_policy) {
17066 			DRV_LOG(ERR, "Failed to get the sub policy.");
17067 			goto err_exit;
17068 		}
17069 		if (!reuse_sub_policy)
17070 			sub_policies[j++] = sub_policy;
17071 		next_sub_policy = sub_policy;
17072 	}
17073 	return sub_policy;
17074 err_exit:
17075 	while (j) {
17076 		uint16_t sub_policy_num;
17077 
17078 		sub_policy = sub_policies[--j];
17079 		mtr_policy = sub_policy->main_policy;
17080 		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
17081 		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
17082 			sub_policy_num = (mtr_policy->sub_policy_num >>
17083 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
17084 				MLX5_MTR_SUB_POLICY_NUM_MASK;
17085 			mtr_policy->sub_policys[domain][sub_policy_num - 1] =
17086 									NULL;
17087 			sub_policy_num--;
17088 			mtr_policy->sub_policy_num &=
17089 				~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
17090 				  (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
17091 			mtr_policy->sub_policy_num |=
17092 			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
17093 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
17094 			mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
17095 					sub_policy->idx);
17096 		}
17097 	}
17098 	return NULL;
17099 }
17100 
17101 /**
17102  * Create the sub policy tag rule for all meters in hierarchy.
17103  *
17104  * @param[in] dev
17105  *   Pointer to Ethernet device.
17106  * @param[in] fm
17107  *   Meter information table.
17108  * @param[in] src_port
17109  *   The src port this extra rule should use.
17110  * @param[in] item
17111  *   The src port match item.
17112  * @param[out] error
17113  *   Perform verbose error reporting if not NULL.
17114  * @return
17115  *   0 on success, a negative errno value otherwise and rte_errno is set.
17116  */
17117 static int
17118 flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev,
17119 				struct mlx5_flow_meter_info *fm,
17120 				int32_t src_port,
17121 				const struct rte_flow_item *item,
17122 				struct rte_flow_error *error)
17123 {
17124 	struct mlx5_priv *priv = dev->data->dev_private;
17125 	struct mlx5_flow_meter_policy *mtr_policy;
17126 	struct mlx5_flow_meter_sub_policy *sub_policy;
17127 	struct mlx5_flow_meter_info *next_fm = NULL;
17128 	struct mlx5_flow_meter_policy *next_policy;
17129 	struct mlx5_flow_meter_sub_policy *next_sub_policy;
17130 	struct mlx5_flow_tbl_data_entry *tbl_data;
17131 	struct mlx5_sub_policy_color_rule *color_rule;
17132 	struct mlx5_meter_policy_acts acts;
17133 	uint32_t color_reg_c_idx;
17134 	bool mtr_first = (src_port != UINT16_MAX) ? true : false;
17135 	struct rte_flow_attr attr = {
17136 		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
17137 		.priority = 0,
17138 		.ingress = 0,
17139 		.egress = 0,
17140 		.transfer = 1,
17141 		.reserved = 0,
17142 	};
17143 	uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER;
17144 	int i;
17145 
17146 	mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
17147 	MLX5_ASSERT(mtr_policy);
17148 	if (!mtr_policy->is_hierarchy)
17149 		return 0;
17150 	next_fm = mlx5_flow_meter_find(priv,
17151 			mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
17152 	if (!next_fm) {
17153 		return rte_flow_error_set(error, EINVAL,
17154 				RTE_FLOW_ERROR_TYPE_ACTION, NULL,
17155 				"Failed to find next meter in hierarchy.");
17156 	}
17157 	if (!next_fm->drop_cnt)
17158 		goto exit;
17159 	color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error);
17160 	sub_policy = mtr_policy->sub_policys[domain][0];
17161 	for (i = 0; i < RTE_COLORS; i++) {
17162 		bool rule_exist = false;
17163 		struct mlx5_meter_policy_action_container *act_cnt;
17164 
17165 		if (i >= RTE_COLOR_YELLOW)
17166 			break;
17167 		TAILQ_FOREACH(color_rule,
17168 			      &sub_policy->color_rules[i], next_port)
17169 			if (color_rule->src_port == src_port) {
17170 				rule_exist = true;
17171 				break;
17172 			}
17173 		if (rule_exist)
17174 			continue;
17175 		color_rule = mlx5_malloc(MLX5_MEM_ZERO,
17176 				sizeof(struct mlx5_sub_policy_color_rule),
17177 				0, SOCKET_ID_ANY);
17178 		if (!color_rule)
17179 			return rte_flow_error_set(error, ENOMEM,
17180 				RTE_FLOW_ERROR_TYPE_ACTION,
17181 				NULL, "No memory to create tag color rule.");
17182 		color_rule->src_port = src_port;
17183 		attr.priority = i;
17184 		next_policy = mlx5_flow_meter_policy_find(dev,
17185 						next_fm->policy_id, NULL);
17186 		MLX5_ASSERT(next_policy);
17187 		next_sub_policy = next_policy->sub_policys[domain][0];
17188 		tbl_data = container_of(next_sub_policy->tbl_rsc,
17189 					struct mlx5_flow_tbl_data_entry, tbl);
17190 		act_cnt = &mtr_policy->act_cnt[i];
17191 		if (mtr_first) {
17192 			acts.dv_actions[0] = next_fm->meter_action;
17193 			acts.dv_actions[1] = act_cnt->modify_hdr->action;
17194 		} else {
17195 			acts.dv_actions[0] = act_cnt->modify_hdr->action;
17196 			acts.dv_actions[1] = next_fm->meter_action;
17197 		}
17198 		acts.dv_actions[2] = tbl_data->jump.action;
17199 		acts.actions_n = 3;
17200 		if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) {
17201 			next_fm = NULL;
17202 			goto err_exit;
17203 		}
17204 		if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
17205 				MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
17206 				&attr, true, item,
17207 				&color_rule->matcher, error)) {
17208 			rte_flow_error_set(error, errno,
17209 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
17210 				"Failed to create hierarchy meter matcher.");
17211 			goto err_exit;
17212 		}
17213 		if (__flow_dv_create_policy_flow(dev, color_reg_c_idx,
17214 					(enum rte_color)i,
17215 					color_rule->matcher->matcher_object,
17216 					acts.actions_n, acts.dv_actions,
17217 					true, item,
17218 					&color_rule->rule, &attr)) {
17219 			rte_flow_error_set(error, errno,
17220 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
17221 				"Failed to create hierarchy meter rule.");
17222 			goto err_exit;
17223 		}
17224 		TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
17225 				  color_rule, next_port);
17226 	}
17227 exit:
17228 	/**
17229 	 * Recursive call to iterate all meters in hierarchy and
17230 	 * create needed rules.
17231 	 */
17232 	return flow_dv_meter_hierarchy_rule_create(dev, next_fm,
17233 						src_port, item, error);
17234 err_exit:
17235 	if (color_rule) {
17236 		if (color_rule->rule)
17237 			mlx5_flow_os_destroy_flow(color_rule->rule);
17238 		if (color_rule->matcher) {
17239 			struct mlx5_flow_tbl_data_entry *tbl =
17240 				container_of(color_rule->matcher->tbl,
17241 						typeof(*tbl), tbl);
17242 			mlx5_list_unregister(tbl->matchers,
17243 						&color_rule->matcher->entry);
17244 		}
17245 		mlx5_free(color_rule);
17246 	}
17247 	if (next_fm)
17248 		mlx5_flow_meter_detach(priv, next_fm);
17249 	return -rte_errno;
17250 }
17251 
17252 /**
17253  * Destroy the sub policy table with RX queue.
17254  *
17255  * @param[in] dev
17256  *   Pointer to Ethernet device.
17257  * @param[in] mtr_policy
17258  *   Pointer to meter policy table.
17259  */
17260 static void
17261 flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev,
17262 				    struct mlx5_flow_meter_policy *mtr_policy)
17263 {
17264 	struct mlx5_priv *priv = dev->data->dev_private;
17265 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
17266 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
17267 	uint32_t i, j;
17268 	uint16_t sub_policy_num, new_policy_num;
17269 
17270 	rte_spinlock_lock(&mtr_policy->sl);
17271 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
17272 		switch (mtr_policy->act_cnt[i].fate_action) {
17273 		case MLX5_FLOW_FATE_SHARED_RSS:
17274 			sub_policy_num = (mtr_policy->sub_policy_num >>
17275 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
17276 			MLX5_MTR_SUB_POLICY_NUM_MASK;
17277 			new_policy_num = sub_policy_num;
17278 			for (j = 0; j < sub_policy_num; j++) {
17279 				sub_policy =
17280 					mtr_policy->sub_policys[domain][j];
17281 				if (sub_policy) {
17282 					__flow_dv_destroy_sub_policy_rules(dev,
17283 						sub_policy);
17284 				if (sub_policy !=
17285 					mtr_policy->sub_policys[domain][0]) {
17286 					mtr_policy->sub_policys[domain][j] =
17287 								NULL;
17288 					mlx5_ipool_free
17289 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
17290 						sub_policy->idx);
17291 						new_policy_num--;
17292 					}
17293 				}
17294 			}
17295 			if (new_policy_num != sub_policy_num) {
17296 				mtr_policy->sub_policy_num &=
17297 				~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
17298 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
17299 				mtr_policy->sub_policy_num |=
17300 				(new_policy_num &
17301 					MLX5_MTR_SUB_POLICY_NUM_MASK) <<
17302 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
17303 			}
17304 			break;
17305 		case MLX5_FLOW_FATE_QUEUE:
17306 			sub_policy = mtr_policy->sub_policys[domain][0];
17307 			__flow_dv_destroy_sub_policy_rules(dev,
17308 							   sub_policy);
17309 			break;
17310 		default:
17311 			/*Other actions without queue and do nothing*/
17312 			break;
17313 		}
17314 	}
17315 	rte_spinlock_unlock(&mtr_policy->sl);
17316 }
17317 /**
17318  * Check whether the DR drop action is supported on the root table or not.
17319  *
17320  * Create a simple flow with DR drop action on root table to validate
17321  * if DR drop action on root table is supported or not.
17322  *
17323  * @param[in] dev
17324  *   Pointer to rte_eth_dev structure.
17325  *
17326  * @return
17327  *   0 on success, a negative errno value otherwise and rte_errno is set.
17328  */
17329 int
17330 mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev)
17331 {
17332 	struct mlx5_priv *priv = dev->data->dev_private;
17333 	struct mlx5_dev_ctx_shared *sh = priv->sh;
17334 	struct mlx5_flow_dv_match_params mask = {
17335 		.size = sizeof(mask.buf),
17336 	};
17337 	struct mlx5_flow_dv_match_params value = {
17338 		.size = sizeof(value.buf),
17339 	};
17340 	struct mlx5dv_flow_matcher_attr dv_attr = {
17341 		.type = IBV_FLOW_ATTR_NORMAL,
17342 		.priority = 0,
17343 		.match_criteria_enable = 0,
17344 		.match_mask = (void *)&mask,
17345 	};
17346 	struct mlx5_flow_tbl_resource *tbl = NULL;
17347 	void *matcher = NULL;
17348 	void *flow = NULL;
17349 	int ret = -1;
17350 
17351 	tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL,
17352 					0, 0, 0, NULL);
17353 	if (!tbl)
17354 		goto err;
17355 	dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
17356 	__flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
17357 	ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr,
17358 					       tbl->obj, &matcher);
17359 	if (ret)
17360 		goto err;
17361 	__flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
17362 	ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
17363 				       &sh->dr_drop_action, &flow);
17364 err:
17365 	/*
17366 	 * If DR drop action is not supported on root table, flow create will
17367 	 * be failed with EOPNOTSUPP or EPROTONOSUPPORT.
17368 	 */
17369 	if (!flow) {
17370 		if (matcher &&
17371 		    (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP))
17372 			DRV_LOG(INFO, "DR drop action is not supported in root table.");
17373 		else
17374 			DRV_LOG(ERR, "Unexpected error in DR drop action support detection");
17375 		ret = -1;
17376 	} else {
17377 		claim_zero(mlx5_flow_os_destroy_flow(flow));
17378 	}
17379 	if (matcher)
17380 		claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
17381 	if (tbl)
17382 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
17383 	return ret;
17384 }
17385 
17386 /**
17387  * Validate the batch counter support in root table.
17388  *
17389  * Create a simple flow with invalid counter and drop action on root table to
17390  * validate if batch counter with offset on root table is supported or not.
17391  *
17392  * @param[in] dev
17393  *   Pointer to rte_eth_dev structure.
17394  *
17395  * @return
17396  *   0 on success, a negative errno value otherwise and rte_errno is set.
17397  */
17398 int
17399 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev)
17400 {
17401 	struct mlx5_priv *priv = dev->data->dev_private;
17402 	struct mlx5_dev_ctx_shared *sh = priv->sh;
17403 	struct mlx5_flow_dv_match_params mask = {
17404 		.size = sizeof(mask.buf),
17405 	};
17406 	struct mlx5_flow_dv_match_params value = {
17407 		.size = sizeof(value.buf),
17408 	};
17409 	struct mlx5dv_flow_matcher_attr dv_attr = {
17410 		.type = IBV_FLOW_ATTR_NORMAL | IBV_FLOW_ATTR_FLAGS_EGRESS,
17411 		.priority = 0,
17412 		.match_criteria_enable = 0,
17413 		.match_mask = (void *)&mask,
17414 	};
17415 	void *actions[2] = { 0 };
17416 	struct mlx5_flow_tbl_resource *tbl = NULL;
17417 	struct mlx5_devx_obj *dcs = NULL;
17418 	void *matcher = NULL;
17419 	void *flow = NULL;
17420 	int ret = -1;
17421 
17422 	tbl = flow_dv_tbl_resource_get(dev, 0, 1, 0, false, NULL,
17423 					0, 0, 0, NULL);
17424 	if (!tbl)
17425 		goto err;
17426 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4);
17427 	if (!dcs)
17428 		goto err;
17429 	ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX,
17430 						    &actions[0]);
17431 	if (ret)
17432 		goto err;
17433 	dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
17434 	__flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
17435 	ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr,
17436 					       tbl->obj, &matcher);
17437 	if (ret)
17438 		goto err;
17439 	__flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
17440 	ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
17441 				       actions, &flow);
17442 err:
17443 	/*
17444 	 * If batch counter with offset is not supported, the driver will not
17445 	 * validate the invalid offset value, flow create should success.
17446 	 * In this case, it means batch counter is not supported in root table.
17447 	 *
17448 	 * Otherwise, if flow create is failed, counter offset is supported.
17449 	 */
17450 	if (flow) {
17451 		DRV_LOG(INFO, "Batch counter is not supported in root "
17452 			      "table. Switch to fallback mode.");
17453 		rte_errno = ENOTSUP;
17454 		ret = -rte_errno;
17455 		claim_zero(mlx5_flow_os_destroy_flow(flow));
17456 	} else {
17457 		/* Check matcher to make sure validate fail at flow create. */
17458 		if (!matcher || (matcher && errno != EINVAL))
17459 			DRV_LOG(ERR, "Unexpected error in counter offset "
17460 				     "support detection");
17461 		ret = 0;
17462 	}
17463 	if (actions[0])
17464 		claim_zero(mlx5_flow_os_destroy_flow_action(actions[0]));
17465 	if (matcher)
17466 		claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
17467 	if (tbl)
17468 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
17469 	if (dcs)
17470 		claim_zero(mlx5_devx_cmd_destroy(dcs));
17471 	return ret;
17472 }
17473 
17474 /**
17475  * Query a devx counter.
17476  *
17477  * @param[in] dev
17478  *   Pointer to the Ethernet device structure.
17479  * @param[in] cnt
17480  *   Index to the flow counter.
17481  * @param[in] clear
17482  *   Set to clear the counter statistics.
17483  * @param[out] pkts
17484  *   The statistics value of packets.
17485  * @param[out] bytes
17486  *   The statistics value of bytes.
17487  *
17488  * @return
17489  *   0 on success, otherwise return -1.
17490  */
17491 static int
17492 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear,
17493 		      uint64_t *pkts, uint64_t *bytes)
17494 {
17495 	struct mlx5_priv *priv = dev->data->dev_private;
17496 	struct mlx5_flow_counter *cnt;
17497 	uint64_t inn_pkts, inn_bytes;
17498 	int ret;
17499 
17500 	if (!priv->sh->devx)
17501 		return -1;
17502 
17503 	ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes);
17504 	if (ret)
17505 		return -1;
17506 	cnt = flow_dv_counter_get_by_idx(dev, counter, NULL);
17507 	*pkts = inn_pkts - cnt->hits;
17508 	*bytes = inn_bytes - cnt->bytes;
17509 	if (clear) {
17510 		cnt->hits = inn_pkts;
17511 		cnt->bytes = inn_bytes;
17512 	}
17513 	return 0;
17514 }
17515 
17516 /**
17517  * Get aged-out flows.
17518  *
17519  * @param[in] dev
17520  *   Pointer to the Ethernet device structure.
17521  * @param[in] context
17522  *   The address of an array of pointers to the aged-out flows contexts.
17523  * @param[in] nb_contexts
17524  *   The length of context array pointers.
17525  * @param[out] error
17526  *   Perform verbose error reporting if not NULL. Initialized in case of
17527  *   error only.
17528  *
17529  * @return
17530  *   how many contexts get in success, otherwise negative errno value.
17531  *   if nb_contexts is 0, return the amount of all aged contexts.
17532  *   if nb_contexts is not 0 , return the amount of aged flows reported
17533  *   in the context array.
17534  * @note: only stub for now
17535  */
17536 static int
17537 flow_dv_get_aged_flows(struct rte_eth_dev *dev,
17538 		    void **context,
17539 		    uint32_t nb_contexts,
17540 		    struct rte_flow_error *error)
17541 {
17542 	struct mlx5_priv *priv = dev->data->dev_private;
17543 	struct mlx5_age_info *age_info;
17544 	struct mlx5_age_param *age_param;
17545 	struct mlx5_flow_counter *counter;
17546 	struct mlx5_aso_age_action *act;
17547 	int nb_flows = 0;
17548 
17549 	if (nb_contexts && !context)
17550 		return rte_flow_error_set(error, EINVAL,
17551 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
17552 					  NULL, "empty context");
17553 	age_info = GET_PORT_AGE_INFO(priv);
17554 	rte_spinlock_lock(&age_info->aged_sl);
17555 	LIST_FOREACH(act, &age_info->aged_aso, next) {
17556 		nb_flows++;
17557 		if (nb_contexts) {
17558 			context[nb_flows - 1] =
17559 						act->age_params.context;
17560 			if (!(--nb_contexts))
17561 				break;
17562 		}
17563 	}
17564 	TAILQ_FOREACH(counter, &age_info->aged_counters, next) {
17565 		nb_flows++;
17566 		if (nb_contexts) {
17567 			age_param = MLX5_CNT_TO_AGE(counter);
17568 			context[nb_flows - 1] = age_param->context;
17569 			if (!(--nb_contexts))
17570 				break;
17571 		}
17572 	}
17573 	rte_spinlock_unlock(&age_info->aged_sl);
17574 	MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER);
17575 	return nb_flows;
17576 }
17577 
17578 /*
17579  * Mutex-protected thunk to lock-free flow_dv_counter_alloc().
17580  */
17581 static uint32_t
17582 flow_dv_counter_allocate(struct rte_eth_dev *dev)
17583 {
17584 	return flow_dv_counter_alloc(dev, 0);
17585 }
17586 
17587 /**
17588  * Validate indirect action.
17589  * Dispatcher for action type specific validation.
17590  *
17591  * @param[in] dev
17592  *   Pointer to the Ethernet device structure.
17593  * @param[in] conf
17594  *   Indirect action configuration.
17595  * @param[in] action
17596  *   The indirect action object to validate.
17597  * @param[out] error
17598  *   Perform verbose error reporting if not NULL. Initialized in case of
17599  *   error only.
17600  *
17601  * @return
17602  *   0 on success, otherwise negative errno value.
17603  */
17604 static int
17605 flow_dv_action_validate(struct rte_eth_dev *dev,
17606 			const struct rte_flow_indir_action_conf *conf,
17607 			const struct rte_flow_action *action,
17608 			struct rte_flow_error *err)
17609 {
17610 	struct mlx5_priv *priv = dev->data->dev_private;
17611 
17612 	RTE_SET_USED(conf);
17613 	switch (action->type) {
17614 	case RTE_FLOW_ACTION_TYPE_RSS:
17615 		/*
17616 		 * priv->obj_ops is set according to driver capabilities.
17617 		 * When DevX capabilities are
17618 		 * sufficient, it is set to devx_obj_ops.
17619 		 * Otherwise, it is set to ibv_obj_ops.
17620 		 * ibv_obj_ops doesn't support ind_table_modify operation.
17621 		 * In this case the indirect RSS action can't be used.
17622 		 */
17623 		if (priv->obj_ops.ind_table_modify == NULL)
17624 			return rte_flow_error_set
17625 					(err, ENOTSUP,
17626 					 RTE_FLOW_ERROR_TYPE_ACTION,
17627 					 NULL,
17628 					 "Indirect RSS action not supported");
17629 		return mlx5_validate_action_rss(dev, action, err);
17630 	case RTE_FLOW_ACTION_TYPE_AGE:
17631 		if (!priv->sh->aso_age_mng)
17632 			return rte_flow_error_set(err, ENOTSUP,
17633 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
17634 						NULL,
17635 						"Indirect age action not supported");
17636 		return flow_dv_validate_action_age(0, action, dev, err);
17637 	case RTE_FLOW_ACTION_TYPE_COUNT:
17638 		return flow_dv_validate_action_count(dev, true, 0, err);
17639 	case RTE_FLOW_ACTION_TYPE_CONNTRACK:
17640 		if (!priv->sh->ct_aso_en)
17641 			return rte_flow_error_set(err, ENOTSUP,
17642 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
17643 					"ASO CT is not supported");
17644 		return mlx5_validate_action_ct(dev, action->conf, err);
17645 	default:
17646 		return rte_flow_error_set(err, ENOTSUP,
17647 					  RTE_FLOW_ERROR_TYPE_ACTION,
17648 					  NULL,
17649 					  "action type not supported");
17650 	}
17651 }
17652 
17653 /*
17654  * Check if the RSS configurations for colors of a meter policy match
17655  * each other, except the queues.
17656  *
17657  * @param[in] r1
17658  *   Pointer to the first RSS flow action.
17659  * @param[in] r2
17660  *   Pointer to the second RSS flow action.
17661  *
17662  * @return
17663  *   0 on match, 1 on conflict.
17664  */
17665 static inline int
17666 flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1,
17667 			       const struct rte_flow_action_rss *r2)
17668 {
17669 	if (r1 == NULL || r2 == NULL)
17670 		return 0;
17671 	if (!(r1->level <= 1 && r2->level <= 1) &&
17672 	    !(r1->level > 1 && r2->level > 1))
17673 		return 1;
17674 	if (r1->types != r2->types &&
17675 	    !((r1->types == 0 || r1->types == RTE_ETH_RSS_IP) &&
17676 	      (r2->types == 0 || r2->types == RTE_ETH_RSS_IP)))
17677 		return 1;
17678 	if (r1->key || r2->key) {
17679 		const void *key1 = r1->key ? r1->key : rss_hash_default_key;
17680 		const void *key2 = r2->key ? r2->key : rss_hash_default_key;
17681 
17682 		if (memcmp(key1, key2, MLX5_RSS_HASH_KEY_LEN))
17683 			return 1;
17684 	}
17685 	return 0;
17686 }
17687 
17688 /**
17689  * Validate the meter hierarchy chain for meter policy.
17690  *
17691  * @param[in] dev
17692  *   Pointer to the Ethernet device structure.
17693  * @param[in] meter_id
17694  *   Meter id.
17695  * @param[in] action_flags
17696  *   Holds the actions detected until now.
17697  * @param[out] is_rss
17698  *   Is RSS or not.
17699  * @param[out] hierarchy_domain
17700  *   The domain bitmap for hierarchy policy.
17701  * @param[out] error
17702  *   Perform verbose error reporting if not NULL. Initialized in case of
17703  *   error only.
17704  *
17705  * @return
17706  *   0 on success, otherwise negative errno value with error set.
17707  */
17708 static int
17709 flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev,
17710 				  uint32_t meter_id,
17711 				  uint64_t action_flags,
17712 				  bool *is_rss,
17713 				  uint8_t *hierarchy_domain,
17714 				  struct rte_mtr_error *error)
17715 {
17716 	struct mlx5_priv *priv = dev->data->dev_private;
17717 	struct mlx5_flow_meter_info *fm;
17718 	struct mlx5_flow_meter_policy *policy;
17719 	uint8_t cnt = 1;
17720 
17721 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
17722 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
17723 		return -rte_mtr_error_set(error, EINVAL,
17724 					RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN,
17725 					NULL,
17726 					"Multiple fate actions not supported.");
17727 	*hierarchy_domain = 0;
17728 	while (true) {
17729 		fm = mlx5_flow_meter_find(priv, meter_id, NULL);
17730 		if (!fm)
17731 			return -rte_mtr_error_set(error, EINVAL,
17732 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
17733 					"Meter not found in meter hierarchy.");
17734 		if (fm->def_policy)
17735 			return -rte_mtr_error_set(error, EINVAL,
17736 					RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
17737 			"Non termination meter not supported in hierarchy.");
17738 		policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
17739 		MLX5_ASSERT(policy);
17740 		/**
17741 		 * Only inherit the supported domains of the first meter in
17742 		 * hierarchy.
17743 		 * One meter supports at least one domain.
17744 		 */
17745 		if (!*hierarchy_domain) {
17746 			if (policy->transfer)
17747 				*hierarchy_domain |=
17748 						MLX5_MTR_DOMAIN_TRANSFER_BIT;
17749 			if (policy->ingress)
17750 				*hierarchy_domain |=
17751 						MLX5_MTR_DOMAIN_INGRESS_BIT;
17752 			if (policy->egress)
17753 				*hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT;
17754 		}
17755 		if (!policy->is_hierarchy) {
17756 			*is_rss = policy->is_rss;
17757 			break;
17758 		}
17759 		meter_id = policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id;
17760 		if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM)
17761 			return -rte_mtr_error_set(error, EINVAL,
17762 					RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
17763 					"Exceed max hierarchy meter number.");
17764 	}
17765 	return 0;
17766 }
17767 
17768 /**
17769  * Validate meter policy actions.
17770  * Dispatcher for action type specific validation.
17771  *
17772  * @param[in] dev
17773  *   Pointer to the Ethernet device structure.
17774  * @param[in] action
17775  *   The meter policy action object to validate.
17776  * @param[in] attr
17777  *   Attributes of flow to determine steering domain.
17778  * @param[out] error
17779  *   Perform verbose error reporting if not NULL. Initialized in case of
17780  *   error only.
17781  *
17782  * @return
17783  *   0 on success, otherwise negative errno value.
17784  */
17785 static int
17786 flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
17787 			const struct rte_flow_action *actions[RTE_COLORS],
17788 			struct rte_flow_attr *attr,
17789 			bool *is_rss,
17790 			uint8_t *domain_bitmap,
17791 			uint8_t *policy_mode,
17792 			struct rte_mtr_error *error)
17793 {
17794 	struct mlx5_priv *priv = dev->data->dev_private;
17795 	struct mlx5_dev_config *dev_conf = &priv->config;
17796 	const struct rte_flow_action *act;
17797 	uint64_t action_flags[RTE_COLORS] = {0};
17798 	int actions_n;
17799 	int i, ret;
17800 	struct rte_flow_error flow_err;
17801 	uint8_t domain_color[RTE_COLORS] = {0};
17802 	uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
17803 	uint8_t hierarchy_domain = 0;
17804 	const struct rte_flow_action_meter *mtr;
17805 	bool def_green = false;
17806 	bool def_yellow = false;
17807 	const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL};
17808 
17809 	if (!priv->config.dv_esw_en)
17810 		def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
17811 	*domain_bitmap = def_domain;
17812 	/* Red color could only support DROP action. */
17813 	if (!actions[RTE_COLOR_RED] ||
17814 	    actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP)
17815 		return -rte_mtr_error_set(error, ENOTSUP,
17816 				RTE_MTR_ERROR_TYPE_METER_POLICY,
17817 				NULL, "Red color only supports drop action.");
17818 	/*
17819 	 * Check default policy actions:
17820 	 * Green / Yellow: no action, Red: drop action
17821 	 * Either G or Y will trigger default policy actions to be created.
17822 	 */
17823 	if (!actions[RTE_COLOR_GREEN] ||
17824 	    actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END)
17825 		def_green = true;
17826 	if (!actions[RTE_COLOR_YELLOW] ||
17827 	    actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END)
17828 		def_yellow = true;
17829 	if (def_green && def_yellow) {
17830 		*policy_mode = MLX5_MTR_POLICY_MODE_DEF;
17831 		return 0;
17832 	} else if (!def_green && def_yellow) {
17833 		*policy_mode = MLX5_MTR_POLICY_MODE_OG;
17834 	} else if (def_green && !def_yellow) {
17835 		*policy_mode = MLX5_MTR_POLICY_MODE_OY;
17836 	} else {
17837 		*policy_mode = MLX5_MTR_POLICY_MODE_ALL;
17838 	}
17839 	/* Set to empty string in case of NULL pointer access by user. */
17840 	flow_err.message = "";
17841 	for (i = 0; i < RTE_COLORS; i++) {
17842 		act = actions[i];
17843 		for (action_flags[i] = 0, actions_n = 0;
17844 		     act && act->type != RTE_FLOW_ACTION_TYPE_END;
17845 		     act++) {
17846 			if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
17847 				return -rte_mtr_error_set(error, ENOTSUP,
17848 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17849 					  NULL, "too many actions");
17850 			switch (act->type) {
17851 			case RTE_FLOW_ACTION_TYPE_PORT_ID:
17852 			case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
17853 				if (!priv->config.dv_esw_en)
17854 					return -rte_mtr_error_set(error,
17855 					ENOTSUP,
17856 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17857 					NULL, "PORT action validate check"
17858 					" fail for ESW disable");
17859 				ret = flow_dv_validate_action_port_id(dev,
17860 						action_flags[i],
17861 						act, attr, &flow_err);
17862 				if (ret)
17863 					return -rte_mtr_error_set(error,
17864 					ENOTSUP,
17865 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17866 					NULL, flow_err.message ?
17867 					flow_err.message :
17868 					"PORT action validate check fail");
17869 				++actions_n;
17870 				action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID;
17871 				break;
17872 			case RTE_FLOW_ACTION_TYPE_MARK:
17873 				ret = flow_dv_validate_action_mark(dev, act,
17874 							   action_flags[i],
17875 							   attr, &flow_err);
17876 				if (ret < 0)
17877 					return -rte_mtr_error_set(error,
17878 					ENOTSUP,
17879 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17880 					NULL, flow_err.message ?
17881 					flow_err.message :
17882 					"Mark action validate check fail");
17883 				if (dev_conf->dv_xmeta_en !=
17884 					MLX5_XMETA_MODE_LEGACY)
17885 					return -rte_mtr_error_set(error,
17886 					ENOTSUP,
17887 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17888 					NULL, "Extend MARK action is "
17889 					"not supported. Please try use "
17890 					"default policy for meter.");
17891 				action_flags[i] |= MLX5_FLOW_ACTION_MARK;
17892 				++actions_n;
17893 				break;
17894 			case RTE_FLOW_ACTION_TYPE_SET_TAG:
17895 				ret = flow_dv_validate_action_set_tag(dev,
17896 							act, action_flags[i],
17897 							attr, &flow_err);
17898 				if (ret)
17899 					return -rte_mtr_error_set(error,
17900 					ENOTSUP,
17901 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17902 					NULL, flow_err.message ?
17903 					flow_err.message :
17904 					"Set tag action validate check fail");
17905 				action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG;
17906 				++actions_n;
17907 				break;
17908 			case RTE_FLOW_ACTION_TYPE_DROP:
17909 				ret = mlx5_flow_validate_action_drop
17910 					(action_flags[i], attr, &flow_err);
17911 				if (ret < 0)
17912 					return -rte_mtr_error_set(error,
17913 					ENOTSUP,
17914 					RTE_MTR_ERROR_TYPE_METER_POLICY,
17915 					NULL, flow_err.message ?
17916 					flow_err.message :
17917 					"Drop action validate check fail");
17918 				action_flags[i] |= MLX5_FLOW_ACTION_DROP;
17919 				++actions_n;
17920 				break;
17921 			case RTE_FLOW_ACTION_TYPE_QUEUE:
17922 				/*
17923 				 * Check whether extensive
17924 				 * metadata feature is engaged.
17925 				 */
17926 				if (dev_conf->dv_flow_en &&
17927 				    (dev_conf->dv_xmeta_en !=
17928 				     MLX5_XMETA_MODE_LEGACY) &&
17929 				    mlx5_flow_ext_mreg_supported(dev))
17930 					return -rte_mtr_error_set(error,
17931 					  ENOTSUP,
17932 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17933 					  NULL, "Queue action with meta "
17934 					  "is not supported. Please try use "
17935 					  "default policy for meter.");
17936 				ret = mlx5_flow_validate_action_queue(act,
17937 							action_flags[i], dev,
17938 							attr, &flow_err);
17939 				if (ret < 0)
17940 					return -rte_mtr_error_set(error,
17941 					  ENOTSUP,
17942 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17943 					  NULL, flow_err.message ?
17944 					  flow_err.message :
17945 					  "Queue action validate check fail");
17946 				action_flags[i] |= MLX5_FLOW_ACTION_QUEUE;
17947 				++actions_n;
17948 				break;
17949 			case RTE_FLOW_ACTION_TYPE_RSS:
17950 				if (dev_conf->dv_flow_en &&
17951 				    (dev_conf->dv_xmeta_en !=
17952 				     MLX5_XMETA_MODE_LEGACY) &&
17953 				    mlx5_flow_ext_mreg_supported(dev))
17954 					return -rte_mtr_error_set(error,
17955 					  ENOTSUP,
17956 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17957 					  NULL, "RSS action with meta "
17958 					  "is not supported. Please try use "
17959 					  "default policy for meter.");
17960 				ret = mlx5_validate_action_rss(dev, act,
17961 							       &flow_err);
17962 				if (ret < 0)
17963 					return -rte_mtr_error_set(error,
17964 					  ENOTSUP,
17965 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17966 					  NULL, flow_err.message ?
17967 					  flow_err.message :
17968 					  "RSS action validate check fail");
17969 				action_flags[i] |= MLX5_FLOW_ACTION_RSS;
17970 				++actions_n;
17971 				/* Either G or Y will set the RSS. */
17972 				rss_color[i] = act->conf;
17973 				break;
17974 			case RTE_FLOW_ACTION_TYPE_JUMP:
17975 				ret = flow_dv_validate_action_jump(dev,
17976 					NULL, act, action_flags[i],
17977 					attr, true, &flow_err);
17978 				if (ret)
17979 					return -rte_mtr_error_set(error,
17980 					  ENOTSUP,
17981 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
17982 					  NULL, flow_err.message ?
17983 					  flow_err.message :
17984 					  "Jump action validate check fail");
17985 				++actions_n;
17986 				action_flags[i] |= MLX5_FLOW_ACTION_JUMP;
17987 				break;
17988 			/*
17989 			 * Only the last meter in the hierarchy will support
17990 			 * the YELLOW color steering. Then in the meter policy
17991 			 * actions list, there should be no other meter inside.
17992 			 */
17993 			case RTE_FLOW_ACTION_TYPE_METER:
17994 				if (i != RTE_COLOR_GREEN)
17995 					return -rte_mtr_error_set(error,
17996 						ENOTSUP,
17997 						RTE_MTR_ERROR_TYPE_METER_POLICY,
17998 						NULL,
17999 						"Meter hierarchy only supports GREEN color.");
18000 				if (*policy_mode != MLX5_MTR_POLICY_MODE_OG)
18001 					return -rte_mtr_error_set(error,
18002 						ENOTSUP,
18003 						RTE_MTR_ERROR_TYPE_METER_POLICY,
18004 						NULL,
18005 						"No yellow policy should be provided in meter hierarchy.");
18006 				mtr = act->conf;
18007 				ret = flow_dv_validate_policy_mtr_hierarchy(dev,
18008 							mtr->mtr_id,
18009 							action_flags[i],
18010 							is_rss,
18011 							&hierarchy_domain,
18012 							error);
18013 				if (ret)
18014 					return ret;
18015 				++actions_n;
18016 				action_flags[i] |=
18017 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
18018 				break;
18019 			default:
18020 				return -rte_mtr_error_set(error, ENOTSUP,
18021 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18022 					NULL,
18023 					"Doesn't support optional action");
18024 			}
18025 		}
18026 		if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID) {
18027 			domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
18028 		} else if ((action_flags[i] &
18029 			  (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
18030 			  (action_flags[i] & MLX5_FLOW_ACTION_MARK)) {
18031 			/*
18032 			 * Only support MLX5_XMETA_MODE_LEGACY
18033 			 * so MARK action is only in ingress domain.
18034 			 */
18035 			domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
18036 		} else {
18037 			domain_color[i] = def_domain;
18038 			if (action_flags[i] &&
18039 			    !(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
18040 				domain_color[i] &=
18041 				~MLX5_MTR_DOMAIN_TRANSFER_BIT;
18042 		}
18043 		if (action_flags[i] &
18044 		    MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
18045 			domain_color[i] &= hierarchy_domain;
18046 		/*
18047 		 * Non-termination actions only support NIC Tx domain.
18048 		 * The adjustion should be skipped when there is no
18049 		 * action or only END is provided. The default domains
18050 		 * bit-mask is set to find the MIN intersection.
18051 		 * The action flags checking should also be skipped.
18052 		 */
18053 		if ((def_green && i == RTE_COLOR_GREEN) ||
18054 		    (def_yellow && i == RTE_COLOR_YELLOW))
18055 			continue;
18056 		/*
18057 		 * Validate the drop action mutual exclusion
18058 		 * with other actions. Drop action is mutually-exclusive
18059 		 * with any other action, except for Count action.
18060 		 */
18061 		if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) &&
18062 		    (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) {
18063 			return -rte_mtr_error_set(error, ENOTSUP,
18064 				RTE_MTR_ERROR_TYPE_METER_POLICY,
18065 				NULL, "Drop action is mutually-exclusive "
18066 				"with any other action");
18067 		}
18068 		/* Eswitch has few restrictions on using items and actions */
18069 		if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
18070 			if (!mlx5_flow_ext_mreg_supported(dev) &&
18071 			    action_flags[i] & MLX5_FLOW_ACTION_MARK)
18072 				return -rte_mtr_error_set(error, ENOTSUP,
18073 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18074 					NULL, "unsupported action MARK");
18075 			if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE)
18076 				return -rte_mtr_error_set(error, ENOTSUP,
18077 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18078 					NULL, "unsupported action QUEUE");
18079 			if (action_flags[i] & MLX5_FLOW_ACTION_RSS)
18080 				return -rte_mtr_error_set(error, ENOTSUP,
18081 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18082 					NULL, "unsupported action RSS");
18083 			if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
18084 				return -rte_mtr_error_set(error, ENOTSUP,
18085 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18086 					NULL, "no fate action is found");
18087 		} else {
18088 			if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) &&
18089 			    (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) {
18090 				if ((domain_color[i] &
18091 				     MLX5_MTR_DOMAIN_EGRESS_BIT))
18092 					domain_color[i] =
18093 						MLX5_MTR_DOMAIN_EGRESS_BIT;
18094 				else
18095 					return -rte_mtr_error_set(error,
18096 						ENOTSUP,
18097 						RTE_MTR_ERROR_TYPE_METER_POLICY,
18098 						NULL,
18099 						"no fate action is found");
18100 			}
18101 		}
18102 	}
18103 	/* If both colors have RSS, the attributes should be the same. */
18104 	if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN],
18105 					   rss_color[RTE_COLOR_YELLOW]))
18106 		return -rte_mtr_error_set(error, EINVAL,
18107 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
18108 					  NULL, "policy RSS attr conflict");
18109 	if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW])
18110 		*is_rss = true;
18111 	/* "domain_color[C]" is non-zero for each color, default is ALL. */
18112 	if (!def_green && !def_yellow &&
18113 	    domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] &&
18114 	    !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) &&
18115 	    !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP))
18116 		return -rte_mtr_error_set(error, EINVAL,
18117 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
18118 					  NULL, "policy domains conflict");
18119 	/*
18120 	 * At least one color policy is listed in the actions, the domains
18121 	 * to be supported should be the intersection.
18122 	 */
18123 	*domain_bitmap = domain_color[RTE_COLOR_GREEN] &
18124 			 domain_color[RTE_COLOR_YELLOW];
18125 	return 0;
18126 }
18127 
18128 static int
18129 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
18130 {
18131 	struct mlx5_priv *priv = dev->data->dev_private;
18132 	int ret = 0;
18133 
18134 	if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) {
18135 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain,
18136 						flags);
18137 		if (ret != 0)
18138 			return ret;
18139 	}
18140 	if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) {
18141 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags);
18142 		if (ret != 0)
18143 			return ret;
18144 	}
18145 	if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) {
18146 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags);
18147 		if (ret != 0)
18148 			return ret;
18149 	}
18150 	return 0;
18151 }
18152 
18153 /**
18154  * Discover the number of available flow priorities
18155  * by trying to create a flow with the highest priority value
18156  * for each possible number.
18157  *
18158  * @param[in] dev
18159  *   Ethernet device.
18160  * @param[in] vprio
18161  *   List of possible number of available priorities.
18162  * @param[in] vprio_n
18163  *   Size of @p vprio array.
18164  * @return
18165  *   On success, number of available flow priorities.
18166  *   On failure, a negative errno-style code and rte_errno is set.
18167  */
18168 static int
18169 flow_dv_discover_priorities(struct rte_eth_dev *dev,
18170 			    const uint16_t *vprio, int vprio_n)
18171 {
18172 	struct mlx5_priv *priv = dev->data->dev_private;
18173 	struct mlx5_indexed_pool *pool = priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW];
18174 	struct rte_flow_item_eth eth;
18175 	struct rte_flow_item item = {
18176 		.type = RTE_FLOW_ITEM_TYPE_ETH,
18177 		.spec = &eth,
18178 		.mask = &eth,
18179 	};
18180 	struct mlx5_flow_dv_matcher matcher = {
18181 		.mask = {
18182 			.size = sizeof(matcher.mask.buf),
18183 		},
18184 	};
18185 	union mlx5_flow_tbl_key tbl_key;
18186 	struct mlx5_flow flow;
18187 	void *action;
18188 	struct rte_flow_error error;
18189 	uint8_t misc_mask;
18190 	int i, err, ret = -ENOTSUP;
18191 
18192 	/*
18193 	 * Prepare a flow with a catch-all pattern and a drop action.
18194 	 * Use drop queue, because shared drop action may be unavailable.
18195 	 */
18196 	action = priv->drop_queue.hrxq->action;
18197 	if (action == NULL) {
18198 		DRV_LOG(ERR, "Priority discovery requires a drop action");
18199 		rte_errno = ENOTSUP;
18200 		return -rte_errno;
18201 	}
18202 	memset(&flow, 0, sizeof(flow));
18203 	flow.handle = mlx5_ipool_zmalloc(pool, &flow.handle_idx);
18204 	if (flow.handle == NULL) {
18205 		DRV_LOG(ERR, "Cannot create flow handle");
18206 		rte_errno = ENOMEM;
18207 		return -rte_errno;
18208 	}
18209 	flow.ingress = true;
18210 	flow.dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
18211 	flow.dv.actions[0] = action;
18212 	flow.dv.actions_n = 1;
18213 	memset(&eth, 0, sizeof(eth));
18214 	flow_dv_translate_item_eth(matcher.mask.buf, flow.dv.value.buf,
18215 				   &item, /* inner */ false, /* group */ 0);
18216 	matcher.crc = rte_raw_cksum(matcher.mask.buf, matcher.mask.size);
18217 	for (i = 0; i < vprio_n; i++) {
18218 		/* Configure the next proposed maximum priority. */
18219 		matcher.priority = vprio[i] - 1;
18220 		memset(&tbl_key, 0, sizeof(tbl_key));
18221 		err = flow_dv_matcher_register(dev, &matcher, &tbl_key, &flow,
18222 					       /* tunnel */ NULL,
18223 					       /* group */ 0,
18224 					       &error);
18225 		if (err != 0) {
18226 			/* This action is pure SW and must always succeed. */
18227 			DRV_LOG(ERR, "Cannot register matcher");
18228 			ret = -rte_errno;
18229 			break;
18230 		}
18231 		/* Try to apply the flow to HW. */
18232 		misc_mask = flow_dv_matcher_enable(flow.dv.value.buf);
18233 		__flow_dv_adjust_buf_size(&flow.dv.value.size, misc_mask);
18234 		err = mlx5_flow_os_create_flow
18235 				(flow.handle->dvh.matcher->matcher_object,
18236 				 (void *)&flow.dv.value, flow.dv.actions_n,
18237 				 flow.dv.actions, &flow.handle->drv_flow);
18238 		if (err == 0) {
18239 			claim_zero(mlx5_flow_os_destroy_flow
18240 						(flow.handle->drv_flow));
18241 			flow.handle->drv_flow = NULL;
18242 		}
18243 		claim_zero(flow_dv_matcher_release(dev, flow.handle));
18244 		if (err != 0)
18245 			break;
18246 		ret = vprio[i];
18247 	}
18248 	mlx5_ipool_free(pool, flow.handle_idx);
18249 	/* Set rte_errno if no expected priority value matched. */
18250 	if (ret < 0)
18251 		rte_errno = -ret;
18252 	return ret;
18253 }
18254 
18255 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
18256 	.validate = flow_dv_validate,
18257 	.prepare = flow_dv_prepare,
18258 	.translate = flow_dv_translate,
18259 	.apply = flow_dv_apply,
18260 	.remove = flow_dv_remove,
18261 	.destroy = flow_dv_destroy,
18262 	.query = flow_dv_query,
18263 	.create_mtr_tbls = flow_dv_create_mtr_tbls,
18264 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
18265 	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
18266 	.create_meter = flow_dv_mtr_alloc,
18267 	.free_meter = flow_dv_aso_mtr_release_to_pool,
18268 	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
18269 	.create_mtr_acts = flow_dv_create_mtr_policy_acts,
18270 	.destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
18271 	.create_policy_rules = flow_dv_create_policy_rules,
18272 	.destroy_policy_rules = flow_dv_destroy_policy_rules,
18273 	.create_def_policy = flow_dv_create_def_policy,
18274 	.destroy_def_policy = flow_dv_destroy_def_policy,
18275 	.meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare,
18276 	.meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create,
18277 	.destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq,
18278 	.counter_alloc = flow_dv_counter_allocate,
18279 	.counter_free = flow_dv_counter_free,
18280 	.counter_query = flow_dv_counter_query,
18281 	.get_aged_flows = flow_dv_get_aged_flows,
18282 	.action_validate = flow_dv_action_validate,
18283 	.action_create = flow_dv_action_create,
18284 	.action_destroy = flow_dv_action_destroy,
18285 	.action_update = flow_dv_action_update,
18286 	.action_query = flow_dv_action_query,
18287 	.sync_domain = flow_dv_sync_domain,
18288 	.discover_priorities = flow_dv_discover_priorities,
18289 	.item_create = flow_dv_item_create,
18290 	.item_release = flow_dv_item_release,
18291 };
18292 
18293 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
18294 
18295