xref: /dpdk/drivers/net/mlx5/mlx5_flow_dv.c (revision 4aa10e5dc1b0fd6cc5b1b18770ac603e2c33a66c)
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 <bus_pci_driver.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 #define MLX5_ITEM_VALID(item, key_type) \
67 	(((MLX5_SET_MATCHER_SW & (key_type)) && !((item)->spec)) || \
68 	 ((MLX5_SET_MATCHER_HS_V == (key_type)) && !((item)->spec)) || \
69 	 ((MLX5_SET_MATCHER_HS_M == (key_type)) && !((item)->mask)))
70 
71 #define MLX5_ITEM_UPDATE(item, key_type, v, m, gm) \
72 	do { \
73 		if ((key_type) == MLX5_SET_MATCHER_SW_V) { \
74 			v = (item)->spec; \
75 			m = (item)->mask ? (item)->mask : (gm); \
76 		} else if ((key_type) == MLX5_SET_MATCHER_HS_V) { \
77 			v = (item)->spec; \
78 			m = (v); \
79 		} else { \
80 			v = (item)->mask ? (item)->mask : (gm); \
81 			m = (v); \
82 		} \
83 	} while (0)
84 
85 union flow_dv_attr {
86 	struct {
87 		uint32_t valid:1;
88 		uint32_t ipv4:1;
89 		uint32_t ipv6:1;
90 		uint32_t tcp:1;
91 		uint32_t udp:1;
92 		uint32_t reserved:27;
93 	};
94 	uint32_t attr;
95 };
96 
97 static int
98 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
99 				     uint32_t encap_decap_idx);
100 
101 static int
102 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
103 					uint32_t port_id);
104 static void
105 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss);
106 
107 static int
108 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
109 				  uint32_t rix_jump);
110 
111 /**
112  * Initialize flow attributes structure according to flow items' types.
113  *
114  * flow_dv_validate() avoids multiple L3/L4 layers cases other than tunnel
115  * mode. For tunnel mode, the items to be modified are the outermost ones.
116  *
117  * @param[in] item
118  *   Pointer to item specification.
119  * @param[out] attr
120  *   Pointer to flow attributes structure.
121  * @param[in] dev_flow
122  *   Pointer to the sub flow.
123  * @param[in] tunnel_decap
124  *   Whether action is after tunnel decapsulation.
125  */
126 static void
127 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
128 		  struct mlx5_flow *dev_flow, bool tunnel_decap)
129 {
130 	uint64_t layers = dev_flow->handle->layers;
131 	bool tunnel_match = false;
132 
133 	/*
134 	 * If layers is already initialized, it means this dev_flow is the
135 	 * suffix flow, the layers flags is set by the prefix flow. Need to
136 	 * use the layer flags from prefix flow as the suffix flow may not
137 	 * have the user defined items as the flow is split.
138 	 */
139 	if (layers) {
140 		if (tunnel_decap) {
141 			/*
142 			 * If decap action before modify, it means the driver
143 			 * should take the inner as outer for the modify actions.
144 			 */
145 			layers = ((layers >> 6) & MLX5_FLOW_LAYER_OUTER);
146 		}
147 		if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
148 			attr->ipv4 = 1;
149 		else if (layers & MLX5_FLOW_LAYER_OUTER_L3_IPV6)
150 			attr->ipv6 = 1;
151 		if (layers & MLX5_FLOW_LAYER_OUTER_L4_TCP)
152 			attr->tcp = 1;
153 		else if (layers & MLX5_FLOW_LAYER_OUTER_L4_UDP)
154 			attr->udp = 1;
155 		attr->valid = 1;
156 		return;
157 	}
158 	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
159 		uint8_t next_protocol = 0xff;
160 		switch (item->type) {
161 		case RTE_FLOW_ITEM_TYPE_GRE:
162 		case RTE_FLOW_ITEM_TYPE_NVGRE:
163 		case RTE_FLOW_ITEM_TYPE_VXLAN:
164 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
165 		case RTE_FLOW_ITEM_TYPE_GENEVE:
166 		case RTE_FLOW_ITEM_TYPE_MPLS:
167 		case RTE_FLOW_ITEM_TYPE_GTP:
168 			if (tunnel_decap) {
169 				attr->attr = 0;
170 				tunnel_match = true;
171 			}
172 			break;
173 		case RTE_FLOW_ITEM_TYPE_IPV4:
174 			if (!attr->ipv6)
175 				attr->ipv4 = 1;
176 			if (item->mask != NULL &&
177 			    ((const struct rte_flow_item_ipv4 *)
178 			    item->mask)->hdr.next_proto_id)
179 				next_protocol =
180 				    ((const struct rte_flow_item_ipv4 *)
181 				      (item->spec))->hdr.next_proto_id &
182 				    ((const struct rte_flow_item_ipv4 *)
183 				      (item->mask))->hdr.next_proto_id;
184 			if ((next_protocol == IPPROTO_IPIP ||
185 			    next_protocol == IPPROTO_IPV6) && tunnel_decap &&
186 			    !tunnel_match)
187 				attr->attr = 0;
188 			break;
189 		case RTE_FLOW_ITEM_TYPE_IPV6:
190 			if (!attr->ipv4)
191 				attr->ipv6 = 1;
192 			if (item->mask != NULL &&
193 			    ((const struct rte_flow_item_ipv6 *)
194 			    item->mask)->hdr.proto)
195 				next_protocol =
196 				    ((const struct rte_flow_item_ipv6 *)
197 				      (item->spec))->hdr.proto &
198 				    ((const struct rte_flow_item_ipv6 *)
199 				      (item->mask))->hdr.proto;
200 			if ((next_protocol == IPPROTO_IPIP ||
201 			    next_protocol == IPPROTO_IPV6) && tunnel_decap &&
202 			    !tunnel_match)
203 				attr->attr = 0;
204 			break;
205 		case RTE_FLOW_ITEM_TYPE_UDP:
206 			if (!attr->tcp)
207 				attr->udp = 1;
208 			break;
209 		case RTE_FLOW_ITEM_TYPE_TCP:
210 			if (!attr->udp)
211 				attr->tcp = 1;
212 			break;
213 		default:
214 			break;
215 		}
216 	}
217 	attr->valid = 1;
218 }
219 
220 struct field_modify_info modify_eth[] = {
221 	{4,  0, MLX5_MODI_OUT_DMAC_47_16},
222 	{2,  4, MLX5_MODI_OUT_DMAC_15_0},
223 	{4,  6, MLX5_MODI_OUT_SMAC_47_16},
224 	{2, 10, MLX5_MODI_OUT_SMAC_15_0},
225 	{0, 0, 0},
226 };
227 
228 struct field_modify_info modify_vlan_out_first_vid[] = {
229 	/* Size in bits !!! */
230 	{12, 0, MLX5_MODI_OUT_FIRST_VID},
231 	{0, 0, 0},
232 };
233 
234 struct field_modify_info modify_ipv4[] = {
235 	{1,  1, MLX5_MODI_OUT_IP_DSCP},
236 	{1,  8, MLX5_MODI_OUT_IPV4_TTL},
237 	{4, 12, MLX5_MODI_OUT_SIPV4},
238 	{4, 16, MLX5_MODI_OUT_DIPV4},
239 	{0, 0, 0},
240 };
241 
242 struct field_modify_info modify_ipv6[] = {
243 	{1,  0, MLX5_MODI_OUT_IP_DSCP},
244 	{1,  7, MLX5_MODI_OUT_IPV6_HOPLIMIT},
245 	{4,  8, MLX5_MODI_OUT_SIPV6_127_96},
246 	{4, 12, MLX5_MODI_OUT_SIPV6_95_64},
247 	{4, 16, MLX5_MODI_OUT_SIPV6_63_32},
248 	{4, 20, MLX5_MODI_OUT_SIPV6_31_0},
249 	{4, 24, MLX5_MODI_OUT_DIPV6_127_96},
250 	{4, 28, MLX5_MODI_OUT_DIPV6_95_64},
251 	{4, 32, MLX5_MODI_OUT_DIPV6_63_32},
252 	{4, 36, MLX5_MODI_OUT_DIPV6_31_0},
253 	{0, 0, 0},
254 };
255 
256 struct field_modify_info modify_udp[] = {
257 	{2, 0, MLX5_MODI_OUT_UDP_SPORT},
258 	{2, 2, MLX5_MODI_OUT_UDP_DPORT},
259 	{0, 0, 0},
260 };
261 
262 struct field_modify_info modify_tcp[] = {
263 	{2, 0, MLX5_MODI_OUT_TCP_SPORT},
264 	{2, 2, MLX5_MODI_OUT_TCP_DPORT},
265 	{4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM},
266 	{4, 8, MLX5_MODI_OUT_TCP_ACK_NUM},
267 	{0, 0, 0},
268 };
269 
270 static void
271 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused,
272 			  uint8_t next_protocol, uint64_t *item_flags,
273 			  int *tunnel)
274 {
275 	MLX5_ASSERT(item->type == RTE_FLOW_ITEM_TYPE_IPV4 ||
276 		    item->type == RTE_FLOW_ITEM_TYPE_IPV6);
277 	if (next_protocol == IPPROTO_IPIP) {
278 		*item_flags |= MLX5_FLOW_LAYER_IPIP;
279 		*tunnel = 1;
280 	}
281 	if (next_protocol == IPPROTO_IPV6) {
282 		*item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP;
283 		*tunnel = 1;
284 	}
285 }
286 
287 static inline struct mlx5_hlist *
288 flow_dv_hlist_prepare(struct mlx5_dev_ctx_shared *sh, struct mlx5_hlist **phl,
289 		     const char *name, uint32_t size, bool direct_key,
290 		     bool lcores_share, void *ctx,
291 		     mlx5_list_create_cb cb_create,
292 		     mlx5_list_match_cb cb_match,
293 		     mlx5_list_remove_cb cb_remove,
294 		     mlx5_list_clone_cb cb_clone,
295 		     mlx5_list_clone_free_cb cb_clone_free,
296 		     struct rte_flow_error *error)
297 {
298 	struct mlx5_hlist *hl;
299 	struct mlx5_hlist *expected = NULL;
300 	char s[MLX5_NAME_SIZE];
301 
302 	hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST);
303 	if (likely(hl))
304 		return hl;
305 	snprintf(s, sizeof(s), "%s_%s", sh->ibdev_name, name);
306 	hl = mlx5_hlist_create(s, size, direct_key, lcores_share,
307 			ctx, cb_create, cb_match, cb_remove, cb_clone,
308 			cb_clone_free);
309 	if (!hl) {
310 		DRV_LOG(ERR, "%s hash creation failed", name);
311 		rte_flow_error_set(error, ENOMEM,
312 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
313 				   "cannot allocate resource memory");
314 		return NULL;
315 	}
316 	if (!__atomic_compare_exchange_n(phl, &expected, hl, false,
317 					 __ATOMIC_SEQ_CST,
318 					 __ATOMIC_SEQ_CST)) {
319 		mlx5_hlist_destroy(hl);
320 		hl = __atomic_load_n(phl, __ATOMIC_SEQ_CST);
321 	}
322 	return hl;
323 }
324 
325 /* Update VLAN's VID/PCP based on input rte_flow_action.
326  *
327  * @param[in] action
328  *   Pointer to struct rte_flow_action.
329  * @param[out] vlan
330  *   Pointer to struct rte_vlan_hdr.
331  */
332 static void
333 mlx5_update_vlan_vid_pcp(const struct rte_flow_action *action,
334 			 struct rte_vlan_hdr *vlan)
335 {
336 	uint16_t vlan_tci;
337 	if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP) {
338 		vlan_tci =
339 		    ((const struct rte_flow_action_of_set_vlan_pcp *)
340 					       action->conf)->vlan_pcp;
341 		vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT;
342 		vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
343 		vlan->vlan_tci |= vlan_tci;
344 	} else if (action->type == RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID) {
345 		vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
346 		vlan->vlan_tci |= rte_be_to_cpu_16
347 		    (((const struct rte_flow_action_of_set_vlan_vid *)
348 					     action->conf)->vlan_vid);
349 	}
350 }
351 
352 /**
353  * Convert modify-header action to DV specification.
354  *
355  * Data length of each action is determined by provided field description
356  * and the item mask. Data bit offset and width of each action is determined
357  * by provided item mask.
358  *
359  * @param[in] item
360  *   Pointer to item specification.
361  * @param[in] field
362  *   Pointer to field modification information.
363  *     For MLX5_MODIFICATION_TYPE_SET specifies destination field.
364  *     For MLX5_MODIFICATION_TYPE_ADD specifies destination field.
365  *     For MLX5_MODIFICATION_TYPE_COPY specifies source field.
366  * @param[in] dcopy
367  *   Destination field info for MLX5_MODIFICATION_TYPE_COPY in @type.
368  *   Negative offset value sets the same offset as source offset.
369  *   size field is ignored, value is taken from source field.
370  * @param[in,out] resource
371  *   Pointer to the modify-header resource.
372  * @param[in] type
373  *   Type of modification.
374  * @param[out] error
375  *   Pointer to the error structure.
376  *
377  * @return
378  *   0 on success, a negative errno value otherwise and rte_errno is set.
379  */
380 int
381 flow_dv_convert_modify_action(struct rte_flow_item *item,
382 			      struct field_modify_info *field,
383 			      struct field_modify_info *dcopy,
384 			      struct mlx5_flow_dv_modify_hdr_resource *resource,
385 			      uint32_t type, struct rte_flow_error *error)
386 {
387 	uint32_t i = resource->actions_num;
388 	struct mlx5_modification_cmd *actions = resource->actions;
389 	uint32_t carry_b = 0;
390 
391 	/*
392 	 * The item and mask are provided in big-endian format.
393 	 * The fields should be presented as in big-endian format either.
394 	 * Mask must be always present, it defines the actual field width.
395 	 */
396 	MLX5_ASSERT(item->mask);
397 	MLX5_ASSERT(field->size);
398 	do {
399 		uint32_t size_b;
400 		uint32_t off_b;
401 		uint32_t mask;
402 		uint32_t data;
403 		bool next_field = true;
404 		bool next_dcopy = true;
405 
406 		if (i >= MLX5_MAX_MODIFY_NUM)
407 			return rte_flow_error_set(error, EINVAL,
408 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
409 				 "too many items to modify");
410 		/* Fetch variable byte size mask from the array. */
411 		mask = flow_dv_fetch_field((const uint8_t *)item->mask +
412 					   field->offset, field->size);
413 		if (!mask) {
414 			++field;
415 			continue;
416 		}
417 		/* Deduce actual data width in bits from mask value. */
418 		off_b = rte_bsf32(mask) + carry_b;
419 		size_b = sizeof(uint32_t) * CHAR_BIT -
420 			 off_b - __builtin_clz(mask);
421 		MLX5_ASSERT(size_b);
422 		actions[i] = (struct mlx5_modification_cmd) {
423 			.action_type = type,
424 			.field = field->id,
425 			.offset = off_b,
426 			.length = (size_b == sizeof(uint32_t) * CHAR_BIT) ?
427 				0 : size_b,
428 		};
429 		if (type == MLX5_MODIFICATION_TYPE_COPY) {
430 			MLX5_ASSERT(dcopy);
431 			actions[i].dst_field = dcopy->id;
432 			actions[i].dst_offset =
433 				(int)dcopy->offset < 0 ? off_b : dcopy->offset;
434 			/* Convert entire record to big-endian format. */
435 			actions[i].data1 = rte_cpu_to_be_32(actions[i].data1);
436 			/*
437 			 * Destination field overflow. Copy leftovers of
438 			 * a source field to the next destination field.
439 			 */
440 			carry_b = 0;
441 			if ((size_b > dcopy->size * CHAR_BIT - dcopy->offset) &&
442 			    dcopy->size != 0) {
443 				actions[i].length =
444 					dcopy->size * CHAR_BIT - dcopy->offset;
445 				carry_b = actions[i].length;
446 				next_field = false;
447 			}
448 			/*
449 			 * Not enough bits in a source filed to fill a
450 			 * destination field. Switch to the next source.
451 			 */
452 			if ((size_b < dcopy->size * CHAR_BIT - dcopy->offset) &&
453 			    (size_b == field->size * CHAR_BIT - off_b)) {
454 				actions[i].length =
455 					field->size * CHAR_BIT - off_b;
456 				dcopy->offset += actions[i].length;
457 				next_dcopy = false;
458 			}
459 			if (next_dcopy)
460 				++dcopy;
461 		} else {
462 			MLX5_ASSERT(item->spec);
463 			data = flow_dv_fetch_field((const uint8_t *)item->spec +
464 						   field->offset, field->size);
465 			/* Shift out the trailing masked bits from data. */
466 			data = (data & mask) >> off_b;
467 			actions[i].data1 = rte_cpu_to_be_32(data);
468 		}
469 		/* Convert entire record to expected big-endian format. */
470 		actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
471 		if (next_field)
472 			++field;
473 		++i;
474 	} while (field->size);
475 	if (resource->actions_num == i)
476 		return rte_flow_error_set(error, EINVAL,
477 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
478 					  "invalid modification flow item");
479 	resource->actions_num = i;
480 	return 0;
481 }
482 
483 /**
484  * Convert modify-header set IPv4 address action to DV specification.
485  *
486  * @param[in,out] resource
487  *   Pointer to the modify-header resource.
488  * @param[in] action
489  *   Pointer to action specification.
490  * @param[out] error
491  *   Pointer to the error structure.
492  *
493  * @return
494  *   0 on success, a negative errno value otherwise and rte_errno is set.
495  */
496 static int
497 flow_dv_convert_action_modify_ipv4
498 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
499 			 const struct rte_flow_action *action,
500 			 struct rte_flow_error *error)
501 {
502 	const struct rte_flow_action_set_ipv4 *conf =
503 		(const struct rte_flow_action_set_ipv4 *)(action->conf);
504 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
505 	struct rte_flow_item_ipv4 ipv4;
506 	struct rte_flow_item_ipv4 ipv4_mask;
507 
508 	memset(&ipv4, 0, sizeof(ipv4));
509 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
510 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) {
511 		ipv4.hdr.src_addr = conf->ipv4_addr;
512 		ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr;
513 	} else {
514 		ipv4.hdr.dst_addr = conf->ipv4_addr;
515 		ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr;
516 	}
517 	item.spec = &ipv4;
518 	item.mask = &ipv4_mask;
519 	return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
520 					     MLX5_MODIFICATION_TYPE_SET, error);
521 }
522 
523 /**
524  * Convert modify-header set IPv6 address action to DV specification.
525  *
526  * @param[in,out] resource
527  *   Pointer to the modify-header resource.
528  * @param[in] action
529  *   Pointer to action specification.
530  * @param[out] error
531  *   Pointer to the error structure.
532  *
533  * @return
534  *   0 on success, a negative errno value otherwise and rte_errno is set.
535  */
536 static int
537 flow_dv_convert_action_modify_ipv6
538 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
539 			 const struct rte_flow_action *action,
540 			 struct rte_flow_error *error)
541 {
542 	const struct rte_flow_action_set_ipv6 *conf =
543 		(const struct rte_flow_action_set_ipv6 *)(action->conf);
544 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
545 	struct rte_flow_item_ipv6 ipv6;
546 	struct rte_flow_item_ipv6 ipv6_mask;
547 
548 	memset(&ipv6, 0, sizeof(ipv6));
549 	memset(&ipv6_mask, 0, sizeof(ipv6_mask));
550 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) {
551 		memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr,
552 		       sizeof(ipv6.hdr.src_addr));
553 		memcpy(&ipv6_mask.hdr.src_addr,
554 		       &rte_flow_item_ipv6_mask.hdr.src_addr,
555 		       sizeof(ipv6.hdr.src_addr));
556 	} else {
557 		memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr,
558 		       sizeof(ipv6.hdr.dst_addr));
559 		memcpy(&ipv6_mask.hdr.dst_addr,
560 		       &rte_flow_item_ipv6_mask.hdr.dst_addr,
561 		       sizeof(ipv6.hdr.dst_addr));
562 	}
563 	item.spec = &ipv6;
564 	item.mask = &ipv6_mask;
565 	return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
566 					     MLX5_MODIFICATION_TYPE_SET, error);
567 }
568 
569 /**
570  * Convert modify-header set MAC address action to DV specification.
571  *
572  * @param[in,out] resource
573  *   Pointer to the modify-header resource.
574  * @param[in] action
575  *   Pointer to action specification.
576  * @param[out] error
577  *   Pointer to the error structure.
578  *
579  * @return
580  *   0 on success, a negative errno value otherwise and rte_errno is set.
581  */
582 static int
583 flow_dv_convert_action_modify_mac
584 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
585 			 const struct rte_flow_action *action,
586 			 struct rte_flow_error *error)
587 {
588 	const struct rte_flow_action_set_mac *conf =
589 		(const struct rte_flow_action_set_mac *)(action->conf);
590 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH };
591 	struct rte_flow_item_eth eth;
592 	struct rte_flow_item_eth eth_mask;
593 
594 	memset(&eth, 0, sizeof(eth));
595 	memset(&eth_mask, 0, sizeof(eth_mask));
596 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) {
597 		memcpy(&eth.hdr.src_addr.addr_bytes, &conf->mac_addr,
598 		       sizeof(eth.hdr.src_addr.addr_bytes));
599 		memcpy(&eth_mask.hdr.src_addr.addr_bytes,
600 		       &rte_flow_item_eth_mask.hdr.src_addr.addr_bytes,
601 		       sizeof(eth_mask.hdr.src_addr.addr_bytes));
602 	} else {
603 		memcpy(&eth.hdr.dst_addr.addr_bytes, &conf->mac_addr,
604 		       sizeof(eth.hdr.dst_addr.addr_bytes));
605 		memcpy(&eth_mask.hdr.dst_addr.addr_bytes,
606 		       &rte_flow_item_eth_mask.hdr.dst_addr.addr_bytes,
607 		       sizeof(eth_mask.hdr.dst_addr.addr_bytes));
608 	}
609 	item.spec = &eth;
610 	item.mask = &eth_mask;
611 	return flow_dv_convert_modify_action(&item, modify_eth, NULL, resource,
612 					     MLX5_MODIFICATION_TYPE_SET, error);
613 }
614 
615 /**
616  * Convert modify-header set VLAN VID action to DV specification.
617  *
618  * @param[in,out] resource
619  *   Pointer to the modify-header resource.
620  * @param[in] action
621  *   Pointer to action specification.
622  * @param[out] error
623  *   Pointer to the error structure.
624  *
625  * @return
626  *   0 on success, a negative errno value otherwise and rte_errno is set.
627  */
628 static int
629 flow_dv_convert_action_modify_vlan_vid
630 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
631 			 const struct rte_flow_action *action,
632 			 struct rte_flow_error *error)
633 {
634 	const struct rte_flow_action_of_set_vlan_vid *conf =
635 		(const struct rte_flow_action_of_set_vlan_vid *)(action->conf);
636 	int i = resource->actions_num;
637 	struct mlx5_modification_cmd *actions = resource->actions;
638 	struct field_modify_info *field = modify_vlan_out_first_vid;
639 
640 	if (i >= MLX5_MAX_MODIFY_NUM)
641 		return rte_flow_error_set(error, EINVAL,
642 			 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
643 			 "too many items to modify");
644 	actions[i] = (struct mlx5_modification_cmd) {
645 		.action_type = MLX5_MODIFICATION_TYPE_SET,
646 		.field = field->id,
647 		.length = field->size,
648 		.offset = field->offset,
649 	};
650 	actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
651 	actions[i].data1 = conf->vlan_vid;
652 	actions[i].data1 = actions[i].data1 << 16;
653 	resource->actions_num = ++i;
654 	return 0;
655 }
656 
657 /**
658  * Convert modify-header set TP action to DV specification.
659  *
660  * @param[in,out] resource
661  *   Pointer to the modify-header resource.
662  * @param[in] action
663  *   Pointer to action specification.
664  * @param[in] items
665  *   Pointer to rte_flow_item objects list.
666  * @param[in] attr
667  *   Pointer to flow attributes structure.
668  * @param[in] dev_flow
669  *   Pointer to the sub flow.
670  * @param[in] tunnel_decap
671  *   Whether action is after tunnel decapsulation.
672  * @param[out] error
673  *   Pointer to the error structure.
674  *
675  * @return
676  *   0 on success, a negative errno value otherwise and rte_errno is set.
677  */
678 static int
679 flow_dv_convert_action_modify_tp
680 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
681 			 const struct rte_flow_action *action,
682 			 const struct rte_flow_item *items,
683 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
684 			 bool tunnel_decap, struct rte_flow_error *error)
685 {
686 	const struct rte_flow_action_set_tp *conf =
687 		(const struct rte_flow_action_set_tp *)(action->conf);
688 	struct rte_flow_item item;
689 	struct rte_flow_item_udp udp;
690 	struct rte_flow_item_udp udp_mask;
691 	struct rte_flow_item_tcp tcp;
692 	struct rte_flow_item_tcp tcp_mask;
693 	struct field_modify_info *field;
694 
695 	if (!attr->valid)
696 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
697 	if (attr->udp) {
698 		memset(&udp, 0, sizeof(udp));
699 		memset(&udp_mask, 0, sizeof(udp_mask));
700 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
701 			udp.hdr.src_port = conf->port;
702 			udp_mask.hdr.src_port =
703 					rte_flow_item_udp_mask.hdr.src_port;
704 		} else {
705 			udp.hdr.dst_port = conf->port;
706 			udp_mask.hdr.dst_port =
707 					rte_flow_item_udp_mask.hdr.dst_port;
708 		}
709 		item.type = RTE_FLOW_ITEM_TYPE_UDP;
710 		item.spec = &udp;
711 		item.mask = &udp_mask;
712 		field = modify_udp;
713 	} else {
714 		MLX5_ASSERT(attr->tcp);
715 		memset(&tcp, 0, sizeof(tcp));
716 		memset(&tcp_mask, 0, sizeof(tcp_mask));
717 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
718 			tcp.hdr.src_port = conf->port;
719 			tcp_mask.hdr.src_port =
720 					rte_flow_item_tcp_mask.hdr.src_port;
721 		} else {
722 			tcp.hdr.dst_port = conf->port;
723 			tcp_mask.hdr.dst_port =
724 					rte_flow_item_tcp_mask.hdr.dst_port;
725 		}
726 		item.type = RTE_FLOW_ITEM_TYPE_TCP;
727 		item.spec = &tcp;
728 		item.mask = &tcp_mask;
729 		field = modify_tcp;
730 	}
731 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
732 					     MLX5_MODIFICATION_TYPE_SET, error);
733 }
734 
735 /**
736  * Convert modify-header set TTL action to DV specification.
737  *
738  * @param[in,out] resource
739  *   Pointer to the modify-header resource.
740  * @param[in] action
741  *   Pointer to action specification.
742  * @param[in] items
743  *   Pointer to rte_flow_item objects list.
744  * @param[in] attr
745  *   Pointer to flow attributes structure.
746  * @param[in] dev_flow
747  *   Pointer to the sub flow.
748  * @param[in] tunnel_decap
749  *   Whether action is after tunnel decapsulation.
750  * @param[out] error
751  *   Pointer to the error structure.
752  *
753  * @return
754  *   0 on success, a negative errno value otherwise and rte_errno is set.
755  */
756 static int
757 flow_dv_convert_action_modify_ttl
758 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
759 			 const struct rte_flow_action *action,
760 			 const struct rte_flow_item *items,
761 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
762 			 bool tunnel_decap, struct rte_flow_error *error)
763 {
764 	const struct rte_flow_action_set_ttl *conf =
765 		(const struct rte_flow_action_set_ttl *)(action->conf);
766 	struct rte_flow_item item;
767 	struct rte_flow_item_ipv4 ipv4;
768 	struct rte_flow_item_ipv4 ipv4_mask;
769 	struct rte_flow_item_ipv6 ipv6;
770 	struct rte_flow_item_ipv6 ipv6_mask;
771 	struct field_modify_info *field;
772 
773 	if (!attr->valid)
774 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
775 	if (attr->ipv4) {
776 		memset(&ipv4, 0, sizeof(ipv4));
777 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
778 		ipv4.hdr.time_to_live = conf->ttl_value;
779 		ipv4_mask.hdr.time_to_live = 0xFF;
780 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
781 		item.spec = &ipv4;
782 		item.mask = &ipv4_mask;
783 		field = modify_ipv4;
784 	} else {
785 		MLX5_ASSERT(attr->ipv6);
786 		memset(&ipv6, 0, sizeof(ipv6));
787 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
788 		ipv6.hdr.hop_limits = conf->ttl_value;
789 		ipv6_mask.hdr.hop_limits = 0xFF;
790 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
791 		item.spec = &ipv6;
792 		item.mask = &ipv6_mask;
793 		field = modify_ipv6;
794 	}
795 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
796 					     MLX5_MODIFICATION_TYPE_SET, error);
797 }
798 
799 /**
800  * Convert modify-header decrement TTL action to DV specification.
801  *
802  * @param[in,out] resource
803  *   Pointer to the modify-header resource.
804  * @param[in] action
805  *   Pointer to action specification.
806  * @param[in] items
807  *   Pointer to rte_flow_item objects list.
808  * @param[in] attr
809  *   Pointer to flow attributes structure.
810  * @param[in] dev_flow
811  *   Pointer to the sub flow.
812  * @param[in] tunnel_decap
813  *   Whether action is after tunnel decapsulation.
814  * @param[out] error
815  *   Pointer to the error structure.
816  *
817  * @return
818  *   0 on success, a negative errno value otherwise and rte_errno is set.
819  */
820 static int
821 flow_dv_convert_action_modify_dec_ttl
822 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
823 			 const struct rte_flow_item *items,
824 			 union flow_dv_attr *attr, struct mlx5_flow *dev_flow,
825 			 bool tunnel_decap, struct rte_flow_error *error)
826 {
827 	struct rte_flow_item item;
828 	struct rte_flow_item_ipv4 ipv4;
829 	struct rte_flow_item_ipv4 ipv4_mask;
830 	struct rte_flow_item_ipv6 ipv6;
831 	struct rte_flow_item_ipv6 ipv6_mask;
832 	struct field_modify_info *field;
833 
834 	if (!attr->valid)
835 		flow_dv_attr_init(items, attr, dev_flow, tunnel_decap);
836 	if (attr->ipv4) {
837 		memset(&ipv4, 0, sizeof(ipv4));
838 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
839 		ipv4.hdr.time_to_live = 0xFF;
840 		ipv4_mask.hdr.time_to_live = 0xFF;
841 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
842 		item.spec = &ipv4;
843 		item.mask = &ipv4_mask;
844 		field = modify_ipv4;
845 	} else {
846 		MLX5_ASSERT(attr->ipv6);
847 		memset(&ipv6, 0, sizeof(ipv6));
848 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
849 		ipv6.hdr.hop_limits = 0xFF;
850 		ipv6_mask.hdr.hop_limits = 0xFF;
851 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
852 		item.spec = &ipv6;
853 		item.mask = &ipv6_mask;
854 		field = modify_ipv6;
855 	}
856 	return flow_dv_convert_modify_action(&item, field, NULL, resource,
857 					     MLX5_MODIFICATION_TYPE_ADD, error);
858 }
859 
860 /**
861  * Convert modify-header increment/decrement TCP Sequence number
862  * to DV specification.
863  *
864  * @param[in,out] resource
865  *   Pointer to the modify-header resource.
866  * @param[in] action
867  *   Pointer to action specification.
868  * @param[out] error
869  *   Pointer to the error structure.
870  *
871  * @return
872  *   0 on success, a negative errno value otherwise and rte_errno is set.
873  */
874 static int
875 flow_dv_convert_action_modify_tcp_seq
876 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
877 			 const struct rte_flow_action *action,
878 			 struct rte_flow_error *error)
879 {
880 	const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
881 	uint64_t value = rte_be_to_cpu_32(*conf);
882 	struct rte_flow_item item;
883 	struct rte_flow_item_tcp tcp;
884 	struct rte_flow_item_tcp tcp_mask;
885 
886 	memset(&tcp, 0, sizeof(tcp));
887 	memset(&tcp_mask, 0, sizeof(tcp_mask));
888 	if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ)
889 		/*
890 		 * The HW has no decrement operation, only increment operation.
891 		 * To simulate decrement X from Y using increment operation
892 		 * we need to add UINT32_MAX X times to Y.
893 		 * Each adding of UINT32_MAX decrements Y by 1.
894 		 */
895 		value *= UINT32_MAX;
896 	tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value);
897 	tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX);
898 	item.type = RTE_FLOW_ITEM_TYPE_TCP;
899 	item.spec = &tcp;
900 	item.mask = &tcp_mask;
901 	return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
902 					     MLX5_MODIFICATION_TYPE_ADD, error);
903 }
904 
905 /**
906  * Convert modify-header increment/decrement TCP Acknowledgment number
907  * to DV specification.
908  *
909  * @param[in,out] resource
910  *   Pointer to the modify-header resource.
911  * @param[in] action
912  *   Pointer to action specification.
913  * @param[out] error
914  *   Pointer to the error structure.
915  *
916  * @return
917  *   0 on success, a negative errno value otherwise and rte_errno is set.
918  */
919 static int
920 flow_dv_convert_action_modify_tcp_ack
921 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
922 			 const struct rte_flow_action *action,
923 			 struct rte_flow_error *error)
924 {
925 	const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
926 	uint64_t value = rte_be_to_cpu_32(*conf);
927 	struct rte_flow_item item;
928 	struct rte_flow_item_tcp tcp;
929 	struct rte_flow_item_tcp tcp_mask;
930 
931 	memset(&tcp, 0, sizeof(tcp));
932 	memset(&tcp_mask, 0, sizeof(tcp_mask));
933 	if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK)
934 		/*
935 		 * The HW has no decrement operation, only increment operation.
936 		 * To simulate decrement X from Y using increment operation
937 		 * we need to add UINT32_MAX X times to Y.
938 		 * Each adding of UINT32_MAX decrements Y by 1.
939 		 */
940 		value *= UINT32_MAX;
941 	tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value);
942 	tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX);
943 	item.type = RTE_FLOW_ITEM_TYPE_TCP;
944 	item.spec = &tcp;
945 	item.mask = &tcp_mask;
946 	return flow_dv_convert_modify_action(&item, modify_tcp, NULL, resource,
947 					     MLX5_MODIFICATION_TYPE_ADD, error);
948 }
949 
950 static enum mlx5_modification_field reg_to_field[] = {
951 	[REG_NON] = MLX5_MODI_OUT_NONE,
952 	[REG_A] = MLX5_MODI_META_DATA_REG_A,
953 	[REG_B] = MLX5_MODI_META_DATA_REG_B,
954 	[REG_C_0] = MLX5_MODI_META_REG_C_0,
955 	[REG_C_1] = MLX5_MODI_META_REG_C_1,
956 	[REG_C_2] = MLX5_MODI_META_REG_C_2,
957 	[REG_C_3] = MLX5_MODI_META_REG_C_3,
958 	[REG_C_4] = MLX5_MODI_META_REG_C_4,
959 	[REG_C_5] = MLX5_MODI_META_REG_C_5,
960 	[REG_C_6] = MLX5_MODI_META_REG_C_6,
961 	[REG_C_7] = MLX5_MODI_META_REG_C_7,
962 };
963 
964 /**
965  * Convert register set to DV specification.
966  *
967  * @param[in,out] resource
968  *   Pointer to the modify-header resource.
969  * @param[in] action
970  *   Pointer to action specification.
971  * @param[out] error
972  *   Pointer to the error structure.
973  *
974  * @return
975  *   0 on success, a negative errno value otherwise and rte_errno is set.
976  */
977 static int
978 flow_dv_convert_action_set_reg
979 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
980 			 const struct rte_flow_action *action,
981 			 struct rte_flow_error *error)
982 {
983 	const struct mlx5_rte_flow_action_set_tag *conf = action->conf;
984 	struct mlx5_modification_cmd *actions = resource->actions;
985 	uint32_t i = resource->actions_num;
986 
987 	if (i >= MLX5_MAX_MODIFY_NUM)
988 		return rte_flow_error_set(error, EINVAL,
989 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
990 					  "too many items to modify");
991 	MLX5_ASSERT(conf->id != REG_NON);
992 	MLX5_ASSERT(conf->id < (enum modify_reg)RTE_DIM(reg_to_field));
993 	actions[i] = (struct mlx5_modification_cmd) {
994 		.action_type = MLX5_MODIFICATION_TYPE_SET,
995 		.field = reg_to_field[conf->id],
996 		.offset = conf->offset,
997 		.length = conf->length,
998 	};
999 	actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
1000 	actions[i].data1 = rte_cpu_to_be_32(conf->data);
1001 	++i;
1002 	resource->actions_num = i;
1003 	return 0;
1004 }
1005 
1006 /**
1007  * Convert SET_TAG action to DV specification.
1008  *
1009  * @param[in] dev
1010  *   Pointer to the rte_eth_dev structure.
1011  * @param[in,out] resource
1012  *   Pointer to the modify-header resource.
1013  * @param[in] conf
1014  *   Pointer to action specification.
1015  * @param[out] error
1016  *   Pointer to the error structure.
1017  *
1018  * @return
1019  *   0 on success, a negative errno value otherwise and rte_errno is set.
1020  */
1021 static int
1022 flow_dv_convert_action_set_tag
1023 			(struct rte_eth_dev *dev,
1024 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1025 			 const struct rte_flow_action_set_tag *conf,
1026 			 struct rte_flow_error *error)
1027 {
1028 	rte_be32_t data = rte_cpu_to_be_32(conf->data);
1029 	rte_be32_t mask = rte_cpu_to_be_32(conf->mask);
1030 	struct rte_flow_item item = {
1031 		.spec = &data,
1032 		.mask = &mask,
1033 	};
1034 	struct field_modify_info reg_c_x[] = {
1035 		[1] = {0, 0, 0},
1036 	};
1037 	enum mlx5_modification_field reg_type;
1038 	int ret;
1039 
1040 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
1041 	if (ret < 0)
1042 		return ret;
1043 	MLX5_ASSERT(ret != REG_NON);
1044 	MLX5_ASSERT((unsigned int)ret < RTE_DIM(reg_to_field));
1045 	reg_type = reg_to_field[ret];
1046 	MLX5_ASSERT(reg_type > 0);
1047 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_type};
1048 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1049 					     MLX5_MODIFICATION_TYPE_SET, error);
1050 }
1051 
1052 /**
1053  * Convert internal COPY_REG action to DV specification.
1054  *
1055  * @param[in] dev
1056  *   Pointer to the rte_eth_dev structure.
1057  * @param[in,out] res
1058  *   Pointer to the modify-header resource.
1059  * @param[in] action
1060  *   Pointer to action specification.
1061  * @param[out] error
1062  *   Pointer to the error structure.
1063  *
1064  * @return
1065  *   0 on success, a negative errno value otherwise and rte_errno is set.
1066  */
1067 static int
1068 flow_dv_convert_action_copy_mreg(struct rte_eth_dev *dev,
1069 				 struct mlx5_flow_dv_modify_hdr_resource *res,
1070 				 const struct rte_flow_action *action,
1071 				 struct rte_flow_error *error)
1072 {
1073 	const struct mlx5_flow_action_copy_mreg *conf = action->conf;
1074 	rte_be32_t mask = RTE_BE32(UINT32_MAX);
1075 	struct rte_flow_item item = {
1076 		.spec = NULL,
1077 		.mask = &mask,
1078 	};
1079 	struct field_modify_info reg_src[] = {
1080 		{4, 0, reg_to_field[conf->src]},
1081 		{0, 0, 0},
1082 	};
1083 	struct field_modify_info reg_dst = {
1084 		.offset = 0,
1085 		.id = reg_to_field[conf->dst],
1086 	};
1087 	/* Adjust reg_c[0] usage according to reported mask. */
1088 	if (conf->dst == REG_C_0 || conf->src == REG_C_0) {
1089 		struct mlx5_priv *priv = dev->data->dev_private;
1090 		uint32_t reg_c0 = priv->sh->dv_regc0_mask;
1091 
1092 		MLX5_ASSERT(reg_c0);
1093 		MLX5_ASSERT(priv->sh->config.dv_xmeta_en !=
1094 			    MLX5_XMETA_MODE_LEGACY);
1095 		if (conf->dst == REG_C_0) {
1096 			/* Copy to reg_c[0], within mask only. */
1097 			reg_dst.offset = rte_bsf32(reg_c0);
1098 			mask = rte_cpu_to_be_32(reg_c0 >> reg_dst.offset);
1099 		} else {
1100 			reg_dst.offset = 0;
1101 			mask = rte_cpu_to_be_32(reg_c0);
1102 		}
1103 	}
1104 	return flow_dv_convert_modify_action(&item,
1105 					     reg_src, &reg_dst, res,
1106 					     MLX5_MODIFICATION_TYPE_COPY,
1107 					     error);
1108 }
1109 
1110 /**
1111  * Convert MARK action to DV specification. This routine is used
1112  * in extensive metadata only and requires metadata register to be
1113  * handled. In legacy mode hardware tag resource is engaged.
1114  *
1115  * @param[in] dev
1116  *   Pointer to the rte_eth_dev structure.
1117  * @param[in] conf
1118  *   Pointer to MARK action specification.
1119  * @param[in,out] resource
1120  *   Pointer to the modify-header resource.
1121  * @param[out] error
1122  *   Pointer to the error structure.
1123  *
1124  * @return
1125  *   0 on success, a negative errno value otherwise and rte_errno is set.
1126  */
1127 static int
1128 flow_dv_convert_action_mark(struct rte_eth_dev *dev,
1129 			    const struct rte_flow_action_mark *conf,
1130 			    struct mlx5_flow_dv_modify_hdr_resource *resource,
1131 			    struct rte_flow_error *error)
1132 {
1133 	struct mlx5_priv *priv = dev->data->dev_private;
1134 	rte_be32_t mask = rte_cpu_to_be_32(MLX5_FLOW_MARK_MASK &
1135 					   priv->sh->dv_mark_mask);
1136 	rte_be32_t data = rte_cpu_to_be_32(conf->id) & mask;
1137 	struct rte_flow_item item = {
1138 		.spec = &data,
1139 		.mask = &mask,
1140 	};
1141 	struct field_modify_info reg_c_x[] = {
1142 		[1] = {0, 0, 0},
1143 	};
1144 	int reg;
1145 
1146 	if (!mask)
1147 		return rte_flow_error_set(error, EINVAL,
1148 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1149 					  NULL, "zero mark action mask");
1150 	reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
1151 	if (reg < 0)
1152 		return reg;
1153 	MLX5_ASSERT(reg > 0);
1154 	if (reg == REG_C_0) {
1155 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1156 		uint32_t shl_c0 = rte_bsf32(msk_c0);
1157 
1158 		data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0);
1159 		mask = rte_cpu_to_be_32(mask) & msk_c0;
1160 		mask = rte_cpu_to_be_32(mask << shl_c0);
1161 	}
1162 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1163 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1164 					     MLX5_MODIFICATION_TYPE_SET, error);
1165 }
1166 
1167 /**
1168  * Get metadata register index for specified steering domain.
1169  *
1170  * @param[in] dev
1171  *   Pointer to the rte_eth_dev structure.
1172  * @param[in] attr
1173  *   Attributes of flow to determine steering domain.
1174  * @param[out] error
1175  *   Pointer to the error structure.
1176  *
1177  * @return
1178  *   positive index on success, a negative errno value otherwise
1179  *   and rte_errno is set.
1180  */
1181 static enum modify_reg
1182 flow_dv_get_metadata_reg(struct rte_eth_dev *dev,
1183 			 const struct rte_flow_attr *attr,
1184 			 struct rte_flow_error *error)
1185 {
1186 	int reg =
1187 		mlx5_flow_get_reg_id(dev, attr->transfer ?
1188 					  MLX5_METADATA_FDB :
1189 					    attr->egress ?
1190 					    MLX5_METADATA_TX :
1191 					    MLX5_METADATA_RX, 0, error);
1192 	if (reg < 0)
1193 		return rte_flow_error_set(error,
1194 					  ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
1195 					  NULL, "unavailable "
1196 					  "metadata register");
1197 	return reg;
1198 }
1199 
1200 /**
1201  * Convert SET_META action to DV specification.
1202  *
1203  * @param[in] dev
1204  *   Pointer to the rte_eth_dev structure.
1205  * @param[in,out] resource
1206  *   Pointer to the modify-header resource.
1207  * @param[in] attr
1208  *   Attributes of flow that includes this item.
1209  * @param[in] conf
1210  *   Pointer to action specification.
1211  * @param[out] error
1212  *   Pointer to the error structure.
1213  *
1214  * @return
1215  *   0 on success, a negative errno value otherwise and rte_errno is set.
1216  */
1217 static int
1218 flow_dv_convert_action_set_meta
1219 			(struct rte_eth_dev *dev,
1220 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1221 			 const struct rte_flow_attr *attr,
1222 			 const struct rte_flow_action_set_meta *conf,
1223 			 struct rte_flow_error *error)
1224 {
1225 	uint32_t mask = rte_cpu_to_be_32(conf->mask);
1226 	uint32_t data = rte_cpu_to_be_32(conf->data) & mask;
1227 	struct rte_flow_item item = {
1228 		.spec = &data,
1229 		.mask = &mask,
1230 	};
1231 	struct field_modify_info reg_c_x[] = {
1232 		[1] = {0, 0, 0},
1233 	};
1234 	int reg = flow_dv_get_metadata_reg(dev, attr, error);
1235 
1236 	if (reg < 0)
1237 		return reg;
1238 	MLX5_ASSERT(reg != REG_NON);
1239 	if (reg == REG_C_0) {
1240 		struct mlx5_priv *priv = dev->data->dev_private;
1241 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
1242 		uint32_t shl_c0 = rte_bsf32(msk_c0);
1243 
1244 		data = rte_cpu_to_be_32(rte_cpu_to_be_32(data) << shl_c0);
1245 		mask = rte_cpu_to_be_32(mask) & msk_c0;
1246 		mask = rte_cpu_to_be_32(mask << shl_c0);
1247 	}
1248 	reg_c_x[0] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1249 	/* The routine expects parameters in memory as big-endian ones. */
1250 	return flow_dv_convert_modify_action(&item, reg_c_x, NULL, resource,
1251 					     MLX5_MODIFICATION_TYPE_SET, error);
1252 }
1253 
1254 /**
1255  * Convert modify-header set IPv4 DSCP action to DV specification.
1256  *
1257  * @param[in,out] resource
1258  *   Pointer to the modify-header resource.
1259  * @param[in] action
1260  *   Pointer to action specification.
1261  * @param[out] error
1262  *   Pointer to the error structure.
1263  *
1264  * @return
1265  *   0 on success, a negative errno value otherwise and rte_errno is set.
1266  */
1267 static int
1268 flow_dv_convert_action_modify_ipv4_dscp
1269 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1270 			 const struct rte_flow_action *action,
1271 			 struct rte_flow_error *error)
1272 {
1273 	const struct rte_flow_action_set_dscp *conf =
1274 		(const struct rte_flow_action_set_dscp *)(action->conf);
1275 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
1276 	struct rte_flow_item_ipv4 ipv4;
1277 	struct rte_flow_item_ipv4 ipv4_mask;
1278 
1279 	memset(&ipv4, 0, sizeof(ipv4));
1280 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
1281 	ipv4.hdr.type_of_service = conf->dscp;
1282 	ipv4_mask.hdr.type_of_service = RTE_IPV4_HDR_DSCP_MASK >> 2;
1283 	item.spec = &ipv4;
1284 	item.mask = &ipv4_mask;
1285 	return flow_dv_convert_modify_action(&item, modify_ipv4, NULL, resource,
1286 					     MLX5_MODIFICATION_TYPE_SET, error);
1287 }
1288 
1289 /**
1290  * Convert modify-header set IPv6 DSCP action to DV specification.
1291  *
1292  * @param[in,out] resource
1293  *   Pointer to the modify-header resource.
1294  * @param[in] action
1295  *   Pointer to action specification.
1296  * @param[out] error
1297  *   Pointer to the error structure.
1298  *
1299  * @return
1300  *   0 on success, a negative errno value otherwise and rte_errno is set.
1301  */
1302 static int
1303 flow_dv_convert_action_modify_ipv6_dscp
1304 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
1305 			 const struct rte_flow_action *action,
1306 			 struct rte_flow_error *error)
1307 {
1308 	const struct rte_flow_action_set_dscp *conf =
1309 		(const struct rte_flow_action_set_dscp *)(action->conf);
1310 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
1311 	struct rte_flow_item_ipv6 ipv6;
1312 	struct rte_flow_item_ipv6 ipv6_mask;
1313 
1314 	memset(&ipv6, 0, sizeof(ipv6));
1315 	memset(&ipv6_mask, 0, sizeof(ipv6_mask));
1316 	/*
1317 	 * Even though the DSCP bits offset of IPv6 is not byte aligned,
1318 	 * rdma-core only accept the DSCP bits byte aligned start from
1319 	 * bit 0 to 5 as to be compatible with IPv4. No need to shift the
1320 	 * bits in IPv6 case as rdma-core requires byte aligned value.
1321 	 */
1322 	ipv6.hdr.vtc_flow = conf->dscp;
1323 	ipv6_mask.hdr.vtc_flow = RTE_IPV6_HDR_DSCP_MASK >> 22;
1324 	item.spec = &ipv6;
1325 	item.mask = &ipv6_mask;
1326 	return flow_dv_convert_modify_action(&item, modify_ipv6, NULL, resource,
1327 					     MLX5_MODIFICATION_TYPE_SET, error);
1328 }
1329 
1330 int
1331 mlx5_flow_item_field_width(struct rte_eth_dev *dev,
1332 			   enum rte_flow_field_id field, int inherit,
1333 			   const struct rte_flow_attr *attr,
1334 			   struct rte_flow_error *error)
1335 {
1336 	struct mlx5_priv *priv = dev->data->dev_private;
1337 
1338 	switch (field) {
1339 	case RTE_FLOW_FIELD_START:
1340 		return 32;
1341 	case RTE_FLOW_FIELD_MAC_DST:
1342 	case RTE_FLOW_FIELD_MAC_SRC:
1343 		return 48;
1344 	case RTE_FLOW_FIELD_VLAN_TYPE:
1345 		return 16;
1346 	case RTE_FLOW_FIELD_VLAN_ID:
1347 		return 12;
1348 	case RTE_FLOW_FIELD_MAC_TYPE:
1349 		return 16;
1350 	case RTE_FLOW_FIELD_IPV4_DSCP:
1351 		return 6;
1352 	case RTE_FLOW_FIELD_IPV4_TTL:
1353 		return 8;
1354 	case RTE_FLOW_FIELD_IPV4_SRC:
1355 	case RTE_FLOW_FIELD_IPV4_DST:
1356 		return 32;
1357 	case RTE_FLOW_FIELD_IPV6_DSCP:
1358 		return 6;
1359 	case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
1360 		return 8;
1361 	case RTE_FLOW_FIELD_IPV6_SRC:
1362 	case RTE_FLOW_FIELD_IPV6_DST:
1363 		return 128;
1364 	case RTE_FLOW_FIELD_TCP_PORT_SRC:
1365 	case RTE_FLOW_FIELD_TCP_PORT_DST:
1366 		return 16;
1367 	case RTE_FLOW_FIELD_TCP_SEQ_NUM:
1368 	case RTE_FLOW_FIELD_TCP_ACK_NUM:
1369 		return 32;
1370 	case RTE_FLOW_FIELD_TCP_FLAGS:
1371 		return 9;
1372 	case RTE_FLOW_FIELD_UDP_PORT_SRC:
1373 	case RTE_FLOW_FIELD_UDP_PORT_DST:
1374 		return 16;
1375 	case RTE_FLOW_FIELD_VXLAN_VNI:
1376 	case RTE_FLOW_FIELD_GENEVE_VNI:
1377 		return 24;
1378 	case RTE_FLOW_FIELD_GTP_TEID:
1379 	case RTE_FLOW_FIELD_TAG:
1380 		return 32;
1381 	case RTE_FLOW_FIELD_MARK:
1382 		return __builtin_popcount(priv->sh->dv_mark_mask);
1383 	case RTE_FLOW_FIELD_META:
1384 		return (flow_dv_get_metadata_reg(dev, attr, error) == REG_C_0) ?
1385 			__builtin_popcount(priv->sh->dv_meta_mask) : 32;
1386 	case RTE_FLOW_FIELD_POINTER:
1387 	case RTE_FLOW_FIELD_VALUE:
1388 		return inherit < 0 ? 0 : inherit;
1389 	case RTE_FLOW_FIELD_IPV4_ECN:
1390 	case RTE_FLOW_FIELD_IPV6_ECN:
1391 	case RTE_FLOW_FIELD_METER_COLOR:
1392 		return 2;
1393 	default:
1394 		MLX5_ASSERT(false);
1395 	}
1396 	return 0;
1397 }
1398 
1399 static __rte_always_inline uint8_t
1400 flow_modify_info_mask_8(uint32_t length, uint32_t off)
1401 {
1402 	return (0xffu >> (8 - length)) << off;
1403 }
1404 
1405 static __rte_always_inline uint16_t
1406 flow_modify_info_mask_16(uint32_t length, uint32_t off)
1407 {
1408 	return rte_cpu_to_be_16((0xffffu >> (16 - length)) << off);
1409 }
1410 
1411 static __rte_always_inline uint32_t
1412 flow_modify_info_mask_32(uint32_t length, uint32_t off)
1413 {
1414 	return rte_cpu_to_be_32((0xffffffffu >> (32 - length)) << off);
1415 }
1416 
1417 static __rte_always_inline uint32_t
1418 flow_modify_info_mask_32_masked(uint32_t length, uint32_t off, uint32_t post_mask)
1419 {
1420 	uint32_t mask = (0xffffffffu >> (32 - length)) << off;
1421 	return rte_cpu_to_be_32(mask & post_mask);
1422 }
1423 
1424 void
1425 mlx5_flow_field_id_to_modify_info
1426 		(const struct rte_flow_action_modify_data *data,
1427 		 struct field_modify_info *info, uint32_t *mask,
1428 		 uint32_t width, struct rte_eth_dev *dev,
1429 		 const struct rte_flow_attr *attr, struct rte_flow_error *error)
1430 {
1431 	struct mlx5_priv *priv = dev->data->dev_private;
1432 	uint32_t idx = 0;
1433 	uint32_t off_be = 0;
1434 	uint32_t length = 0;
1435 	switch ((int)data->field) {
1436 	case RTE_FLOW_FIELD_START:
1437 		/* not supported yet */
1438 		MLX5_ASSERT(false);
1439 		break;
1440 	case RTE_FLOW_FIELD_MAC_DST:
1441 		MLX5_ASSERT(data->offset + width <= 48);
1442 		off_be = 48 - (data->offset + width);
1443 		if (off_be < 16) {
1444 			info[idx] = (struct field_modify_info){2, 4,
1445 					MLX5_MODI_OUT_DMAC_15_0};
1446 			length = off_be + width <= 16 ? width : 16 - off_be;
1447 			if (mask)
1448 				mask[1] = flow_modify_info_mask_16(length,
1449 								   off_be);
1450 			else
1451 				info[idx].offset = off_be;
1452 			width -= length;
1453 			if (!width)
1454 				break;
1455 			off_be = 0;
1456 			idx++;
1457 		} else {
1458 			off_be -= 16;
1459 		}
1460 		info[idx] = (struct field_modify_info){4, 0,
1461 				MLX5_MODI_OUT_DMAC_47_16};
1462 		if (mask)
1463 			mask[0] = flow_modify_info_mask_32(width, off_be);
1464 		else
1465 			info[idx].offset = off_be;
1466 		break;
1467 	case RTE_FLOW_FIELD_MAC_SRC:
1468 		MLX5_ASSERT(data->offset + width <= 48);
1469 		off_be = 48 - (data->offset + width);
1470 		if (off_be < 16) {
1471 			info[idx] = (struct field_modify_info){2, 4,
1472 					MLX5_MODI_OUT_SMAC_15_0};
1473 			length = off_be + width <= 16 ? width : 16 - off_be;
1474 			if (mask)
1475 				mask[1] = flow_modify_info_mask_16(length,
1476 								   off_be);
1477 			else
1478 				info[idx].offset = off_be;
1479 			width -= length;
1480 			if (!width)
1481 				break;
1482 			off_be = 0;
1483 			idx++;
1484 		} else {
1485 			off_be -= 16;
1486 		}
1487 		info[idx] = (struct field_modify_info){4, 0,
1488 				MLX5_MODI_OUT_SMAC_47_16};
1489 		if (mask)
1490 			mask[0] = flow_modify_info_mask_32(width, off_be);
1491 		else
1492 			info[idx].offset = off_be;
1493 		break;
1494 	case RTE_FLOW_FIELD_VLAN_TYPE:
1495 		/* not supported yet */
1496 		break;
1497 	case RTE_FLOW_FIELD_VLAN_ID:
1498 		MLX5_ASSERT(data->offset + width <= 12);
1499 		off_be = 12 - (data->offset + width);
1500 		info[idx] = (struct field_modify_info){2, 0,
1501 					MLX5_MODI_OUT_FIRST_VID};
1502 		if (mask)
1503 			mask[idx] = flow_modify_info_mask_16(width, off_be);
1504 		else
1505 			info[idx].offset = off_be;
1506 		break;
1507 	case RTE_FLOW_FIELD_MAC_TYPE:
1508 		MLX5_ASSERT(data->offset + width <= 16);
1509 		off_be = 16 - (data->offset + width);
1510 		info[idx] = (struct field_modify_info){2, 0,
1511 					MLX5_MODI_OUT_ETHERTYPE};
1512 		if (mask)
1513 			mask[idx] = flow_modify_info_mask_16(width, off_be);
1514 		else
1515 			info[idx].offset = off_be;
1516 		break;
1517 	case RTE_FLOW_FIELD_IPV4_DSCP:
1518 		MLX5_ASSERT(data->offset + width <= 6);
1519 		off_be = 6 - (data->offset + width);
1520 		info[idx] = (struct field_modify_info){1, 0,
1521 					MLX5_MODI_OUT_IP_DSCP};
1522 		if (mask)
1523 			mask[idx] = flow_modify_info_mask_8(width, off_be);
1524 		else
1525 			info[idx].offset = off_be;
1526 		break;
1527 	case RTE_FLOW_FIELD_IPV4_TTL:
1528 		MLX5_ASSERT(data->offset + width <= 8);
1529 		off_be = 8 - (data->offset + width);
1530 		info[idx] = (struct field_modify_info){1, 0,
1531 					MLX5_MODI_OUT_IPV4_TTL};
1532 		if (mask)
1533 			mask[idx] = flow_modify_info_mask_8(width, off_be);
1534 		else
1535 			info[idx].offset = off_be;
1536 		break;
1537 	case RTE_FLOW_FIELD_IPV4_SRC:
1538 		MLX5_ASSERT(data->offset + width <= 32);
1539 		off_be = 32 - (data->offset + width);
1540 		info[idx] = (struct field_modify_info){4, 0,
1541 					MLX5_MODI_OUT_SIPV4};
1542 		if (mask)
1543 			mask[idx] = flow_modify_info_mask_32(width, off_be);
1544 		else
1545 			info[idx].offset = off_be;
1546 		break;
1547 	case RTE_FLOW_FIELD_IPV4_DST:
1548 		MLX5_ASSERT(data->offset + width <= 32);
1549 		off_be = 32 - (data->offset + width);
1550 		info[idx] = (struct field_modify_info){4, 0,
1551 					MLX5_MODI_OUT_DIPV4};
1552 		if (mask)
1553 			mask[idx] = flow_modify_info_mask_32(width, off_be);
1554 		else
1555 			info[idx].offset = off_be;
1556 		break;
1557 	case RTE_FLOW_FIELD_IPV6_DSCP:
1558 		MLX5_ASSERT(data->offset + width <= 6);
1559 		off_be = 6 - (data->offset + width);
1560 		info[idx] = (struct field_modify_info){1, 0,
1561 					MLX5_MODI_OUT_IP_DSCP};
1562 		if (mask)
1563 			mask[idx] = flow_modify_info_mask_8(width, off_be);
1564 		else
1565 			info[idx].offset = off_be;
1566 		break;
1567 	case RTE_FLOW_FIELD_IPV6_HOPLIMIT:
1568 		MLX5_ASSERT(data->offset + width <= 8);
1569 		off_be = 8 - (data->offset + width);
1570 		info[idx] = (struct field_modify_info){1, 0,
1571 					MLX5_MODI_OUT_IPV6_HOPLIMIT};
1572 		if (mask)
1573 			mask[idx] = flow_modify_info_mask_8(width, off_be);
1574 		else
1575 			info[idx].offset = off_be;
1576 		break;
1577 	case RTE_FLOW_FIELD_IPV6_SRC: {
1578 		/*
1579 		 * Fields corresponding to IPv6 source address bytes
1580 		 * arranged according to network byte ordering.
1581 		 */
1582 		struct field_modify_info fields[] = {
1583 			{ 4, 0, MLX5_MODI_OUT_SIPV6_127_96 },
1584 			{ 4, 4, MLX5_MODI_OUT_SIPV6_95_64 },
1585 			{ 4, 8, MLX5_MODI_OUT_SIPV6_63_32 },
1586 			{ 4, 12, MLX5_MODI_OUT_SIPV6_31_0 },
1587 		};
1588 		/* First mask to be modified is the mask of 4th address byte. */
1589 		uint32_t midx = 3;
1590 
1591 		MLX5_ASSERT(data->offset + width <= 128);
1592 		off_be = 128 - (data->offset + width);
1593 		while (width > 0 && midx > 0) {
1594 			if (off_be < 32) {
1595 				info[idx] = fields[midx];
1596 				length = off_be + width <= 32 ?
1597 					 width : 32 - off_be;
1598 				if (mask)
1599 					mask[midx] = flow_modify_info_mask_32
1600 						(length, off_be);
1601 				else
1602 					info[idx].offset = off_be;
1603 				width -= length;
1604 				off_be = 0;
1605 				idx++;
1606 			} else {
1607 				off_be -= 32;
1608 			}
1609 			midx--;
1610 		}
1611 		if (!width)
1612 			break;
1613 		info[idx] = fields[midx];
1614 		if (mask)
1615 			mask[midx] = flow_modify_info_mask_32(width, off_be);
1616 		else
1617 			info[idx].offset = off_be;
1618 		break;
1619 	}
1620 	case RTE_FLOW_FIELD_IPV6_DST: {
1621 		/*
1622 		 * Fields corresponding to IPv6 destination address bytes
1623 		 * arranged according to network byte ordering.
1624 		 */
1625 		struct field_modify_info fields[] = {
1626 			{ 4, 0, MLX5_MODI_OUT_DIPV6_127_96 },
1627 			{ 4, 4, MLX5_MODI_OUT_DIPV6_95_64 },
1628 			{ 4, 8, MLX5_MODI_OUT_DIPV6_63_32 },
1629 			{ 4, 12, MLX5_MODI_OUT_DIPV6_31_0 },
1630 		};
1631 		/* First mask to be modified is the mask of 4th address byte. */
1632 		uint32_t midx = 3;
1633 
1634 		MLX5_ASSERT(data->offset + width <= 128);
1635 		off_be = 128 - (data->offset + width);
1636 		while (width > 0 && midx > 0) {
1637 			if (off_be < 32) {
1638 				info[idx] = fields[midx];
1639 				length = off_be + width <= 32 ?
1640 					 width : 32 - off_be;
1641 				if (mask)
1642 					mask[midx] = flow_modify_info_mask_32
1643 						(length, off_be);
1644 				else
1645 					info[idx].offset = off_be;
1646 				width -= length;
1647 				off_be = 0;
1648 				idx++;
1649 			} else {
1650 				off_be -= 32;
1651 			}
1652 			midx--;
1653 		}
1654 		if (!width)
1655 			break;
1656 		info[idx] = fields[midx];
1657 		if (mask)
1658 			mask[midx] = flow_modify_info_mask_32(width, off_be);
1659 		else
1660 			info[idx].offset = off_be;
1661 		break;
1662 	}
1663 	case RTE_FLOW_FIELD_TCP_PORT_SRC:
1664 		MLX5_ASSERT(data->offset + width <= 16);
1665 		off_be = 16 - (data->offset + width);
1666 		info[idx] = (struct field_modify_info){2, 0,
1667 					MLX5_MODI_OUT_TCP_SPORT};
1668 		if (mask)
1669 			mask[idx] = flow_modify_info_mask_16(width, off_be);
1670 		else
1671 			info[idx].offset = off_be;
1672 		break;
1673 	case RTE_FLOW_FIELD_TCP_PORT_DST:
1674 		MLX5_ASSERT(data->offset + width <= 16);
1675 		off_be = 16 - (data->offset + width);
1676 		info[idx] = (struct field_modify_info){2, 0,
1677 					MLX5_MODI_OUT_TCP_DPORT};
1678 		if (mask)
1679 			mask[idx] = flow_modify_info_mask_16(width, off_be);
1680 		else
1681 			info[idx].offset = off_be;
1682 		break;
1683 	case RTE_FLOW_FIELD_TCP_SEQ_NUM:
1684 		MLX5_ASSERT(data->offset + width <= 32);
1685 		off_be = 32 - (data->offset + width);
1686 		info[idx] = (struct field_modify_info){4, 0,
1687 					MLX5_MODI_OUT_TCP_SEQ_NUM};
1688 		if (mask)
1689 			mask[idx] = flow_modify_info_mask_32(width, off_be);
1690 		else
1691 			info[idx].offset = off_be;
1692 		break;
1693 	case RTE_FLOW_FIELD_TCP_ACK_NUM:
1694 		MLX5_ASSERT(data->offset + width <= 32);
1695 		off_be = 32 - (data->offset + width);
1696 		info[idx] = (struct field_modify_info){4, 0,
1697 					MLX5_MODI_OUT_TCP_ACK_NUM};
1698 		if (mask)
1699 			mask[idx] = flow_modify_info_mask_32(width, off_be);
1700 		else
1701 			info[idx].offset = off_be;
1702 		break;
1703 	case RTE_FLOW_FIELD_TCP_FLAGS:
1704 		MLX5_ASSERT(data->offset + width <= 9);
1705 		off_be = 9 - (data->offset + width);
1706 		info[idx] = (struct field_modify_info){2, 0,
1707 					MLX5_MODI_OUT_TCP_FLAGS};
1708 		if (mask)
1709 			mask[idx] = flow_modify_info_mask_16(width, off_be);
1710 		else
1711 			info[idx].offset = off_be;
1712 		break;
1713 	case RTE_FLOW_FIELD_UDP_PORT_SRC:
1714 		MLX5_ASSERT(data->offset + width <= 16);
1715 		off_be = 16 - (data->offset + width);
1716 		info[idx] = (struct field_modify_info){2, 0,
1717 					MLX5_MODI_OUT_UDP_SPORT};
1718 		if (mask)
1719 			mask[idx] = flow_modify_info_mask_16(width, off_be);
1720 		else
1721 			info[idx].offset = off_be;
1722 		break;
1723 	case RTE_FLOW_FIELD_UDP_PORT_DST:
1724 		MLX5_ASSERT(data->offset + width <= 16);
1725 		off_be = 16 - (data->offset + width);
1726 		info[idx] = (struct field_modify_info){2, 0,
1727 					MLX5_MODI_OUT_UDP_DPORT};
1728 		if (mask)
1729 			mask[idx] = flow_modify_info_mask_16(width, off_be);
1730 		else
1731 			info[idx].offset = off_be;
1732 		break;
1733 	case RTE_FLOW_FIELD_VXLAN_VNI:
1734 		MLX5_ASSERT(data->offset + width <= 24);
1735 		/* VNI is on bits 31-8 of TUNNEL_HDR_DW_1. */
1736 		off_be = 24 - (data->offset + width) + 8;
1737 		info[idx] = (struct field_modify_info){4, 0,
1738 					MLX5_MODI_TUNNEL_HDR_DW_1};
1739 		if (mask)
1740 			mask[idx] = flow_modify_info_mask_32(width, off_be);
1741 		else
1742 			info[idx].offset = off_be;
1743 		break;
1744 	case RTE_FLOW_FIELD_GENEVE_VNI:
1745 		/* not supported yet*/
1746 		break;
1747 	case RTE_FLOW_FIELD_GTP_TEID:
1748 		MLX5_ASSERT(data->offset + width <= 32);
1749 		off_be = 32 - (data->offset + width);
1750 		info[idx] = (struct field_modify_info){4, 0,
1751 					MLX5_MODI_GTP_TEID};
1752 		if (mask)
1753 			mask[idx] = flow_modify_info_mask_32(width, off_be);
1754 		else
1755 			info[idx].offset = off_be;
1756 		break;
1757 	case RTE_FLOW_FIELD_TAG:
1758 		{
1759 			MLX5_ASSERT(data->offset + width <= 32);
1760 			int reg;
1761 
1762 			if (priv->sh->config.dv_flow_en == 2)
1763 				reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_TAG,
1764 							 data->level);
1765 			else
1766 				reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG,
1767 							   data->level, error);
1768 			if (reg < 0)
1769 				return;
1770 			MLX5_ASSERT(reg != REG_NON);
1771 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1772 			info[idx] = (struct field_modify_info){4, 0,
1773 						reg_to_field[reg]};
1774 			if (mask)
1775 				mask[idx] = flow_modify_info_mask_32
1776 					(width, data->offset);
1777 			else
1778 				info[idx].offset = data->offset;
1779 		}
1780 		break;
1781 	case RTE_FLOW_FIELD_MARK:
1782 		{
1783 			uint32_t mark_mask = priv->sh->dv_mark_mask;
1784 			uint32_t mark_count = __builtin_popcount(mark_mask);
1785 			RTE_SET_USED(mark_count);
1786 			MLX5_ASSERT(data->offset + width <= mark_count);
1787 			int reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK,
1788 						       0, error);
1789 			if (reg < 0)
1790 				return;
1791 			MLX5_ASSERT(reg != REG_NON);
1792 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1793 			info[idx] = (struct field_modify_info){4, 0,
1794 						reg_to_field[reg]};
1795 			if (mask)
1796 				mask[idx] = flow_modify_info_mask_32_masked
1797 					(width, data->offset, mark_mask);
1798 			else
1799 				info[idx].offset = data->offset;
1800 		}
1801 		break;
1802 	case RTE_FLOW_FIELD_META:
1803 		{
1804 			uint32_t meta_mask = priv->sh->dv_meta_mask;
1805 			uint32_t meta_count = __builtin_popcount(meta_mask);
1806 			RTE_SET_USED(meta_count);
1807 			MLX5_ASSERT(data->offset + width <= meta_count);
1808 			int reg = flow_dv_get_metadata_reg(dev, attr, error);
1809 			if (reg < 0)
1810 				return;
1811 			MLX5_ASSERT(reg != REG_NON);
1812 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1813 			info[idx] = (struct field_modify_info){4, 0,
1814 						reg_to_field[reg]};
1815 			if (mask)
1816 				mask[idx] = flow_modify_info_mask_32_masked
1817 					(width, data->offset, meta_mask);
1818 			else
1819 				info[idx].offset = data->offset;
1820 		}
1821 		break;
1822 	case RTE_FLOW_FIELD_IPV4_ECN:
1823 	case RTE_FLOW_FIELD_IPV6_ECN:
1824 		MLX5_ASSERT(data->offset + width <= 2);
1825 		off_be = 2 - (data->offset + width);
1826 		info[idx] = (struct field_modify_info){1, 0,
1827 					MLX5_MODI_OUT_IP_ECN};
1828 		if (mask)
1829 			mask[idx] = flow_modify_info_mask_8(width, off_be);
1830 		else
1831 			info[idx].offset = off_be;
1832 		break;
1833 	case RTE_FLOW_FIELD_GTP_PSC_QFI:
1834 		MLX5_ASSERT(data->offset + width <= 8);
1835 		off_be = data->offset + 8;
1836 		info[idx] = (struct field_modify_info){4, 0,
1837 					MLX5_MODI_GTPU_FIRST_EXT_DW_0};
1838 		if (mask)
1839 			mask[idx] = flow_modify_info_mask_32(width, off_be);
1840 		else
1841 			info[idx].offset = off_be;
1842 		break;
1843 	case MLX5_RTE_FLOW_FIELD_META_REG:
1844 		{
1845 			uint32_t meta_mask = priv->sh->dv_meta_mask;
1846 			uint32_t meta_count = __builtin_popcount(meta_mask);
1847 			uint32_t reg = data->level;
1848 
1849 			RTE_SET_USED(meta_count);
1850 			MLX5_ASSERT(data->offset + width <= meta_count);
1851 			MLX5_ASSERT(reg != REG_NON);
1852 			MLX5_ASSERT(reg < RTE_DIM(reg_to_field));
1853 			info[idx] = (struct field_modify_info){4, 0, reg_to_field[reg]};
1854 			if (mask)
1855 				mask[idx] = flow_modify_info_mask_32_masked
1856 					(width, data->offset, meta_mask);
1857 			else
1858 				info[idx].offset = data->offset;
1859 		}
1860 		break;
1861 	case RTE_FLOW_FIELD_METER_COLOR:
1862 		{
1863 			const uint32_t color_mask =
1864 				(UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
1865 			int reg;
1866 
1867 			if (priv->sh->config.dv_flow_en == 2)
1868 				reg = flow_hw_get_reg_id
1869 					(RTE_FLOW_ITEM_TYPE_METER_COLOR, 0);
1870 			else
1871 				reg = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR,
1872 						       0, error);
1873 			if (reg < 0)
1874 				return;
1875 			MLX5_ASSERT(reg != REG_NON);
1876 			MLX5_ASSERT((unsigned int)reg < RTE_DIM(reg_to_field));
1877 			info[idx] = (struct field_modify_info){4, 0,
1878 						reg_to_field[reg]};
1879 			if (mask)
1880 				mask[idx] = flow_modify_info_mask_32_masked
1881 					(width, data->offset, color_mask);
1882 			else
1883 				info[idx].offset = data->offset;
1884 		}
1885 		break;
1886 	case RTE_FLOW_FIELD_POINTER:
1887 	case RTE_FLOW_FIELD_VALUE:
1888 	default:
1889 		MLX5_ASSERT(false);
1890 		break;
1891 	}
1892 }
1893 
1894 /**
1895  * Convert modify_field action to DV specification.
1896  *
1897  * @param[in] dev
1898  *   Pointer to the rte_eth_dev structure.
1899  * @param[in,out] resource
1900  *   Pointer to the modify-header resource.
1901  * @param[in] action
1902  *   Pointer to action specification.
1903  * @param[in] attr
1904  *   Attributes of flow that includes this item.
1905  * @param[out] error
1906  *   Pointer to the error structure.
1907  *
1908  * @return
1909  *   0 on success, a negative errno value otherwise and rte_errno is set.
1910  */
1911 static int
1912 flow_dv_convert_action_modify_field
1913 			(struct rte_eth_dev *dev,
1914 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1915 			 const struct rte_flow_action *action,
1916 			 const struct rte_flow_attr *attr,
1917 			 struct rte_flow_error *error)
1918 {
1919 	const struct rte_flow_action_modify_field *conf =
1920 		(const struct rte_flow_action_modify_field *)(action->conf);
1921 	struct rte_flow_item item = {
1922 		.spec = NULL,
1923 		.mask = NULL
1924 	};
1925 	struct field_modify_info field[MLX5_ACT_MAX_MOD_FIELDS] = {
1926 								{0, 0, 0} };
1927 	struct field_modify_info dcopy[MLX5_ACT_MAX_MOD_FIELDS] = {
1928 								{0, 0, 0} };
1929 	uint32_t mask[MLX5_ACT_MAX_MOD_FIELDS] = {0, 0, 0, 0, 0};
1930 	uint32_t type, meta = 0;
1931 
1932 	if (conf->src.field == RTE_FLOW_FIELD_POINTER ||
1933 	    conf->src.field == RTE_FLOW_FIELD_VALUE) {
1934 		type = conf->operation == RTE_FLOW_MODIFY_SET ?
1935 			MLX5_MODIFICATION_TYPE_SET : MLX5_MODIFICATION_TYPE_ADD;
1936 		/** For SET fill the destination field (field) first. */
1937 		mlx5_flow_field_id_to_modify_info(&conf->dst, field, mask,
1938 						  conf->width, dev,
1939 						  attr, error);
1940 		item.spec = conf->src.field == RTE_FLOW_FIELD_POINTER ?
1941 					(void *)(uintptr_t)conf->src.pvalue :
1942 					(void *)(uintptr_t)&conf->src.value;
1943 		if (conf->dst.field == RTE_FLOW_FIELD_META ||
1944 		    conf->dst.field == RTE_FLOW_FIELD_TAG ||
1945 		    conf->dst.field == RTE_FLOW_FIELD_METER_COLOR) {
1946 			meta = *(const unaligned_uint32_t *)item.spec;
1947 			meta = rte_cpu_to_be_32(meta);
1948 			item.spec = &meta;
1949 		}
1950 	} else {
1951 		type = MLX5_MODIFICATION_TYPE_COPY;
1952 		/** For COPY fill the destination field (dcopy) without mask. */
1953 		mlx5_flow_field_id_to_modify_info(&conf->dst, dcopy, NULL,
1954 						  conf->width, dev,
1955 						  attr, error);
1956 		/** Then construct the source field (field) with mask. */
1957 		mlx5_flow_field_id_to_modify_info(&conf->src, field, mask,
1958 						  conf->width, dev,
1959 						  attr, error);
1960 	}
1961 	item.mask = &mask;
1962 	return flow_dv_convert_modify_action(&item,
1963 			field, dcopy, resource, type, error);
1964 }
1965 
1966 /**
1967  * Validate MARK item.
1968  *
1969  * @param[in] dev
1970  *   Pointer to the rte_eth_dev structure.
1971  * @param[in] item
1972  *   Item specification.
1973  * @param[in] attr
1974  *   Attributes of flow that includes this item.
1975  * @param[out] error
1976  *   Pointer to error structure.
1977  *
1978  * @return
1979  *   0 on success, a negative errno value otherwise and rte_errno is set.
1980  */
1981 static int
1982 flow_dv_validate_item_mark(struct rte_eth_dev *dev,
1983 			   const struct rte_flow_item *item,
1984 			   const struct rte_flow_attr *attr __rte_unused,
1985 			   struct rte_flow_error *error)
1986 {
1987 	struct mlx5_priv *priv = dev->data->dev_private;
1988 	struct mlx5_sh_config *config = &priv->sh->config;
1989 	const struct rte_flow_item_mark *spec = item->spec;
1990 	const struct rte_flow_item_mark *mask = item->mask;
1991 	const struct rte_flow_item_mark nic_mask = {
1992 		.id = priv->sh->dv_mark_mask,
1993 	};
1994 	int ret;
1995 
1996 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
1997 		return rte_flow_error_set(error, ENOTSUP,
1998 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
1999 					  "extended metadata feature"
2000 					  " isn't enabled");
2001 	if (!mlx5_flow_ext_mreg_supported(dev))
2002 		return rte_flow_error_set(error, ENOTSUP,
2003 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2004 					  "extended metadata register"
2005 					  " isn't supported");
2006 	if (!nic_mask.id)
2007 		return rte_flow_error_set(error, ENOTSUP,
2008 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2009 					  "extended metadata register"
2010 					  " isn't available");
2011 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
2012 	if (ret < 0)
2013 		return ret;
2014 	if (!spec)
2015 		return rte_flow_error_set(error, EINVAL,
2016 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2017 					  item->spec,
2018 					  "data cannot be empty");
2019 	if (spec->id >= (MLX5_FLOW_MARK_MAX & nic_mask.id))
2020 		return rte_flow_error_set(error, EINVAL,
2021 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
2022 					  &spec->id,
2023 					  "mark id exceeds the limit");
2024 	if (!mask)
2025 		mask = &nic_mask;
2026 	if (!mask->id)
2027 		return rte_flow_error_set(error, EINVAL,
2028 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2029 					"mask cannot be zero");
2030 
2031 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2032 					(const uint8_t *)&nic_mask,
2033 					sizeof(struct rte_flow_item_mark),
2034 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2035 	if (ret < 0)
2036 		return ret;
2037 	return 0;
2038 }
2039 
2040 /**
2041  * Validate META item.
2042  *
2043  * @param[in] dev
2044  *   Pointer to the rte_eth_dev structure.
2045  * @param[in] item
2046  *   Item specification.
2047  * @param[in] attr
2048  *   Attributes of flow that includes this item.
2049  * @param[out] error
2050  *   Pointer to error structure.
2051  *
2052  * @return
2053  *   0 on success, a negative errno value otherwise and rte_errno is set.
2054  */
2055 static int
2056 flow_dv_validate_item_meta(struct rte_eth_dev *dev __rte_unused,
2057 			   const struct rte_flow_item *item,
2058 			   const struct rte_flow_attr *attr,
2059 			   struct rte_flow_error *error)
2060 {
2061 	struct mlx5_priv *priv = dev->data->dev_private;
2062 	struct mlx5_sh_config *config = &priv->sh->config;
2063 	const struct rte_flow_item_meta *spec = item->spec;
2064 	const struct rte_flow_item_meta *mask = item->mask;
2065 	struct rte_flow_item_meta nic_mask = {
2066 		.data = UINT32_MAX
2067 	};
2068 	int reg;
2069 	int ret;
2070 
2071 	if (!spec)
2072 		return rte_flow_error_set(error, EINVAL,
2073 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2074 					  item->spec,
2075 					  "data cannot be empty");
2076 	if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
2077 		if (!mlx5_flow_ext_mreg_supported(dev))
2078 			return rte_flow_error_set(error, ENOTSUP,
2079 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2080 					  "extended metadata register"
2081 					  " isn't supported");
2082 		reg = flow_dv_get_metadata_reg(dev, attr, error);
2083 		if (reg < 0)
2084 			return reg;
2085 		if (reg == REG_NON)
2086 			return rte_flow_error_set(error, ENOTSUP,
2087 					RTE_FLOW_ERROR_TYPE_ITEM, item,
2088 					"unavailable extended metadata register");
2089 		if (reg == REG_B)
2090 			return rte_flow_error_set(error, ENOTSUP,
2091 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2092 					  "match on reg_b "
2093 					  "isn't supported");
2094 		if (reg != REG_A)
2095 			nic_mask.data = priv->sh->dv_meta_mask;
2096 	} else {
2097 		if (attr->transfer)
2098 			return rte_flow_error_set(error, ENOTSUP,
2099 					RTE_FLOW_ERROR_TYPE_ITEM, item,
2100 					"extended metadata feature "
2101 					"should be enabled when "
2102 					"meta item is requested "
2103 					"with e-switch mode ");
2104 		if (attr->ingress)
2105 			return rte_flow_error_set(error, ENOTSUP,
2106 					RTE_FLOW_ERROR_TYPE_ITEM, item,
2107 					"match on metadata for ingress "
2108 					"is not supported in legacy "
2109 					"metadata mode");
2110 	}
2111 	if (!mask)
2112 		mask = &rte_flow_item_meta_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_meta),
2121 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2122 	return ret;
2123 }
2124 
2125 /**
2126  * Validate TAG item.
2127  *
2128  * @param[in] dev
2129  *   Pointer to the rte_eth_dev structure.
2130  * @param[in] item
2131  *   Item specification.
2132  * @param[in] attr
2133  *   Attributes of flow that includes this item.
2134  * @param[out] error
2135  *   Pointer to error structure.
2136  *
2137  * @return
2138  *   0 on success, a negative errno value otherwise and rte_errno is set.
2139  */
2140 static int
2141 flow_dv_validate_item_tag(struct rte_eth_dev *dev,
2142 			  const struct rte_flow_item *item,
2143 			  const struct rte_flow_attr *attr __rte_unused,
2144 			  struct rte_flow_error *error)
2145 {
2146 	const struct rte_flow_item_tag *spec = item->spec;
2147 	const struct rte_flow_item_tag *mask = item->mask;
2148 	const struct rte_flow_item_tag nic_mask = {
2149 		.data = RTE_BE32(UINT32_MAX),
2150 		.index = 0xff,
2151 	};
2152 	int ret;
2153 
2154 	if (!mlx5_flow_ext_mreg_supported(dev))
2155 		return rte_flow_error_set(error, ENOTSUP,
2156 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2157 					  "extensive metadata register"
2158 					  " isn't supported");
2159 	if (!spec)
2160 		return rte_flow_error_set(error, EINVAL,
2161 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
2162 					  item->spec,
2163 					  "data cannot be empty");
2164 	if (!mask)
2165 		mask = &rte_flow_item_tag_mask;
2166 	if (!mask->data)
2167 		return rte_flow_error_set(error, EINVAL,
2168 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2169 					"mask cannot be zero");
2170 
2171 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2172 					(const uint8_t *)&nic_mask,
2173 					sizeof(struct rte_flow_item_tag),
2174 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2175 	if (ret < 0)
2176 		return ret;
2177 	if (mask->index != 0xff)
2178 		return rte_flow_error_set(error, EINVAL,
2179 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
2180 					  "partial mask for tag index"
2181 					  " is not supported");
2182 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, spec->index, error);
2183 	if (ret < 0)
2184 		return ret;
2185 	MLX5_ASSERT(ret != REG_NON);
2186 	return 0;
2187 }
2188 
2189 /**
2190  * Validate vport item.
2191  *
2192  * @param[in] dev
2193  *   Pointer to the rte_eth_dev structure.
2194  * @param[in] item
2195  *   Item specification.
2196  * @param[in] attr
2197  *   Attributes of flow that includes this item.
2198  * @param[in] item_flags
2199  *   Bit-fields that holds the items detected until now.
2200  * @param[out] error
2201  *   Pointer to error structure.
2202  *
2203  * @return
2204  *   0 on success, a negative errno value otherwise and rte_errno is set.
2205  */
2206 static int
2207 flow_dv_validate_item_port_id(struct rte_eth_dev *dev,
2208 			      const struct rte_flow_item *item,
2209 			      const struct rte_flow_attr *attr,
2210 			      uint64_t item_flags,
2211 			      struct mlx5_priv **act_priv,
2212 			      struct rte_flow_error *error)
2213 {
2214 	const struct rte_flow_item_port_id *spec = item->spec;
2215 	const struct rte_flow_item_port_id *mask = item->mask;
2216 	const struct rte_flow_item_port_id switch_mask = {
2217 			.id = 0xffffffff,
2218 	};
2219 	struct mlx5_priv *esw_priv;
2220 	struct mlx5_priv *dev_priv;
2221 	int ret;
2222 
2223 	if (!attr->transfer)
2224 		return rte_flow_error_set(error, EINVAL,
2225 					  RTE_FLOW_ERROR_TYPE_ITEM,
2226 					  NULL,
2227 					  "match on port id is valid only"
2228 					  " when transfer flag is enabled");
2229 	if (item_flags & MLX5_FLOW_ITEM_PORT_ID)
2230 		return rte_flow_error_set(error, ENOTSUP,
2231 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2232 					  "multiple source ports are not"
2233 					  " supported");
2234 	if (!mask)
2235 		mask = &switch_mask;
2236 	if (mask->id != 0xffffffff)
2237 		return rte_flow_error_set(error, ENOTSUP,
2238 					   RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2239 					   mask,
2240 					   "no support for partial mask on"
2241 					   " \"id\" field");
2242 	ret = mlx5_flow_item_acceptable
2243 				(item, (const uint8_t *)mask,
2244 				 (const uint8_t *)&rte_flow_item_port_id_mask,
2245 				 sizeof(struct rte_flow_item_port_id),
2246 				 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2247 	if (ret)
2248 		return ret;
2249 	if (!spec)
2250 		return 0;
2251 	if (spec->id == MLX5_PORT_ESW_MGR)
2252 		return 0;
2253 	esw_priv = mlx5_port_to_eswitch_info(spec->id, false);
2254 	if (!esw_priv)
2255 		return rte_flow_error_set(error, rte_errno,
2256 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2257 					  "failed to obtain E-Switch info for"
2258 					  " port");
2259 	dev_priv = mlx5_dev_to_eswitch_info(dev);
2260 	if (!dev_priv)
2261 		return rte_flow_error_set(error, rte_errno,
2262 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2263 					  NULL,
2264 					  "failed to obtain E-Switch info");
2265 	if (esw_priv->domain_id != dev_priv->domain_id)
2266 		return rte_flow_error_set(error, EINVAL,
2267 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2268 					  "cannot match on a port from a"
2269 					  " different E-Switch");
2270 	*act_priv = esw_priv;
2271 	return 0;
2272 }
2273 
2274 /**
2275  * Validate represented port item.
2276  *
2277  * @param[in] dev
2278  *   Pointer to the rte_eth_dev structure.
2279  * @param[in] item
2280  *   Item specification.
2281  * @param[in] attr
2282  *   Attributes of flow that includes this item.
2283  * @param[in] item_flags
2284  *   Bit-fields that holds the items detected until now.
2285  * @param[out] error
2286  *   Pointer to error structure.
2287  *
2288  * @return
2289  *   0 on success, a negative errno value otherwise and rte_errno is set.
2290  */
2291 static int
2292 flow_dv_validate_item_represented_port(struct rte_eth_dev *dev,
2293 				       const struct rte_flow_item *item,
2294 				       const struct rte_flow_attr *attr,
2295 				       uint64_t item_flags,
2296 				       struct mlx5_priv **act_priv,
2297 				       struct rte_flow_error *error)
2298 {
2299 	const struct rte_flow_item_ethdev *spec = item->spec;
2300 	const struct rte_flow_item_ethdev *mask = item->mask;
2301 	const struct rte_flow_item_ethdev switch_mask = {
2302 			.port_id = UINT16_MAX,
2303 	};
2304 	struct mlx5_priv *esw_priv;
2305 	struct mlx5_priv *dev_priv;
2306 	int ret;
2307 
2308 	if (!attr->transfer)
2309 		return rte_flow_error_set(error, EINVAL,
2310 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2311 					  "match on port id is valid only when transfer flag is enabled");
2312 	if (item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT)
2313 		return rte_flow_error_set(error, ENOTSUP,
2314 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2315 					  "multiple source ports are not supported");
2316 	if (!mask)
2317 		mask = &switch_mask;
2318 	if (mask->port_id != UINT16_MAX)
2319 		return rte_flow_error_set(error, ENOTSUP,
2320 					   RTE_FLOW_ERROR_TYPE_ITEM_MASK, mask,
2321 					   "no support for partial mask on \"id\" field");
2322 	ret = mlx5_flow_item_acceptable
2323 				(item, (const uint8_t *)mask,
2324 				 (const uint8_t *)&rte_flow_item_ethdev_mask,
2325 				 sizeof(struct rte_flow_item_ethdev),
2326 				 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2327 	if (ret)
2328 		return ret;
2329 	if (!spec || spec->port_id == UINT16_MAX)
2330 		return 0;
2331 	esw_priv = mlx5_port_to_eswitch_info(spec->port_id, false);
2332 	if (!esw_priv)
2333 		return rte_flow_error_set(error, rte_errno,
2334 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2335 					  "failed to obtain E-Switch info for port");
2336 	dev_priv = mlx5_dev_to_eswitch_info(dev);
2337 	if (!dev_priv)
2338 		return rte_flow_error_set(error, rte_errno,
2339 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2340 					  NULL,
2341 					  "failed to obtain E-Switch info");
2342 	if (esw_priv->domain_id != dev_priv->domain_id)
2343 		return rte_flow_error_set(error, EINVAL,
2344 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
2345 					  "cannot match on a port from a different E-Switch");
2346 	*act_priv = esw_priv;
2347 	return 0;
2348 }
2349 
2350 /**
2351  * Validate VLAN item.
2352  *
2353  * @param[in] item
2354  *   Item specification.
2355  * @param[in] item_flags
2356  *   Bit-fields that holds the items detected until now.
2357  * @param[in] dev
2358  *   Ethernet device flow is being created on.
2359  * @param[out] error
2360  *   Pointer to error structure.
2361  *
2362  * @return
2363  *   0 on success, a negative errno value otherwise and rte_errno is set.
2364  */
2365 static int
2366 flow_dv_validate_item_vlan(const struct rte_flow_item *item,
2367 			   uint64_t item_flags,
2368 			   struct rte_eth_dev *dev,
2369 			   struct rte_flow_error *error)
2370 {
2371 	const struct rte_flow_item_vlan *mask = item->mask;
2372 	const struct rte_flow_item_vlan nic_mask = {
2373 		.hdr.vlan_tci = RTE_BE16(UINT16_MAX),
2374 		.hdr.eth_proto = RTE_BE16(UINT16_MAX),
2375 		.has_more_vlan = 1,
2376 	};
2377 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2378 	int ret;
2379 	const uint64_t l34m = tunnel ? (MLX5_FLOW_LAYER_INNER_L3 |
2380 					MLX5_FLOW_LAYER_INNER_L4) :
2381 				       (MLX5_FLOW_LAYER_OUTER_L3 |
2382 					MLX5_FLOW_LAYER_OUTER_L4);
2383 	const uint64_t vlanm = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
2384 					MLX5_FLOW_LAYER_OUTER_VLAN;
2385 
2386 	if (item_flags & vlanm)
2387 		return rte_flow_error_set(error, EINVAL,
2388 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2389 					  "multiple VLAN layers not supported");
2390 	else if ((item_flags & l34m) != 0)
2391 		return rte_flow_error_set(error, EINVAL,
2392 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2393 					  "VLAN cannot follow L3/L4 layer");
2394 	if (!mask)
2395 		mask = &rte_flow_item_vlan_mask;
2396 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2397 					(const uint8_t *)&nic_mask,
2398 					sizeof(struct rte_flow_item_vlan),
2399 					MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2400 	if (ret)
2401 		return ret;
2402 	if (!tunnel && mask->hdr.vlan_tci != RTE_BE16(0x0fff)) {
2403 		struct mlx5_priv *priv = dev->data->dev_private;
2404 
2405 		if (priv->vmwa_context) {
2406 			/*
2407 			 * Non-NULL context means we have a virtual machine
2408 			 * and SR-IOV enabled, we have to create VLAN interface
2409 			 * to make hypervisor to setup E-Switch vport
2410 			 * context correctly. We avoid creating the multiple
2411 			 * VLAN interfaces, so we cannot support VLAN tag mask.
2412 			 */
2413 			return rte_flow_error_set(error, EINVAL,
2414 						  RTE_FLOW_ERROR_TYPE_ITEM,
2415 						  item,
2416 						  "VLAN tag mask is not"
2417 						  " supported in virtual"
2418 						  " environment");
2419 		}
2420 	}
2421 	return 0;
2422 }
2423 
2424 /*
2425  * GTP flags are contained in 1 byte of the format:
2426  * -------------------------------------------
2427  * | bit   | 0 - 2   | 3  | 4   | 5 | 6 | 7  |
2428  * |-----------------------------------------|
2429  * | value | Version | PT | Res | E | S | PN |
2430  * -------------------------------------------
2431  *
2432  * Matching is supported only for GTP flags E, S, PN.
2433  */
2434 #define MLX5_GTP_FLAGS_MASK	0x07
2435 
2436 /**
2437  * Validate GTP item.
2438  *
2439  * @param[in] dev
2440  *   Pointer to the rte_eth_dev structure.
2441  * @param[in] item
2442  *   Item specification.
2443  * @param[in] item_flags
2444  *   Bit-fields that holds the items detected until now.
2445  * @param[out] error
2446  *   Pointer to error structure.
2447  *
2448  * @return
2449  *   0 on success, a negative errno value otherwise and rte_errno is set.
2450  */
2451 static int
2452 flow_dv_validate_item_gtp(struct rte_eth_dev *dev,
2453 			  const struct rte_flow_item *item,
2454 			  uint64_t item_flags,
2455 			  struct rte_flow_error *error)
2456 {
2457 	struct mlx5_priv *priv = dev->data->dev_private;
2458 	const struct rte_flow_item_gtp *spec = item->spec;
2459 	const struct rte_flow_item_gtp *mask = item->mask;
2460 	const struct rte_flow_item_gtp nic_mask = {
2461 		.hdr.gtp_hdr_info = MLX5_GTP_FLAGS_MASK,
2462 		.hdr.msg_type = 0xff,
2463 		.hdr.teid = RTE_BE32(0xffffffff),
2464 	};
2465 
2466 	if (!priv->sh->cdev->config.hca_attr.tunnel_stateless_gtp)
2467 		return rte_flow_error_set(error, ENOTSUP,
2468 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2469 					  "GTP support is not enabled");
2470 	if (item_flags & MLX5_FLOW_LAYER_TUNNEL)
2471 		return rte_flow_error_set(error, ENOTSUP,
2472 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2473 					  "multiple tunnel layers not"
2474 					  " supported");
2475 	if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_UDP))
2476 		return rte_flow_error_set(error, EINVAL,
2477 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2478 					  "no outer UDP layer found");
2479 	if (!mask)
2480 		mask = &rte_flow_item_gtp_mask;
2481 	if (spec && spec->hdr.gtp_hdr_info & ~MLX5_GTP_FLAGS_MASK)
2482 		return rte_flow_error_set(error, ENOTSUP,
2483 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2484 					  "Match is supported for GTP"
2485 					  " flags only");
2486 	return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2487 					 (const uint8_t *)&nic_mask,
2488 					 sizeof(struct rte_flow_item_gtp),
2489 					 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2490 }
2491 
2492 /**
2493  * Validate GTP PSC item.
2494  *
2495  * @param[in] item
2496  *   Item specification.
2497  * @param[in] last_item
2498  *   Previous validated item in the pattern items.
2499  * @param[in] gtp_item
2500  *   Previous GTP item specification.
2501  * @param root
2502  *   Whether action is on root table.
2503  * @param[out] error
2504  *   Pointer to error structure.
2505  *
2506  * @return
2507  *   0 on success, a negative errno value otherwise and rte_errno is set.
2508  */
2509 static int
2510 flow_dv_validate_item_gtp_psc(const struct rte_flow_item *item,
2511 			      uint64_t last_item,
2512 			      const struct rte_flow_item *gtp_item,
2513 			      bool root,
2514 			      struct rte_flow_error *error)
2515 {
2516 	const struct rte_flow_item_gtp *gtp_spec;
2517 	const struct rte_flow_item_gtp *gtp_mask;
2518 	const struct rte_flow_item_gtp_psc *mask;
2519 	const struct rte_flow_item_gtp_psc nic_mask = {
2520 		.hdr.type = 0xF,
2521 		.hdr.qfi = 0x3F,
2522 	};
2523 
2524 	if (!gtp_item || !(last_item & MLX5_FLOW_LAYER_GTP))
2525 		return rte_flow_error_set
2526 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2527 			 "GTP PSC item must be preceded with GTP item");
2528 	gtp_spec = gtp_item->spec;
2529 	gtp_mask = gtp_item->mask ? gtp_item->mask : &rte_flow_item_gtp_mask;
2530 	/* GTP spec and E flag is requested to match zero. */
2531 	if (gtp_spec &&
2532 		(gtp_mask->hdr.gtp_hdr_info &
2533 		~gtp_spec->hdr.gtp_hdr_info & MLX5_GTP_EXT_HEADER_FLAG))
2534 		return rte_flow_error_set
2535 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item,
2536 			 "GTP E flag must be 1 to match GTP PSC");
2537 	/* Check the flow is not created in group zero. */
2538 	if (root)
2539 		return rte_flow_error_set
2540 			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2541 			 "GTP PSC is not supported for group 0");
2542 	/* GTP spec is here and E flag is requested to match zero. */
2543 	if (!item->spec)
2544 		return 0;
2545 	mask = item->mask ? item->mask : &rte_flow_item_gtp_psc_mask;
2546 	return mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
2547 					 (const uint8_t *)&nic_mask,
2548 					 sizeof(struct rte_flow_item_gtp_psc),
2549 					 MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
2550 }
2551 
2552 /**
2553  * Validate IPV4 item.
2554  * Use existing validation function mlx5_flow_validate_item_ipv4(), and
2555  * add specific validation of fragment_offset field,
2556  *
2557  * @param[in] item
2558  *   Item specification.
2559  * @param[in] item_flags
2560  *   Bit-fields that holds the items detected until now.
2561  * @param[out] error
2562  *   Pointer to error structure.
2563  *
2564  * @return
2565  *   0 on success, a negative errno value otherwise and rte_errno is set.
2566  */
2567 static int
2568 flow_dv_validate_item_ipv4(struct rte_eth_dev *dev,
2569 			   const struct rte_flow_item *item,
2570 			   uint64_t item_flags, uint64_t last_item,
2571 			   uint16_t ether_type, struct rte_flow_error *error)
2572 {
2573 	int ret;
2574 	struct mlx5_priv *priv = dev->data->dev_private;
2575 	struct mlx5_hca_attr *attr = &priv->sh->cdev->config.hca_attr;
2576 	const struct rte_flow_item_ipv4 *spec = item->spec;
2577 	const struct rte_flow_item_ipv4 *last = item->last;
2578 	const struct rte_flow_item_ipv4 *mask = item->mask;
2579 	rte_be16_t fragment_offset_spec = 0;
2580 	rte_be16_t fragment_offset_last = 0;
2581 	struct rte_flow_item_ipv4 nic_ipv4_mask = {
2582 		.hdr = {
2583 			.src_addr = RTE_BE32(0xffffffff),
2584 			.dst_addr = RTE_BE32(0xffffffff),
2585 			.type_of_service = 0xff,
2586 			.fragment_offset = RTE_BE16(0xffff),
2587 			.next_proto_id = 0xff,
2588 			.time_to_live = 0xff,
2589 		},
2590 	};
2591 
2592 	if (mask && (mask->hdr.version_ihl & RTE_IPV4_HDR_IHL_MASK)) {
2593 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2594 		bool ihl_cap = !tunnel ?
2595 			       attr->outer_ipv4_ihl : attr->inner_ipv4_ihl;
2596 		if (!ihl_cap)
2597 			return rte_flow_error_set(error, ENOTSUP,
2598 						  RTE_FLOW_ERROR_TYPE_ITEM,
2599 						  item,
2600 						  "IPV4 ihl offload not supported");
2601 		nic_ipv4_mask.hdr.version_ihl = mask->hdr.version_ihl;
2602 	}
2603 	ret = mlx5_flow_validate_item_ipv4(item, item_flags, last_item,
2604 					   ether_type, &nic_ipv4_mask,
2605 					   MLX5_ITEM_RANGE_ACCEPTED, error);
2606 	if (ret < 0)
2607 		return ret;
2608 	if (spec && mask)
2609 		fragment_offset_spec = spec->hdr.fragment_offset &
2610 				       mask->hdr.fragment_offset;
2611 	if (!fragment_offset_spec)
2612 		return 0;
2613 	/*
2614 	 * spec and mask are valid, enforce using full mask to make sure the
2615 	 * complete value is used correctly.
2616 	 */
2617 	if ((mask->hdr.fragment_offset & RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2618 			!= RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2619 		return rte_flow_error_set(error, EINVAL,
2620 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2621 					  item, "must use full mask for"
2622 					  " fragment_offset");
2623 	/*
2624 	 * Match on fragment_offset 0x2000 means MF is 1 and frag-offset is 0,
2625 	 * indicating this is 1st fragment of fragmented packet.
2626 	 * This is not yet supported in MLX5, return appropriate error message.
2627 	 */
2628 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG))
2629 		return rte_flow_error_set(error, ENOTSUP,
2630 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2631 					  "match on first fragment not "
2632 					  "supported");
2633 	if (fragment_offset_spec && !last)
2634 		return rte_flow_error_set(error, ENOTSUP,
2635 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2636 					  "specified value not supported");
2637 	/* spec and last are valid, validate the specified range. */
2638 	fragment_offset_last = last->hdr.fragment_offset &
2639 			       mask->hdr.fragment_offset;
2640 	/*
2641 	 * Match on fragment_offset spec 0x2001 and last 0x3fff
2642 	 * means MF is 1 and frag-offset is > 0.
2643 	 * This packet is fragment 2nd and onward, excluding last.
2644 	 * This is not yet supported in MLX5, return appropriate
2645 	 * error message.
2646 	 */
2647 	if (fragment_offset_spec == RTE_BE16(RTE_IPV4_HDR_MF_FLAG + 1) &&
2648 	    fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK))
2649 		return rte_flow_error_set(error, ENOTSUP,
2650 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2651 					  last, "match on following "
2652 					  "fragments not supported");
2653 	/*
2654 	 * Match on fragment_offset spec 0x0001 and last 0x1fff
2655 	 * means MF is 0 and frag-offset is > 0.
2656 	 * This packet is last fragment of fragmented packet.
2657 	 * This is not yet supported in MLX5, return appropriate
2658 	 * error message.
2659 	 */
2660 	if (fragment_offset_spec == RTE_BE16(1) &&
2661 	    fragment_offset_last == RTE_BE16(RTE_IPV4_HDR_OFFSET_MASK))
2662 		return rte_flow_error_set(error, ENOTSUP,
2663 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2664 					  last, "match on last "
2665 					  "fragment not supported");
2666 	/*
2667 	 * Match on fragment_offset spec 0x0001 and last 0x3fff
2668 	 * means MF and/or frag-offset is not 0.
2669 	 * This is a fragmented packet.
2670 	 * Other range values are invalid and rejected.
2671 	 */
2672 	if (!(fragment_offset_spec == RTE_BE16(1) &&
2673 	      fragment_offset_last == RTE_BE16(MLX5_IPV4_FRAG_OFFSET_MASK)))
2674 		return rte_flow_error_set(error, ENOTSUP,
2675 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2676 					  "specified range not supported");
2677 	return 0;
2678 }
2679 
2680 /**
2681  * Validate IPV6 fragment extension item.
2682  *
2683  * @param[in] item
2684  *   Item specification.
2685  * @param[in] item_flags
2686  *   Bit-fields that holds the items detected until now.
2687  * @param[out] error
2688  *   Pointer to error structure.
2689  *
2690  * @return
2691  *   0 on success, a negative errno value otherwise and rte_errno is set.
2692  */
2693 static int
2694 flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item,
2695 				    uint64_t item_flags,
2696 				    struct rte_flow_error *error)
2697 {
2698 	const struct rte_flow_item_ipv6_frag_ext *spec = item->spec;
2699 	const struct rte_flow_item_ipv6_frag_ext *last = item->last;
2700 	const struct rte_flow_item_ipv6_frag_ext *mask = item->mask;
2701 	rte_be16_t frag_data_spec = 0;
2702 	rte_be16_t frag_data_last = 0;
2703 	const int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2704 	const uint64_t l4m = tunnel ? MLX5_FLOW_LAYER_INNER_L4 :
2705 				      MLX5_FLOW_LAYER_OUTER_L4;
2706 	int ret = 0;
2707 	struct rte_flow_item_ipv6_frag_ext nic_mask = {
2708 		.hdr = {
2709 			.next_header = 0xff,
2710 			.frag_data = RTE_BE16(0xffff),
2711 		},
2712 	};
2713 
2714 	if (item_flags & l4m)
2715 		return rte_flow_error_set(error, EINVAL,
2716 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2717 					  "ipv6 fragment extension item cannot "
2718 					  "follow L4 item.");
2719 	if ((tunnel && !(item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
2720 	    (!tunnel && !(item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6)))
2721 		return rte_flow_error_set(error, EINVAL,
2722 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2723 					  "ipv6 fragment extension item must "
2724 					  "follow ipv6 item");
2725 	if (spec && mask)
2726 		frag_data_spec = spec->hdr.frag_data & mask->hdr.frag_data;
2727 	if (!frag_data_spec)
2728 		return 0;
2729 	/*
2730 	 * spec and mask are valid, enforce using full mask to make sure the
2731 	 * complete value is used correctly.
2732 	 */
2733 	if ((mask->hdr.frag_data & RTE_BE16(RTE_IPV6_FRAG_USED_MASK)) !=
2734 				RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2735 		return rte_flow_error_set(error, EINVAL,
2736 					  RTE_FLOW_ERROR_TYPE_ITEM_MASK,
2737 					  item, "must use full mask for"
2738 					  " frag_data");
2739 	/*
2740 	 * Match on frag_data 0x00001 means M is 1 and frag-offset is 0.
2741 	 * This is 1st fragment of fragmented packet.
2742 	 */
2743 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_MF_MASK))
2744 		return rte_flow_error_set(error, ENOTSUP,
2745 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2746 					  "match on first fragment not "
2747 					  "supported");
2748 	if (frag_data_spec && !last)
2749 		return rte_flow_error_set(error, EINVAL,
2750 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
2751 					  "specified value not supported");
2752 	ret = mlx5_flow_item_acceptable
2753 				(item, (const uint8_t *)mask,
2754 				 (const uint8_t *)&nic_mask,
2755 				 sizeof(struct rte_flow_item_ipv6_frag_ext),
2756 				 MLX5_ITEM_RANGE_ACCEPTED, error);
2757 	if (ret)
2758 		return ret;
2759 	/* spec and last are valid, validate the specified range. */
2760 	frag_data_last = last->hdr.frag_data & mask->hdr.frag_data;
2761 	/*
2762 	 * Match on frag_data spec 0x0009 and last 0xfff9
2763 	 * means M is 1 and frag-offset is > 0.
2764 	 * This packet is fragment 2nd and onward, excluding last.
2765 	 * This is not yet supported in MLX5, return appropriate
2766 	 * error message.
2767 	 */
2768 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN |
2769 				       RTE_IPV6_EHDR_MF_MASK) &&
2770 	    frag_data_last == RTE_BE16(RTE_IPV6_FRAG_USED_MASK))
2771 		return rte_flow_error_set(error, ENOTSUP,
2772 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2773 					  last, "match on following "
2774 					  "fragments not supported");
2775 	/*
2776 	 * Match on frag_data spec 0x0008 and last 0xfff8
2777 	 * means M is 0 and frag-offset is > 0.
2778 	 * This packet is last fragment of fragmented packet.
2779 	 * This is not yet supported in MLX5, return appropriate
2780 	 * error message.
2781 	 */
2782 	if (frag_data_spec == RTE_BE16(RTE_IPV6_EHDR_FO_ALIGN) &&
2783 	    frag_data_last == RTE_BE16(RTE_IPV6_EHDR_FO_MASK))
2784 		return rte_flow_error_set(error, ENOTSUP,
2785 					  RTE_FLOW_ERROR_TYPE_ITEM_LAST,
2786 					  last, "match on last "
2787 					  "fragment not supported");
2788 	/* Other range values are invalid and rejected. */
2789 	return rte_flow_error_set(error, EINVAL,
2790 				  RTE_FLOW_ERROR_TYPE_ITEM_LAST, last,
2791 				  "specified range not supported");
2792 }
2793 
2794 /*
2795  * Validate ASO CT item.
2796  *
2797  * @param[in] dev
2798  *   Pointer to the rte_eth_dev structure.
2799  * @param[in] item
2800  *   Item specification.
2801  * @param[in] item_flags
2802  *   Pointer to bit-fields that holds the items detected until now.
2803  * @param[out] error
2804  *   Pointer to error structure.
2805  *
2806  * @return
2807  *   0 on success, a negative errno value otherwise and rte_errno is set.
2808  */
2809 static int
2810 flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev,
2811 			     const struct rte_flow_item *item,
2812 			     uint64_t *item_flags,
2813 			     struct rte_flow_error *error)
2814 {
2815 	const struct rte_flow_item_conntrack *spec = item->spec;
2816 	const struct rte_flow_item_conntrack *mask = item->mask;
2817 	RTE_SET_USED(dev);
2818 	uint32_t flags;
2819 
2820 	if (*item_flags & MLX5_FLOW_LAYER_ASO_CT)
2821 		return rte_flow_error_set(error, EINVAL,
2822 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2823 					  "Only one CT is supported");
2824 	if (!mask)
2825 		mask = &rte_flow_item_conntrack_mask;
2826 	flags = spec->flags & mask->flags;
2827 	if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) &&
2828 	    ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) ||
2829 	     (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) ||
2830 	     (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)))
2831 		return rte_flow_error_set(error, EINVAL,
2832 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
2833 					  "Conflict status bits");
2834 	/* State change also needs to be considered. */
2835 	*item_flags |= MLX5_FLOW_LAYER_ASO_CT;
2836 	return 0;
2837 }
2838 
2839 /**
2840  * Validate the pop VLAN action.
2841  *
2842  * @param[in] dev
2843  *   Pointer to the rte_eth_dev structure.
2844  * @param[in] action_flags
2845  *   Holds the actions detected until now.
2846  * @param[in] action
2847  *   Pointer to the pop vlan action.
2848  * @param[in] item_flags
2849  *   The items found in this flow rule.
2850  * @param[in] attr
2851  *   Pointer to flow attributes.
2852  * @param[out] error
2853  *   Pointer to error structure.
2854  *
2855  * @return
2856  *   0 on success, a negative errno value otherwise and rte_errno is set.
2857  */
2858 static int
2859 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev,
2860 				 uint64_t action_flags,
2861 				 const struct rte_flow_action *action,
2862 				 uint64_t item_flags,
2863 				 const struct rte_flow_attr *attr,
2864 				 struct rte_flow_error *error)
2865 {
2866 	const struct mlx5_priv *priv = dev->data->dev_private;
2867 
2868 	if (!priv->sh->pop_vlan_action)
2869 		return rte_flow_error_set(error, ENOTSUP,
2870 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2871 					  NULL,
2872 					  "pop vlan action is not supported");
2873 	if (action_flags & MLX5_FLOW_VLAN_ACTIONS)
2874 		return rte_flow_error_set(error, ENOTSUP,
2875 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2876 					  "no support for multiple VLAN "
2877 					  "actions");
2878 	/* Pop VLAN with preceding Decap requires inner header with VLAN. */
2879 	if ((action_flags & MLX5_FLOW_ACTION_DECAP) &&
2880 	    !(item_flags & MLX5_FLOW_LAYER_INNER_VLAN))
2881 		return rte_flow_error_set(error, ENOTSUP,
2882 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2883 					  NULL,
2884 					  "cannot pop vlan after decap without "
2885 					  "match on inner vlan in the flow");
2886 	/* Pop VLAN without preceding Decap requires outer header with VLAN. */
2887 	if (!(action_flags & MLX5_FLOW_ACTION_DECAP) &&
2888 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
2889 		return rte_flow_error_set(error, ENOTSUP,
2890 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2891 					  NULL,
2892 					  "cannot pop vlan without a "
2893 					  "match on (outer) vlan in the flow");
2894 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
2895 		return rte_flow_error_set(error, EINVAL,
2896 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
2897 					  "wrong action order, port_id should "
2898 					  "be after pop VLAN action");
2899 	if (!attr->transfer && priv->representor)
2900 		return rte_flow_error_set(error, ENOTSUP,
2901 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2902 					  "pop vlan action for VF representor "
2903 					  "not supported on NIC table");
2904 	return 0;
2905 }
2906 
2907 /**
2908  * Get VLAN default info from vlan match info.
2909  *
2910  * @param[in] items
2911  *   the list of item specifications.
2912  * @param[out] vlan
2913  *   pointer VLAN info to fill to.
2914  *
2915  * @return
2916  *   0 on success, a negative errno value otherwise and rte_errno is set.
2917  */
2918 static void
2919 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items,
2920 				  struct rte_vlan_hdr *vlan)
2921 {
2922 	const struct rte_flow_item_vlan nic_mask = {
2923 		.hdr.vlan_tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK |
2924 				MLX5DV_FLOW_VLAN_VID_MASK),
2925 		.hdr.eth_proto = RTE_BE16(0xffff),
2926 	};
2927 
2928 	if (items == NULL)
2929 		return;
2930 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
2931 		int type = items->type;
2932 
2933 		if (type == RTE_FLOW_ITEM_TYPE_VLAN ||
2934 		    type == MLX5_RTE_FLOW_ITEM_TYPE_VLAN)
2935 			break;
2936 	}
2937 	if (items->type != RTE_FLOW_ITEM_TYPE_END) {
2938 		const struct rte_flow_item_vlan *vlan_m = items->mask;
2939 		const struct rte_flow_item_vlan *vlan_v = items->spec;
2940 
2941 		/* If VLAN item in pattern doesn't contain data, return here. */
2942 		if (!vlan_v)
2943 			return;
2944 		if (!vlan_m)
2945 			vlan_m = &nic_mask;
2946 		/* Only full match values are accepted */
2947 		if ((vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) ==
2948 		     MLX5DV_FLOW_VLAN_PCP_MASK_BE) {
2949 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
2950 			vlan->vlan_tci |=
2951 				rte_be_to_cpu_16(vlan_v->hdr.vlan_tci &
2952 						 MLX5DV_FLOW_VLAN_PCP_MASK_BE);
2953 		}
2954 		if ((vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) ==
2955 		     MLX5DV_FLOW_VLAN_VID_MASK_BE) {
2956 			vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
2957 			vlan->vlan_tci |=
2958 				rte_be_to_cpu_16(vlan_v->hdr.vlan_tci &
2959 						 MLX5DV_FLOW_VLAN_VID_MASK_BE);
2960 		}
2961 		if (vlan_m->hdr.eth_proto == nic_mask.hdr.eth_proto)
2962 			vlan->eth_proto = rte_be_to_cpu_16(vlan_v->hdr.eth_proto &
2963 							   vlan_m->hdr.eth_proto);
2964 	}
2965 }
2966 
2967 /**
2968  * Validate the push VLAN action.
2969  *
2970  * @param[in] dev
2971  *   Pointer to the rte_eth_dev structure.
2972  * @param[in] action_flags
2973  *   Holds the actions detected until now.
2974  * @param[in] item_flags
2975  *   The items found in this flow rule.
2976  * @param[in] action
2977  *   Pointer to the action structure.
2978  * @param[in] attr
2979  *   Pointer to flow attributes
2980  * @param[out] error
2981  *   Pointer to error structure.
2982  *
2983  * @return
2984  *   0 on success, a negative errno value otherwise and rte_errno is set.
2985  */
2986 static int
2987 flow_dv_validate_action_push_vlan(struct rte_eth_dev *dev,
2988 				  uint64_t action_flags,
2989 				  const struct rte_flow_item_vlan *vlan_m,
2990 				  const struct rte_flow_action *action,
2991 				  const struct rte_flow_attr *attr,
2992 				  struct rte_flow_error *error)
2993 {
2994 	const struct rte_flow_action_of_push_vlan *push_vlan = action->conf;
2995 	const struct mlx5_priv *priv = dev->data->dev_private;
2996 
2997 	if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) &&
2998 	    push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ))
2999 		return rte_flow_error_set(error, EINVAL,
3000 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3001 					  "invalid vlan ethertype");
3002 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
3003 		return rte_flow_error_set(error, EINVAL,
3004 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3005 					  "wrong action order, port_id should "
3006 					  "be after push VLAN");
3007 	if (!attr->transfer && priv->representor)
3008 		return rte_flow_error_set(error, ENOTSUP,
3009 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3010 					  "push vlan action for VF representor "
3011 					  "not supported on NIC table");
3012 	if (vlan_m &&
3013 	    (vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) &&
3014 	    (vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) !=
3015 		MLX5DV_FLOW_VLAN_PCP_MASK_BE &&
3016 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP) &&
3017 	    !(mlx5_flow_find_action
3018 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP)))
3019 		return rte_flow_error_set(error, EINVAL,
3020 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3021 					  "not full match mask on VLAN PCP and "
3022 					  "there is no of_set_vlan_pcp action, "
3023 					  "push VLAN action cannot figure out "
3024 					  "PCP value");
3025 	if (vlan_m &&
3026 	    (vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) &&
3027 	    (vlan_m->hdr.vlan_tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) !=
3028 		MLX5DV_FLOW_VLAN_VID_MASK_BE &&
3029 	    !(action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID) &&
3030 	    !(mlx5_flow_find_action
3031 		(action + 1, RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID)))
3032 		return rte_flow_error_set(error, EINVAL,
3033 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3034 					  "not full match mask on VLAN VID and "
3035 					  "there is no of_set_vlan_vid action, "
3036 					  "push VLAN action cannot figure out "
3037 					  "VID value");
3038 	(void)attr;
3039 	return 0;
3040 }
3041 
3042 /**
3043  * Validate the set VLAN PCP.
3044  *
3045  * @param[in] action_flags
3046  *   Holds the actions detected until now.
3047  * @param[in] actions
3048  *   Pointer to the list of actions remaining in the flow rule.
3049  * @param[out] error
3050  *   Pointer to error structure.
3051  *
3052  * @return
3053  *   0 on success, a negative errno value otherwise and rte_errno is set.
3054  */
3055 static int
3056 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags,
3057 				     const struct rte_flow_action actions[],
3058 				     struct rte_flow_error *error)
3059 {
3060 	const struct rte_flow_action *action = actions;
3061 	const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf;
3062 
3063 	if (conf->vlan_pcp > 7)
3064 		return rte_flow_error_set(error, EINVAL,
3065 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3066 					  "VLAN PCP value is too big");
3067 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN))
3068 		return rte_flow_error_set(error, ENOTSUP,
3069 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3070 					  "set VLAN PCP action must follow "
3071 					  "the push VLAN action");
3072 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_PCP)
3073 		return rte_flow_error_set(error, ENOTSUP,
3074 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3075 					  "Multiple VLAN PCP modification are "
3076 					  "not supported");
3077 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
3078 		return rte_flow_error_set(error, EINVAL,
3079 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3080 					  "wrong action order, port_id should "
3081 					  "be after set VLAN PCP");
3082 	return 0;
3083 }
3084 
3085 /**
3086  * Validate the set VLAN VID.
3087  *
3088  * @param[in] item_flags
3089  *   Holds the items detected in this rule.
3090  * @param[in] action_flags
3091  *   Holds the actions detected until now.
3092  * @param[in] actions
3093  *   Pointer to the list of actions remaining in the flow rule.
3094  * @param[out] error
3095  *   Pointer to error structure.
3096  *
3097  * @return
3098  *   0 on success, a negative errno value otherwise and rte_errno is set.
3099  */
3100 static int
3101 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
3102 				     uint64_t action_flags,
3103 				     const struct rte_flow_action actions[],
3104 				     struct rte_flow_error *error)
3105 {
3106 	const struct rte_flow_action *action = actions;
3107 	const struct rte_flow_action_of_set_vlan_vid *conf = action->conf;
3108 
3109 	if (rte_be_to_cpu_16(conf->vlan_vid) > 0xFFE)
3110 		return rte_flow_error_set(error, EINVAL,
3111 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3112 					  "VLAN VID value is too big");
3113 	if (!(action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) &&
3114 	    !(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
3115 		return rte_flow_error_set(error, ENOTSUP,
3116 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3117 					  "set VLAN VID action must follow push"
3118 					  " VLAN action or match on VLAN item");
3119 	if (action_flags & MLX5_FLOW_ACTION_OF_SET_VLAN_VID)
3120 		return rte_flow_error_set(error, ENOTSUP,
3121 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3122 					  "Multiple VLAN VID modifications are "
3123 					  "not supported");
3124 	if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
3125 		return rte_flow_error_set(error, EINVAL,
3126 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3127 					  "wrong action order, port_id should "
3128 					  "be after set VLAN VID");
3129 	return 0;
3130 }
3131 
3132 /*
3133  * Validate the FLAG action.
3134  *
3135  * @param[in] dev
3136  *   Pointer to the rte_eth_dev structure.
3137  * @param[in] action_flags
3138  *   Holds the actions detected until now.
3139  * @param[in] attr
3140  *   Pointer to flow attributes
3141  * @param[out] error
3142  *   Pointer to error structure.
3143  *
3144  * @return
3145  *   0 on success, a negative errno value otherwise and rte_errno is set.
3146  */
3147 static int
3148 flow_dv_validate_action_flag(struct rte_eth_dev *dev,
3149 			     uint64_t action_flags,
3150 			     const struct rte_flow_attr *attr,
3151 			     struct rte_flow_error *error)
3152 {
3153 	struct mlx5_priv *priv = dev->data->dev_private;
3154 	struct mlx5_sh_config *config = &priv->sh->config;
3155 	int ret;
3156 
3157 	/* Fall back if no extended metadata register support. */
3158 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3159 		return mlx5_flow_validate_action_flag(action_flags, attr,
3160 						      error);
3161 	/* Extensive metadata mode requires registers. */
3162 	if (!mlx5_flow_ext_mreg_supported(dev))
3163 		return rte_flow_error_set(error, ENOTSUP,
3164 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3165 					  "no metadata registers "
3166 					  "to support flag action");
3167 	if (!(priv->sh->dv_mark_mask & MLX5_FLOW_MARK_DEFAULT))
3168 		return rte_flow_error_set(error, ENOTSUP,
3169 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3170 					  "extended metadata register"
3171 					  " isn't available");
3172 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3173 	if (ret < 0)
3174 		return ret;
3175 	MLX5_ASSERT(ret > 0);
3176 	if (action_flags & MLX5_FLOW_ACTION_MARK)
3177 		return rte_flow_error_set(error, EINVAL,
3178 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3179 					  "can't mark and flag in same flow");
3180 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
3181 		return rte_flow_error_set(error, EINVAL,
3182 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3183 					  "can't have 2 flag"
3184 					  " actions in same flow");
3185 	return 0;
3186 }
3187 
3188 /**
3189  * Validate MARK action.
3190  *
3191  * @param[in] dev
3192  *   Pointer to the rte_eth_dev structure.
3193  * @param[in] action
3194  *   Pointer to action.
3195  * @param[in] action_flags
3196  *   Holds the actions detected until now.
3197  * @param[in] attr
3198  *   Pointer to flow attributes
3199  * @param[out] error
3200  *   Pointer to error structure.
3201  *
3202  * @return
3203  *   0 on success, a negative errno value otherwise and rte_errno is set.
3204  */
3205 static int
3206 flow_dv_validate_action_mark(struct rte_eth_dev *dev,
3207 			     const struct rte_flow_action *action,
3208 			     uint64_t action_flags,
3209 			     const struct rte_flow_attr *attr,
3210 			     struct rte_flow_error *error)
3211 {
3212 	struct mlx5_priv *priv = dev->data->dev_private;
3213 	struct mlx5_sh_config *config = &priv->sh->config;
3214 	const struct rte_flow_action_mark *mark = action->conf;
3215 	int ret;
3216 
3217 	if (is_tunnel_offload_active(dev))
3218 		return rte_flow_error_set(error, ENOTSUP,
3219 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3220 					  "no mark action "
3221 					  "if tunnel offload active");
3222 	/* Fall back if no extended metadata register support. */
3223 	if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY)
3224 		return mlx5_flow_validate_action_mark(action, action_flags,
3225 						      attr, error);
3226 	/* Extensive metadata mode requires registers. */
3227 	if (!mlx5_flow_ext_mreg_supported(dev))
3228 		return rte_flow_error_set(error, ENOTSUP,
3229 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3230 					  "no metadata registers "
3231 					  "to support mark action");
3232 	if (!priv->sh->dv_mark_mask)
3233 		return rte_flow_error_set(error, ENOTSUP,
3234 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3235 					  "extended metadata register"
3236 					  " isn't available");
3237 	ret = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, error);
3238 	if (ret < 0)
3239 		return ret;
3240 	MLX5_ASSERT(ret > 0);
3241 	if (!mark)
3242 		return rte_flow_error_set(error, EINVAL,
3243 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3244 					  "configuration cannot be null");
3245 	if (mark->id >= (MLX5_FLOW_MARK_MAX & priv->sh->dv_mark_mask))
3246 		return rte_flow_error_set(error, EINVAL,
3247 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
3248 					  &mark->id,
3249 					  "mark id exceeds the limit");
3250 	if (action_flags & MLX5_FLOW_ACTION_FLAG)
3251 		return rte_flow_error_set(error, EINVAL,
3252 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3253 					  "can't flag and mark in same flow");
3254 	if (action_flags & MLX5_FLOW_ACTION_MARK)
3255 		return rte_flow_error_set(error, EINVAL,
3256 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3257 					  "can't have 2 mark actions in same"
3258 					  " flow");
3259 	return 0;
3260 }
3261 
3262 /**
3263  * Validate SET_META action.
3264  *
3265  * @param[in] dev
3266  *   Pointer to the rte_eth_dev structure.
3267  * @param[in] action
3268  *   Pointer to the action structure.
3269  * @param[in] action_flags
3270  *   Holds the actions detected until now.
3271  * @param[in] attr
3272  *   Pointer to flow attributes
3273  * @param[out] error
3274  *   Pointer to error structure.
3275  *
3276  * @return
3277  *   0 on success, a negative errno value otherwise and rte_errno is set.
3278  */
3279 static int
3280 flow_dv_validate_action_set_meta(struct rte_eth_dev *dev,
3281 				 const struct rte_flow_action *action,
3282 				 uint64_t action_flags __rte_unused,
3283 				 const struct rte_flow_attr *attr,
3284 				 struct rte_flow_error *error)
3285 {
3286 	struct mlx5_priv *priv = dev->data->dev_private;
3287 	struct mlx5_sh_config *config = &priv->sh->config;
3288 	const struct rte_flow_action_set_meta *conf;
3289 	uint32_t nic_mask = UINT32_MAX;
3290 	int reg;
3291 
3292 	if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
3293 	    !mlx5_flow_ext_mreg_supported(dev))
3294 		return rte_flow_error_set(error, ENOTSUP,
3295 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3296 					  "extended metadata register"
3297 					  " isn't supported");
3298 	reg = flow_dv_get_metadata_reg(dev, attr, error);
3299 	if (reg < 0)
3300 		return reg;
3301 	if (reg == REG_NON)
3302 		return rte_flow_error_set(error, ENOTSUP,
3303 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3304 					  "unavailable extended metadata register");
3305 	if (reg != REG_A && reg != REG_B) {
3306 		struct mlx5_priv *priv = dev->data->dev_private;
3307 
3308 		nic_mask = priv->sh->dv_meta_mask;
3309 	}
3310 	if (!(action->conf))
3311 		return rte_flow_error_set(error, EINVAL,
3312 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3313 					  "configuration cannot be null");
3314 	conf = (const struct rte_flow_action_set_meta *)action->conf;
3315 	if (!conf->mask)
3316 		return rte_flow_error_set(error, EINVAL,
3317 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3318 					  "zero mask doesn't have any effect");
3319 	if (conf->mask & ~nic_mask)
3320 		return rte_flow_error_set(error, EINVAL,
3321 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3322 					  "meta data must be within reg C0");
3323 	return 0;
3324 }
3325 
3326 /**
3327  * Validate SET_TAG action.
3328  *
3329  * @param[in] dev
3330  *   Pointer to the rte_eth_dev structure.
3331  * @param[in] action
3332  *   Pointer to the action structure.
3333  * @param[in] action_flags
3334  *   Holds the actions detected until now.
3335  * @param[in] attr
3336  *   Pointer to flow attributes
3337  * @param[out] error
3338  *   Pointer to error structure.
3339  *
3340  * @return
3341  *   0 on success, a negative errno value otherwise and rte_errno is set.
3342  */
3343 static int
3344 flow_dv_validate_action_set_tag(struct rte_eth_dev *dev,
3345 				const struct rte_flow_action *action,
3346 				uint64_t action_flags,
3347 				const struct rte_flow_attr *attr,
3348 				struct rte_flow_error *error)
3349 {
3350 	const struct rte_flow_action_set_tag *conf;
3351 	const uint64_t terminal_action_flags =
3352 		MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE |
3353 		MLX5_FLOW_ACTION_RSS;
3354 	int ret;
3355 
3356 	if (!mlx5_flow_ext_mreg_supported(dev))
3357 		return rte_flow_error_set(error, ENOTSUP,
3358 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3359 					  "extensive metadata register"
3360 					  " isn't supported");
3361 	if (!(action->conf))
3362 		return rte_flow_error_set(error, EINVAL,
3363 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3364 					  "configuration cannot be null");
3365 	conf = (const struct rte_flow_action_set_tag *)action->conf;
3366 	if (!conf->mask)
3367 		return rte_flow_error_set(error, EINVAL,
3368 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3369 					  "zero mask doesn't have any effect");
3370 	ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, conf->index, error);
3371 	if (ret < 0)
3372 		return ret;
3373 	if (attr->ingress && (action_flags & terminal_action_flags))
3374 		return rte_flow_error_set(error, EINVAL,
3375 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3376 					  "set_tag has no effect"
3377 					  " with terminal actions");
3378 	return 0;
3379 }
3380 
3381 /**
3382  * Indicates whether ASO aging is supported.
3383  *
3384  * @param[in] priv
3385  *   Pointer to device private context structure.
3386  * @param[in] root
3387  *   Whether action is on root table.
3388  *
3389  * @return
3390  *   True when ASO aging is supported, false otherwise.
3391  */
3392 static inline bool
3393 flow_hit_aso_supported(const struct mlx5_priv *priv, bool root)
3394 {
3395 	MLX5_ASSERT(priv);
3396 	return (priv->sh->flow_hit_aso_en && !root);
3397 }
3398 
3399 /**
3400  * Validate count action.
3401  *
3402  * @param[in] dev
3403  *   Pointer to rte_eth_dev structure.
3404  * @param[in] shared
3405  *   Indicator if action is shared.
3406  * @param[in] action_flags
3407  *   Holds the actions detected until now.
3408  * @param[in] root
3409  *   Whether action is on root table.
3410  * @param[out] error
3411  *   Pointer to error structure.
3412  *
3413  * @return
3414  *   0 on success, a negative errno value otherwise and rte_errno is set.
3415  */
3416 static int
3417 flow_dv_validate_action_count(struct rte_eth_dev *dev, bool shared,
3418 			      uint64_t action_flags,
3419 			      bool root,
3420 			      struct rte_flow_error *error)
3421 {
3422 	struct mlx5_priv *priv = dev->data->dev_private;
3423 
3424 	if (!priv->sh->cdev->config.devx)
3425 		goto notsup_err;
3426 	if (action_flags & MLX5_FLOW_ACTION_COUNT)
3427 		return rte_flow_error_set(error, EINVAL,
3428 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3429 					  "duplicate count actions set");
3430 	if (shared && (action_flags & MLX5_FLOW_ACTION_AGE) &&
3431 	    !flow_hit_aso_supported(priv, root))
3432 		return rte_flow_error_set(error, EINVAL,
3433 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3434 					  "old age and indirect count combination is not supported");
3435 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
3436 	return 0;
3437 #endif
3438 notsup_err:
3439 	return rte_flow_error_set
3440 		      (error, ENOTSUP,
3441 		       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3442 		       NULL,
3443 		       "count action not supported");
3444 }
3445 
3446 /**
3447  * Validate the L2 encap action.
3448  *
3449  * @param[in] dev
3450  *   Pointer to the rte_eth_dev structure.
3451  * @param[in] action_flags
3452  *   Holds the actions detected until now.
3453  * @param[in] action
3454  *   Pointer to the action structure.
3455  * @param[in] attr
3456  *   Pointer to flow attributes.
3457  * @param[out] error
3458  *   Pointer to error structure.
3459  *
3460  * @return
3461  *   0 on success, a negative errno value otherwise and rte_errno is set.
3462  */
3463 static int
3464 flow_dv_validate_action_l2_encap(struct rte_eth_dev *dev,
3465 				 uint64_t action_flags,
3466 				 const struct rte_flow_action *action,
3467 				 const struct rte_flow_attr *attr,
3468 				 struct rte_flow_error *error)
3469 {
3470 	const struct mlx5_priv *priv = dev->data->dev_private;
3471 
3472 	if (!(action->conf))
3473 		return rte_flow_error_set(error, EINVAL,
3474 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
3475 					  "configuration cannot be null");
3476 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3477 		return rte_flow_error_set(error, EINVAL,
3478 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3479 					  "can only have a single encap action "
3480 					  "in a flow");
3481 	if (!attr->transfer && priv->representor)
3482 		return rte_flow_error_set(error, ENOTSUP,
3483 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3484 					  "encap action for VF representor "
3485 					  "not supported on NIC table");
3486 	return 0;
3487 }
3488 
3489 /**
3490  * Validate a decap action.
3491  *
3492  * @param[in] dev
3493  *   Pointer to the rte_eth_dev structure.
3494  * @param[in] action_flags
3495  *   Holds the actions detected until now.
3496  * @param[in] action
3497  *   Pointer to the action structure.
3498  * @param[in] item_flags
3499  *   Holds the items detected.
3500  * @param[in] attr
3501  *   Pointer to flow attributes
3502  * @param[out] error
3503  *   Pointer to error structure.
3504  *
3505  * @return
3506  *   0 on success, a negative errno value otherwise and rte_errno is set.
3507  */
3508 static int
3509 flow_dv_validate_action_decap(struct rte_eth_dev *dev,
3510 			      uint64_t action_flags,
3511 			      const struct rte_flow_action *action,
3512 			      const uint64_t item_flags,
3513 			      const struct rte_flow_attr *attr,
3514 			      struct rte_flow_error *error)
3515 {
3516 	const struct mlx5_priv *priv = dev->data->dev_private;
3517 
3518 	if (priv->sh->cdev->config.hca_attr.scatter_fcs_w_decap_disable &&
3519 	    !priv->sh->config.decap_en)
3520 		return rte_flow_error_set(error, ENOTSUP,
3521 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3522 					  "decap is not enabled");
3523 	if (action_flags & MLX5_FLOW_XCAP_ACTIONS)
3524 		return rte_flow_error_set(error, ENOTSUP,
3525 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3526 					  action_flags &
3527 					  MLX5_FLOW_ACTION_DECAP ? "can only "
3528 					  "have a single decap action" : "decap "
3529 					  "after encap is not supported");
3530 	if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
3531 		return rte_flow_error_set(error, EINVAL,
3532 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3533 					  "can't have decap action after"
3534 					  " modify action");
3535 	if (attr->egress)
3536 		return rte_flow_error_set(error, ENOTSUP,
3537 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
3538 					  NULL,
3539 					  "decap action not supported for "
3540 					  "egress");
3541 	if (!attr->transfer && priv->representor)
3542 		return rte_flow_error_set(error, ENOTSUP,
3543 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3544 					  "decap action for VF representor "
3545 					  "not supported on NIC table");
3546 	if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP &&
3547 	    !(item_flags & MLX5_FLOW_LAYER_VXLAN))
3548 		return rte_flow_error_set(error, ENOTSUP,
3549 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3550 				"VXLAN item should be present for VXLAN decap");
3551 	return 0;
3552 }
3553 
3554 const struct rte_flow_action_raw_decap empty_decap = {.data = NULL, .size = 0,};
3555 
3556 /**
3557  * Validate the raw encap and decap actions.
3558  *
3559  * @param[in] dev
3560  *   Pointer to the rte_eth_dev structure.
3561  * @param[in] decap
3562  *   Pointer to the decap action.
3563  * @param[in] encap
3564  *   Pointer to the encap action.
3565  * @param[in] attr
3566  *   Pointer to flow attributes
3567  * @param[in/out] action_flags
3568  *   Holds the actions detected until now.
3569  * @param[out] actions_n
3570  *   pointer to the number of actions counter.
3571  * @param[in] action
3572  *   Pointer to the action structure.
3573  * @param[in] item_flags
3574  *   Holds the items detected.
3575  * @param[out] error
3576  *   Pointer to error structure.
3577  *
3578  * @return
3579  *   0 on success, a negative errno value otherwise and rte_errno is set.
3580  */
3581 static int
3582 flow_dv_validate_action_raw_encap_decap
3583 	(struct rte_eth_dev *dev,
3584 	 const struct rte_flow_action_raw_decap *decap,
3585 	 const struct rte_flow_action_raw_encap *encap,
3586 	 const struct rte_flow_attr *attr, uint64_t *action_flags,
3587 	 int *actions_n, const struct rte_flow_action *action,
3588 	 uint64_t item_flags, struct rte_flow_error *error)
3589 {
3590 	const struct mlx5_priv *priv = dev->data->dev_private;
3591 	int ret;
3592 
3593 	if (encap && (!encap->size || !encap->data))
3594 		return rte_flow_error_set(error, EINVAL,
3595 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3596 					  "raw encap data cannot be empty");
3597 	if (decap && encap) {
3598 		if (decap->size <= MLX5_ENCAPSULATION_DECISION_SIZE &&
3599 		    encap->size > MLX5_ENCAPSULATION_DECISION_SIZE)
3600 			/* L3 encap. */
3601 			decap = NULL;
3602 		else if (encap->size <=
3603 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3604 			   decap->size >
3605 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3606 			/* L3 decap. */
3607 			encap = NULL;
3608 		else if (encap->size >
3609 			   MLX5_ENCAPSULATION_DECISION_SIZE &&
3610 			   decap->size >
3611 			   MLX5_ENCAPSULATION_DECISION_SIZE)
3612 			/* 2 L2 actions: encap and decap. */
3613 			;
3614 		else
3615 			return rte_flow_error_set(error,
3616 				ENOTSUP,
3617 				RTE_FLOW_ERROR_TYPE_ACTION,
3618 				NULL, "unsupported too small "
3619 				"raw decap and too small raw "
3620 				"encap combination");
3621 	}
3622 	if (decap) {
3623 		ret = flow_dv_validate_action_decap(dev, *action_flags, action,
3624 						    item_flags, attr, error);
3625 		if (ret < 0)
3626 			return ret;
3627 		*action_flags |= MLX5_FLOW_ACTION_DECAP;
3628 		++(*actions_n);
3629 	}
3630 	if (encap) {
3631 		if (encap->size <= MLX5_ENCAPSULATION_DECISION_SIZE)
3632 			return rte_flow_error_set(error, ENOTSUP,
3633 						  RTE_FLOW_ERROR_TYPE_ACTION,
3634 						  NULL,
3635 						  "small raw encap size");
3636 		if (*action_flags & MLX5_FLOW_ACTION_ENCAP)
3637 			return rte_flow_error_set(error, EINVAL,
3638 						  RTE_FLOW_ERROR_TYPE_ACTION,
3639 						  NULL,
3640 						  "more than one encap action");
3641 		if (!attr->transfer && priv->representor)
3642 			return rte_flow_error_set
3643 					(error, ENOTSUP,
3644 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3645 					 "encap action for VF representor "
3646 					 "not supported on NIC table");
3647 		*action_flags |= MLX5_FLOW_ACTION_ENCAP;
3648 		++(*actions_n);
3649 	}
3650 	return 0;
3651 }
3652 
3653 /*
3654  * Validate the ASO CT action.
3655  *
3656  * @param[in] dev
3657  *   Pointer to the rte_eth_dev structure.
3658  * @param[in] action_flags
3659  *   Holds the actions detected until now.
3660  * @param[in] item_flags
3661  *   The items found in this flow rule.
3662  * @param root
3663  *   Whether action is on root table.
3664  * @param[out] error
3665  *   Pointer to error structure.
3666  *
3667  * @return
3668  *   0 on success, a negative errno value otherwise and rte_errno is set.
3669  */
3670 static int
3671 flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev,
3672 			       uint64_t action_flags,
3673 			       uint64_t item_flags,
3674 			       bool root,
3675 			       struct rte_flow_error *error)
3676 {
3677 	RTE_SET_USED(dev);
3678 
3679 	if (root)
3680 		return rte_flow_error_set(error, ENOTSUP,
3681 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3682 					  NULL,
3683 					  "Only support non-root table");
3684 	if (action_flags & MLX5_FLOW_FATE_ACTIONS)
3685 		return rte_flow_error_set(error, ENOTSUP,
3686 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3687 					  "CT cannot follow a fate action");
3688 	if ((action_flags & MLX5_FLOW_ACTION_METER) ||
3689 	    (action_flags & MLX5_FLOW_ACTION_AGE))
3690 		return rte_flow_error_set(error, EINVAL,
3691 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3692 					  "Only one ASO action is supported");
3693 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
3694 		return rte_flow_error_set(error, EINVAL,
3695 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
3696 					  "Encap cannot exist before CT");
3697 	if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP))
3698 		return rte_flow_error_set(error, EINVAL,
3699 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3700 					  "Not a outer TCP packet");
3701 	return 0;
3702 }
3703 
3704 /**
3705  * Validate METER_COLOR item.
3706  *
3707  * @param[in] dev
3708  *   Pointer to the rte_eth_dev structure.
3709  * @param[in] item
3710  *   Item specification.
3711  * @param[in] attr
3712  *   Attributes of flow that includes this item.
3713  * @param[out] error
3714  *   Pointer to error structure.
3715  *
3716  * @return
3717  *   0 on success, a negative errno value otherwise and rte_errno is set.
3718  */
3719 static int
3720 flow_dv_validate_item_meter_color(struct rte_eth_dev *dev,
3721 			   const struct rte_flow_item *item,
3722 			   const struct rte_flow_attr *attr __rte_unused,
3723 			   struct rte_flow_error *error)
3724 {
3725 	struct mlx5_priv *priv = dev->data->dev_private;
3726 	const struct rte_flow_item_meter_color *spec = item->spec;
3727 	const struct rte_flow_item_meter_color *mask = item->mask;
3728 	struct rte_flow_item_meter_color nic_mask = {
3729 		.color = RTE_COLORS
3730 	};
3731 	int ret;
3732 
3733 	if (priv->mtr_color_reg == REG_NON)
3734 		return rte_flow_error_set(error, ENOTSUP,
3735 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
3736 					  "meter color register"
3737 					  " isn't available");
3738 	ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error);
3739 	if (ret < 0)
3740 		return ret;
3741 	if (!spec)
3742 		return rte_flow_error_set(error, EINVAL,
3743 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
3744 					  item->spec,
3745 					  "data cannot be empty");
3746 	if (spec->color > RTE_COLORS)
3747 		return rte_flow_error_set(error, EINVAL,
3748 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
3749 					  &spec->color,
3750 					  "meter color is invalid");
3751 	if (!mask)
3752 		mask = &rte_flow_item_meter_color_mask;
3753 	if (!mask->color)
3754 		return rte_flow_error_set(error, EINVAL,
3755 					RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
3756 					"mask cannot be zero");
3757 
3758 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
3759 				(const uint8_t *)&nic_mask,
3760 				sizeof(struct rte_flow_item_meter_color),
3761 				MLX5_ITEM_RANGE_NOT_ACCEPTED, error);
3762 	if (ret < 0)
3763 		return ret;
3764 	return 0;
3765 }
3766 
3767 int
3768 flow_dv_encap_decap_match_cb(void *tool_ctx __rte_unused,
3769 			     struct mlx5_list_entry *entry, void *cb_ctx)
3770 {
3771 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3772 	struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3773 	struct mlx5_flow_dv_encap_decap_resource *resource;
3774 
3775 	resource = container_of(entry, struct mlx5_flow_dv_encap_decap_resource,
3776 				entry);
3777 	if (resource->reformat_type == ctx_resource->reformat_type &&
3778 	    resource->ft_type == ctx_resource->ft_type &&
3779 	    resource->flags == ctx_resource->flags &&
3780 	    resource->size == ctx_resource->size &&
3781 	    !memcmp((const void *)resource->buf,
3782 		    (const void *)ctx_resource->buf,
3783 		    resource->size))
3784 		return 0;
3785 	return -1;
3786 }
3787 
3788 struct mlx5_list_entry *
3789 flow_dv_encap_decap_create_cb(void *tool_ctx, void *cb_ctx)
3790 {
3791 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3792 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3793 	struct mlx5dv_dr_domain *domain;
3794 	struct mlx5_flow_dv_encap_decap_resource *ctx_resource = ctx->data;
3795 	struct mlx5_flow_dv_encap_decap_resource *resource;
3796 	uint32_t idx;
3797 	int ret;
3798 
3799 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
3800 		domain = sh->fdb_domain;
3801 	else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
3802 		domain = sh->rx_domain;
3803 	else
3804 		domain = sh->tx_domain;
3805 	/* Register new encap/decap resource. */
3806 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], &idx);
3807 	if (!resource) {
3808 		rte_flow_error_set(ctx->error, ENOMEM,
3809 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3810 				   "cannot allocate resource memory");
3811 		return NULL;
3812 	}
3813 	*resource = *ctx_resource;
3814 	resource->idx = idx;
3815 	ret = mlx5_flow_os_create_flow_action_packet_reformat(sh->cdev->ctx,
3816 							      domain, resource,
3817 							     &resource->action);
3818 	if (ret) {
3819 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], idx);
3820 		rte_flow_error_set(ctx->error, ENOMEM,
3821 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3822 				   NULL, "cannot create action");
3823 		return NULL;
3824 	}
3825 
3826 	return &resource->entry;
3827 }
3828 
3829 struct mlx5_list_entry *
3830 flow_dv_encap_decap_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
3831 			     void *cb_ctx)
3832 {
3833 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3834 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3835 	struct mlx5_flow_dv_encap_decap_resource *cache_resource;
3836 	uint32_t idx;
3837 
3838 	cache_resource = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
3839 					   &idx);
3840 	if (!cache_resource) {
3841 		rte_flow_error_set(ctx->error, ENOMEM,
3842 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3843 				   "cannot allocate resource memory");
3844 		return NULL;
3845 	}
3846 	memcpy(cache_resource, oentry, sizeof(*cache_resource));
3847 	cache_resource->idx = idx;
3848 	return &cache_resource->entry;
3849 }
3850 
3851 void
3852 flow_dv_encap_decap_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
3853 {
3854 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3855 	struct mlx5_flow_dv_encap_decap_resource *res =
3856 				       container_of(entry, typeof(*res), entry);
3857 
3858 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
3859 }
3860 
3861 /**
3862  * Find existing encap/decap resource or create and register a new one.
3863  *
3864  * @param[in, out] dev
3865  *   Pointer to rte_eth_dev structure.
3866  * @param[in, out] resource
3867  *   Pointer to encap/decap resource.
3868  * @parm[in, out] dev_flow
3869  *   Pointer to the dev_flow.
3870  * @param[out] error
3871  *   pointer to error structure.
3872  *
3873  * @return
3874  *   0 on success otherwise -errno and errno is set.
3875  */
3876 static int
3877 flow_dv_encap_decap_resource_register
3878 			(struct rte_eth_dev *dev,
3879 			 struct mlx5_flow_dv_encap_decap_resource *resource,
3880 			 struct mlx5_flow *dev_flow,
3881 			 struct rte_flow_error *error)
3882 {
3883 	struct mlx5_priv *priv = dev->data->dev_private;
3884 	struct mlx5_dev_ctx_shared *sh = priv->sh;
3885 	struct mlx5_list_entry *entry;
3886 	union {
3887 		struct {
3888 			uint32_t ft_type:8;
3889 			uint32_t refmt_type:8;
3890 			/*
3891 			 * Header reformat actions can be shared between
3892 			 * non-root tables. One bit to indicate non-root
3893 			 * table or not.
3894 			 */
3895 			uint32_t is_root:1;
3896 			uint32_t reserve:15;
3897 		};
3898 		uint32_t v32;
3899 	} encap_decap_key = {
3900 		{
3901 			.ft_type = resource->ft_type,
3902 			.refmt_type = resource->reformat_type,
3903 			.is_root = !!dev_flow->dv.group,
3904 			.reserve = 0,
3905 		}
3906 	};
3907 	struct mlx5_flow_cb_ctx ctx = {
3908 		.error = error,
3909 		.data = resource,
3910 	};
3911 	struct mlx5_hlist *encaps_decaps;
3912 	uint64_t key64;
3913 
3914 	encaps_decaps = flow_dv_hlist_prepare(sh, &sh->encaps_decaps,
3915 				"encaps_decaps",
3916 				MLX5_FLOW_ENCAP_DECAP_HTABLE_SZ,
3917 				true, true, sh,
3918 				flow_dv_encap_decap_create_cb,
3919 				flow_dv_encap_decap_match_cb,
3920 				flow_dv_encap_decap_remove_cb,
3921 				flow_dv_encap_decap_clone_cb,
3922 				flow_dv_encap_decap_clone_free_cb,
3923 				error);
3924 	if (unlikely(!encaps_decaps))
3925 		return -rte_errno;
3926 	resource->flags = dev_flow->dv.group ? 0 : 1;
3927 	key64 =  __rte_raw_cksum(&encap_decap_key.v32,
3928 				 sizeof(encap_decap_key.v32), 0);
3929 	if (resource->reformat_type !=
3930 	    MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2 &&
3931 	    resource->size)
3932 		key64 = __rte_raw_cksum(resource->buf, resource->size, key64);
3933 	entry = mlx5_hlist_register(encaps_decaps, key64, &ctx);
3934 	if (!entry)
3935 		return -rte_errno;
3936 	resource = container_of(entry, typeof(*resource), entry);
3937 	dev_flow->dv.encap_decap = resource;
3938 	dev_flow->handle->dvh.rix_encap_decap = resource->idx;
3939 	return 0;
3940 }
3941 
3942 /**
3943  * Find existing table jump resource or create and register a new one.
3944  *
3945  * @param[in, out] dev
3946  *   Pointer to rte_eth_dev structure.
3947  * @param[in, out] tbl
3948  *   Pointer to flow table resource.
3949  * @parm[in, out] dev_flow
3950  *   Pointer to the dev_flow.
3951  * @param[out] error
3952  *   pointer to error structure.
3953  *
3954  * @return
3955  *   0 on success otherwise -errno and errno is set.
3956  */
3957 static int
3958 flow_dv_jump_tbl_resource_register
3959 			(struct rte_eth_dev *dev __rte_unused,
3960 			 struct mlx5_flow_tbl_resource *tbl,
3961 			 struct mlx5_flow *dev_flow,
3962 			 struct rte_flow_error *error __rte_unused)
3963 {
3964 	struct mlx5_flow_tbl_data_entry *tbl_data =
3965 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
3966 
3967 	MLX5_ASSERT(tbl);
3968 	MLX5_ASSERT(tbl_data->jump.action);
3969 	dev_flow->handle->rix_jump = tbl_data->idx;
3970 	dev_flow->dv.jump = &tbl_data->jump;
3971 	return 0;
3972 }
3973 
3974 int
3975 flow_dv_port_id_match_cb(void *tool_ctx __rte_unused,
3976 			 struct mlx5_list_entry *entry, void *cb_ctx)
3977 {
3978 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3979 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3980 	struct mlx5_flow_dv_port_id_action_resource *res =
3981 				       container_of(entry, typeof(*res), entry);
3982 
3983 	return ref->port_id != res->port_id;
3984 }
3985 
3986 struct mlx5_list_entry *
3987 flow_dv_port_id_create_cb(void *tool_ctx, void *cb_ctx)
3988 {
3989 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
3990 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
3991 	struct mlx5_flow_dv_port_id_action_resource *ref = ctx->data;
3992 	struct mlx5_flow_dv_port_id_action_resource *resource;
3993 	uint32_t idx;
3994 	int ret;
3995 
3996 	/* Register new port id action resource. */
3997 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
3998 	if (!resource) {
3999 		rte_flow_error_set(ctx->error, ENOMEM,
4000 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4001 				   "cannot allocate port_id action memory");
4002 		return NULL;
4003 	}
4004 	*resource = *ref;
4005 	ret = mlx5_flow_os_create_flow_action_dest_port(sh->fdb_domain,
4006 							ref->port_id,
4007 							&resource->action);
4008 	if (ret) {
4009 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], idx);
4010 		rte_flow_error_set(ctx->error, ENOMEM,
4011 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4012 				   "cannot create action");
4013 		return NULL;
4014 	}
4015 	resource->idx = idx;
4016 	return &resource->entry;
4017 }
4018 
4019 struct mlx5_list_entry *
4020 flow_dv_port_id_clone_cb(void *tool_ctx,
4021 			 struct mlx5_list_entry *entry __rte_unused,
4022 			 void *cb_ctx)
4023 {
4024 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
4025 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
4026 	struct mlx5_flow_dv_port_id_action_resource *resource;
4027 	uint32_t idx;
4028 
4029 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PORT_ID], &idx);
4030 	if (!resource) {
4031 		rte_flow_error_set(ctx->error, ENOMEM,
4032 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4033 				   "cannot allocate port_id action memory");
4034 		return NULL;
4035 	}
4036 	memcpy(resource, entry, sizeof(*resource));
4037 	resource->idx = idx;
4038 	return &resource->entry;
4039 }
4040 
4041 void
4042 flow_dv_port_id_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
4043 {
4044 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
4045 	struct mlx5_flow_dv_port_id_action_resource *resource =
4046 				  container_of(entry, typeof(*resource), entry);
4047 
4048 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
4049 }
4050 
4051 /**
4052  * Find existing table port ID resource or create and register a new one.
4053  *
4054  * @param[in, out] dev
4055  *   Pointer to rte_eth_dev structure.
4056  * @param[in, out] ref
4057  *   Pointer to port ID action resource reference.
4058  * @parm[in, out] dev_flow
4059  *   Pointer to the dev_flow.
4060  * @param[out] error
4061  *   pointer to error structure.
4062  *
4063  * @return
4064  *   0 on success otherwise -errno and errno is set.
4065  */
4066 static int
4067 flow_dv_port_id_action_resource_register
4068 			(struct rte_eth_dev *dev,
4069 			 struct mlx5_flow_dv_port_id_action_resource *ref,
4070 			 struct mlx5_flow *dev_flow,
4071 			 struct rte_flow_error *error)
4072 {
4073 	struct mlx5_priv *priv = dev->data->dev_private;
4074 	struct mlx5_list_entry *entry;
4075 	struct mlx5_flow_dv_port_id_action_resource *resource;
4076 	struct mlx5_flow_cb_ctx ctx = {
4077 		.error = error,
4078 		.data = ref,
4079 	};
4080 
4081 	entry = mlx5_list_register(priv->sh->port_id_action_list, &ctx);
4082 	if (!entry)
4083 		return -rte_errno;
4084 	resource = container_of(entry, typeof(*resource), entry);
4085 	dev_flow->dv.port_id_action = resource;
4086 	dev_flow->handle->rix_port_id_action = resource->idx;
4087 	return 0;
4088 }
4089 
4090 int
4091 flow_dv_push_vlan_match_cb(void *tool_ctx __rte_unused,
4092 			   struct mlx5_list_entry *entry, void *cb_ctx)
4093 {
4094 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
4095 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
4096 	struct mlx5_flow_dv_push_vlan_action_resource *res =
4097 				       container_of(entry, typeof(*res), entry);
4098 
4099 	return ref->vlan_tag != res->vlan_tag || ref->ft_type != res->ft_type;
4100 }
4101 
4102 struct mlx5_list_entry *
4103 flow_dv_push_vlan_create_cb(void *tool_ctx, void *cb_ctx)
4104 {
4105 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
4106 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
4107 	struct mlx5_flow_dv_push_vlan_action_resource *ref = ctx->data;
4108 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
4109 	struct mlx5dv_dr_domain *domain;
4110 	uint32_t idx;
4111 	int ret;
4112 
4113 	/* Register new port id action resource. */
4114 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
4115 	if (!resource) {
4116 		rte_flow_error_set(ctx->error, ENOMEM,
4117 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4118 				   "cannot allocate push_vlan action memory");
4119 		return NULL;
4120 	}
4121 	*resource = *ref;
4122 	if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
4123 		domain = sh->fdb_domain;
4124 	else if (ref->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
4125 		domain = sh->rx_domain;
4126 	else
4127 		domain = sh->tx_domain;
4128 	ret = mlx5_flow_os_create_flow_action_push_vlan(domain, ref->vlan_tag,
4129 							&resource->action);
4130 	if (ret) {
4131 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
4132 		rte_flow_error_set(ctx->error, ENOMEM,
4133 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4134 				   "cannot create push vlan action");
4135 		return NULL;
4136 	}
4137 	resource->idx = idx;
4138 	return &resource->entry;
4139 }
4140 
4141 struct mlx5_list_entry *
4142 flow_dv_push_vlan_clone_cb(void *tool_ctx,
4143 			   struct mlx5_list_entry *entry __rte_unused,
4144 			   void *cb_ctx)
4145 {
4146 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
4147 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
4148 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
4149 	uint32_t idx;
4150 
4151 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_PUSH_VLAN], &idx);
4152 	if (!resource) {
4153 		rte_flow_error_set(ctx->error, ENOMEM,
4154 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4155 				   "cannot allocate push_vlan action memory");
4156 		return NULL;
4157 	}
4158 	memcpy(resource, entry, sizeof(*resource));
4159 	resource->idx = idx;
4160 	return &resource->entry;
4161 }
4162 
4163 void
4164 flow_dv_push_vlan_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
4165 {
4166 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
4167 	struct mlx5_flow_dv_push_vlan_action_resource *resource =
4168 				  container_of(entry, typeof(*resource), entry);
4169 
4170 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
4171 }
4172 
4173 /**
4174  * Find existing push vlan resource or create and register a new one.
4175  *
4176  * @param [in, out] dev
4177  *   Pointer to rte_eth_dev structure.
4178  * @param[in, out] ref
4179  *   Pointer to port ID action resource reference.
4180  * @parm[in, out] dev_flow
4181  *   Pointer to the dev_flow.
4182  * @param[out] error
4183  *   pointer to error structure.
4184  *
4185  * @return
4186  *   0 on success otherwise -errno and errno is set.
4187  */
4188 static int
4189 flow_dv_push_vlan_action_resource_register
4190 		       (struct rte_eth_dev *dev,
4191 			struct mlx5_flow_dv_push_vlan_action_resource *ref,
4192 			struct mlx5_flow *dev_flow,
4193 			struct rte_flow_error *error)
4194 {
4195 	struct mlx5_priv *priv = dev->data->dev_private;
4196 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
4197 	struct mlx5_list_entry *entry;
4198 	struct mlx5_flow_cb_ctx ctx = {
4199 		.error = error,
4200 		.data = ref,
4201 	};
4202 
4203 	entry = mlx5_list_register(priv->sh->push_vlan_action_list, &ctx);
4204 	if (!entry)
4205 		return -rte_errno;
4206 	resource = container_of(entry, typeof(*resource), entry);
4207 
4208 	dev_flow->handle->dvh.rix_push_vlan = resource->idx;
4209 	dev_flow->dv.push_vlan_res = resource;
4210 	return 0;
4211 }
4212 
4213 /**
4214  * Get the size of specific rte_flow_item_type hdr size
4215  *
4216  * @param[in] item_type
4217  *   Tested rte_flow_item_type.
4218  *
4219  * @return
4220  *   sizeof struct item_type, 0 if void or irrelevant.
4221  */
4222 size_t
4223 flow_dv_get_item_hdr_len(const enum rte_flow_item_type item_type)
4224 {
4225 	size_t retval;
4226 
4227 	switch (item_type) {
4228 	case RTE_FLOW_ITEM_TYPE_ETH:
4229 		retval = sizeof(struct rte_ether_hdr);
4230 		break;
4231 	case RTE_FLOW_ITEM_TYPE_VLAN:
4232 		retval = sizeof(struct rte_vlan_hdr);
4233 		break;
4234 	case RTE_FLOW_ITEM_TYPE_IPV4:
4235 		retval = sizeof(struct rte_ipv4_hdr);
4236 		break;
4237 	case RTE_FLOW_ITEM_TYPE_IPV6:
4238 		retval = sizeof(struct rte_ipv6_hdr);
4239 		break;
4240 	case RTE_FLOW_ITEM_TYPE_UDP:
4241 		retval = sizeof(struct rte_udp_hdr);
4242 		break;
4243 	case RTE_FLOW_ITEM_TYPE_TCP:
4244 		retval = sizeof(struct rte_tcp_hdr);
4245 		break;
4246 	case RTE_FLOW_ITEM_TYPE_VXLAN:
4247 	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4248 		retval = sizeof(struct rte_vxlan_hdr);
4249 		break;
4250 	case RTE_FLOW_ITEM_TYPE_GRE:
4251 	case RTE_FLOW_ITEM_TYPE_NVGRE:
4252 		retval = sizeof(struct rte_gre_hdr);
4253 		break;
4254 	case RTE_FLOW_ITEM_TYPE_MPLS:
4255 		retval = sizeof(struct rte_mpls_hdr);
4256 		break;
4257 	case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */
4258 	default:
4259 		retval = 0;
4260 		break;
4261 	}
4262 	return retval;
4263 }
4264 
4265 #define MLX5_ENCAP_IPV4_VERSION		0x40
4266 #define MLX5_ENCAP_IPV4_IHL_MIN		0x05
4267 #define MLX5_ENCAP_IPV4_TTL_DEF		0x40
4268 #define MLX5_ENCAP_IPV6_VTC_FLOW	0x60000000
4269 #define MLX5_ENCAP_IPV6_HOP_LIMIT	0xff
4270 #define MLX5_ENCAP_VXLAN_FLAGS		0x08000000
4271 #define MLX5_ENCAP_VXLAN_GPE_FLAGS	0x04
4272 
4273 /**
4274  * Convert the encap action data from list of rte_flow_item to raw buffer
4275  *
4276  * @param[in] items
4277  *   Pointer to rte_flow_item objects list.
4278  * @param[out] buf
4279  *   Pointer to the output buffer.
4280  * @param[out] size
4281  *   Pointer to the output buffer size.
4282  * @param[out] error
4283  *   Pointer to the error structure.
4284  *
4285  * @return
4286  *   0 on success, a negative errno value otherwise and rte_errno is set.
4287  */
4288 int
4289 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf,
4290 			   size_t *size, struct rte_flow_error *error)
4291 {
4292 	struct rte_ether_hdr *eth = NULL;
4293 	struct rte_vlan_hdr *vlan = NULL;
4294 	struct rte_ipv4_hdr *ipv4 = NULL;
4295 	struct rte_ipv6_hdr *ipv6 = NULL;
4296 	struct rte_udp_hdr *udp = NULL;
4297 	struct rte_vxlan_hdr *vxlan = NULL;
4298 	struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL;
4299 	struct rte_gre_hdr *gre = NULL;
4300 	size_t len;
4301 	size_t temp_size = 0;
4302 
4303 	if (!items)
4304 		return rte_flow_error_set(error, EINVAL,
4305 					  RTE_FLOW_ERROR_TYPE_ACTION,
4306 					  NULL, "invalid empty data");
4307 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
4308 		len = flow_dv_get_item_hdr_len(items->type);
4309 		if (len + temp_size > MLX5_ENCAP_MAX_LEN)
4310 			return rte_flow_error_set(error, EINVAL,
4311 						  RTE_FLOW_ERROR_TYPE_ACTION,
4312 						  (void *)items->type,
4313 						  "items total size is too big"
4314 						  " for encap action");
4315 		rte_memcpy((void *)&buf[temp_size], items->spec, len);
4316 		switch (items->type) {
4317 		case RTE_FLOW_ITEM_TYPE_ETH:
4318 			eth = (struct rte_ether_hdr *)&buf[temp_size];
4319 			break;
4320 		case RTE_FLOW_ITEM_TYPE_VLAN:
4321 			vlan = (struct rte_vlan_hdr *)&buf[temp_size];
4322 			if (!eth)
4323 				return rte_flow_error_set(error, EINVAL,
4324 						RTE_FLOW_ERROR_TYPE_ACTION,
4325 						(void *)items->type,
4326 						"eth header not found");
4327 			if (!eth->ether_type)
4328 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN);
4329 			break;
4330 		case RTE_FLOW_ITEM_TYPE_IPV4:
4331 			ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size];
4332 			if (!vlan && !eth)
4333 				return rte_flow_error_set(error, EINVAL,
4334 						RTE_FLOW_ERROR_TYPE_ACTION,
4335 						(void *)items->type,
4336 						"neither eth nor vlan"
4337 						" header found");
4338 			if (vlan && !vlan->eth_proto)
4339 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4340 			else if (eth && !eth->ether_type)
4341 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4);
4342 			if (!ipv4->version_ihl)
4343 				ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION |
4344 						    MLX5_ENCAP_IPV4_IHL_MIN;
4345 			if (!ipv4->time_to_live)
4346 				ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF;
4347 			break;
4348 		case RTE_FLOW_ITEM_TYPE_IPV6:
4349 			ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size];
4350 			if (!vlan && !eth)
4351 				return rte_flow_error_set(error, EINVAL,
4352 						RTE_FLOW_ERROR_TYPE_ACTION,
4353 						(void *)items->type,
4354 						"neither eth nor vlan"
4355 						" header found");
4356 			if (vlan && !vlan->eth_proto)
4357 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4358 			else if (eth && !eth->ether_type)
4359 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6);
4360 			if (!ipv6->vtc_flow)
4361 				ipv6->vtc_flow =
4362 					RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW);
4363 			if (!ipv6->hop_limits)
4364 				ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT;
4365 			break;
4366 		case RTE_FLOW_ITEM_TYPE_UDP:
4367 			udp = (struct rte_udp_hdr *)&buf[temp_size];
4368 			if (!ipv4 && !ipv6)
4369 				return rte_flow_error_set(error, EINVAL,
4370 						RTE_FLOW_ERROR_TYPE_ACTION,
4371 						(void *)items->type,
4372 						"ip header not found");
4373 			if (ipv4 && !ipv4->next_proto_id)
4374 				ipv4->next_proto_id = IPPROTO_UDP;
4375 			else if (ipv6 && !ipv6->proto)
4376 				ipv6->proto = IPPROTO_UDP;
4377 			break;
4378 		case RTE_FLOW_ITEM_TYPE_VXLAN:
4379 			vxlan = (struct rte_vxlan_hdr *)&buf[temp_size];
4380 			if (!udp)
4381 				return rte_flow_error_set(error, EINVAL,
4382 						RTE_FLOW_ERROR_TYPE_ACTION,
4383 						(void *)items->type,
4384 						"udp header not found");
4385 			if (!udp->dst_port)
4386 				udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN);
4387 			if (!vxlan->vx_flags)
4388 				vxlan->vx_flags =
4389 					RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS);
4390 			break;
4391 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4392 			vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size];
4393 			if (!udp)
4394 				return rte_flow_error_set(error, EINVAL,
4395 						RTE_FLOW_ERROR_TYPE_ACTION,
4396 						(void *)items->type,
4397 						"udp header not found");
4398 			if (!vxlan_gpe->proto)
4399 				return rte_flow_error_set(error, EINVAL,
4400 						RTE_FLOW_ERROR_TYPE_ACTION,
4401 						(void *)items->type,
4402 						"next protocol not found");
4403 			if (!udp->dst_port)
4404 				udp->dst_port =
4405 					RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE);
4406 			if (!vxlan_gpe->vx_flags)
4407 				vxlan_gpe->vx_flags =
4408 						MLX5_ENCAP_VXLAN_GPE_FLAGS;
4409 			break;
4410 		case RTE_FLOW_ITEM_TYPE_GRE:
4411 		case RTE_FLOW_ITEM_TYPE_NVGRE:
4412 			gre = (struct rte_gre_hdr *)&buf[temp_size];
4413 			if (!gre->proto)
4414 				return rte_flow_error_set(error, EINVAL,
4415 						RTE_FLOW_ERROR_TYPE_ACTION,
4416 						(void *)items->type,
4417 						"next protocol not found");
4418 			if (!ipv4 && !ipv6)
4419 				return rte_flow_error_set(error, EINVAL,
4420 						RTE_FLOW_ERROR_TYPE_ACTION,
4421 						(void *)items->type,
4422 						"ip header not found");
4423 			if (ipv4 && !ipv4->next_proto_id)
4424 				ipv4->next_proto_id = IPPROTO_GRE;
4425 			else if (ipv6 && !ipv6->proto)
4426 				ipv6->proto = IPPROTO_GRE;
4427 			break;
4428 		case RTE_FLOW_ITEM_TYPE_VOID:
4429 			break;
4430 		default:
4431 			return rte_flow_error_set(error, EINVAL,
4432 						  RTE_FLOW_ERROR_TYPE_ACTION,
4433 						  (void *)items->type,
4434 						  "unsupported item type");
4435 			break;
4436 		}
4437 		temp_size += len;
4438 	}
4439 	*size = temp_size;
4440 	return 0;
4441 }
4442 
4443 static int
4444 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error)
4445 {
4446 	struct rte_ether_hdr *eth = NULL;
4447 	struct rte_vlan_hdr *vlan = NULL;
4448 	struct rte_ipv6_hdr *ipv6 = NULL;
4449 	struct rte_udp_hdr *udp = NULL;
4450 	char *next_hdr;
4451 	uint16_t proto;
4452 
4453 	eth = (struct rte_ether_hdr *)data;
4454 	next_hdr = (char *)(eth + 1);
4455 	proto = RTE_BE16(eth->ether_type);
4456 
4457 	/* VLAN skipping */
4458 	while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) {
4459 		vlan = (struct rte_vlan_hdr *)next_hdr;
4460 		proto = RTE_BE16(vlan->eth_proto);
4461 		next_hdr += sizeof(struct rte_vlan_hdr);
4462 	}
4463 
4464 	/* HW calculates IPv4 csum. no need to proceed */
4465 	if (proto == RTE_ETHER_TYPE_IPV4)
4466 		return 0;
4467 
4468 	/* non IPv4/IPv6 header. not supported */
4469 	if (proto != RTE_ETHER_TYPE_IPV6) {
4470 		return rte_flow_error_set(error, ENOTSUP,
4471 					  RTE_FLOW_ERROR_TYPE_ACTION,
4472 					  NULL, "Cannot offload non IPv4/IPv6");
4473 	}
4474 
4475 	ipv6 = (struct rte_ipv6_hdr *)next_hdr;
4476 
4477 	/* ignore non UDP */
4478 	if (ipv6->proto != IPPROTO_UDP)
4479 		return 0;
4480 
4481 	udp = (struct rte_udp_hdr *)(ipv6 + 1);
4482 	udp->dgram_cksum = 0;
4483 
4484 	return 0;
4485 }
4486 
4487 /**
4488  * Convert L2 encap action to DV specification.
4489  *
4490  * @param[in] dev
4491  *   Pointer to rte_eth_dev structure.
4492  * @param[in] action
4493  *   Pointer to action structure.
4494  * @param[in, out] dev_flow
4495  *   Pointer to the mlx5_flow.
4496  * @param[in] transfer
4497  *   Mark if the flow is E-Switch flow.
4498  * @param[out] error
4499  *   Pointer to the error structure.
4500  *
4501  * @return
4502  *   0 on success, a negative errno value otherwise and rte_errno is set.
4503  */
4504 static int
4505 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev,
4506 			       const struct rte_flow_action *action,
4507 			       struct mlx5_flow *dev_flow,
4508 			       uint8_t transfer,
4509 			       struct rte_flow_error *error)
4510 {
4511 	const struct rte_flow_item *encap_data;
4512 	const struct rte_flow_action_raw_encap *raw_encap_data;
4513 	struct mlx5_flow_dv_encap_decap_resource res = {
4514 		.reformat_type =
4515 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL,
4516 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4517 				      MLX5DV_FLOW_TABLE_TYPE_NIC_TX,
4518 	};
4519 
4520 	if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
4521 		raw_encap_data =
4522 			(const struct rte_flow_action_raw_encap *)action->conf;
4523 		res.size = raw_encap_data->size;
4524 		memcpy(res.buf, raw_encap_data->data, res.size);
4525 	} else {
4526 		if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
4527 			encap_data =
4528 				((const struct rte_flow_action_vxlan_encap *)
4529 						action->conf)->definition;
4530 		else
4531 			encap_data =
4532 				((const struct rte_flow_action_nvgre_encap *)
4533 						action->conf)->definition;
4534 		if (flow_dv_convert_encap_data(encap_data, res.buf,
4535 					       &res.size, error))
4536 			return -rte_errno;
4537 	}
4538 	if (flow_dv_zero_encap_udp_csum(res.buf, error))
4539 		return -rte_errno;
4540 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4541 		return rte_flow_error_set(error, EINVAL,
4542 					  RTE_FLOW_ERROR_TYPE_ACTION,
4543 					  NULL, "can't create L2 encap action");
4544 	return 0;
4545 }
4546 
4547 /**
4548  * Convert L2 decap action to DV specification.
4549  *
4550  * @param[in] dev
4551  *   Pointer to rte_eth_dev structure.
4552  * @param[in, out] dev_flow
4553  *   Pointer to the mlx5_flow.
4554  * @param[in] transfer
4555  *   Mark if the flow is E-Switch flow.
4556  * @param[out] error
4557  *   Pointer to the error structure.
4558  *
4559  * @return
4560  *   0 on success, a negative errno value otherwise and rte_errno is set.
4561  */
4562 static int
4563 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev,
4564 			       struct mlx5_flow *dev_flow,
4565 			       uint8_t transfer,
4566 			       struct rte_flow_error *error)
4567 {
4568 	struct mlx5_flow_dv_encap_decap_resource res = {
4569 		.size = 0,
4570 		.reformat_type =
4571 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2,
4572 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
4573 				      MLX5DV_FLOW_TABLE_TYPE_NIC_RX,
4574 	};
4575 
4576 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4577 		return rte_flow_error_set(error, EINVAL,
4578 					  RTE_FLOW_ERROR_TYPE_ACTION,
4579 					  NULL, "can't create L2 decap action");
4580 	return 0;
4581 }
4582 
4583 /**
4584  * Convert raw decap/encap (L3 tunnel) action to DV specification.
4585  *
4586  * @param[in] dev
4587  *   Pointer to rte_eth_dev structure.
4588  * @param[in] action
4589  *   Pointer to action structure.
4590  * @param[in, out] dev_flow
4591  *   Pointer to the mlx5_flow.
4592  * @param[in] attr
4593  *   Pointer to the flow attributes.
4594  * @param[out] error
4595  *   Pointer to the error structure.
4596  *
4597  * @return
4598  *   0 on success, a negative errno value otherwise and rte_errno is set.
4599  */
4600 static int
4601 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
4602 				const struct rte_flow_action *action,
4603 				struct mlx5_flow *dev_flow,
4604 				const struct rte_flow_attr *attr,
4605 				struct rte_flow_error *error)
4606 {
4607 	const struct rte_flow_action_raw_encap *encap_data;
4608 	struct mlx5_flow_dv_encap_decap_resource res;
4609 
4610 	memset(&res, 0, sizeof(res));
4611 	encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
4612 	res.size = encap_data->size;
4613 	memcpy(res.buf, encap_data->data, res.size);
4614 	res.reformat_type = res.size < MLX5_ENCAPSULATION_DECISION_SIZE ?
4615 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2 :
4616 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
4617 	if (attr->transfer)
4618 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4619 	else
4620 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4621 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4622 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
4623 		return rte_flow_error_set(error, EINVAL,
4624 					  RTE_FLOW_ERROR_TYPE_ACTION,
4625 					  NULL, "can't create encap action");
4626 	return 0;
4627 }
4628 
4629 /**
4630  * Create action push VLAN.
4631  *
4632  * @param[in] dev
4633  *   Pointer to rte_eth_dev structure.
4634  * @param[in] attr
4635  *   Pointer to the flow attributes.
4636  * @param[in] vlan
4637  *   Pointer to the vlan to push to the Ethernet header.
4638  * @param[in, out] dev_flow
4639  *   Pointer to the mlx5_flow.
4640  * @param[out] error
4641  *   Pointer to the error structure.
4642  *
4643  * @return
4644  *   0 on success, a negative errno value otherwise and rte_errno is set.
4645  */
4646 static int
4647 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
4648 				const struct rte_flow_attr *attr,
4649 				const struct rte_vlan_hdr *vlan,
4650 				struct mlx5_flow *dev_flow,
4651 				struct rte_flow_error *error)
4652 {
4653 	struct mlx5_flow_dv_push_vlan_action_resource res;
4654 
4655 	memset(&res, 0, sizeof(res));
4656 	res.vlan_tag =
4657 		rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 |
4658 				 vlan->vlan_tci);
4659 	if (attr->transfer)
4660 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
4661 	else
4662 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
4663 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
4664 	return flow_dv_push_vlan_action_resource_register
4665 					    (dev, &res, dev_flow, error);
4666 }
4667 
4668 /**
4669  * Validate the modify-header actions.
4670  *
4671  * @param[in] action_flags
4672  *   Holds the actions detected until now.
4673  * @param[in] action
4674  *   Pointer to the modify action.
4675  * @param[out] error
4676  *   Pointer to error structure.
4677  *
4678  * @return
4679  *   0 on success, a negative errno value otherwise and rte_errno is set.
4680  */
4681 static int
4682 flow_dv_validate_action_modify_hdr(const uint64_t action_flags,
4683 				   const struct rte_flow_action *action,
4684 				   struct rte_flow_error *error)
4685 {
4686 	if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf)
4687 		return rte_flow_error_set(error, EINVAL,
4688 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
4689 					  NULL, "action configuration not set");
4690 	if (action_flags & MLX5_FLOW_ACTION_ENCAP)
4691 		return rte_flow_error_set(error, EINVAL,
4692 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
4693 					  "can't have encap action before"
4694 					  " modify action");
4695 	return 0;
4696 }
4697 
4698 /**
4699  * Validate the modify-header MAC address actions.
4700  *
4701  * @param[in] action_flags
4702  *   Holds the actions detected until now.
4703  * @param[in] action
4704  *   Pointer to the modify action.
4705  * @param[in] item_flags
4706  *   Holds the items detected.
4707  * @param[out] error
4708  *   Pointer to error structure.
4709  *
4710  * @return
4711  *   0 on success, a negative errno value otherwise and rte_errno is set.
4712  */
4713 static int
4714 flow_dv_validate_action_modify_mac(const uint64_t action_flags,
4715 				   const struct rte_flow_action *action,
4716 				   const uint64_t item_flags,
4717 				   struct rte_flow_error *error)
4718 {
4719 	int ret = 0;
4720 
4721 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4722 	if (!ret) {
4723 		if (!(item_flags & MLX5_FLOW_LAYER_L2))
4724 			return rte_flow_error_set(error, EINVAL,
4725 						  RTE_FLOW_ERROR_TYPE_ACTION,
4726 						  NULL,
4727 						  "no L2 item in pattern");
4728 	}
4729 	return ret;
4730 }
4731 
4732 /**
4733  * Validate the modify-header IPv4 address actions.
4734  *
4735  * @param[in] action_flags
4736  *   Holds the actions detected until now.
4737  * @param[in] action
4738  *   Pointer to the modify action.
4739  * @param[in] item_flags
4740  *   Holds the items detected.
4741  * @param[out] error
4742  *   Pointer to error structure.
4743  *
4744  * @return
4745  *   0 on success, a negative errno value otherwise and rte_errno is set.
4746  */
4747 static int
4748 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags,
4749 				    const struct rte_flow_action *action,
4750 				    const uint64_t item_flags,
4751 				    struct rte_flow_error *error)
4752 {
4753 	int ret = 0;
4754 	uint64_t layer;
4755 
4756 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4757 	if (!ret) {
4758 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4759 				 MLX5_FLOW_LAYER_INNER_L3_IPV4 :
4760 				 MLX5_FLOW_LAYER_OUTER_L3_IPV4;
4761 		if (!(item_flags & layer))
4762 			return rte_flow_error_set(error, EINVAL,
4763 						  RTE_FLOW_ERROR_TYPE_ACTION,
4764 						  NULL,
4765 						  "no ipv4 item in pattern");
4766 	}
4767 	return ret;
4768 }
4769 
4770 /**
4771  * Validate the modify-header IPv6 address actions.
4772  *
4773  * @param[in] action_flags
4774  *   Holds the actions detected until now.
4775  * @param[in] action
4776  *   Pointer to the modify action.
4777  * @param[in] item_flags
4778  *   Holds the items detected.
4779  * @param[out] error
4780  *   Pointer to error structure.
4781  *
4782  * @return
4783  *   0 on success, a negative errno value otherwise and rte_errno is set.
4784  */
4785 static int
4786 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags,
4787 				    const struct rte_flow_action *action,
4788 				    const uint64_t item_flags,
4789 				    struct rte_flow_error *error)
4790 {
4791 	int ret = 0;
4792 	uint64_t layer;
4793 
4794 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4795 	if (!ret) {
4796 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4797 				 MLX5_FLOW_LAYER_INNER_L3_IPV6 :
4798 				 MLX5_FLOW_LAYER_OUTER_L3_IPV6;
4799 		if (!(item_flags & layer))
4800 			return rte_flow_error_set(error, EINVAL,
4801 						  RTE_FLOW_ERROR_TYPE_ACTION,
4802 						  NULL,
4803 						  "no ipv6 item in pattern");
4804 	}
4805 	return ret;
4806 }
4807 
4808 /**
4809  * Validate the modify-header TP actions.
4810  *
4811  * @param[in] action_flags
4812  *   Holds the actions detected until now.
4813  * @param[in] action
4814  *   Pointer to the modify action.
4815  * @param[in] item_flags
4816  *   Holds the items detected.
4817  * @param[out] error
4818  *   Pointer to error structure.
4819  *
4820  * @return
4821  *   0 on success, a negative errno value otherwise and rte_errno is set.
4822  */
4823 static int
4824 flow_dv_validate_action_modify_tp(const uint64_t action_flags,
4825 				  const struct rte_flow_action *action,
4826 				  const uint64_t item_flags,
4827 				  struct rte_flow_error *error)
4828 {
4829 	int ret = 0;
4830 	uint64_t layer;
4831 
4832 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4833 	if (!ret) {
4834 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4835 				 MLX5_FLOW_LAYER_INNER_L4 :
4836 				 MLX5_FLOW_LAYER_OUTER_L4;
4837 		if (!(item_flags & layer))
4838 			return rte_flow_error_set(error, EINVAL,
4839 						  RTE_FLOW_ERROR_TYPE_ACTION,
4840 						  NULL, "no transport layer "
4841 						  "in pattern");
4842 	}
4843 	return ret;
4844 }
4845 
4846 /**
4847  * Validate the modify-header actions of increment/decrement
4848  * TCP Sequence-number.
4849  *
4850  * @param[in] action_flags
4851  *   Holds the actions detected until now.
4852  * @param[in] action
4853  *   Pointer to the modify action.
4854  * @param[in] item_flags
4855  *   Holds the items detected.
4856  * @param[out] error
4857  *   Pointer to error structure.
4858  *
4859  * @return
4860  *   0 on success, a negative errno value otherwise and rte_errno is set.
4861  */
4862 static int
4863 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags,
4864 				       const struct rte_flow_action *action,
4865 				       const uint64_t item_flags,
4866 				       struct rte_flow_error *error)
4867 {
4868 	int ret = 0;
4869 	uint64_t layer;
4870 
4871 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4872 	if (!ret) {
4873 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4874 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4875 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4876 		if (!(item_flags & layer))
4877 			return rte_flow_error_set(error, EINVAL,
4878 						  RTE_FLOW_ERROR_TYPE_ACTION,
4879 						  NULL, "no TCP item in"
4880 						  " pattern");
4881 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ &&
4882 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) ||
4883 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ &&
4884 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ)))
4885 			return rte_flow_error_set(error, EINVAL,
4886 						  RTE_FLOW_ERROR_TYPE_ACTION,
4887 						  NULL,
4888 						  "cannot decrease and increase"
4889 						  " TCP sequence number"
4890 						  " at the same time");
4891 	}
4892 	return ret;
4893 }
4894 
4895 /**
4896  * Validate the modify-header actions of increment/decrement
4897  * TCP Acknowledgment number.
4898  *
4899  * @param[in] action_flags
4900  *   Holds the actions detected until now.
4901  * @param[in] action
4902  *   Pointer to the modify action.
4903  * @param[in] item_flags
4904  *   Holds the items detected.
4905  * @param[out] error
4906  *   Pointer to error structure.
4907  *
4908  * @return
4909  *   0 on success, a negative errno value otherwise and rte_errno is set.
4910  */
4911 static int
4912 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags,
4913 				       const struct rte_flow_action *action,
4914 				       const uint64_t item_flags,
4915 				       struct rte_flow_error *error)
4916 {
4917 	int ret = 0;
4918 	uint64_t layer;
4919 
4920 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4921 	if (!ret) {
4922 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4923 				 MLX5_FLOW_LAYER_INNER_L4_TCP :
4924 				 MLX5_FLOW_LAYER_OUTER_L4_TCP;
4925 		if (!(item_flags & layer))
4926 			return rte_flow_error_set(error, EINVAL,
4927 						  RTE_FLOW_ERROR_TYPE_ACTION,
4928 						  NULL, "no TCP item in"
4929 						  " pattern");
4930 		if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK &&
4931 			(action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) ||
4932 		    (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK &&
4933 			(action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK)))
4934 			return rte_flow_error_set(error, EINVAL,
4935 						  RTE_FLOW_ERROR_TYPE_ACTION,
4936 						  NULL,
4937 						  "cannot decrease and increase"
4938 						  " TCP acknowledgment number"
4939 						  " at the same time");
4940 	}
4941 	return ret;
4942 }
4943 
4944 /**
4945  * Validate the modify-header TTL actions.
4946  *
4947  * @param[in] action_flags
4948  *   Holds the actions detected until now.
4949  * @param[in] action
4950  *   Pointer to the modify action.
4951  * @param[in] item_flags
4952  *   Holds the items detected.
4953  * @param[out] error
4954  *   Pointer to error structure.
4955  *
4956  * @return
4957  *   0 on success, a negative errno value otherwise and rte_errno is set.
4958  */
4959 static int
4960 flow_dv_validate_action_modify_ttl(const uint64_t action_flags,
4961 				   const struct rte_flow_action *action,
4962 				   const uint64_t item_flags,
4963 				   struct rte_flow_error *error)
4964 {
4965 	int ret = 0;
4966 	uint64_t layer;
4967 
4968 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
4969 	if (!ret) {
4970 		layer = (action_flags & MLX5_FLOW_ACTION_DECAP) ?
4971 				 MLX5_FLOW_LAYER_INNER_L3 :
4972 				 MLX5_FLOW_LAYER_OUTER_L3;
4973 		if (!(item_flags & layer))
4974 			return rte_flow_error_set(error, EINVAL,
4975 						  RTE_FLOW_ERROR_TYPE_ACTION,
4976 						  NULL,
4977 						  "no IP protocol in pattern");
4978 	}
4979 	return ret;
4980 }
4981 
4982 /**
4983  * Validate the generic modify field actions.
4984  * @param[in] dev
4985  *   Pointer to the rte_eth_dev structure.
4986  * @param[in] action_flags
4987  *   Holds the actions detected until now.
4988  * @param[in] action
4989  *   Pointer to the modify action.
4990  * @param[in] attr
4991  *   Pointer to the flow attributes.
4992  * @param root
4993  *   Whether action is on root table.
4994  * @param[out] error
4995  *   Pointer to error structure.
4996  *
4997  * @return
4998  *   Number of header fields to modify (0 or more) on success,
4999  *   a negative errno value otherwise and rte_errno is set.
5000  */
5001 static int
5002 flow_dv_validate_action_modify_field(struct rte_eth_dev *dev,
5003 				   const uint64_t action_flags,
5004 				   const struct rte_flow_action *action,
5005 				   const struct rte_flow_attr *attr,
5006 				   bool root,
5007 				   struct rte_flow_error *error)
5008 {
5009 	int ret = 0;
5010 	struct mlx5_priv *priv = dev->data->dev_private;
5011 	struct mlx5_sh_config *config = &priv->sh->config;
5012 	struct mlx5_hca_attr *hca_attr = &priv->sh->cdev->config.hca_attr;
5013 	const struct rte_flow_action_modify_field *action_modify_field =
5014 		action->conf;
5015 	uint32_t dst_width = mlx5_flow_item_field_width(dev,
5016 				action_modify_field->dst.field,
5017 				-1, attr, error);
5018 	uint32_t src_width = mlx5_flow_item_field_width(dev,
5019 				action_modify_field->src.field,
5020 				dst_width, attr, error);
5021 
5022 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5023 	if (ret)
5024 		return ret;
5025 
5026 	if (action_modify_field->width == 0)
5027 		return rte_flow_error_set(error, EINVAL,
5028 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5029 				"no bits are requested to be modified");
5030 	else if (action_modify_field->width > dst_width ||
5031 		 action_modify_field->width > src_width)
5032 		return rte_flow_error_set(error, EINVAL,
5033 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5034 				"cannot modify more bits than"
5035 				" the width of a field");
5036 	if (action_modify_field->dst.field != RTE_FLOW_FIELD_VALUE &&
5037 	    action_modify_field->dst.field != RTE_FLOW_FIELD_POINTER) {
5038 		if (action_modify_field->dst.offset +
5039 		    action_modify_field->width > dst_width)
5040 			return rte_flow_error_set(error, EINVAL,
5041 					RTE_FLOW_ERROR_TYPE_ACTION, action,
5042 					"destination offset is too big");
5043 		if (action_modify_field->dst.level &&
5044 		    action_modify_field->dst.field != RTE_FLOW_FIELD_TAG)
5045 			return rte_flow_error_set(error, ENOTSUP,
5046 					RTE_FLOW_ERROR_TYPE_ACTION, action,
5047 					"inner header fields modification"
5048 					" is not supported");
5049 	}
5050 	if (action_modify_field->src.field != RTE_FLOW_FIELD_VALUE &&
5051 	    action_modify_field->src.field != RTE_FLOW_FIELD_POINTER) {
5052 		if (root)
5053 			return rte_flow_error_set(error, ENOTSUP,
5054 					RTE_FLOW_ERROR_TYPE_ACTION, action,
5055 					"modify field action is not"
5056 					" supported for group 0");
5057 		if (action_modify_field->src.offset +
5058 		    action_modify_field->width > src_width)
5059 			return rte_flow_error_set(error, EINVAL,
5060 					RTE_FLOW_ERROR_TYPE_ACTION, action,
5061 					"source offset is too big");
5062 		if (action_modify_field->src.level &&
5063 		    action_modify_field->src.field != RTE_FLOW_FIELD_TAG)
5064 			return rte_flow_error_set(error, ENOTSUP,
5065 					RTE_FLOW_ERROR_TYPE_ACTION, action,
5066 					"inner header fields modification"
5067 					" is not supported");
5068 	}
5069 	if ((action_modify_field->dst.field ==
5070 	     action_modify_field->src.field) &&
5071 	    (action_modify_field->dst.level ==
5072 	     action_modify_field->src.level))
5073 		return rte_flow_error_set(error, EINVAL,
5074 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5075 				"source and destination fields"
5076 				" cannot be the same");
5077 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VALUE ||
5078 	    action_modify_field->dst.field == RTE_FLOW_FIELD_POINTER ||
5079 	    action_modify_field->dst.field == RTE_FLOW_FIELD_MARK)
5080 		return rte_flow_error_set(error, EINVAL,
5081 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5082 				"mark, immediate value or a pointer to it"
5083 				" cannot be used as a destination");
5084 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_START ||
5085 	    action_modify_field->src.field == RTE_FLOW_FIELD_START)
5086 		return rte_flow_error_set(error, ENOTSUP,
5087 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5088 				"modifications of an arbitrary"
5089 				" place in a packet is not supported");
5090 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VLAN_TYPE ||
5091 	    action_modify_field->src.field == RTE_FLOW_FIELD_VLAN_TYPE)
5092 		return rte_flow_error_set(error, ENOTSUP,
5093 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5094 				"modifications of the 802.1Q Tag"
5095 				" Identifier is not supported");
5096 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_VXLAN_VNI ||
5097 	    action_modify_field->src.field == RTE_FLOW_FIELD_VXLAN_VNI)
5098 		return rte_flow_error_set(error, ENOTSUP,
5099 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5100 				"modifications of the VXLAN Network"
5101 				" Identifier is not supported");
5102 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_GENEVE_VNI ||
5103 	    action_modify_field->src.field == RTE_FLOW_FIELD_GENEVE_VNI)
5104 		return rte_flow_error_set(error, ENOTSUP,
5105 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5106 				"modifications of the GENEVE Network"
5107 				" Identifier is not supported");
5108 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_MARK ||
5109 	    action_modify_field->src.field == RTE_FLOW_FIELD_MARK)
5110 		if (config->dv_xmeta_en == MLX5_XMETA_MODE_LEGACY ||
5111 		    !mlx5_flow_ext_mreg_supported(dev))
5112 			return rte_flow_error_set(error, ENOTSUP,
5113 					RTE_FLOW_ERROR_TYPE_ACTION, action,
5114 					"cannot modify mark in legacy mode"
5115 					" or without extensive registers");
5116 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_META ||
5117 	    action_modify_field->src.field == RTE_FLOW_FIELD_META) {
5118 		if (config->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
5119 		    !mlx5_flow_ext_mreg_supported(dev))
5120 			return rte_flow_error_set(error, ENOTSUP,
5121 					RTE_FLOW_ERROR_TYPE_ACTION, action,
5122 					"cannot modify meta without"
5123 					" extensive registers support");
5124 		ret = flow_dv_get_metadata_reg(dev, attr, error);
5125 		if (ret < 0 || ret == REG_NON)
5126 			return rte_flow_error_set(error, ENOTSUP,
5127 					RTE_FLOW_ERROR_TYPE_ACTION, action,
5128 					"cannot modify meta without"
5129 					" extensive registers available");
5130 	}
5131 	if (action_modify_field->operation == RTE_FLOW_MODIFY_SUB)
5132 		return rte_flow_error_set(error, ENOTSUP,
5133 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5134 				"sub operations are not supported");
5135 	if (action_modify_field->dst.field == RTE_FLOW_FIELD_IPV4_ECN ||
5136 	    action_modify_field->src.field == RTE_FLOW_FIELD_IPV4_ECN ||
5137 	    action_modify_field->dst.field == RTE_FLOW_FIELD_IPV6_ECN ||
5138 	    action_modify_field->src.field == RTE_FLOW_FIELD_IPV6_ECN)
5139 		if (!hca_attr->modify_outer_ip_ecn && root)
5140 			return rte_flow_error_set(error, ENOTSUP,
5141 				RTE_FLOW_ERROR_TYPE_ACTION, action,
5142 				"modifications of the ECN for current firmware is not supported");
5143 	return (action_modify_field->width / 32) +
5144 	       !!(action_modify_field->width % 32);
5145 }
5146 
5147 /**
5148  * Validate jump action.
5149  *
5150  * @param[in] action
5151  *   Pointer to the jump action.
5152  * @param[in] action_flags
5153  *   Holds the actions detected until now.
5154  * @param[in] attributes
5155  *   Pointer to flow attributes
5156  * @param[in] external
5157  *   Action belongs to flow rule created by request external to PMD.
5158  * @param[out] error
5159  *   Pointer to error structure.
5160  *
5161  * @return
5162  *   0 on success, a negative errno value otherwise and rte_errno is set.
5163  */
5164 static int
5165 flow_dv_validate_action_jump(struct rte_eth_dev *dev,
5166 			     const struct mlx5_flow_tunnel *tunnel,
5167 			     const struct rte_flow_action *action,
5168 			     uint64_t action_flags,
5169 			     const struct rte_flow_attr *attributes,
5170 			     bool external, struct rte_flow_error *error)
5171 {
5172 	uint32_t target_group, table = 0;
5173 	struct mlx5_priv *priv = dev->data->dev_private;
5174 	int ret = 0;
5175 	struct flow_grp_info grp_info = {
5176 		.external = !!external,
5177 		.transfer = !!attributes->transfer,
5178 		.fdb_def_rule = !!priv->fdb_def_rule,
5179 		.std_tbl_fix = 0
5180 	};
5181 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
5182 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
5183 		return rte_flow_error_set(error, EINVAL,
5184 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5185 					  "can't have 2 fate actions in"
5186 					  " same flow");
5187 	if (!action->conf)
5188 		return rte_flow_error_set(error, EINVAL,
5189 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5190 					  NULL, "action configuration not set");
5191 	target_group =
5192 		((const struct rte_flow_action_jump *)action->conf)->group;
5193 	ret = mlx5_flow_group_to_table(dev, tunnel, target_group, &table,
5194 				       &grp_info, error);
5195 	if (ret)
5196 		return ret;
5197 	if (attributes->group == target_group &&
5198 	    !(action_flags & (MLX5_FLOW_ACTION_TUNNEL_SET |
5199 			      MLX5_FLOW_ACTION_TUNNEL_MATCH)))
5200 		return rte_flow_error_set(error, EINVAL,
5201 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5202 					  "target group must be other than"
5203 					  " the current flow group");
5204 	if (table == 0)
5205 		return rte_flow_error_set(error, EINVAL,
5206 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5207 					  NULL, "root table shouldn't be destination");
5208 	return 0;
5209 }
5210 
5211 /*
5212  * Validate action PORT_ID / REPRESENTED_PORT.
5213  *
5214  * @param[in] dev
5215  *   Pointer to rte_eth_dev structure.
5216  * @param[in] action_flags
5217  *   Bit-fields that holds the actions detected until now.
5218  * @param[in] action
5219  *   PORT_ID / REPRESENTED_PORT action structure.
5220  * @param[in] attr
5221  *   Attributes of flow that includes this action.
5222  * @param[out] error
5223  *   Pointer to error structure.
5224  *
5225  * @return
5226  *   0 on success, a negative errno value otherwise and rte_errno is set.
5227  */
5228 static int
5229 flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
5230 				uint64_t action_flags,
5231 				const struct rte_flow_action *action,
5232 				const struct rte_flow_attr *attr,
5233 				struct rte_flow_error *error)
5234 {
5235 	const struct rte_flow_action_port_id *port_id;
5236 	const struct rte_flow_action_ethdev *ethdev;
5237 	struct mlx5_priv *act_priv;
5238 	struct mlx5_priv *dev_priv;
5239 	uint16_t port;
5240 
5241 	if (!attr->transfer)
5242 		return rte_flow_error_set(error, ENOTSUP,
5243 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5244 					  NULL,
5245 					  "port action is valid in transfer"
5246 					  " mode only");
5247 	if (!action || !action->conf)
5248 		return rte_flow_error_set(error, ENOTSUP,
5249 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
5250 					  NULL,
5251 					  "port action parameters must be"
5252 					  " specified");
5253 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
5254 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
5255 		return rte_flow_error_set(error, EINVAL,
5256 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5257 					  "can have only one fate actions in"
5258 					  " a flow");
5259 	dev_priv = mlx5_dev_to_eswitch_info(dev);
5260 	if (!dev_priv)
5261 		return rte_flow_error_set(error, rte_errno,
5262 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5263 					  NULL,
5264 					  "failed to obtain E-Switch info");
5265 	switch (action->type) {
5266 	case RTE_FLOW_ACTION_TYPE_PORT_ID:
5267 		port_id = action->conf;
5268 		port = port_id->original ? dev->data->port_id : port_id->id;
5269 		break;
5270 	case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
5271 		ethdev = action->conf;
5272 		port = ethdev->port_id;
5273 		break;
5274 	default:
5275 		MLX5_ASSERT(false);
5276 		return rte_flow_error_set
5277 				(error, EINVAL,
5278 				 RTE_FLOW_ERROR_TYPE_ACTION, action,
5279 				 "unknown E-Switch action");
5280 	}
5281 	act_priv = mlx5_port_to_eswitch_info(port, false);
5282 	if (!act_priv)
5283 		return rte_flow_error_set
5284 				(error, rte_errno,
5285 				 RTE_FLOW_ERROR_TYPE_ACTION_CONF, action->conf,
5286 				 "failed to obtain E-Switch port id for port");
5287 	if (act_priv->domain_id != dev_priv->domain_id)
5288 		return rte_flow_error_set
5289 				(error, EINVAL,
5290 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5291 				 "port does not belong to"
5292 				 " E-Switch being configured");
5293 	return 0;
5294 }
5295 
5296 /**
5297  * Get the maximum number of modify header actions.
5298  *
5299  * @param dev
5300  *   Pointer to rte_eth_dev structure.
5301  * @param root
5302  *   Whether action is on root table.
5303  *
5304  * @return
5305  *   Max number of modify header actions device can support.
5306  */
5307 static inline unsigned int
5308 flow_dv_modify_hdr_action_max(struct rte_eth_dev *dev __rte_unused,
5309 			      bool root)
5310 {
5311 	/*
5312 	 * There's no way to directly query the max capacity from FW.
5313 	 * The maximal value on root table should be assumed to be supported.
5314 	 */
5315 	if (!root)
5316 		return MLX5_MAX_MODIFY_NUM;
5317 	else
5318 		return MLX5_ROOT_TBL_MODIFY_NUM;
5319 }
5320 
5321 /**
5322  * Validate the meter action.
5323  *
5324  * @param[in] dev
5325  *   Pointer to rte_eth_dev structure.
5326  * @param[in] action_flags
5327  *   Bit-fields that holds the actions detected until now.
5328  * @param[in] item_flags
5329  *   Holds the items detected.
5330  * @param[in] action
5331  *   Pointer to the meter action.
5332  * @param[in] attr
5333  *   Attributes of flow that includes this action.
5334  * @param[in] port_id_item
5335  *   Pointer to item indicating port id.
5336  * @param[out] error
5337  *   Pointer to error structure.
5338  *
5339  * @return
5340  *   0 on success, a negative errno value otherwise and rte_errno is set.
5341  */
5342 static int
5343 mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
5344 				uint64_t action_flags, uint64_t item_flags,
5345 				const struct rte_flow_action *action,
5346 				const struct rte_flow_attr *attr,
5347 				const struct rte_flow_item *port_id_item,
5348 				bool *def_policy,
5349 				struct rte_flow_error *error)
5350 {
5351 	struct mlx5_priv *priv = dev->data->dev_private;
5352 	const struct rte_flow_action_meter *am = action->conf;
5353 	struct mlx5_flow_meter_info *fm;
5354 	struct mlx5_flow_meter_policy *mtr_policy;
5355 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
5356 	uint16_t flow_src_port = priv->representor_id;
5357 	bool all_ports = false;
5358 
5359 	if (!am)
5360 		return rte_flow_error_set(error, EINVAL,
5361 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5362 					  "meter action conf is NULL");
5363 
5364 	if (action_flags & MLX5_FLOW_ACTION_METER)
5365 		return rte_flow_error_set(error, ENOTSUP,
5366 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5367 					  "meter chaining not support");
5368 	if (action_flags & MLX5_FLOW_ACTION_JUMP)
5369 		return rte_flow_error_set(error, ENOTSUP,
5370 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5371 					  "meter with jump not support");
5372 	if (!priv->mtr_en)
5373 		return rte_flow_error_set(error, ENOTSUP,
5374 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5375 					  NULL,
5376 					  "meter action not supported");
5377 	fm = mlx5_flow_meter_find(priv, am->mtr_id, NULL);
5378 	if (!fm)
5379 		return rte_flow_error_set(error, EINVAL,
5380 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5381 					  "Meter not found");
5382 	/* aso meter can always be shared by different domains */
5383 	if (fm->ref_cnt && !priv->sh->meter_aso_en &&
5384 	    !(fm->transfer == attr->transfer ||
5385 	      (!fm->ingress && !attr->ingress && attr->egress) ||
5386 	      (!fm->egress && !attr->egress && attr->ingress)))
5387 		return rte_flow_error_set(error, EINVAL,
5388 			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5389 			"Flow attributes domain are either invalid "
5390 			"or have a domain conflict with current "
5391 			"meter attributes");
5392 	if (fm->def_policy) {
5393 		if (!((attr->transfer &&
5394 			mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
5395 			(attr->egress &&
5396 			mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
5397 			(attr->ingress &&
5398 			mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
5399 			return rte_flow_error_set(error, EINVAL,
5400 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5401 					  "Flow attributes domain "
5402 					  "have a conflict with current "
5403 					  "meter domain attributes");
5404 		*def_policy = true;
5405 	} else {
5406 		mtr_policy = mlx5_flow_meter_policy_find(dev,
5407 						fm->policy_id, NULL);
5408 		if (!mtr_policy)
5409 			return rte_flow_error_set(error, EINVAL,
5410 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5411 					  "Invalid policy id for meter ");
5412 		if (!((attr->transfer && mtr_policy->transfer) ||
5413 			(attr->egress && mtr_policy->egress) ||
5414 			(attr->ingress && mtr_policy->ingress)))
5415 			return rte_flow_error_set(error, EINVAL,
5416 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5417 					  "Flow attributes domain "
5418 					  "have a conflict with current "
5419 					  "meter domain attributes");
5420 		if (port_id_item) {
5421 			if (mlx5_flow_get_item_vport_id(dev, port_id_item, &flow_src_port,
5422 							&all_ports, error))
5423 				return -rte_errno;
5424 		}
5425 		if (attr->transfer) {
5426 			/* When flow matching all src ports, meter should not have drop count. */
5427 			if (all_ports && (fm->drop_cnt || mtr_policy->hierarchy_match_port))
5428 				return rte_flow_error_set(error, EINVAL,
5429 							  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, NULL,
5430 							  "Meter drop count or "
5431 							  "modify_field/set_tag in meter hierarchy "
5432 							  "not supported when matching all ports.");
5433 		} else if (mtr_policy->is_rss) {
5434 			struct mlx5_flow_meter_policy *fp;
5435 			struct mlx5_meter_policy_action_container *acg;
5436 			struct mlx5_meter_policy_action_container *acy;
5437 			const struct rte_flow_action *rss_act;
5438 			int ret;
5439 
5440 			fp = mlx5_flow_meter_hierarchy_get_final_policy(dev,
5441 								mtr_policy);
5442 			if (fp == NULL)
5443 				return rte_flow_error_set(error, EINVAL,
5444 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5445 						  "Unable to get the final "
5446 						  "policy in the hierarchy");
5447 			acg = &fp->act_cnt[RTE_COLOR_GREEN];
5448 			acy = &fp->act_cnt[RTE_COLOR_YELLOW];
5449 			MLX5_ASSERT(acg->fate_action ==
5450 				    MLX5_FLOW_FATE_SHARED_RSS ||
5451 				    acy->fate_action ==
5452 				    MLX5_FLOW_FATE_SHARED_RSS);
5453 			if (acg->fate_action == MLX5_FLOW_FATE_SHARED_RSS)
5454 				rss_act = acg->rss;
5455 			else
5456 				rss_act = acy->rss;
5457 			ret = mlx5_flow_validate_action_rss(rss_act,
5458 					action_flags, dev, attr,
5459 					item_flags, error);
5460 			if (ret)
5461 				return ret;
5462 		}
5463 		*def_policy = false;
5464 	}
5465 	return 0;
5466 }
5467 
5468 /**
5469  * Validate the age action.
5470  *
5471  * @param[in] action_flags
5472  *   Holds the actions detected until now.
5473  * @param[in] action
5474  *   Pointer to the age action.
5475  * @param[in] dev
5476  *   Pointer to the Ethernet device structure.
5477  * @param[out] error
5478  *   Pointer to error structure.
5479  *
5480  * @return
5481  *   0 on success, a negative errno value otherwise and rte_errno is set.
5482  */
5483 static int
5484 flow_dv_validate_action_age(uint64_t action_flags,
5485 			    const struct rte_flow_action *action,
5486 			    struct rte_eth_dev *dev,
5487 			    struct rte_flow_error *error)
5488 {
5489 	struct mlx5_priv *priv = dev->data->dev_private;
5490 	const struct rte_flow_action_age *age = action->conf;
5491 
5492 	if (!priv->sh->cdev->config.devx ||
5493 	    (priv->sh->sws_cmng.counter_fallback && !priv->sh->aso_age_mng))
5494 		return rte_flow_error_set(error, ENOTSUP,
5495 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5496 					  NULL,
5497 					  "age action not supported");
5498 	if (!(action->conf))
5499 		return rte_flow_error_set(error, EINVAL,
5500 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5501 					  "configuration cannot be null");
5502 	if (!(age->timeout))
5503 		return rte_flow_error_set(error, EINVAL,
5504 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5505 					  "invalid timeout value 0");
5506 	if (action_flags & MLX5_FLOW_ACTION_AGE)
5507 		return rte_flow_error_set(error, EINVAL,
5508 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5509 					  "duplicate age actions set");
5510 	return 0;
5511 }
5512 
5513 /**
5514  * Validate the modify-header IPv4 DSCP actions.
5515  *
5516  * @param[in] action_flags
5517  *   Holds the actions detected until now.
5518  * @param[in] action
5519  *   Pointer to the modify action.
5520  * @param[in] item_flags
5521  *   Holds the items detected.
5522  * @param[out] error
5523  *   Pointer to error structure.
5524  *
5525  * @return
5526  *   0 on success, a negative errno value otherwise and rte_errno is set.
5527  */
5528 static int
5529 flow_dv_validate_action_modify_ipv4_dscp(const uint64_t action_flags,
5530 					 const struct rte_flow_action *action,
5531 					 const uint64_t item_flags,
5532 					 struct rte_flow_error *error)
5533 {
5534 	int ret = 0;
5535 
5536 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5537 	if (!ret) {
5538 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4))
5539 			return rte_flow_error_set(error, EINVAL,
5540 						  RTE_FLOW_ERROR_TYPE_ACTION,
5541 						  NULL,
5542 						  "no ipv4 item in pattern");
5543 	}
5544 	return ret;
5545 }
5546 
5547 /**
5548  * Validate the modify-header IPv6 DSCP actions.
5549  *
5550  * @param[in] action_flags
5551  *   Holds the actions detected until now.
5552  * @param[in] action
5553  *   Pointer to the modify action.
5554  * @param[in] item_flags
5555  *   Holds the items detected.
5556  * @param[out] error
5557  *   Pointer to error structure.
5558  *
5559  * @return
5560  *   0 on success, a negative errno value otherwise and rte_errno is set.
5561  */
5562 static int
5563 flow_dv_validate_action_modify_ipv6_dscp(const uint64_t action_flags,
5564 					 const struct rte_flow_action *action,
5565 					 const uint64_t item_flags,
5566 					 struct rte_flow_error *error)
5567 {
5568 	int ret = 0;
5569 
5570 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
5571 	if (!ret) {
5572 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6))
5573 			return rte_flow_error_set(error, EINVAL,
5574 						  RTE_FLOW_ERROR_TYPE_ACTION,
5575 						  NULL,
5576 						  "no ipv6 item in pattern");
5577 	}
5578 	return ret;
5579 }
5580 
5581 int
5582 flow_dv_modify_match_cb(void *tool_ctx __rte_unused,
5583 			struct mlx5_list_entry *entry, void *cb_ctx)
5584 {
5585 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5586 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5587 	struct mlx5_flow_dv_modify_hdr_resource *resource =
5588 				  container_of(entry, typeof(*resource), entry);
5589 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5590 
5591 	key_len += ref->actions_num * sizeof(ref->actions[0]);
5592 	return ref->actions_num != resource->actions_num ||
5593 	       memcmp(&ref->ft_type, &resource->ft_type, key_len);
5594 }
5595 
5596 static struct mlx5_indexed_pool *
5597 flow_dv_modify_ipool_get(struct mlx5_dev_ctx_shared *sh, uint8_t index)
5598 {
5599 	struct mlx5_indexed_pool *ipool = __atomic_load_n
5600 				     (&sh->mdh_ipools[index], __ATOMIC_SEQ_CST);
5601 
5602 	if (!ipool) {
5603 		struct mlx5_indexed_pool *expected = NULL;
5604 		struct mlx5_indexed_pool_config cfg =
5605 		    (struct mlx5_indexed_pool_config) {
5606 		       .size = sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
5607 								   (index + 1) *
5608 					   sizeof(struct mlx5_modification_cmd),
5609 		       .trunk_size = 64,
5610 		       .grow_trunk = 3,
5611 		       .grow_shift = 2,
5612 		       .need_lock = 1,
5613 		       .release_mem_en = !!sh->config.reclaim_mode,
5614 		       .per_core_cache =
5615 				       sh->config.reclaim_mode ? 0 : (1 << 16),
5616 		       .malloc = mlx5_malloc,
5617 		       .free = mlx5_free,
5618 		       .type = "mlx5_modify_action_resource",
5619 		};
5620 
5621 		cfg.size = RTE_ALIGN(cfg.size, sizeof(ipool));
5622 		ipool = mlx5_ipool_create(&cfg);
5623 		if (!ipool)
5624 			return NULL;
5625 		if (!__atomic_compare_exchange_n(&sh->mdh_ipools[index],
5626 						 &expected, ipool, false,
5627 						 __ATOMIC_SEQ_CST,
5628 						 __ATOMIC_SEQ_CST)) {
5629 			mlx5_ipool_destroy(ipool);
5630 			ipool = __atomic_load_n(&sh->mdh_ipools[index],
5631 						__ATOMIC_SEQ_CST);
5632 		}
5633 	}
5634 	return ipool;
5635 }
5636 
5637 struct mlx5_list_entry *
5638 flow_dv_modify_create_cb(void *tool_ctx, void *cb_ctx)
5639 {
5640 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5641 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5642 	struct mlx5dv_dr_domain *ns;
5643 	struct mlx5_flow_dv_modify_hdr_resource *entry;
5644 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5645 	struct mlx5_indexed_pool *ipool = flow_dv_modify_ipool_get(sh,
5646 							  ref->actions_num - 1);
5647 	int ret;
5648 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5649 	uint32_t key_len = sizeof(*ref) - offsetof(typeof(*ref), ft_type);
5650 	uint32_t idx;
5651 
5652 	if (unlikely(!ipool)) {
5653 		rte_flow_error_set(ctx->error, ENOMEM,
5654 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5655 				   NULL, "cannot allocate modify ipool");
5656 		return NULL;
5657 	}
5658 	entry = mlx5_ipool_zmalloc(ipool, &idx);
5659 	if (!entry) {
5660 		rte_flow_error_set(ctx->error, ENOMEM,
5661 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5662 				   "cannot allocate resource memory");
5663 		return NULL;
5664 	}
5665 	rte_memcpy(&entry->ft_type,
5666 		   RTE_PTR_ADD(ref, offsetof(typeof(*ref), ft_type)),
5667 		   key_len + data_len);
5668 	if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
5669 		ns = sh->fdb_domain;
5670 	else if (entry->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
5671 		ns = sh->tx_domain;
5672 	else
5673 		ns = sh->rx_domain;
5674 	ret = mlx5_flow_os_create_flow_action_modify_header
5675 					(sh->cdev->ctx, ns, entry,
5676 					 data_len, &entry->action);
5677 	if (ret) {
5678 		mlx5_ipool_free(sh->mdh_ipools[ref->actions_num - 1], idx);
5679 		rte_flow_error_set(ctx->error, ENOMEM,
5680 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5681 				   NULL, "cannot create modification action");
5682 		return NULL;
5683 	}
5684 	entry->idx = idx;
5685 	return &entry->entry;
5686 }
5687 
5688 struct mlx5_list_entry *
5689 flow_dv_modify_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
5690 			void *cb_ctx)
5691 {
5692 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5693 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
5694 	struct mlx5_flow_dv_modify_hdr_resource *entry;
5695 	struct mlx5_flow_dv_modify_hdr_resource *ref = ctx->data;
5696 	uint32_t data_len = ref->actions_num * sizeof(ref->actions[0]);
5697 	uint32_t idx;
5698 
5699 	entry = mlx5_ipool_malloc(sh->mdh_ipools[ref->actions_num - 1],
5700 				  &idx);
5701 	if (!entry) {
5702 		rte_flow_error_set(ctx->error, ENOMEM,
5703 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5704 				   "cannot allocate resource memory");
5705 		return NULL;
5706 	}
5707 	memcpy(entry, oentry, sizeof(*entry) + data_len);
5708 	entry->idx = idx;
5709 	return &entry->entry;
5710 }
5711 
5712 void
5713 flow_dv_modify_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
5714 {
5715 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
5716 	struct mlx5_flow_dv_modify_hdr_resource *res =
5717 		container_of(entry, typeof(*res), entry);
5718 
5719 	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
5720 }
5721 
5722 /**
5723  * Validate the sample action.
5724  *
5725  * @param[in, out] action_flags
5726  *   Holds the actions detected until now.
5727  * @param[in] action
5728  *   Pointer to the sample action.
5729  * @param[in] dev
5730  *   Pointer to the Ethernet device structure.
5731  * @param[in] attr
5732  *   Attributes of flow that includes this action.
5733  * @param[in] item_flags
5734  *   Holds the items detected.
5735  * @param[in] rss
5736  *   Pointer to the RSS action.
5737  * @param[out] sample_rss
5738  *   Pointer to the RSS action in sample action list.
5739  * @param[out] count
5740  *   Pointer to the COUNT action in sample action list.
5741  * @param[out] fdb_mirror
5742  *   Pointer to the FDB mirror flag.
5743  * @param root
5744  *   Whether action is on root table.
5745  * @param[out] error
5746  *   Pointer to error structure.
5747  *
5748  * @return
5749  *   0 on success, a negative errno value otherwise and rte_errno is set.
5750  */
5751 static int
5752 flow_dv_validate_action_sample(uint64_t *action_flags,
5753 			       const struct rte_flow_action *action,
5754 			       struct rte_eth_dev *dev,
5755 			       const struct rte_flow_attr *attr,
5756 			       uint64_t item_flags,
5757 			       const struct rte_flow_action_rss *rss,
5758 			       const struct rte_flow_action_rss **sample_rss,
5759 			       const struct rte_flow_action_count **count,
5760 			       int *fdb_mirror,
5761 			       bool root,
5762 			       struct rte_flow_error *error)
5763 {
5764 	struct mlx5_priv *priv = dev->data->dev_private;
5765 	struct mlx5_sh_config *dev_conf = &priv->sh->config;
5766 	const struct rte_flow_action_sample *sample = action->conf;
5767 	const struct rte_flow_action *act;
5768 	uint64_t sub_action_flags = 0;
5769 	uint16_t queue_index = 0xFFFF;
5770 	int actions_n = 0;
5771 	int ret;
5772 
5773 	if (!sample)
5774 		return rte_flow_error_set(error, EINVAL,
5775 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5776 					  "configuration cannot be NULL");
5777 	if (sample->ratio == 0)
5778 		return rte_flow_error_set(error, EINVAL,
5779 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5780 					  "ratio value starts from 1");
5781 	if (!priv->sh->cdev->config.devx ||
5782 	    (sample->ratio > 0 && !priv->sampler_en))
5783 		return rte_flow_error_set(error, ENOTSUP,
5784 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5785 					  NULL,
5786 					  "sample action not supported");
5787 	if (*action_flags & MLX5_FLOW_ACTION_SAMPLE)
5788 		return rte_flow_error_set(error, EINVAL,
5789 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
5790 					  "Multiple sample actions not "
5791 					  "supported");
5792 	if (*action_flags & MLX5_FLOW_ACTION_METER)
5793 		return rte_flow_error_set(error, EINVAL,
5794 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5795 					  "wrong action order, meter should "
5796 					  "be after sample action");
5797 	if (*action_flags & MLX5_FLOW_ACTION_JUMP)
5798 		return rte_flow_error_set(error, EINVAL,
5799 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5800 					  "wrong action order, jump should "
5801 					  "be after sample action");
5802 	if (*action_flags & MLX5_FLOW_ACTION_CT)
5803 		return rte_flow_error_set(error, EINVAL,
5804 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
5805 					  "Sample after CT not supported");
5806 	act = sample->actions;
5807 	for (; act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
5808 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
5809 			return rte_flow_error_set(error, ENOTSUP,
5810 						  RTE_FLOW_ERROR_TYPE_ACTION,
5811 						  act, "too many actions");
5812 		switch (act->type) {
5813 		case RTE_FLOW_ACTION_TYPE_QUEUE:
5814 			ret = mlx5_flow_validate_action_queue(act,
5815 							      sub_action_flags,
5816 							      dev,
5817 							      attr, error);
5818 			if (ret < 0)
5819 				return ret;
5820 			queue_index = ((const struct rte_flow_action_queue *)
5821 							(act->conf))->index;
5822 			sub_action_flags |= MLX5_FLOW_ACTION_QUEUE;
5823 			++actions_n;
5824 			break;
5825 		case RTE_FLOW_ACTION_TYPE_RSS:
5826 			*sample_rss = act->conf;
5827 			ret = mlx5_flow_validate_action_rss(act,
5828 							    sub_action_flags,
5829 							    dev, attr,
5830 							    item_flags,
5831 							    error);
5832 			if (ret < 0)
5833 				return ret;
5834 			if (rss && *sample_rss &&
5835 			    ((*sample_rss)->level != rss->level ||
5836 			    (*sample_rss)->types != rss->types))
5837 				return rte_flow_error_set(error, ENOTSUP,
5838 					RTE_FLOW_ERROR_TYPE_ACTION,
5839 					NULL,
5840 					"Can't use the different RSS types "
5841 					"or level in the same flow");
5842 			if (*sample_rss != NULL && (*sample_rss)->queue_num)
5843 				queue_index = (*sample_rss)->queue[0];
5844 			sub_action_flags |= MLX5_FLOW_ACTION_RSS;
5845 			++actions_n;
5846 			break;
5847 		case RTE_FLOW_ACTION_TYPE_MARK:
5848 			ret = flow_dv_validate_action_mark(dev, act,
5849 							   sub_action_flags,
5850 							   attr, error);
5851 			if (ret < 0)
5852 				return ret;
5853 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)
5854 				sub_action_flags |= MLX5_FLOW_ACTION_MARK |
5855 						MLX5_FLOW_ACTION_MARK_EXT;
5856 			else
5857 				sub_action_flags |= MLX5_FLOW_ACTION_MARK;
5858 			++actions_n;
5859 			break;
5860 		case RTE_FLOW_ACTION_TYPE_COUNT:
5861 			ret = flow_dv_validate_action_count
5862 				(dev, false, *action_flags | sub_action_flags,
5863 				 root, error);
5864 			if (ret < 0)
5865 				return ret;
5866 			*count = act->conf;
5867 			sub_action_flags |= MLX5_FLOW_ACTION_COUNT;
5868 			*action_flags |= MLX5_FLOW_ACTION_COUNT;
5869 			++actions_n;
5870 			break;
5871 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
5872 		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
5873 			ret = flow_dv_validate_action_port_id(dev,
5874 							      sub_action_flags,
5875 							      act,
5876 							      attr,
5877 							      error);
5878 			if (ret)
5879 				return ret;
5880 			sub_action_flags |= MLX5_FLOW_ACTION_PORT_ID;
5881 			++actions_n;
5882 			break;
5883 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
5884 			ret = flow_dv_validate_action_raw_encap_decap
5885 				(dev, NULL, act->conf, attr, &sub_action_flags,
5886 				 &actions_n, action, item_flags, error);
5887 			if (ret < 0)
5888 				return ret;
5889 			++actions_n;
5890 			break;
5891 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5892 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
5893 			ret = flow_dv_validate_action_l2_encap(dev,
5894 							       sub_action_flags,
5895 							       act, attr,
5896 							       error);
5897 			if (ret < 0)
5898 				return ret;
5899 			sub_action_flags |= MLX5_FLOW_ACTION_ENCAP;
5900 			++actions_n;
5901 			break;
5902 		default:
5903 			return rte_flow_error_set(error, ENOTSUP,
5904 						  RTE_FLOW_ERROR_TYPE_ACTION,
5905 						  NULL,
5906 						  "Doesn't support optional "
5907 						  "action");
5908 		}
5909 	}
5910 	if (attr->ingress) {
5911 		if (!(sub_action_flags & (MLX5_FLOW_ACTION_QUEUE |
5912 					  MLX5_FLOW_ACTION_RSS)))
5913 			return rte_flow_error_set(error, EINVAL,
5914 						  RTE_FLOW_ERROR_TYPE_ACTION,
5915 						  NULL,
5916 						  "Ingress must has a dest "
5917 						  "QUEUE for Sample");
5918 	} else if (attr->egress) {
5919 		return rte_flow_error_set(error, ENOTSUP,
5920 					  RTE_FLOW_ERROR_TYPE_ACTION,
5921 					  NULL,
5922 					  "Sample Only support Ingress "
5923 					  "or E-Switch");
5924 	} else if (sample->actions->type != RTE_FLOW_ACTION_TYPE_END) {
5925 		MLX5_ASSERT(attr->transfer);
5926 		if (sample->ratio > 1)
5927 			return rte_flow_error_set(error, ENOTSUP,
5928 						  RTE_FLOW_ERROR_TYPE_ACTION,
5929 						  NULL,
5930 						  "E-Switch doesn't support "
5931 						  "any optional action "
5932 						  "for sampling");
5933 		if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE)
5934 			return rte_flow_error_set(error, ENOTSUP,
5935 						  RTE_FLOW_ERROR_TYPE_ACTION,
5936 						  NULL,
5937 						  "unsupported action QUEUE");
5938 		if (sub_action_flags & MLX5_FLOW_ACTION_RSS)
5939 			return rte_flow_error_set(error, ENOTSUP,
5940 						  RTE_FLOW_ERROR_TYPE_ACTION,
5941 						  NULL,
5942 						  "unsupported action QUEUE");
5943 		if (!(sub_action_flags & MLX5_FLOW_ACTION_PORT_ID))
5944 			return rte_flow_error_set(error, EINVAL,
5945 						  RTE_FLOW_ERROR_TYPE_ACTION,
5946 						  NULL,
5947 						  "E-Switch must has a dest "
5948 						  "port for mirroring");
5949 		*fdb_mirror = 1;
5950 	}
5951 	/* Continue validation for Xcap actions.*/
5952 	if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) &&
5953 	    (queue_index == 0xFFFF || !mlx5_rxq_is_hairpin(dev, queue_index))) {
5954 		if ((sub_action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
5955 		     MLX5_FLOW_XCAP_ACTIONS)
5956 			return rte_flow_error_set(error, ENOTSUP,
5957 						  RTE_FLOW_ERROR_TYPE_ACTION,
5958 						  NULL, "encap and decap "
5959 						  "combination aren't "
5960 						  "supported");
5961 		if (attr->ingress && (sub_action_flags & MLX5_FLOW_ACTION_ENCAP))
5962 			return rte_flow_error_set(error, ENOTSUP,
5963 						  RTE_FLOW_ERROR_TYPE_ACTION,
5964 						  NULL, "encap is not supported"
5965 						  " for ingress traffic");
5966 	}
5967 	return 0;
5968 }
5969 
5970 /**
5971  * Find existing modify-header resource or create and register a new one.
5972  *
5973  * @param dev[in, out]
5974  *   Pointer to rte_eth_dev structure.
5975  * @param[in, out] resource
5976  *   Pointer to modify-header resource.
5977  * @parm[in, out] dev_flow
5978  *   Pointer to the dev_flow.
5979  * @param[out] error
5980  *   pointer to error structure.
5981  *
5982  * @return
5983  *   0 on success otherwise -errno and errno is set.
5984  */
5985 static int
5986 flow_dv_modify_hdr_resource_register
5987 			(struct rte_eth_dev *dev,
5988 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
5989 			 struct mlx5_flow *dev_flow,
5990 			 struct rte_flow_error *error)
5991 {
5992 	struct mlx5_priv *priv = dev->data->dev_private;
5993 	struct mlx5_dev_ctx_shared *sh = priv->sh;
5994 	uint32_t key_len = sizeof(*resource) -
5995 			   offsetof(typeof(*resource), ft_type) +
5996 			   resource->actions_num * sizeof(resource->actions[0]);
5997 	struct mlx5_list_entry *entry;
5998 	struct mlx5_flow_cb_ctx ctx = {
5999 		.error = error,
6000 		.data = resource,
6001 	};
6002 	struct mlx5_hlist *modify_cmds;
6003 	uint64_t key64;
6004 
6005 	modify_cmds = flow_dv_hlist_prepare(sh, &sh->modify_cmds,
6006 				"hdr_modify",
6007 				MLX5_FLOW_HDR_MODIFY_HTABLE_SZ,
6008 				true, false, sh,
6009 				flow_dv_modify_create_cb,
6010 				flow_dv_modify_match_cb,
6011 				flow_dv_modify_remove_cb,
6012 				flow_dv_modify_clone_cb,
6013 				flow_dv_modify_clone_free_cb,
6014 				error);
6015 	if (unlikely(!modify_cmds))
6016 		return -rte_errno;
6017 	resource->root = !dev_flow->dv.group;
6018 	if (resource->actions_num > flow_dv_modify_hdr_action_max(dev,
6019 								resource->root))
6020 		return rte_flow_error_set(error, EOVERFLOW,
6021 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
6022 					  "too many modify header items");
6023 	key64 = __rte_raw_cksum(&resource->ft_type, key_len, 0);
6024 	entry = mlx5_hlist_register(modify_cmds, key64, &ctx);
6025 	if (!entry)
6026 		return -rte_errno;
6027 	resource = container_of(entry, typeof(*resource), entry);
6028 	dev_flow->handle->dvh.modify_hdr = resource;
6029 	return 0;
6030 }
6031 
6032 /**
6033  * Get DV flow counter by index.
6034  *
6035  * @param[in] dev
6036  *   Pointer to the Ethernet device structure.
6037  * @param[in] idx
6038  *   mlx5 flow counter index in the container.
6039  * @param[out] ppool
6040  *   mlx5 flow counter pool in the container.
6041  *
6042  * @return
6043  *   Pointer to the counter, NULL otherwise.
6044  */
6045 static struct mlx5_flow_counter *
6046 flow_dv_counter_get_by_idx(struct rte_eth_dev *dev,
6047 			   uint32_t idx,
6048 			   struct mlx5_flow_counter_pool **ppool)
6049 {
6050 	struct mlx5_priv *priv = dev->data->dev_private;
6051 	struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng;
6052 	struct mlx5_flow_counter_pool *pool;
6053 
6054 	/* Decrease to original index and clear shared bit. */
6055 	idx = (idx - 1) & (MLX5_CNT_SHARED_OFFSET - 1);
6056 	MLX5_ASSERT(idx / MLX5_COUNTERS_PER_POOL < MLX5_COUNTER_POOLS_MAX_NUM);
6057 	pool = cmng->pools[idx / MLX5_COUNTERS_PER_POOL];
6058 	MLX5_ASSERT(pool);
6059 	if (ppool)
6060 		*ppool = pool;
6061 	return MLX5_POOL_GET_CNT(pool, idx % MLX5_COUNTERS_PER_POOL);
6062 }
6063 
6064 /**
6065  * Check the devx counter belongs to the pool.
6066  *
6067  * @param[in] pool
6068  *   Pointer to the counter pool.
6069  * @param[in] id
6070  *   The counter devx ID.
6071  *
6072  * @return
6073  *   True if counter belongs to the pool, false otherwise.
6074  */
6075 static bool
6076 flow_dv_is_counter_in_pool(struct mlx5_flow_counter_pool *pool, int id)
6077 {
6078 	int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) *
6079 		   MLX5_COUNTERS_PER_POOL;
6080 
6081 	if (id >= base && id < base + MLX5_COUNTERS_PER_POOL)
6082 		return true;
6083 	return false;
6084 }
6085 
6086 /**
6087  * Get a pool by devx counter ID.
6088  *
6089  * @param[in] cmng
6090  *   Pointer to the counter management.
6091  * @param[in] id
6092  *   The counter devx ID.
6093  *
6094  * @return
6095  *   The counter pool pointer if exists, NULL otherwise,
6096  */
6097 static struct mlx5_flow_counter_pool *
6098 flow_dv_find_pool_by_id(struct mlx5_flow_counter_mng *cmng, int id)
6099 {
6100 	uint32_t i;
6101 	struct mlx5_flow_counter_pool *pool = NULL;
6102 
6103 	rte_spinlock_lock(&cmng->pool_update_sl);
6104 	/* Check last used pool. */
6105 	if (cmng->last_pool_idx != POOL_IDX_INVALID &&
6106 	    flow_dv_is_counter_in_pool(cmng->pools[cmng->last_pool_idx], id)) {
6107 		pool = cmng->pools[cmng->last_pool_idx];
6108 		goto out;
6109 	}
6110 	/* ID out of range means no suitable pool in the container. */
6111 	if (id > cmng->max_id || id < cmng->min_id)
6112 		goto out;
6113 	/*
6114 	 * Find the pool from the end of the container, since mostly counter
6115 	 * ID is sequence increasing, and the last pool should be the needed
6116 	 * one.
6117 	 */
6118 	i = cmng->n_valid;
6119 	while (i--) {
6120 		struct mlx5_flow_counter_pool *pool_tmp = cmng->pools[i];
6121 
6122 		if (flow_dv_is_counter_in_pool(pool_tmp, id)) {
6123 			pool = pool_tmp;
6124 			break;
6125 		}
6126 	}
6127 out:
6128 	rte_spinlock_unlock(&cmng->pool_update_sl);
6129 	return pool;
6130 }
6131 
6132 /**
6133  * Query a devx flow counter.
6134  *
6135  * @param[in] dev
6136  *   Pointer to the Ethernet device structure.
6137  * @param[in] counter
6138  *   Index to the flow counter.
6139  * @param[out] pkts
6140  *   The statistics value of packets.
6141  * @param[out] bytes
6142  *   The statistics value of bytes.
6143  *
6144  * @return
6145  *   0 on success, otherwise a negative errno value and rte_errno is set.
6146  */
6147 static inline int
6148 _flow_dv_query_count(struct rte_eth_dev *dev, uint32_t counter, uint64_t *pkts,
6149 		     uint64_t *bytes)
6150 {
6151 	struct mlx5_priv *priv = dev->data->dev_private;
6152 	struct mlx5_flow_counter_pool *pool = NULL;
6153 	struct mlx5_flow_counter *cnt;
6154 	int offset;
6155 
6156 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
6157 	MLX5_ASSERT(pool);
6158 	if (priv->sh->sws_cmng.counter_fallback)
6159 		return mlx5_devx_cmd_flow_counter_query(cnt->dcs_when_active, 0,
6160 					0, pkts, bytes, 0, NULL, NULL, 0);
6161 	rte_spinlock_lock(&pool->sl);
6162 	if (!pool->raw) {
6163 		*pkts = 0;
6164 		*bytes = 0;
6165 	} else {
6166 		offset = MLX5_CNT_ARRAY_IDX(pool, cnt);
6167 		*pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits);
6168 		*bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes);
6169 	}
6170 	rte_spinlock_unlock(&pool->sl);
6171 	return 0;
6172 }
6173 
6174 /**
6175  * Create and initialize a new counter pool.
6176  *
6177  * @param[in] dev
6178  *   Pointer to the Ethernet device structure.
6179  * @param[out] dcs
6180  *   The devX counter handle.
6181  * @param[in] age
6182  *   Whether the pool is for counter that was allocated for aging.
6183  *
6184  * @return
6185  *   The pool container pointer on success, NULL otherwise and rte_errno is set.
6186  */
6187 static struct mlx5_flow_counter_pool *
6188 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
6189 		    uint32_t age)
6190 {
6191 	struct mlx5_priv *priv = dev->data->dev_private;
6192 	struct mlx5_flow_counter_pool *pool;
6193 	struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng;
6194 	bool fallback = cmng->counter_fallback;
6195 	uint32_t size = sizeof(*pool);
6196 
6197 	if (cmng->n_valid == MLX5_COUNTER_POOLS_MAX_NUM) {
6198 		DRV_LOG(ERR, "All counter is in used, try again later.");
6199 		rte_errno = EAGAIN;
6200 		return NULL;
6201 	}
6202 	size += MLX5_COUNTERS_PER_POOL * MLX5_CNT_SIZE;
6203 	size += (!age ? 0 : MLX5_COUNTERS_PER_POOL * MLX5_AGE_SIZE);
6204 	pool = mlx5_malloc(MLX5_MEM_ZERO, size, 0, SOCKET_ID_ANY);
6205 	if (!pool) {
6206 		rte_errno = ENOMEM;
6207 		return NULL;
6208 	}
6209 	pool->raw = NULL;
6210 	pool->is_aged = !!age;
6211 	pool->query_gen = 0;
6212 	pool->min_dcs = dcs;
6213 	rte_spinlock_init(&pool->sl);
6214 	rte_spinlock_init(&pool->csl);
6215 	TAILQ_INIT(&pool->counters[0]);
6216 	TAILQ_INIT(&pool->counters[1]);
6217 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
6218 	rte_spinlock_lock(&cmng->pool_update_sl);
6219 	pool->index = cmng->n_valid;
6220 	cmng->pools[pool->index] = pool;
6221 	cmng->n_valid++;
6222 	if (unlikely(fallback)) {
6223 		int base = RTE_ALIGN_FLOOR(dcs->id, MLX5_COUNTERS_PER_POOL);
6224 
6225 		if (base < cmng->min_id)
6226 			cmng->min_id = base;
6227 		if (base > cmng->max_id)
6228 			cmng->max_id = base + MLX5_COUNTERS_PER_POOL - 1;
6229 		cmng->last_pool_idx = pool->index;
6230 	}
6231 	rte_spinlock_unlock(&cmng->pool_update_sl);
6232 	return pool;
6233 }
6234 
6235 /**
6236  * Prepare a new counter and/or a new counter pool.
6237  *
6238  * @param[in] dev
6239  *   Pointer to the Ethernet device structure.
6240  * @param[out] cnt_free
6241  *   Where to put the pointer of a new counter.
6242  * @param[in] age
6243  *   Whether the pool is for counter that was allocated for aging.
6244  *
6245  * @return
6246  *   The counter pool pointer and @p cnt_free is set on success,
6247  *   NULL otherwise and rte_errno is set.
6248  */
6249 static struct mlx5_flow_counter_pool *
6250 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev,
6251 			     struct mlx5_flow_counter **cnt_free,
6252 			     uint32_t age)
6253 {
6254 	struct mlx5_priv *priv = dev->data->dev_private;
6255 	struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng;
6256 	struct mlx5_flow_counter_pool *pool;
6257 	struct mlx5_counters tmp_tq;
6258 	struct mlx5_devx_obj *dcs = NULL;
6259 	struct mlx5_flow_counter *cnt;
6260 	enum mlx5_counter_type cnt_type =
6261 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6262 	bool fallback = priv->sh->sws_cmng.counter_fallback;
6263 	uint32_t i;
6264 
6265 	if (fallback) {
6266 		/* bulk_bitmap must be 0 for single counter allocation. */
6267 		dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0);
6268 		if (!dcs)
6269 			return NULL;
6270 		pool = flow_dv_find_pool_by_id(cmng, dcs->id);
6271 		if (!pool) {
6272 			pool = flow_dv_pool_create(dev, dcs, age);
6273 			if (!pool) {
6274 				mlx5_devx_cmd_destroy(dcs);
6275 				return NULL;
6276 			}
6277 		}
6278 		i = dcs->id % MLX5_COUNTERS_PER_POOL;
6279 		cnt = MLX5_POOL_GET_CNT(pool, i);
6280 		cnt->pool = pool;
6281 		cnt->dcs_when_free = dcs;
6282 		*cnt_free = cnt;
6283 		return pool;
6284 	}
6285 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4);
6286 	if (!dcs) {
6287 		rte_errno = ENODATA;
6288 		return NULL;
6289 	}
6290 	pool = flow_dv_pool_create(dev, dcs, age);
6291 	if (!pool) {
6292 		mlx5_devx_cmd_destroy(dcs);
6293 		return NULL;
6294 	}
6295 	TAILQ_INIT(&tmp_tq);
6296 	for (i = 1; i < MLX5_COUNTERS_PER_POOL; ++i) {
6297 		cnt = MLX5_POOL_GET_CNT(pool, i);
6298 		cnt->pool = pool;
6299 		TAILQ_INSERT_HEAD(&tmp_tq, cnt, next);
6300 	}
6301 	rte_spinlock_lock(&cmng->csl[cnt_type]);
6302 	TAILQ_CONCAT(&cmng->counters[cnt_type], &tmp_tq, next);
6303 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
6304 	*cnt_free = MLX5_POOL_GET_CNT(pool, 0);
6305 	(*cnt_free)->pool = pool;
6306 	return pool;
6307 }
6308 
6309 /**
6310  * Allocate a flow counter.
6311  *
6312  * @param[in] dev
6313  *   Pointer to the Ethernet device structure.
6314  * @param[in] age
6315  *   Whether the counter was allocated for aging.
6316  *
6317  * @return
6318  *   Index to flow counter on success, 0 otherwise and rte_errno is set.
6319  */
6320 static uint32_t
6321 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t age)
6322 {
6323 	struct mlx5_priv *priv = dev->data->dev_private;
6324 	struct mlx5_flow_counter_pool *pool = NULL;
6325 	struct mlx5_flow_counter *cnt_free = NULL;
6326 	bool fallback = priv->sh->sws_cmng.counter_fallback;
6327 	struct mlx5_flow_counter_mng *cmng = &priv->sh->sws_cmng;
6328 	enum mlx5_counter_type cnt_type =
6329 			age ? MLX5_COUNTER_TYPE_AGE : MLX5_COUNTER_TYPE_ORIGIN;
6330 	uint32_t cnt_idx;
6331 
6332 	if (!priv->sh->cdev->config.devx) {
6333 		rte_errno = ENOTSUP;
6334 		return 0;
6335 	}
6336 	/* Get free counters from container. */
6337 	rte_spinlock_lock(&cmng->csl[cnt_type]);
6338 	cnt_free = TAILQ_FIRST(&cmng->counters[cnt_type]);
6339 	if (cnt_free)
6340 		TAILQ_REMOVE(&cmng->counters[cnt_type], cnt_free, next);
6341 	rte_spinlock_unlock(&cmng->csl[cnt_type]);
6342 	if (!cnt_free && !flow_dv_counter_pool_prepare(dev, &cnt_free, age))
6343 		goto err;
6344 	pool = cnt_free->pool;
6345 	if (fallback)
6346 		cnt_free->dcs_when_active = cnt_free->dcs_when_free;
6347 	/* Create a DV counter action only in the first time usage. */
6348 	if (!cnt_free->action) {
6349 		uint16_t offset;
6350 		struct mlx5_devx_obj *dcs;
6351 		int ret;
6352 
6353 		if (!fallback) {
6354 			offset = MLX5_CNT_ARRAY_IDX(pool, cnt_free);
6355 			dcs = pool->min_dcs;
6356 		} else {
6357 			offset = 0;
6358 			dcs = cnt_free->dcs_when_free;
6359 		}
6360 		ret = mlx5_flow_os_create_flow_action_count(dcs->obj, offset,
6361 							    &cnt_free->action);
6362 		if (ret) {
6363 			rte_errno = errno;
6364 			goto err;
6365 		}
6366 	}
6367 	cnt_idx = MLX5_MAKE_CNT_IDX(pool->index,
6368 				MLX5_CNT_ARRAY_IDX(pool, cnt_free));
6369 	/* Update the counter reset values. */
6370 	if (_flow_dv_query_count(dev, cnt_idx, &cnt_free->hits,
6371 				 &cnt_free->bytes))
6372 		goto err;
6373 	if (!fallback && !priv->sh->sws_cmng.query_thread_on)
6374 		/* Start the asynchronous batch query by the host thread. */
6375 		mlx5_set_query_alarm(priv->sh);
6376 	/*
6377 	 * When the count action isn't shared (by ID), shared_info field is
6378 	 * used for indirect action API's refcnt.
6379 	 * When the counter action is not shared neither by ID nor by indirect
6380 	 * action API, shared info must be 1.
6381 	 */
6382 	cnt_free->shared_info.refcnt = 1;
6383 	return cnt_idx;
6384 err:
6385 	if (cnt_free) {
6386 		cnt_free->pool = pool;
6387 		if (fallback)
6388 			cnt_free->dcs_when_free = cnt_free->dcs_when_active;
6389 		rte_spinlock_lock(&cmng->csl[cnt_type]);
6390 		TAILQ_INSERT_TAIL(&cmng->counters[cnt_type], cnt_free, next);
6391 		rte_spinlock_unlock(&cmng->csl[cnt_type]);
6392 	}
6393 	return 0;
6394 }
6395 
6396 /**
6397  * Get age param from counter index.
6398  *
6399  * @param[in] dev
6400  *   Pointer to the Ethernet device structure.
6401  * @param[in] counter
6402  *   Index to the counter handler.
6403  *
6404  * @return
6405  *   The aging parameter specified for the counter index.
6406  */
6407 static struct mlx5_age_param*
6408 flow_dv_counter_idx_get_age(struct rte_eth_dev *dev,
6409 				uint32_t counter)
6410 {
6411 	struct mlx5_flow_counter *cnt;
6412 	struct mlx5_flow_counter_pool *pool = NULL;
6413 
6414 	flow_dv_counter_get_by_idx(dev, counter, &pool);
6415 	counter = (counter - 1) % MLX5_COUNTERS_PER_POOL;
6416 	cnt = MLX5_POOL_GET_CNT(pool, counter);
6417 	return MLX5_CNT_TO_AGE(cnt);
6418 }
6419 
6420 /**
6421  * Remove a flow counter from aged counter list.
6422  *
6423  * @param[in] dev
6424  *   Pointer to the Ethernet device structure.
6425  * @param[in] counter
6426  *   Index to the counter handler.
6427  * @param[in] cnt
6428  *   Pointer to the counter handler.
6429  */
6430 static void
6431 flow_dv_counter_remove_from_age(struct rte_eth_dev *dev,
6432 				uint32_t counter, struct mlx5_flow_counter *cnt)
6433 {
6434 	struct mlx5_age_info *age_info;
6435 	struct mlx5_age_param *age_param;
6436 	struct mlx5_priv *priv = dev->data->dev_private;
6437 	uint16_t expected = AGE_CANDIDATE;
6438 
6439 	age_info = GET_PORT_AGE_INFO(priv);
6440 	age_param = flow_dv_counter_idx_get_age(dev, counter);
6441 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
6442 					 AGE_FREE, false, __ATOMIC_RELAXED,
6443 					 __ATOMIC_RELAXED)) {
6444 		/**
6445 		 * We need the lock even it is age timeout,
6446 		 * since counter may still in process.
6447 		 */
6448 		rte_spinlock_lock(&age_info->aged_sl);
6449 		TAILQ_REMOVE(&age_info->aged_counters, cnt, next);
6450 		rte_spinlock_unlock(&age_info->aged_sl);
6451 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
6452 	}
6453 }
6454 
6455 /**
6456  * Release a flow counter.
6457  *
6458  * @param[in] dev
6459  *   Pointer to the Ethernet device structure.
6460  * @param[in] counter
6461  *   Index to the counter handler.
6462  */
6463 static void
6464 flow_dv_counter_free(struct rte_eth_dev *dev, uint32_t counter)
6465 {
6466 	struct mlx5_priv *priv = dev->data->dev_private;
6467 	struct mlx5_flow_counter_pool *pool = NULL;
6468 	struct mlx5_flow_counter *cnt;
6469 	enum mlx5_counter_type cnt_type;
6470 
6471 	if (!counter)
6472 		return;
6473 	cnt = flow_dv_counter_get_by_idx(dev, counter, &pool);
6474 	MLX5_ASSERT(pool);
6475 	if (pool->is_aged) {
6476 		flow_dv_counter_remove_from_age(dev, counter, cnt);
6477 	} else {
6478 		/*
6479 		 * If the counter action is shared by indirect action API,
6480 		 * the atomic function reduces its references counter.
6481 		 * If after the reduction the action is still referenced, the
6482 		 * function returns here and does not release it.
6483 		 * When the counter action is not shared by
6484 		 * indirect action API, shared info is 1 before the reduction,
6485 		 * so this condition is failed and function doesn't return here.
6486 		 */
6487 		if (__atomic_sub_fetch(&cnt->shared_info.refcnt, 1,
6488 				       __ATOMIC_RELAXED))
6489 			return;
6490 	}
6491 	cnt->pool = pool;
6492 	/*
6493 	 * Put the counter back to list to be updated in none fallback mode.
6494 	 * Currently, we are using two list alternately, while one is in query,
6495 	 * add the freed counter to the other list based on the pool query_gen
6496 	 * value. After query finishes, add counter the list to the global
6497 	 * container counter list. The list changes while query starts. In
6498 	 * this case, lock will not be needed as query callback and release
6499 	 * function both operate with the different list.
6500 	 */
6501 	if (!priv->sh->sws_cmng.counter_fallback) {
6502 		rte_spinlock_lock(&pool->csl);
6503 		TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next);
6504 		rte_spinlock_unlock(&pool->csl);
6505 	} else {
6506 		cnt->dcs_when_free = cnt->dcs_when_active;
6507 		cnt_type = pool->is_aged ? MLX5_COUNTER_TYPE_AGE :
6508 					   MLX5_COUNTER_TYPE_ORIGIN;
6509 		rte_spinlock_lock(&priv->sh->sws_cmng.csl[cnt_type]);
6510 		TAILQ_INSERT_TAIL(&priv->sh->sws_cmng.counters[cnt_type],
6511 				  cnt, next);
6512 		rte_spinlock_unlock(&priv->sh->sws_cmng.csl[cnt_type]);
6513 	}
6514 }
6515 
6516 /**
6517  * Resize a meter id container.
6518  *
6519  * @param[in] dev
6520  *   Pointer to the Ethernet device structure.
6521  *
6522  * @return
6523  *   0 on success, otherwise negative errno value and rte_errno is set.
6524  */
6525 static int
6526 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
6527 {
6528 	struct mlx5_priv *priv = dev->data->dev_private;
6529 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6530 				&priv->sh->mtrmng->pools_mng;
6531 	void *old_pools = pools_mng->pools;
6532 	uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
6533 	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
6534 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
6535 
6536 	if (!pools) {
6537 		rte_errno = ENOMEM;
6538 		return -ENOMEM;
6539 	}
6540 	if (!pools_mng->n)
6541 		if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER, 1)) {
6542 			mlx5_free(pools);
6543 			return -ENOMEM;
6544 		}
6545 	if (old_pools)
6546 		memcpy(pools, old_pools, pools_mng->n *
6547 				       sizeof(struct mlx5_aso_mtr_pool *));
6548 	pools_mng->n = resize;
6549 	pools_mng->pools = pools;
6550 	if (old_pools)
6551 		mlx5_free(old_pools);
6552 	return 0;
6553 }
6554 
6555 /**
6556  * Prepare a new meter and/or a new meter pool.
6557  *
6558  * @param[in] dev
6559  *   Pointer to the Ethernet device structure.
6560  * @param[out] mtr_free
6561  *   Where to put the pointer of a new meter.g.
6562  *
6563  * @return
6564  *   The meter pool pointer and @mtr_free is set on success,
6565  *   NULL otherwise and rte_errno is set.
6566  */
6567 static struct mlx5_aso_mtr_pool *
6568 flow_dv_mtr_pool_create(struct rte_eth_dev *dev, struct mlx5_aso_mtr **mtr_free)
6569 {
6570 	struct mlx5_priv *priv = dev->data->dev_private;
6571 	struct mlx5_aso_mtr_pools_mng *pools_mng = &priv->sh->mtrmng->pools_mng;
6572 	struct mlx5_aso_mtr_pool *pool = NULL;
6573 	struct mlx5_devx_obj *dcs = NULL;
6574 	uint32_t i;
6575 	uint32_t log_obj_size;
6576 
6577 	log_obj_size = rte_log2_u32(MLX5_ASO_MTRS_PER_POOL >> 1);
6578 	dcs = mlx5_devx_cmd_create_flow_meter_aso_obj(priv->sh->cdev->ctx,
6579 						      priv->sh->cdev->pdn,
6580 						      log_obj_size);
6581 	if (!dcs) {
6582 		rte_errno = ENODATA;
6583 		return NULL;
6584 	}
6585 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
6586 	if (!pool) {
6587 		rte_errno = ENOMEM;
6588 		claim_zero(mlx5_devx_cmd_destroy(dcs));
6589 		return NULL;
6590 	}
6591 	pool->devx_obj = dcs;
6592 	rte_rwlock_write_lock(&pools_mng->resize_mtrwl);
6593 	pool->index = pools_mng->n_valid;
6594 	if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
6595 		mlx5_free(pool);
6596 		claim_zero(mlx5_devx_cmd_destroy(dcs));
6597 		rte_rwlock_write_unlock(&pools_mng->resize_mtrwl);
6598 		return NULL;
6599 	}
6600 	pools_mng->pools[pool->index] = pool;
6601 	pools_mng->n_valid++;
6602 	rte_rwlock_write_unlock(&pools_mng->resize_mtrwl);
6603 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
6604 		pool->mtrs[i].offset = i;
6605 		LIST_INSERT_HEAD(&pools_mng->meters, &pool->mtrs[i], next);
6606 	}
6607 	pool->mtrs[0].offset = 0;
6608 	*mtr_free = &pool->mtrs[0];
6609 	return pool;
6610 }
6611 
6612 /**
6613  * Release a flow meter into pool.
6614  *
6615  * @param[in] dev
6616  *   Pointer to the Ethernet device structure.
6617  * @param[in] mtr_idx
6618  *   Index to aso flow meter.
6619  */
6620 static void
6621 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
6622 {
6623 	struct mlx5_priv *priv = dev->data->dev_private;
6624 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6625 				&priv->sh->mtrmng->pools_mng;
6626 	struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
6627 
6628 	MLX5_ASSERT(aso_mtr);
6629 	rte_spinlock_lock(&pools_mng->mtrsl);
6630 	memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
6631 	aso_mtr->state = ASO_METER_FREE;
6632 	LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
6633 	rte_spinlock_unlock(&pools_mng->mtrsl);
6634 }
6635 
6636 /**
6637  * Allocate a aso flow meter.
6638  *
6639  * @param[in] dev
6640  *   Pointer to the Ethernet device structure.
6641  *
6642  * @return
6643  *   Index to aso flow meter on success, 0 otherwise and rte_errno is set.
6644  */
6645 static uint32_t
6646 flow_dv_mtr_alloc(struct rte_eth_dev *dev)
6647 {
6648 	struct mlx5_priv *priv = dev->data->dev_private;
6649 	struct mlx5_aso_mtr *mtr_free = NULL;
6650 	struct mlx5_aso_mtr_pools_mng *pools_mng =
6651 				&priv->sh->mtrmng->pools_mng;
6652 	struct mlx5_aso_mtr_pool *pool;
6653 	uint32_t mtr_idx = 0;
6654 
6655 	if (!priv->sh->cdev->config.devx) {
6656 		rte_errno = ENOTSUP;
6657 		return 0;
6658 	}
6659 	/* Allocate the flow meter memory. */
6660 	/* Get free meters from management. */
6661 	rte_spinlock_lock(&pools_mng->mtrsl);
6662 	mtr_free = LIST_FIRST(&pools_mng->meters);
6663 	if (mtr_free)
6664 		LIST_REMOVE(mtr_free, next);
6665 	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
6666 		rte_spinlock_unlock(&pools_mng->mtrsl);
6667 		return 0;
6668 	}
6669 	mtr_free->state = ASO_METER_WAIT;
6670 	rte_spinlock_unlock(&pools_mng->mtrsl);
6671 	pool = container_of(mtr_free,
6672 			struct mlx5_aso_mtr_pool,
6673 			mtrs[mtr_free->offset]);
6674 	mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
6675 	if (!mtr_free->fm.meter_action_g) {
6676 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
6677 		struct rte_flow_error error;
6678 		uint8_t reg_id;
6679 
6680 		reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error);
6681 		mtr_free->fm.meter_action_g =
6682 			mlx5_glue->dv_create_flow_action_aso
6683 						(priv->sh->rx_domain,
6684 						 pool->devx_obj->obj,
6685 						 mtr_free->offset,
6686 						 (1 << MLX5_FLOW_COLOR_GREEN),
6687 						 reg_id - REG_C_0);
6688 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
6689 		if (!mtr_free->fm.meter_action_g) {
6690 			flow_dv_aso_mtr_release_to_pool(dev, mtr_idx);
6691 			return 0;
6692 		}
6693 	}
6694 	return mtr_idx;
6695 }
6696 
6697 /**
6698  * Verify the @p attributes will be correctly understood by the NIC and store
6699  * them in the @p flow if everything is correct.
6700  *
6701  * @param[in] dev
6702  *   Pointer to dev struct.
6703  * @param[in] attributes
6704  *   Pointer to flow attributes
6705  * @param[in] external
6706  *   This flow rule is created by request external to PMD.
6707  * @param[out] error
6708  *   Pointer to error structure.
6709  *
6710  * @return
6711  *   - 0 on success and non root table.
6712  *   - 1 on success and root table.
6713  *   - a negative errno value otherwise and rte_errno is set.
6714  */
6715 static int
6716 flow_dv_validate_attributes(struct rte_eth_dev *dev,
6717 			    const struct mlx5_flow_tunnel *tunnel,
6718 			    const struct rte_flow_attr *attributes,
6719 			    const struct flow_grp_info *grp_info,
6720 			    struct rte_flow_error *error)
6721 {
6722 	struct mlx5_priv *priv = dev->data->dev_private;
6723 	uint32_t lowest_priority = mlx5_get_lowest_priority(dev, attributes);
6724 	int ret = 0;
6725 
6726 #ifndef HAVE_MLX5DV_DR
6727 	RTE_SET_USED(tunnel);
6728 	RTE_SET_USED(grp_info);
6729 	if (attributes->group)
6730 		return rte_flow_error_set(error, ENOTSUP,
6731 					  RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
6732 					  NULL,
6733 					  "groups are not supported");
6734 #else
6735 	uint32_t table = 0;
6736 
6737 	ret = mlx5_flow_group_to_table(dev, tunnel, attributes->group, &table,
6738 				       grp_info, error);
6739 	if (ret)
6740 		return ret;
6741 	if (!table)
6742 		ret = MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
6743 #endif
6744 	if (attributes->priority != MLX5_FLOW_LOWEST_PRIO_INDICATOR &&
6745 	    attributes->priority > lowest_priority)
6746 		return rte_flow_error_set(error, ENOTSUP,
6747 					  RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
6748 					  NULL,
6749 					  "priority out of range");
6750 	if (attributes->transfer && !priv->sh->config.dv_esw_en)
6751 		return rte_flow_error_set(error, ENOTSUP,
6752 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
6753 					  "E-Switch dr is not supported");
6754 	if (attributes->ingress + attributes->egress + attributes->transfer != 1) {
6755 		return rte_flow_error_set(error, EINVAL,
6756 					  RTE_FLOW_ERROR_TYPE_ATTR, NULL,
6757 					  "must specify exactly one of "
6758 					  "ingress, egress or transfer");
6759 	}
6760 	return ret;
6761 }
6762 
6763 static int
6764 validate_integrity_bits(const struct rte_flow_item_integrity *mask,
6765 			int64_t pattern_flags, uint64_t l3_flags,
6766 			uint64_t l4_flags, uint64_t ip4_flag,
6767 			struct rte_flow_error *error)
6768 {
6769 	if (mask->l3_ok && !(pattern_flags & l3_flags))
6770 		return rte_flow_error_set(error, EINVAL,
6771 					  RTE_FLOW_ERROR_TYPE_ITEM,
6772 					  NULL, "missing L3 protocol");
6773 
6774 	if (mask->ipv4_csum_ok && !(pattern_flags & ip4_flag))
6775 		return rte_flow_error_set(error, EINVAL,
6776 					  RTE_FLOW_ERROR_TYPE_ITEM,
6777 					  NULL, "missing IPv4 protocol");
6778 
6779 	if ((mask->l4_ok || mask->l4_csum_ok) && !(pattern_flags & l4_flags))
6780 		return rte_flow_error_set(error, EINVAL,
6781 					  RTE_FLOW_ERROR_TYPE_ITEM,
6782 					  NULL, "missing L4 protocol");
6783 
6784 	return 0;
6785 }
6786 
6787 static int
6788 flow_dv_validate_item_integrity_post(const struct
6789 				     rte_flow_item *integrity_items[2],
6790 				     int64_t pattern_flags,
6791 				     struct rte_flow_error *error)
6792 {
6793 	const struct rte_flow_item_integrity *mask;
6794 	int ret;
6795 
6796 	if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) {
6797 		mask = (typeof(mask))integrity_items[0]->mask;
6798 		ret = validate_integrity_bits(mask, pattern_flags,
6799 					      MLX5_FLOW_LAYER_OUTER_L3,
6800 					      MLX5_FLOW_LAYER_OUTER_L4,
6801 					      MLX5_FLOW_LAYER_OUTER_L3_IPV4,
6802 					      error);
6803 		if (ret)
6804 			return ret;
6805 	}
6806 	if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) {
6807 		mask = (typeof(mask))integrity_items[1]->mask;
6808 		ret = validate_integrity_bits(mask, pattern_flags,
6809 					      MLX5_FLOW_LAYER_INNER_L3,
6810 					      MLX5_FLOW_LAYER_INNER_L4,
6811 					      MLX5_FLOW_LAYER_INNER_L3_IPV4,
6812 					      error);
6813 		if (ret)
6814 			return ret;
6815 	}
6816 	return 0;
6817 }
6818 
6819 static int
6820 flow_dv_validate_item_integrity(struct rte_eth_dev *dev,
6821 				const struct rte_flow_item *integrity_item,
6822 				uint64_t pattern_flags, uint64_t *last_item,
6823 				const struct rte_flow_item *integrity_items[2],
6824 				struct rte_flow_error *error)
6825 {
6826 	struct mlx5_priv *priv = dev->data->dev_private;
6827 	const struct rte_flow_item_integrity *mask = (typeof(mask))
6828 						     integrity_item->mask;
6829 	const struct rte_flow_item_integrity *spec = (typeof(spec))
6830 						     integrity_item->spec;
6831 
6832 	if (!priv->sh->cdev->config.hca_attr.pkt_integrity_match)
6833 		return rte_flow_error_set(error, ENOTSUP,
6834 					  RTE_FLOW_ERROR_TYPE_ITEM,
6835 					  integrity_item,
6836 					  "packet integrity integrity_item not supported");
6837 	if (!spec)
6838 		return rte_flow_error_set(error, ENOTSUP,
6839 					  RTE_FLOW_ERROR_TYPE_ITEM,
6840 					  integrity_item,
6841 					  "no spec for integrity item");
6842 	if (!mask)
6843 		mask = &rte_flow_item_integrity_mask;
6844 	if (!mlx5_validate_integrity_item(mask))
6845 		return rte_flow_error_set(error, ENOTSUP,
6846 					  RTE_FLOW_ERROR_TYPE_ITEM,
6847 					  integrity_item,
6848 					  "unsupported integrity filter");
6849 	if ((mask->l3_ok & !spec->l3_ok) || (mask->l4_ok & !spec->l4_ok) ||
6850 		(mask->ipv4_csum_ok & !spec->ipv4_csum_ok) ||
6851 		(mask->l4_csum_ok & !spec->l4_csum_ok))
6852 		return rte_flow_error_set(error, EINVAL,
6853 					  RTE_FLOW_ERROR_TYPE_ITEM,
6854 					  NULL, "negative integrity flow is not supported");
6855 	if (spec->level > 1) {
6856 		if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY)
6857 			return rte_flow_error_set
6858 				(error, ENOTSUP,
6859 				 RTE_FLOW_ERROR_TYPE_ITEM,
6860 				 NULL, "multiple inner integrity items not supported");
6861 		integrity_items[1] = integrity_item;
6862 		*last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY;
6863 	} else {
6864 		if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY)
6865 			return rte_flow_error_set
6866 				(error, ENOTSUP,
6867 				 RTE_FLOW_ERROR_TYPE_ITEM,
6868 				 NULL, "multiple outer integrity items not supported");
6869 		integrity_items[0] = integrity_item;
6870 		*last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY;
6871 	}
6872 	return 0;
6873 }
6874 
6875 static int
6876 flow_dv_validate_item_flex(struct rte_eth_dev *dev,
6877 			   const struct rte_flow_item *item,
6878 			   uint64_t item_flags,
6879 			   uint64_t *last_item,
6880 			   bool is_inner,
6881 			   struct rte_flow_error *error)
6882 {
6883 	const struct rte_flow_item_flex *flow_spec = item->spec;
6884 	const struct rte_flow_item_flex *flow_mask = item->mask;
6885 	struct mlx5_flex_item *flex;
6886 
6887 	if (!flow_spec)
6888 		return rte_flow_error_set(error, EINVAL,
6889 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
6890 					  "flex flow item spec cannot be NULL");
6891 	if (!flow_mask)
6892 		return rte_flow_error_set(error, EINVAL,
6893 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
6894 					  "flex flow item mask cannot be NULL");
6895 	if (item->last)
6896 		return rte_flow_error_set(error, ENOTSUP,
6897 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
6898 					  "flex flow item last not supported");
6899 	if (mlx5_flex_acquire_index(dev, flow_spec->handle, false) < 0)
6900 		return rte_flow_error_set(error, EINVAL,
6901 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
6902 					  "invalid flex flow item handle");
6903 	flex = (struct mlx5_flex_item *)flow_spec->handle;
6904 	switch (flex->tunnel_mode) {
6905 	case FLEX_TUNNEL_MODE_SINGLE:
6906 		if (item_flags &
6907 		    (MLX5_FLOW_ITEM_OUTER_FLEX | MLX5_FLOW_ITEM_INNER_FLEX))
6908 			rte_flow_error_set(error, EINVAL,
6909 					   RTE_FLOW_ERROR_TYPE_ITEM,
6910 					   NULL, "multiple flex items not supported");
6911 		break;
6912 	case FLEX_TUNNEL_MODE_OUTER:
6913 		if (is_inner)
6914 			rte_flow_error_set(error, EINVAL,
6915 					   RTE_FLOW_ERROR_TYPE_ITEM,
6916 					   NULL, "inner flex item was not configured");
6917 		if (item_flags & MLX5_FLOW_ITEM_OUTER_FLEX)
6918 			rte_flow_error_set(error, ENOTSUP,
6919 					   RTE_FLOW_ERROR_TYPE_ITEM,
6920 					   NULL, "multiple flex items not supported");
6921 		break;
6922 	case FLEX_TUNNEL_MODE_INNER:
6923 		if (!is_inner)
6924 			rte_flow_error_set(error, EINVAL,
6925 					   RTE_FLOW_ERROR_TYPE_ITEM,
6926 					   NULL, "outer flex item was not configured");
6927 		if (item_flags & MLX5_FLOW_ITEM_INNER_FLEX)
6928 			rte_flow_error_set(error, EINVAL,
6929 					   RTE_FLOW_ERROR_TYPE_ITEM,
6930 					   NULL, "multiple flex items not supported");
6931 		break;
6932 	case FLEX_TUNNEL_MODE_MULTI:
6933 		if ((is_inner && (item_flags & MLX5_FLOW_ITEM_INNER_FLEX)) ||
6934 		    (!is_inner && (item_flags & MLX5_FLOW_ITEM_OUTER_FLEX))) {
6935 			rte_flow_error_set(error, EINVAL,
6936 					   RTE_FLOW_ERROR_TYPE_ITEM,
6937 					   NULL, "multiple flex items not supported");
6938 		}
6939 		break;
6940 	case FLEX_TUNNEL_MODE_TUNNEL:
6941 		if (is_inner || (item_flags & MLX5_FLOW_ITEM_FLEX_TUNNEL))
6942 			rte_flow_error_set(error, EINVAL,
6943 					   RTE_FLOW_ERROR_TYPE_ITEM,
6944 					   NULL, "multiple flex tunnel items not supported");
6945 		break;
6946 	default:
6947 		rte_flow_error_set(error, EINVAL,
6948 				   RTE_FLOW_ERROR_TYPE_ITEM,
6949 				   NULL, "invalid flex item configuration");
6950 	}
6951 	*last_item = flex->tunnel_mode == FLEX_TUNNEL_MODE_TUNNEL ?
6952 		     MLX5_FLOW_ITEM_FLEX_TUNNEL : is_inner ?
6953 		     MLX5_FLOW_ITEM_INNER_FLEX : MLX5_FLOW_ITEM_OUTER_FLEX;
6954 	return 0;
6955 }
6956 
6957 /**
6958  * Internal validation function. For validating both actions and items.
6959  *
6960  * @param[in] dev
6961  *   Pointer to the rte_eth_dev structure.
6962  * @param[in] attr
6963  *   Pointer to the flow attributes.
6964  * @param[in] items
6965  *   Pointer to the list of items.
6966  * @param[in] actions
6967  *   Pointer to the list of actions.
6968  * @param[in] external
6969  *   This flow rule is created by request external to PMD.
6970  * @param[in] hairpin
6971  *   Number of hairpin TX actions, 0 means classic flow.
6972  * @param[out] error
6973  *   Pointer to the error structure.
6974  *
6975  * @return
6976  *   0 on success, a negative errno value otherwise and rte_errno is set.
6977  */
6978 static int
6979 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
6980 		 const struct rte_flow_item items[],
6981 		 const struct rte_flow_action actions[],
6982 		 bool external, int hairpin, struct rte_flow_error *error)
6983 {
6984 	int ret;
6985 	uint64_t aso_mask, action_flags = 0;
6986 	uint64_t item_flags = 0;
6987 	uint64_t last_item = 0;
6988 	uint8_t next_protocol = 0xff;
6989 	uint16_t ether_type = 0;
6990 	int actions_n = 0;
6991 	uint8_t item_ipv6_proto = 0;
6992 	int fdb_mirror = 0;
6993 	int modify_after_mirror = 0;
6994 	const struct rte_flow_item *geneve_item = NULL;
6995 	const struct rte_flow_item *gre_item = NULL;
6996 	const struct rte_flow_item *gtp_item = NULL;
6997 	const struct rte_flow_action_raw_decap *decap;
6998 	const struct rte_flow_action_raw_encap *encap;
6999 	const struct rte_flow_action_rss *rss = NULL;
7000 	const struct rte_flow_action_rss *sample_rss = NULL;
7001 	const struct rte_flow_action_count *sample_count = NULL;
7002 	const struct rte_flow_item_tcp nic_tcp_mask = {
7003 		.hdr = {
7004 			.tcp_flags = 0xFF,
7005 			.src_port = RTE_BE16(UINT16_MAX),
7006 			.dst_port = RTE_BE16(UINT16_MAX),
7007 		}
7008 	};
7009 	const struct rte_flow_item_ipv6 nic_ipv6_mask = {
7010 		.hdr = {
7011 			.src_addr =
7012 			"\xff\xff\xff\xff\xff\xff\xff\xff"
7013 			"\xff\xff\xff\xff\xff\xff\xff\xff",
7014 			.dst_addr =
7015 			"\xff\xff\xff\xff\xff\xff\xff\xff"
7016 			"\xff\xff\xff\xff\xff\xff\xff\xff",
7017 			.vtc_flow = RTE_BE32(0xffffffff),
7018 			.proto = 0xff,
7019 			.hop_limits = 0xff,
7020 		},
7021 		.has_frag_ext = 1,
7022 	};
7023 	const struct rte_flow_item_ecpri nic_ecpri_mask = {
7024 		.hdr = {
7025 			.common = {
7026 				.u32 =
7027 				RTE_BE32(((const struct rte_ecpri_common_hdr) {
7028 					.type = 0xFF,
7029 					}).u32),
7030 			},
7031 			.dummy[0] = 0xffffffff,
7032 		},
7033 	};
7034 	struct mlx5_priv *priv = dev->data->dev_private;
7035 	struct mlx5_sh_config *dev_conf = &priv->sh->config;
7036 	uint16_t queue_index = 0xFFFF;
7037 	const struct rte_flow_item_vlan *vlan_m = NULL;
7038 	uint32_t rw_act_num = 0;
7039 	uint64_t is_root;
7040 	const struct mlx5_flow_tunnel *tunnel;
7041 	enum mlx5_tof_rule_type tof_rule_type;
7042 	struct flow_grp_info grp_info = {
7043 		.external = !!external,
7044 		.transfer = !!attr->transfer,
7045 		.fdb_def_rule = !!priv->fdb_def_rule,
7046 		.std_tbl_fix = true,
7047 	};
7048 	const struct rte_eth_hairpin_conf *conf;
7049 	const struct rte_flow_item *integrity_items[2] = {NULL, NULL};
7050 	const struct rte_flow_item *port_id_item = NULL;
7051 	bool def_policy = false;
7052 	bool shared_count = false;
7053 	uint16_t udp_dport = 0;
7054 	uint32_t tag_id = 0;
7055 	const struct rte_flow_action_age *non_shared_age = NULL;
7056 	const struct rte_flow_action_count *count = NULL;
7057 	struct mlx5_priv *act_priv = NULL;
7058 	int aso_after_sample = 0;
7059 
7060 	if (items == NULL)
7061 		return -1;
7062 	tunnel = is_tunnel_offload_active(dev) ?
7063 		 mlx5_get_tof(items, actions, &tof_rule_type) : NULL;
7064 	if (tunnel) {
7065 		if (!dev_conf->dv_flow_en)
7066 			return rte_flow_error_set
7067 				(error, ENOTSUP,
7068 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
7069 				 NULL, "tunnel offload requires DV flow interface");
7070 		if (priv->representor)
7071 			return rte_flow_error_set
7072 				(error, ENOTSUP,
7073 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
7074 				 NULL, "decap not supported for VF representor");
7075 		if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE)
7076 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
7077 		else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE)
7078 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH |
7079 					MLX5_FLOW_ACTION_DECAP;
7080 		grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
7081 					(dev, attr, tunnel, tof_rule_type);
7082 	}
7083 	ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error);
7084 	if (ret < 0)
7085 		return ret;
7086 	is_root = (uint64_t)ret;
7087 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
7088 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
7089 		int type = items->type;
7090 
7091 		if (!mlx5_flow_os_item_supported(type))
7092 			return rte_flow_error_set(error, ENOTSUP,
7093 						  RTE_FLOW_ERROR_TYPE_ITEM,
7094 						  NULL, "item not supported");
7095 		switch (type) {
7096 		case RTE_FLOW_ITEM_TYPE_VOID:
7097 			break;
7098 		case RTE_FLOW_ITEM_TYPE_ESP:
7099 			ret = mlx5_flow_os_validate_item_esp(items, item_flags,
7100 							  next_protocol,
7101 							  error);
7102 			if (ret < 0)
7103 				return ret;
7104 			last_item = MLX5_FLOW_ITEM_ESP;
7105 			break;
7106 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
7107 			ret = flow_dv_validate_item_port_id
7108 					(dev, items, attr, item_flags, &act_priv, error);
7109 			if (ret < 0)
7110 				return ret;
7111 			last_item = MLX5_FLOW_ITEM_PORT_ID;
7112 			port_id_item = items;
7113 			break;
7114 		case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT:
7115 		case RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR:
7116 			ret = flow_dv_validate_item_represented_port
7117 					(dev, items, attr, item_flags, &act_priv, error);
7118 			if (ret < 0)
7119 				return ret;
7120 			last_item = MLX5_FLOW_ITEM_REPRESENTED_PORT;
7121 			port_id_item = items;
7122 			break;
7123 		case RTE_FLOW_ITEM_TYPE_ETH:
7124 			ret = mlx5_flow_validate_item_eth(items, item_flags,
7125 							  true, error);
7126 			if (ret < 0)
7127 				return ret;
7128 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
7129 					     MLX5_FLOW_LAYER_OUTER_L2;
7130 			if (items->mask != NULL && items->spec != NULL) {
7131 				ether_type =
7132 					((const struct rte_flow_item_eth *)
7133 					 items->spec)->hdr.ether_type;
7134 				ether_type &=
7135 					((const struct rte_flow_item_eth *)
7136 					 items->mask)->hdr.ether_type;
7137 				ether_type = rte_be_to_cpu_16(ether_type);
7138 			} else {
7139 				ether_type = 0;
7140 			}
7141 			break;
7142 		case RTE_FLOW_ITEM_TYPE_VLAN:
7143 			ret = flow_dv_validate_item_vlan(items, item_flags,
7144 							 dev, error);
7145 			if (ret < 0)
7146 				return ret;
7147 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
7148 					     MLX5_FLOW_LAYER_OUTER_VLAN;
7149 			if (items->mask != NULL && items->spec != NULL) {
7150 				ether_type =
7151 					((const struct rte_flow_item_vlan *)
7152 					 items->spec)->hdr.eth_proto;
7153 				ether_type &=
7154 					((const struct rte_flow_item_vlan *)
7155 					 items->mask)->hdr.eth_proto;
7156 				ether_type = rte_be_to_cpu_16(ether_type);
7157 			} else {
7158 				ether_type = 0;
7159 			}
7160 			/* Store outer VLAN mask for of_push_vlan action. */
7161 			if (!tunnel)
7162 				vlan_m = items->mask;
7163 			break;
7164 		case RTE_FLOW_ITEM_TYPE_IPV4:
7165 			mlx5_flow_tunnel_ip_check(items, next_protocol,
7166 						  &item_flags, &tunnel);
7167 			ret = flow_dv_validate_item_ipv4(dev, items, item_flags,
7168 							 last_item, ether_type,
7169 							 error);
7170 			if (ret < 0)
7171 				return ret;
7172 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
7173 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
7174 			if (items->mask != NULL &&
7175 			    ((const struct rte_flow_item_ipv4 *)
7176 			     items->mask)->hdr.next_proto_id) {
7177 				next_protocol =
7178 					((const struct rte_flow_item_ipv4 *)
7179 					 (items->spec))->hdr.next_proto_id;
7180 				next_protocol &=
7181 					((const struct rte_flow_item_ipv4 *)
7182 					 (items->mask))->hdr.next_proto_id;
7183 			} else {
7184 				/* Reset for inner layer. */
7185 				next_protocol = 0xff;
7186 			}
7187 			break;
7188 		case RTE_FLOW_ITEM_TYPE_IPV6:
7189 			mlx5_flow_tunnel_ip_check(items, next_protocol,
7190 						  &item_flags, &tunnel);
7191 			ret = mlx5_flow_validate_item_ipv6(items, item_flags,
7192 							   last_item,
7193 							   ether_type,
7194 							   &nic_ipv6_mask,
7195 							   error);
7196 			if (ret < 0)
7197 				return ret;
7198 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
7199 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
7200 			if (items->mask != NULL &&
7201 			    ((const struct rte_flow_item_ipv6 *)
7202 			     items->mask)->hdr.proto) {
7203 				item_ipv6_proto =
7204 					((const struct rte_flow_item_ipv6 *)
7205 					 items->spec)->hdr.proto;
7206 				next_protocol =
7207 					((const struct rte_flow_item_ipv6 *)
7208 					 items->spec)->hdr.proto;
7209 				next_protocol &=
7210 					((const struct rte_flow_item_ipv6 *)
7211 					 items->mask)->hdr.proto;
7212 			} else {
7213 				/* Reset for inner layer. */
7214 				next_protocol = 0xff;
7215 			}
7216 			break;
7217 		case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
7218 			ret = flow_dv_validate_item_ipv6_frag_ext(items,
7219 								  item_flags,
7220 								  error);
7221 			if (ret < 0)
7222 				return ret;
7223 			last_item = tunnel ?
7224 					MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
7225 					MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
7226 			if (items->mask != NULL &&
7227 			    ((const struct rte_flow_item_ipv6_frag_ext *)
7228 			     items->mask)->hdr.next_header) {
7229 				next_protocol =
7230 				((const struct rte_flow_item_ipv6_frag_ext *)
7231 				 items->spec)->hdr.next_header;
7232 				next_protocol &=
7233 				((const struct rte_flow_item_ipv6_frag_ext *)
7234 				 items->mask)->hdr.next_header;
7235 			} else {
7236 				/* Reset for inner layer. */
7237 				next_protocol = 0xff;
7238 			}
7239 			break;
7240 		case RTE_FLOW_ITEM_TYPE_TCP:
7241 			ret = mlx5_flow_validate_item_tcp
7242 						(items, item_flags,
7243 						 next_protocol,
7244 						 &nic_tcp_mask,
7245 						 error);
7246 			if (ret < 0)
7247 				return ret;
7248 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
7249 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
7250 			break;
7251 		case RTE_FLOW_ITEM_TYPE_UDP:
7252 			ret = mlx5_flow_validate_item_udp(items, item_flags,
7253 							  next_protocol,
7254 							  error);
7255 			const struct rte_flow_item_udp *spec = items->spec;
7256 			const struct rte_flow_item_udp *mask = items->mask;
7257 			if (!mask)
7258 				mask = &rte_flow_item_udp_mask;
7259 			if (spec != NULL)
7260 				udp_dport = rte_be_to_cpu_16
7261 						(spec->hdr.dst_port &
7262 						 mask->hdr.dst_port);
7263 			if (ret < 0)
7264 				return ret;
7265 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
7266 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
7267 			break;
7268 		case RTE_FLOW_ITEM_TYPE_GRE:
7269 			ret = mlx5_flow_validate_item_gre(items, item_flags,
7270 							  next_protocol, error);
7271 			if (ret < 0)
7272 				return ret;
7273 			gre_item = items;
7274 			last_item = MLX5_FLOW_LAYER_GRE;
7275 			break;
7276 		case RTE_FLOW_ITEM_TYPE_GRE_OPTION:
7277 			ret = mlx5_flow_validate_item_gre_option(dev, items, item_flags,
7278 							  attr, gre_item, error);
7279 			if (ret < 0)
7280 				return ret;
7281 			last_item = MLX5_FLOW_LAYER_GRE;
7282 			break;
7283 		case RTE_FLOW_ITEM_TYPE_NVGRE:
7284 			ret = mlx5_flow_validate_item_nvgre(items, item_flags,
7285 							    next_protocol,
7286 							    error);
7287 			if (ret < 0)
7288 				return ret;
7289 			last_item = MLX5_FLOW_LAYER_NVGRE;
7290 			break;
7291 		case RTE_FLOW_ITEM_TYPE_GRE_KEY:
7292 			ret = mlx5_flow_validate_item_gre_key
7293 				(items, item_flags, gre_item, error);
7294 			if (ret < 0)
7295 				return ret;
7296 			last_item = MLX5_FLOW_LAYER_GRE_KEY;
7297 			break;
7298 		case RTE_FLOW_ITEM_TYPE_VXLAN:
7299 			ret = mlx5_flow_validate_item_vxlan(dev, udp_dport,
7300 							    items, item_flags,
7301 							    is_root, error);
7302 			if (ret < 0)
7303 				return ret;
7304 			last_item = MLX5_FLOW_LAYER_VXLAN;
7305 			break;
7306 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
7307 			ret = mlx5_flow_validate_item_vxlan_gpe(items,
7308 								item_flags, dev,
7309 								error);
7310 			if (ret < 0)
7311 				return ret;
7312 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
7313 			break;
7314 		case RTE_FLOW_ITEM_TYPE_GENEVE:
7315 			ret = mlx5_flow_validate_item_geneve(items,
7316 							     item_flags, dev,
7317 							     error);
7318 			if (ret < 0)
7319 				return ret;
7320 			geneve_item = items;
7321 			last_item = MLX5_FLOW_LAYER_GENEVE;
7322 			break;
7323 		case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
7324 			ret = mlx5_flow_validate_item_geneve_opt(items,
7325 								 last_item,
7326 								 geneve_item,
7327 								 dev,
7328 								 error);
7329 			if (ret < 0)
7330 				return ret;
7331 			last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
7332 			break;
7333 		case RTE_FLOW_ITEM_TYPE_MPLS:
7334 			ret = mlx5_flow_validate_item_mpls(dev, items,
7335 							   item_flags,
7336 							   last_item, error);
7337 			if (ret < 0)
7338 				return ret;
7339 			last_item = MLX5_FLOW_LAYER_MPLS;
7340 			break;
7341 
7342 		case RTE_FLOW_ITEM_TYPE_MARK:
7343 			ret = flow_dv_validate_item_mark(dev, items, attr,
7344 							 error);
7345 			if (ret < 0)
7346 				return ret;
7347 			last_item = MLX5_FLOW_ITEM_MARK;
7348 			break;
7349 		case RTE_FLOW_ITEM_TYPE_META:
7350 			ret = flow_dv_validate_item_meta(dev, items, attr,
7351 							 error);
7352 			if (ret < 0)
7353 				return ret;
7354 			last_item = MLX5_FLOW_ITEM_METADATA;
7355 			break;
7356 		case RTE_FLOW_ITEM_TYPE_ICMP:
7357 			ret = mlx5_flow_validate_item_icmp(items, item_flags,
7358 							   next_protocol,
7359 							   error);
7360 			if (ret < 0)
7361 				return ret;
7362 			last_item = MLX5_FLOW_LAYER_ICMP;
7363 			break;
7364 		case RTE_FLOW_ITEM_TYPE_ICMP6:
7365 			ret = mlx5_flow_validate_item_icmp6(items, item_flags,
7366 							    next_protocol,
7367 							    error);
7368 			if (ret < 0)
7369 				return ret;
7370 			item_ipv6_proto = IPPROTO_ICMPV6;
7371 			last_item = MLX5_FLOW_LAYER_ICMP6;
7372 			break;
7373 		case RTE_FLOW_ITEM_TYPE_TAG:
7374 			ret = flow_dv_validate_item_tag(dev, items,
7375 							attr, error);
7376 			if (ret < 0)
7377 				return ret;
7378 			last_item = MLX5_FLOW_ITEM_TAG;
7379 			break;
7380 		case MLX5_RTE_FLOW_ITEM_TYPE_SQ:
7381 			last_item = MLX5_FLOW_ITEM_SQ;
7382 			break;
7383 		case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
7384 			break;
7385 		case RTE_FLOW_ITEM_TYPE_GTP:
7386 			ret = flow_dv_validate_item_gtp(dev, items, item_flags,
7387 							error);
7388 			if (ret < 0)
7389 				return ret;
7390 			gtp_item = items;
7391 			last_item = MLX5_FLOW_LAYER_GTP;
7392 			break;
7393 		case RTE_FLOW_ITEM_TYPE_GTP_PSC:
7394 			ret = flow_dv_validate_item_gtp_psc(items, last_item,
7395 							    gtp_item, is_root,
7396 							    error);
7397 			if (ret < 0)
7398 				return ret;
7399 			last_item = MLX5_FLOW_LAYER_GTP_PSC;
7400 			break;
7401 		case RTE_FLOW_ITEM_TYPE_ECPRI:
7402 			/* Capacity will be checked in the translate stage. */
7403 			ret = mlx5_flow_validate_item_ecpri(items, item_flags,
7404 							    last_item,
7405 							    ether_type,
7406 							    &nic_ecpri_mask,
7407 							    error);
7408 			if (ret < 0)
7409 				return ret;
7410 			last_item = MLX5_FLOW_LAYER_ECPRI;
7411 			break;
7412 		case RTE_FLOW_ITEM_TYPE_INTEGRITY:
7413 			ret = flow_dv_validate_item_integrity(dev, items,
7414 							      item_flags,
7415 							      &last_item,
7416 							      integrity_items,
7417 							      error);
7418 			if (ret < 0)
7419 				return ret;
7420 			break;
7421 		case RTE_FLOW_ITEM_TYPE_CONNTRACK:
7422 			ret = flow_dv_validate_item_aso_ct(dev, items,
7423 							   &item_flags, error);
7424 			if (ret < 0)
7425 				return ret;
7426 			break;
7427 		case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL:
7428 			/* tunnel offload item was processed before
7429 			 * list it here as a supported type
7430 			 */
7431 			break;
7432 		case RTE_FLOW_ITEM_TYPE_FLEX:
7433 			ret = flow_dv_validate_item_flex(dev, items, item_flags,
7434 							 &last_item,
7435 							 tunnel != 0, error);
7436 			if (ret < 0)
7437 				return ret;
7438 			break;
7439 		case RTE_FLOW_ITEM_TYPE_METER_COLOR:
7440 			ret = flow_dv_validate_item_meter_color(dev, items,
7441 								attr, error);
7442 			if (ret < 0)
7443 				return ret;
7444 			last_item = MLX5_FLOW_ITEM_METER_COLOR;
7445 			break;
7446 		default:
7447 			return rte_flow_error_set(error, ENOTSUP,
7448 						  RTE_FLOW_ERROR_TYPE_ITEM,
7449 						  NULL, "item not supported");
7450 		}
7451 		item_flags |= last_item;
7452 	}
7453 	if (item_flags & MLX5_FLOW_ITEM_INTEGRITY) {
7454 		ret = flow_dv_validate_item_integrity_post(integrity_items,
7455 							   item_flags, error);
7456 		if (ret)
7457 			return ret;
7458 	}
7459 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
7460 		int type = actions->type;
7461 
7462 		if (!mlx5_flow_os_action_supported(type))
7463 			return rte_flow_error_set(error, ENOTSUP,
7464 						  RTE_FLOW_ERROR_TYPE_ACTION,
7465 						  actions,
7466 						  "action not supported");
7467 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
7468 			return rte_flow_error_set(error, ENOTSUP,
7469 						  RTE_FLOW_ERROR_TYPE_ACTION,
7470 						  actions, "too many actions");
7471 		if (action_flags &
7472 			MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
7473 			return rte_flow_error_set(error, ENOTSUP,
7474 				RTE_FLOW_ERROR_TYPE_ACTION,
7475 				NULL, "meter action with policy "
7476 				"must be the last action");
7477 		switch (type) {
7478 		case RTE_FLOW_ACTION_TYPE_VOID:
7479 			break;
7480 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
7481 		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
7482 			ret = flow_dv_validate_action_port_id(dev,
7483 							      action_flags,
7484 							      actions,
7485 							      attr,
7486 							      error);
7487 			if (ret)
7488 				return ret;
7489 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
7490 			++actions_n;
7491 			break;
7492 		case RTE_FLOW_ACTION_TYPE_FLAG:
7493 			ret = flow_dv_validate_action_flag(dev, action_flags,
7494 							   attr, error);
7495 			if (ret < 0)
7496 				return ret;
7497 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7498 				/* Count all modify-header actions as one. */
7499 				if (!(action_flags &
7500 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
7501 					++actions_n;
7502 				action_flags |= MLX5_FLOW_ACTION_FLAG |
7503 						MLX5_FLOW_ACTION_MARK_EXT;
7504 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7505 					modify_after_mirror = 1;
7506 
7507 			} else {
7508 				action_flags |= MLX5_FLOW_ACTION_FLAG;
7509 				++actions_n;
7510 			}
7511 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
7512 			break;
7513 		case RTE_FLOW_ACTION_TYPE_MARK:
7514 			ret = flow_dv_validate_action_mark(dev, actions,
7515 							   action_flags,
7516 							   attr, error);
7517 			if (ret < 0)
7518 				return ret;
7519 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
7520 				/* Count all modify-header actions as one. */
7521 				if (!(action_flags &
7522 				      MLX5_FLOW_MODIFY_HDR_ACTIONS))
7523 					++actions_n;
7524 				action_flags |= MLX5_FLOW_ACTION_MARK |
7525 						MLX5_FLOW_ACTION_MARK_EXT;
7526 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7527 					modify_after_mirror = 1;
7528 			} else {
7529 				action_flags |= MLX5_FLOW_ACTION_MARK;
7530 				++actions_n;
7531 			}
7532 			rw_act_num += MLX5_ACT_NUM_SET_MARK;
7533 			break;
7534 		case RTE_FLOW_ACTION_TYPE_SET_META:
7535 			ret = flow_dv_validate_action_set_meta(dev, actions,
7536 							       action_flags,
7537 							       attr, error);
7538 			if (ret < 0)
7539 				return ret;
7540 			/* Count all modify-header actions as one action. */
7541 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7542 				++actions_n;
7543 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7544 				modify_after_mirror = 1;
7545 			action_flags |= MLX5_FLOW_ACTION_SET_META;
7546 			rw_act_num += MLX5_ACT_NUM_SET_META;
7547 			break;
7548 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
7549 			ret = flow_dv_validate_action_set_tag(dev, actions,
7550 							      action_flags,
7551 							      attr, error);
7552 			if (ret < 0)
7553 				return ret;
7554 			/* Count all modify-header actions as one action. */
7555 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7556 				++actions_n;
7557 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7558 				modify_after_mirror = 1;
7559 			tag_id = ((const struct rte_flow_action_set_tag *)
7560 				  actions->conf)->index;
7561 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
7562 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7563 			break;
7564 		case RTE_FLOW_ACTION_TYPE_DROP:
7565 			ret = mlx5_flow_validate_action_drop(action_flags,
7566 							     attr, error);
7567 			if (ret < 0)
7568 				return ret;
7569 			action_flags |= MLX5_FLOW_ACTION_DROP;
7570 			++actions_n;
7571 			break;
7572 		case RTE_FLOW_ACTION_TYPE_QUEUE:
7573 			ret = mlx5_flow_validate_action_queue(actions,
7574 							      action_flags, dev,
7575 							      attr, error);
7576 			if (ret < 0)
7577 				return ret;
7578 			queue_index = ((const struct rte_flow_action_queue *)
7579 							(actions->conf))->index;
7580 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
7581 			++actions_n;
7582 			break;
7583 		case RTE_FLOW_ACTION_TYPE_RSS:
7584 			rss = actions->conf;
7585 			ret = mlx5_flow_validate_action_rss(actions,
7586 							    action_flags, dev,
7587 							    attr, item_flags,
7588 							    error);
7589 			if (ret < 0)
7590 				return ret;
7591 			if (rss && sample_rss &&
7592 			    (sample_rss->level != rss->level ||
7593 			    sample_rss->types != rss->types))
7594 				return rte_flow_error_set(error, ENOTSUP,
7595 					RTE_FLOW_ERROR_TYPE_ACTION,
7596 					NULL,
7597 					"Can't use the different RSS types "
7598 					"or level in the same flow");
7599 			if (rss != NULL && rss->queue_num)
7600 				queue_index = rss->queue[0];
7601 			action_flags |= MLX5_FLOW_ACTION_RSS;
7602 			++actions_n;
7603 			break;
7604 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
7605 			ret =
7606 			mlx5_flow_validate_action_default_miss(action_flags,
7607 					attr, error);
7608 			if (ret < 0)
7609 				return ret;
7610 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
7611 			++actions_n;
7612 			break;
7613 		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
7614 			shared_count = true;
7615 			/* fall-through. */
7616 		case RTE_FLOW_ACTION_TYPE_COUNT:
7617 			ret = flow_dv_validate_action_count(dev, shared_count,
7618 							    action_flags,
7619 							    is_root, error);
7620 			if (ret < 0)
7621 				return ret;
7622 			count = actions->conf;
7623 			action_flags |= MLX5_FLOW_ACTION_COUNT;
7624 			++actions_n;
7625 			break;
7626 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
7627 			if (flow_dv_validate_action_pop_vlan(dev,
7628 							     action_flags,
7629 							     actions,
7630 							     item_flags, attr,
7631 							     error))
7632 				return -rte_errno;
7633 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7634 				modify_after_mirror = 1;
7635 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
7636 			++actions_n;
7637 			break;
7638 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
7639 			ret = flow_dv_validate_action_push_vlan(dev,
7640 								action_flags,
7641 								vlan_m,
7642 								actions, attr,
7643 								error);
7644 			if (ret < 0)
7645 				return ret;
7646 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7647 				modify_after_mirror = 1;
7648 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
7649 			++actions_n;
7650 			break;
7651 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
7652 			ret = flow_dv_validate_action_set_vlan_pcp
7653 						(action_flags, actions, error);
7654 			if (ret < 0)
7655 				return ret;
7656 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7657 				modify_after_mirror = 1;
7658 			/* Count PCP with push_vlan command. */
7659 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_PCP;
7660 			break;
7661 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
7662 			ret = flow_dv_validate_action_set_vlan_vid
7663 						(item_flags, action_flags,
7664 						 actions, error);
7665 			if (ret < 0)
7666 				return ret;
7667 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7668 				modify_after_mirror = 1;
7669 			/* Count VID with push_vlan command. */
7670 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
7671 			rw_act_num += MLX5_ACT_NUM_MDF_VID;
7672 			break;
7673 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
7674 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
7675 			ret = flow_dv_validate_action_l2_encap(dev,
7676 							       action_flags,
7677 							       actions, attr,
7678 							       error);
7679 			if (ret < 0)
7680 				return ret;
7681 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
7682 			++actions_n;
7683 			break;
7684 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
7685 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
7686 			ret = flow_dv_validate_action_decap(dev, action_flags,
7687 							    actions, item_flags,
7688 							    attr, error);
7689 			if (ret < 0)
7690 				return ret;
7691 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7692 				modify_after_mirror = 1;
7693 			action_flags |= MLX5_FLOW_ACTION_DECAP;
7694 			++actions_n;
7695 			break;
7696 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
7697 			ret = flow_dv_validate_action_raw_encap_decap
7698 				(dev, NULL, actions->conf, attr, &action_flags,
7699 				 &actions_n, actions, item_flags, error);
7700 			if (ret < 0)
7701 				return ret;
7702 			break;
7703 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
7704 			decap = actions->conf;
7705 			while ((++actions)->type == RTE_FLOW_ACTION_TYPE_VOID)
7706 				;
7707 			if (actions->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
7708 				encap = NULL;
7709 				actions--;
7710 			} else {
7711 				encap = actions->conf;
7712 			}
7713 			ret = flow_dv_validate_action_raw_encap_decap
7714 					   (dev,
7715 					    decap ? decap : &empty_decap, encap,
7716 					    attr, &action_flags, &actions_n,
7717 					    actions, item_flags, error);
7718 			if (ret < 0)
7719 				return ret;
7720 			if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) &&
7721 			    (action_flags & MLX5_FLOW_ACTION_DECAP))
7722 				modify_after_mirror = 1;
7723 			break;
7724 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
7725 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
7726 			ret = flow_dv_validate_action_modify_mac(action_flags,
7727 								 actions,
7728 								 item_flags,
7729 								 error);
7730 			if (ret < 0)
7731 				return ret;
7732 			/* Count all modify-header actions as one action. */
7733 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7734 				++actions_n;
7735 			action_flags |= actions->type ==
7736 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
7737 						MLX5_FLOW_ACTION_SET_MAC_SRC :
7738 						MLX5_FLOW_ACTION_SET_MAC_DST;
7739 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7740 				modify_after_mirror = 1;
7741 			/*
7742 			 * Even if the source and destination MAC addresses have
7743 			 * overlap in the header with 4B alignment, the convert
7744 			 * function will handle them separately and 4 SW actions
7745 			 * will be created. And 2 actions will be added each
7746 			 * time no matter how many bytes of address will be set.
7747 			 */
7748 			rw_act_num += MLX5_ACT_NUM_MDF_MAC;
7749 			break;
7750 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
7751 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
7752 			ret = flow_dv_validate_action_modify_ipv4(action_flags,
7753 								  actions,
7754 								  item_flags,
7755 								  error);
7756 			if (ret < 0)
7757 				return ret;
7758 			/* Count all modify-header actions as one action. */
7759 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7760 				++actions_n;
7761 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7762 				modify_after_mirror = 1;
7763 			action_flags |= actions->type ==
7764 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
7765 						MLX5_FLOW_ACTION_SET_IPV4_SRC :
7766 						MLX5_FLOW_ACTION_SET_IPV4_DST;
7767 			rw_act_num += MLX5_ACT_NUM_MDF_IPV4;
7768 			break;
7769 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
7770 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
7771 			ret = flow_dv_validate_action_modify_ipv6(action_flags,
7772 								  actions,
7773 								  item_flags,
7774 								  error);
7775 			if (ret < 0)
7776 				return ret;
7777 			if (item_ipv6_proto == IPPROTO_ICMPV6)
7778 				return rte_flow_error_set(error, ENOTSUP,
7779 					RTE_FLOW_ERROR_TYPE_ACTION,
7780 					actions,
7781 					"Can't change header "
7782 					"with ICMPv6 proto");
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 |= actions->type ==
7789 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
7790 						MLX5_FLOW_ACTION_SET_IPV6_SRC :
7791 						MLX5_FLOW_ACTION_SET_IPV6_DST;
7792 			rw_act_num += MLX5_ACT_NUM_MDF_IPV6;
7793 			break;
7794 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
7795 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
7796 			ret = flow_dv_validate_action_modify_tp(action_flags,
7797 								actions,
7798 								item_flags,
7799 								error);
7800 			if (ret < 0)
7801 				return ret;
7802 			/* Count all modify-header actions as one action. */
7803 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7804 				++actions_n;
7805 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7806 				modify_after_mirror = 1;
7807 			action_flags |= actions->type ==
7808 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
7809 						MLX5_FLOW_ACTION_SET_TP_SRC :
7810 						MLX5_FLOW_ACTION_SET_TP_DST;
7811 			rw_act_num += MLX5_ACT_NUM_MDF_PORT;
7812 			break;
7813 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
7814 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
7815 			ret = flow_dv_validate_action_modify_ttl(action_flags,
7816 								 actions,
7817 								 item_flags,
7818 								 error);
7819 			if (ret < 0)
7820 				return ret;
7821 			/* Count all modify-header actions as one action. */
7822 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7823 				++actions_n;
7824 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7825 				modify_after_mirror = 1;
7826 			action_flags |= actions->type ==
7827 					RTE_FLOW_ACTION_TYPE_SET_TTL ?
7828 						MLX5_FLOW_ACTION_SET_TTL :
7829 						MLX5_FLOW_ACTION_DEC_TTL;
7830 			rw_act_num += MLX5_ACT_NUM_MDF_TTL;
7831 			break;
7832 		case RTE_FLOW_ACTION_TYPE_JUMP:
7833 			ret = flow_dv_validate_action_jump(dev, tunnel, actions,
7834 							   action_flags,
7835 							   attr, external,
7836 							   error);
7837 			if (ret)
7838 				return ret;
7839 			++actions_n;
7840 			action_flags |= MLX5_FLOW_ACTION_JUMP;
7841 			break;
7842 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
7843 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
7844 			ret = flow_dv_validate_action_modify_tcp_seq
7845 								(action_flags,
7846 								 actions,
7847 								 item_flags,
7848 								 error);
7849 			if (ret < 0)
7850 				return ret;
7851 			/* Count all modify-header actions as one action. */
7852 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7853 				++actions_n;
7854 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7855 				modify_after_mirror = 1;
7856 			action_flags |= actions->type ==
7857 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
7858 						MLX5_FLOW_ACTION_INC_TCP_SEQ :
7859 						MLX5_FLOW_ACTION_DEC_TCP_SEQ;
7860 			rw_act_num += MLX5_ACT_NUM_MDF_TCPSEQ;
7861 			break;
7862 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
7863 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
7864 			ret = flow_dv_validate_action_modify_tcp_ack
7865 								(action_flags,
7866 								 actions,
7867 								 item_flags,
7868 								 error);
7869 			if (ret < 0)
7870 				return ret;
7871 			/* Count all modify-header actions as one action. */
7872 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7873 				++actions_n;
7874 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7875 				modify_after_mirror = 1;
7876 			action_flags |= actions->type ==
7877 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
7878 						MLX5_FLOW_ACTION_INC_TCP_ACK :
7879 						MLX5_FLOW_ACTION_DEC_TCP_ACK;
7880 			rw_act_num += MLX5_ACT_NUM_MDF_TCPACK;
7881 			break;
7882 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
7883 			break;
7884 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
7885 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
7886 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7887 			break;
7888 		case RTE_FLOW_ACTION_TYPE_METER:
7889 			ret = mlx5_flow_validate_action_meter(dev,
7890 							      action_flags,
7891 							      item_flags,
7892 							      actions, attr,
7893 							      port_id_item,
7894 							      &def_policy,
7895 							      error);
7896 			if (ret < 0)
7897 				return ret;
7898 			action_flags |= MLX5_FLOW_ACTION_METER;
7899 			if (!def_policy)
7900 				action_flags |=
7901 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
7902 			++actions_n;
7903 			/* Meter action will add one more TAG action. */
7904 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
7905 			break;
7906 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
7907 			if (is_root)
7908 				return rte_flow_error_set(error, ENOTSUP,
7909 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
7910 									   NULL,
7911 			  "Shared ASO age action is not supported for group 0");
7912 			if (action_flags & MLX5_FLOW_ACTION_AGE)
7913 				return rte_flow_error_set
7914 						  (error, EINVAL,
7915 						   RTE_FLOW_ERROR_TYPE_ACTION,
7916 						   NULL,
7917 						   "duplicate age actions set");
7918 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7919 				aso_after_sample = 1;
7920 			action_flags |= MLX5_FLOW_ACTION_AGE;
7921 			++actions_n;
7922 			break;
7923 		case RTE_FLOW_ACTION_TYPE_AGE:
7924 			non_shared_age = actions->conf;
7925 			ret = flow_dv_validate_action_age(action_flags,
7926 							  actions, dev,
7927 							  error);
7928 			if (ret < 0)
7929 				return ret;
7930 			/*
7931 			 * Validate the regular AGE action (using counter)
7932 			 * mutual exclusion with indirect counter actions.
7933 			 */
7934 			if (!flow_hit_aso_supported(priv, is_root)) {
7935 				if (shared_count)
7936 					return rte_flow_error_set
7937 						(error, EINVAL,
7938 						RTE_FLOW_ERROR_TYPE_ACTION,
7939 						NULL,
7940 						"old age and indirect count combination is not supported");
7941 				if (sample_count)
7942 					return rte_flow_error_set
7943 						(error, EINVAL,
7944 						RTE_FLOW_ERROR_TYPE_ACTION,
7945 						NULL,
7946 						"old age action and count must be in the same sub flow");
7947 			} else {
7948 				if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7949 					aso_after_sample = 1;
7950 			}
7951 			action_flags |= MLX5_FLOW_ACTION_AGE;
7952 			++actions_n;
7953 			break;
7954 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
7955 			ret = flow_dv_validate_action_modify_ipv4_dscp
7956 							 (action_flags,
7957 							  actions,
7958 							  item_flags,
7959 							  error);
7960 			if (ret < 0)
7961 				return ret;
7962 			/* Count all modify-header actions as one action. */
7963 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7964 				++actions_n;
7965 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7966 				modify_after_mirror = 1;
7967 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
7968 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7969 			break;
7970 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
7971 			ret = flow_dv_validate_action_modify_ipv6_dscp
7972 								(action_flags,
7973 								 actions,
7974 								 item_flags,
7975 								 error);
7976 			if (ret < 0)
7977 				return ret;
7978 			/* Count all modify-header actions as one action. */
7979 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
7980 				++actions_n;
7981 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
7982 				modify_after_mirror = 1;
7983 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
7984 			rw_act_num += MLX5_ACT_NUM_SET_DSCP;
7985 			break;
7986 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
7987 			ret = flow_dv_validate_action_sample(&action_flags,
7988 							     actions, dev,
7989 							     attr, item_flags,
7990 							     rss, &sample_rss,
7991 							     &sample_count,
7992 							     &fdb_mirror,
7993 							     is_root,
7994 							     error);
7995 			if (ret < 0)
7996 				return ret;
7997 			if ((action_flags & MLX5_FLOW_ACTION_SET_TAG) &&
7998 			    tag_id == 0 && priv->mtr_color_reg == REG_NON)
7999 				return rte_flow_error_set(error, EINVAL,
8000 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8001 					"sample after tag action causes metadata tag index 0 corruption");
8002 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
8003 			++actions_n;
8004 			break;
8005 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
8006 			ret = flow_dv_validate_action_modify_field(dev,
8007 								   action_flags,
8008 								   actions,
8009 								   attr,
8010 								   is_root,
8011 								   error);
8012 			if (ret < 0)
8013 				return ret;
8014 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
8015 				modify_after_mirror = 1;
8016 			/* Count all modify-header actions as one action. */
8017 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
8018 				++actions_n;
8019 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
8020 			rw_act_num += ret;
8021 			break;
8022 		case RTE_FLOW_ACTION_TYPE_CONNTRACK:
8023 			ret = flow_dv_validate_action_aso_ct(dev, action_flags,
8024 							     item_flags,
8025 							     is_root, error);
8026 			if (ret < 0)
8027 				return ret;
8028 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
8029 				aso_after_sample = 1;
8030 			action_flags |= MLX5_FLOW_ACTION_CT;
8031 			break;
8032 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
8033 			/* tunnel offload action was processed before
8034 			 * list it here as a supported type
8035 			 */
8036 			break;
8037 #ifdef HAVE_MLX5DV_DR_ACTION_CREATE_DEST_ROOT_TABLE
8038 		case RTE_FLOW_ACTION_TYPE_SEND_TO_KERNEL:
8039 			action_flags |= MLX5_FLOW_ACTION_SEND_TO_KERNEL;
8040 			++actions_n;
8041 			break;
8042 #endif
8043 		default:
8044 			return rte_flow_error_set(error, ENOTSUP,
8045 						  RTE_FLOW_ERROR_TYPE_ACTION,
8046 						  actions,
8047 						  "action not supported");
8048 		}
8049 	}
8050 	/*
8051 	 * Validate actions in flow rules
8052 	 * - Explicit decap action is prohibited by the tunnel offload API.
8053 	 * - Drop action in tunnel steer rule is prohibited by the API.
8054 	 * - Application cannot use MARK action because it's value can mask
8055 	 *   tunnel default miss notification.
8056 	 * - JUMP in tunnel match rule has no support in current PMD
8057 	 *   implementation.
8058 	 * - TAG & META are reserved for future uses.
8059 	 */
8060 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_SET) {
8061 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_DECAP    |
8062 					    MLX5_FLOW_ACTION_MARK     |
8063 					    MLX5_FLOW_ACTION_SET_TAG  |
8064 					    MLX5_FLOW_ACTION_SET_META |
8065 					    MLX5_FLOW_ACTION_DROP;
8066 
8067 		if (action_flags & bad_actions_mask)
8068 			return rte_flow_error_set
8069 					(error, EINVAL,
8070 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8071 					"Invalid RTE action in tunnel "
8072 					"set decap rule");
8073 		if (!(action_flags & MLX5_FLOW_ACTION_JUMP))
8074 			return rte_flow_error_set
8075 					(error, EINVAL,
8076 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8077 					"tunnel set decap rule must terminate "
8078 					"with JUMP");
8079 		if (attr->egress)
8080 			return rte_flow_error_set
8081 					(error, EINVAL,
8082 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8083 					"tunnel flows for ingress and transfer traffic only");
8084 	}
8085 	if (action_flags & MLX5_FLOW_ACTION_TUNNEL_MATCH) {
8086 		uint64_t bad_actions_mask = MLX5_FLOW_ACTION_JUMP    |
8087 					    MLX5_FLOW_ACTION_MARK    |
8088 					    MLX5_FLOW_ACTION_SET_TAG |
8089 					    MLX5_FLOW_ACTION_SET_META;
8090 
8091 		if (action_flags & bad_actions_mask)
8092 			return rte_flow_error_set
8093 					(error, EINVAL,
8094 					RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8095 					"Invalid RTE action in tunnel "
8096 					"set match rule");
8097 	}
8098 	/*
8099 	 * Validate the drop action mutual exclusion with other actions.
8100 	 * Drop action is mutually-exclusive with any other action, except for
8101 	 * Count/Sample/Age actions.
8102 	 * Drop action compatibility with tunnel offload was already validated.
8103 	 */
8104 	if (action_flags & (MLX5_FLOW_ACTION_TUNNEL_MATCH |
8105 			    MLX5_FLOW_ACTION_TUNNEL_MATCH));
8106 	else if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
8107 	    (action_flags & ~(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_DROP_INCLUSIVE_ACTIONS)))
8108 		return rte_flow_error_set(error, EINVAL,
8109 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8110 					  "Drop action is mutually-exclusive "
8111 					  "with any other action, except for "
8112 					  "Count/Sample/Age action");
8113 	/* Eswitch has few restrictions on using items and actions */
8114 	if (attr->transfer) {
8115 		if (!mlx5_flow_ext_mreg_supported(dev) &&
8116 		    action_flags & MLX5_FLOW_ACTION_FLAG)
8117 			return rte_flow_error_set(error, ENOTSUP,
8118 						  RTE_FLOW_ERROR_TYPE_ACTION,
8119 						  NULL,
8120 						  "unsupported action FLAG");
8121 		if (!mlx5_flow_ext_mreg_supported(dev) &&
8122 		    action_flags & MLX5_FLOW_ACTION_MARK)
8123 			return rte_flow_error_set(error, ENOTSUP,
8124 						  RTE_FLOW_ERROR_TYPE_ACTION,
8125 						  NULL,
8126 						  "unsupported action MARK");
8127 		if (action_flags & MLX5_FLOW_ACTION_QUEUE)
8128 			return rte_flow_error_set(error, ENOTSUP,
8129 						  RTE_FLOW_ERROR_TYPE_ACTION,
8130 						  NULL,
8131 						  "unsupported action QUEUE");
8132 		if (action_flags & MLX5_FLOW_ACTION_RSS)
8133 			return rte_flow_error_set(error, ENOTSUP,
8134 						  RTE_FLOW_ERROR_TYPE_ACTION,
8135 						  NULL,
8136 						  "unsupported action RSS");
8137 		if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
8138 			return rte_flow_error_set(error, EINVAL,
8139 						  RTE_FLOW_ERROR_TYPE_ACTION,
8140 						  actions,
8141 						  "no fate action is found");
8142 	} else {
8143 		if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress)
8144 			return rte_flow_error_set(error, EINVAL,
8145 						  RTE_FLOW_ERROR_TYPE_ACTION,
8146 						  actions,
8147 						  "no fate action is found");
8148 	}
8149 	/*
8150 	 * Continue validation for Xcap and VLAN actions.
8151 	 * If hairpin is working in explicit TX rule mode, there is no actions
8152 	 * splitting and the validation of hairpin ingress flow should be the
8153 	 * same as other standard flows.
8154 	 */
8155 	if ((action_flags & (MLX5_FLOW_XCAP_ACTIONS |
8156 			     MLX5_FLOW_VLAN_ACTIONS)) &&
8157 	    (queue_index == 0xFFFF || !mlx5_rxq_is_hairpin(dev, queue_index) ||
8158 	     ((conf = mlx5_rxq_get_hairpin_conf(dev, queue_index)) != NULL &&
8159 	     conf->tx_explicit != 0))) {
8160 		if ((action_flags & MLX5_FLOW_XCAP_ACTIONS) ==
8161 		    MLX5_FLOW_XCAP_ACTIONS)
8162 			return rte_flow_error_set(error, ENOTSUP,
8163 						  RTE_FLOW_ERROR_TYPE_ACTION,
8164 						  NULL, "encap and decap "
8165 						  "combination aren't supported");
8166 		/* Push VLAN is not supported in ingress except for NICs newer than CX5. */
8167 		if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN) {
8168 			struct mlx5_dev_ctx_shared *sh = priv->sh;
8169 			bool direction_error = false;
8170 
8171 			if (attr->transfer) {
8172 				bool fdb_tx = flow_source_vport_representor(priv, act_priv);
8173 				bool is_cx5 = sh->steering_format_version ==
8174 				    MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
8175 
8176 				if (!fdb_tx && is_cx5)
8177 					direction_error = true;
8178 			} else if (attr->ingress) {
8179 				direction_error = true;
8180 			}
8181 			if (direction_error)
8182 				return rte_flow_error_set(error, ENOTSUP,
8183 							  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
8184 							  NULL,
8185 							  "push VLAN action not supported "
8186 							  "for ingress");
8187 		}
8188 		if (attr->ingress) {
8189 			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
8190 				return rte_flow_error_set
8191 						(error, ENOTSUP,
8192 						 RTE_FLOW_ERROR_TYPE_ACTION,
8193 						 NULL, "encap is not supported"
8194 						 " for ingress traffic");
8195 			else if ((action_flags & MLX5_FLOW_VLAN_ACTIONS) ==
8196 					MLX5_FLOW_VLAN_ACTIONS)
8197 				return rte_flow_error_set
8198 						(error, ENOTSUP,
8199 						 RTE_FLOW_ERROR_TYPE_ACTION,
8200 						 NULL, "no support for "
8201 						 "multiple VLAN actions");
8202 		}
8203 	}
8204 	/* Pop VLAN is not supported in egress except for NICs newer than CX5. */
8205 	if (action_flags & MLX5_FLOW_ACTION_OF_POP_VLAN) {
8206 		struct mlx5_dev_ctx_shared *sh = priv->sh;
8207 		bool direction_error = false;
8208 
8209 		if (attr->transfer) {
8210 			bool fdb_tx = flow_source_vport_representor(priv, act_priv);
8211 			bool is_cx5 = sh->steering_format_version ==
8212 					MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5;
8213 
8214 			if (fdb_tx && is_cx5)
8215 				direction_error = true;
8216 		} else if (attr->egress) {
8217 			direction_error = true;
8218 		}
8219 		if (direction_error)
8220 			return rte_flow_error_set(error, ENOTSUP,
8221 						RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
8222 						NULL,
8223 						"pop vlan action not supported for egress");
8224 	}
8225 	if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) {
8226 		if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
8227 			~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) &&
8228 			attr->ingress)
8229 			return rte_flow_error_set
8230 				(error, ENOTSUP,
8231 				RTE_FLOW_ERROR_TYPE_ACTION,
8232 				NULL, "fate action not supported for "
8233 				"meter with policy");
8234 		if (attr->egress) {
8235 			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
8236 				return rte_flow_error_set
8237 					(error, ENOTSUP,
8238 					RTE_FLOW_ERROR_TYPE_ACTION,
8239 					NULL, "modify header action in egress "
8240 					"cannot be done before meter action");
8241 			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
8242 				return rte_flow_error_set
8243 					(error, ENOTSUP,
8244 					RTE_FLOW_ERROR_TYPE_ACTION,
8245 					NULL, "encap action in egress "
8246 					"cannot be done before meter action");
8247 			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
8248 				return rte_flow_error_set
8249 					(error, ENOTSUP,
8250 					RTE_FLOW_ERROR_TYPE_ACTION,
8251 					NULL, "push vlan action in egress "
8252 					"cannot be done before meter action");
8253 		}
8254 	}
8255 	/*
8256 	 * Only support one ASO action in a single flow rule.
8257 	 * non-shared AGE + counter will fallback to use HW counter, no ASO hit object.
8258 	 * Group 0 uses HW counter for AGE too even if no counter action.
8259 	 */
8260 	aso_mask = (action_flags & MLX5_FLOW_ACTION_METER && priv->sh->meter_aso_en) << 2 |
8261 		   (action_flags & MLX5_FLOW_ACTION_CT && priv->sh->ct_aso_en) << 1 |
8262 		   (action_flags & MLX5_FLOW_ACTION_AGE &&
8263 		    !(non_shared_age && count) &&
8264 		    (attr->group || (attr->transfer && priv->fdb_def_rule)) &&
8265 		    priv->sh->flow_hit_aso_en);
8266 	if (__builtin_popcountl(aso_mask) > 1)
8267 		return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
8268 					  NULL, "unsupported combining AGE, METER, CT ASO actions in a single rule");
8269 	/*
8270 	 * Hairpin flow will add one more TAG action in TX implicit mode.
8271 	 * In TX explicit mode, there will be no hairpin flow ID.
8272 	 */
8273 	if (hairpin > 0)
8274 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
8275 	/* extra metadata enabled: one more TAG action will be add. */
8276 	if (dev_conf->dv_flow_en &&
8277 	    dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY &&
8278 	    mlx5_flow_ext_mreg_supported(dev))
8279 		rw_act_num += MLX5_ACT_NUM_SET_TAG;
8280 	if (rw_act_num >
8281 			flow_dv_modify_hdr_action_max(dev, is_root)) {
8282 		return rte_flow_error_set(error, ENOTSUP,
8283 					  RTE_FLOW_ERROR_TYPE_ACTION,
8284 					  NULL, "too many header modify"
8285 					  " actions to support");
8286 	}
8287 	if (fdb_mirror) {
8288 		if (!priv->sh->cdev->config.hca_attr.reg_c_preserve &&
8289 		    flow_source_vport_representor(priv, act_priv)) {
8290 			/* Eswitch egress mirror and modify flow has limitation on CX5 */
8291 			if (modify_after_mirror)
8292 				return rte_flow_error_set(error, EINVAL,
8293 						RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8294 						"sample before modify action is not supported");
8295 			if (action_flags & MLX5_FLOW_ACTION_JUMP)
8296 				return rte_flow_error_set(error, EINVAL,
8297 							RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8298 							"sample and jump action combination is not supported");
8299 		}
8300 		if (aso_mask > 0 && aso_after_sample && fdb_mirror)
8301 			return rte_flow_error_set(error, ENOTSUP,
8302 						  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
8303 						  "sample before ASO action is not supported");
8304 	}
8305 	/*
8306 	 * Validation the NIC Egress flow on representor, except implicit
8307 	 * hairpin default egress flow with TX_QUEUE item, other flows not
8308 	 * work due to metadata regC0 mismatch.
8309 	 */
8310 	if (attr->egress && priv->representor && !(item_flags & MLX5_FLOW_ITEM_SQ))
8311 		return rte_flow_error_set(error, EINVAL,
8312 					  RTE_FLOW_ERROR_TYPE_ITEM,
8313 					  NULL,
8314 					  "NIC egress rules on representors"
8315 					  " is not supported");
8316 	return 0;
8317 }
8318 
8319 /**
8320  * Internal preparation function. Allocates the DV flow size,
8321  * this size is constant.
8322  *
8323  * @param[in] dev
8324  *   Pointer to the rte_eth_dev structure.
8325  * @param[in] attr
8326  *   Pointer to the flow attributes.
8327  * @param[in] items
8328  *   Pointer to the list of items.
8329  * @param[in] actions
8330  *   Pointer to the list of actions.
8331  * @param[out] error
8332  *   Pointer to the error structure.
8333  *
8334  * @return
8335  *   Pointer to mlx5_flow object on success,
8336  *   otherwise NULL and rte_errno is set.
8337  */
8338 static struct mlx5_flow *
8339 flow_dv_prepare(struct rte_eth_dev *dev,
8340 		const struct rte_flow_attr *attr __rte_unused,
8341 		const struct rte_flow_item items[] __rte_unused,
8342 		const struct rte_flow_action actions[] __rte_unused,
8343 		struct rte_flow_error *error)
8344 {
8345 	uint32_t handle_idx = 0;
8346 	struct mlx5_flow *dev_flow;
8347 	struct mlx5_flow_handle *dev_handle;
8348 	struct mlx5_priv *priv = dev->data->dev_private;
8349 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
8350 
8351 	MLX5_ASSERT(wks);
8352 	wks->skip_matcher_reg = 0;
8353 	wks->policy = NULL;
8354 	wks->final_policy = NULL;
8355 	wks->vport_meta_tag = 0;
8356 	/* In case of corrupting the memory. */
8357 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
8358 		rte_flow_error_set(error, ENOSPC,
8359 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8360 				   "not free temporary device flow");
8361 		return NULL;
8362 	}
8363 	dev_handle = mlx5_ipool_zmalloc(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
8364 				   &handle_idx);
8365 	if (!dev_handle) {
8366 		rte_flow_error_set(error, ENOMEM,
8367 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
8368 				   "not enough memory to create flow handle");
8369 		return NULL;
8370 	}
8371 	MLX5_ASSERT(wks->flow_idx < RTE_DIM(wks->flows));
8372 	dev_flow = &wks->flows[wks->flow_idx++];
8373 	memset(dev_flow, 0, sizeof(*dev_flow));
8374 	dev_flow->handle = dev_handle;
8375 	dev_flow->handle_idx = handle_idx;
8376 	dev_flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
8377 	dev_flow->ingress = attr->ingress;
8378 	dev_flow->dv.transfer = attr->transfer;
8379 	return dev_flow;
8380 }
8381 
8382 #ifdef RTE_LIBRTE_MLX5_DEBUG
8383 /**
8384  * Sanity check for match mask and value. Similar to check_valid_spec() in
8385  * kernel driver. If unmasked bit is present in value, it returns failure.
8386  *
8387  * @param match_mask
8388  *   pointer to match mask buffer.
8389  * @param match_value
8390  *   pointer to match value buffer.
8391  *
8392  * @return
8393  *   0 if valid, -EINVAL otherwise.
8394  */
8395 static int
8396 flow_dv_check_valid_spec(void *match_mask, void *match_value)
8397 {
8398 	uint8_t *m = match_mask;
8399 	uint8_t *v = match_value;
8400 	unsigned int i;
8401 
8402 	for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) {
8403 		if (v[i] & ~m[i]) {
8404 			DRV_LOG(ERR,
8405 				"match_value differs from match_criteria"
8406 				" %p[%u] != %p[%u]",
8407 				match_value, i, match_mask, i);
8408 			return -EINVAL;
8409 		}
8410 	}
8411 	return 0;
8412 }
8413 #endif
8414 
8415 /**
8416  * Add match of ip_version.
8417  *
8418  * @param[in] group
8419  *   Flow group.
8420  * @param[in] headers_v
8421  *   Values header pointer.
8422  * @param[in] headers_m
8423  *   Masks header pointer.
8424  * @param[in] ip_version
8425  *   The IP version to set.
8426  */
8427 static inline void
8428 flow_dv_set_match_ip_version(uint32_t group,
8429 			     void *headers_v,
8430 			     uint32_t key_type,
8431 			     uint8_t ip_version)
8432 {
8433 	if (group == 0 && (key_type & MLX5_SET_MATCHER_M))
8434 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, 0xf);
8435 	else
8436 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version,
8437 			 ip_version);
8438 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, 0);
8439 }
8440 
8441 /**
8442  * Add Ethernet item to the value.
8443  *
8444  * @param[in, out] key
8445  *   Flow matcher value.
8446  * @param[in] item
8447  *   Flow pattern to translate.
8448  * @param[in] inner
8449  *   Item is inner pattern.
8450  * @param[in] grpup
8451  *   Flow matcher group.
8452  * @param[in] key_type
8453  *   Set flow matcher mask or value.
8454  */
8455 static void
8456 flow_dv_translate_item_eth(void *key, const struct rte_flow_item *item,
8457 			   int inner, uint32_t group, uint32_t key_type)
8458 {
8459 	const struct rte_flow_item_eth *eth_vv = item->spec;
8460 	const struct rte_flow_item_eth *eth_m;
8461 	const struct rte_flow_item_eth *eth_v;
8462 	const struct rte_flow_item_eth nic_mask = {
8463 		.hdr.dst_addr.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8464 		.hdr.src_addr.addr_bytes = "\xff\xff\xff\xff\xff\xff",
8465 		.hdr.ether_type = RTE_BE16(0xffff),
8466 		.has_vlan = 0,
8467 	};
8468 	void *hdrs_v;
8469 	char *l24_v;
8470 	unsigned int i;
8471 
8472 	if (MLX5_ITEM_VALID(item, key_type))
8473 		return;
8474 	MLX5_ITEM_UPDATE(item, key_type, eth_v, eth_m, &nic_mask);
8475 	if (!eth_vv)
8476 		eth_vv = eth_v;
8477 	if (inner)
8478 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8479 	else
8480 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8481 	/* The value must be in the range of the mask. */
8482 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, dmac_47_16);
8483 	for (i = 0; i < sizeof(eth_m->hdr.dst_addr); ++i)
8484 		l24_v[i] = eth_m->hdr.dst_addr.addr_bytes[i] & eth_v->hdr.dst_addr.addr_bytes[i];
8485 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, smac_47_16);
8486 	/* The value must be in the range of the mask. */
8487 	for (i = 0; i < sizeof(eth_m->hdr.dst_addr); ++i)
8488 		l24_v[i] = eth_m->hdr.src_addr.addr_bytes[i] & eth_v->hdr.src_addr.addr_bytes[i];
8489 	/*
8490 	 * HW supports match on one Ethertype, the Ethertype following the last
8491 	 * VLAN tag of the packet (see PRM).
8492 	 * Set match on ethertype only if ETH header is not followed by VLAN.
8493 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8494 	 * ethertype, and use ip_version field instead.
8495 	 * eCPRI over Ether layer will use type value 0xAEFE.
8496 	 */
8497 	if (eth_m->hdr.ether_type == 0xFFFF) {
8498 		rte_be16_t type = eth_v->hdr.ether_type;
8499 
8500 		/*
8501 		 * When set the matcher mask, refer to the original spec
8502 		 * value.
8503 		 */
8504 		if (key_type == MLX5_SET_MATCHER_SW_M) {
8505 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8506 			type = eth_vv->hdr.ether_type;
8507 		}
8508 		/* Set cvlan_tag mask for any single\multi\un-tagged case. */
8509 		switch (type) {
8510 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8511 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8512 			return;
8513 		case RTE_BE16(RTE_ETHER_TYPE_QINQ):
8514 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8515 			return;
8516 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8517 			flow_dv_set_match_ip_version(group, hdrs_v, key_type,
8518 						     4);
8519 			return;
8520 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8521 			flow_dv_set_match_ip_version(group, hdrs_v, key_type,
8522 						     6);
8523 			return;
8524 		default:
8525 			break;
8526 		}
8527 	}
8528 	/*
8529 	 * Only SW steering value should refer to the mask value.
8530 	 * Other cases are using the fake masks, just ignore the mask.
8531 	 */
8532 	if (eth_v->has_vlan && eth_m->has_vlan) {
8533 		/*
8534 		 * Here, when also has_more_vlan field in VLAN item is
8535 		 * not set, only single-tagged packets will be matched.
8536 		 */
8537 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8538 		if (key_type != MLX5_SET_MATCHER_HS_M && eth_vv->has_vlan)
8539 			return;
8540 	}
8541 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
8542 	*(uint16_t *)(l24_v) = eth_m->hdr.ether_type & eth_v->hdr.ether_type;
8543 }
8544 
8545 /**
8546  * Add VLAN item to the value.
8547  *
8548  * @param[in, out] key
8549  *   Flow matcher value.
8550  * @param[in] item
8551  *   Flow pattern to translate.
8552  * @param[in] inner
8553  *   Item is inner pattern.
8554  * @param[in] wks
8555  *   Item workspace.
8556  * @param[in] key_type
8557  *   Set flow matcher mask or value.
8558  */
8559 static void
8560 flow_dv_translate_item_vlan(void *key, const struct rte_flow_item *item,
8561 			    int inner, struct mlx5_dv_matcher_workspace *wks,
8562 			    uint32_t key_type)
8563 {
8564 	const struct rte_flow_item_vlan *vlan_m;
8565 	const struct rte_flow_item_vlan *vlan_v;
8566 	const struct rte_flow_item_vlan *vlan_vv = item->spec;
8567 	void *hdrs_v;
8568 	uint16_t tci_v;
8569 
8570 	if (inner) {
8571 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
8572 	} else {
8573 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8574 		/*
8575 		 * This is workaround, masks are not supported,
8576 		 * and pre-validated.
8577 		 */
8578 		if (vlan_vv)
8579 			wks->vlan_tag = rte_be_to_cpu_16(vlan_vv->hdr.vlan_tci) & 0x0fff;
8580 	}
8581 	/*
8582 	 * When VLAN item exists in flow, mark packet as tagged,
8583 	 * even if TCI is not specified.
8584 	 */
8585 	if (!MLX5_GET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag))
8586 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 1);
8587 	if (MLX5_ITEM_VALID(item, key_type))
8588 		return;
8589 	MLX5_ITEM_UPDATE(item, key_type, vlan_v, vlan_m,
8590 			 &rte_flow_item_vlan_mask);
8591 	tci_v = rte_be_to_cpu_16(vlan_m->hdr.vlan_tci & vlan_v->hdr.vlan_tci);
8592 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_vid, tci_v);
8593 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_cfi, tci_v >> 12);
8594 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, first_prio, tci_v >> 13);
8595 	/*
8596 	 * HW is optimized for IPv4/IPv6. In such cases, avoid setting
8597 	 * ethertype, and use ip_version field instead.
8598 	 */
8599 	if (vlan_m->hdr.eth_proto == 0xFFFF) {
8600 		rte_be16_t inner_type = vlan_v->hdr.eth_proto;
8601 
8602 		/*
8603 		 * When set the matcher mask, refer to the original spec
8604 		 * value.
8605 		 */
8606 		if (key_type == MLX5_SET_MATCHER_SW_M)
8607 			inner_type = vlan_vv->hdr.eth_proto;
8608 		switch (inner_type) {
8609 		case RTE_BE16(RTE_ETHER_TYPE_VLAN):
8610 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8611 			if (key_type & MLX5_SET_MATCHER_V)
8612 				MLX5_SET(fte_match_set_lyr_2_4, hdrs_v,
8613 					 cvlan_tag, 0);
8614 			return;
8615 		case RTE_BE16(RTE_ETHER_TYPE_IPV4):
8616 			flow_dv_set_match_ip_version
8617 				(wks->group, hdrs_v, key_type, 4);
8618 			return;
8619 		case RTE_BE16(RTE_ETHER_TYPE_IPV6):
8620 			flow_dv_set_match_ip_version
8621 				(wks->group, hdrs_v, key_type, 6);
8622 			return;
8623 		default:
8624 			break;
8625 		}
8626 	}
8627 	if (vlan_m->has_more_vlan && vlan_v->has_more_vlan) {
8628 		MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, svlan_tag, 1);
8629 		/* Only one vlan_tag bit can be set. */
8630 		if (key_type & MLX5_SET_MATCHER_V)
8631 			MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, cvlan_tag, 0);
8632 		return;
8633 	}
8634 	MLX5_SET(fte_match_set_lyr_2_4, hdrs_v, ethertype,
8635 		 rte_be_to_cpu_16(vlan_m->hdr.eth_proto & vlan_v->hdr.eth_proto));
8636 }
8637 
8638 /**
8639  * Add IPV4 item to the value.
8640  *
8641  * @param[in, out] key
8642  *   Flow matcher value.
8643  * @param[in] item
8644  *   Flow pattern to translate.
8645  * @param[in] inner
8646  *   Item is inner pattern.
8647  * @param[in] group
8648  *   The group to insert the rule.
8649  * @param[in] key_type
8650  *   Set flow matcher mask or value.
8651  */
8652 static void
8653 flow_dv_translate_item_ipv4(void *key, const struct rte_flow_item *item,
8654 			    int inner, uint32_t group, uint32_t key_type)
8655 {
8656 	const struct rte_flow_item_ipv4 *ipv4_m;
8657 	const struct rte_flow_item_ipv4 *ipv4_v;
8658 	const struct rte_flow_item_ipv4 nic_mask = {
8659 		.hdr = {
8660 			.src_addr = RTE_BE32(0xffffffff),
8661 			.dst_addr = RTE_BE32(0xffffffff),
8662 			.type_of_service = 0xff,
8663 			.next_proto_id = 0xff,
8664 			.time_to_live = 0xff,
8665 		},
8666 	};
8667 	void *headers_v;
8668 	char *l24_v;
8669 	uint8_t tos;
8670 
8671 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
8672 			    MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8673 	flow_dv_set_match_ip_version(group, headers_v, key_type, 4);
8674 	if (MLX5_ITEM_VALID(item, key_type))
8675 		return;
8676 	MLX5_ITEM_UPDATE(item, key_type, ipv4_v, ipv4_m, &nic_mask);
8677 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8678 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
8679 	*(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr;
8680 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8681 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
8682 	*(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr;
8683 	tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service;
8684 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ipv4_ihl,
8685 		 ipv4_v->hdr.ihl & ipv4_m->hdr.ihl);
8686 	if (key_type == MLX5_SET_MATCHER_SW_M)
8687 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn,
8688 			 ipv4_v->hdr.type_of_service);
8689 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos);
8690 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2);
8691 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8692 		 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id);
8693 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8694 		 ipv4_v->hdr.time_to_live & ipv4_m->hdr.time_to_live);
8695 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8696 		 !!(ipv4_v->hdr.fragment_offset & ipv4_m->hdr.fragment_offset));
8697 }
8698 
8699 /**
8700  * Add IPV6 item to the value.
8701  *
8702  * @param[in, out] key
8703  *   Flow matcher value.
8704  * @param[in] item
8705  *   Flow pattern to translate.
8706  * @param[in] inner
8707  *   Item is inner pattern.
8708  * @param[in] group
8709  *   The group to insert the rule.
8710  * @param[in] key_type
8711  *   Set flow matcher mask or value.
8712  */
8713 static void
8714 flow_dv_translate_item_ipv6(void *key, const struct rte_flow_item *item,
8715 			    int inner, uint32_t group, uint32_t key_type)
8716 {
8717 	const struct rte_flow_item_ipv6 *ipv6_m;
8718 	const struct rte_flow_item_ipv6 *ipv6_v;
8719 	const struct rte_flow_item_ipv6 nic_mask = {
8720 		.hdr = {
8721 			.src_addr =
8722 				"\xff\xff\xff\xff\xff\xff\xff\xff"
8723 				"\xff\xff\xff\xff\xff\xff\xff\xff",
8724 			.dst_addr =
8725 				"\xff\xff\xff\xff\xff\xff\xff\xff"
8726 				"\xff\xff\xff\xff\xff\xff\xff\xff",
8727 			.vtc_flow = RTE_BE32(0xffffffff),
8728 			.proto = 0xff,
8729 			.hop_limits = 0xff,
8730 		},
8731 	};
8732 	void *headers_v;
8733 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8734 	char *l24_v;
8735 	uint32_t vtc_v;
8736 	int i;
8737 	int size;
8738 
8739 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
8740 			    MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8741 	flow_dv_set_match_ip_version(group, headers_v, key_type, 6);
8742 	if (MLX5_ITEM_VALID(item, key_type))
8743 		return;
8744 	MLX5_ITEM_UPDATE(item, key_type, ipv6_v, ipv6_m, &nic_mask);
8745 	size = sizeof(ipv6_m->hdr.dst_addr);
8746 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8747 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
8748 	for (i = 0; i < size; ++i)
8749 		l24_v[i] = ipv6_m->hdr.dst_addr[i] & ipv6_v->hdr.dst_addr[i];
8750 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
8751 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
8752 	for (i = 0; i < size; ++i)
8753 		l24_v[i] = ipv6_m->hdr.src_addr[i] & ipv6_v->hdr.src_addr[i];
8754 	/* TOS. */
8755 	vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow);
8756 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20);
8757 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22);
8758 	/* Label. */
8759 	if (inner)
8760 		MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label,
8761 			 vtc_v);
8762 	else
8763 		MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label,
8764 			 vtc_v);
8765 	/* Protocol. */
8766 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8767 		 ipv6_v->hdr.proto & ipv6_m->hdr.proto);
8768 	/* Hop limit. */
8769 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ttl_hoplimit,
8770 		 ipv6_v->hdr.hop_limits & ipv6_m->hdr.hop_limits);
8771 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
8772 		 !!(ipv6_v->has_frag_ext & ipv6_m->has_frag_ext));
8773 }
8774 
8775 /**
8776  * Add IPV6 fragment extension item to the value.
8777  *
8778  * @param[in, out] key
8779  *   Flow matcher value.
8780  * @param[in] item
8781  *   Flow pattern to translate.
8782  * @param[in] inner
8783  *   Item is inner pattern.
8784  * @param[in] key_type
8785  *   Set flow matcher mask or value.
8786  */
8787 static void
8788 flow_dv_translate_item_ipv6_frag_ext(void *key,
8789 				     const struct rte_flow_item *item,
8790 				     int inner, uint32_t key_type)
8791 {
8792 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_m;
8793 	const struct rte_flow_item_ipv6_frag_ext *ipv6_frag_ext_v;
8794 	const struct rte_flow_item_ipv6_frag_ext nic_mask = {
8795 		.hdr = {
8796 			.next_header = 0xff,
8797 			.frag_data = RTE_BE16(0xffff),
8798 		},
8799 	};
8800 	void *headers_v;
8801 
8802 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
8803 			    MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8804 	/* IPv6 fragment extension item exists, so packet is IP fragment. */
8805 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, 1);
8806 	if (MLX5_ITEM_VALID(item, key_type))
8807 		return;
8808 	MLX5_ITEM_UPDATE(item, key_type, ipv6_frag_ext_v,
8809 			 ipv6_frag_ext_m, &nic_mask);
8810 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
8811 		 ipv6_frag_ext_v->hdr.next_header &
8812 		 ipv6_frag_ext_m->hdr.next_header);
8813 }
8814 
8815 /**
8816  * Add TCP item to the value.
8817  *
8818  * @param[in, out] key
8819  *   Flow matcher value.
8820  * @param[in] item
8821  *   Flow pattern to translate.
8822  * @param[in] inner
8823  *   Item is inner pattern.
8824  * @param[in] key_type
8825  *   Set flow matcher mask or value.
8826  */
8827 static void
8828 flow_dv_translate_item_tcp(void *key, const struct rte_flow_item *item,
8829 			   int inner, uint32_t key_type)
8830 {
8831 	const struct rte_flow_item_tcp *tcp_m;
8832 	const struct rte_flow_item_tcp *tcp_v;
8833 	void *headers_v;
8834 
8835 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
8836 		MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8837 	if (key_type & MLX5_SET_MATCHER_M)
8838 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
8839 			 ip_protocol, 0xff);
8840 	else
8841 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
8842 			 ip_protocol, IPPROTO_TCP);
8843 	if (MLX5_ITEM_VALID(item, key_type))
8844 		return;
8845 	MLX5_ITEM_UPDATE(item, key_type, tcp_v, tcp_m,
8846 			 &rte_flow_item_tcp_mask);
8847 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
8848 		 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port));
8849 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
8850 		 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port));
8851 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
8852 		 tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags);
8853 }
8854 
8855 /**
8856  * Add ESP item to the value.
8857  *
8858  * @param[in, out] key
8859  *   Flow matcher value.
8860  * @param[in] item
8861  *   Flow pattern to translate.
8862  * @param[in] inner
8863  *   Item is inner pattern.
8864  * @param[in] key_type
8865  *   Set flow matcher mask or value.
8866  */
8867 static void
8868 flow_dv_translate_item_esp(void *key, const struct rte_flow_item *item,
8869 			   int inner, uint32_t key_type)
8870 {
8871 	const struct rte_flow_item_esp *esp_m;
8872 	const struct rte_flow_item_esp *esp_v;
8873 	void *headers_v;
8874 	char *spi_v;
8875 
8876 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
8877 		MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8878 	if (key_type & MLX5_SET_MATCHER_M)
8879 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
8880 			 ip_protocol, 0xff);
8881 	else
8882 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
8883 			 ip_protocol, IPPROTO_ESP);
8884 	if (MLX5_ITEM_VALID(item, key_type))
8885 		return;
8886 	MLX5_ITEM_UPDATE(item, key_type, esp_v, esp_m,
8887 			 &rte_flow_item_esp_mask);
8888 	headers_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8889 	spi_v = inner ? MLX5_ADDR_OF(fte_match_set_misc, headers_v,
8890 				inner_esp_spi) : MLX5_ADDR_OF(fte_match_set_misc
8891 				, headers_v, outer_esp_spi);
8892 	*(uint32_t *)spi_v = esp_m->hdr.spi & esp_v->hdr.spi;
8893 }
8894 
8895 /**
8896  * Add UDP item to the value.
8897  *
8898  * @param[in, out] key
8899  *   Flow matcher value.
8900  * @param[in] item
8901  *   Flow pattern to translate.
8902  * @param[in] inner
8903  *   Item is inner pattern.
8904  * @param[in] key_type
8905  *   Set flow matcher mask or value.
8906  */
8907 static void
8908 flow_dv_translate_item_udp(void *key, const struct rte_flow_item *item,
8909 			   int inner, struct mlx5_dv_matcher_workspace *wks,
8910 			   uint32_t key_type)
8911 {
8912 	const struct rte_flow_item_udp *udp_m;
8913 	const struct rte_flow_item_udp *udp_v;
8914 	void *headers_v;
8915 
8916 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
8917 		MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8918 	if (key_type & MLX5_SET_MATCHER_M)
8919 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
8920 			 ip_protocol, 0xff);
8921 	else
8922 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
8923 			 ip_protocol, IPPROTO_UDP);
8924 	if (MLX5_ITEM_VALID(item, key_type))
8925 		return;
8926 	MLX5_ITEM_UPDATE(item, key_type, udp_v, udp_m,
8927 			 &rte_flow_item_udp_mask);
8928 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
8929 		 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port));
8930 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
8931 		 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port));
8932 	/* Force get UDP dport in case to be used in VXLAN translate. */
8933 	if (key_type & MLX5_SET_MATCHER_SW) {
8934 		udp_v = item->spec;
8935 		wks->udp_dport = rte_be_to_cpu_16(udp_v->hdr.dst_port &
8936 						  udp_m->hdr.dst_port);
8937 	}
8938 }
8939 
8940 /**
8941  * Add GRE optional Key item to the value.
8942  *
8943  * @param[in, out] key
8944  *   Flow matcher value.
8945  * @param[in] item
8946  *   Flow pattern to translate.
8947  * @param[in] inner
8948  *   Item is inner pattern.
8949  */
8950 static void
8951 flow_dv_translate_item_gre_key(void *key, const struct rte_flow_item *item,
8952 			       uint32_t key_type)
8953 {
8954 	const rte_be32_t *key_m;
8955 	const rte_be32_t *key_v;
8956 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8957 	rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX);
8958 
8959 	/* GRE K bit must be on and should already be validated */
8960 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1);
8961 	if (MLX5_ITEM_VALID(item, key_type))
8962 		return;
8963 	MLX5_ITEM_UPDATE(item, key_type, key_v, key_m,
8964 			 &gre_key_default_mask);
8965 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_h,
8966 		 rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8);
8967 	MLX5_SET(fte_match_set_misc, misc_v, gre_key_l,
8968 		 rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF);
8969 }
8970 
8971 /**
8972  * Add GRE item to the value.
8973  *
8974  * @param[in, out] key
8975  *   Flow matcher value.
8976  * @param[in] item
8977  *   Flow pattern to translate.
8978  * @param[in] pattern_flags
8979  *   Accumulated pattern flags.
8980  * @param[in] key_type
8981  *   Set flow matcher mask or value.
8982  */
8983 static void
8984 flow_dv_translate_item_gre(void *key, const struct rte_flow_item *item,
8985 			   uint64_t pattern_flags, uint32_t key_type)
8986 {
8987 	static const struct rte_flow_item_gre empty_gre = {0,};
8988 	const struct rte_flow_item_gre *gre_m = item->mask;
8989 	const struct rte_flow_item_gre *gre_v = item->spec;
8990 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
8991 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
8992 	struct {
8993 		union {
8994 			__extension__
8995 			struct {
8996 				uint16_t version:3;
8997 				uint16_t rsvd0:9;
8998 				uint16_t s_present:1;
8999 				uint16_t k_present:1;
9000 				uint16_t rsvd_bit1:1;
9001 				uint16_t c_present:1;
9002 			};
9003 			uint16_t value;
9004 		};
9005 	} gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v;
9006 	uint16_t protocol_m, protocol_v;
9007 
9008 	if (key_type & MLX5_SET_MATCHER_M)
9009 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 0xff);
9010 	else
9011 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
9012 			 IPPROTO_GRE);
9013 	if (!gre_v) {
9014 		gre_v = &empty_gre;
9015 		gre_m = &empty_gre;
9016 	} else {
9017 		if (!gre_m)
9018 			gre_m = &rte_flow_item_gre_mask;
9019 	}
9020 	if (key_type & MLX5_SET_MATCHER_M)
9021 		gre_v = gre_m;
9022 	else if (key_type == MLX5_SET_MATCHER_HS_V)
9023 		gre_m = gre_v;
9024 	gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver);
9025 	gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver);
9026 	MLX5_SET(fte_match_set_misc, misc_v, gre_c_present,
9027 		 gre_crks_rsvd0_ver_v.c_present &
9028 		 gre_crks_rsvd0_ver_m.c_present);
9029 	MLX5_SET(fte_match_set_misc, misc_v, gre_k_present,
9030 		 gre_crks_rsvd0_ver_v.k_present &
9031 		 gre_crks_rsvd0_ver_m.k_present);
9032 	MLX5_SET(fte_match_set_misc, misc_v, gre_s_present,
9033 		 gre_crks_rsvd0_ver_v.s_present &
9034 		 gre_crks_rsvd0_ver_m.s_present);
9035 	protocol_m = rte_be_to_cpu_16(gre_m->protocol);
9036 	protocol_v = rte_be_to_cpu_16(gre_v->protocol);
9037 	if (!protocol_m) {
9038 		/* Force next protocol to prevent matchers duplication */
9039 		protocol_v = mlx5_translate_tunnel_etypes(pattern_flags);
9040 		if (protocol_v)
9041 			protocol_m = 0xFFFF;
9042 		/* Restore the value to mask in mask case. */
9043 		if (key_type & MLX5_SET_MATCHER_M)
9044 			protocol_v = protocol_m;
9045 	}
9046 	MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
9047 		 protocol_m & protocol_v);
9048 }
9049 
9050 /**
9051  * Add GRE optional items to the value.
9052  *
9053  * @param[in, out] key
9054  *   Flow matcher value.
9055  * @param[in] item
9056  *   Flow pattern to translate.
9057  * @param[in] gre_item
9058  *   Pointer to gre_item.
9059  * @param[in] pattern_flags
9060  *   Accumulated pattern flags.
9061  * @param[in] key_type
9062  *   Set flow matcher mask or value.
9063  */
9064 static void
9065 flow_dv_translate_item_gre_option(void *key,
9066 				  const struct rte_flow_item *item,
9067 				  const struct rte_flow_item *gre_item,
9068 				  uint64_t pattern_flags, uint32_t key_type)
9069 {
9070 	void *misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5);
9071 	const struct rte_flow_item_gre_opt *option_m = item->mask;
9072 	const struct rte_flow_item_gre_opt *option_v = item->spec;
9073 	const struct rte_flow_item_gre *gre_m = gre_item->mask;
9074 	const struct rte_flow_item_gre *gre_v = gre_item->spec;
9075 	static const struct rte_flow_item_gre empty_gre = {0};
9076 	struct rte_flow_item gre_key_item;
9077 	uint16_t c_rsvd0_ver_m, c_rsvd0_ver_v;
9078 	uint16_t protocol_m, protocol_v;
9079 
9080 	/*
9081 	 * If only match key field, keep using misc for matching.
9082 	 * If need to match checksum or sequence, using misc5 and do
9083 	 * not need using misc.
9084 	 */
9085 	if (!(option_m->sequence.sequence ||
9086 	      option_m->checksum_rsvd.checksum)) {
9087 		flow_dv_translate_item_gre(key, gre_item, pattern_flags, key_type);
9088 		gre_key_item.spec = &option_v->key.key;
9089 		gre_key_item.mask = &option_m->key.key;
9090 		flow_dv_translate_item_gre_key(key, &gre_key_item, key_type);
9091 		return;
9092 	}
9093 	if (!gre_v) {
9094 		gre_v = &empty_gre;
9095 		gre_m = &empty_gre;
9096 	} else {
9097 		if (!gre_m)
9098 			gre_m = &rte_flow_item_gre_mask;
9099 	}
9100 	protocol_v = gre_v->protocol;
9101 	protocol_m = gre_m->protocol;
9102 	if (!protocol_m) {
9103 		/* Force next protocol to prevent matchers duplication */
9104 		uint16_t ether_type =
9105 			mlx5_translate_tunnel_etypes(pattern_flags);
9106 		if (ether_type) {
9107 			protocol_v = rte_be_to_cpu_16(ether_type);
9108 			protocol_m = UINT16_MAX;
9109 		}
9110 	}
9111 	c_rsvd0_ver_v = gre_v->c_rsvd0_ver;
9112 	c_rsvd0_ver_m = gre_m->c_rsvd0_ver;
9113 	if (option_m->sequence.sequence) {
9114 		c_rsvd0_ver_v |= RTE_BE16(0x1000);
9115 		c_rsvd0_ver_m |= RTE_BE16(0x1000);
9116 	}
9117 	if (option_m->key.key) {
9118 		c_rsvd0_ver_v |= RTE_BE16(0x2000);
9119 		c_rsvd0_ver_m |= RTE_BE16(0x2000);
9120 	}
9121 	if (option_m->checksum_rsvd.checksum) {
9122 		c_rsvd0_ver_v |= RTE_BE16(0x8000);
9123 		c_rsvd0_ver_m |= RTE_BE16(0x8000);
9124 	}
9125 	if (key_type & MLX5_SET_MATCHER_M) {
9126 		c_rsvd0_ver_v = c_rsvd0_ver_m;
9127 		protocol_v = protocol_m;
9128 		option_v = option_m;
9129 	}
9130 	/*
9131 	 * Hardware parses GRE optional field into the fixed location,
9132 	 * do not need to adjust the tunnel dword indices.
9133 	 */
9134 	MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_0,
9135 		 rte_be_to_cpu_32((c_rsvd0_ver_v | protocol_v << 16) &
9136 				  (c_rsvd0_ver_m | protocol_m << 16)));
9137 	MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_1,
9138 		 rte_be_to_cpu_32(option_v->checksum_rsvd.checksum &
9139 				  option_m->checksum_rsvd.checksum));
9140 	MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_2,
9141 		 rte_be_to_cpu_32(option_v->key.key & option_m->key.key));
9142 	MLX5_SET(fte_match_set_misc5, misc5_v, tunnel_header_3,
9143 		 rte_be_to_cpu_32(option_v->sequence.sequence &
9144 				  option_m->sequence.sequence));
9145 }
9146 
9147 /**
9148  * Add NVGRE item to matcher and to the value.
9149  *
9150  * @param[in, out] key
9151  *   Flow matcher value.
9152  * @param[in] item
9153  *   Flow pattern to translate.
9154  * @param[in] pattern_flags
9155  *   Accumulated pattern flags.
9156  * @param[in] key_type
9157  *   Set flow matcher mask or value.
9158  */
9159 static void
9160 flow_dv_translate_item_nvgre(void *key, const struct rte_flow_item *item,
9161 			     unsigned long pattern_flags, uint32_t key_type)
9162 {
9163 	const struct rte_flow_item_nvgre *nvgre_m;
9164 	const struct rte_flow_item_nvgre *nvgre_v;
9165 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9166 	const char *tni_flow_id_m;
9167 	const char *tni_flow_id_v;
9168 	char *gre_key_v;
9169 	int size;
9170 	int i;
9171 
9172 	/* For NVGRE, GRE header fields must be set with defined values. */
9173 	const struct rte_flow_item_gre gre_spec = {
9174 		.c_rsvd0_ver = RTE_BE16(0x2000),
9175 		.protocol = RTE_BE16(RTE_ETHER_TYPE_TEB)
9176 	};
9177 	const struct rte_flow_item_gre gre_mask = {
9178 		.c_rsvd0_ver = RTE_BE16(0xB000),
9179 		.protocol = RTE_BE16(UINT16_MAX),
9180 	};
9181 	const struct rte_flow_item gre_item = {
9182 		.spec = &gre_spec,
9183 		.mask = &gre_mask,
9184 		.last = NULL,
9185 	};
9186 	flow_dv_translate_item_gre(key, &gre_item, pattern_flags, key_type);
9187 	if (MLX5_ITEM_VALID(item, key_type))
9188 		return;
9189 	MLX5_ITEM_UPDATE(item, key_type, nvgre_v, nvgre_m,
9190 		    &rte_flow_item_nvgre_mask);
9191 	tni_flow_id_m = (const char *)nvgre_m->tni;
9192 	tni_flow_id_v = (const char *)nvgre_v->tni;
9193 	size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
9194 	gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
9195 	for (i = 0; i < size; ++i)
9196 		gre_key_v[i] = tni_flow_id_m[i] & tni_flow_id_v[i];
9197 }
9198 
9199 /**
9200  * Add VXLAN item to the value.
9201  *
9202  * @param[in] dev
9203  *   Pointer to the Ethernet device structure.
9204  * @param[in] attr
9205  *   Flow rule attributes.
9206  * @param[in, out] key
9207  *   Flow matcher value.
9208  * @param[in] item
9209  *   Flow pattern to translate.
9210  * @param[in] inner
9211  *   Item is inner pattern.
9212  * @param[in] wks
9213  *   Matcher workspace.
9214  * @param[in] key_type
9215  *   Set flow matcher mask or value.
9216  */
9217 static void
9218 flow_dv_translate_item_vxlan(struct rte_eth_dev *dev,
9219 			     const struct rte_flow_attr *attr,
9220 			     void *key, const struct rte_flow_item *item,
9221 			     int inner, struct mlx5_dv_matcher_workspace *wks,
9222 			     uint32_t key_type)
9223 {
9224 	const struct rte_flow_item_vxlan *vxlan_m;
9225 	const struct rte_flow_item_vxlan *vxlan_v;
9226 	const struct rte_flow_item_vxlan *vxlan_vv = item->spec;
9227 	void *headers_v;
9228 	void *misc_v;
9229 	void *misc5_v;
9230 	uint32_t tunnel_v;
9231 	uint32_t *tunnel_header_v;
9232 	char *vni_v;
9233 	uint16_t dport;
9234 	int size;
9235 	int i;
9236 	struct mlx5_priv *priv = dev->data->dev_private;
9237 	const struct rte_flow_item_vxlan nic_mask = {
9238 		.hdr.vni = "\xff\xff\xff",
9239 		.hdr.rsvd1 = 0xff,
9240 	};
9241 
9242 	misc5_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_5);
9243 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
9244 		MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9245 	dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
9246 		MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
9247 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9248 		if (key_type & MLX5_SET_MATCHER_M)
9249 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
9250 				 udp_dport, 0xFFFF);
9251 		else
9252 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
9253 				 udp_dport, dport);
9254 	}
9255 	/*
9256 	 * Read the UDP dport to check if the value satisfies the VXLAN
9257 	 * matching with MISC5 for CX5.
9258 	 */
9259 	if (wks->udp_dport)
9260 		dport = wks->udp_dport;
9261 	if (MLX5_ITEM_VALID(item, key_type))
9262 		return;
9263 	MLX5_ITEM_UPDATE(item, key_type, vxlan_v, vxlan_m, &nic_mask);
9264 	if ((item->mask == &nic_mask) &&
9265 	    ((!attr->group && !(attr->transfer && priv->fdb_def_rule) &&
9266 	    !priv->sh->tunnel_header_0_1) ||
9267 	    ((attr->group || (attr->transfer && priv->fdb_def_rule)) &&
9268 	    !priv->sh->misc5_cap)))
9269 		vxlan_m = &rte_flow_item_vxlan_mask;
9270 	if ((priv->sh->steering_format_version ==
9271 	     MLX5_STEERING_LOGIC_FORMAT_CONNECTX_5 &&
9272 	     dport != MLX5_UDP_PORT_VXLAN) ||
9273 	    (!attr->group && !(attr->transfer && priv->fdb_def_rule)) ||
9274 	    ((attr->group || (attr->transfer && priv->fdb_def_rule)) &&
9275 	    !priv->sh->misc5_cap)) {
9276 		misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9277 		size = sizeof(vxlan_m->hdr.vni);
9278 		vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni);
9279 		for (i = 0; i < size; ++i)
9280 			vni_v[i] = vxlan_m->hdr.vni[i] & vxlan_v->hdr.vni[i];
9281 		return;
9282 	}
9283 	tunnel_header_v = (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc5,
9284 						   misc5_v,
9285 						   tunnel_header_1);
9286 	tunnel_v = (vxlan_v->hdr.vni[0] & vxlan_m->hdr.vni[0]) |
9287 		   (vxlan_v->hdr.vni[1] & vxlan_m->hdr.vni[1]) << 8 |
9288 		   (vxlan_v->hdr.vni[2] & vxlan_m->hdr.vni[2]) << 16;
9289 	*tunnel_header_v = tunnel_v;
9290 	if (key_type == MLX5_SET_MATCHER_SW_M) {
9291 		tunnel_v = (vxlan_vv->hdr.vni[0] & vxlan_m->hdr.vni[0]) |
9292 			   (vxlan_vv->hdr.vni[1] & vxlan_m->hdr.vni[1]) << 8 |
9293 			   (vxlan_vv->hdr.vni[2] & vxlan_m->hdr.vni[2]) << 16;
9294 		if (!tunnel_v)
9295 			*tunnel_header_v = 0x0;
9296 		if (vxlan_vv->hdr.rsvd1 & vxlan_m->hdr.rsvd1)
9297 			*tunnel_header_v |= vxlan_v->hdr.rsvd1 << 24;
9298 	} else {
9299 		*tunnel_header_v |= (vxlan_v->hdr.rsvd1 & vxlan_m->hdr.rsvd1) << 24;
9300 	}
9301 }
9302 
9303 /**
9304  * Add VXLAN-GPE item to the value.
9305  *
9306  * @param[in, out] key
9307  *   Flow matcher value.
9308  * @param[in] item
9309  *   Flow pattern to translate.
9310  * @param[in] pattern_flags
9311  *   Item pattern flags.
9312  * @param[in] key_type
9313  *   Set flow matcher mask or value.
9314  */
9315 
9316 static void
9317 flow_dv_translate_item_vxlan_gpe(void *key, const struct rte_flow_item *item,
9318 				 const uint64_t pattern_flags,
9319 				 uint32_t key_type)
9320 {
9321 	static const struct rte_flow_item_vxlan_gpe dummy_vxlan_gpe_hdr = {{{0}}};
9322 	const struct rte_flow_item_vxlan_gpe *vxlan_m = item->mask;
9323 	const struct rte_flow_item_vxlan_gpe *vxlan_v = item->spec;
9324 	/* The item was validated to be on the outer side */
9325 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9326 	void *misc_v =
9327 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9328 	char *vni_v =
9329 		MLX5_ADDR_OF(fte_match_set_misc3, misc_v, outer_vxlan_gpe_vni);
9330 	int i, size = sizeof(vxlan_m->hdr.vni);
9331 	uint8_t flags_m = 0xff;
9332 	uint8_t flags_v = 0xc;
9333 	uint8_t m_protocol, v_protocol;
9334 
9335 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9336 		if (key_type & MLX5_SET_MATCHER_M)
9337 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9338 				 0xFFFF);
9339 		else
9340 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9341 				 MLX5_UDP_PORT_VXLAN_GPE);
9342 	}
9343 	if (!vxlan_v) {
9344 		vxlan_v = &dummy_vxlan_gpe_hdr;
9345 		vxlan_m = &dummy_vxlan_gpe_hdr;
9346 	} else {
9347 		if (!vxlan_m)
9348 			vxlan_m = &rte_flow_item_vxlan_gpe_mask;
9349 	}
9350 	if (key_type & MLX5_SET_MATCHER_M)
9351 		vxlan_v = vxlan_m;
9352 	else if (key_type == MLX5_SET_MATCHER_HS_V)
9353 		vxlan_m = vxlan_v;
9354 	for (i = 0; i < size; ++i)
9355 		vni_v[i] = vxlan_m->hdr.vni[i] & vxlan_v->hdr.vni[i];
9356 	if (vxlan_m->hdr.flags) {
9357 		flags_m = vxlan_m->hdr.flags;
9358 		flags_v = vxlan_v->hdr.flags;
9359 	}
9360 	MLX5_SET(fte_match_set_misc3, misc_v, outer_vxlan_gpe_flags,
9361 		 flags_m & flags_v);
9362 	m_protocol = vxlan_m->hdr.protocol;
9363 	v_protocol = vxlan_v->hdr.protocol;
9364 	if (!m_protocol) {
9365 		/* Force next protocol to ensure next headers parsing. */
9366 		if (pattern_flags & MLX5_FLOW_LAYER_INNER_L2)
9367 			v_protocol = RTE_VXLAN_GPE_TYPE_ETH;
9368 		else if (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4)
9369 			v_protocol = RTE_VXLAN_GPE_TYPE_IPV4;
9370 		else if (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6)
9371 			v_protocol = RTE_VXLAN_GPE_TYPE_IPV6;
9372 		if (v_protocol)
9373 			m_protocol = 0xFF;
9374 		/* Restore the value to mask in mask case. */
9375 		if (key_type & MLX5_SET_MATCHER_M)
9376 			v_protocol = m_protocol;
9377 	}
9378 	MLX5_SET(fte_match_set_misc3, misc_v,
9379 		 outer_vxlan_gpe_next_protocol, m_protocol & v_protocol);
9380 }
9381 
9382 /**
9383  * Add Geneve item to the value.
9384  *
9385  * @param[in, out] key
9386  *   Flow matcher value.
9387  * @param[in] item
9388  *   Flow pattern to translate.
9389  * @param[in] pattern_flags
9390  *   Item pattern flags.
9391  * @param[in] key_type
9392  *   Set flow matcher mask or value.
9393  */
9394 
9395 static void
9396 flow_dv_translate_item_geneve(void *key, const struct rte_flow_item *item,
9397 			      uint64_t pattern_flags, uint32_t key_type)
9398 {
9399 	static const struct rte_flow_item_geneve empty_geneve = {0,};
9400 	const struct rte_flow_item_geneve *geneve_m = item->mask;
9401 	const struct rte_flow_item_geneve *geneve_v = item->spec;
9402 	/* GENEVE flow item validation allows single tunnel item */
9403 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9404 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9405 	uint16_t gbhdr_m;
9406 	uint16_t gbhdr_v;
9407 	char *vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, geneve_vni);
9408 	size_t size = sizeof(geneve_m->vni), i;
9409 	uint16_t protocol_m, protocol_v;
9410 
9411 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9412 		if (key_type & MLX5_SET_MATCHER_M)
9413 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9414 				 0xFFFF);
9415 		else
9416 			MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
9417 				 MLX5_UDP_PORT_GENEVE);
9418 	}
9419 	if (!geneve_v) {
9420 		geneve_v = &empty_geneve;
9421 		geneve_m = &empty_geneve;
9422 	} else {
9423 		if (!geneve_m)
9424 			geneve_m = &rte_flow_item_geneve_mask;
9425 	}
9426 	if (key_type & MLX5_SET_MATCHER_M)
9427 		geneve_v = geneve_m;
9428 	else if (key_type == MLX5_SET_MATCHER_HS_V)
9429 		geneve_m = geneve_v;
9430 	for (i = 0; i < size; ++i)
9431 		vni_v[i] = geneve_m->vni[i] & geneve_v->vni[i];
9432 	gbhdr_m = rte_be_to_cpu_16(geneve_m->ver_opt_len_o_c_rsvd0);
9433 	gbhdr_v = rte_be_to_cpu_16(geneve_v->ver_opt_len_o_c_rsvd0);
9434 	MLX5_SET(fte_match_set_misc, misc_v, geneve_oam,
9435 		 MLX5_GENEVE_OAMF_VAL(gbhdr_v) & MLX5_GENEVE_OAMF_VAL(gbhdr_m));
9436 	MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9437 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_v) &
9438 		 MLX5_GENEVE_OPTLEN_VAL(gbhdr_m));
9439 	protocol_m = rte_be_to_cpu_16(geneve_m->protocol);
9440 	protocol_v = rte_be_to_cpu_16(geneve_v->protocol);
9441 	if (!protocol_m) {
9442 		/* Force next protocol to prevent matchers duplication */
9443 		protocol_v = mlx5_translate_tunnel_etypes(pattern_flags);
9444 		if (protocol_v)
9445 			protocol_m = 0xFFFF;
9446 		/* Restore the value to mask in mask case. */
9447 		if (key_type & MLX5_SET_MATCHER_M)
9448 			protocol_v = protocol_m;
9449 	}
9450 	MLX5_SET(fte_match_set_misc, misc_v, geneve_protocol_type,
9451 		 protocol_m & protocol_v);
9452 }
9453 
9454 /**
9455  * Create Geneve TLV option resource.
9456  *
9457  * @param dev[in, out]
9458  *   Pointer to rte_eth_dev structure.
9459  * @param[in] item
9460  *   Flow pattern to translate.
9461  * @param[out] error
9462  *   pointer to error structure.
9463  *
9464  * @return
9465  *   0 on success otherwise -errno and errno is set.
9466  */
9467 
9468 int
9469 flow_dev_geneve_tlv_option_resource_register(struct rte_eth_dev *dev,
9470 					     const struct rte_flow_item *item,
9471 					     struct rte_flow_error *error)
9472 {
9473 	struct mlx5_priv *priv = dev->data->dev_private;
9474 	struct mlx5_dev_ctx_shared *sh = priv->sh;
9475 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
9476 			sh->geneve_tlv_option_resource;
9477 	struct mlx5_devx_obj *obj;
9478 	const struct rte_flow_item_geneve_opt *geneve_opt_v = item->spec;
9479 	int ret = 0;
9480 
9481 	if (!geneve_opt_v)
9482 		return -1;
9483 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
9484 	if (geneve_opt_resource != NULL) {
9485 		if (geneve_opt_resource->option_class ==
9486 			geneve_opt_v->option_class &&
9487 			geneve_opt_resource->option_type ==
9488 			geneve_opt_v->option_type &&
9489 			geneve_opt_resource->length ==
9490 			geneve_opt_v->option_len) {
9491 			/*
9492 			 * We already have GENEVE TLV option obj allocated.
9493 			 * Increasing refcnt only in SWS. HWS uses it as global.
9494 			 */
9495 			if (priv->sh->config.dv_flow_en == 1)
9496 				__atomic_fetch_add(&geneve_opt_resource->refcnt, 1,
9497 						   __ATOMIC_RELAXED);
9498 		} else {
9499 			ret = rte_flow_error_set(error, ENOMEM,
9500 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9501 				"Only one GENEVE TLV option supported");
9502 			goto exit;
9503 		}
9504 	} else {
9505 		/* Create a GENEVE TLV object and resource. */
9506 		obj = mlx5_devx_cmd_create_geneve_tlv_option(sh->cdev->ctx,
9507 				geneve_opt_v->option_class,
9508 				geneve_opt_v->option_type,
9509 				geneve_opt_v->option_len);
9510 		if (!obj) {
9511 			ret = rte_flow_error_set(error, ENODATA,
9512 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9513 				"Failed to create GENEVE TLV Devx object");
9514 			goto exit;
9515 		}
9516 		sh->geneve_tlv_option_resource =
9517 				mlx5_malloc(MLX5_MEM_ZERO,
9518 						sizeof(*geneve_opt_resource),
9519 						0, SOCKET_ID_ANY);
9520 		if (!sh->geneve_tlv_option_resource) {
9521 			claim_zero(mlx5_devx_cmd_destroy(obj));
9522 			ret = rte_flow_error_set(error, ENOMEM,
9523 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
9524 				"GENEVE TLV object memory allocation failed");
9525 			goto exit;
9526 		}
9527 		geneve_opt_resource = sh->geneve_tlv_option_resource;
9528 		geneve_opt_resource->obj = obj;
9529 		geneve_opt_resource->option_class = geneve_opt_v->option_class;
9530 		geneve_opt_resource->option_type = geneve_opt_v->option_type;
9531 		geneve_opt_resource->length = geneve_opt_v->option_len;
9532 		__atomic_store_n(&geneve_opt_resource->refcnt, 1,
9533 				__ATOMIC_RELAXED);
9534 	}
9535 exit:
9536 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
9537 	return ret;
9538 }
9539 
9540 /**
9541  * Add Geneve TLV option item to value.
9542  *
9543  * @param[in, out] dev
9544  *   Pointer to rte_eth_dev structure.
9545  * @param[in, out] key
9546  *   Flow matcher value.
9547  * @param[in] item
9548  *   Flow pattern to translate.
9549  * @param[in] key_type
9550  *   Set flow matcher mask or value.
9551  * @param[out] error
9552  *   Pointer to error structure.
9553  */
9554 static int
9555 flow_dv_translate_item_geneve_opt(struct rte_eth_dev *dev, void *key,
9556 				  const struct rte_flow_item *item,
9557 				  uint32_t key_type,
9558 				  struct rte_flow_error *error)
9559 {
9560 	const struct rte_flow_item_geneve_opt *geneve_opt_m;
9561 	const struct rte_flow_item_geneve_opt *geneve_opt_v;
9562 	const struct rte_flow_item_geneve_opt *geneve_opt_vv = item->spec;
9563 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9564 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
9565 	rte_be32_t opt_data_key = 0, opt_data_mask = 0;
9566 	uint32_t *data;
9567 	int ret = 0;
9568 
9569 	if (MLX5_ITEM_VALID(item, key_type))
9570 		return -1;
9571 	MLX5_ITEM_UPDATE(item, key_type, geneve_opt_v, geneve_opt_m,
9572 			 &rte_flow_item_geneve_opt_mask);
9573 	/* Register resource requires item spec. */
9574 	if (key_type & MLX5_SET_MATCHER_V) {
9575 		ret = flow_dev_geneve_tlv_option_resource_register(dev, item,
9576 								   error);
9577 		if (ret) {
9578 			DRV_LOG(ERR, "Failed to create geneve_tlv_obj");
9579 			return ret;
9580 		}
9581 	}
9582 	/*
9583 	 * Set the option length in GENEVE header if not requested.
9584 	 * The GENEVE TLV option length is expressed by the option length field
9585 	 * in the GENEVE header.
9586 	 * If the option length was not requested but the GENEVE TLV option item
9587 	 * is present we set the option length field implicitly.
9588 	 */
9589 	if (!MLX5_GET16(fte_match_set_misc, misc_v, geneve_opt_len)) {
9590 		if (key_type & MLX5_SET_MATCHER_M)
9591 			MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9592 				 MLX5_GENEVE_OPTLEN_MASK);
9593 		else
9594 			MLX5_SET(fte_match_set_misc, misc_v, geneve_opt_len,
9595 				 geneve_opt_v->option_len + 1);
9596 	}
9597 	/* Set the data. */
9598 	if (key_type == MLX5_SET_MATCHER_SW_V)
9599 		data = geneve_opt_vv->data;
9600 	else
9601 		data = geneve_opt_v->data;
9602 	if (data) {
9603 		memcpy(&opt_data_key, data,
9604 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9605 				sizeof(opt_data_key)));
9606 		memcpy(&opt_data_mask, geneve_opt_m->data,
9607 			RTE_MIN((uint32_t)(geneve_opt_v->option_len * 4),
9608 				sizeof(opt_data_mask)));
9609 		MLX5_SET(fte_match_set_misc3, misc3_v,
9610 				geneve_tlv_option_0_data,
9611 			rte_be_to_cpu_32(opt_data_key & opt_data_mask));
9612 	}
9613 	return ret;
9614 }
9615 
9616 /**
9617  * Add MPLS item to the value.
9618  *
9619  * @param[in, out] key
9620  *   Flow matcher value.
9621  * @param[in] item
9622  *   Flow pattern to translate.
9623  * @param[in] prev_layer
9624  *   The protocol layer indicated in previous item.
9625  * @param[in] inner
9626  *   Item is inner pattern.
9627  * @param[in] key_type
9628  *   Set flow matcher mask or value.
9629  */
9630 static void
9631 flow_dv_translate_item_mpls(void *key, const struct rte_flow_item *item,
9632 			    uint64_t prev_layer, int inner,
9633 			    uint32_t key_type)
9634 {
9635 	const uint32_t *in_mpls_m;
9636 	const uint32_t *in_mpls_v;
9637 	uint32_t *out_mpls_v = 0;
9638 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
9639 	void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9640 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
9641 
9642 	switch (prev_layer) {
9643 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9644 		if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
9645 			if (key_type & MLX5_SET_MATCHER_M)
9646 				MLX5_SET(fte_match_set_lyr_2_4, headers_v,
9647 					 udp_dport, 0xffff);
9648 			else
9649 				MLX5_SET(fte_match_set_lyr_2_4, headers_v,
9650 					 udp_dport, MLX5_UDP_PORT_MPLS);
9651 		}
9652 		break;
9653 	case MLX5_FLOW_LAYER_GRE:
9654 		/* Fall-through. */
9655 	case MLX5_FLOW_LAYER_GRE_KEY:
9656 		if (!MLX5_GET16(fte_match_set_misc, misc_v, gre_protocol)) {
9657 			if (key_type & MLX5_SET_MATCHER_M)
9658 				MLX5_SET(fte_match_set_misc, misc_v,
9659 					 gre_protocol, 0xffff);
9660 			else
9661 				MLX5_SET(fte_match_set_misc, misc_v,
9662 					 gre_protocol, RTE_ETHER_TYPE_MPLS);
9663 		}
9664 		break;
9665 	default:
9666 		break;
9667 	}
9668 	if (MLX5_ITEM_VALID(item, key_type))
9669 		return;
9670 	MLX5_ITEM_UPDATE(item, key_type, in_mpls_v, in_mpls_m,
9671 			 &rte_flow_item_mpls_mask);
9672 	switch (prev_layer) {
9673 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
9674 		out_mpls_v =
9675 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9676 						 outer_first_mpls_over_udp);
9677 		break;
9678 	case MLX5_FLOW_LAYER_GRE:
9679 		out_mpls_v =
9680 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
9681 						 outer_first_mpls_over_gre);
9682 		break;
9683 	default:
9684 		/* Inner MPLS not over GRE is not supported. */
9685 		if (!inner)
9686 			out_mpls_v =
9687 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
9688 							 misc2_v,
9689 							 outer_first_mpls);
9690 		break;
9691 	}
9692 	if (out_mpls_v)
9693 		*out_mpls_v = *in_mpls_v & *in_mpls_m;
9694 }
9695 
9696 /**
9697  * Add metadata register item to matcher
9698  *
9699  * @param[in, out] key
9700  *   Flow matcher value.
9701  * @param[in] reg_type
9702  *   Type of device metadata register
9703  * @param[in] data
9704  *   Register data
9705  * @param[in] mask
9706  *   Register mask
9707  */
9708 static void
9709 flow_dv_match_meta_reg(void *key, enum modify_reg reg_type,
9710 		       uint32_t data, uint32_t mask)
9711 {
9712 	void *misc2_v =
9713 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
9714 	uint32_t temp;
9715 
9716 	data &= mask;
9717 	switch (reg_type) {
9718 	case REG_A:
9719 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a, data);
9720 		break;
9721 	case REG_B:
9722 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_b, data);
9723 		break;
9724 	case REG_C_0:
9725 		/*
9726 		 * The metadata register C0 field might be divided into
9727 		 * source vport index and META item value, we should set
9728 		 * this field according to specified mask, not as whole one.
9729 		 */
9730 		temp = MLX5_GET(fte_match_set_misc2, misc2_v, metadata_reg_c_0);
9731 		if (mask)
9732 			temp &= ~mask;
9733 		temp |= data;
9734 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_0, temp);
9735 		break;
9736 	case REG_C_1:
9737 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_1, data);
9738 		break;
9739 	case REG_C_2:
9740 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_2, data);
9741 		break;
9742 	case REG_C_3:
9743 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_3, data);
9744 		break;
9745 	case REG_C_4:
9746 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_4, data);
9747 		break;
9748 	case REG_C_5:
9749 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_5, data);
9750 		break;
9751 	case REG_C_6:
9752 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_6, data);
9753 		break;
9754 	case REG_C_7:
9755 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_c_7, data);
9756 		break;
9757 	default:
9758 		MLX5_ASSERT(false);
9759 		break;
9760 	}
9761 }
9762 
9763 /**
9764  * Add metadata register item to matcher
9765  *
9766  * @param[in, out] matcher
9767  *   Flow matcher.
9768  * @param[in, out] key
9769  *   Flow matcher value.
9770  * @param[in] reg_type
9771  *   Type of device metadata register
9772  * @param[in] value
9773  *   Register value
9774  * @param[in] mask
9775  *   Register mask
9776  */
9777 static void
9778 flow_dv_match_meta_reg_all(void *matcher, void *key, enum modify_reg reg_type,
9779 			   uint32_t data, uint32_t mask)
9780 {
9781 	flow_dv_match_meta_reg(key, reg_type, data, mask);
9782 	flow_dv_match_meta_reg(matcher, reg_type, mask, mask);
9783 }
9784 
9785 /**
9786  * Add MARK item to matcher
9787  *
9788  * @param[in] dev
9789  *   The device to configure through.
9790  * @param[in, out] key
9791  *   Flow matcher value.
9792  * @param[in] item
9793  *   Flow pattern to translate.
9794  * @param[in] key_type
9795  *   Set flow matcher mask or value.
9796  */
9797 static void
9798 flow_dv_translate_item_mark(struct rte_eth_dev *dev, void *key,
9799 			    const struct rte_flow_item *item,
9800 			    uint32_t key_type)
9801 {
9802 	struct mlx5_priv *priv = dev->data->dev_private;
9803 	const struct rte_flow_item_mark *mark;
9804 	uint32_t value;
9805 	uint32_t mask = 0;
9806 
9807 	if (key_type & MLX5_SET_MATCHER_SW) {
9808 		mark = item->mask ? (const void *)item->mask :
9809 				    &rte_flow_item_mark_mask;
9810 		mask = mark->id;
9811 		if (key_type == MLX5_SET_MATCHER_SW_M) {
9812 			value = mask;
9813 		} else {
9814 			mark = (const void *)item->spec;
9815 			MLX5_ASSERT(mark);
9816 			value = mark->id;
9817 		}
9818 	} else {
9819 		mark = (key_type == MLX5_SET_MATCHER_HS_V) ?
9820 			(const void *)item->spec : (const void *)item->mask;
9821 		MLX5_ASSERT(mark);
9822 		value = mark->id;
9823 		if (key_type == MLX5_SET_MATCHER_HS_M)
9824 			mask = value;
9825 	}
9826 	mask &= priv->sh->dv_mark_mask;
9827 	value &= mask;
9828 	if (mask) {
9829 		enum modify_reg reg;
9830 
9831 		/* Get the metadata register index for the mark. */
9832 		reg = mlx5_flow_get_reg_id(dev, MLX5_FLOW_MARK, 0, NULL);
9833 		MLX5_ASSERT(reg > 0);
9834 		if (reg == REG_C_0) {
9835 			struct mlx5_priv *priv = dev->data->dev_private;
9836 			uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9837 			uint32_t shl_c0 = rte_bsf32(msk_c0);
9838 
9839 			mask &= msk_c0;
9840 			mask <<= shl_c0;
9841 			value <<= shl_c0;
9842 		}
9843 		flow_dv_match_meta_reg(key, reg, value, mask);
9844 	}
9845 }
9846 
9847 /**
9848  * Add META item to matcher
9849  *
9850  * @param[in] dev
9851  *   The devich to configure through.
9852  * @param[in, out] key
9853  *   Flow matcher value.
9854  * @param[in] attr
9855  *   Attributes of flow that includes this item.
9856  * @param[in] item
9857  *   Flow pattern to translate.
9858  * @param[in] key_type
9859  *   Set flow matcher mask or value.
9860  */
9861 static void
9862 flow_dv_translate_item_meta(struct rte_eth_dev *dev,
9863 			    void *key,
9864 			    const struct rte_flow_attr *attr,
9865 			    const struct rte_flow_item *item,
9866 			    uint32_t key_type)
9867 {
9868 	const struct rte_flow_item_meta *meta_m;
9869 	const struct rte_flow_item_meta *meta_v;
9870 	uint32_t value;
9871 	uint32_t mask = 0;
9872 	int reg;
9873 
9874 	if (MLX5_ITEM_VALID(item, key_type))
9875 		return;
9876 	MLX5_ITEM_UPDATE(item, key_type, meta_v, meta_m,
9877 			 &rte_flow_item_meta_mask);
9878 	value = meta_v->data;
9879 	mask = meta_m->data;
9880 	if (key_type == MLX5_SET_MATCHER_HS_M)
9881 		mask = value;
9882 	/*
9883 	 * In the current implementation, REG_B cannot be used to match.
9884 	 * Force to use REG_C_1 in HWS root table as other tables.
9885 	 * This map may change.
9886 	 * NIC: modify - REG_B to be present in SW
9887 	 *      match - REG_C_1 when copied from FDB, different from SWS
9888 	 * FDB: modify - REG_C_1 in Xmeta mode, REG_NON in legacy mode
9889 	 *      match - REG_C_1 in FDB
9890 	 */
9891 	if (!!(key_type & MLX5_SET_MATCHER_SW))
9892 		reg = flow_dv_get_metadata_reg(dev, attr, NULL);
9893 	else
9894 		reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_META, 0);
9895 	if (reg < 0)
9896 		return;
9897 	MLX5_ASSERT(reg != REG_NON);
9898 	if (reg == REG_C_0) {
9899 		struct mlx5_priv *priv = dev->data->dev_private;
9900 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9901 		uint32_t shl_c0 = rte_bsf32(msk_c0);
9902 
9903 		mask &= msk_c0;
9904 		mask <<= shl_c0;
9905 		value <<= shl_c0;
9906 	}
9907 	flow_dv_match_meta_reg(key, reg, value, mask);
9908 }
9909 
9910 /**
9911  * Add vport metadata Reg C0 item to matcher
9912  *
9913  * @param[in, out] key
9914  *   Flow matcher value.
9915  * @param[in] value
9916  *   Register value
9917  * @param[in] mask
9918  *   Register mask
9919  */
9920 static void
9921 flow_dv_translate_item_meta_vport(void *key, uint32_t value, uint32_t mask)
9922 {
9923 	flow_dv_match_meta_reg(key, REG_C_0, value, mask);
9924 }
9925 
9926 /**
9927  * Add tag item to matcher
9928  *
9929  * @param[in] dev
9930  *   The devich to configure through.
9931  * @param[in, out] key
9932  *   Flow matcher value.
9933  * @param[in] item
9934  *   Flow pattern to translate.
9935  * @param[in] key_type
9936  *   Set flow matcher mask or value.
9937  */
9938 static void
9939 flow_dv_translate_mlx5_item_tag(struct rte_eth_dev *dev, void *key,
9940 				const struct rte_flow_item *item,
9941 				uint32_t key_type)
9942 {
9943 	const struct mlx5_rte_flow_item_tag *tag_v = item->spec;
9944 	const struct mlx5_rte_flow_item_tag *tag_m = item->mask;
9945 	uint32_t mask, value;
9946 
9947 	MLX5_ASSERT(tag_v);
9948 	value = tag_v->data;
9949 	mask = tag_m ? tag_m->data : UINT32_MAX;
9950 	if (key_type & MLX5_SET_MATCHER_M)
9951 		value = mask;
9952 	if (tag_v->id == REG_C_0) {
9953 		struct mlx5_priv *priv = dev->data->dev_private;
9954 		uint32_t msk_c0 = priv->sh->dv_regc0_mask;
9955 		uint32_t shl_c0 = rte_bsf32(msk_c0);
9956 
9957 		mask &= msk_c0;
9958 		mask <<= shl_c0;
9959 		value <<= shl_c0;
9960 	}
9961 	flow_dv_match_meta_reg(key, tag_v->id, value, mask);
9962 }
9963 
9964 /**
9965  * Add TAG item to matcher
9966  *
9967  * @param[in] dev
9968  *   The devich to configure through.
9969  * @param[in, out] key
9970  *   Flow matcher value.
9971  * @param[in] item
9972  *   Flow pattern to translate.
9973  * @param[in] key_type
9974  *   Set flow matcher mask or value.
9975  */
9976 static void
9977 flow_dv_translate_item_tag(struct rte_eth_dev *dev, void *key,
9978 			   const struct rte_flow_item *item,
9979 			   uint32_t key_type)
9980 {
9981 	const struct rte_flow_item_tag *tag_vv = item->spec;
9982 	const struct rte_flow_item_tag *tag_v;
9983 	const struct rte_flow_item_tag *tag_m;
9984 	enum modify_reg reg;
9985 	uint32_t index;
9986 
9987 	if (MLX5_ITEM_VALID(item, key_type))
9988 		return;
9989 	MLX5_ITEM_UPDATE(item, key_type, tag_v, tag_m,
9990 		&rte_flow_item_tag_mask);
9991 	/* When set mask, the index should be from spec. */
9992 	index = tag_vv ? tag_vv->index : tag_v->index;
9993 	/* Get the metadata register index for the tag. */
9994 	if (!!(key_type & MLX5_SET_MATCHER_SW))
9995 		reg = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, index, NULL);
9996 	else
9997 		reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_TAG, index);
9998 	MLX5_ASSERT(reg > 0);
9999 	flow_dv_match_meta_reg(key, reg, tag_v->data, tag_m->data);
10000 }
10001 
10002 /**
10003  * Add source vport match to the specified matcher.
10004  *
10005  * @param[in, out] key
10006  *   Flow matcher value.
10007  * @param[in] port
10008  *   Source vport value to match
10009  */
10010 static void
10011 flow_dv_translate_item_source_vport(void *key,
10012 				    int16_t port)
10013 {
10014 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
10015 
10016 	MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
10017 }
10018 
10019 /**
10020  * Translate port-id item to eswitch match on  port-id.
10021  *
10022  * @param[in] dev
10023  *   The devich to configure through.
10024  * @param[in, out] key
10025  *   Flow matcher value.
10026  * @param[in] item
10027  *   Flow pattern to translate.
10028  * @param[in] attr
10029  *   Flow attributes.
10030  * @param[in] key_type
10031  *   Set flow matcher mask or value.
10032  *
10033  * @return
10034  *   0 on success, a negative errno value otherwise.
10035  */
10036 static int
10037 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *key,
10038 			       const struct rte_flow_item *item,
10039 			       const struct rte_flow_attr *attr,
10040 			       uint32_t key_type)
10041 {
10042 	const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL;
10043 	const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL;
10044 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
10045 	struct mlx5_priv *priv;
10046 	uint16_t mask, id;
10047 	uint32_t vport_meta;
10048 
10049 	MLX5_ASSERT(wks);
10050 	if (pid_v && pid_v->id == MLX5_PORT_ESW_MGR) {
10051 		flow_dv_translate_item_source_vport(key,
10052 				key_type & MLX5_SET_MATCHER_V ?
10053 				mlx5_flow_get_esw_manager_vport_id(dev) : 0xffff);
10054 		return 0;
10055 	}
10056 	mask = pid_m ? pid_m->id : 0xffff;
10057 	id = pid_v ? pid_v->id : dev->data->port_id;
10058 	priv = mlx5_port_to_eswitch_info(id, item == NULL);
10059 	if (!priv)
10060 		return -rte_errno;
10061 	if (key_type & MLX5_SET_MATCHER_M) {
10062 		id = mask;
10063 		vport_meta = priv->vport_meta_mask;
10064 	} else {
10065 		id = priv->vport_id;
10066 		vport_meta = priv->vport_meta_tag;
10067 		wks->vport_meta_tag = vport_meta;
10068 	}
10069 	/*
10070 	 * Translate to vport field or to metadata, depending on mode.
10071 	 * Kernel can use either misc.source_port or half of C0 metadata
10072 	 * register.
10073 	 */
10074 	if (priv->vport_meta_mask) {
10075 		/*
10076 		 * Provide the hint for SW steering library
10077 		 * to insert the flow into ingress domain and
10078 		 * save the extra vport match.
10079 		 */
10080 		if (mask == 0xffff && priv->vport_id == 0xffff &&
10081 		    priv->pf_bond < 0 && attr->transfer)
10082 			flow_dv_translate_item_source_vport(key, id);
10083 		/*
10084 		 * We should always set the vport metadata register,
10085 		 * otherwise the SW steering library can drop
10086 		 * the rule if wire vport metadata value is not zero,
10087 		 * it depends on kernel configuration.
10088 		 */
10089 		flow_dv_translate_item_meta_vport
10090 				(key, vport_meta, priv->vport_meta_mask);
10091 	} else {
10092 		flow_dv_translate_item_source_vport(key, id);
10093 	}
10094 	return 0;
10095 }
10096 
10097 /**
10098  * Translate port representor item to eswitch match on port id.
10099  *
10100  * @param[in] dev
10101  *   The devich to configure through.
10102  * @param[in, out] key
10103  *   Flow matcher value.
10104  * @param[in] key_type
10105  *   Set flow matcher mask or value.
10106  *
10107  * @return
10108  *   0 on success, a negative errno value otherwise.
10109  */
10110 static int
10111 flow_dv_translate_item_port_representor(struct rte_eth_dev *dev, void *key,
10112 					uint32_t key_type)
10113 {
10114 	flow_dv_translate_item_source_vport(key,
10115 			key_type & MLX5_SET_MATCHER_V ?
10116 			mlx5_flow_get_esw_manager_vport_id(dev) : 0xffff);
10117 	return 0;
10118 }
10119 
10120 /**
10121  * Translate represented port item to eswitch match on port id.
10122  *
10123  * @param[in] dev
10124  *   The devich to configure through.
10125  * @param[in, out] key
10126  *   Flow matcher value.
10127  * @param[in] item
10128  *   Flow pattern to translate.
10129  * @param[in]
10130  *   Flow attributes.
10131  *
10132  * @return
10133  *   0 on success, a negative errno value otherwise.
10134  */
10135 static int
10136 flow_dv_translate_item_represented_port(struct rte_eth_dev *dev, void *key,
10137 					const struct rte_flow_item *item,
10138 					const struct rte_flow_attr *attr,
10139 					uint32_t key_type)
10140 {
10141 	const struct rte_flow_item_ethdev *pid_m = item ? item->mask : NULL;
10142 	const struct rte_flow_item_ethdev *pid_v = item ? item->spec : NULL;
10143 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
10144 	struct mlx5_priv *priv;
10145 	uint16_t mask, id;
10146 	uint32_t vport_meta;
10147 
10148 	MLX5_ASSERT(wks);
10149 	if (!pid_m && !pid_v)
10150 		return 0;
10151 	if (pid_v && pid_v->port_id == UINT16_MAX) {
10152 		flow_dv_translate_item_source_vport(key,
10153 			key_type & MLX5_SET_MATCHER_V ?
10154 			mlx5_flow_get_esw_manager_vport_id(dev) : 0xffff);
10155 		return 0;
10156 	}
10157 	mask = pid_m ? pid_m->port_id : UINT16_MAX;
10158 	id = pid_v ? pid_v->port_id : dev->data->port_id;
10159 	priv = mlx5_port_to_eswitch_info(id, item == NULL);
10160 	if (!priv)
10161 		return -rte_errno;
10162 	if (key_type & MLX5_SET_MATCHER_M) {
10163 		id = mask;
10164 		vport_meta = priv->vport_meta_mask;
10165 	} else {
10166 		id = priv->vport_id;
10167 		vport_meta = priv->vport_meta_tag;
10168 		wks->vport_meta_tag = vport_meta;
10169 	}
10170 	/*
10171 	 * Translate to vport field or to metadata, depending on mode.
10172 	 * Kernel can use either misc.source_port or half of C0 metadata
10173 	 * register.
10174 	 */
10175 	if (priv->vport_meta_mask) {
10176 		/*
10177 		 * Provide the hint for SW steering library
10178 		 * to insert the flow into ingress domain and
10179 		 * save the extra vport match.
10180 		 */
10181 		if (mask == UINT16_MAX && priv->vport_id == UINT16_MAX &&
10182 		    priv->pf_bond < 0 && attr->transfer &&
10183 		    priv->sh->config.dv_flow_en != 2)
10184 			flow_dv_translate_item_source_vport(key, id);
10185 		/*
10186 		 * We should always set the vport metadata register,
10187 		 * otherwise the SW steering library can drop
10188 		 * the rule if wire vport metadata value is not zero,
10189 		 * it depends on kernel configuration.
10190 		 */
10191 		flow_dv_translate_item_meta_vport(key, vport_meta,
10192 						  priv->vport_meta_mask);
10193 	} else {
10194 		flow_dv_translate_item_source_vport(key, id);
10195 	}
10196 	return 0;
10197 }
10198 
10199 /**
10200  * Translate port-id item to eswitch match on  port-id.
10201  *
10202  * @param[in] dev
10203  *   The devich to configure through.
10204  * @param[in, out] matcher
10205  *   Flow matcher.
10206  * @param[in, out] key
10207  *   Flow matcher value.
10208  * @param[in] item
10209  *   Flow pattern to translate.
10210  * @param[in] attr
10211  *   Flow attributes.
10212  *
10213  * @return
10214  *   0 on success, a negative errno value otherwise.
10215  */
10216 static int
10217 flow_dv_translate_item_port_id_all(struct rte_eth_dev *dev,
10218 			       void *matcher, void *key,
10219 			       const struct rte_flow_item *item,
10220 			       const struct rte_flow_attr *attr)
10221 {
10222 	int ret;
10223 
10224 	ret = flow_dv_translate_item_port_id
10225 			(dev, matcher, item, attr, MLX5_SET_MATCHER_SW_M);
10226 	if (ret)
10227 		return ret;
10228 	ret = flow_dv_translate_item_port_id
10229 			(dev, key, item, attr, MLX5_SET_MATCHER_SW_V);
10230 	return ret;
10231 }
10232 
10233 
10234 /**
10235  * Add ICMP6 item to the value.
10236  *
10237  * @param[in, out] key
10238  *   Flow matcher value.
10239  * @param[in] item
10240  *   Flow pattern to translate.
10241  * @param[in] inner
10242  *   Item is inner pattern.
10243  * @param[in] key_type
10244  *   Set flow matcher mask or value.
10245  */
10246 static void
10247 flow_dv_translate_item_icmp6(void *key, const struct rte_flow_item *item,
10248 			     int inner, uint32_t key_type)
10249 {
10250 	const struct rte_flow_item_icmp6 *icmp6_m;
10251 	const struct rte_flow_item_icmp6 *icmp6_v;
10252 	void *headers_v;
10253 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
10254 
10255 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
10256 		MLX5_ADDR_OF(fte_match_param, key, outer_headers);
10257 	if (key_type & MLX5_SET_MATCHER_M)
10258 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, 0xFF);
10259 	else
10260 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
10261 			 IPPROTO_ICMPV6);
10262 	if (MLX5_ITEM_VALID(item, key_type))
10263 		return;
10264 	MLX5_ITEM_UPDATE(item, key_type, icmp6_v, icmp6_m,
10265 		&rte_flow_item_icmp6_mask);
10266 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type,
10267 		 icmp6_v->type & icmp6_m->type);
10268 	MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code,
10269 		 icmp6_v->code & icmp6_m->code);
10270 }
10271 
10272 /**
10273  * Add ICMP item to the value.
10274  *
10275  * @param[in, out] key
10276  *   Flow matcher value.
10277  * @param[in] item
10278  *   Flow pattern to translate.
10279  * @param[in] inner
10280  *   Item is inner pattern.
10281  * @param[in] key_type
10282  *   Set flow matcher mask or value.
10283  */
10284 static void
10285 flow_dv_translate_item_icmp(void *key, const struct rte_flow_item *item,
10286 			    int inner, uint32_t key_type)
10287 {
10288 	const struct rte_flow_item_icmp *icmp_m;
10289 	const struct rte_flow_item_icmp *icmp_v;
10290 	uint32_t icmp_header_data_m = 0;
10291 	uint32_t icmp_header_data_v = 0;
10292 	void *headers_v;
10293 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
10294 
10295 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
10296 			MLX5_ADDR_OF(fte_match_param, key, outer_headers);
10297 	if (key_type & MLX5_SET_MATCHER_M)
10298 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
10299 			 ip_protocol, 0xFF);
10300 	else
10301 		MLX5_SET(fte_match_set_lyr_2_4, headers_v,
10302 			 ip_protocol, IPPROTO_ICMP);
10303 	if (MLX5_ITEM_VALID(item, key_type))
10304 		return;
10305 	MLX5_ITEM_UPDATE(item, key_type, icmp_v, icmp_m,
10306 		&rte_flow_item_icmp_mask);
10307 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type,
10308 		 icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type);
10309 	MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code,
10310 		 icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code);
10311 	icmp_header_data_m = rte_be_to_cpu_16(icmp_m->hdr.icmp_seq_nb);
10312 	icmp_header_data_m |= rte_be_to_cpu_16(icmp_m->hdr.icmp_ident) << 16;
10313 	if (icmp_header_data_m) {
10314 		icmp_header_data_v = rte_be_to_cpu_16(icmp_v->hdr.icmp_seq_nb);
10315 		icmp_header_data_v |=
10316 			 rte_be_to_cpu_16(icmp_v->hdr.icmp_ident) << 16;
10317 		MLX5_SET(fte_match_set_misc3, misc3_v, icmp_header_data,
10318 			 icmp_header_data_v & icmp_header_data_m);
10319 	}
10320 }
10321 
10322 /**
10323  * Add GTP item to the value.
10324  *
10325  * @param[in, out] key
10326  *   Flow matcher value.
10327  * @param[in] item
10328  *   Flow pattern to translate.
10329  * @param[in] inner
10330  *   Item is inner pattern.
10331  * @param[in] key_type
10332  *   Set flow matcher mask or value.
10333  */
10334 static void
10335 flow_dv_translate_item_gtp(void *key, const struct rte_flow_item *item,
10336 			   int inner, uint32_t key_type)
10337 {
10338 	const struct rte_flow_item_gtp *gtp_m;
10339 	const struct rte_flow_item_gtp *gtp_v;
10340 	void *headers_v;
10341 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
10342 	uint16_t dport = RTE_GTPU_UDP_PORT;
10343 
10344 	headers_v = inner ? MLX5_ADDR_OF(fte_match_param, key, inner_headers) :
10345 			MLX5_ADDR_OF(fte_match_param, key, outer_headers);
10346 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
10347 		if (key_type & MLX5_SET_MATCHER_M)
10348 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
10349 				 udp_dport, 0xFFFF);
10350 		else
10351 			MLX5_SET(fte_match_set_lyr_2_4, headers_v,
10352 				 udp_dport, dport);
10353 	}
10354 	if (MLX5_ITEM_VALID(item, key_type))
10355 		return;
10356 	MLX5_ITEM_UPDATE(item, key_type, gtp_v, gtp_m,
10357 		&rte_flow_item_gtp_mask);
10358 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags,
10359 		 gtp_v->hdr.gtp_hdr_info & gtp_m->hdr.gtp_hdr_info);
10360 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_type,
10361 		 gtp_v->hdr.msg_type & gtp_m->hdr.msg_type);
10362 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid,
10363 		 rte_be_to_cpu_32(gtp_v->hdr.teid & gtp_m->hdr.teid));
10364 }
10365 
10366 /**
10367  * Add GTP PSC item to matcher.
10368  *
10369  * @param[in, out] key
10370  *   Flow matcher value.
10371  * @param[in] item
10372  *   Flow pattern to translate.
10373  * @param[in] key_type
10374  *   Set flow matcher mask or value.
10375  */
10376 static int
10377 flow_dv_translate_item_gtp_psc(void *key, const struct rte_flow_item *item,
10378 			       uint32_t key_type)
10379 {
10380 	const struct rte_flow_item_gtp_psc *gtp_psc_m;
10381 	const struct rte_flow_item_gtp_psc *gtp_psc_v;
10382 	void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
10383 	union {
10384 		uint32_t w32;
10385 		struct {
10386 			uint16_t seq_num;
10387 			uint8_t npdu_num;
10388 			uint8_t next_ext_header_type;
10389 		};
10390 	} dw_2;
10391 	union {
10392 		uint32_t w32;
10393 		struct {
10394 			uint8_t len;
10395 			uint8_t type_flags;
10396 			uint8_t qfi;
10397 			uint8_t reserved;
10398 		};
10399 	} dw_0;
10400 	uint8_t gtp_flags;
10401 
10402 	/* Always set E-flag match on one, regardless of GTP item settings. */
10403 	gtp_flags = MLX5_GET(fte_match_set_misc3, misc3_v, gtpu_msg_flags);
10404 	gtp_flags |= MLX5_GTP_EXT_HEADER_FLAG;
10405 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_msg_flags, gtp_flags);
10406 	/*Set next extension header type. */
10407 	dw_2.seq_num = 0;
10408 	dw_2.npdu_num = 0;
10409 	if (key_type & MLX5_SET_MATCHER_M)
10410 		dw_2.next_ext_header_type = 0xff;
10411 	else
10412 		dw_2.next_ext_header_type = 0x85;
10413 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_dw_2,
10414 		 rte_cpu_to_be_32(dw_2.w32));
10415 	if (MLX5_ITEM_VALID(item, key_type))
10416 		return 0;
10417 	MLX5_ITEM_UPDATE(item, key_type, gtp_psc_v,
10418 		gtp_psc_m, &rte_flow_item_gtp_psc_mask);
10419 	dw_0.w32 = 0;
10420 	dw_0.type_flags = MLX5_GTP_PDU_TYPE_SHIFT(gtp_psc_v->hdr.type &
10421 						  gtp_psc_m->hdr.type);
10422 	dw_0.qfi = gtp_psc_v->hdr.qfi & gtp_psc_m->hdr.qfi;
10423 	MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_first_ext_dw_0,
10424 		 rte_cpu_to_be_32(dw_0.w32));
10425 	return 0;
10426 }
10427 
10428 /**
10429  * Add eCPRI item to matcher and to the value.
10430  *
10431  * @param[in] dev
10432  *   The devich to configure through.
10433  * @param[in, out] key
10434  *   Flow matcher value.
10435  * @param[in] item
10436  *   Flow pattern to translate.
10437  * @param[in] last_item
10438  *   Last item flags.
10439  * @param[in] key_type
10440  *   Set flow matcher mask or value.
10441  */
10442 static void
10443 flow_dv_translate_item_ecpri(struct rte_eth_dev *dev, void *key,
10444 			     const struct rte_flow_item *item,
10445 			     uint64_t last_item, uint32_t key_type)
10446 {
10447 	struct mlx5_priv *priv = dev->data->dev_private;
10448 	const struct rte_flow_item_ecpri *ecpri_m;
10449 	const struct rte_flow_item_ecpri *ecpri_v;
10450 	const struct rte_flow_item_ecpri *ecpri_vv = item->spec;
10451 	struct rte_ecpri_common_hdr common;
10452 	void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4);
10453 	uint32_t *samples;
10454 	void *dw_v;
10455 
10456 	/*
10457 	 * In case of eCPRI over Ethernet, if EtherType is not specified,
10458 	 * match on eCPRI EtherType implicitly.
10459 	 */
10460 	if (last_item & MLX5_FLOW_LAYER_OUTER_L2) {
10461 		void *hdrs_v, *l2v;
10462 
10463 		hdrs_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
10464 		l2v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, hdrs_v, ethertype);
10465 		if (*(uint16_t *)l2v == 0) {
10466 			if (key_type & MLX5_SET_MATCHER_M)
10467 				*(uint16_t *)l2v = UINT16_MAX;
10468 			else
10469 				*(uint16_t *)l2v =
10470 					RTE_BE16(RTE_ETHER_TYPE_ECPRI);
10471 		}
10472 	}
10473 	if (MLX5_ITEM_VALID(item, key_type))
10474 		return;
10475 	MLX5_ITEM_UPDATE(item, key_type, ecpri_v, ecpri_m,
10476 		&rte_flow_item_ecpri_mask);
10477 	/*
10478 	 * Maximal four DW samples are supported in a single matching now.
10479 	 * Two are used now for a eCPRI matching:
10480 	 * 1. Type: one byte, mask should be 0x00ff0000 in network order
10481 	 * 2. ID of a message: one or two bytes, mask 0xffff0000 or 0xff000000
10482 	 *    if any.
10483 	 */
10484 	if (!ecpri_m->hdr.common.u32)
10485 		return;
10486 	samples = priv->sh->ecpri_parser.ids;
10487 	/* Need to take the whole DW as the mask to fill the entry. */
10488 	dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
10489 			    prog_sample_field_value_0);
10490 	/* Already big endian (network order) in the header. */
10491 	*(uint32_t *)dw_v = ecpri_v->hdr.common.u32 & ecpri_m->hdr.common.u32;
10492 	/* Sample#0, used for matching type, offset 0. */
10493 	/* It makes no sense to set the sample ID in the mask field. */
10494 	MLX5_SET(fte_match_set_misc4, misc4_v,
10495 		 prog_sample_field_id_0, samples[0]);
10496 	/*
10497 	 * Checking if message body part needs to be matched.
10498 	 * Some wildcard rules only matching type field should be supported.
10499 	 */
10500 	if (ecpri_m->hdr.dummy[0]) {
10501 		if (key_type == MLX5_SET_MATCHER_SW_M)
10502 			common.u32 = rte_be_to_cpu_32(ecpri_vv->hdr.common.u32);
10503 		else
10504 			common.u32 = rte_be_to_cpu_32(ecpri_v->hdr.common.u32);
10505 		switch (common.type) {
10506 		case RTE_ECPRI_MSG_TYPE_IQ_DATA:
10507 		case RTE_ECPRI_MSG_TYPE_RTC_CTRL:
10508 		case RTE_ECPRI_MSG_TYPE_DLY_MSR:
10509 			dw_v = MLX5_ADDR_OF(fte_match_set_misc4, misc4_v,
10510 					    prog_sample_field_value_1);
10511 			*(uint32_t *)dw_v = ecpri_v->hdr.dummy[0] &
10512 					    ecpri_m->hdr.dummy[0];
10513 			/* Sample#1, to match message body, offset 4. */
10514 			MLX5_SET(fte_match_set_misc4, misc4_v,
10515 				 prog_sample_field_id_1, samples[1]);
10516 			break;
10517 		default:
10518 			/* Others, do not match any sample ID. */
10519 			break;
10520 		}
10521 	}
10522 }
10523 
10524 /*
10525  * Add connection tracking status item to matcher
10526  *
10527  * @param[in] dev
10528  *   The devich to configure through.
10529  * @param[in, out] matcher
10530  *   Flow matcher.
10531  * @param[in, out] key
10532  *   Flow matcher value.
10533  * @param[in] item
10534  *   Flow pattern to translate.
10535  */
10536 static void
10537 flow_dv_translate_item_aso_ct(struct rte_eth_dev *dev,
10538 			      void *matcher, void *key,
10539 			      const struct rte_flow_item *item)
10540 {
10541 	uint32_t reg_value = 0;
10542 	int reg_id;
10543 	/* 8LSB 0b 11/0000/11, middle 4 bits are reserved. */
10544 	uint32_t reg_mask = 0;
10545 	const struct rte_flow_item_conntrack *spec = item->spec;
10546 	const struct rte_flow_item_conntrack *mask = item->mask;
10547 	uint32_t flags;
10548 	struct rte_flow_error error;
10549 
10550 	if (!mask)
10551 		mask = &rte_flow_item_conntrack_mask;
10552 	if (!spec || !mask->flags)
10553 		return;
10554 	flags = spec->flags & mask->flags;
10555 	/* The conflict should be checked in the validation. */
10556 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID)
10557 		reg_value |= MLX5_CT_SYNDROME_VALID;
10558 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
10559 		reg_value |= MLX5_CT_SYNDROME_STATE_CHANGE;
10560 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID)
10561 		reg_value |= MLX5_CT_SYNDROME_INVALID;
10562 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)
10563 		reg_value |= MLX5_CT_SYNDROME_TRAP;
10564 	if (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
10565 		reg_value |= MLX5_CT_SYNDROME_BAD_PACKET;
10566 	if (mask->flags & (RTE_FLOW_CONNTRACK_PKT_STATE_VALID |
10567 			   RTE_FLOW_CONNTRACK_PKT_STATE_INVALID |
10568 			   RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED))
10569 		reg_mask |= 0xc0;
10570 	if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_CHANGED)
10571 		reg_mask |= MLX5_CT_SYNDROME_STATE_CHANGE;
10572 	if (mask->flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD)
10573 		reg_mask |= MLX5_CT_SYNDROME_BAD_PACKET;
10574 	/* The REG_C_x value could be saved during startup. */
10575 	reg_id = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, &error);
10576 	if (reg_id == REG_NON)
10577 		return;
10578 	flow_dv_match_meta_reg_all(matcher, key, (enum modify_reg)reg_id,
10579 			       reg_value, reg_mask);
10580 }
10581 
10582 static void
10583 flow_dv_translate_item_flex(struct rte_eth_dev *dev, void *matcher, void *key,
10584 			    const struct rte_flow_item *item,
10585 			    struct mlx5_flow *dev_flow, bool is_inner)
10586 {
10587 	const struct rte_flow_item_flex *spec =
10588 		(const struct rte_flow_item_flex *)item->spec;
10589 	int index = mlx5_flex_acquire_index(dev, spec->handle, false);
10590 
10591 	MLX5_ASSERT(index >= 0 && index <= (int)(sizeof(uint32_t) * CHAR_BIT));
10592 	if (index < 0)
10593 		return;
10594 	if (!(dev_flow->handle->flex_item & RTE_BIT32(index))) {
10595 		/* Don't count both inner and outer flex items in one rule. */
10596 		if (mlx5_flex_acquire_index(dev, spec->handle, true) != index)
10597 			MLX5_ASSERT(false);
10598 		dev_flow->handle->flex_item |= (uint8_t)RTE_BIT32(index);
10599 	}
10600 	mlx5_flex_flow_translate_item(dev, matcher, key, item, is_inner);
10601 }
10602 
10603 /**
10604  * Add METER_COLOR item to matcher
10605  *
10606  * @param[in] dev
10607  *   The device to configure through.
10608  * @param[in, out] key
10609  *   Flow matcher value.
10610  * @param[in] item
10611  *   Flow pattern to translate.
10612  * @param[in] key_type
10613  *   Set flow matcher mask or value.
10614  */
10615 static void
10616 flow_dv_translate_item_meter_color(struct rte_eth_dev *dev, void *key,
10617 			    const struct rte_flow_item *item,
10618 			    uint32_t key_type)
10619 {
10620 	const struct rte_flow_item_meter_color *color_m = item->mask;
10621 	const struct rte_flow_item_meter_color *color_v = item->spec;
10622 	uint32_t value, mask;
10623 	int reg = REG_NON;
10624 
10625 	MLX5_ASSERT(color_v);
10626 	if (MLX5_ITEM_VALID(item, key_type))
10627 		return;
10628 	MLX5_ITEM_UPDATE(item, key_type, color_v, color_m,
10629 		&rte_flow_item_meter_color_mask);
10630 	value = rte_col_2_mlx5_col(color_v->color);
10631 	mask = color_m ?
10632 		color_m->color : (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
10633 	if (!!(key_type & MLX5_SET_MATCHER_SW))
10634 		reg = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, NULL);
10635 	else
10636 		reg = flow_hw_get_reg_id(RTE_FLOW_ITEM_TYPE_METER_COLOR, 0);
10637 	if (reg == REG_NON)
10638 		return;
10639 	flow_dv_match_meta_reg(key, (enum modify_reg)reg, value, mask);
10640 }
10641 
10642 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
10643 
10644 #define HEADER_IS_ZERO(match_criteria, headers)				     \
10645 	!(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
10646 		 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
10647 
10648 /**
10649  * Calculate flow matcher enable bitmap.
10650  *
10651  * @param match_criteria
10652  *   Pointer to flow matcher criteria.
10653  *
10654  * @return
10655  *   Bitmap of enabled fields.
10656  */
10657 static uint8_t
10658 flow_dv_matcher_enable(uint32_t *match_criteria)
10659 {
10660 	uint8_t match_criteria_enable;
10661 
10662 	match_criteria_enable =
10663 		(!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
10664 		MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
10665 	match_criteria_enable |=
10666 		(!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
10667 		MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
10668 	match_criteria_enable |=
10669 		(!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
10670 		MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
10671 	match_criteria_enable |=
10672 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
10673 		MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
10674 	match_criteria_enable |=
10675 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
10676 		MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
10677 	match_criteria_enable |=
10678 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_4)) <<
10679 		MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT;
10680 	match_criteria_enable |=
10681 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_5)) <<
10682 		MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT;
10683 	return match_criteria_enable;
10684 }
10685 
10686 static void
10687 __flow_dv_adjust_buf_size(size_t *size, uint8_t match_criteria)
10688 {
10689 	/*
10690 	 * Check flow matching criteria first, subtract misc5/4 length if flow
10691 	 * doesn't own misc5/4 parameters. In some old rdma-core releases,
10692 	 * misc5/4 are not supported, and matcher creation failure is expected
10693 	 * w/o subtraction. If misc5 is provided, misc4 must be counted in since
10694 	 * misc5 is right after misc4.
10695 	 */
10696 	if (!(match_criteria & (1 << MLX5_MATCH_CRITERIA_ENABLE_MISC5_BIT))) {
10697 		*size = MLX5_ST_SZ_BYTES(fte_match_param) -
10698 			MLX5_ST_SZ_BYTES(fte_match_set_misc5);
10699 		if (!(match_criteria & (1 <<
10700 			MLX5_MATCH_CRITERIA_ENABLE_MISC4_BIT))) {
10701 			*size -= MLX5_ST_SZ_BYTES(fte_match_set_misc4);
10702 		}
10703 	}
10704 }
10705 
10706 static struct mlx5_list_entry *
10707 flow_dv_matcher_clone_cb(void *tool_ctx __rte_unused,
10708 			 struct mlx5_list_entry *entry, void *cb_ctx)
10709 {
10710 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10711 	struct mlx5_flow_dv_matcher *ref = ctx->data;
10712 	struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
10713 							    typeof(*tbl), tbl);
10714 	struct mlx5_flow_dv_matcher *resource = mlx5_malloc(MLX5_MEM_ANY,
10715 							    sizeof(*resource),
10716 							    0, SOCKET_ID_ANY);
10717 
10718 	if (!resource) {
10719 		rte_flow_error_set(ctx->error, ENOMEM,
10720 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10721 				   "cannot create matcher");
10722 		return NULL;
10723 	}
10724 	memcpy(resource, entry, sizeof(*resource));
10725 	resource->tbl = &tbl->tbl;
10726 	return &resource->entry;
10727 }
10728 
10729 static void
10730 flow_dv_matcher_clone_free_cb(void *tool_ctx __rte_unused,
10731 			     struct mlx5_list_entry *entry)
10732 {
10733 	mlx5_free(entry);
10734 }
10735 
10736 struct mlx5_list_entry *
10737 flow_dv_tbl_create_cb(void *tool_ctx, void *cb_ctx)
10738 {
10739 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10740 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10741 	struct rte_eth_dev *dev = ctx->dev;
10742 	struct mlx5_flow_tbl_data_entry *tbl_data;
10743 	struct mlx5_flow_tbl_tunnel_prm *tt_prm = ctx->data2;
10744 	struct rte_flow_error *error = ctx->error;
10745 	union mlx5_flow_tbl_key key = { .v64 = *(uint64_t *)(ctx->data) };
10746 	struct mlx5_flow_tbl_resource *tbl;
10747 	void *domain;
10748 	uint32_t idx = 0;
10749 	int ret;
10750 
10751 	tbl_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10752 	if (!tbl_data) {
10753 		rte_flow_error_set(error, ENOMEM,
10754 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10755 				   NULL,
10756 				   "cannot allocate flow table data entry");
10757 		return NULL;
10758 	}
10759 	tbl_data->idx = idx;
10760 	tbl_data->tunnel = tt_prm->tunnel;
10761 	tbl_data->group_id = tt_prm->group_id;
10762 	tbl_data->external = !!tt_prm->external;
10763 	tbl_data->tunnel_offload = is_tunnel_offload_active(dev);
10764 	tbl_data->is_egress = !!key.is_egress;
10765 	tbl_data->is_transfer = !!key.is_fdb;
10766 	tbl_data->dummy = !!key.dummy;
10767 	tbl_data->level = key.level;
10768 	tbl_data->id = key.id;
10769 	tbl = &tbl_data->tbl;
10770 	if (key.dummy)
10771 		return &tbl_data->entry;
10772 	if (key.is_fdb)
10773 		domain = sh->fdb_domain;
10774 	else if (key.is_egress)
10775 		domain = sh->tx_domain;
10776 	else
10777 		domain = sh->rx_domain;
10778 	ret = mlx5_flow_os_create_flow_tbl(domain, key.level, &tbl->obj);
10779 	if (ret) {
10780 		rte_flow_error_set(error, ENOMEM,
10781 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10782 				   NULL, "cannot create flow table object");
10783 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10784 		return NULL;
10785 	}
10786 	if (key.level != 0) {
10787 		ret = mlx5_flow_os_create_flow_action_dest_flow_tbl
10788 					(tbl->obj, &tbl_data->jump.action);
10789 		if (ret) {
10790 			rte_flow_error_set(error, ENOMEM,
10791 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10792 					   NULL,
10793 					   "cannot create flow jump action");
10794 			mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10795 			mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10796 			return NULL;
10797 		}
10798 	}
10799 	MKSTR(matcher_name, "%s_%s_%u_%u_matcher_list",
10800 	      key.is_fdb ? "FDB" : "NIC", key.is_egress ? "egress" : "ingress",
10801 	      key.level, key.id);
10802 	tbl_data->matchers = mlx5_list_create(matcher_name, sh, true,
10803 					      flow_dv_matcher_create_cb,
10804 					      flow_dv_matcher_match_cb,
10805 					      flow_dv_matcher_remove_cb,
10806 					      flow_dv_matcher_clone_cb,
10807 					      flow_dv_matcher_clone_free_cb);
10808 	if (!tbl_data->matchers) {
10809 		rte_flow_error_set(error, ENOMEM,
10810 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10811 				   NULL,
10812 				   "cannot create tbl matcher list");
10813 		mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10814 		mlx5_flow_os_destroy_flow_tbl(tbl->obj);
10815 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], idx);
10816 		return NULL;
10817 	}
10818 	return &tbl_data->entry;
10819 }
10820 
10821 int
10822 flow_dv_tbl_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
10823 		     void *cb_ctx)
10824 {
10825 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10826 	struct mlx5_flow_tbl_data_entry *tbl_data =
10827 		container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10828 	union mlx5_flow_tbl_key key = { .v64 =  *(uint64_t *)(ctx->data) };
10829 
10830 	return tbl_data->level != key.level ||
10831 	       tbl_data->id != key.id ||
10832 	       tbl_data->dummy != key.dummy ||
10833 	       tbl_data->is_transfer != !!key.is_fdb ||
10834 	       tbl_data->is_egress != !!key.is_egress;
10835 }
10836 
10837 struct mlx5_list_entry *
10838 flow_dv_tbl_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
10839 		      void *cb_ctx)
10840 {
10841 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10842 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
10843 	struct mlx5_flow_tbl_data_entry *tbl_data;
10844 	struct rte_flow_error *error = ctx->error;
10845 	uint32_t idx = 0;
10846 
10847 	tbl_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_JUMP], &idx);
10848 	if (!tbl_data) {
10849 		rte_flow_error_set(error, ENOMEM,
10850 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
10851 				   NULL,
10852 				   "cannot allocate flow table data entry");
10853 		return NULL;
10854 	}
10855 	memcpy(tbl_data, oentry, sizeof(*tbl_data));
10856 	tbl_data->idx = idx;
10857 	return &tbl_data->entry;
10858 }
10859 
10860 void
10861 flow_dv_tbl_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10862 {
10863 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10864 	struct mlx5_flow_tbl_data_entry *tbl_data =
10865 		    container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10866 
10867 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10868 }
10869 
10870 /**
10871  * Get a flow table.
10872  *
10873  * @param[in, out] dev
10874  *   Pointer to rte_eth_dev structure.
10875  * @param[in] table_level
10876  *   Table level to use.
10877  * @param[in] egress
10878  *   Direction of the table.
10879  * @param[in] transfer
10880  *   E-Switch or NIC flow.
10881  * @param[in] dummy
10882  *   Dummy entry for dv API.
10883  * @param[in] table_id
10884  *   Table id to use.
10885  * @param[out] error
10886  *   pointer to error structure.
10887  *
10888  * @return
10889  *   Returns tables resource based on the index, NULL in case of failed.
10890  */
10891 struct mlx5_flow_tbl_resource *
10892 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
10893 			 uint32_t table_level, uint8_t egress,
10894 			 uint8_t transfer,
10895 			 bool external,
10896 			 const struct mlx5_flow_tunnel *tunnel,
10897 			 uint32_t group_id, uint8_t dummy,
10898 			 uint32_t table_id,
10899 			 struct rte_flow_error *error)
10900 {
10901 	struct mlx5_priv *priv = dev->data->dev_private;
10902 	union mlx5_flow_tbl_key table_key = {
10903 		{
10904 			.level = table_level,
10905 			.id = table_id,
10906 			.reserved = 0,
10907 			.dummy = !!dummy,
10908 			.is_fdb = !!transfer,
10909 			.is_egress = !!egress,
10910 		}
10911 	};
10912 	struct mlx5_flow_tbl_tunnel_prm tt_prm = {
10913 		.tunnel = tunnel,
10914 		.group_id = group_id,
10915 		.external = external,
10916 	};
10917 	struct mlx5_flow_cb_ctx ctx = {
10918 		.dev = dev,
10919 		.error = error,
10920 		.data = &table_key.v64,
10921 		.data2 = &tt_prm,
10922 	};
10923 	struct mlx5_list_entry *entry;
10924 	struct mlx5_flow_tbl_data_entry *tbl_data;
10925 
10926 	entry = mlx5_hlist_register(priv->sh->flow_tbls, table_key.v64, &ctx);
10927 	if (!entry) {
10928 		rte_flow_error_set(error, ENOMEM,
10929 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
10930 				   "cannot get table");
10931 		return NULL;
10932 	}
10933 	DRV_LOG(DEBUG, "table_level %u table_id %u "
10934 		"tunnel %u group %u registered.",
10935 		table_level, table_id,
10936 		tunnel ? tunnel->tunnel_id : 0, group_id);
10937 	tbl_data = container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10938 	return &tbl_data->tbl;
10939 }
10940 
10941 void
10942 flow_dv_tbl_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
10943 {
10944 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
10945 	struct mlx5_flow_tbl_data_entry *tbl_data =
10946 		    container_of(entry, struct mlx5_flow_tbl_data_entry, entry);
10947 
10948 	MLX5_ASSERT(entry && sh);
10949 	if (tbl_data->jump.action)
10950 		mlx5_flow_os_destroy_flow_action(tbl_data->jump.action);
10951 	if (tbl_data->tbl.obj)
10952 		mlx5_flow_os_destroy_flow_tbl(tbl_data->tbl.obj);
10953 	if (tbl_data->tunnel_offload && tbl_data->external) {
10954 		struct mlx5_list_entry *he;
10955 		struct mlx5_hlist *tunnel_grp_hash;
10956 		struct mlx5_flow_tunnel_hub *thub = sh->tunnel_hub;
10957 		union tunnel_tbl_key tunnel_key = {
10958 			.tunnel_id = tbl_data->tunnel ?
10959 					tbl_data->tunnel->tunnel_id : 0,
10960 			.group = tbl_data->group_id
10961 		};
10962 		uint32_t table_level = tbl_data->level;
10963 		struct mlx5_flow_cb_ctx ctx = {
10964 			.data = (void *)&tunnel_key.val,
10965 		};
10966 
10967 		tunnel_grp_hash = tbl_data->tunnel ?
10968 					tbl_data->tunnel->groups :
10969 					thub->groups;
10970 		he = mlx5_hlist_lookup(tunnel_grp_hash, tunnel_key.val, &ctx);
10971 		if (he)
10972 			mlx5_hlist_unregister(tunnel_grp_hash, he);
10973 		DRV_LOG(DEBUG,
10974 			"table_level %u id %u tunnel %u group %u released.",
10975 			table_level,
10976 			tbl_data->id,
10977 			tbl_data->tunnel ?
10978 			tbl_data->tunnel->tunnel_id : 0,
10979 			tbl_data->group_id);
10980 	}
10981 	if (tbl_data->matchers)
10982 		mlx5_list_destroy(tbl_data->matchers);
10983 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_JUMP], tbl_data->idx);
10984 }
10985 
10986 /**
10987  * Release a flow table.
10988  *
10989  * @param[in] sh
10990  *   Pointer to device shared structure.
10991  * @param[in] tbl
10992  *   Table resource to be released.
10993  *
10994  * @return
10995  *   Returns 0 if table was released, else return 1;
10996  */
10997 int
10998 flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
10999 			     struct mlx5_flow_tbl_resource *tbl)
11000 {
11001 	struct mlx5_flow_tbl_data_entry *tbl_data =
11002 		container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
11003 
11004 	if (!tbl)
11005 		return 0;
11006 	return mlx5_hlist_unregister(sh->flow_tbls, &tbl_data->entry);
11007 }
11008 
11009 int
11010 flow_dv_matcher_match_cb(void *tool_ctx __rte_unused,
11011 			 struct mlx5_list_entry *entry, void *cb_ctx)
11012 {
11013 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11014 	struct mlx5_flow_dv_matcher *ref = ctx->data;
11015 	struct mlx5_flow_dv_matcher *cur = container_of(entry, typeof(*cur),
11016 							entry);
11017 
11018 	return cur->crc != ref->crc ||
11019 	       cur->priority != ref->priority ||
11020 	       memcmp((const void *)cur->mask.buf,
11021 		      (const void *)ref->mask.buf, ref->mask.size);
11022 }
11023 
11024 struct mlx5_list_entry *
11025 flow_dv_matcher_create_cb(void *tool_ctx, void *cb_ctx)
11026 {
11027 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
11028 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11029 	struct mlx5_flow_dv_matcher *ref = ctx->data;
11030 	struct mlx5_flow_dv_matcher *resource;
11031 	struct mlx5dv_flow_matcher_attr dv_attr = {
11032 		.type = IBV_FLOW_ATTR_NORMAL,
11033 		.match_mask = (void *)&ref->mask,
11034 	};
11035 	struct mlx5_flow_tbl_data_entry *tbl = container_of(ref->tbl,
11036 							    typeof(*tbl), tbl);
11037 	int ret;
11038 
11039 	resource = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*resource), 0,
11040 			       SOCKET_ID_ANY);
11041 	if (!resource) {
11042 		rte_flow_error_set(ctx->error, ENOMEM,
11043 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
11044 				   "cannot create matcher");
11045 		return NULL;
11046 	}
11047 	*resource = *ref;
11048 	dv_attr.match_criteria_enable =
11049 		flow_dv_matcher_enable(resource->mask.buf);
11050 	__flow_dv_adjust_buf_size(&ref->mask.size,
11051 				  dv_attr.match_criteria_enable);
11052 	dv_attr.priority = ref->priority;
11053 	if (tbl->is_egress)
11054 		dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
11055 	ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr,
11056 					       tbl->tbl.obj,
11057 					       &resource->matcher_object);
11058 	if (ret) {
11059 		mlx5_free(resource);
11060 		rte_flow_error_set(ctx->error, ENOMEM,
11061 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
11062 				   "cannot create matcher");
11063 		return NULL;
11064 	}
11065 	return &resource->entry;
11066 }
11067 
11068 /**
11069  * Register the flow matcher.
11070  *
11071  * @param[in, out] dev
11072  *   Pointer to rte_eth_dev structure.
11073  * @param[in, out] matcher
11074  *   Pointer to flow matcher.
11075  * @param[in, out] key
11076  *   Pointer to flow table key.
11077  * @parm[in, out] dev_flow
11078  *   Pointer to the dev_flow.
11079  * @param[out] error
11080  *   pointer to error structure.
11081  *
11082  * @return
11083  *   0 on success otherwise -errno and errno is set.
11084  */
11085 static int
11086 flow_dv_matcher_register(struct rte_eth_dev *dev,
11087 			 struct mlx5_flow_dv_matcher *ref,
11088 			 union mlx5_flow_tbl_key *key,
11089 			 struct mlx5_flow *dev_flow,
11090 			 const struct mlx5_flow_tunnel *tunnel,
11091 			 uint32_t group_id,
11092 			 struct rte_flow_error *error)
11093 {
11094 	struct mlx5_list_entry *entry;
11095 	struct mlx5_flow_dv_matcher *resource;
11096 	struct mlx5_flow_tbl_resource *tbl;
11097 	struct mlx5_flow_tbl_data_entry *tbl_data;
11098 	struct mlx5_flow_cb_ctx ctx = {
11099 		.error = error,
11100 		.data = ref,
11101 	};
11102 	/**
11103 	 * tunnel offload API requires this registration for cases when
11104 	 * tunnel match rule was inserted before tunnel set rule.
11105 	 */
11106 	tbl = flow_dv_tbl_resource_get(dev, key->level,
11107 				       key->is_egress, key->is_fdb,
11108 				       dev_flow->external, tunnel,
11109 				       group_id, 0, key->id, error);
11110 	if (!tbl)
11111 		return -rte_errno;	/* No need to refill the error info */
11112 	tbl_data = container_of(tbl, struct mlx5_flow_tbl_data_entry, tbl);
11113 	ref->tbl = tbl;
11114 	entry = mlx5_list_register(tbl_data->matchers, &ctx);
11115 	if (!entry) {
11116 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
11117 		return rte_flow_error_set(error, ENOMEM,
11118 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
11119 					  "cannot allocate ref memory");
11120 	}
11121 	resource = container_of(entry, typeof(*resource), entry);
11122 	dev_flow->handle->dvh.matcher = resource;
11123 	return 0;
11124 }
11125 
11126 struct mlx5_list_entry *
11127 flow_dv_tag_create_cb(void *tool_ctx, void *cb_ctx)
11128 {
11129 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
11130 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11131 	struct mlx5_flow_dv_tag_resource *entry;
11132 	uint32_t idx = 0;
11133 	int ret;
11134 
11135 	entry = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
11136 	if (!entry) {
11137 		rte_flow_error_set(ctx->error, ENOMEM,
11138 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
11139 				   "cannot allocate resource memory");
11140 		return NULL;
11141 	}
11142 	entry->idx = idx;
11143 	entry->tag_id = *(uint32_t *)(ctx->data);
11144 	ret = mlx5_flow_os_create_flow_action_tag(entry->tag_id,
11145 						  &entry->action);
11146 	if (ret) {
11147 		mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], idx);
11148 		rte_flow_error_set(ctx->error, ENOMEM,
11149 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11150 				   NULL, "cannot create action");
11151 		return NULL;
11152 	}
11153 	return &entry->entry;
11154 }
11155 
11156 int
11157 flow_dv_tag_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
11158 		     void *cb_ctx)
11159 {
11160 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11161 	struct mlx5_flow_dv_tag_resource *tag =
11162 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
11163 
11164 	return *(uint32_t *)(ctx->data) != tag->tag_id;
11165 }
11166 
11167 struct mlx5_list_entry *
11168 flow_dv_tag_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
11169 		     void *cb_ctx)
11170 {
11171 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
11172 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11173 	struct mlx5_flow_dv_tag_resource *entry;
11174 	uint32_t idx = 0;
11175 
11176 	entry = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_TAG], &idx);
11177 	if (!entry) {
11178 		rte_flow_error_set(ctx->error, ENOMEM,
11179 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
11180 				   "cannot allocate tag resource memory");
11181 		return NULL;
11182 	}
11183 	memcpy(entry, oentry, sizeof(*entry));
11184 	entry->idx = idx;
11185 	return &entry->entry;
11186 }
11187 
11188 void
11189 flow_dv_tag_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
11190 {
11191 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
11192 	struct mlx5_flow_dv_tag_resource *tag =
11193 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
11194 
11195 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
11196 }
11197 
11198 /**
11199  * Find existing tag resource or create and register a new one.
11200  *
11201  * @param dev[in, out]
11202  *   Pointer to rte_eth_dev structure.
11203  * @param[in, out] tag_be24
11204  *   Tag value in big endian then R-shift 8.
11205  * @parm[in, out] dev_flow
11206  *   Pointer to the dev_flow.
11207  * @param[out] error
11208  *   pointer to error structure.
11209  *
11210  * @return
11211  *   0 on success otherwise -errno and errno is set.
11212  */
11213 static int
11214 flow_dv_tag_resource_register
11215 			(struct rte_eth_dev *dev,
11216 			 uint32_t tag_be24,
11217 			 struct mlx5_flow *dev_flow,
11218 			 struct rte_flow_error *error)
11219 {
11220 	struct mlx5_priv *priv = dev->data->dev_private;
11221 	struct mlx5_flow_dv_tag_resource *resource;
11222 	struct mlx5_list_entry *entry;
11223 	struct mlx5_flow_cb_ctx ctx = {
11224 					.error = error,
11225 					.data = &tag_be24,
11226 					};
11227 	struct mlx5_hlist *tag_table;
11228 
11229 	tag_table = flow_dv_hlist_prepare(priv->sh, &priv->sh->tag_table,
11230 				      "tags",
11231 				      MLX5_TAGS_HLIST_ARRAY_SIZE,
11232 				      false, false, priv->sh,
11233 				      flow_dv_tag_create_cb,
11234 				      flow_dv_tag_match_cb,
11235 				      flow_dv_tag_remove_cb,
11236 				      flow_dv_tag_clone_cb,
11237 				      flow_dv_tag_clone_free_cb,
11238 				      error);
11239 	if (unlikely(!tag_table))
11240 		return -rte_errno;
11241 	entry = mlx5_hlist_register(tag_table, tag_be24, &ctx);
11242 	if (entry) {
11243 		resource = container_of(entry, struct mlx5_flow_dv_tag_resource,
11244 					entry);
11245 		dev_flow->handle->dvh.rix_tag = resource->idx;
11246 		dev_flow->dv.tag_resource = resource;
11247 		return 0;
11248 	}
11249 	return -rte_errno;
11250 }
11251 
11252 void
11253 flow_dv_tag_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
11254 {
11255 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
11256 	struct mlx5_flow_dv_tag_resource *tag =
11257 		   container_of(entry, struct mlx5_flow_dv_tag_resource, entry);
11258 
11259 	MLX5_ASSERT(tag && sh && tag->action);
11260 	claim_zero(mlx5_flow_os_destroy_flow_action(tag->action));
11261 	DRV_LOG(DEBUG, "Tag %p: removed.", (void *)tag);
11262 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_TAG], tag->idx);
11263 }
11264 
11265 /**
11266  * Release the tag.
11267  *
11268  * @param dev
11269  *   Pointer to Ethernet device.
11270  * @param tag_idx
11271  *   Tag index.
11272  *
11273  * @return
11274  *   1 while a reference on it exists, 0 when freed.
11275  */
11276 static int
11277 flow_dv_tag_release(struct rte_eth_dev *dev,
11278 		    uint32_t tag_idx)
11279 {
11280 	struct mlx5_priv *priv = dev->data->dev_private;
11281 	struct mlx5_flow_dv_tag_resource *tag;
11282 
11283 	tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG], tag_idx);
11284 	if (!tag)
11285 		return 0;
11286 	DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
11287 		dev->data->port_id, (void *)tag, tag->entry.ref_cnt);
11288 	return mlx5_hlist_unregister(priv->sh->tag_table, &tag->entry);
11289 }
11290 
11291 /**
11292  * Translate action PORT_ID / REPRESENTED_PORT to vport.
11293  *
11294  * @param[in] dev
11295  *   Pointer to rte_eth_dev structure.
11296  * @param[in] action
11297  *   Pointer to action PORT_ID / REPRESENTED_PORT.
11298  * @param[out] dst_port_id
11299  *   The target port ID.
11300  * @param[out] error
11301  *   Pointer to the error structure.
11302  *
11303  * @return
11304  *   0 on success, a negative errno value otherwise and rte_errno is set.
11305  */
11306 static int
11307 flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
11308 				 const struct rte_flow_action *action,
11309 				 uint32_t *dst_port_id,
11310 				 struct rte_flow_error *error)
11311 {
11312 	uint32_t port;
11313 	struct mlx5_priv *priv;
11314 
11315 	switch (action->type) {
11316 	case RTE_FLOW_ACTION_TYPE_PORT_ID: {
11317 		const struct rte_flow_action_port_id *conf;
11318 
11319 		conf = (const struct rte_flow_action_port_id *)action->conf;
11320 		port = conf->original ? dev->data->port_id : conf->id;
11321 		break;
11322 	}
11323 	case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT: {
11324 		const struct rte_flow_action_ethdev *ethdev;
11325 
11326 		ethdev = (const struct rte_flow_action_ethdev *)action->conf;
11327 		port = ethdev->port_id;
11328 		break;
11329 	}
11330 	default:
11331 		MLX5_ASSERT(false);
11332 		return rte_flow_error_set(error, EINVAL,
11333 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
11334 					  "unknown E-Switch action");
11335 	}
11336 
11337 	priv = mlx5_port_to_eswitch_info(port, false);
11338 	if (!priv)
11339 		return rte_flow_error_set(error, -rte_errno,
11340 					  RTE_FLOW_ERROR_TYPE_ACTION,
11341 					  NULL,
11342 					  "No eswitch info was found for port");
11343 #ifdef HAVE_MLX5DV_DR_CREATE_DEST_IB_PORT
11344 	/*
11345 	 * This parameter is transferred to
11346 	 * mlx5dv_dr_action_create_dest_ib_port().
11347 	 */
11348 	*dst_port_id = priv->dev_port;
11349 #else
11350 	/*
11351 	 * Legacy mode, no LAG configurations is supported.
11352 	 * This parameter is transferred to
11353 	 * mlx5dv_dr_action_create_dest_vport().
11354 	 */
11355 	*dst_port_id = priv->vport_id;
11356 #endif
11357 	return 0;
11358 }
11359 
11360 /**
11361  * Create a counter with aging configuration.
11362  *
11363  * @param[in] dev
11364  *   Pointer to rte_eth_dev structure.
11365  * @param[in] dev_flow
11366  *   Pointer to the mlx5_flow.
11367  * @param[out] count
11368  *   Pointer to the counter action configuration.
11369  * @param[in] age
11370  *   Pointer to the aging action configuration.
11371  *
11372  * @return
11373  *   Index to flow counter on success, 0 otherwise.
11374  */
11375 static uint32_t
11376 flow_dv_translate_create_counter(struct rte_eth_dev *dev,
11377 				struct mlx5_flow *dev_flow,
11378 				const struct rte_flow_action_count *count
11379 					__rte_unused,
11380 				const struct rte_flow_action_age *age)
11381 {
11382 	uint32_t counter;
11383 	struct mlx5_age_param *age_param;
11384 
11385 	counter = flow_dv_counter_alloc(dev, !!age);
11386 	if (!counter || age == NULL)
11387 		return counter;
11388 	age_param = flow_dv_counter_idx_get_age(dev, counter);
11389 	age_param->context = age->context ? age->context :
11390 		(void *)(uintptr_t)(dev_flow->flow_idx);
11391 	age_param->timeout = age->timeout;
11392 	age_param->port_id = dev->data->port_id;
11393 	__atomic_store_n(&age_param->sec_since_last_hit, 0, __ATOMIC_RELAXED);
11394 	__atomic_store_n(&age_param->state, AGE_CANDIDATE, __ATOMIC_RELAXED);
11395 	return counter;
11396 }
11397 
11398 /**
11399  * Add SQ matcher
11400  *
11401  * @param[in, out] matcher
11402  *   Flow matcher.
11403  * @param[in, out] key
11404  *   Flow matcher value.
11405  * @param[in] item
11406  *   Flow pattern to translate.
11407  * @param[in] key_type
11408  *   Set flow matcher mask or value.
11409  */
11410 static void
11411 flow_dv_translate_item_sq(void *key,
11412 			  const struct rte_flow_item *item,
11413 			  uint32_t key_type)
11414 {
11415 	const struct mlx5_rte_flow_item_sq *queue_m;
11416 	const struct mlx5_rte_flow_item_sq *queue_v;
11417 	const struct mlx5_rte_flow_item_sq queue_mask = {
11418 		.queue = UINT32_MAX,
11419 	};
11420 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
11421 	uint32_t queue;
11422 
11423 	MLX5_ITEM_UPDATE(item, key_type, queue_v, queue_m, &queue_mask);
11424 	if (!queue_m || !queue_v)
11425 		return;
11426 	if (key_type & MLX5_SET_MATCHER_V) {
11427 		queue = queue_v->queue;
11428 		if (key_type == MLX5_SET_MATCHER_SW_V)
11429 			queue &= queue_m->queue;
11430 	} else {
11431 		queue = queue_m->queue;
11432 	}
11433 	MLX5_SET(fte_match_set_misc, misc_v, source_sqn, queue);
11434 }
11435 
11436 /**
11437  * Set the hash fields according to the @p flow information.
11438  *
11439  * @param[in] item_flags
11440  *   The match pattern item flags.
11441  * @param[in] rss_desc
11442  *   Pointer to the mlx5_flow_rss_desc.
11443  * @param[out] hash_fields
11444  *   Pointer to the RSS hash fields.
11445  */
11446 void
11447 flow_dv_hashfields_set(uint64_t item_flags,
11448 		       struct mlx5_flow_rss_desc *rss_desc,
11449 		       uint64_t *hash_fields)
11450 {
11451 	uint64_t items = item_flags;
11452 	uint64_t fields = 0;
11453 	int rss_inner = 0;
11454 	uint64_t rss_types = rte_eth_rss_hf_refine(rss_desc->types);
11455 
11456 	*hash_fields = 0;
11457 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
11458 	if (rss_desc->level >= 2)
11459 		rss_inner = 1;
11460 #endif
11461 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV4)) ||
11462 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV4))) {
11463 		if (rss_types & MLX5_IPV4_LAYER_TYPES) {
11464 			if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY)
11465 				fields |= IBV_RX_HASH_SRC_IPV4;
11466 			else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY)
11467 				fields |= IBV_RX_HASH_DST_IPV4;
11468 			else
11469 				fields |= MLX5_IPV4_IBV_RX_HASH;
11470 		}
11471 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L3_IPV6)) ||
11472 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L3_IPV6))) {
11473 		if (rss_types & MLX5_IPV6_LAYER_TYPES) {
11474 			if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY)
11475 				fields |= IBV_RX_HASH_SRC_IPV6;
11476 			else if (rss_types & RTE_ETH_RSS_L3_DST_ONLY)
11477 				fields |= IBV_RX_HASH_DST_IPV6;
11478 			else
11479 				fields |= MLX5_IPV6_IBV_RX_HASH;
11480 		}
11481 	}
11482 	if (items & MLX5_FLOW_ITEM_ESP) {
11483 		if (rss_types & RTE_ETH_RSS_ESP)
11484 			fields |= IBV_RX_HASH_IPSEC_SPI;
11485 	}
11486 	if ((fields & ~IBV_RX_HASH_IPSEC_SPI) == 0) {
11487 		*hash_fields = fields;
11488 		/*
11489 		 * There is no match between the RSS types and the
11490 		 * L3 protocol (IPv4/IPv6) defined in the flow rule.
11491 		 */
11492 		return;
11493 	}
11494 	if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_UDP)) ||
11495 	    (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_UDP))) {
11496 		if (rss_types & RTE_ETH_RSS_UDP) {
11497 			if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY)
11498 				fields |= IBV_RX_HASH_SRC_PORT_UDP;
11499 			else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY)
11500 				fields |= IBV_RX_HASH_DST_PORT_UDP;
11501 			else
11502 				fields |= MLX5_UDP_IBV_RX_HASH;
11503 		}
11504 	} else if ((rss_inner && (items & MLX5_FLOW_LAYER_INNER_L4_TCP)) ||
11505 		   (!rss_inner && (items & MLX5_FLOW_LAYER_OUTER_L4_TCP))) {
11506 		if (rss_types & RTE_ETH_RSS_TCP) {
11507 			if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY)
11508 				fields |= IBV_RX_HASH_SRC_PORT_TCP;
11509 			else if (rss_types & RTE_ETH_RSS_L4_DST_ONLY)
11510 				fields |= IBV_RX_HASH_DST_PORT_TCP;
11511 			else
11512 				fields |= MLX5_TCP_IBV_RX_HASH;
11513 		}
11514 	}
11515 	if (rss_inner)
11516 		fields |= IBV_RX_HASH_INNER;
11517 	*hash_fields = fields;
11518 }
11519 
11520 /**
11521  * Prepare an Rx Hash queue.
11522  *
11523  * @param dev
11524  *   Pointer to Ethernet device.
11525  * @param[in] dev_flow
11526  *   Pointer to the mlx5_flow.
11527  * @param[in] rss_desc
11528  *   Pointer to the mlx5_flow_rss_desc.
11529  * @param[out] hrxq_idx
11530  *   Hash Rx queue index.
11531  *
11532  * @return
11533  *   The Verbs/DevX object initialised, NULL otherwise and rte_errno is set.
11534  */
11535 static struct mlx5_hrxq *
11536 flow_dv_hrxq_prepare(struct rte_eth_dev *dev,
11537 		     struct mlx5_flow *dev_flow,
11538 		     struct mlx5_flow_rss_desc *rss_desc,
11539 		     uint32_t *hrxq_idx)
11540 {
11541 	struct mlx5_flow_handle *dh = dev_flow->handle;
11542 	uint32_t shared_rss = rss_desc->shared_rss;
11543 	struct mlx5_hrxq *hrxq;
11544 
11545 	MLX5_ASSERT(rss_desc->queue_num);
11546 	rss_desc->key_len = MLX5_RSS_HASH_KEY_LEN;
11547 	rss_desc->hash_fields = dev_flow->hash_fields;
11548 	rss_desc->tunnel = !!(dh->layers & MLX5_FLOW_LAYER_TUNNEL);
11549 	rss_desc->shared_rss = 0;
11550 	if (rss_desc->hash_fields == 0)
11551 		rss_desc->queue_num = 1;
11552 	hrxq = mlx5_hrxq_get(dev, rss_desc);
11553 	*hrxq_idx = hrxq ? hrxq->idx : 0;
11554 	rss_desc->shared_rss = shared_rss;
11555 	return hrxq;
11556 }
11557 
11558 /**
11559  * Release sample sub action resource.
11560  *
11561  * @param[in, out] dev
11562  *   Pointer to rte_eth_dev structure.
11563  * @param[in] act_res
11564  *   Pointer to sample sub action resource.
11565  */
11566 static void
11567 flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev,
11568 				   struct mlx5_flow_sub_actions_idx *act_res)
11569 {
11570 	if (act_res->rix_hrxq) {
11571 		mlx5_hrxq_release(dev, act_res->rix_hrxq);
11572 		act_res->rix_hrxq = 0;
11573 	}
11574 	if (act_res->rix_encap_decap) {
11575 		flow_dv_encap_decap_resource_release(dev,
11576 						     act_res->rix_encap_decap);
11577 		act_res->rix_encap_decap = 0;
11578 	}
11579 	if (act_res->rix_port_id_action) {
11580 		flow_dv_port_id_action_resource_release(dev,
11581 						act_res->rix_port_id_action);
11582 		act_res->rix_port_id_action = 0;
11583 	}
11584 	if (act_res->rix_tag) {
11585 		flow_dv_tag_release(dev, act_res->rix_tag);
11586 		act_res->rix_tag = 0;
11587 	}
11588 	if (act_res->rix_jump) {
11589 		flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump);
11590 		act_res->rix_jump = 0;
11591 	}
11592 }
11593 
11594 int
11595 flow_dv_sample_match_cb(void *tool_ctx __rte_unused,
11596 			struct mlx5_list_entry *entry, void *cb_ctx)
11597 {
11598 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11599 	struct rte_eth_dev *dev = ctx->dev;
11600 	struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
11601 	struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
11602 							      typeof(*resource),
11603 							      entry);
11604 
11605 	if (ctx_resource->ratio == resource->ratio &&
11606 	    ctx_resource->ft_type == resource->ft_type &&
11607 	    ctx_resource->ft_id == resource->ft_id &&
11608 	    ctx_resource->set_action == resource->set_action &&
11609 	    !memcmp((void *)&ctx_resource->sample_act,
11610 		    (void *)&resource->sample_act,
11611 		    sizeof(struct mlx5_flow_sub_actions_list))) {
11612 		/*
11613 		 * Existing sample action should release the prepared
11614 		 * sub-actions reference counter.
11615 		 */
11616 		flow_dv_sample_sub_actions_release(dev,
11617 						   &ctx_resource->sample_idx);
11618 		return 0;
11619 	}
11620 	return 1;
11621 }
11622 
11623 struct mlx5_list_entry *
11624 flow_dv_sample_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
11625 {
11626 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11627 	struct rte_eth_dev *dev = ctx->dev;
11628 	struct mlx5_flow_dv_sample_resource *ctx_resource = ctx->data;
11629 	void **sample_dv_actions = ctx_resource->sub_actions;
11630 	struct mlx5_flow_dv_sample_resource *resource;
11631 	struct mlx5dv_dr_flow_sampler_attr sampler_attr;
11632 	struct mlx5_priv *priv = dev->data->dev_private;
11633 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11634 	struct mlx5_flow_tbl_resource *tbl;
11635 	uint32_t idx = 0;
11636 	const uint32_t next_ft_step = 1;
11637 	uint32_t next_ft_id = ctx_resource->ft_id + next_ft_step;
11638 	uint8_t is_egress = 0;
11639 	uint8_t is_transfer = 0;
11640 	struct rte_flow_error *error = ctx->error;
11641 
11642 	/* Register new sample resource. */
11643 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11644 	if (!resource) {
11645 		rte_flow_error_set(error, ENOMEM,
11646 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11647 					  NULL,
11648 					  "cannot allocate resource memory");
11649 		return NULL;
11650 	}
11651 	*resource = *ctx_resource;
11652 	/* Create normal path table level */
11653 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11654 		is_transfer = 1;
11655 	else if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
11656 		is_egress = 1;
11657 	tbl = flow_dv_tbl_resource_get(dev, next_ft_id,
11658 					is_egress, is_transfer,
11659 					true, NULL, 0, 0, 0, error);
11660 	if (!tbl) {
11661 		rte_flow_error_set(error, ENOMEM,
11662 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11663 					  NULL,
11664 					  "fail to create normal path table "
11665 					  "for sample");
11666 		goto error;
11667 	}
11668 	resource->normal_path_tbl = tbl;
11669 	if (ctx_resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB) {
11670 		if (!sh->default_miss_action) {
11671 			rte_flow_error_set(error, ENOMEM,
11672 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11673 						NULL,
11674 						"default miss action was not "
11675 						"created");
11676 			goto error;
11677 		}
11678 		sample_dv_actions[ctx_resource->sample_act.actions_num++] =
11679 						sh->default_miss_action;
11680 	}
11681 	/* Create a DR sample action */
11682 	sampler_attr.sample_ratio = resource->ratio;
11683 	sampler_attr.default_next_table = tbl->obj;
11684 	sampler_attr.num_sample_actions = ctx_resource->sample_act.actions_num;
11685 	sampler_attr.sample_actions = (struct mlx5dv_dr_action **)
11686 							&sample_dv_actions[0];
11687 	sampler_attr.action = resource->set_action;
11688 	if (mlx5_os_flow_dr_create_flow_action_sampler
11689 			(&sampler_attr, &resource->verbs_action)) {
11690 		rte_flow_error_set(error, ENOMEM,
11691 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11692 					NULL, "cannot create sample action");
11693 		goto error;
11694 	}
11695 	resource->idx = idx;
11696 	resource->dev = dev;
11697 	return &resource->entry;
11698 error:
11699 	if (resource->ft_type != MLX5DV_FLOW_TABLE_TYPE_FDB)
11700 		flow_dv_sample_sub_actions_release(dev,
11701 						   &resource->sample_idx);
11702 	if (resource->normal_path_tbl)
11703 		flow_dv_tbl_resource_release(MLX5_SH(dev),
11704 				resource->normal_path_tbl);
11705 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_SAMPLE], idx);
11706 	return NULL;
11707 
11708 }
11709 
11710 struct mlx5_list_entry *
11711 flow_dv_sample_clone_cb(void *tool_ctx __rte_unused,
11712 			 struct mlx5_list_entry *entry __rte_unused,
11713 			 void *cb_ctx)
11714 {
11715 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11716 	struct rte_eth_dev *dev = ctx->dev;
11717 	struct mlx5_flow_dv_sample_resource *resource;
11718 	struct mlx5_priv *priv = dev->data->dev_private;
11719 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11720 	uint32_t idx = 0;
11721 
11722 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_SAMPLE], &idx);
11723 	if (!resource) {
11724 		rte_flow_error_set(ctx->error, ENOMEM,
11725 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11726 					  NULL,
11727 					  "cannot allocate resource memory");
11728 		return NULL;
11729 	}
11730 	memcpy(resource, entry, sizeof(*resource));
11731 	resource->idx = idx;
11732 	resource->dev = dev;
11733 	return &resource->entry;
11734 }
11735 
11736 void
11737 flow_dv_sample_clone_free_cb(void *tool_ctx __rte_unused,
11738 			     struct mlx5_list_entry *entry)
11739 {
11740 	struct mlx5_flow_dv_sample_resource *resource =
11741 				  container_of(entry, typeof(*resource), entry);
11742 	struct rte_eth_dev *dev = resource->dev;
11743 	struct mlx5_priv *priv = dev->data->dev_private;
11744 
11745 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
11746 }
11747 
11748 /**
11749  * Find existing sample resource or create and register a new one.
11750  *
11751  * @param[in, out] dev
11752  *   Pointer to rte_eth_dev structure.
11753  * @param[in] ref
11754  *   Pointer to sample resource reference.
11755  * @parm[in, out] dev_flow
11756  *   Pointer to the dev_flow.
11757  * @param[out] error
11758  *   pointer to error structure.
11759  *
11760  * @return
11761  *   0 on success otherwise -errno and errno is set.
11762  */
11763 static int
11764 flow_dv_sample_resource_register(struct rte_eth_dev *dev,
11765 			 struct mlx5_flow_dv_sample_resource *ref,
11766 			 struct mlx5_flow *dev_flow,
11767 			 struct rte_flow_error *error)
11768 {
11769 	struct mlx5_flow_dv_sample_resource *resource;
11770 	struct mlx5_list_entry *entry;
11771 	struct mlx5_priv *priv = dev->data->dev_private;
11772 	struct mlx5_flow_cb_ctx ctx = {
11773 		.dev = dev,
11774 		.error = error,
11775 		.data = ref,
11776 	};
11777 
11778 	entry = mlx5_list_register(priv->sh->sample_action_list, &ctx);
11779 	if (!entry)
11780 		return -rte_errno;
11781 	resource = container_of(entry, typeof(*resource), entry);
11782 	dev_flow->handle->dvh.rix_sample = resource->idx;
11783 	dev_flow->dv.sample_res = resource;
11784 	return 0;
11785 }
11786 
11787 int
11788 flow_dv_dest_array_match_cb(void *tool_ctx __rte_unused,
11789 			    struct mlx5_list_entry *entry, void *cb_ctx)
11790 {
11791 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11792 	struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11793 	struct rte_eth_dev *dev = ctx->dev;
11794 	struct mlx5_flow_dv_dest_array_resource *resource =
11795 				  container_of(entry, typeof(*resource), entry);
11796 	uint32_t idx = 0;
11797 
11798 	if (ctx_resource->num_of_dest == resource->num_of_dest &&
11799 	    ctx_resource->ft_type == resource->ft_type &&
11800 	    !memcmp((void *)resource->sample_act,
11801 		    (void *)ctx_resource->sample_act,
11802 		   (ctx_resource->num_of_dest *
11803 		   sizeof(struct mlx5_flow_sub_actions_list)))) {
11804 		/*
11805 		 * Existing sample action should release the prepared
11806 		 * sub-actions reference counter.
11807 		 */
11808 		for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11809 			flow_dv_sample_sub_actions_release(dev,
11810 					&ctx_resource->sample_idx[idx]);
11811 		return 0;
11812 	}
11813 	return 1;
11814 }
11815 
11816 struct mlx5_list_entry *
11817 flow_dv_dest_array_create_cb(void *tool_ctx __rte_unused, void *cb_ctx)
11818 {
11819 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11820 	struct rte_eth_dev *dev = ctx->dev;
11821 	struct mlx5_flow_dv_dest_array_resource *resource;
11822 	struct mlx5_flow_dv_dest_array_resource *ctx_resource = ctx->data;
11823 	struct mlx5dv_dr_action_dest_attr *dest_attr[MLX5_MAX_DEST_NUM] = { 0 };
11824 	struct mlx5dv_dr_action_dest_reformat dest_reformat[MLX5_MAX_DEST_NUM];
11825 	struct mlx5_priv *priv = dev->data->dev_private;
11826 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11827 	struct mlx5_flow_sub_actions_list *sample_act;
11828 	struct mlx5dv_dr_domain *domain;
11829 	uint32_t idx = 0, res_idx = 0;
11830 	struct rte_flow_error *error = ctx->error;
11831 	uint64_t action_flags;
11832 	int ret;
11833 
11834 	/* Register new destination array resource. */
11835 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11836 					    &res_idx);
11837 	if (!resource) {
11838 		rte_flow_error_set(error, ENOMEM,
11839 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11840 					  NULL,
11841 					  "cannot allocate resource memory");
11842 		return NULL;
11843 	}
11844 	*resource = *ctx_resource;
11845 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
11846 		domain = sh->fdb_domain;
11847 	else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
11848 		domain = sh->rx_domain;
11849 	else
11850 		domain = sh->tx_domain;
11851 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11852 		dest_attr[idx] = (struct mlx5dv_dr_action_dest_attr *)
11853 				 mlx5_malloc(MLX5_MEM_ZERO,
11854 				 sizeof(struct mlx5dv_dr_action_dest_attr),
11855 				 0, SOCKET_ID_ANY);
11856 		if (!dest_attr[idx]) {
11857 			rte_flow_error_set(error, ENOMEM,
11858 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11859 					   NULL,
11860 					   "cannot allocate resource memory");
11861 			goto error;
11862 		}
11863 		dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST;
11864 		sample_act = &ctx_resource->sample_act[idx];
11865 		action_flags = sample_act->action_flags;
11866 		switch (action_flags) {
11867 		case MLX5_FLOW_ACTION_QUEUE:
11868 			dest_attr[idx]->dest = sample_act->dr_queue_action;
11869 			break;
11870 		case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP):
11871 			dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT;
11872 			dest_attr[idx]->dest_reformat = &dest_reformat[idx];
11873 			dest_attr[idx]->dest_reformat->reformat =
11874 					sample_act->dr_encap_action;
11875 			dest_attr[idx]->dest_reformat->dest =
11876 					sample_act->dr_port_id_action;
11877 			break;
11878 		case MLX5_FLOW_ACTION_PORT_ID:
11879 			dest_attr[idx]->dest = sample_act->dr_port_id_action;
11880 			break;
11881 		case MLX5_FLOW_ACTION_JUMP:
11882 			dest_attr[idx]->dest = sample_act->dr_jump_action;
11883 			break;
11884 		default:
11885 			rte_flow_error_set(error, EINVAL,
11886 					   RTE_FLOW_ERROR_TYPE_ACTION,
11887 					   NULL,
11888 					   "unsupported actions type");
11889 			goto error;
11890 		}
11891 	}
11892 	/* create a dest array action */
11893 	ret = mlx5_os_flow_dr_create_flow_action_dest_array
11894 						(domain,
11895 						 resource->num_of_dest,
11896 						 dest_attr,
11897 						 &resource->action);
11898 	if (ret) {
11899 		rte_flow_error_set(error, ENOMEM,
11900 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11901 				   NULL,
11902 				   "cannot create destination array action");
11903 		goto error;
11904 	}
11905 	resource->idx = res_idx;
11906 	resource->dev = dev;
11907 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++)
11908 		mlx5_free(dest_attr[idx]);
11909 	return &resource->entry;
11910 error:
11911 	for (idx = 0; idx < ctx_resource->num_of_dest; idx++) {
11912 		flow_dv_sample_sub_actions_release(dev,
11913 						   &resource->sample_idx[idx]);
11914 		if (dest_attr[idx])
11915 			mlx5_free(dest_attr[idx]);
11916 	}
11917 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DEST_ARRAY], res_idx);
11918 	return NULL;
11919 }
11920 
11921 struct mlx5_list_entry *
11922 flow_dv_dest_array_clone_cb(void *tool_ctx __rte_unused,
11923 			    struct mlx5_list_entry *entry __rte_unused,
11924 			    void *cb_ctx)
11925 {
11926 	struct mlx5_flow_cb_ctx *ctx = cb_ctx;
11927 	struct rte_eth_dev *dev = ctx->dev;
11928 	struct mlx5_flow_dv_dest_array_resource *resource;
11929 	struct mlx5_priv *priv = dev->data->dev_private;
11930 	struct mlx5_dev_ctx_shared *sh = priv->sh;
11931 	uint32_t res_idx = 0;
11932 	struct rte_flow_error *error = ctx->error;
11933 
11934 	resource = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_DEST_ARRAY],
11935 				      &res_idx);
11936 	if (!resource) {
11937 		rte_flow_error_set(error, ENOMEM,
11938 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
11939 					  NULL,
11940 					  "cannot allocate dest-array memory");
11941 		return NULL;
11942 	}
11943 	memcpy(resource, entry, sizeof(*resource));
11944 	resource->idx = res_idx;
11945 	resource->dev = dev;
11946 	return &resource->entry;
11947 }
11948 
11949 void
11950 flow_dv_dest_array_clone_free_cb(void *tool_ctx __rte_unused,
11951 				 struct mlx5_list_entry *entry)
11952 {
11953 	struct mlx5_flow_dv_dest_array_resource *resource =
11954 			container_of(entry, typeof(*resource), entry);
11955 	struct rte_eth_dev *dev = resource->dev;
11956 	struct mlx5_priv *priv = dev->data->dev_private;
11957 
11958 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
11959 }
11960 
11961 /**
11962  * Find existing destination array resource or create and register a new one.
11963  *
11964  * @param[in, out] dev
11965  *   Pointer to rte_eth_dev structure.
11966  * @param[in] ref
11967  *   Pointer to destination array resource reference.
11968  * @parm[in, out] dev_flow
11969  *   Pointer to the dev_flow.
11970  * @param[out] error
11971  *   pointer to error structure.
11972  *
11973  * @return
11974  *   0 on success otherwise -errno and errno is set.
11975  */
11976 static int
11977 flow_dv_dest_array_resource_register(struct rte_eth_dev *dev,
11978 			 struct mlx5_flow_dv_dest_array_resource *ref,
11979 			 struct mlx5_flow *dev_flow,
11980 			 struct rte_flow_error *error)
11981 {
11982 	struct mlx5_flow_dv_dest_array_resource *resource;
11983 	struct mlx5_priv *priv = dev->data->dev_private;
11984 	struct mlx5_list_entry *entry;
11985 	struct mlx5_flow_cb_ctx ctx = {
11986 		.dev = dev,
11987 		.error = error,
11988 		.data = ref,
11989 	};
11990 
11991 	entry = mlx5_list_register(priv->sh->dest_array_list, &ctx);
11992 	if (!entry)
11993 		return -rte_errno;
11994 	resource = container_of(entry, typeof(*resource), entry);
11995 	dev_flow->handle->dvh.rix_dest_array = resource->idx;
11996 	dev_flow->dv.dest_array_res = resource;
11997 	return 0;
11998 }
11999 
12000 /**
12001  * Convert Sample action to DV specification.
12002  *
12003  * @param[in] dev
12004  *   Pointer to rte_eth_dev structure.
12005  * @param[in] action
12006  *   Pointer to sample action structure.
12007  * @param[in, out] dev_flow
12008  *   Pointer to the mlx5_flow.
12009  * @param[in] attr
12010  *   Pointer to the flow attributes.
12011  * @param[in, out] num_of_dest
12012  *   Pointer to the num of destination.
12013  * @param[in, out] sample_actions
12014  *   Pointer to sample actions list.
12015  * @param[in, out] res
12016  *   Pointer to sample resource.
12017  * @param[out] error
12018  *   Pointer to the error structure.
12019  *
12020  * @return
12021  *   0 on success, a negative errno value otherwise and rte_errno is set.
12022  */
12023 static int
12024 flow_dv_translate_action_sample(struct rte_eth_dev *dev,
12025 				const struct rte_flow_action_sample *action,
12026 				struct mlx5_flow *dev_flow,
12027 				const struct rte_flow_attr *attr,
12028 				uint32_t *num_of_dest,
12029 				void **sample_actions,
12030 				struct mlx5_flow_dv_sample_resource *res,
12031 				struct rte_flow_error *error)
12032 {
12033 	struct mlx5_priv *priv = dev->data->dev_private;
12034 	const struct rte_flow_action *sub_actions;
12035 	struct mlx5_flow_sub_actions_list *sample_act;
12036 	struct mlx5_flow_sub_actions_idx *sample_idx;
12037 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
12038 	struct rte_flow *flow = dev_flow->flow;
12039 	struct mlx5_flow_rss_desc *rss_desc;
12040 	uint64_t action_flags = 0;
12041 
12042 	MLX5_ASSERT(wks);
12043 	rss_desc = &wks->rss_desc;
12044 	sample_act = &res->sample_act;
12045 	sample_idx = &res->sample_idx;
12046 	res->ratio = action->ratio;
12047 	sub_actions = action->actions;
12048 	for (; sub_actions->type != RTE_FLOW_ACTION_TYPE_END; sub_actions++) {
12049 		int type = sub_actions->type;
12050 		uint32_t pre_rix = 0;
12051 		void *pre_r;
12052 		switch (type) {
12053 		case RTE_FLOW_ACTION_TYPE_QUEUE:
12054 		{
12055 			const struct rte_flow_action_queue *queue;
12056 			struct mlx5_hrxq *hrxq;
12057 			uint32_t hrxq_idx;
12058 
12059 			queue = sub_actions->conf;
12060 			rss_desc->queue_num = 1;
12061 			rss_desc->queue[0] = queue->index;
12062 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
12063 						    rss_desc, &hrxq_idx);
12064 			if (!hrxq)
12065 				return rte_flow_error_set
12066 					(error, rte_errno,
12067 					 RTE_FLOW_ERROR_TYPE_ACTION,
12068 					 NULL,
12069 					 "cannot create fate queue");
12070 			sample_act->dr_queue_action = hrxq->action;
12071 			sample_idx->rix_hrxq = hrxq_idx;
12072 			sample_actions[sample_act->actions_num++] =
12073 						hrxq->action;
12074 			(*num_of_dest)++;
12075 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
12076 			if (action_flags & MLX5_FLOW_ACTION_MARK)
12077 				dev_flow->handle->rix_hrxq = hrxq_idx;
12078 			dev_flow->handle->fate_action =
12079 					MLX5_FLOW_FATE_QUEUE;
12080 			break;
12081 		}
12082 		case RTE_FLOW_ACTION_TYPE_RSS:
12083 		{
12084 			struct mlx5_hrxq *hrxq;
12085 			uint32_t hrxq_idx;
12086 			const struct rte_flow_action_rss *rss;
12087 			const uint8_t *rss_key;
12088 
12089 			rss = sub_actions->conf;
12090 			memcpy(rss_desc->queue, rss->queue,
12091 			       rss->queue_num * sizeof(uint16_t));
12092 			rss_desc->queue_num = rss->queue_num;
12093 			/* NULL RSS key indicates default RSS key. */
12094 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
12095 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
12096 			/*
12097 			 * rss->level and rss.types should be set in advance
12098 			 * when expanding items for RSS.
12099 			 */
12100 			flow_dv_hashfields_set(dev_flow->handle->layers,
12101 					       rss_desc,
12102 					       &dev_flow->hash_fields);
12103 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
12104 						    rss_desc, &hrxq_idx);
12105 			if (!hrxq)
12106 				return rte_flow_error_set
12107 					(error, rte_errno,
12108 					 RTE_FLOW_ERROR_TYPE_ACTION,
12109 					 NULL,
12110 					 "cannot create fate queue");
12111 			sample_act->dr_queue_action = hrxq->action;
12112 			sample_idx->rix_hrxq = hrxq_idx;
12113 			sample_actions[sample_act->actions_num++] =
12114 						hrxq->action;
12115 			(*num_of_dest)++;
12116 			action_flags |= MLX5_FLOW_ACTION_RSS;
12117 			if (action_flags & MLX5_FLOW_ACTION_MARK)
12118 				dev_flow->handle->rix_hrxq = hrxq_idx;
12119 			dev_flow->handle->fate_action =
12120 					MLX5_FLOW_FATE_QUEUE;
12121 			break;
12122 		}
12123 		case RTE_FLOW_ACTION_TYPE_MARK:
12124 		{
12125 			uint32_t tag_be = mlx5_flow_mark_set
12126 				(((const struct rte_flow_action_mark *)
12127 				(sub_actions->conf))->id);
12128 
12129 			wks->mark = 1;
12130 			pre_rix = dev_flow->handle->dvh.rix_tag;
12131 			/* Save the mark resource before sample */
12132 			pre_r = dev_flow->dv.tag_resource;
12133 			if (flow_dv_tag_resource_register(dev, tag_be,
12134 						  dev_flow, error))
12135 				return -rte_errno;
12136 			MLX5_ASSERT(dev_flow->dv.tag_resource);
12137 			sample_act->dr_tag_action =
12138 				dev_flow->dv.tag_resource->action;
12139 			sample_idx->rix_tag =
12140 				dev_flow->handle->dvh.rix_tag;
12141 			sample_actions[sample_act->actions_num++] =
12142 						sample_act->dr_tag_action;
12143 			/* Recover the mark resource after sample */
12144 			dev_flow->dv.tag_resource = pre_r;
12145 			dev_flow->handle->dvh.rix_tag = pre_rix;
12146 			action_flags |= MLX5_FLOW_ACTION_MARK;
12147 			break;
12148 		}
12149 		case RTE_FLOW_ACTION_TYPE_COUNT:
12150 		{
12151 			if (!flow->counter) {
12152 				flow->counter =
12153 					flow_dv_translate_create_counter(dev,
12154 						dev_flow, sub_actions->conf,
12155 						0);
12156 				if (!flow->counter)
12157 					return rte_flow_error_set
12158 						(error, rte_errno,
12159 						RTE_FLOW_ERROR_TYPE_ACTION,
12160 						NULL,
12161 						"cannot create counter"
12162 						" object.");
12163 			}
12164 			sample_act->dr_cnt_action =
12165 				  (flow_dv_counter_get_by_idx(dev,
12166 				  flow->counter, NULL))->action;
12167 			sample_actions[sample_act->actions_num++] =
12168 						sample_act->dr_cnt_action;
12169 			action_flags |= MLX5_FLOW_ACTION_COUNT;
12170 			break;
12171 		}
12172 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
12173 		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
12174 		{
12175 			struct mlx5_flow_dv_port_id_action_resource
12176 					port_id_resource;
12177 			uint32_t port_id = 0;
12178 
12179 			memset(&port_id_resource, 0, sizeof(port_id_resource));
12180 			/* Save the port id resource before sample */
12181 			pre_rix = dev_flow->handle->rix_port_id_action;
12182 			pre_r = dev_flow->dv.port_id_action;
12183 			if (flow_dv_translate_action_port_id(dev, sub_actions,
12184 							     &port_id, error))
12185 				return -rte_errno;
12186 			port_id_resource.port_id = port_id;
12187 			if (flow_dv_port_id_action_resource_register
12188 			    (dev, &port_id_resource, dev_flow, error))
12189 				return -rte_errno;
12190 			sample_act->dr_port_id_action =
12191 				dev_flow->dv.port_id_action->action;
12192 			sample_idx->rix_port_id_action =
12193 				dev_flow->handle->rix_port_id_action;
12194 			sample_actions[sample_act->actions_num++] =
12195 						sample_act->dr_port_id_action;
12196 			/* Recover the port id resource after sample */
12197 			dev_flow->dv.port_id_action = pre_r;
12198 			dev_flow->handle->rix_port_id_action = pre_rix;
12199 			(*num_of_dest)++;
12200 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
12201 			break;
12202 		}
12203 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
12204 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
12205 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
12206 			/* Save the encap resource before sample */
12207 			pre_rix = dev_flow->handle->dvh.rix_encap_decap;
12208 			pre_r = dev_flow->dv.encap_decap;
12209 			if (flow_dv_create_action_l2_encap(dev, sub_actions,
12210 							   dev_flow,
12211 							   attr->transfer,
12212 							   error))
12213 				return -rte_errno;
12214 			sample_act->dr_encap_action =
12215 				dev_flow->dv.encap_decap->action;
12216 			sample_idx->rix_encap_decap =
12217 				dev_flow->handle->dvh.rix_encap_decap;
12218 			sample_actions[sample_act->actions_num++] =
12219 						sample_act->dr_encap_action;
12220 			/* Recover the encap resource after sample */
12221 			dev_flow->dv.encap_decap = pre_r;
12222 			dev_flow->handle->dvh.rix_encap_decap = pre_rix;
12223 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
12224 			break;
12225 		default:
12226 			return rte_flow_error_set(error, EINVAL,
12227 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
12228 				NULL,
12229 				"Not support for sampler action");
12230 		}
12231 	}
12232 	sample_act->action_flags = action_flags;
12233 	res->ft_id = dev_flow->dv.group;
12234 	if (attr->transfer) {
12235 		union {
12236 			uint32_t action_in[MLX5_ST_SZ_DW(set_action_in)];
12237 			uint64_t set_action;
12238 		} action_ctx = { .set_action = 0 };
12239 		uint32_t vport_meta_tag = wks->vport_meta_tag ?
12240 					  wks->vport_meta_tag :
12241 					  priv->vport_meta_tag;
12242 
12243 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
12244 		MLX5_SET(set_action_in, action_ctx.action_in, action_type,
12245 			 MLX5_MODIFICATION_TYPE_SET);
12246 		MLX5_SET(set_action_in, action_ctx.action_in, field,
12247 			 MLX5_MODI_META_REG_C_0);
12248 		MLX5_SET(set_action_in, action_ctx.action_in, data,
12249 			 vport_meta_tag);
12250 		res->set_action = action_ctx.set_action;
12251 	} else if (attr->ingress) {
12252 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
12253 	} else {
12254 		res->ft_type = MLX5DV_FLOW_TABLE_TYPE_NIC_TX;
12255 	}
12256 	return 0;
12257 }
12258 
12259 static void *
12260 flow_dv_translate_action_send_to_kernel(struct rte_eth_dev *dev,
12261 					struct rte_flow_error *error)
12262 {
12263 	struct mlx5_flow_tbl_resource *tbl;
12264 	struct mlx5_dev_ctx_shared *sh;
12265 	uint32_t priority;
12266 	void *action;
12267 	int ret;
12268 
12269 	sh = MLX5_SH(dev);
12270 	if (sh->send_to_kernel_action.action)
12271 		return sh->send_to_kernel_action.action;
12272 	priority = mlx5_get_send_to_kernel_priority(dev);
12273 	if (priority == (uint32_t)-1) {
12274 		rte_flow_error_set(error, ENOTSUP,
12275 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12276 				   "required priority is not available");
12277 		return NULL;
12278 	}
12279 	tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL, 0, 0, 0,
12280 				       error);
12281 	if (!tbl) {
12282 		rte_flow_error_set(error, ENODATA,
12283 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12284 				   "cannot find destination root table");
12285 		return NULL;
12286 	}
12287 	ret = mlx5_flow_os_create_flow_action_send_to_kernel(tbl->obj,
12288 				priority, &action);
12289 	if (ret) {
12290 		rte_flow_error_set(error, ENOMEM,
12291 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
12292 				   "cannot create action");
12293 		goto err;
12294 	}
12295 	MLX5_ASSERT(action);
12296 	sh->send_to_kernel_action.action = action;
12297 	sh->send_to_kernel_action.tbl = tbl;
12298 	return action;
12299 err:
12300 	flow_dv_tbl_resource_release(sh, tbl);
12301 	return NULL;
12302 }
12303 
12304 /**
12305  * Convert Sample action to DV specification.
12306  *
12307  * @param[in] dev
12308  *   Pointer to rte_eth_dev structure.
12309  * @param[in, out] dev_flow
12310  *   Pointer to the mlx5_flow.
12311  * @param[in] num_of_dest
12312  *   The num of destination.
12313  * @param[in, out] res
12314  *   Pointer to sample resource.
12315  * @param[in, out] mdest_res
12316  *   Pointer to destination array resource.
12317  * @param[in] sample_actions
12318  *   Pointer to sample path actions list.
12319  * @param[in] action_flags
12320  *   Holds the actions detected until now.
12321  * @param[out] error
12322  *   Pointer to the error structure.
12323  *
12324  * @return
12325  *   0 on success, a negative errno value otherwise and rte_errno is set.
12326  */
12327 static int
12328 flow_dv_create_action_sample(struct rte_eth_dev *dev,
12329 			     struct mlx5_flow *dev_flow,
12330 			     uint32_t num_of_dest,
12331 			     struct mlx5_flow_dv_sample_resource *res,
12332 			     struct mlx5_flow_dv_dest_array_resource *mdest_res,
12333 			     void **sample_actions,
12334 			     uint64_t action_flags,
12335 			     struct rte_flow_error *error)
12336 {
12337 	/* update normal path action resource into last index of array */
12338 	uint32_t dest_index = MLX5_MAX_DEST_NUM - 1;
12339 	struct mlx5_flow_sub_actions_list *sample_act =
12340 					&mdest_res->sample_act[dest_index];
12341 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
12342 	struct mlx5_flow_rss_desc *rss_desc;
12343 	uint32_t normal_idx = 0;
12344 	struct mlx5_hrxq *hrxq;
12345 	uint32_t hrxq_idx;
12346 
12347 	MLX5_ASSERT(wks);
12348 	rss_desc = &wks->rss_desc;
12349 	if (num_of_dest > 1) {
12350 		if (sample_act->action_flags & MLX5_FLOW_ACTION_QUEUE) {
12351 			/* Handle QP action for mirroring */
12352 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow,
12353 						    rss_desc, &hrxq_idx);
12354 			if (!hrxq)
12355 				return rte_flow_error_set
12356 				     (error, rte_errno,
12357 				      RTE_FLOW_ERROR_TYPE_ACTION,
12358 				      NULL,
12359 				      "cannot create rx queue");
12360 			normal_idx++;
12361 			mdest_res->sample_idx[dest_index].rix_hrxq = hrxq_idx;
12362 			sample_act->dr_queue_action = hrxq->action;
12363 			if (action_flags & MLX5_FLOW_ACTION_MARK)
12364 				dev_flow->handle->rix_hrxq = hrxq_idx;
12365 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
12366 		}
12367 		if (sample_act->action_flags & MLX5_FLOW_ACTION_ENCAP) {
12368 			normal_idx++;
12369 			mdest_res->sample_idx[dest_index].rix_encap_decap =
12370 				dev_flow->handle->dvh.rix_encap_decap;
12371 			sample_act->dr_encap_action =
12372 				dev_flow->dv.encap_decap->action;
12373 			dev_flow->handle->dvh.rix_encap_decap = 0;
12374 		}
12375 		if (sample_act->action_flags & MLX5_FLOW_ACTION_PORT_ID) {
12376 			normal_idx++;
12377 			mdest_res->sample_idx[dest_index].rix_port_id_action =
12378 				dev_flow->handle->rix_port_id_action;
12379 			sample_act->dr_port_id_action =
12380 				dev_flow->dv.port_id_action->action;
12381 			dev_flow->handle->rix_port_id_action = 0;
12382 		}
12383 		if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) {
12384 			normal_idx++;
12385 			mdest_res->sample_idx[dest_index].rix_jump =
12386 				dev_flow->handle->rix_jump;
12387 			sample_act->dr_jump_action =
12388 				dev_flow->dv.jump->action;
12389 			dev_flow->handle->rix_jump = 0;
12390 		}
12391 		sample_act->actions_num = normal_idx;
12392 		/* update sample action resource into first index of array */
12393 		mdest_res->ft_type = res->ft_type;
12394 		memcpy(&mdest_res->sample_idx[0], &res->sample_idx,
12395 				sizeof(struct mlx5_flow_sub_actions_idx));
12396 		memcpy(&mdest_res->sample_act[0], &res->sample_act,
12397 				sizeof(struct mlx5_flow_sub_actions_list));
12398 		mdest_res->num_of_dest = num_of_dest;
12399 		if (flow_dv_dest_array_resource_register(dev, mdest_res,
12400 							 dev_flow, error))
12401 			return rte_flow_error_set(error, EINVAL,
12402 						  RTE_FLOW_ERROR_TYPE_ACTION,
12403 						  NULL, "can't create sample "
12404 						  "action");
12405 	} else {
12406 		res->sub_actions = sample_actions;
12407 		if (flow_dv_sample_resource_register(dev, res, dev_flow, error))
12408 			return rte_flow_error_set(error, EINVAL,
12409 						  RTE_FLOW_ERROR_TYPE_ACTION,
12410 						  NULL,
12411 						  "can't create sample action");
12412 	}
12413 	return 0;
12414 }
12415 
12416 /**
12417  * Remove an ASO age action from age actions list.
12418  *
12419  * @param[in] dev
12420  *   Pointer to the Ethernet device structure.
12421  * @param[in] age
12422  *   Pointer to the aso age action handler.
12423  */
12424 static void
12425 flow_dv_aso_age_remove_from_age(struct rte_eth_dev *dev,
12426 				struct mlx5_aso_age_action *age)
12427 {
12428 	struct mlx5_age_info *age_info;
12429 	struct mlx5_age_param *age_param = &age->age_params;
12430 	struct mlx5_priv *priv = dev->data->dev_private;
12431 	uint16_t expected = AGE_CANDIDATE;
12432 
12433 	age_info = GET_PORT_AGE_INFO(priv);
12434 	if (!__atomic_compare_exchange_n(&age_param->state, &expected,
12435 					 AGE_FREE, false, __ATOMIC_RELAXED,
12436 					 __ATOMIC_RELAXED)) {
12437 		/**
12438 		 * We need the lock even it is age timeout,
12439 		 * since age action may still in process.
12440 		 */
12441 		rte_spinlock_lock(&age_info->aged_sl);
12442 		LIST_REMOVE(age, next);
12443 		rte_spinlock_unlock(&age_info->aged_sl);
12444 		__atomic_store_n(&age_param->state, AGE_FREE, __ATOMIC_RELAXED);
12445 	}
12446 }
12447 
12448 /**
12449  * Release an ASO age action.
12450  *
12451  * @param[in] dev
12452  *   Pointer to the Ethernet device structure.
12453  * @param[in] age_idx
12454  *   Index of ASO age action to release.
12455  * @param[in] flow
12456  *   True if the release operation is during flow destroy operation.
12457  *   False if the release operation is during action destroy operation.
12458  *
12459  * @return
12460  *   0 when age action was removed, otherwise the number of references.
12461  */
12462 static int
12463 flow_dv_aso_age_release(struct rte_eth_dev *dev, uint32_t age_idx)
12464 {
12465 	struct mlx5_priv *priv = dev->data->dev_private;
12466 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
12467 	struct mlx5_aso_age_action *age = flow_aso_age_get_by_idx(dev, age_idx);
12468 	uint32_t ret = __atomic_sub_fetch(&age->refcnt, 1, __ATOMIC_RELAXED);
12469 
12470 	if (!ret) {
12471 		flow_dv_aso_age_remove_from_age(dev, age);
12472 		rte_spinlock_lock(&mng->free_sl);
12473 		LIST_INSERT_HEAD(&mng->free, age, next);
12474 		rte_spinlock_unlock(&mng->free_sl);
12475 	}
12476 	return ret;
12477 }
12478 
12479 /**
12480  * Resize the ASO age pools array by MLX5_ASO_AGE_CONTAINER_RESIZE pools.
12481  *
12482  * @param[in] dev
12483  *   Pointer to the Ethernet device structure.
12484  *
12485  * @return
12486  *   0 on success, otherwise negative errno value and rte_errno is set.
12487  */
12488 static int
12489 flow_dv_aso_age_pools_resize(struct rte_eth_dev *dev)
12490 {
12491 	struct mlx5_priv *priv = dev->data->dev_private;
12492 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
12493 	void *old_pools = mng->pools;
12494 	uint32_t resize = mng->n + MLX5_ASO_AGE_CONTAINER_RESIZE;
12495 	uint32_t mem_size = sizeof(struct mlx5_aso_age_pool *) * resize;
12496 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
12497 
12498 	if (!pools) {
12499 		rte_errno = ENOMEM;
12500 		return -ENOMEM;
12501 	}
12502 	if (old_pools) {
12503 		memcpy(pools, old_pools,
12504 		       mng->n * sizeof(struct mlx5_flow_counter_pool *));
12505 		mlx5_free(old_pools);
12506 	} else {
12507 		/* First ASO flow hit allocation - starting ASO data-path. */
12508 		int ret = mlx5_aso_flow_hit_queue_poll_start(priv->sh);
12509 
12510 		if (ret) {
12511 			mlx5_free(pools);
12512 			return ret;
12513 		}
12514 	}
12515 	mng->n = resize;
12516 	mng->pools = pools;
12517 	return 0;
12518 }
12519 
12520 /**
12521  * Create and initialize a new ASO aging pool.
12522  *
12523  * @param[in] dev
12524  *   Pointer to the Ethernet device structure.
12525  * @param[out] age_free
12526  *   Where to put the pointer of a new age action.
12527  *
12528  * @return
12529  *   The age actions pool pointer and @p age_free is set on success,
12530  *   NULL otherwise and rte_errno is set.
12531  */
12532 static struct mlx5_aso_age_pool *
12533 flow_dv_age_pool_create(struct rte_eth_dev *dev,
12534 			struct mlx5_aso_age_action **age_free)
12535 {
12536 	struct mlx5_priv *priv = dev->data->dev_private;
12537 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
12538 	struct mlx5_aso_age_pool *pool = NULL;
12539 	struct mlx5_devx_obj *obj = NULL;
12540 	uint32_t i;
12541 
12542 	obj = mlx5_devx_cmd_create_flow_hit_aso_obj(priv->sh->cdev->ctx,
12543 						    priv->sh->cdev->pdn);
12544 	if (!obj) {
12545 		rte_errno = ENODATA;
12546 		DRV_LOG(ERR, "Failed to create flow_hit_aso_obj using DevX.");
12547 		return NULL;
12548 	}
12549 	pool = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*pool), 0, SOCKET_ID_ANY);
12550 	if (!pool) {
12551 		claim_zero(mlx5_devx_cmd_destroy(obj));
12552 		rte_errno = ENOMEM;
12553 		return NULL;
12554 	}
12555 	pool->flow_hit_aso_obj = obj;
12556 	pool->time_of_last_age_check = MLX5_CURR_TIME_SEC;
12557 	rte_rwlock_write_lock(&mng->resize_rwl);
12558 	pool->index = mng->next;
12559 	/* Resize pools array if there is no room for the new pool in it. */
12560 	if (pool->index == mng->n && flow_dv_aso_age_pools_resize(dev)) {
12561 		claim_zero(mlx5_devx_cmd_destroy(obj));
12562 		mlx5_free(pool);
12563 		rte_rwlock_write_unlock(&mng->resize_rwl);
12564 		return NULL;
12565 	}
12566 	mng->pools[pool->index] = pool;
12567 	mng->next++;
12568 	rte_rwlock_write_unlock(&mng->resize_rwl);
12569 	/* Assign the first action in the new pool, the rest go to free list. */
12570 	*age_free = &pool->actions[0];
12571 	for (i = 1; i < MLX5_ASO_AGE_ACTIONS_PER_POOL; i++) {
12572 		pool->actions[i].offset = i;
12573 		LIST_INSERT_HEAD(&mng->free, &pool->actions[i], next);
12574 	}
12575 	return pool;
12576 }
12577 
12578 /**
12579  * Allocate a ASO aging bit.
12580  *
12581  * @param[in] dev
12582  *   Pointer to the Ethernet device structure.
12583  * @param[out] error
12584  *   Pointer to the error structure.
12585  *
12586  * @return
12587  *   Index to ASO age action on success, 0 otherwise and rte_errno is set.
12588  */
12589 static uint32_t
12590 flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
12591 {
12592 	struct mlx5_priv *priv = dev->data->dev_private;
12593 	const struct mlx5_aso_age_pool *pool;
12594 	struct mlx5_aso_age_action *age_free = NULL;
12595 	struct mlx5_aso_age_mng *mng = priv->sh->aso_age_mng;
12596 
12597 	MLX5_ASSERT(mng);
12598 	/* Try to get the next free age action bit. */
12599 	rte_spinlock_lock(&mng->free_sl);
12600 	age_free = LIST_FIRST(&mng->free);
12601 	if (age_free) {
12602 		LIST_REMOVE(age_free, next);
12603 	} else if (!flow_dv_age_pool_create(dev, &age_free)) {
12604 		rte_spinlock_unlock(&mng->free_sl);
12605 		rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
12606 				   NULL, "failed to create ASO age pool");
12607 		return 0; /* 0 is an error. */
12608 	}
12609 	rte_spinlock_unlock(&mng->free_sl);
12610 	pool = container_of
12611 	  ((const struct mlx5_aso_age_action (*)[MLX5_ASO_AGE_ACTIONS_PER_POOL])
12612 		  (age_free - age_free->offset), const struct mlx5_aso_age_pool,
12613 								       actions);
12614 	if (!age_free->dr_action) {
12615 		int reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_FLOW_HIT, 0,
12616 						 error);
12617 
12618 		if (reg_c < 0) {
12619 			rte_flow_error_set(error, rte_errno,
12620 					   RTE_FLOW_ERROR_TYPE_ACTION,
12621 					   NULL, "failed to get reg_c "
12622 					   "for ASO flow hit");
12623 			return 0; /* 0 is an error. */
12624 		}
12625 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
12626 		age_free->dr_action = mlx5_glue->dv_create_flow_action_aso
12627 				(priv->sh->rx_domain,
12628 				 pool->flow_hit_aso_obj->obj, age_free->offset,
12629 				 MLX5DV_DR_ACTION_FLAGS_ASO_FIRST_HIT_SET,
12630 				 (reg_c - REG_C_0));
12631 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
12632 		if (!age_free->dr_action) {
12633 			rte_errno = errno;
12634 			rte_spinlock_lock(&mng->free_sl);
12635 			LIST_INSERT_HEAD(&mng->free, age_free, next);
12636 			rte_spinlock_unlock(&mng->free_sl);
12637 			rte_flow_error_set(error, rte_errno,
12638 					   RTE_FLOW_ERROR_TYPE_ACTION,
12639 					   NULL, "failed to create ASO "
12640 					   "flow hit action");
12641 			return 0; /* 0 is an error. */
12642 		}
12643 	}
12644 	__atomic_store_n(&age_free->refcnt, 1, __ATOMIC_RELAXED);
12645 	return pool->index | ((age_free->offset + 1) << 16);
12646 }
12647 
12648 /**
12649  * Initialize flow ASO age parameters.
12650  *
12651  * @param[in] dev
12652  *   Pointer to rte_eth_dev structure.
12653  * @param[in] age_idx
12654  *   Index of ASO age action.
12655  * @param[in] context
12656  *   Pointer to flow counter age context.
12657  * @param[in] timeout
12658  *   Aging timeout in seconds.
12659  *
12660  */
12661 static void
12662 flow_dv_aso_age_params_init(struct rte_eth_dev *dev,
12663 			    uint32_t age_idx,
12664 			    void *context,
12665 			    uint32_t timeout)
12666 {
12667 	struct mlx5_aso_age_action *aso_age;
12668 
12669 	aso_age = flow_aso_age_get_by_idx(dev, age_idx);
12670 	MLX5_ASSERT(aso_age);
12671 	aso_age->age_params.context = context;
12672 	aso_age->age_params.timeout = timeout;
12673 	aso_age->age_params.port_id = dev->data->port_id;
12674 	__atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0,
12675 			 __ATOMIC_RELAXED);
12676 	__atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE,
12677 			 __ATOMIC_RELAXED);
12678 }
12679 
12680 static void
12681 flow_dv_translate_integrity_l4(const struct rte_flow_item_integrity *mask,
12682 			       void *headers)
12683 {
12684 	/*
12685 	 * In HWS mode MLX5_ITEM_UPDATE() macro assigns the same pointer to
12686 	 * both mask and value, therefore ether can be used.
12687 	 * In SWS SW_V mode mask points to item mask and value points to item
12688 	 * spec. Integrity item value is used only if matching mask is set.
12689 	 * Use mask reference here to keep SWS functionality.
12690 	 */
12691 	if (mask->l4_ok) {
12692 		/* RTE l4_ok filter aggregates hardware l4_ok and
12693 		 * l4_checksum_ok filters.
12694 		 * Positive RTE l4_ok match requires hardware match on both L4
12695 		 * hardware integrity bits.
12696 		 * PMD supports positive integrity item semantics only.
12697 		 */
12698 		MLX5_SET(fte_match_set_lyr_2_4, headers, l4_ok, 1);
12699 		MLX5_SET(fte_match_set_lyr_2_4, headers, l4_checksum_ok, 1);
12700 	} else if (mask->l4_csum_ok) {
12701 		MLX5_SET(fte_match_set_lyr_2_4, headers, l4_checksum_ok, 1);
12702 	}
12703 }
12704 
12705 static void
12706 flow_dv_translate_integrity_l3(const struct rte_flow_item_integrity *mask,
12707 			       void *headers, bool is_ipv4)
12708 {
12709 	/*
12710 	 * In HWS mode MLX5_ITEM_UPDATE() macro assigns the same pointer to
12711 	 * both mask and value, therefore ether can be used.
12712 	 * In SWS SW_V mode mask points to item mask and value points to item
12713 	 * spec. Integrity item value used only if matching mask is set.
12714 	 * Use mask reference here to keep SWS functionality.
12715 	 */
12716 	if (mask->l3_ok) {
12717 		/* RTE l3_ok filter aggregates for IPv4 hardware l3_ok and
12718 		 * ipv4_csum_ok filters.
12719 		 * Positive RTE l3_ok match requires hardware match on both L3
12720 		 * hardware integrity bits.
12721 		 * PMD supports positive integrity item semantics only.
12722 		 */
12723 		MLX5_SET(fte_match_set_lyr_2_4, headers, l3_ok, 1);
12724 		if (is_ipv4) {
12725 			MLX5_SET(fte_match_set_lyr_2_4, headers,
12726 				 ipv4_checksum_ok, 1);
12727 		}
12728 	} else if (is_ipv4 && mask->ipv4_csum_ok) {
12729 		MLX5_SET(fte_match_set_lyr_2_4, headers, ipv4_checksum_ok, 1);
12730 	}
12731 }
12732 
12733 static void
12734 set_integrity_bits(void *headers, const struct rte_flow_item *integrity_item,
12735 		   bool is_l3_ip4, uint32_t key_type)
12736 {
12737 	const struct rte_flow_item_integrity *spec;
12738 	const struct rte_flow_item_integrity *mask;
12739 
12740 	/* Integrity bits validation cleared spec pointer */
12741 	if (MLX5_ITEM_VALID(integrity_item, key_type))
12742 		return;
12743 	MLX5_ITEM_UPDATE(integrity_item, key_type, spec, mask,
12744 			 &rte_flow_item_integrity_mask);
12745 	flow_dv_translate_integrity_l3(mask, headers, is_l3_ip4);
12746 	flow_dv_translate_integrity_l4(mask, headers);
12747 }
12748 
12749 static void
12750 flow_dv_translate_item_integrity_post(void *key,
12751 				      const
12752 				      struct rte_flow_item *integrity_items[2],
12753 				      uint64_t pattern_flags, uint32_t key_type)
12754 {
12755 	void *headers;
12756 	bool is_l3_ip4;
12757 
12758 	if (pattern_flags & MLX5_FLOW_ITEM_INNER_INTEGRITY) {
12759 		headers = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
12760 		is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4) !=
12761 			    0;
12762 		set_integrity_bits(headers, integrity_items[1], is_l3_ip4,
12763 				   key_type);
12764 	}
12765 	if (pattern_flags & MLX5_FLOW_ITEM_OUTER_INTEGRITY) {
12766 		headers = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
12767 		is_l3_ip4 = (pattern_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4) !=
12768 			    0;
12769 		set_integrity_bits(headers, integrity_items[0], is_l3_ip4,
12770 				   key_type);
12771 	}
12772 }
12773 
12774 static uint64_t
12775 flow_dv_translate_item_integrity(const struct rte_flow_item *item,
12776 				 struct mlx5_dv_matcher_workspace *wks,
12777 				 uint64_t key_type)
12778 {
12779 	if ((key_type & MLX5_SET_MATCHER_SW) != 0) {
12780 		const struct rte_flow_item_integrity
12781 			*spec = (typeof(spec))item->spec;
12782 
12783 		/* SWS integrity bits validation cleared spec pointer */
12784 		if (spec->level > 1) {
12785 			wks->integrity_items[1] = item;
12786 			wks->last_item |= MLX5_FLOW_ITEM_INNER_INTEGRITY;
12787 		} else {
12788 			wks->integrity_items[0] = item;
12789 			wks->last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY;
12790 		}
12791 	} else {
12792 		/* HWS supports outer integrity only */
12793 		wks->integrity_items[0] = item;
12794 		wks->last_item |= MLX5_FLOW_ITEM_OUTER_INTEGRITY;
12795 	}
12796 	return wks->last_item;
12797 }
12798 
12799 /**
12800  * Prepares DV flow counter with aging configuration.
12801  * Gets it by index when exists, creates a new one when doesn't.
12802  *
12803  * @param[in] dev
12804  *   Pointer to rte_eth_dev structure.
12805  * @param[in] dev_flow
12806  *   Pointer to the mlx5_flow.
12807  * @param[in, out] flow
12808  *   Pointer to the sub flow.
12809  * @param[in] count
12810  *   Pointer to the counter action configuration.
12811  * @param[in] age
12812  *   Pointer to the aging action configuration.
12813  * @param[out] error
12814  *   Pointer to the error structure.
12815  *
12816  * @return
12817  *   Pointer to the counter, NULL otherwise.
12818  */
12819 static struct mlx5_flow_counter *
12820 flow_dv_prepare_counter(struct rte_eth_dev *dev,
12821 			struct mlx5_flow *dev_flow,
12822 			struct rte_flow *flow,
12823 			const struct rte_flow_action_count *count,
12824 			const struct rte_flow_action_age *age,
12825 			struct rte_flow_error *error)
12826 {
12827 	if (!flow->counter) {
12828 		flow->counter = flow_dv_translate_create_counter(dev, dev_flow,
12829 								 count, age);
12830 		if (!flow->counter) {
12831 			rte_flow_error_set(error, rte_errno,
12832 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
12833 					   "cannot create counter object.");
12834 			return NULL;
12835 		}
12836 	}
12837 	return flow_dv_counter_get_by_idx(dev, flow->counter, NULL);
12838 }
12839 
12840 /*
12841  * Release an ASO CT action by its own device.
12842  *
12843  * @param[in] dev
12844  *   Pointer to the Ethernet device structure.
12845  * @param[in] idx
12846  *   Index of ASO CT action to release.
12847  *
12848  * @return
12849  *   0 when CT action was removed, otherwise the number of references.
12850  */
12851 static inline int
12852 flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx)
12853 {
12854 	struct mlx5_priv *priv = dev->data->dev_private;
12855 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12856 	uint32_t ret;
12857 	struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx);
12858 	enum mlx5_aso_ct_state state =
12859 			__atomic_load_n(&ct->state, __ATOMIC_RELAXED);
12860 
12861 	/* Cannot release when CT is in the ASO SQ. */
12862 	if (state == ASO_CONNTRACK_WAIT || state == ASO_CONNTRACK_QUERY)
12863 		return -1;
12864 	ret = __atomic_sub_fetch(&ct->refcnt, 1, __ATOMIC_RELAXED);
12865 	if (!ret) {
12866 		if (ct->dr_action_orig) {
12867 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12868 			claim_zero(mlx5_glue->destroy_flow_action
12869 					(ct->dr_action_orig));
12870 #endif
12871 			ct->dr_action_orig = NULL;
12872 		}
12873 		if (ct->dr_action_rply) {
12874 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
12875 			claim_zero(mlx5_glue->destroy_flow_action
12876 					(ct->dr_action_rply));
12877 #endif
12878 			ct->dr_action_rply = NULL;
12879 		}
12880 		/* Clear the state to free, no need in 1st allocation. */
12881 		MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_FREE);
12882 		rte_spinlock_lock(&mng->ct_sl);
12883 		LIST_INSERT_HEAD(&mng->free_cts, ct, next);
12884 		rte_spinlock_unlock(&mng->ct_sl);
12885 	}
12886 	return (int)ret;
12887 }
12888 
12889 static inline int
12890 flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx,
12891 		       struct rte_flow_error *error)
12892 {
12893 	uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx);
12894 	uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx);
12895 	struct rte_eth_dev *owndev = &rte_eth_devices[owner];
12896 	int ret;
12897 
12898 	MLX5_ASSERT(owner < RTE_MAX_ETHPORTS);
12899 	if (dev->data->dev_started != 1)
12900 		return rte_flow_error_set(error, EAGAIN,
12901 					  RTE_FLOW_ERROR_TYPE_ACTION,
12902 					  NULL,
12903 					  "Indirect CT action cannot be destroyed when the port is stopped");
12904 	ret = flow_dv_aso_ct_dev_release(owndev, idx);
12905 	if (ret < 0)
12906 		return rte_flow_error_set(error, EAGAIN,
12907 					  RTE_FLOW_ERROR_TYPE_ACTION,
12908 					  NULL,
12909 					  "Current state prevents indirect CT action from being destroyed");
12910 	return ret;
12911 }
12912 
12913 /*
12914  * Resize the ASO CT pools array by 64 pools.
12915  *
12916  * @param[in] dev
12917  *   Pointer to the Ethernet device structure.
12918  *
12919  * @return
12920  *   0 on success, otherwise negative errno value and rte_errno is set.
12921  */
12922 static int
12923 flow_dv_aso_ct_pools_resize(struct rte_eth_dev *dev)
12924 {
12925 	struct mlx5_priv *priv = dev->data->dev_private;
12926 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12927 	void *old_pools = mng->pools;
12928 	/* Magic number now, need a macro. */
12929 	uint32_t resize = mng->n + 64;
12930 	uint32_t mem_size = sizeof(struct mlx5_aso_ct_pool *) * resize;
12931 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
12932 
12933 	if (!pools) {
12934 		rte_errno = ENOMEM;
12935 		return -rte_errno;
12936 	}
12937 	rte_rwlock_write_lock(&mng->resize_rwl);
12938 	/* ASO SQ/QP was already initialized in the startup. */
12939 	if (old_pools) {
12940 		/* Realloc could be an alternative choice. */
12941 		rte_memcpy(pools, old_pools,
12942 			   mng->n * sizeof(struct mlx5_aso_ct_pool *));
12943 		mlx5_free(old_pools);
12944 	}
12945 	mng->n = resize;
12946 	mng->pools = pools;
12947 	rte_rwlock_write_unlock(&mng->resize_rwl);
12948 	return 0;
12949 }
12950 
12951 /*
12952  * Create and initialize a new ASO CT pool.
12953  *
12954  * @param[in] dev
12955  *   Pointer to the Ethernet device structure.
12956  * @param[out] ct_free
12957  *   Where to put the pointer of a new CT action.
12958  *
12959  * @return
12960  *   The CT actions pool pointer and @p ct_free is set on success,
12961  *   NULL otherwise and rte_errno is set.
12962  */
12963 static struct mlx5_aso_ct_pool *
12964 flow_dv_ct_pool_create(struct rte_eth_dev *dev,
12965 		       struct mlx5_aso_ct_action **ct_free)
12966 {
12967 	struct mlx5_priv *priv = dev->data->dev_private;
12968 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
12969 	struct mlx5_aso_ct_pool *pool = NULL;
12970 	struct mlx5_devx_obj *obj = NULL;
12971 	uint32_t i;
12972 	uint32_t log_obj_size = rte_log2_u32(MLX5_ASO_CT_ACTIONS_PER_POOL);
12973 	size_t mem_size;
12974 
12975 	obj = mlx5_devx_cmd_create_conn_track_offload_obj(priv->sh->cdev->ctx,
12976 							  priv->sh->cdev->pdn,
12977 							  log_obj_size);
12978 	if (!obj) {
12979 		rte_errno = ENODATA;
12980 		DRV_LOG(ERR, "Failed to create conn_track_offload_obj using DevX.");
12981 		return NULL;
12982 	}
12983 	mem_size = sizeof(struct mlx5_aso_ct_action) *
12984 		   MLX5_ASO_CT_ACTIONS_PER_POOL +
12985 		   sizeof(*pool);
12986 	pool = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
12987 	if (!pool) {
12988 		rte_errno = ENOMEM;
12989 		claim_zero(mlx5_devx_cmd_destroy(obj));
12990 		return NULL;
12991 	}
12992 	pool->devx_obj = obj;
12993 	pool->index = mng->next;
12994 	/* Resize pools array if there is no room for the new pool in it. */
12995 	if (pool->index == mng->n && flow_dv_aso_ct_pools_resize(dev)) {
12996 		claim_zero(mlx5_devx_cmd_destroy(obj));
12997 		mlx5_free(pool);
12998 		return NULL;
12999 	}
13000 	mng->pools[pool->index] = pool;
13001 	mng->next++;
13002 	/* Assign the first action in the new pool, the rest go to free list. */
13003 	*ct_free = &pool->actions[0];
13004 	/* Lock outside, the list operation is safe here. */
13005 	for (i = 1; i < MLX5_ASO_CT_ACTIONS_PER_POOL; i++) {
13006 		/* refcnt is 0 when allocating the memory. */
13007 		pool->actions[i].offset = i;
13008 		LIST_INSERT_HEAD(&mng->free_cts, &pool->actions[i], next);
13009 	}
13010 	return pool;
13011 }
13012 
13013 /*
13014  * Allocate a ASO CT action from free list.
13015  *
13016  * @param[in] dev
13017  *   Pointer to the Ethernet device structure.
13018  * @param[out] error
13019  *   Pointer to the error structure.
13020  *
13021  * @return
13022  *   Index to ASO CT action on success, 0 otherwise and rte_errno is set.
13023  */
13024 static uint32_t
13025 flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
13026 {
13027 	struct mlx5_priv *priv = dev->data->dev_private;
13028 	struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
13029 	struct mlx5_aso_ct_action *ct = NULL;
13030 	struct mlx5_aso_ct_pool *pool;
13031 	uint8_t reg_c;
13032 	uint32_t ct_idx;
13033 
13034 	MLX5_ASSERT(mng);
13035 	if (!priv->sh->cdev->config.devx) {
13036 		rte_errno = ENOTSUP;
13037 		return 0;
13038 	}
13039 	/* Get a free CT action, if no, a new pool will be created. */
13040 	rte_spinlock_lock(&mng->ct_sl);
13041 	ct = LIST_FIRST(&mng->free_cts);
13042 	if (ct) {
13043 		LIST_REMOVE(ct, next);
13044 	} else if (!flow_dv_ct_pool_create(dev, &ct)) {
13045 		rte_spinlock_unlock(&mng->ct_sl);
13046 		rte_flow_error_set(error, rte_errno, RTE_FLOW_ERROR_TYPE_ACTION,
13047 				   NULL, "failed to create ASO CT pool");
13048 		return 0;
13049 	}
13050 	rte_spinlock_unlock(&mng->ct_sl);
13051 	pool = container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]);
13052 	ct_idx = MLX5_MAKE_CT_IDX(pool->index, ct->offset);
13053 	/* 0: inactive, 1: created, 2+: used by flows. */
13054 	__atomic_store_n(&ct->refcnt, 1, __ATOMIC_RELAXED);
13055 	reg_c = mlx5_flow_get_reg_id(dev, MLX5_ASO_CONNTRACK, 0, error);
13056 	if (!ct->dr_action_orig) {
13057 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
13058 		ct->dr_action_orig = mlx5_glue->dv_create_flow_action_aso
13059 			(priv->sh->rx_domain, pool->devx_obj->obj,
13060 			 ct->offset,
13061 			 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_INITIATOR,
13062 			 reg_c - REG_C_0);
13063 #else
13064 		RTE_SET_USED(reg_c);
13065 #endif
13066 		if (!ct->dr_action_orig) {
13067 			flow_dv_aso_ct_dev_release(dev, ct_idx);
13068 			rte_flow_error_set(error, rte_errno,
13069 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
13070 					   "failed to create ASO CT action");
13071 			return 0;
13072 		}
13073 	}
13074 	if (!ct->dr_action_rply) {
13075 #ifdef HAVE_MLX5_DR_ACTION_ASO_CT
13076 		ct->dr_action_rply = mlx5_glue->dv_create_flow_action_aso
13077 			(priv->sh->rx_domain, pool->devx_obj->obj,
13078 			 ct->offset,
13079 			 MLX5DV_DR_ACTION_FLAGS_ASO_CT_DIRECTION_RESPONDER,
13080 			 reg_c - REG_C_0);
13081 #endif
13082 		if (!ct->dr_action_rply) {
13083 			flow_dv_aso_ct_dev_release(dev, ct_idx);
13084 			rte_flow_error_set(error, rte_errno,
13085 					   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
13086 					   "failed to create ASO CT action");
13087 			return 0;
13088 		}
13089 	}
13090 	return ct_idx;
13091 }
13092 
13093 /*
13094  * Create a conntrack object with context and actions by using ASO mechanism.
13095  *
13096  * @param[in] dev
13097  *   Pointer to rte_eth_dev structure.
13098  * @param[in] pro
13099  *   Pointer to conntrack information profile.
13100  * @param[out] error
13101  *   Pointer to the error structure.
13102  *
13103  * @return
13104  *   Index to conntrack object on success, 0 otherwise.
13105  */
13106 static uint32_t
13107 flow_dv_translate_create_conntrack(struct rte_eth_dev *dev,
13108 				   const struct rte_flow_action_conntrack *pro,
13109 				   struct rte_flow_error *error)
13110 {
13111 	struct mlx5_priv *priv = dev->data->dev_private;
13112 	struct mlx5_dev_ctx_shared *sh = priv->sh;
13113 	struct mlx5_aso_ct_action *ct;
13114 	uint32_t idx;
13115 
13116 	if (!sh->ct_aso_en)
13117 		return rte_flow_error_set(error, ENOTSUP,
13118 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
13119 					  "Connection is not supported");
13120 	idx = flow_dv_aso_ct_alloc(dev, error);
13121 	if (!idx)
13122 		return rte_flow_error_set(error, rte_errno,
13123 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
13124 					  "Failed to allocate CT object");
13125 	ct = flow_aso_ct_get_by_dev_idx(dev, idx);
13126 	if (mlx5_aso_ct_update_by_wqe(sh, MLX5_HW_INV_QUEUE, ct, pro, NULL, true)) {
13127 		flow_dv_aso_ct_dev_release(dev, idx);
13128 		rte_flow_error_set(error, EBUSY,
13129 				   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
13130 				   "Failed to update CT");
13131 		return 0;
13132 	}
13133 	ct->is_original = !!pro->is_original_dir;
13134 	ct->peer = pro->peer_port;
13135 	return idx;
13136 }
13137 
13138 /**
13139  * Fill the flow matcher with DV spec.
13140  *
13141  * @param[in] dev
13142  *   Pointer to rte_eth_dev structure.
13143  * @param[in] items
13144  *   Pointer to the list of items.
13145  * @param[in] wks
13146  *   Pointer to the matcher workspace.
13147  * @param[in] key
13148  *   Pointer to the flow matcher key.
13149  * @param[in] key_type
13150  *   Key type.
13151  * @param[out] error
13152  *   Pointer to the error structure.
13153  *
13154  * @return
13155  *   0 on success, a negative errno value otherwise and rte_errno is set.
13156  */
13157 static int
13158 flow_dv_translate_items(struct rte_eth_dev *dev,
13159 			const struct rte_flow_item *items,
13160 			struct mlx5_dv_matcher_workspace *wks,
13161 			void *key, uint32_t key_type,
13162 			struct rte_flow_error *error)
13163 {
13164 	struct mlx5_flow_rss_desc *rss_desc = wks->rss_desc;
13165 	uint8_t next_protocol = wks->next_protocol;
13166 	int tunnel = !!(wks->item_flags & MLX5_FLOW_LAYER_TUNNEL);
13167 	int item_type = items->type;
13168 	uint64_t last_item = wks->last_item;
13169 	int ret;
13170 
13171 	switch (item_type) {
13172 	case RTE_FLOW_ITEM_TYPE_ESP:
13173 		flow_dv_translate_item_esp(key, items, tunnel, key_type);
13174 		wks->priority = MLX5_PRIORITY_MAP_L4;
13175 		last_item = MLX5_FLOW_ITEM_ESP;
13176 		break;
13177 	case RTE_FLOW_ITEM_TYPE_PORT_ID:
13178 		flow_dv_translate_item_port_id
13179 			(dev, key, items, wks->attr, key_type);
13180 		last_item = MLX5_FLOW_ITEM_PORT_ID;
13181 		break;
13182 	case RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR:
13183 		flow_dv_translate_item_port_representor
13184 			(dev, key, key_type);
13185 		last_item = MLX5_FLOW_ITEM_PORT_REPRESENTOR;
13186 		break;
13187 	case RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT:
13188 		flow_dv_translate_item_represented_port
13189 			(dev, key, items, wks->attr, key_type);
13190 		last_item = MLX5_FLOW_ITEM_REPRESENTED_PORT;
13191 		break;
13192 	case RTE_FLOW_ITEM_TYPE_ETH:
13193 		flow_dv_translate_item_eth(key, items, tunnel,
13194 					   wks->group, key_type);
13195 		wks->priority = wks->action_flags &
13196 				MLX5_FLOW_ACTION_DEFAULT_MISS &&
13197 				!wks->external ?
13198 				MLX5_PRIORITY_MAP_L3 :
13199 				MLX5_PRIORITY_MAP_L2;
13200 		last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
13201 				     MLX5_FLOW_LAYER_OUTER_L2;
13202 		break;
13203 	case RTE_FLOW_ITEM_TYPE_VLAN:
13204 		flow_dv_translate_item_vlan(key, items, tunnel, wks, key_type);
13205 		wks->priority = MLX5_PRIORITY_MAP_L2;
13206 		last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
13207 					  MLX5_FLOW_LAYER_INNER_VLAN) :
13208 					 (MLX5_FLOW_LAYER_OUTER_L2 |
13209 					  MLX5_FLOW_LAYER_OUTER_VLAN);
13210 		break;
13211 	case RTE_FLOW_ITEM_TYPE_IPV4:
13212 		mlx5_flow_tunnel_ip_check(items, next_protocol,
13213 					  &wks->item_flags, &tunnel);
13214 		flow_dv_translate_item_ipv4(key, items, tunnel,
13215 					    wks->group, key_type);
13216 		wks->priority = MLX5_PRIORITY_MAP_L3;
13217 		last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
13218 				     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
13219 		if (items->mask != NULL &&
13220 		    items->spec != NULL &&
13221 			((const struct rte_flow_item_ipv4 *)
13222 			 items->mask)->hdr.next_proto_id) {
13223 			next_protocol =
13224 				((const struct rte_flow_item_ipv4 *)
13225 				 (items->spec))->hdr.next_proto_id;
13226 			next_protocol &=
13227 				((const struct rte_flow_item_ipv4 *)
13228 				 (items->mask))->hdr.next_proto_id;
13229 		} else if (key_type == MLX5_SET_MATCHER_HS_M &&
13230 			   items->mask != NULL) {
13231 			next_protocol =  ((const struct rte_flow_item_ipv4 *)
13232 					(items->mask))->hdr.next_proto_id;
13233 		} else if (key_type == MLX5_SET_MATCHER_HS_V &&
13234 			   items->spec != NULL) {
13235 			next_protocol =  ((const struct rte_flow_item_ipv4 *)
13236 					(items->spec))->hdr.next_proto_id;
13237 		} else {
13238 			/* Reset for inner layer. */
13239 			next_protocol = 0xff;
13240 		}
13241 		break;
13242 	case RTE_FLOW_ITEM_TYPE_IPV6:
13243 		mlx5_flow_tunnel_ip_check(items, next_protocol,
13244 					  &wks->item_flags, &tunnel);
13245 		flow_dv_translate_item_ipv6(key, items, tunnel,
13246 					    wks->group, key_type);
13247 		wks->priority = MLX5_PRIORITY_MAP_L3;
13248 		last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
13249 				     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
13250 		if (items->mask != NULL &&
13251 		    items->spec != NULL &&
13252 			((const struct rte_flow_item_ipv6 *)
13253 			 items->mask)->hdr.proto) {
13254 			next_protocol =
13255 				((const struct rte_flow_item_ipv6 *)
13256 				 items->spec)->hdr.proto;
13257 			next_protocol &=
13258 				((const struct rte_flow_item_ipv6 *)
13259 				 items->mask)->hdr.proto;
13260 		} else if (key_type == MLX5_SET_MATCHER_HS_M &&
13261 			   items->mask != NULL) {
13262 			next_protocol =  ((const struct rte_flow_item_ipv6 *)
13263 					(items->mask))->hdr.proto;
13264 		} else if (key_type == MLX5_SET_MATCHER_HS_V &&
13265 			   items->spec != NULL) {
13266 			next_protocol =  ((const struct rte_flow_item_ipv6 *)
13267 					(items->spec))->hdr.proto;
13268 		} else {
13269 			/* Reset for inner layer. */
13270 			next_protocol = 0xff;
13271 		}
13272 		break;
13273 	case RTE_FLOW_ITEM_TYPE_IPV6_FRAG_EXT:
13274 		flow_dv_translate_item_ipv6_frag_ext
13275 					(key, items, tunnel, key_type);
13276 		last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6_FRAG_EXT :
13277 				     MLX5_FLOW_LAYER_OUTER_L3_IPV6_FRAG_EXT;
13278 		if (items->mask != NULL &&
13279 		    items->spec != NULL &&
13280 			((const struct rte_flow_item_ipv6_frag_ext *)
13281 			 items->mask)->hdr.next_header) {
13282 			next_protocol =
13283 			((const struct rte_flow_item_ipv6_frag_ext *)
13284 			 items->spec)->hdr.next_header;
13285 			next_protocol &=
13286 			((const struct rte_flow_item_ipv6_frag_ext *)
13287 			 items->mask)->hdr.next_header;
13288 		} else if (key_type == MLX5_SET_MATCHER_HS_M &&
13289 			   items->mask != NULL) {
13290 			next_protocol =  ((const struct rte_flow_item_ipv6_frag_ext *)
13291 					(items->mask))->hdr.next_header;
13292 		} else if (key_type == MLX5_SET_MATCHER_HS_V &&
13293 			   items->spec != NULL) {
13294 			next_protocol =  ((const struct rte_flow_item_ipv6_frag_ext *)
13295 					(items->spec))->hdr.next_header;
13296 		} else {
13297 			/* Reset for inner layer. */
13298 			next_protocol = 0xff;
13299 		}
13300 		break;
13301 	case RTE_FLOW_ITEM_TYPE_TCP:
13302 		flow_dv_translate_item_tcp(key, items, tunnel, key_type);
13303 		wks->priority = MLX5_PRIORITY_MAP_L4;
13304 		last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
13305 				     MLX5_FLOW_LAYER_OUTER_L4_TCP;
13306 		break;
13307 	case RTE_FLOW_ITEM_TYPE_UDP:
13308 		flow_dv_translate_item_udp(key, items, tunnel, wks, key_type);
13309 		wks->priority = MLX5_PRIORITY_MAP_L4;
13310 		last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
13311 				     MLX5_FLOW_LAYER_OUTER_L4_UDP;
13312 		break;
13313 	case RTE_FLOW_ITEM_TYPE_GRE:
13314 		wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13315 		wks->tunnel_item = items;
13316 		wks->gre_item = items;
13317 		last_item = MLX5_FLOW_LAYER_GRE;
13318 		break;
13319 	case RTE_FLOW_ITEM_TYPE_GRE_KEY:
13320 		flow_dv_translate_item_gre_key(key, items, key_type);
13321 		last_item = MLX5_FLOW_LAYER_GRE_KEY;
13322 		break;
13323 	case RTE_FLOW_ITEM_TYPE_GRE_OPTION:
13324 		wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13325 		wks->tunnel_item = items;
13326 		last_item = MLX5_FLOW_LAYER_GRE;
13327 		break;
13328 	case RTE_FLOW_ITEM_TYPE_NVGRE:
13329 		wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13330 		wks->tunnel_item = items;
13331 		last_item = MLX5_FLOW_LAYER_GRE;
13332 		break;
13333 	case RTE_FLOW_ITEM_TYPE_VXLAN:
13334 		flow_dv_translate_item_vxlan(dev, wks->attr, key,
13335 					     items, tunnel, wks, key_type);
13336 		wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13337 		last_item = MLX5_FLOW_LAYER_VXLAN;
13338 		break;
13339 	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
13340 		wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13341 		wks->tunnel_item = items;
13342 		last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
13343 		break;
13344 	case RTE_FLOW_ITEM_TYPE_GENEVE:
13345 		wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13346 		wks->tunnel_item = items;
13347 		last_item = MLX5_FLOW_LAYER_GENEVE;
13348 		break;
13349 	case RTE_FLOW_ITEM_TYPE_GENEVE_OPT:
13350 		ret = flow_dv_translate_item_geneve_opt
13351 				(dev, key, items, key_type, error);
13352 		if (ret)
13353 			return rte_flow_error_set(error, -ret,
13354 				RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13355 				"cannot create GENEVE TLV option");
13356 		wks->geneve_tlv_option = 1;
13357 		last_item = MLX5_FLOW_LAYER_GENEVE_OPT;
13358 		break;
13359 	case RTE_FLOW_ITEM_TYPE_MPLS:
13360 		flow_dv_translate_item_mpls(key, items, last_item,
13361 					    tunnel, key_type);
13362 		wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13363 		last_item = MLX5_FLOW_LAYER_MPLS;
13364 		break;
13365 	case RTE_FLOW_ITEM_TYPE_MARK:
13366 		flow_dv_translate_item_mark(dev, key, items, key_type);
13367 		last_item = MLX5_FLOW_ITEM_MARK;
13368 		break;
13369 	case RTE_FLOW_ITEM_TYPE_META:
13370 		flow_dv_translate_item_meta
13371 				(dev, key, wks->attr, items, key_type);
13372 		last_item = MLX5_FLOW_ITEM_METADATA;
13373 		break;
13374 	case RTE_FLOW_ITEM_TYPE_ICMP:
13375 		flow_dv_translate_item_icmp(key, items, tunnel, key_type);
13376 		wks->priority = MLX5_PRIORITY_MAP_L4;
13377 		last_item = MLX5_FLOW_LAYER_ICMP;
13378 		break;
13379 	case RTE_FLOW_ITEM_TYPE_ICMP6:
13380 		flow_dv_translate_item_icmp6(key, items, tunnel, key_type);
13381 		wks->priority = MLX5_PRIORITY_MAP_L4;
13382 		last_item = MLX5_FLOW_LAYER_ICMP6;
13383 		break;
13384 	case RTE_FLOW_ITEM_TYPE_TAG:
13385 		flow_dv_translate_item_tag(dev, key, items, key_type);
13386 		last_item = MLX5_FLOW_ITEM_TAG;
13387 		break;
13388 	case MLX5_RTE_FLOW_ITEM_TYPE_TAG:
13389 		flow_dv_translate_mlx5_item_tag(dev, key, items, key_type);
13390 		last_item = MLX5_FLOW_ITEM_TAG;
13391 		break;
13392 	case MLX5_RTE_FLOW_ITEM_TYPE_SQ:
13393 		flow_dv_translate_item_sq(key, items, key_type);
13394 		last_item = MLX5_FLOW_ITEM_SQ;
13395 		break;
13396 	case RTE_FLOW_ITEM_TYPE_GTP:
13397 		flow_dv_translate_item_gtp(key, items, tunnel, key_type);
13398 		wks->priority = MLX5_TUNNEL_PRIO_GET(rss_desc);
13399 		last_item = MLX5_FLOW_LAYER_GTP;
13400 		break;
13401 	case RTE_FLOW_ITEM_TYPE_GTP_PSC:
13402 		ret = flow_dv_translate_item_gtp_psc(key, items, key_type);
13403 		if (ret)
13404 			return rte_flow_error_set(error, -ret,
13405 				RTE_FLOW_ERROR_TYPE_ITEM, NULL,
13406 				"cannot create GTP PSC item");
13407 		last_item = MLX5_FLOW_LAYER_GTP_PSC;
13408 		break;
13409 	case RTE_FLOW_ITEM_TYPE_ECPRI:
13410 		if (!mlx5_flex_parser_ecpri_exist(dev)) {
13411 			/* Create it only the first time to be used. */
13412 			ret = mlx5_flex_parser_ecpri_alloc(dev);
13413 			if (ret)
13414 				return rte_flow_error_set
13415 					(error, -ret,
13416 					RTE_FLOW_ERROR_TYPE_ITEM,
13417 					NULL,
13418 					"cannot create eCPRI parser");
13419 		}
13420 		flow_dv_translate_item_ecpri
13421 				(dev, key, items, last_item, key_type);
13422 		/* No other protocol should follow eCPRI layer. */
13423 		last_item = MLX5_FLOW_LAYER_ECPRI;
13424 		break;
13425 	case RTE_FLOW_ITEM_TYPE_METER_COLOR:
13426 		flow_dv_translate_item_meter_color(dev, key, items, key_type);
13427 		last_item = MLX5_FLOW_ITEM_METER_COLOR;
13428 		break;
13429 	case RTE_FLOW_ITEM_TYPE_INTEGRITY:
13430 		last_item = flow_dv_translate_item_integrity(items,
13431 							     wks, key_type);
13432 		break;
13433 	default:
13434 		break;
13435 	}
13436 	wks->item_flags |= last_item;
13437 	wks->last_item = last_item;
13438 	wks->next_protocol = next_protocol;
13439 	return 0;
13440 }
13441 
13442 /**
13443  * Fill the HW steering flow with DV spec.
13444  *
13445  * @param[in] items
13446  *   Pointer to the list of items.
13447  * @param[in] attr
13448  *   Pointer to the flow attributes.
13449  * @param[in] key
13450  *   Pointer to the flow matcher key.
13451  * @param[in] key_type
13452  *   Key type.
13453  * @param[in, out] item_flags
13454  *   Pointer to the flow item flags.
13455  * @param[out] error
13456  *   Pointer to the error structure.
13457  *
13458  * @return
13459  *   0 on success, a negative errno value otherwise and rte_errno is set.
13460  */
13461 int
13462 flow_dv_translate_items_hws(const struct rte_flow_item *items,
13463 			    struct mlx5_flow_attr *attr, void *key,
13464 			    uint32_t key_type, uint64_t *item_flags,
13465 			    uint8_t *match_criteria,
13466 			    struct rte_flow_error *error)
13467 {
13468 	struct mlx5_flow_workspace *flow_wks = mlx5_flow_push_thread_workspace();
13469 	struct mlx5_flow_rss_desc rss_desc = { .level = attr->rss_level };
13470 	struct rte_flow_attr rattr = {
13471 		.group = attr->group,
13472 		.priority = attr->priority,
13473 		.ingress = !!(attr->tbl_type == MLX5DR_TABLE_TYPE_NIC_RX),
13474 		.egress = !!(attr->tbl_type == MLX5DR_TABLE_TYPE_NIC_TX),
13475 		.transfer = !!(attr->tbl_type == MLX5DR_TABLE_TYPE_FDB),
13476 	};
13477 	struct mlx5_dv_matcher_workspace wks = {
13478 		.action_flags = attr->act_flags,
13479 		.item_flags = item_flags ? *item_flags : 0,
13480 		.external = 0,
13481 		.next_protocol = 0xff,
13482 		.attr = &rattr,
13483 		.rss_desc = &rss_desc,
13484 	};
13485 	int ret = 0;
13486 
13487 	RTE_SET_USED(flow_wks);
13488 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
13489 		if (!mlx5_flow_os_item_supported(items->type)) {
13490 			ret = rte_flow_error_set(error, ENOTSUP,
13491 						 RTE_FLOW_ERROR_TYPE_ITEM,
13492 						 NULL, "item not supported");
13493 			goto exit;
13494 		}
13495 		ret = flow_dv_translate_items(&rte_eth_devices[attr->port_id],
13496 			items, &wks, key, key_type,  NULL);
13497 		if (ret)
13498 			goto exit;
13499 	}
13500 	if (wks.item_flags & MLX5_FLOW_ITEM_INTEGRITY) {
13501 		flow_dv_translate_item_integrity_post(key,
13502 						      wks.integrity_items,
13503 						      wks.item_flags,
13504 						      key_type);
13505 	}
13506 	if (wks.item_flags & MLX5_FLOW_LAYER_VXLAN_GPE) {
13507 		flow_dv_translate_item_vxlan_gpe(key,
13508 						 wks.tunnel_item,
13509 						 wks.item_flags,
13510 						 key_type);
13511 	} else if (wks.item_flags & MLX5_FLOW_LAYER_GENEVE) {
13512 		flow_dv_translate_item_geneve(key,
13513 					      wks.tunnel_item,
13514 					      wks.item_flags,
13515 					      key_type);
13516 	} else if (wks.item_flags & MLX5_FLOW_LAYER_GRE) {
13517 		if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_GRE) {
13518 			flow_dv_translate_item_gre(key,
13519 						   wks.tunnel_item,
13520 						   wks.item_flags,
13521 						   key_type);
13522 		} else if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_GRE_OPTION) {
13523 			flow_dv_translate_item_gre_option(key,
13524 							  wks.tunnel_item,
13525 							  wks.gre_item,
13526 							  wks.item_flags,
13527 							  key_type);
13528 		} else if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_NVGRE) {
13529 			flow_dv_translate_item_nvgre(key,
13530 						     wks.tunnel_item,
13531 						     wks.item_flags,
13532 						     key_type);
13533 		} else {
13534 			MLX5_ASSERT(false);
13535 		}
13536 	}
13537 
13538 	if (match_criteria)
13539 		*match_criteria = flow_dv_matcher_enable(key);
13540 	if (item_flags)
13541 		*item_flags = wks.item_flags;
13542 exit:
13543 	mlx5_flow_pop_thread_workspace();
13544 	return ret;
13545 }
13546 
13547 /**
13548  * Fill the SW steering flow with DV spec.
13549  *
13550  * @param[in] dev
13551  *   Pointer to rte_eth_dev structure.
13552  * @param[in, out] dev_flow
13553  *   Pointer to the sub flow.
13554  * @param[in] attr
13555  *   Pointer to the flow attributes.
13556  * @param[in] items
13557  *   Pointer to the list of items.
13558  * @param[in, out] matcher
13559  *   Pointer to the flow matcher.
13560  * @param[out] error
13561  *   Pointer to the error structure.
13562  *
13563  * @return
13564  *   0 on success, a negative errno value otherwise and rte_errno is set.
13565  */
13566 static int
13567 flow_dv_translate_items_sws(struct rte_eth_dev *dev,
13568 			    struct mlx5_flow *dev_flow,
13569 			    const struct rte_flow_attr *attr,
13570 			    const struct rte_flow_item *items,
13571 			    struct mlx5_flow_dv_matcher *matcher,
13572 			    struct rte_flow_error *error)
13573 {
13574 	struct mlx5_priv *priv = dev->data->dev_private;
13575 	void *match_mask = matcher->mask.buf;
13576 	void *match_value = dev_flow->dv.value.buf;
13577 	struct mlx5_dv_matcher_workspace wks = {
13578 		.action_flags = dev_flow->act_flags,
13579 		.item_flags = 0,
13580 		.external = dev_flow->external,
13581 		.next_protocol = 0xff,
13582 		.group = dev_flow->dv.group,
13583 		.attr = attr,
13584 		.rss_desc = &((struct mlx5_flow_workspace *)
13585 			     mlx5_flow_get_thread_workspace())->rss_desc,
13586 	};
13587 	struct mlx5_dv_matcher_workspace wks_m = wks;
13588 	int item_type;
13589 	int ret = 0;
13590 	int tunnel;
13591 
13592 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
13593 		if (!mlx5_flow_os_item_supported(items->type))
13594 			return rte_flow_error_set(error, ENOTSUP,
13595 						  RTE_FLOW_ERROR_TYPE_ITEM,
13596 						  NULL, "item not supported");
13597 		tunnel = !!(wks.item_flags & MLX5_FLOW_LAYER_TUNNEL);
13598 		item_type = items->type;
13599 		switch (item_type) {
13600 		case RTE_FLOW_ITEM_TYPE_CONNTRACK:
13601 			flow_dv_translate_item_aso_ct(dev, match_mask,
13602 						      match_value, items);
13603 			break;
13604 		case RTE_FLOW_ITEM_TYPE_FLEX:
13605 			flow_dv_translate_item_flex(dev, match_mask,
13606 						    match_value, items,
13607 						    dev_flow, tunnel != 0);
13608 			wks.last_item = tunnel ? MLX5_FLOW_ITEM_INNER_FLEX :
13609 						 MLX5_FLOW_ITEM_OUTER_FLEX;
13610 			break;
13611 		case MLX5_RTE_FLOW_ITEM_TYPE_SQ:
13612 			flow_dv_translate_item_sq(match_value, items,
13613 						  MLX5_SET_MATCHER_SW_V);
13614 			flow_dv_translate_item_sq(match_mask, items,
13615 						  MLX5_SET_MATCHER_SW_M);
13616 			break;
13617 		default:
13618 			ret = flow_dv_translate_items(dev, items, &wks_m,
13619 				match_mask, MLX5_SET_MATCHER_SW_M, error);
13620 			if (ret)
13621 				return ret;
13622 			ret = flow_dv_translate_items(dev, items, &wks,
13623 				match_value, MLX5_SET_MATCHER_SW_V, error);
13624 			if (ret)
13625 				return ret;
13626 			break;
13627 		}
13628 		wks.item_flags |= wks.last_item;
13629 	}
13630 	/*
13631 	 * When E-Switch mode is enabled, we have two cases where we need to
13632 	 * set the source port manually.
13633 	 * The first one, is in case of NIC ingress steering rule, and the
13634 	 * second is E-Switch rule where no port_id item was found.
13635 	 * In both cases the source port is set according the current port
13636 	 * in use.
13637 	 */
13638 	if (!(wks.item_flags & MLX5_FLOW_ITEM_PORT_ID) &&
13639 	    !(wks.item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) &&
13640 	    !(wks.item_flags & MLX5_FLOW_ITEM_PORT_REPRESENTOR) &&
13641 	    priv->sh->esw_mode &&
13642 	    !attr->egress &&
13643 	    attr->group != MLX5_FLOW_MREG_CP_TABLE_GROUP) {
13644 		if (flow_dv_translate_item_port_id_all(dev, match_mask,
13645 						   match_value, NULL, attr))
13646 			return -rte_errno;
13647 	}
13648 	if (wks.item_flags & MLX5_FLOW_ITEM_INTEGRITY) {
13649 		flow_dv_translate_item_integrity_post(match_mask,
13650 						      wks_m.integrity_items,
13651 						      wks_m.item_flags,
13652 						      MLX5_SET_MATCHER_SW_M);
13653 		flow_dv_translate_item_integrity_post(match_value,
13654 						      wks.integrity_items,
13655 						      wks.item_flags,
13656 						      MLX5_SET_MATCHER_SW_V);
13657 	}
13658 	if (wks.item_flags & MLX5_FLOW_LAYER_VXLAN_GPE) {
13659 		flow_dv_translate_item_vxlan_gpe(match_mask,
13660 						 wks.tunnel_item,
13661 						 wks.item_flags,
13662 						 MLX5_SET_MATCHER_SW_M);
13663 		flow_dv_translate_item_vxlan_gpe(match_value,
13664 						 wks.tunnel_item,
13665 						 wks.item_flags,
13666 						 MLX5_SET_MATCHER_SW_V);
13667 	} else if (wks.item_flags & MLX5_FLOW_LAYER_GENEVE) {
13668 		flow_dv_translate_item_geneve(match_mask,
13669 					      wks.tunnel_item,
13670 					      wks.item_flags,
13671 					      MLX5_SET_MATCHER_SW_M);
13672 		flow_dv_translate_item_geneve(match_value,
13673 					      wks.tunnel_item,
13674 					      wks.item_flags,
13675 					      MLX5_SET_MATCHER_SW_V);
13676 	} else if (wks.item_flags & MLX5_FLOW_LAYER_GRE) {
13677 		if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_GRE) {
13678 			flow_dv_translate_item_gre(match_mask,
13679 						   wks.tunnel_item,
13680 						   wks.item_flags,
13681 						   MLX5_SET_MATCHER_SW_M);
13682 			flow_dv_translate_item_gre(match_value,
13683 						   wks.tunnel_item,
13684 						   wks.item_flags,
13685 						   MLX5_SET_MATCHER_SW_V);
13686 		} else if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_NVGRE) {
13687 			flow_dv_translate_item_nvgre(match_mask,
13688 						     wks.tunnel_item,
13689 						     wks.item_flags,
13690 						     MLX5_SET_MATCHER_SW_M);
13691 			flow_dv_translate_item_nvgre(match_value,
13692 						     wks.tunnel_item,
13693 						     wks.item_flags,
13694 						     MLX5_SET_MATCHER_SW_V);
13695 		} else if (wks.tunnel_item->type == RTE_FLOW_ITEM_TYPE_GRE_OPTION) {
13696 			flow_dv_translate_item_gre_option(match_mask,
13697 							  wks.tunnel_item,
13698 							  wks.gre_item,
13699 							  wks.item_flags,
13700 							  MLX5_SET_MATCHER_SW_M);
13701 			flow_dv_translate_item_gre_option(match_value,
13702 							  wks.tunnel_item,
13703 							  wks.gre_item,
13704 							  wks.item_flags,
13705 							  MLX5_SET_MATCHER_SW_V);
13706 		} else {
13707 			MLX5_ASSERT(false);
13708 		}
13709 	}
13710 	dev_flow->handle->vf_vlan.tag = wks.vlan_tag;
13711 	matcher->priority = wks.priority;
13712 #ifdef RTE_LIBRTE_MLX5_DEBUG
13713 	MLX5_ASSERT(!flow_dv_check_valid_spec(match_mask, match_value));
13714 #endif
13715 	/*
13716 	 * Layers may be already initialized from prefix flow if this dev_flow
13717 	 * is the suffix flow.
13718 	 */
13719 	dev_flow->handle->layers |= wks.item_flags;
13720 	dev_flow->flow->geneve_tlv_option = wks.geneve_tlv_option;
13721 	return 0;
13722 }
13723 
13724 /**
13725  * Fill the flow with DV spec, lock free
13726  * (mutex should be acquired by caller).
13727  *
13728  * @param[in] dev
13729  *   Pointer to rte_eth_dev structure.
13730  * @param[in, out] dev_flow
13731  *   Pointer to the sub flow.
13732  * @param[in] attr
13733  *   Pointer to the flow attributes.
13734  * @param[in] items
13735  *   Pointer to the list of items.
13736  * @param[in] actions
13737  *   Pointer to the list of actions.
13738  * @param[out] error
13739  *   Pointer to the error structure.
13740  *
13741  * @return
13742  *   0 on success, a negative errno value otherwise and rte_errno is set.
13743  */
13744 static int
13745 flow_dv_translate(struct rte_eth_dev *dev,
13746 		  struct mlx5_flow *dev_flow,
13747 		  const struct rte_flow_attr *attr,
13748 		  const struct rte_flow_item items[],
13749 		  const struct rte_flow_action actions[],
13750 		  struct rte_flow_error *error)
13751 {
13752 	struct mlx5_priv *priv = dev->data->dev_private;
13753 	struct mlx5_sh_config *dev_conf = &priv->sh->config;
13754 	struct rte_flow *flow = dev_flow->flow;
13755 	struct mlx5_flow_handle *handle = dev_flow->handle;
13756 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
13757 	struct mlx5_flow_rss_desc *rss_desc;
13758 	uint64_t action_flags = 0;
13759 	struct mlx5_flow_dv_matcher matcher = {
13760 		.mask = {
13761 			.size = sizeof(matcher.mask.buf),
13762 		},
13763 	};
13764 	int actions_n = 0;
13765 	bool actions_end = false;
13766 	union {
13767 		struct mlx5_flow_dv_modify_hdr_resource res;
13768 		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
13769 			    sizeof(struct mlx5_modification_cmd) *
13770 			    (MLX5_MAX_MODIFY_NUM + 1)];
13771 	} mhdr_dummy;
13772 	struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
13773 	const struct rte_flow_action_count *count = NULL;
13774 	const struct rte_flow_action_age *non_shared_age = NULL;
13775 	union flow_dv_attr flow_attr = { .attr = 0 };
13776 	uint32_t tag_be;
13777 	union mlx5_flow_tbl_key tbl_key;
13778 	uint32_t modify_action_position = UINT32_MAX;
13779 	struct rte_vlan_hdr vlan = { 0 };
13780 	struct mlx5_flow_dv_dest_array_resource mdest_res;
13781 	struct mlx5_flow_dv_sample_resource sample_res;
13782 	void *sample_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
13783 	const struct rte_flow_action_sample *sample = NULL;
13784 	struct mlx5_flow_sub_actions_list *sample_act;
13785 	uint32_t sample_act_pos = UINT32_MAX;
13786 	uint32_t age_act_pos = UINT32_MAX;
13787 	uint32_t num_of_dest = 0;
13788 	int tmp_actions_n = 0;
13789 	uint32_t table;
13790 	int ret = 0;
13791 	const struct mlx5_flow_tunnel *tunnel = NULL;
13792 	struct flow_grp_info grp_info = {
13793 		.external = !!dev_flow->external,
13794 		.transfer = !!attr->transfer,
13795 		.fdb_def_rule = !!priv->fdb_def_rule,
13796 		.skip_scale = dev_flow->skip_scale &
13797 			(1 << MLX5_SCALE_FLOW_GROUP_BIT),
13798 		.std_tbl_fix = true,
13799 	};
13800 
13801 	if (!wks)
13802 		return rte_flow_error_set(error, ENOMEM,
13803 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
13804 					  NULL,
13805 					  "failed to push flow workspace");
13806 	rss_desc = &wks->rss_desc;
13807 	memset(&mdest_res, 0, sizeof(struct mlx5_flow_dv_dest_array_resource));
13808 	memset(&sample_res, 0, sizeof(struct mlx5_flow_dv_sample_resource));
13809 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
13810 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
13811 	/* update normal path action resource into last index of array */
13812 	sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1];
13813 	if (is_tunnel_offload_active(dev)) {
13814 		if (dev_flow->tunnel) {
13815 			RTE_VERIFY(dev_flow->tof_type ==
13816 				   MLX5_TUNNEL_OFFLOAD_MISS_RULE);
13817 			tunnel = dev_flow->tunnel;
13818 		} else {
13819 			tunnel = mlx5_get_tof(items, actions,
13820 					      &dev_flow->tof_type);
13821 			dev_flow->tunnel = tunnel;
13822 		}
13823 		grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
13824 					(dev, attr, tunnel, dev_flow->tof_type);
13825 	}
13826 	mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
13827 					   MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
13828 	ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table,
13829 				       &grp_info, error);
13830 	if (ret)
13831 		return ret;
13832 	dev_flow->dv.group = table;
13833 	if (attr->transfer)
13834 		mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
13835 	/* number of actions must be set to 0 in case of dirty stack. */
13836 	mhdr_res->actions_num = 0;
13837 	if (is_flow_tunnel_match_rule(dev_flow->tof_type)) {
13838 		/*
13839 		 * do not add decap action if match rule drops packet
13840 		 * HW rejects rules with decap & drop
13841 		 *
13842 		 * if tunnel match rule was inserted before matching tunnel set
13843 		 * rule flow table used in the match rule must be registered.
13844 		 * current implementation handles that in the
13845 		 * flow_dv_match_register() at the function end.
13846 		 */
13847 		bool add_decap = true;
13848 		const struct rte_flow_action *ptr = actions;
13849 
13850 		for (; ptr->type != RTE_FLOW_ACTION_TYPE_END; ptr++) {
13851 			if (ptr->type == RTE_FLOW_ACTION_TYPE_DROP) {
13852 				add_decap = false;
13853 				break;
13854 			}
13855 		}
13856 		if (add_decap) {
13857 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
13858 							   attr->transfer,
13859 							   error))
13860 				return -rte_errno;
13861 			dev_flow->dv.actions[actions_n++] =
13862 					dev_flow->dv.encap_decap->action;
13863 			action_flags |= MLX5_FLOW_ACTION_DECAP;
13864 		}
13865 	}
13866 	for (; !actions_end ; actions++) {
13867 		const struct rte_flow_action_queue *queue;
13868 		const struct rte_flow_action_rss *rss;
13869 		const struct rte_flow_action *action = actions;
13870 		const uint8_t *rss_key;
13871 		struct mlx5_flow_tbl_resource *tbl;
13872 		struct mlx5_aso_age_action *age_act;
13873 		struct mlx5_flow_counter *cnt_act;
13874 		uint32_t port_id = 0;
13875 		struct mlx5_flow_dv_port_id_action_resource port_id_resource;
13876 		int action_type = actions->type;
13877 		const struct rte_flow_action *found_action = NULL;
13878 		uint32_t jump_group = 0;
13879 		uint32_t owner_idx;
13880 		struct mlx5_aso_ct_action *ct;
13881 
13882 		if (!mlx5_flow_os_action_supported(action_type))
13883 			return rte_flow_error_set(error, ENOTSUP,
13884 						  RTE_FLOW_ERROR_TYPE_ACTION,
13885 						  actions,
13886 						  "action not supported");
13887 		switch (action_type) {
13888 		case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
13889 			action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
13890 			break;
13891 		case RTE_FLOW_ACTION_TYPE_VOID:
13892 			break;
13893 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
13894 		case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
13895 			if (flow_dv_translate_action_port_id(dev, action,
13896 							     &port_id, error))
13897 				return -rte_errno;
13898 			port_id_resource.port_id = port_id;
13899 			MLX5_ASSERT(!handle->rix_port_id_action);
13900 			if (flow_dv_port_id_action_resource_register
13901 			    (dev, &port_id_resource, dev_flow, error))
13902 				return -rte_errno;
13903 			dev_flow->dv.actions[actions_n++] =
13904 					dev_flow->dv.port_id_action->action;
13905 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
13906 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_PORT_ID;
13907 			sample_act->action_flags |= MLX5_FLOW_ACTION_PORT_ID;
13908 			num_of_dest++;
13909 			break;
13910 		case RTE_FLOW_ACTION_TYPE_FLAG:
13911 			action_flags |= MLX5_FLOW_ACTION_FLAG;
13912 			wks->mark = 1;
13913 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
13914 				struct rte_flow_action_mark mark = {
13915 					.id = MLX5_FLOW_MARK_DEFAULT,
13916 				};
13917 
13918 				if (flow_dv_convert_action_mark(dev, &mark,
13919 								mhdr_res,
13920 								error))
13921 					return -rte_errno;
13922 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
13923 				break;
13924 			}
13925 			tag_be = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
13926 			/*
13927 			 * Only one FLAG or MARK is supported per device flow
13928 			 * right now. So the pointer to the tag resource must be
13929 			 * zero before the register process.
13930 			 */
13931 			MLX5_ASSERT(!handle->dvh.rix_tag);
13932 			if (flow_dv_tag_resource_register(dev, tag_be,
13933 							  dev_flow, error))
13934 				return -rte_errno;
13935 			MLX5_ASSERT(dev_flow->dv.tag_resource);
13936 			dev_flow->dv.actions[actions_n++] =
13937 					dev_flow->dv.tag_resource->action;
13938 			break;
13939 		case RTE_FLOW_ACTION_TYPE_MARK:
13940 			action_flags |= MLX5_FLOW_ACTION_MARK;
13941 			wks->mark = 1;
13942 			if (dev_conf->dv_xmeta_en != MLX5_XMETA_MODE_LEGACY) {
13943 				const struct rte_flow_action_mark *mark =
13944 					(const struct rte_flow_action_mark *)
13945 						actions->conf;
13946 
13947 				if (flow_dv_convert_action_mark(dev, mark,
13948 								mhdr_res,
13949 								error))
13950 					return -rte_errno;
13951 				action_flags |= MLX5_FLOW_ACTION_MARK_EXT;
13952 				break;
13953 			}
13954 			/* Fall-through */
13955 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
13956 			/* Legacy (non-extensive) MARK action. */
13957 			tag_be = mlx5_flow_mark_set
13958 			      (((const struct rte_flow_action_mark *)
13959 			       (actions->conf))->id);
13960 			MLX5_ASSERT(!handle->dvh.rix_tag);
13961 			if (flow_dv_tag_resource_register(dev, tag_be,
13962 							  dev_flow, error))
13963 				return -rte_errno;
13964 			MLX5_ASSERT(dev_flow->dv.tag_resource);
13965 			dev_flow->dv.actions[actions_n++] =
13966 					dev_flow->dv.tag_resource->action;
13967 			break;
13968 		case RTE_FLOW_ACTION_TYPE_SET_META:
13969 			if (flow_dv_convert_action_set_meta
13970 				(dev, mhdr_res, attr,
13971 				 (const struct rte_flow_action_set_meta *)
13972 				  actions->conf, error))
13973 				return -rte_errno;
13974 			action_flags |= MLX5_FLOW_ACTION_SET_META;
13975 			break;
13976 		case RTE_FLOW_ACTION_TYPE_SET_TAG:
13977 			if (flow_dv_convert_action_set_tag
13978 				(dev, mhdr_res,
13979 				 (const struct rte_flow_action_set_tag *)
13980 				  actions->conf, error))
13981 				return -rte_errno;
13982 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
13983 			break;
13984 		case RTE_FLOW_ACTION_TYPE_DROP:
13985 			action_flags |= MLX5_FLOW_ACTION_DROP;
13986 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_DROP;
13987 			break;
13988 		case RTE_FLOW_ACTION_TYPE_QUEUE:
13989 			queue = actions->conf;
13990 			rss_desc->queue_num = 1;
13991 			rss_desc->queue[0] = queue->index;
13992 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
13993 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_QUEUE;
13994 			sample_act->action_flags |= MLX5_FLOW_ACTION_QUEUE;
13995 			num_of_dest++;
13996 			break;
13997 		case RTE_FLOW_ACTION_TYPE_RSS:
13998 			rss = actions->conf;
13999 			memcpy(rss_desc->queue, rss->queue,
14000 			       rss->queue_num * sizeof(uint16_t));
14001 			rss_desc->queue_num = rss->queue_num;
14002 			/* NULL RSS key indicates default RSS key. */
14003 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
14004 			memcpy(rss_desc->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
14005 			/*
14006 			 * rss->level and rss.types should be set in advance
14007 			 * when expanding items for RSS.
14008 			 */
14009 			action_flags |= MLX5_FLOW_ACTION_RSS;
14010 			dev_flow->handle->fate_action = rss_desc->shared_rss ?
14011 				MLX5_FLOW_FATE_SHARED_RSS :
14012 				MLX5_FLOW_FATE_QUEUE;
14013 			break;
14014 		case MLX5_RTE_FLOW_ACTION_TYPE_AGE:
14015 			owner_idx = (uint32_t)(uintptr_t)action->conf;
14016 			age_act = flow_aso_age_get_by_idx(dev, owner_idx);
14017 			if (flow->age == 0) {
14018 				flow->age = owner_idx;
14019 				__atomic_fetch_add(&age_act->refcnt, 1,
14020 						   __ATOMIC_RELAXED);
14021 			}
14022 			age_act_pos = actions_n++;
14023 			action_flags |= MLX5_FLOW_ACTION_AGE;
14024 			break;
14025 		case RTE_FLOW_ACTION_TYPE_SEND_TO_KERNEL:
14026 			dev_flow->dv.actions[actions_n] =
14027 				flow_dv_translate_action_send_to_kernel(dev,
14028 							error);
14029 			if (!dev_flow->dv.actions[actions_n])
14030 				return -rte_errno;
14031 			actions_n++;
14032 			action_flags |= MLX5_FLOW_ACTION_SEND_TO_KERNEL;
14033 			dev_flow->handle->fate_action =
14034 					MLX5_FLOW_FATE_SEND_TO_KERNEL;
14035 			break;
14036 		case RTE_FLOW_ACTION_TYPE_AGE:
14037 			non_shared_age = action->conf;
14038 			age_act_pos = actions_n++;
14039 			action_flags |= MLX5_FLOW_ACTION_AGE;
14040 			break;
14041 		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
14042 			owner_idx = (uint32_t)(uintptr_t)action->conf;
14043 			cnt_act = flow_dv_counter_get_by_idx(dev, owner_idx,
14044 							     NULL);
14045 			MLX5_ASSERT(cnt_act != NULL);
14046 			/**
14047 			 * When creating meter drop flow in drop table, the
14048 			 * counter should not overwrite the rte flow counter.
14049 			 */
14050 			if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
14051 			    dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP) {
14052 				dev_flow->dv.actions[actions_n++] =
14053 							cnt_act->action;
14054 			} else {
14055 				if (flow->counter == 0) {
14056 					flow->counter = owner_idx;
14057 					__atomic_fetch_add
14058 						(&cnt_act->shared_info.refcnt,
14059 						 1, __ATOMIC_RELAXED);
14060 				}
14061 				/* Save information first, will apply later. */
14062 				action_flags |= MLX5_FLOW_ACTION_COUNT;
14063 			}
14064 			break;
14065 		case RTE_FLOW_ACTION_TYPE_COUNT:
14066 			if (!priv->sh->cdev->config.devx) {
14067 				return rte_flow_error_set
14068 					      (error, ENOTSUP,
14069 					       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14070 					       NULL,
14071 					       "count action not supported");
14072 			}
14073 			/* Save information first, will apply later. */
14074 			count = action->conf;
14075 			action_flags |= MLX5_FLOW_ACTION_COUNT;
14076 			break;
14077 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
14078 			dev_flow->dv.actions[actions_n++] =
14079 						priv->sh->pop_vlan_action;
14080 			action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
14081 			break;
14082 		case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
14083 			if (!(action_flags &
14084 			      MLX5_FLOW_ACTION_OF_SET_VLAN_VID))
14085 				flow_dev_get_vlan_info_from_items(items, &vlan);
14086 			vlan.eth_proto = rte_be_to_cpu_16
14087 			     ((((const struct rte_flow_action_of_push_vlan *)
14088 						   actions->conf)->ethertype));
14089 			found_action = mlx5_flow_find_action
14090 					(actions + 1,
14091 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID);
14092 			if (found_action)
14093 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
14094 			found_action = mlx5_flow_find_action
14095 					(actions + 1,
14096 					 RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP);
14097 			if (found_action)
14098 				mlx5_update_vlan_vid_pcp(found_action, &vlan);
14099 			if (flow_dv_create_action_push_vlan
14100 					    (dev, attr, &vlan, dev_flow, error))
14101 				return -rte_errno;
14102 			dev_flow->dv.actions[actions_n++] =
14103 					dev_flow->dv.push_vlan_res->action;
14104 			action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
14105 			break;
14106 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
14107 			/* of_vlan_push action handled this action */
14108 			MLX5_ASSERT(action_flags &
14109 				    MLX5_FLOW_ACTION_OF_PUSH_VLAN);
14110 			break;
14111 		case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
14112 			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
14113 				break;
14114 			flow_dev_get_vlan_info_from_items(items, &vlan);
14115 			mlx5_update_vlan_vid_pcp(actions, &vlan);
14116 			/* If no VLAN push - this is a modify header action */
14117 			if (flow_dv_convert_action_modify_vlan_vid
14118 						(mhdr_res, actions, error))
14119 				return -rte_errno;
14120 			action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
14121 			break;
14122 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
14123 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
14124 			if (flow_dv_create_action_l2_encap(dev, actions,
14125 							   dev_flow,
14126 							   attr->transfer,
14127 							   error))
14128 				return -rte_errno;
14129 			dev_flow->dv.actions[actions_n++] =
14130 					dev_flow->dv.encap_decap->action;
14131 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
14132 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
14133 				sample_act->action_flags |=
14134 							MLX5_FLOW_ACTION_ENCAP;
14135 			break;
14136 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
14137 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
14138 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
14139 							   attr->transfer,
14140 							   error))
14141 				return -rte_errno;
14142 			dev_flow->dv.actions[actions_n++] =
14143 					dev_flow->dv.encap_decap->action;
14144 			action_flags |= MLX5_FLOW_ACTION_DECAP;
14145 			break;
14146 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
14147 			/* Handle encap with preceding decap. */
14148 			if (action_flags & MLX5_FLOW_ACTION_DECAP) {
14149 				if (flow_dv_create_action_raw_encap
14150 					(dev, actions, dev_flow, attr, error))
14151 					return -rte_errno;
14152 				dev_flow->dv.actions[actions_n++] =
14153 					dev_flow->dv.encap_decap->action;
14154 			} else {
14155 				/* Handle encap without preceding decap. */
14156 				if (flow_dv_create_action_l2_encap
14157 				    (dev, actions, dev_flow, attr->transfer,
14158 				     error))
14159 					return -rte_errno;
14160 				dev_flow->dv.actions[actions_n++] =
14161 					dev_flow->dv.encap_decap->action;
14162 			}
14163 			action_flags |= MLX5_FLOW_ACTION_ENCAP;
14164 			if (action_flags & MLX5_FLOW_ACTION_SAMPLE)
14165 				sample_act->action_flags |=
14166 							MLX5_FLOW_ACTION_ENCAP;
14167 			break;
14168 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
14169 			while ((++action)->type == RTE_FLOW_ACTION_TYPE_VOID)
14170 				;
14171 			if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
14172 				if (flow_dv_create_action_l2_decap
14173 				    (dev, dev_flow, attr->transfer, error))
14174 					return -rte_errno;
14175 				dev_flow->dv.actions[actions_n++] =
14176 					dev_flow->dv.encap_decap->action;
14177 			}
14178 			/* If decap is followed by encap, handle it at encap. */
14179 			action_flags |= MLX5_FLOW_ACTION_DECAP;
14180 			break;
14181 		case MLX5_RTE_FLOW_ACTION_TYPE_JUMP:
14182 			dev_flow->dv.actions[actions_n++] =
14183 				(void *)(uintptr_t)action->conf;
14184 			action_flags |= MLX5_FLOW_ACTION_JUMP;
14185 			break;
14186 		case RTE_FLOW_ACTION_TYPE_JUMP:
14187 			jump_group = ((const struct rte_flow_action_jump *)
14188 							action->conf)->group;
14189 			grp_info.std_tbl_fix = 0;
14190 			if (dev_flow->skip_scale &
14191 				(1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT))
14192 				grp_info.skip_scale = 1;
14193 			else
14194 				grp_info.skip_scale = 0;
14195 			ret = mlx5_flow_group_to_table(dev, tunnel,
14196 						       jump_group,
14197 						       &table,
14198 						       &grp_info, error);
14199 			if (ret)
14200 				return ret;
14201 			tbl = flow_dv_tbl_resource_get(dev, table, attr->egress,
14202 						       attr->transfer,
14203 						       !!dev_flow->external,
14204 						       tunnel, jump_group, 0,
14205 						       0, error);
14206 			if (!tbl)
14207 				return rte_flow_error_set
14208 						(error, errno,
14209 						 RTE_FLOW_ERROR_TYPE_ACTION,
14210 						 NULL,
14211 						 "cannot create jump action.");
14212 			if (flow_dv_jump_tbl_resource_register
14213 			    (dev, tbl, dev_flow, error)) {
14214 				flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
14215 				return rte_flow_error_set
14216 						(error, errno,
14217 						 RTE_FLOW_ERROR_TYPE_ACTION,
14218 						 NULL,
14219 						 "cannot create jump action.");
14220 			}
14221 			dev_flow->dv.actions[actions_n++] =
14222 					dev_flow->dv.jump->action;
14223 			action_flags |= MLX5_FLOW_ACTION_JUMP;
14224 			dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP;
14225 			sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP;
14226 			num_of_dest++;
14227 			break;
14228 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
14229 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
14230 			if (flow_dv_convert_action_modify_mac
14231 					(mhdr_res, actions, error))
14232 				return -rte_errno;
14233 			action_flags |= actions->type ==
14234 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
14235 					MLX5_FLOW_ACTION_SET_MAC_SRC :
14236 					MLX5_FLOW_ACTION_SET_MAC_DST;
14237 			break;
14238 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
14239 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
14240 			if (flow_dv_convert_action_modify_ipv4
14241 					(mhdr_res, actions, error))
14242 				return -rte_errno;
14243 			action_flags |= actions->type ==
14244 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
14245 					MLX5_FLOW_ACTION_SET_IPV4_SRC :
14246 					MLX5_FLOW_ACTION_SET_IPV4_DST;
14247 			break;
14248 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
14249 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
14250 			if (flow_dv_convert_action_modify_ipv6
14251 					(mhdr_res, actions, error))
14252 				return -rte_errno;
14253 			action_flags |= actions->type ==
14254 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
14255 					MLX5_FLOW_ACTION_SET_IPV6_SRC :
14256 					MLX5_FLOW_ACTION_SET_IPV6_DST;
14257 			break;
14258 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
14259 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
14260 			if (flow_dv_convert_action_modify_tp
14261 					(mhdr_res, actions, items,
14262 					 &flow_attr, dev_flow, !!(action_flags &
14263 					 MLX5_FLOW_ACTION_DECAP), error))
14264 				return -rte_errno;
14265 			action_flags |= actions->type ==
14266 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
14267 					MLX5_FLOW_ACTION_SET_TP_SRC :
14268 					MLX5_FLOW_ACTION_SET_TP_DST;
14269 			break;
14270 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
14271 			if (flow_dv_convert_action_modify_dec_ttl
14272 					(mhdr_res, items, &flow_attr, dev_flow,
14273 					 !!(action_flags &
14274 					 MLX5_FLOW_ACTION_DECAP), error))
14275 				return -rte_errno;
14276 			action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
14277 			break;
14278 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
14279 			if (flow_dv_convert_action_modify_ttl
14280 					(mhdr_res, actions, items, &flow_attr,
14281 					 dev_flow, !!(action_flags &
14282 					 MLX5_FLOW_ACTION_DECAP), error))
14283 				return -rte_errno;
14284 			action_flags |= MLX5_FLOW_ACTION_SET_TTL;
14285 			break;
14286 		case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
14287 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
14288 			if (flow_dv_convert_action_modify_tcp_seq
14289 					(mhdr_res, actions, error))
14290 				return -rte_errno;
14291 			action_flags |= actions->type ==
14292 					RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
14293 					MLX5_FLOW_ACTION_INC_TCP_SEQ :
14294 					MLX5_FLOW_ACTION_DEC_TCP_SEQ;
14295 			break;
14296 
14297 		case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
14298 		case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
14299 			if (flow_dv_convert_action_modify_tcp_ack
14300 					(mhdr_res, actions, error))
14301 				return -rte_errno;
14302 			action_flags |= actions->type ==
14303 					RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
14304 					MLX5_FLOW_ACTION_INC_TCP_ACK :
14305 					MLX5_FLOW_ACTION_DEC_TCP_ACK;
14306 			break;
14307 		case MLX5_RTE_FLOW_ACTION_TYPE_TAG:
14308 			if (flow_dv_convert_action_set_reg
14309 					(mhdr_res, actions, error))
14310 				return -rte_errno;
14311 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
14312 			break;
14313 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
14314 			if (flow_dv_convert_action_copy_mreg
14315 					(dev, mhdr_res, actions, error))
14316 				return -rte_errno;
14317 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
14318 			break;
14319 		case MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS:
14320 			action_flags |= MLX5_FLOW_ACTION_DEFAULT_MISS;
14321 			dev_flow->handle->fate_action =
14322 					MLX5_FLOW_FATE_DEFAULT_MISS;
14323 			break;
14324 		case RTE_FLOW_ACTION_TYPE_METER:
14325 			if (!wks->fm)
14326 				return rte_flow_error_set(error, rte_errno,
14327 					RTE_FLOW_ERROR_TYPE_ACTION,
14328 					NULL, "Failed to get meter in flow.");
14329 			/* Set the meter action. */
14330 			dev_flow->dv.actions[actions_n++] =
14331 				wks->fm->meter_action_g;
14332 			action_flags |= MLX5_FLOW_ACTION_METER;
14333 			break;
14334 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
14335 			if (flow_dv_convert_action_modify_ipv4_dscp(mhdr_res,
14336 							      actions, error))
14337 				return -rte_errno;
14338 			action_flags |= MLX5_FLOW_ACTION_SET_IPV4_DSCP;
14339 			break;
14340 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
14341 			if (flow_dv_convert_action_modify_ipv6_dscp(mhdr_res,
14342 							      actions, error))
14343 				return -rte_errno;
14344 			action_flags |= MLX5_FLOW_ACTION_SET_IPV6_DSCP;
14345 			break;
14346 		case RTE_FLOW_ACTION_TYPE_SAMPLE:
14347 			sample_act_pos = actions_n;
14348 			sample = (const struct rte_flow_action_sample *)
14349 				 action->conf;
14350 			actions_n++;
14351 			action_flags |= MLX5_FLOW_ACTION_SAMPLE;
14352 			/* put encap action into group if work with port id */
14353 			if ((action_flags & MLX5_FLOW_ACTION_ENCAP) &&
14354 			    (action_flags & MLX5_FLOW_ACTION_PORT_ID))
14355 				sample_act->action_flags |=
14356 							MLX5_FLOW_ACTION_ENCAP;
14357 			break;
14358 		case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
14359 			if (flow_dv_convert_action_modify_field
14360 					(dev, mhdr_res, actions, attr, error))
14361 				return -rte_errno;
14362 			action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
14363 			break;
14364 		case RTE_FLOW_ACTION_TYPE_CONNTRACK:
14365 			owner_idx = (uint32_t)(uintptr_t)action->conf;
14366 			ct = flow_aso_ct_get_by_idx(dev, owner_idx);
14367 			if (!ct)
14368 				return rte_flow_error_set(error, EINVAL,
14369 						RTE_FLOW_ERROR_TYPE_ACTION,
14370 						NULL,
14371 						"Failed to get CT object.");
14372 			if (mlx5_aso_ct_available(priv->sh, MLX5_HW_INV_QUEUE, ct))
14373 				return rte_flow_error_set(error, rte_errno,
14374 						RTE_FLOW_ERROR_TYPE_ACTION,
14375 						NULL,
14376 						"CT is unavailable.");
14377 			if (ct->is_original)
14378 				dev_flow->dv.actions[actions_n] =
14379 							ct->dr_action_orig;
14380 			else
14381 				dev_flow->dv.actions[actions_n] =
14382 							ct->dr_action_rply;
14383 			if (flow->ct == 0) {
14384 				flow->indirect_type =
14385 						MLX5_INDIRECT_ACTION_TYPE_CT;
14386 				flow->ct = owner_idx;
14387 				__atomic_fetch_add(&ct->refcnt, 1,
14388 						   __ATOMIC_RELAXED);
14389 			}
14390 			actions_n++;
14391 			action_flags |= MLX5_FLOW_ACTION_CT;
14392 			break;
14393 		case RTE_FLOW_ACTION_TYPE_END:
14394 			actions_end = true;
14395 			if (mhdr_res->actions_num) {
14396 				/* create modify action if needed. */
14397 				if (flow_dv_modify_hdr_resource_register
14398 					(dev, mhdr_res, dev_flow, error))
14399 					return -rte_errno;
14400 				dev_flow->dv.actions[modify_action_position] =
14401 					handle->dvh.modify_hdr->action;
14402 			}
14403 			/*
14404 			 * Handle AGE and COUNT action by single HW counter
14405 			 * when they are not shared.
14406 			 */
14407 			if (action_flags & MLX5_FLOW_ACTION_AGE) {
14408 				if ((non_shared_age && count) ||
14409 				    !flow_hit_aso_supported(priv, !dev_flow->dv.group)) {
14410 					/* Creates age by counters. */
14411 					cnt_act = flow_dv_prepare_counter
14412 								(dev, dev_flow,
14413 								 flow, count,
14414 								 non_shared_age,
14415 								 error);
14416 					if (!cnt_act)
14417 						return -rte_errno;
14418 					dev_flow->dv.actions[age_act_pos] =
14419 								cnt_act->action;
14420 					break;
14421 				}
14422 				if (!flow->age && non_shared_age) {
14423 					flow->age = flow_dv_aso_age_alloc
14424 								(dev, error);
14425 					if (!flow->age)
14426 						return -rte_errno;
14427 					flow_dv_aso_age_params_init
14428 						    (dev, flow->age,
14429 						     non_shared_age->context ?
14430 						     non_shared_age->context :
14431 						     (void *)(uintptr_t)
14432 						     (dev_flow->flow_idx),
14433 						     non_shared_age->timeout);
14434 				}
14435 				age_act = flow_aso_age_get_by_idx(dev,
14436 								  flow->age);
14437 				dev_flow->dv.actions[age_act_pos] =
14438 							     age_act->dr_action;
14439 			}
14440 			if (action_flags & MLX5_FLOW_ACTION_COUNT) {
14441 				/*
14442 				 * Create one count action, to be used
14443 				 * by all sub-flows.
14444 				 */
14445 				cnt_act = flow_dv_prepare_counter(dev, dev_flow,
14446 								  flow, count,
14447 								  NULL, error);
14448 				if (!cnt_act)
14449 					return -rte_errno;
14450 				dev_flow->dv.actions[actions_n++] =
14451 								cnt_act->action;
14452 			}
14453 		default:
14454 			break;
14455 		}
14456 		if (mhdr_res->actions_num &&
14457 		    modify_action_position == UINT32_MAX)
14458 			modify_action_position = actions_n++;
14459 	}
14460 	dev_flow->act_flags = action_flags;
14461 	ret = flow_dv_translate_items_sws(dev, dev_flow, attr, items, &matcher,
14462 				      error);
14463 	if (ret)
14464 		return -rte_errno;
14465 	if (action_flags & MLX5_FLOW_ACTION_RSS)
14466 		flow_dv_hashfields_set(dev_flow->handle->layers,
14467 				       rss_desc,
14468 				       &dev_flow->hash_fields);
14469 	/* If has RSS action in the sample action, the Sample/Mirror resource
14470 	 * should be registered after the hash filed be update.
14471 	 */
14472 	if (action_flags & MLX5_FLOW_ACTION_SAMPLE) {
14473 		ret = flow_dv_translate_action_sample(dev,
14474 						      sample,
14475 						      dev_flow, attr,
14476 						      &num_of_dest,
14477 						      sample_actions,
14478 						      &sample_res,
14479 						      error);
14480 		if (ret < 0)
14481 			return ret;
14482 		ret = flow_dv_create_action_sample(dev,
14483 						   dev_flow,
14484 						   num_of_dest,
14485 						   &sample_res,
14486 						   &mdest_res,
14487 						   sample_actions,
14488 						   action_flags,
14489 						   error);
14490 		if (ret < 0)
14491 			return rte_flow_error_set
14492 						(error, rte_errno,
14493 						RTE_FLOW_ERROR_TYPE_ACTION,
14494 						NULL,
14495 						"cannot create sample action");
14496 		if (num_of_dest > 1) {
14497 			dev_flow->dv.actions[sample_act_pos] =
14498 			dev_flow->dv.dest_array_res->action;
14499 		} else {
14500 			dev_flow->dv.actions[sample_act_pos] =
14501 			dev_flow->dv.sample_res->verbs_action;
14502 		}
14503 	}
14504 	/*
14505 	 * For multiple destination (sample action with ratio=1), the encap
14506 	 * action and port id action will be combined into group action.
14507 	 * So need remove the original these actions in the flow and only
14508 	 * use the sample action instead of.
14509 	 */
14510 	if (num_of_dest > 1 &&
14511 	    (sample_act->dr_port_id_action || sample_act->dr_jump_action)) {
14512 		int i;
14513 		void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
14514 
14515 		for (i = 0; i < actions_n; i++) {
14516 			if ((sample_act->dr_encap_action &&
14517 				sample_act->dr_encap_action ==
14518 				dev_flow->dv.actions[i]) ||
14519 				(sample_act->dr_port_id_action &&
14520 				sample_act->dr_port_id_action ==
14521 				dev_flow->dv.actions[i]) ||
14522 				(sample_act->dr_jump_action &&
14523 				sample_act->dr_jump_action ==
14524 				dev_flow->dv.actions[i]))
14525 				continue;
14526 			temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];
14527 		}
14528 		memcpy((void *)dev_flow->dv.actions,
14529 				(void *)temp_actions,
14530 				tmp_actions_n * sizeof(void *));
14531 		actions_n = tmp_actions_n;
14532 	}
14533 	dev_flow->dv.actions_n = actions_n;
14534 	if (wks->skip_matcher_reg)
14535 		return 0;
14536 	/* Register matcher. */
14537 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
14538 				    matcher.mask.size);
14539 	matcher.priority = mlx5_get_matcher_priority(dev, attr,
14540 						     matcher.priority,
14541 						     dev_flow->external);
14542 	/**
14543 	 * When creating meter drop flow in drop table, using original
14544 	 * 5-tuple match, the matcher priority should be lower than
14545 	 * mtr_id matcher.
14546 	 */
14547 	if (attr->group == MLX5_FLOW_TABLE_LEVEL_METER &&
14548 	    dev_flow->dv.table_id == MLX5_MTR_TABLE_ID_DROP &&
14549 	    matcher.priority <= MLX5_REG_BITS)
14550 		matcher.priority += MLX5_REG_BITS;
14551 	/* reserved field no needs to be set to 0 here. */
14552 	tbl_key.is_fdb = attr->transfer;
14553 	tbl_key.is_egress = attr->egress;
14554 	tbl_key.level = dev_flow->dv.group;
14555 	tbl_key.id = dev_flow->dv.table_id;
14556 	if (flow_dv_matcher_register(dev, &matcher, &tbl_key, dev_flow,
14557 				     tunnel, attr->group, error))
14558 		return -rte_errno;
14559 	return 0;
14560 }
14561 
14562 /**
14563  * Set hash RX queue by hash fields (see enum ibv_rx_hash_fields)
14564  * and tunnel.
14565  *
14566  * @param[in, out] action
14567  *   Shred RSS action holding hash RX queue objects.
14568  * @param[in] hash_fields
14569  *   Defines combination of packet fields to participate in RX hash.
14570  * @param[in] tunnel
14571  *   Tunnel type
14572  * @param[in] hrxq_idx
14573  *   Hash RX queue index to set.
14574  *
14575  * @return
14576  *   0 on success, otherwise negative errno value.
14577  */
14578 static int
14579 __flow_dv_action_rss_hrxq_set(struct mlx5_shared_action_rss *action,
14580 			      const uint64_t hash_fields,
14581 			      uint32_t hrxq_idx)
14582 {
14583 	uint32_t *hrxqs = action->hrxq;
14584 
14585 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
14586 	case MLX5_RSS_HASH_IPV4:
14587 		/* fall-through. */
14588 	case MLX5_RSS_HASH_IPV4_DST_ONLY:
14589 		/* fall-through. */
14590 	case MLX5_RSS_HASH_IPV4_SRC_ONLY:
14591 		hrxqs[0] = hrxq_idx;
14592 		return 0;
14593 	case MLX5_RSS_HASH_IPV4_TCP:
14594 		/* fall-through. */
14595 	case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY:
14596 		/* fall-through. */
14597 	case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY:
14598 		hrxqs[1] = hrxq_idx;
14599 		return 0;
14600 	case MLX5_RSS_HASH_IPV4_UDP:
14601 		/* fall-through. */
14602 	case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
14603 		/* fall-through. */
14604 	case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
14605 		hrxqs[2] = hrxq_idx;
14606 		return 0;
14607 	case MLX5_RSS_HASH_IPV6:
14608 		/* fall-through. */
14609 	case MLX5_RSS_HASH_IPV6_DST_ONLY:
14610 		/* fall-through. */
14611 	case MLX5_RSS_HASH_IPV6_SRC_ONLY:
14612 		hrxqs[3] = hrxq_idx;
14613 		return 0;
14614 	case MLX5_RSS_HASH_IPV6_TCP:
14615 		/* fall-through. */
14616 	case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
14617 		/* fall-through. */
14618 	case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
14619 		hrxqs[4] = hrxq_idx;
14620 		return 0;
14621 	case MLX5_RSS_HASH_IPV6_UDP:
14622 		/* fall-through. */
14623 	case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
14624 		/* fall-through. */
14625 	case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
14626 		hrxqs[5] = hrxq_idx;
14627 		return 0;
14628 	case MLX5_RSS_HASH_NONE:
14629 		hrxqs[6] = hrxq_idx;
14630 		return 0;
14631 	case MLX5_RSS_HASH_IPV4_ESP:
14632 		hrxqs[7] = hrxq_idx;
14633 		return 0;
14634 	case MLX5_RSS_HASH_IPV6_ESP:
14635 		hrxqs[8] = hrxq_idx;
14636 		return 0;
14637 	case MLX5_RSS_HASH_ESP_SPI:
14638 		hrxqs[9] = hrxq_idx;
14639 		return 0;
14640 	default:
14641 		return -1;
14642 	}
14643 }
14644 
14645 /**
14646  * Look up for hash RX queue by hash fields (see enum ibv_rx_hash_fields)
14647  * and tunnel.
14648  *
14649  * @param[in] dev
14650  *   Pointer to the Ethernet device structure.
14651  * @param[in] idx
14652  *   Shared RSS action ID holding hash RX queue objects.
14653  * @param[in] hash_fields
14654  *   Defines combination of packet fields to participate in RX hash.
14655  * @param[in] tunnel
14656  *   Tunnel type
14657  *
14658  * @return
14659  *   Valid hash RX queue index, otherwise 0.
14660  */
14661 uint32_t
14662 flow_dv_action_rss_hrxq_lookup(struct rte_eth_dev *dev, uint32_t idx,
14663 			       const uint64_t hash_fields)
14664 {
14665 	struct mlx5_priv *priv = dev->data->dev_private;
14666 	struct mlx5_shared_action_rss *shared_rss =
14667 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
14668 	const uint32_t *hrxqs = shared_rss->hrxq;
14669 
14670 	switch (hash_fields & ~IBV_RX_HASH_INNER) {
14671 	case MLX5_RSS_HASH_IPV4:
14672 		/* fall-through. */
14673 	case MLX5_RSS_HASH_IPV4_DST_ONLY:
14674 		/* fall-through. */
14675 	case MLX5_RSS_HASH_IPV4_SRC_ONLY:
14676 		return hrxqs[0];
14677 	case MLX5_RSS_HASH_IPV4_TCP:
14678 		/* fall-through. */
14679 	case MLX5_RSS_HASH_IPV4_TCP_DST_ONLY:
14680 		/* fall-through. */
14681 	case MLX5_RSS_HASH_IPV4_TCP_SRC_ONLY:
14682 		return hrxqs[1];
14683 	case MLX5_RSS_HASH_IPV4_UDP:
14684 		/* fall-through. */
14685 	case MLX5_RSS_HASH_IPV4_UDP_DST_ONLY:
14686 		/* fall-through. */
14687 	case MLX5_RSS_HASH_IPV4_UDP_SRC_ONLY:
14688 		return hrxqs[2];
14689 	case MLX5_RSS_HASH_IPV6:
14690 		/* fall-through. */
14691 	case MLX5_RSS_HASH_IPV6_DST_ONLY:
14692 		/* fall-through. */
14693 	case MLX5_RSS_HASH_IPV6_SRC_ONLY:
14694 		return hrxqs[3];
14695 	case MLX5_RSS_HASH_IPV6_TCP:
14696 		/* fall-through. */
14697 	case MLX5_RSS_HASH_IPV6_TCP_DST_ONLY:
14698 		/* fall-through. */
14699 	case MLX5_RSS_HASH_IPV6_TCP_SRC_ONLY:
14700 		return hrxqs[4];
14701 	case MLX5_RSS_HASH_IPV6_UDP:
14702 		/* fall-through. */
14703 	case MLX5_RSS_HASH_IPV6_UDP_DST_ONLY:
14704 		/* fall-through. */
14705 	case MLX5_RSS_HASH_IPV6_UDP_SRC_ONLY:
14706 		return hrxqs[5];
14707 	case MLX5_RSS_HASH_NONE:
14708 		return hrxqs[6];
14709 	case MLX5_RSS_HASH_IPV4_ESP:
14710 		return hrxqs[7];
14711 	case MLX5_RSS_HASH_IPV6_ESP:
14712 		return hrxqs[8];
14713 	case MLX5_RSS_HASH_ESP_SPI:
14714 		return hrxqs[9];
14715 	default:
14716 		return 0;
14717 	}
14718 
14719 }
14720 
14721 /**
14722  * Apply the flow to the NIC, lock free,
14723  * (mutex should be acquired by caller).
14724  *
14725  * @param[in] dev
14726  *   Pointer to the Ethernet device structure.
14727  * @param[in, out] flow
14728  *   Pointer to flow structure.
14729  * @param[out] error
14730  *   Pointer to error structure.
14731  *
14732  * @return
14733  *   0 on success, a negative errno value otherwise and rte_errno is set.
14734  */
14735 static int
14736 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
14737 	      struct rte_flow_error *error)
14738 {
14739 	struct mlx5_flow_dv_workspace *dv;
14740 	struct mlx5_flow_handle *dh;
14741 	struct mlx5_flow_handle_dv *dv_h;
14742 	struct mlx5_flow *dev_flow;
14743 	struct mlx5_priv *priv = dev->data->dev_private;
14744 	uint32_t handle_idx;
14745 	int n;
14746 	int err;
14747 	int idx;
14748 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
14749 	struct mlx5_flow_rss_desc *rss_desc = &wks->rss_desc;
14750 	uint8_t misc_mask;
14751 
14752 	MLX5_ASSERT(wks);
14753 	for (idx = wks->flow_idx - 1; idx >= 0; idx--) {
14754 		dev_flow = &wks->flows[idx];
14755 		dv = &dev_flow->dv;
14756 		dh = dev_flow->handle;
14757 		dv_h = &dh->dvh;
14758 		n = dv->actions_n;
14759 		if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
14760 			if (dv->transfer) {
14761 				MLX5_ASSERT(priv->sh->dr_drop_action);
14762 				dv->actions[n++] = priv->sh->dr_drop_action;
14763 			} else {
14764 #ifdef HAVE_MLX5DV_DR
14765 				/* DR supports drop action placeholder. */
14766 				MLX5_ASSERT(priv->sh->dr_drop_action);
14767 				dv->actions[n++] = dv->group ?
14768 					priv->sh->dr_drop_action :
14769 					priv->root_drop_action;
14770 #else
14771 				/* For DV we use the explicit drop queue. */
14772 				MLX5_ASSERT(priv->drop_queue.hrxq);
14773 				dv->actions[n++] =
14774 						priv->drop_queue.hrxq->action;
14775 #endif
14776 			}
14777 		} else if ((dh->fate_action == MLX5_FLOW_FATE_QUEUE &&
14778 			   !dv_h->rix_sample && !dv_h->rix_dest_array)) {
14779 			struct mlx5_hrxq *hrxq;
14780 			uint32_t hrxq_idx;
14781 
14782 			hrxq = flow_dv_hrxq_prepare(dev, dev_flow, rss_desc,
14783 						    &hrxq_idx);
14784 			if (!hrxq) {
14785 				rte_flow_error_set
14786 					(error, rte_errno,
14787 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14788 					 "cannot get hash queue");
14789 				goto error;
14790 			}
14791 			dh->rix_hrxq = hrxq_idx;
14792 			dv->actions[n++] = hrxq->action;
14793 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
14794 			struct mlx5_hrxq *hrxq = NULL;
14795 			uint32_t hrxq_idx;
14796 
14797 			hrxq_idx = flow_dv_action_rss_hrxq_lookup(dev,
14798 						rss_desc->shared_rss,
14799 						dev_flow->hash_fields);
14800 			if (hrxq_idx)
14801 				hrxq = mlx5_ipool_get
14802 					(priv->sh->ipool[MLX5_IPOOL_HRXQ],
14803 					 hrxq_idx);
14804 			if (!hrxq) {
14805 				rte_flow_error_set
14806 					(error, rte_errno,
14807 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14808 					 "cannot get hash queue");
14809 				goto error;
14810 			}
14811 			dh->rix_srss = rss_desc->shared_rss;
14812 			dv->actions[n++] = hrxq->action;
14813 		} else if (dh->fate_action == MLX5_FLOW_FATE_DEFAULT_MISS) {
14814 			if (!priv->sh->default_miss_action) {
14815 				rte_flow_error_set
14816 					(error, rte_errno,
14817 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
14818 					 "default miss action not be created.");
14819 				goto error;
14820 			}
14821 			dv->actions[n++] = priv->sh->default_miss_action;
14822 		}
14823 		misc_mask = flow_dv_matcher_enable(dv->value.buf);
14824 		__flow_dv_adjust_buf_size(&dv->value.size, misc_mask);
14825 		err = mlx5_flow_os_create_flow(dv_h->matcher->matcher_object,
14826 					       (void *)&dv->value, n,
14827 					       dv->actions, &dh->drv_flow);
14828 		if (err) {
14829 			rte_flow_error_set
14830 				(error, errno,
14831 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
14832 				NULL,
14833 				(!priv->sh->config.allow_duplicate_pattern &&
14834 				errno == EEXIST) ?
14835 				"duplicating pattern is not allowed" :
14836 				"hardware refuses to create flow");
14837 			goto error;
14838 		}
14839 		if (priv->vmwa_context &&
14840 		    dh->vf_vlan.tag && !dh->vf_vlan.created) {
14841 			/*
14842 			 * The rule contains the VLAN pattern.
14843 			 * For VF we are going to create VLAN
14844 			 * interface to make hypervisor set correct
14845 			 * e-Switch vport context.
14846 			 */
14847 			mlx5_vlan_vmwa_acquire(dev, &dh->vf_vlan);
14848 		}
14849 	}
14850 	return 0;
14851 error:
14852 	err = rte_errno; /* Save rte_errno before cleanup. */
14853 	SILIST_FOREACH(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW], flow->dev_handles,
14854 		       handle_idx, dh, next) {
14855 		/* hrxq is union, don't clear it if the flag is not set. */
14856 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE && dh->rix_hrxq) {
14857 			mlx5_hrxq_release(dev, dh->rix_hrxq);
14858 			dh->rix_hrxq = 0;
14859 		} else if (dh->fate_action == MLX5_FLOW_FATE_SHARED_RSS) {
14860 			dh->rix_srss = 0;
14861 		}
14862 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
14863 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
14864 	}
14865 	rte_errno = err; /* Restore rte_errno. */
14866 	return -rte_errno;
14867 }
14868 
14869 void
14870 flow_dv_matcher_remove_cb(void *tool_ctx __rte_unused,
14871 			  struct mlx5_list_entry *entry)
14872 {
14873 	struct mlx5_flow_dv_matcher *resource = container_of(entry,
14874 							     typeof(*resource),
14875 							     entry);
14876 
14877 	claim_zero(mlx5_flow_os_destroy_flow_matcher(resource->matcher_object));
14878 	mlx5_free(resource);
14879 }
14880 
14881 /**
14882  * Release the flow matcher.
14883  *
14884  * @param dev
14885  *   Pointer to Ethernet device.
14886  * @param port_id
14887  *   Index to port ID action resource.
14888  *
14889  * @return
14890  *   1 while a reference on it exists, 0 when freed.
14891  */
14892 static int
14893 flow_dv_matcher_release(struct rte_eth_dev *dev,
14894 			struct mlx5_flow_handle *handle)
14895 {
14896 	struct mlx5_flow_dv_matcher *matcher = handle->dvh.matcher;
14897 	struct mlx5_flow_tbl_data_entry *tbl = container_of(matcher->tbl,
14898 							    typeof(*tbl), tbl);
14899 	int ret;
14900 
14901 	MLX5_ASSERT(matcher->matcher_object);
14902 	ret = mlx5_list_unregister(tbl->matchers, &matcher->entry);
14903 	flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl->tbl);
14904 	return ret;
14905 }
14906 
14907 void
14908 flow_dv_encap_decap_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14909 {
14910 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14911 	struct mlx5_flow_dv_encap_decap_resource *res =
14912 				       container_of(entry, typeof(*res), entry);
14913 
14914 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
14915 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_DECAP_ENCAP], res->idx);
14916 }
14917 
14918 /**
14919  * Release an encap/decap resource.
14920  *
14921  * @param dev
14922  *   Pointer to Ethernet device.
14923  * @param encap_decap_idx
14924  *   Index of encap decap resource.
14925  *
14926  * @return
14927  *   1 while a reference on it exists, 0 when freed.
14928  */
14929 static int
14930 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
14931 				     uint32_t encap_decap_idx)
14932 {
14933 	struct mlx5_priv *priv = dev->data->dev_private;
14934 	struct mlx5_flow_dv_encap_decap_resource *resource;
14935 
14936 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DECAP_ENCAP],
14937 				  encap_decap_idx);
14938 	if (!resource)
14939 		return 0;
14940 	MLX5_ASSERT(resource->action);
14941 	return mlx5_hlist_unregister(priv->sh->encaps_decaps, &resource->entry);
14942 }
14943 
14944 /**
14945  * Release an jump to table action resource.
14946  *
14947  * @param dev
14948  *   Pointer to Ethernet device.
14949  * @param rix_jump
14950  *   Index to the jump action resource.
14951  *
14952  * @return
14953  *   1 while a reference on it exists, 0 when freed.
14954  */
14955 static int
14956 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
14957 				  uint32_t rix_jump)
14958 {
14959 	struct mlx5_priv *priv = dev->data->dev_private;
14960 	struct mlx5_flow_tbl_data_entry *tbl_data;
14961 
14962 	tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP],
14963 				  rix_jump);
14964 	if (!tbl_data)
14965 		return 0;
14966 	return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl);
14967 }
14968 
14969 void
14970 flow_dv_modify_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
14971 {
14972 	struct mlx5_flow_dv_modify_hdr_resource *res =
14973 		container_of(entry, typeof(*res), entry);
14974 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
14975 
14976 	claim_zero(mlx5_flow_os_destroy_flow_action(res->action));
14977 	mlx5_ipool_free(sh->mdh_ipools[res->actions_num - 1], res->idx);
14978 }
14979 
14980 /**
14981  * Release a modify-header resource.
14982  *
14983  * @param dev
14984  *   Pointer to Ethernet device.
14985  * @param handle
14986  *   Pointer to mlx5_flow_handle.
14987  *
14988  * @return
14989  *   1 while a reference on it exists, 0 when freed.
14990  */
14991 static int
14992 flow_dv_modify_hdr_resource_release(struct rte_eth_dev *dev,
14993 				    struct mlx5_flow_handle *handle)
14994 {
14995 	struct mlx5_priv *priv = dev->data->dev_private;
14996 	struct mlx5_flow_dv_modify_hdr_resource *entry = handle->dvh.modify_hdr;
14997 
14998 	MLX5_ASSERT(entry->action);
14999 	return mlx5_hlist_unregister(priv->sh->modify_cmds, &entry->entry);
15000 }
15001 
15002 void
15003 flow_dv_port_id_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
15004 {
15005 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
15006 	struct mlx5_flow_dv_port_id_action_resource *resource =
15007 				  container_of(entry, typeof(*resource), entry);
15008 
15009 	claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
15010 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PORT_ID], resource->idx);
15011 }
15012 
15013 /**
15014  * Release port ID action resource.
15015  *
15016  * @param dev
15017  *   Pointer to Ethernet device.
15018  * @param handle
15019  *   Pointer to mlx5_flow_handle.
15020  *
15021  * @return
15022  *   1 while a reference on it exists, 0 when freed.
15023  */
15024 static int
15025 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
15026 					uint32_t port_id)
15027 {
15028 	struct mlx5_priv *priv = dev->data->dev_private;
15029 	struct mlx5_flow_dv_port_id_action_resource *resource;
15030 
15031 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID], port_id);
15032 	if (!resource)
15033 		return 0;
15034 	MLX5_ASSERT(resource->action);
15035 	return mlx5_list_unregister(priv->sh->port_id_action_list,
15036 				    &resource->entry);
15037 }
15038 
15039 /**
15040  * Release shared RSS action resource.
15041  *
15042  * @param dev
15043  *   Pointer to Ethernet device.
15044  * @param srss
15045  *   Shared RSS action index.
15046  */
15047 static void
15048 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss)
15049 {
15050 	struct mlx5_priv *priv = dev->data->dev_private;
15051 	struct mlx5_shared_action_rss *shared_rss;
15052 
15053 	shared_rss = mlx5_ipool_get
15054 			(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], srss);
15055 	__atomic_sub_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
15056 }
15057 
15058 void
15059 flow_dv_push_vlan_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
15060 {
15061 	struct mlx5_dev_ctx_shared *sh = tool_ctx;
15062 	struct mlx5_flow_dv_push_vlan_action_resource *resource =
15063 			container_of(entry, typeof(*resource), entry);
15064 
15065 	claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
15066 	mlx5_ipool_free(sh->ipool[MLX5_IPOOL_PUSH_VLAN], resource->idx);
15067 }
15068 
15069 /**
15070  * Release push vlan action resource.
15071  *
15072  * @param dev
15073  *   Pointer to Ethernet device.
15074  * @param handle
15075  *   Pointer to mlx5_flow_handle.
15076  *
15077  * @return
15078  *   1 while a reference on it exists, 0 when freed.
15079  */
15080 static int
15081 flow_dv_push_vlan_action_resource_release(struct rte_eth_dev *dev,
15082 					  struct mlx5_flow_handle *handle)
15083 {
15084 	struct mlx5_priv *priv = dev->data->dev_private;
15085 	struct mlx5_flow_dv_push_vlan_action_resource *resource;
15086 	uint32_t idx = handle->dvh.rix_push_vlan;
15087 
15088 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PUSH_VLAN], idx);
15089 	if (!resource)
15090 		return 0;
15091 	MLX5_ASSERT(resource->action);
15092 	return mlx5_list_unregister(priv->sh->push_vlan_action_list,
15093 				    &resource->entry);
15094 }
15095 
15096 /**
15097  * Release the fate resource.
15098  *
15099  * @param dev
15100  *   Pointer to Ethernet device.
15101  * @param handle
15102  *   Pointer to mlx5_flow_handle.
15103  */
15104 static void
15105 flow_dv_fate_resource_release(struct rte_eth_dev *dev,
15106 			       struct mlx5_flow_handle *handle)
15107 {
15108 	if (!handle->rix_fate)
15109 		return;
15110 	switch (handle->fate_action) {
15111 	case MLX5_FLOW_FATE_QUEUE:
15112 		if (!handle->dvh.rix_sample && !handle->dvh.rix_dest_array)
15113 			mlx5_hrxq_release(dev, handle->rix_hrxq);
15114 		break;
15115 	case MLX5_FLOW_FATE_JUMP:
15116 		flow_dv_jump_tbl_resource_release(dev, handle->rix_jump);
15117 		break;
15118 	case MLX5_FLOW_FATE_PORT_ID:
15119 		flow_dv_port_id_action_resource_release(dev,
15120 				handle->rix_port_id_action);
15121 		break;
15122 	case MLX5_FLOW_FATE_SEND_TO_KERNEL:
15123 		/* In case of send_to_kernel action the actual release of
15124 		 * resource is done when all shared DR resources are released
15125 		 * since this resource is created once and always reused.
15126 		 */
15127 		break;
15128 	default:
15129 		DRV_LOG(DEBUG, "Incorrect fate action:%d", handle->fate_action);
15130 		break;
15131 	}
15132 	handle->rix_fate = 0;
15133 }
15134 
15135 void
15136 flow_dv_sample_remove_cb(void *tool_ctx __rte_unused,
15137 			 struct mlx5_list_entry *entry)
15138 {
15139 	struct mlx5_flow_dv_sample_resource *resource = container_of(entry,
15140 							      typeof(*resource),
15141 							      entry);
15142 	struct rte_eth_dev *dev = resource->dev;
15143 	struct mlx5_priv *priv = dev->data->dev_private;
15144 
15145 	if (resource->verbs_action)
15146 		claim_zero(mlx5_flow_os_destroy_flow_action
15147 						      (resource->verbs_action));
15148 	if (resource->normal_path_tbl)
15149 		flow_dv_tbl_resource_release(MLX5_SH(dev),
15150 					     resource->normal_path_tbl);
15151 	flow_dv_sample_sub_actions_release(dev, &resource->sample_idx);
15152 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_SAMPLE], resource->idx);
15153 	DRV_LOG(DEBUG, "sample resource %p: removed", (void *)resource);
15154 }
15155 
15156 /**
15157  * Release an sample resource.
15158  *
15159  * @param dev
15160  *   Pointer to Ethernet device.
15161  * @param handle
15162  *   Pointer to mlx5_flow_handle.
15163  *
15164  * @return
15165  *   1 while a reference on it exists, 0 when freed.
15166  */
15167 static int
15168 flow_dv_sample_resource_release(struct rte_eth_dev *dev,
15169 				     struct mlx5_flow_handle *handle)
15170 {
15171 	struct mlx5_priv *priv = dev->data->dev_private;
15172 	struct mlx5_flow_dv_sample_resource *resource;
15173 
15174 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_SAMPLE],
15175 				  handle->dvh.rix_sample);
15176 	if (!resource)
15177 		return 0;
15178 	MLX5_ASSERT(resource->verbs_action);
15179 	return mlx5_list_unregister(priv->sh->sample_action_list,
15180 				    &resource->entry);
15181 }
15182 
15183 void
15184 flow_dv_dest_array_remove_cb(void *tool_ctx __rte_unused,
15185 			     struct mlx5_list_entry *entry)
15186 {
15187 	struct mlx5_flow_dv_dest_array_resource *resource =
15188 			container_of(entry, typeof(*resource), entry);
15189 	struct rte_eth_dev *dev = resource->dev;
15190 	struct mlx5_priv *priv = dev->data->dev_private;
15191 	uint32_t i = 0;
15192 
15193 	MLX5_ASSERT(resource->action);
15194 	if (resource->action)
15195 		claim_zero(mlx5_flow_os_destroy_flow_action(resource->action));
15196 	for (; i < resource->num_of_dest; i++)
15197 		flow_dv_sample_sub_actions_release(dev,
15198 						   &resource->sample_idx[i]);
15199 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY], resource->idx);
15200 	DRV_LOG(DEBUG, "destination array resource %p: removed",
15201 		(void *)resource);
15202 }
15203 
15204 /**
15205  * Release an destination array resource.
15206  *
15207  * @param dev
15208  *   Pointer to Ethernet device.
15209  * @param handle
15210  *   Pointer to mlx5_flow_handle.
15211  *
15212  * @return
15213  *   1 while a reference on it exists, 0 when freed.
15214  */
15215 static int
15216 flow_dv_dest_array_resource_release(struct rte_eth_dev *dev,
15217 				    struct mlx5_flow_handle *handle)
15218 {
15219 	struct mlx5_priv *priv = dev->data->dev_private;
15220 	struct mlx5_flow_dv_dest_array_resource *resource;
15221 
15222 	resource = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_DEST_ARRAY],
15223 				  handle->dvh.rix_dest_array);
15224 	if (!resource)
15225 		return 0;
15226 	MLX5_ASSERT(resource->action);
15227 	return mlx5_list_unregister(priv->sh->dest_array_list,
15228 				    &resource->entry);
15229 }
15230 
15231 void
15232 flow_dev_geneve_tlv_option_resource_release(struct mlx5_dev_ctx_shared *sh)
15233 {
15234 	struct mlx5_geneve_tlv_option_resource *geneve_opt_resource =
15235 				sh->geneve_tlv_option_resource;
15236 	rte_spinlock_lock(&sh->geneve_tlv_opt_sl);
15237 	if (geneve_opt_resource) {
15238 		if (!(__atomic_sub_fetch(&geneve_opt_resource->refcnt, 1,
15239 					 __ATOMIC_RELAXED))) {
15240 			claim_zero(mlx5_devx_cmd_destroy
15241 					(geneve_opt_resource->obj));
15242 			mlx5_free(sh->geneve_tlv_option_resource);
15243 			sh->geneve_tlv_option_resource = NULL;
15244 		}
15245 	}
15246 	rte_spinlock_unlock(&sh->geneve_tlv_opt_sl);
15247 }
15248 
15249 /**
15250  * Remove the flow from the NIC but keeps it in memory.
15251  * Lock free, (mutex should be acquired by caller).
15252  *
15253  * @param[in] dev
15254  *   Pointer to Ethernet device.
15255  * @param[in, out] flow
15256  *   Pointer to flow structure.
15257  */
15258 static void
15259 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
15260 {
15261 	struct mlx5_flow_handle *dh;
15262 	uint32_t handle_idx;
15263 	struct mlx5_priv *priv = dev->data->dev_private;
15264 
15265 	if (!flow)
15266 		return;
15267 	handle_idx = flow->dev_handles;
15268 	while (handle_idx) {
15269 		dh = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
15270 				    handle_idx);
15271 		if (!dh)
15272 			return;
15273 		if (dh->drv_flow) {
15274 			claim_zero(mlx5_flow_os_destroy_flow(dh->drv_flow));
15275 			dh->drv_flow = NULL;
15276 		}
15277 		if (dh->fate_action == MLX5_FLOW_FATE_QUEUE)
15278 			flow_dv_fate_resource_release(dev, dh);
15279 		if (dh->vf_vlan.tag && dh->vf_vlan.created)
15280 			mlx5_vlan_vmwa_release(dev, &dh->vf_vlan);
15281 		handle_idx = dh->next.next;
15282 	}
15283 }
15284 
15285 /**
15286  * Remove the flow from the NIC and the memory.
15287  * Lock free, (mutex should be acquired by caller).
15288  *
15289  * @param[in] dev
15290  *   Pointer to the Ethernet device structure.
15291  * @param[in, out] flow
15292  *   Pointer to flow structure.
15293  */
15294 static void
15295 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
15296 {
15297 	struct mlx5_flow_handle *dev_handle;
15298 	struct mlx5_priv *priv = dev->data->dev_private;
15299 	struct mlx5_flow_meter_info *fm = NULL;
15300 	uint32_t srss = 0;
15301 
15302 	if (!flow)
15303 		return;
15304 	flow_dv_remove(dev, flow);
15305 	if (flow->counter) {
15306 		flow_dv_counter_free(dev, flow->counter);
15307 		flow->counter = 0;
15308 	}
15309 	if (flow->meter) {
15310 		fm = flow_dv_meter_find_by_idx(priv, flow->meter);
15311 		if (fm)
15312 			mlx5_flow_meter_detach(priv, fm);
15313 		flow->meter = 0;
15314 	}
15315 	/* Keep the current age handling by default. */
15316 	if (flow->indirect_type == MLX5_INDIRECT_ACTION_TYPE_CT && flow->ct)
15317 		flow_dv_aso_ct_release(dev, flow->ct, NULL);
15318 	else if (flow->age)
15319 		flow_dv_aso_age_release(dev, flow->age);
15320 	if (flow->geneve_tlv_option) {
15321 		flow_dev_geneve_tlv_option_resource_release(priv->sh);
15322 		flow->geneve_tlv_option = 0;
15323 	}
15324 	while (flow->dev_handles) {
15325 		uint32_t tmp_idx = flow->dev_handles;
15326 
15327 		dev_handle = mlx5_ipool_get(priv->sh->ipool
15328 					    [MLX5_IPOOL_MLX5_FLOW], tmp_idx);
15329 		if (!dev_handle)
15330 			return;
15331 		flow->dev_handles = dev_handle->next.next;
15332 		while (dev_handle->flex_item) {
15333 			int index = rte_bsf32(dev_handle->flex_item);
15334 
15335 			mlx5_flex_release_index(dev, index);
15336 			dev_handle->flex_item &= ~(uint8_t)RTE_BIT32(index);
15337 		}
15338 		if (dev_handle->dvh.matcher)
15339 			flow_dv_matcher_release(dev, dev_handle);
15340 		if (dev_handle->dvh.rix_sample)
15341 			flow_dv_sample_resource_release(dev, dev_handle);
15342 		if (dev_handle->dvh.rix_dest_array)
15343 			flow_dv_dest_array_resource_release(dev, dev_handle);
15344 		if (dev_handle->dvh.rix_encap_decap)
15345 			flow_dv_encap_decap_resource_release(dev,
15346 				dev_handle->dvh.rix_encap_decap);
15347 		if (dev_handle->dvh.modify_hdr)
15348 			flow_dv_modify_hdr_resource_release(dev, dev_handle);
15349 		if (dev_handle->dvh.rix_push_vlan)
15350 			flow_dv_push_vlan_action_resource_release(dev,
15351 								  dev_handle);
15352 		if (dev_handle->dvh.rix_tag)
15353 			flow_dv_tag_release(dev,
15354 					    dev_handle->dvh.rix_tag);
15355 		if (dev_handle->fate_action != MLX5_FLOW_FATE_SHARED_RSS)
15356 			flow_dv_fate_resource_release(dev, dev_handle);
15357 		else if (!srss)
15358 			srss = dev_handle->rix_srss;
15359 		if (fm && dev_handle->is_meter_flow_id &&
15360 		    dev_handle->split_flow_id)
15361 			mlx5_ipool_free(fm->flow_ipool,
15362 					dev_handle->split_flow_id);
15363 		else if (dev_handle->split_flow_id &&
15364 		    !dev_handle->is_meter_flow_id)
15365 			mlx5_ipool_free(priv->sh->ipool
15366 					[MLX5_IPOOL_RSS_EXPANTION_FLOW_ID],
15367 					dev_handle->split_flow_id);
15368 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW],
15369 			   tmp_idx);
15370 	}
15371 	if (srss)
15372 		flow_dv_shared_rss_action_release(dev, srss);
15373 }
15374 
15375 /**
15376  * Release array of hash RX queue objects.
15377  * Helper function.
15378  *
15379  * @param[in] dev
15380  *   Pointer to the Ethernet device structure.
15381  * @param[in, out] hrxqs
15382  *   Array of hash RX queue objects.
15383  *
15384  * @return
15385  *   Total number of references to hash RX queue objects in *hrxqs* array
15386  *   after this operation.
15387  */
15388 static int
15389 __flow_dv_hrxqs_release(struct rte_eth_dev *dev,
15390 			uint32_t (*hrxqs)[MLX5_RSS_HASH_FIELDS_LEN])
15391 {
15392 	size_t i;
15393 	int remaining = 0;
15394 
15395 	for (i = 0; i < RTE_DIM(*hrxqs); i++) {
15396 		int ret = mlx5_hrxq_release(dev, (*hrxqs)[i]);
15397 
15398 		if (!ret)
15399 			(*hrxqs)[i] = 0;
15400 		remaining += ret;
15401 	}
15402 	return remaining;
15403 }
15404 
15405 /**
15406  * Release all hash RX queue objects representing shared RSS action.
15407  *
15408  * @param[in] dev
15409  *   Pointer to the Ethernet device structure.
15410  * @param[in, out] action
15411  *   Shared RSS action to remove hash RX queue objects from.
15412  *
15413  * @return
15414  *   Total number of references to hash RX queue objects stored in *action*
15415  *   after this operation.
15416  *   Expected to be 0 if no external references held.
15417  */
15418 static int
15419 __flow_dv_action_rss_hrxqs_release(struct rte_eth_dev *dev,
15420 				 struct mlx5_shared_action_rss *shared_rss)
15421 {
15422 	return __flow_dv_hrxqs_release(dev, &shared_rss->hrxq);
15423 }
15424 
15425 /**
15426  * Adjust L3/L4 hash value of pre-created shared RSS hrxq according to
15427  * user input.
15428  *
15429  * Only one hash value is available for one L3+L4 combination:
15430  * for example:
15431  * MLX5_RSS_HASH_IPV4, MLX5_RSS_HASH_IPV4_SRC_ONLY, and
15432  * MLX5_RSS_HASH_IPV4_DST_ONLY are mutually exclusive so they can share
15433  * same slot in mlx5_rss_hash_fields.
15434  *
15435  * @param[in] orig_rss_types
15436  *   RSS type as provided in shared RSS action.
15437  * @param[in, out] hash_field
15438  *   hash_field variable needed to be adjusted.
15439  *
15440  * @return
15441  *   void
15442  */
15443 void
15444 flow_dv_action_rss_l34_hash_adjust(uint64_t orig_rss_types,
15445 				   uint64_t *hash_field)
15446 {
15447 	uint64_t rss_types = rte_eth_rss_hf_refine(orig_rss_types);
15448 
15449 	switch (*hash_field & ~IBV_RX_HASH_INNER) {
15450 	case MLX5_RSS_HASH_IPV4:
15451 		if (rss_types & MLX5_IPV4_LAYER_TYPES) {
15452 			*hash_field &= ~MLX5_RSS_HASH_IPV4;
15453 			if (rss_types & RTE_ETH_RSS_L3_DST_ONLY)
15454 				*hash_field |= IBV_RX_HASH_DST_IPV4;
15455 			else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY)
15456 				*hash_field |= IBV_RX_HASH_SRC_IPV4;
15457 			else
15458 				*hash_field |= MLX5_RSS_HASH_IPV4;
15459 		}
15460 		return;
15461 	case MLX5_RSS_HASH_IPV6:
15462 		if (rss_types & MLX5_IPV6_LAYER_TYPES) {
15463 			*hash_field &= ~MLX5_RSS_HASH_IPV6;
15464 			if (rss_types & RTE_ETH_RSS_L3_DST_ONLY)
15465 				*hash_field |= IBV_RX_HASH_DST_IPV6;
15466 			else if (rss_types & RTE_ETH_RSS_L3_SRC_ONLY)
15467 				*hash_field |= IBV_RX_HASH_SRC_IPV6;
15468 			else
15469 				*hash_field |= MLX5_RSS_HASH_IPV6;
15470 		}
15471 		return;
15472 	case MLX5_RSS_HASH_IPV4_UDP:
15473 		/* fall-through. */
15474 	case MLX5_RSS_HASH_IPV6_UDP:
15475 		if (rss_types & RTE_ETH_RSS_UDP) {
15476 			*hash_field &= ~MLX5_UDP_IBV_RX_HASH;
15477 			if (rss_types & RTE_ETH_RSS_L4_DST_ONLY)
15478 				*hash_field |= IBV_RX_HASH_DST_PORT_UDP;
15479 			else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY)
15480 				*hash_field |= IBV_RX_HASH_SRC_PORT_UDP;
15481 			else
15482 				*hash_field |= MLX5_UDP_IBV_RX_HASH;
15483 		}
15484 		return;
15485 	case MLX5_RSS_HASH_IPV4_TCP:
15486 		/* fall-through. */
15487 	case MLX5_RSS_HASH_IPV6_TCP:
15488 		if (rss_types & RTE_ETH_RSS_TCP) {
15489 			*hash_field &= ~MLX5_TCP_IBV_RX_HASH;
15490 			if (rss_types & RTE_ETH_RSS_L4_DST_ONLY)
15491 				*hash_field |= IBV_RX_HASH_DST_PORT_TCP;
15492 			else if (rss_types & RTE_ETH_RSS_L4_SRC_ONLY)
15493 				*hash_field |= IBV_RX_HASH_SRC_PORT_TCP;
15494 			else
15495 				*hash_field |= MLX5_TCP_IBV_RX_HASH;
15496 		}
15497 		return;
15498 	default:
15499 		return;
15500 	}
15501 }
15502 
15503 /**
15504  * Setup shared RSS action.
15505  * Prepare set of hash RX queue objects sufficient to handle all valid
15506  * hash_fields combinations (see enum ibv_rx_hash_fields).
15507  *
15508  * @param[in] dev
15509  *   Pointer to the Ethernet device structure.
15510  * @param[in] action_idx
15511  *   Shared RSS action ipool index.
15512  * @param[in, out] action
15513  *   Partially initialized shared RSS action.
15514  * @param[out] error
15515  *   Perform verbose error reporting if not NULL. Initialized in case of
15516  *   error only.
15517  *
15518  * @return
15519  *   0 on success, otherwise negative errno value.
15520  */
15521 static int
15522 __flow_dv_action_rss_setup(struct rte_eth_dev *dev,
15523 			   uint32_t action_idx,
15524 			   struct mlx5_shared_action_rss *shared_rss,
15525 			   struct rte_flow_error *error)
15526 {
15527 	struct mlx5_priv *priv = dev->data->dev_private;
15528 	struct mlx5_flow_rss_desc rss_desc = { 0 };
15529 	size_t i;
15530 	int err;
15531 
15532 	shared_rss->ind_tbl = mlx5_ind_table_obj_new
15533 			      (dev, shared_rss->origin.queue,
15534 			       shared_rss->origin.queue_num,
15535 			       true,
15536 			       !!dev->data->dev_started);
15537 	if (!shared_rss->ind_tbl)
15538 		return rte_flow_error_set(error, rte_errno,
15539 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
15540 					  "cannot setup indirection table");
15541 	memcpy(rss_desc.key, shared_rss->origin.key, MLX5_RSS_HASH_KEY_LEN);
15542 	rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN;
15543 	rss_desc.const_q = shared_rss->origin.queue;
15544 	rss_desc.queue_num = shared_rss->origin.queue_num;
15545 	/* Set non-zero value to indicate a shared RSS. */
15546 	rss_desc.shared_rss = action_idx;
15547 	rss_desc.ind_tbl = shared_rss->ind_tbl;
15548 	if (priv->sh->config.dv_flow_en == 2)
15549 		rss_desc.hws_flags = MLX5DR_ACTION_FLAG_HWS_RX;
15550 	for (i = 0; i < MLX5_RSS_HASH_FIELDS_LEN; i++) {
15551 		struct mlx5_hrxq *hrxq;
15552 		uint64_t hash_fields = mlx5_rss_hash_fields[i];
15553 		int tunnel = 0;
15554 
15555 		flow_dv_action_rss_l34_hash_adjust(shared_rss->origin.types,
15556 						   &hash_fields);
15557 		if (shared_rss->origin.level > 1) {
15558 			hash_fields |= IBV_RX_HASH_INNER;
15559 			tunnel = 1;
15560 		}
15561 		rss_desc.tunnel = tunnel;
15562 		rss_desc.hash_fields = hash_fields;
15563 		hrxq = mlx5_hrxq_get(dev, &rss_desc);
15564 		if (!hrxq) {
15565 			rte_flow_error_set
15566 				(error, rte_errno,
15567 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
15568 				 "cannot get hash queue");
15569 			goto error_hrxq_new;
15570 		}
15571 		err = __flow_dv_action_rss_hrxq_set
15572 			(shared_rss, hash_fields, hrxq->idx);
15573 		MLX5_ASSERT(!err);
15574 	}
15575 	return 0;
15576 error_hrxq_new:
15577 	err = rte_errno;
15578 	__flow_dv_action_rss_hrxqs_release(dev, shared_rss);
15579 	if (!mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl, true))
15580 		shared_rss->ind_tbl = NULL;
15581 	rte_errno = err;
15582 	return -rte_errno;
15583 }
15584 
15585 /**
15586  * Create shared RSS action.
15587  *
15588  * @param[in] dev
15589  *   Pointer to the Ethernet device structure.
15590  * @param[in] conf
15591  *   Shared action configuration.
15592  * @param[in] rss
15593  *   RSS action specification used to create shared action.
15594  * @param[out] error
15595  *   Perform verbose error reporting if not NULL. Initialized in case of
15596  *   error only.
15597  *
15598  * @return
15599  *   A valid shared action ID in case of success, 0 otherwise and
15600  *   rte_errno is set.
15601  */
15602 static uint32_t
15603 __flow_dv_action_rss_create(struct rte_eth_dev *dev,
15604 			    const struct rte_flow_indir_action_conf *conf,
15605 			    const struct rte_flow_action_rss *rss,
15606 			    struct rte_flow_error *error)
15607 {
15608 	struct mlx5_priv *priv = dev->data->dev_private;
15609 	struct mlx5_shared_action_rss *shared_rss = NULL;
15610 	struct rte_flow_action_rss *origin;
15611 	const uint8_t *rss_key;
15612 	uint32_t idx;
15613 
15614 	RTE_SET_USED(conf);
15615 	shared_rss = mlx5_ipool_zmalloc
15616 			 (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], &idx);
15617 	if (!shared_rss) {
15618 		rte_flow_error_set(error, ENOMEM,
15619 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
15620 				   "cannot allocate resource memory");
15621 		goto error_rss_init;
15622 	}
15623 	if (idx > (1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET)) {
15624 		rte_flow_error_set(error, E2BIG,
15625 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
15626 				   "rss action number out of range");
15627 		goto error_rss_init;
15628 	}
15629 	origin = &shared_rss->origin;
15630 	origin->func = rss->func;
15631 	origin->level = rss->level;
15632 	/* RSS type 0 indicates default RSS type (RTE_ETH_RSS_IP). */
15633 	origin->types = !rss->types ? RTE_ETH_RSS_IP : rss->types;
15634 	/* NULL RSS key indicates default RSS key. */
15635 	rss_key = !rss->key ? rss_hash_default_key : rss->key;
15636 	memcpy(shared_rss->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
15637 	origin->key = &shared_rss->key[0];
15638 	origin->key_len = MLX5_RSS_HASH_KEY_LEN;
15639 	origin->queue = rss->queue;
15640 	origin->queue_num = rss->queue_num;
15641 	if (__flow_dv_action_rss_setup(dev, idx, shared_rss, error))
15642 		goto error_rss_init;
15643 	/* Update queue with indirect table queue memoyr. */
15644 	origin->queue = shared_rss->ind_tbl->queues;
15645 	rte_spinlock_init(&shared_rss->action_rss_sl);
15646 	__atomic_add_fetch(&shared_rss->refcnt, 1, __ATOMIC_RELAXED);
15647 	rte_spinlock_lock(&priv->shared_act_sl);
15648 	ILIST_INSERT(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
15649 		     &priv->rss_shared_actions, idx, shared_rss, next);
15650 	rte_spinlock_unlock(&priv->shared_act_sl);
15651 	return idx;
15652 error_rss_init:
15653 	if (shared_rss) {
15654 		if (shared_rss->ind_tbl)
15655 			mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl,
15656 						   !!dev->data->dev_started);
15657 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
15658 				idx);
15659 	}
15660 	return 0;
15661 }
15662 
15663 /**
15664  * Destroy the shared RSS action.
15665  * Release related hash RX queue objects.
15666  *
15667  * @param[in] dev
15668  *   Pointer to the Ethernet device structure.
15669  * @param[in] idx
15670  *   The shared RSS action object ID to be removed.
15671  * @param[out] error
15672  *   Perform verbose error reporting if not NULL. Initialized in case of
15673  *   error only.
15674  *
15675  * @return
15676  *   0 on success, otherwise negative errno value.
15677  */
15678 static int
15679 __flow_dv_action_rss_release(struct rte_eth_dev *dev, uint32_t idx,
15680 			     struct rte_flow_error *error)
15681 {
15682 	struct mlx5_priv *priv = dev->data->dev_private;
15683 	struct mlx5_shared_action_rss *shared_rss =
15684 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
15685 	uint32_t old_refcnt = 1;
15686 	int remaining;
15687 
15688 	if (!shared_rss)
15689 		return rte_flow_error_set(error, EINVAL,
15690 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15691 					  "invalid shared action");
15692 	if (!__atomic_compare_exchange_n(&shared_rss->refcnt, &old_refcnt,
15693 					 0, 0, __ATOMIC_ACQUIRE,
15694 					 __ATOMIC_RELAXED))
15695 		return rte_flow_error_set(error, EBUSY,
15696 					  RTE_FLOW_ERROR_TYPE_ACTION,
15697 					  NULL,
15698 					  "shared rss has references");
15699 	remaining = __flow_dv_action_rss_hrxqs_release(dev, shared_rss);
15700 	if (remaining)
15701 		return rte_flow_error_set(error, EBUSY,
15702 					  RTE_FLOW_ERROR_TYPE_ACTION,
15703 					  NULL,
15704 					  "shared rss hrxq has references");
15705 	remaining = mlx5_ind_table_obj_release(dev, shared_rss->ind_tbl,
15706 					       !!dev->data->dev_started);
15707 	if (remaining)
15708 		return rte_flow_error_set(error, EBUSY,
15709 					  RTE_FLOW_ERROR_TYPE_ACTION,
15710 					  NULL,
15711 					  "shared rss indirection table has"
15712 					  " references");
15713 	rte_spinlock_lock(&priv->shared_act_sl);
15714 	ILIST_REMOVE(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
15715 		     &priv->rss_shared_actions, idx, shared_rss, next);
15716 	rte_spinlock_unlock(&priv->shared_act_sl);
15717 	mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
15718 			idx);
15719 	return 0;
15720 }
15721 
15722 /**
15723  * Create indirect action, lock free,
15724  * (mutex should be acquired by caller).
15725  * Dispatcher for action type specific call.
15726  *
15727  * @param[in] dev
15728  *   Pointer to the Ethernet device structure.
15729  * @param[in] conf
15730  *   Shared action configuration.
15731  * @param[in] action
15732  *   Action specification used to create indirect action.
15733  * @param[out] error
15734  *   Perform verbose error reporting if not NULL. Initialized in case of
15735  *   error only.
15736  *
15737  * @return
15738  *   A valid shared action handle in case of success, NULL otherwise and
15739  *   rte_errno is set.
15740  */
15741 struct rte_flow_action_handle *
15742 flow_dv_action_create(struct rte_eth_dev *dev,
15743 		      const struct rte_flow_indir_action_conf *conf,
15744 		      const struct rte_flow_action *action,
15745 		      struct rte_flow_error *err)
15746 {
15747 	struct mlx5_priv *priv = dev->data->dev_private;
15748 	uint32_t age_idx = 0;
15749 	uint32_t idx = 0;
15750 	uint32_t ret = 0;
15751 
15752 	switch (action->type) {
15753 	case RTE_FLOW_ACTION_TYPE_RSS:
15754 		ret = __flow_dv_action_rss_create(dev, conf, action->conf, err);
15755 		idx = (MLX5_INDIRECT_ACTION_TYPE_RSS <<
15756 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
15757 		break;
15758 	case RTE_FLOW_ACTION_TYPE_AGE:
15759 		age_idx = flow_dv_aso_age_alloc(dev, err);
15760 		if (!age_idx) {
15761 			ret = -rte_errno;
15762 			break;
15763 		}
15764 		idx = (MLX5_INDIRECT_ACTION_TYPE_AGE <<
15765 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx;
15766 		flow_dv_aso_age_params_init(dev, age_idx,
15767 					((const struct rte_flow_action_age *)
15768 						action->conf)->context ?
15769 					((const struct rte_flow_action_age *)
15770 						action->conf)->context :
15771 					(void *)(uintptr_t)idx,
15772 					((const struct rte_flow_action_age *)
15773 						action->conf)->timeout);
15774 		ret = age_idx;
15775 		break;
15776 	case RTE_FLOW_ACTION_TYPE_COUNT:
15777 		ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL);
15778 		idx = (MLX5_INDIRECT_ACTION_TYPE_COUNT <<
15779 		       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
15780 		break;
15781 	case RTE_FLOW_ACTION_TYPE_CONNTRACK:
15782 		ret = flow_dv_translate_create_conntrack(dev, action->conf,
15783 							 err);
15784 		idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret);
15785 		break;
15786 	default:
15787 		rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
15788 				   NULL, "action type not supported");
15789 		break;
15790 	}
15791 	return ret ? (struct rte_flow_action_handle *)(uintptr_t)idx : NULL;
15792 }
15793 
15794 /**
15795  * Destroy the indirect action.
15796  * Release action related resources on the NIC and the memory.
15797  * Lock free, (mutex should be acquired by caller).
15798  * Dispatcher for action type specific call.
15799  *
15800  * @param[in] dev
15801  *   Pointer to the Ethernet device structure.
15802  * @param[in] handle
15803  *   The indirect action object handle to be removed.
15804  * @param[out] error
15805  *   Perform verbose error reporting if not NULL. Initialized in case of
15806  *   error only.
15807  *
15808  * @return
15809  *   0 on success, otherwise negative errno value.
15810  */
15811 int
15812 flow_dv_action_destroy(struct rte_eth_dev *dev,
15813 		       struct rte_flow_action_handle *handle,
15814 		       struct rte_flow_error *error)
15815 {
15816 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
15817 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
15818 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
15819 	struct mlx5_flow_counter *cnt;
15820 	uint32_t no_flow_refcnt = 1;
15821 	int ret;
15822 
15823 	switch (type) {
15824 	case MLX5_INDIRECT_ACTION_TYPE_RSS:
15825 		return __flow_dv_action_rss_release(dev, idx, error);
15826 	case MLX5_INDIRECT_ACTION_TYPE_COUNT:
15827 		cnt = flow_dv_counter_get_by_idx(dev, idx, NULL);
15828 		if (!__atomic_compare_exchange_n(&cnt->shared_info.refcnt,
15829 						 &no_flow_refcnt, 1, false,
15830 						 __ATOMIC_ACQUIRE,
15831 						 __ATOMIC_RELAXED))
15832 			return rte_flow_error_set(error, EBUSY,
15833 						  RTE_FLOW_ERROR_TYPE_ACTION,
15834 						  NULL,
15835 						  "Indirect count action has references");
15836 		flow_dv_counter_free(dev, idx);
15837 		return 0;
15838 	case MLX5_INDIRECT_ACTION_TYPE_AGE:
15839 		ret = flow_dv_aso_age_release(dev, idx);
15840 		if (ret)
15841 			/*
15842 			 * In this case, the last flow has a reference will
15843 			 * actually release the age action.
15844 			 */
15845 			DRV_LOG(DEBUG, "Indirect age action %" PRIu32 " was"
15846 				" released with references %d.", idx, ret);
15847 		return 0;
15848 	case MLX5_INDIRECT_ACTION_TYPE_CT:
15849 		ret = flow_dv_aso_ct_release(dev, idx, error);
15850 		if (ret < 0)
15851 			return ret;
15852 		if (ret > 0)
15853 			DRV_LOG(DEBUG, "Connection tracking object %u still "
15854 				"has references %d.", idx, ret);
15855 		return 0;
15856 	default:
15857 		return rte_flow_error_set(error, ENOTSUP,
15858 					  RTE_FLOW_ERROR_TYPE_ACTION,
15859 					  NULL,
15860 					  "action type not supported");
15861 	}
15862 }
15863 
15864 /**
15865  * Updates in place shared RSS action configuration.
15866  *
15867  * @param[in] dev
15868  *   Pointer to the Ethernet device structure.
15869  * @param[in] idx
15870  *   The shared RSS action object ID to be updated.
15871  * @param[in] action_conf
15872  *   RSS action specification used to modify *shared_rss*.
15873  * @param[out] error
15874  *   Perform verbose error reporting if not NULL. Initialized in case of
15875  *   error only.
15876  *
15877  * @return
15878  *   0 on success, otherwise negative errno value.
15879  * @note: currently only support update of RSS queues.
15880  */
15881 static int
15882 __flow_dv_action_rss_update(struct rte_eth_dev *dev, uint32_t idx,
15883 			    const struct rte_flow_action_rss *action_conf,
15884 			    struct rte_flow_error *error)
15885 {
15886 	struct mlx5_priv *priv = dev->data->dev_private;
15887 	struct mlx5_shared_action_rss *shared_rss =
15888 	    mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
15889 	int ret = 0;
15890 	void *queue = NULL;
15891 	void *queue_i = NULL;
15892 	uint32_t queue_size = action_conf->queue_num * sizeof(uint16_t);
15893 	bool dev_started = !!dev->data->dev_started;
15894 
15895 	if (!shared_rss)
15896 		return rte_flow_error_set(error, EINVAL,
15897 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15898 					  "invalid shared action to update");
15899 	if (priv->obj_ops.ind_table_modify == NULL)
15900 		return rte_flow_error_set(error, ENOTSUP,
15901 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15902 					  "cannot modify indirection table");
15903 	queue = mlx5_malloc(MLX5_MEM_ZERO,
15904 			    RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
15905 			    0, SOCKET_ID_ANY);
15906 	if (!queue)
15907 		return rte_flow_error_set(error, ENOMEM,
15908 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15909 					  NULL,
15910 					  "cannot allocate resource memory");
15911 	memcpy(queue, action_conf->queue, queue_size);
15912 	MLX5_ASSERT(shared_rss->ind_tbl);
15913 	rte_spinlock_lock(&shared_rss->action_rss_sl);
15914 	queue_i = shared_rss->ind_tbl->queues;
15915 	ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl,
15916 					queue, action_conf->queue_num,
15917 					true /* standalone */,
15918 					dev_started /* ref_new_qs */,
15919 					dev_started /* deref_old_qs */);
15920 	if (ret) {
15921 		ret = rte_flow_error_set(error, rte_errno,
15922 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
15923 					  "cannot update indirection table");
15924 	} else {
15925 		/* Restore the queue to indirect table internal queue. */
15926 		memcpy(queue_i, queue, queue_size);
15927 		shared_rss->ind_tbl->queues = queue_i;
15928 		shared_rss->origin.queue_num = action_conf->queue_num;
15929 	}
15930 	mlx5_free(queue);
15931 	rte_spinlock_unlock(&shared_rss->action_rss_sl);
15932 	return ret;
15933 }
15934 
15935 /*
15936  * Updates in place conntrack context or direction.
15937  * Context update should be synchronized.
15938  *
15939  * @param[in] dev
15940  *   Pointer to the Ethernet device structure.
15941  * @param[in] idx
15942  *   The conntrack object ID to be updated.
15943  * @param[in] update
15944  *   Pointer to the structure of information to update.
15945  * @param[out] error
15946  *   Perform verbose error reporting if not NULL. Initialized in case of
15947  *   error only.
15948  *
15949  * @return
15950  *   0 on success, otherwise negative errno value.
15951  */
15952 static int
15953 __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx,
15954 			   const struct rte_flow_modify_conntrack *update,
15955 			   struct rte_flow_error *error)
15956 {
15957 	struct mlx5_priv *priv = dev->data->dev_private;
15958 	struct mlx5_aso_ct_action *ct;
15959 	const struct rte_flow_action_conntrack *new_prf;
15960 	int ret = 0;
15961 	uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
15962 	uint32_t dev_idx;
15963 
15964 	if (PORT_ID(priv) != owner)
15965 		return rte_flow_error_set(error, EACCES,
15966 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15967 					  NULL,
15968 					  "CT object owned by another port");
15969 	dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
15970 	ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
15971 	if (!ct->refcnt)
15972 		return rte_flow_error_set(error, ENOMEM,
15973 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15974 					  NULL,
15975 					  "CT object is inactive");
15976 	new_prf = &update->new_ct;
15977 	if (update->direction)
15978 		ct->is_original = !!new_prf->is_original_dir;
15979 	if (update->state) {
15980 		/* Only validate the profile when it needs to be updated. */
15981 		ret = mlx5_validate_action_ct(dev, new_prf, error);
15982 		if (ret)
15983 			return ret;
15984 		ret = mlx5_aso_ct_update_by_wqe(priv->sh, MLX5_HW_INV_QUEUE,
15985 						ct, new_prf, NULL, true);
15986 		if (ret)
15987 			return rte_flow_error_set(error, EIO,
15988 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15989 					NULL,
15990 					"Failed to send CT context update WQE");
15991 		/* Block until ready or a failure, default is asynchronous. */
15992 		ret = mlx5_aso_ct_available(priv->sh, MLX5_HW_INV_QUEUE, ct);
15993 		if (ret)
15994 			rte_flow_error_set(error, rte_errno,
15995 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
15996 					   NULL,
15997 					   "Timeout to get the CT update");
15998 	}
15999 	return ret;
16000 }
16001 
16002 /**
16003  * Updates in place shared action configuration, lock free,
16004  * (mutex should be acquired by caller).
16005  *
16006  * @param[in] dev
16007  *   Pointer to the Ethernet device structure.
16008  * @param[in] handle
16009  *   The indirect action object handle to be updated.
16010  * @param[in] update
16011  *   Action specification used to modify the action pointed by *handle*.
16012  *   *update* could be of same type with the action pointed by the *handle*
16013  *   handle argument, or some other structures like a wrapper, depending on
16014  *   the indirect action type.
16015  * @param[out] error
16016  *   Perform verbose error reporting if not NULL. Initialized in case of
16017  *   error only.
16018  *
16019  * @return
16020  *   0 on success, otherwise negative errno value.
16021  */
16022 int
16023 flow_dv_action_update(struct rte_eth_dev *dev,
16024 			struct rte_flow_action_handle *handle,
16025 			const void *update,
16026 			struct rte_flow_error *err)
16027 {
16028 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
16029 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
16030 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
16031 	const void *action_conf;
16032 
16033 	switch (type) {
16034 	case MLX5_INDIRECT_ACTION_TYPE_RSS:
16035 		action_conf = ((const struct rte_flow_action *)update)->conf;
16036 		return __flow_dv_action_rss_update(dev, idx, action_conf, err);
16037 	case MLX5_INDIRECT_ACTION_TYPE_CT:
16038 		return __flow_dv_action_ct_update(dev, idx, update, err);
16039 	default:
16040 		return rte_flow_error_set(err, ENOTSUP,
16041 					  RTE_FLOW_ERROR_TYPE_ACTION,
16042 					  NULL,
16043 					  "action type update not supported");
16044 	}
16045 }
16046 
16047 /**
16048  * Destroy the meter sub policy table rules.
16049  * Lock free, (mutex should be acquired by caller).
16050  *
16051  * @param[in] dev
16052  *   Pointer to Ethernet device.
16053  * @param[in] sub_policy
16054  *   Pointer to meter sub policy table.
16055  */
16056 static void
16057 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
16058 			     struct mlx5_flow_meter_sub_policy *sub_policy)
16059 {
16060 	struct mlx5_priv *priv = dev->data->dev_private;
16061 	struct mlx5_flow_tbl_data_entry *tbl;
16062 	struct mlx5_flow_meter_policy *policy = sub_policy->main_policy;
16063 	struct mlx5_flow_meter_info *next_fm;
16064 	struct mlx5_sub_policy_color_rule *color_rule;
16065 	void *tmp;
16066 	uint32_t i;
16067 
16068 	for (i = 0; i < RTE_COLORS; i++) {
16069 		next_fm = NULL;
16070 		if (i <= RTE_COLOR_YELLOW && policy &&
16071 		    policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
16072 			next_fm = mlx5_flow_meter_find(priv,
16073 					policy->act_cnt[i].next_mtr_id, NULL);
16074 		RTE_TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i],
16075 				   next_port, tmp) {
16076 			claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule));
16077 			tbl = container_of(color_rule->matcher->tbl,
16078 					   typeof(*tbl), tbl);
16079 			mlx5_list_unregister(tbl->matchers,
16080 					     &color_rule->matcher->entry);
16081 			TAILQ_REMOVE(&sub_policy->color_rules[i],
16082 				     color_rule, next_port);
16083 			mlx5_free(color_rule);
16084 			if (next_fm)
16085 				mlx5_flow_meter_detach(priv, next_fm);
16086 		}
16087 	}
16088 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16089 		if (sub_policy->rix_hrxq[i]) {
16090 			if (policy && !policy->is_hierarchy)
16091 				mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
16092 			sub_policy->rix_hrxq[i] = 0;
16093 		}
16094 		if (sub_policy->jump_tbl[i]) {
16095 			flow_dv_tbl_resource_release(MLX5_SH(dev),
16096 						     sub_policy->jump_tbl[i]);
16097 			sub_policy->jump_tbl[i] = NULL;
16098 		}
16099 	}
16100 	if (sub_policy->tbl_rsc) {
16101 		flow_dv_tbl_resource_release(MLX5_SH(dev),
16102 					     sub_policy->tbl_rsc);
16103 		sub_policy->tbl_rsc = NULL;
16104 	}
16105 }
16106 
16107 /**
16108  * Destroy policy rules, lock free,
16109  * (mutex should be acquired by caller).
16110  * Dispatcher for action type specific call.
16111  *
16112  * @param[in] dev
16113  *   Pointer to the Ethernet device structure.
16114  * @param[in] mtr_policy
16115  *   Meter policy struct.
16116  */
16117 static void
16118 flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
16119 			     struct mlx5_flow_meter_policy *mtr_policy)
16120 {
16121 	uint32_t i, j;
16122 	struct mlx5_flow_meter_sub_policy *sub_policy;
16123 	uint16_t sub_policy_num;
16124 
16125 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16126 		sub_policy_num = (mtr_policy->sub_policy_num >>
16127 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
16128 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16129 		for (j = 0; j < sub_policy_num; j++) {
16130 			sub_policy = mtr_policy->sub_policys[i][j];
16131 			if (sub_policy)
16132 				__flow_dv_destroy_sub_policy_rules(dev,
16133 								   sub_policy);
16134 		}
16135 	}
16136 }
16137 
16138 /**
16139  * Destroy policy action, lock free,
16140  * (mutex should be acquired by caller).
16141  * Dispatcher for action type specific call.
16142  *
16143  * @param[in] dev
16144  *   Pointer to the Ethernet device structure.
16145  * @param[in] mtr_policy
16146  *   Meter policy struct.
16147  */
16148 static void
16149 flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
16150 		      struct mlx5_flow_meter_policy *mtr_policy)
16151 {
16152 	struct rte_flow_action *rss_action;
16153 	struct mlx5_flow_handle dev_handle;
16154 	uint32_t i, j;
16155 
16156 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
16157 		if (mtr_policy->act_cnt[i].rix_mark) {
16158 			flow_dv_tag_release(dev,
16159 				mtr_policy->act_cnt[i].rix_mark);
16160 			mtr_policy->act_cnt[i].rix_mark = 0;
16161 		}
16162 		if (mtr_policy->act_cnt[i].modify_hdr) {
16163 			dev_handle.dvh.modify_hdr =
16164 				mtr_policy->act_cnt[i].modify_hdr;
16165 			flow_dv_modify_hdr_resource_release(dev, &dev_handle);
16166 		}
16167 		switch (mtr_policy->act_cnt[i].fate_action) {
16168 		case MLX5_FLOW_FATE_SHARED_RSS:
16169 			rss_action = mtr_policy->act_cnt[i].rss;
16170 			mlx5_free(rss_action);
16171 			break;
16172 		case MLX5_FLOW_FATE_PORT_ID:
16173 			if (mtr_policy->act_cnt[i].rix_port_id_action) {
16174 				flow_dv_port_id_action_resource_release(dev,
16175 				mtr_policy->act_cnt[i].rix_port_id_action);
16176 				mtr_policy->act_cnt[i].rix_port_id_action = 0;
16177 			}
16178 			break;
16179 		case MLX5_FLOW_FATE_DROP:
16180 		case MLX5_FLOW_FATE_JUMP:
16181 			for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
16182 				mtr_policy->act_cnt[i].dr_jump_action[j] =
16183 						NULL;
16184 			break;
16185 		default:
16186 			/*Queue action do nothing*/
16187 			break;
16188 		}
16189 	}
16190 	for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
16191 		mtr_policy->dr_drop_action[j] = NULL;
16192 }
16193 
16194 /**
16195  * Create yellow action for color aware meter.
16196  *
16197  * @param[in] dev
16198  *   Pointer to the Ethernet device structure.
16199  * @param[in] fm
16200  *   Meter information table.
16201  * @param[out] error
16202  *   Perform verbose error reporting if not NULL. Initialized in case of
16203  *   error only.
16204  *
16205  * @return
16206  *   0 on success, a negative errno value otherwise and rte_errno is set.
16207  */
16208 static int
16209 __flow_dv_create_mtr_yellow_action(struct rte_eth_dev *dev,
16210 				   struct mlx5_flow_meter_info *fm,
16211 				   struct rte_mtr_error *error)
16212 {
16213 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
16214 	struct mlx5_priv *priv = dev->data->dev_private;
16215 	struct rte_flow_error flow_err;
16216 	struct mlx5_aso_mtr *aso_mtr;
16217 	struct mlx5_aso_mtr_pool *pool;
16218 	uint8_t reg_id;
16219 
16220 	aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
16221 	pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool, mtrs[aso_mtr->offset]);
16222 	reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
16223 	fm->meter_action_y =
16224 		mlx5_glue->dv_create_flow_action_aso(priv->sh->rx_domain,
16225 						     pool->devx_obj->obj,
16226 						     aso_mtr->offset,
16227 						     (1 << MLX5_FLOW_COLOR_YELLOW),
16228 						     reg_id - REG_C_0);
16229 #else
16230 	RTE_SET_USED(dev);
16231 #endif
16232 	if (!fm->meter_action_y) {
16233 		return -rte_mtr_error_set(error, EINVAL, RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
16234 					  "Fail to create yellow meter action.");
16235 	}
16236 	return 0;
16237 }
16238 
16239 /**
16240  * Create policy action per domain, lock free,
16241  * (mutex should be acquired by caller).
16242  * Dispatcher for action type specific call.
16243  *
16244  * @param[in] dev
16245  *   Pointer to the Ethernet device structure.
16246  * @param[in] mtr_policy
16247  *   Meter policy struct.
16248  * @param[in] action
16249  *   Action specification used to create meter actions.
16250  * @param[in] attr
16251  *   Pointer to the flow attributes.
16252  * @param[out] error
16253  *   Perform verbose error reporting if not NULL. Initialized in case of
16254  *   error only.
16255  *
16256  * @return
16257  *   0 on success, otherwise negative errno value.
16258  */
16259 static int
16260 __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
16261 			struct mlx5_flow_meter_policy *mtr_policy,
16262 			const struct rte_flow_action *actions[RTE_COLORS],
16263 			struct rte_flow_attr *attr,
16264 			enum mlx5_meter_domain domain,
16265 			struct rte_mtr_error *error)
16266 {
16267 	struct mlx5_priv *priv = dev->data->dev_private;
16268 	struct rte_flow_error flow_err;
16269 	const struct rte_flow_action *act;
16270 	uint64_t action_flags;
16271 	struct mlx5_flow_handle dh;
16272 	struct mlx5_flow dev_flow;
16273 	struct mlx5_flow_dv_port_id_action_resource port_id_action;
16274 	int i, ret;
16275 	uint8_t egress, transfer;
16276 	struct mlx5_meter_policy_action_container *act_cnt = NULL;
16277 	union {
16278 		struct mlx5_flow_dv_modify_hdr_resource res;
16279 		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
16280 			    sizeof(struct mlx5_modification_cmd) *
16281 			    (MLX5_MAX_MODIFY_NUM + 1)];
16282 	} mhdr_dummy;
16283 	struct mlx5_flow_dv_modify_hdr_resource *mhdr_res = &mhdr_dummy.res;
16284 
16285 	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
16286 	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
16287 	memset(&dh, 0, sizeof(struct mlx5_flow_handle));
16288 	memset(&dev_flow, 0, sizeof(struct mlx5_flow));
16289 	memset(&port_id_action, 0,
16290 	       sizeof(struct mlx5_flow_dv_port_id_action_resource));
16291 	memset(mhdr_res, 0, sizeof(*mhdr_res));
16292 	mhdr_res->ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
16293 				       (egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
16294 					MLX5DV_FLOW_TABLE_TYPE_NIC_RX);
16295 	dev_flow.handle = &dh;
16296 	dev_flow.dv.port_id_action = &port_id_action;
16297 	dev_flow.external = true;
16298 	for (i = 0; i < RTE_COLORS; i++) {
16299 		if (i < MLX5_MTR_RTE_COLORS)
16300 			act_cnt = &mtr_policy->act_cnt[i];
16301 		/* Skip the color policy actions creation. */
16302 		if ((i == RTE_COLOR_YELLOW && mtr_policy->skip_y) ||
16303 		    (i == RTE_COLOR_GREEN && mtr_policy->skip_g))
16304 			continue;
16305 		action_flags = 0;
16306 		for (act = actions[i];
16307 		     act && act->type != RTE_FLOW_ACTION_TYPE_END; act++) {
16308 			switch (act->type) {
16309 			case RTE_FLOW_ACTION_TYPE_MARK:
16310 			{
16311 				uint32_t tag_be = mlx5_flow_mark_set
16312 					(((const struct rte_flow_action_mark *)
16313 					(act->conf))->id);
16314 
16315 				if (i >= MLX5_MTR_RTE_COLORS)
16316 					return -rte_mtr_error_set(error,
16317 					  ENOTSUP,
16318 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
16319 					  NULL,
16320 					  "cannot create policy "
16321 					  "mark action for this color");
16322 				if (flow_dv_tag_resource_register(dev, tag_be,
16323 						  &dev_flow, &flow_err))
16324 					return -rte_mtr_error_set(error,
16325 					ENOTSUP,
16326 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16327 					NULL,
16328 					"cannot setup policy mark action");
16329 				MLX5_ASSERT(dev_flow.dv.tag_resource);
16330 				act_cnt->rix_mark =
16331 					dev_flow.handle->dvh.rix_tag;
16332 				action_flags |= MLX5_FLOW_ACTION_MARK;
16333 				mtr_policy->mark = 1;
16334 				break;
16335 			}
16336 			case RTE_FLOW_ACTION_TYPE_SET_TAG:
16337 				if (i >= MLX5_MTR_RTE_COLORS)
16338 					return -rte_mtr_error_set(error,
16339 					  ENOTSUP,
16340 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
16341 					  NULL,
16342 					  "cannot create policy "
16343 					  "set tag action for this color");
16344 				if (flow_dv_convert_action_set_tag
16345 				(dev, mhdr_res,
16346 				(const struct rte_flow_action_set_tag *)
16347 				act->conf,  &flow_err))
16348 					return -rte_mtr_error_set(error,
16349 					ENOTSUP,
16350 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16351 					NULL, "cannot convert policy "
16352 					"set tag action");
16353 				if (!mhdr_res->actions_num)
16354 					return -rte_mtr_error_set(error,
16355 					ENOTSUP,
16356 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16357 					NULL, "cannot find policy "
16358 					"set tag action");
16359 				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
16360 				break;
16361 			case RTE_FLOW_ACTION_TYPE_DROP:
16362 			{
16363 				struct mlx5_flow_mtr_mng *mtrmng =
16364 						priv->sh->mtrmng;
16365 				struct mlx5_flow_tbl_data_entry *tbl_data;
16366 
16367 				/*
16368 				 * Create the drop table with
16369 				 * METER DROP level.
16370 				 */
16371 				if (!mtrmng->drop_tbl[domain]) {
16372 					mtrmng->drop_tbl[domain] =
16373 					flow_dv_tbl_resource_get(dev,
16374 					MLX5_FLOW_TABLE_LEVEL_METER,
16375 					egress, transfer, false, NULL, 0,
16376 					0, MLX5_MTR_TABLE_ID_DROP, &flow_err);
16377 					if (!mtrmng->drop_tbl[domain])
16378 						return -rte_mtr_error_set
16379 					(error, ENOTSUP,
16380 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16381 					NULL,
16382 					"Failed to create meter drop table");
16383 				}
16384 				tbl_data = container_of
16385 				(mtrmng->drop_tbl[domain],
16386 				struct mlx5_flow_tbl_data_entry, tbl);
16387 				if (i < MLX5_MTR_RTE_COLORS) {
16388 					act_cnt->dr_jump_action[domain] =
16389 						tbl_data->jump.action;
16390 					act_cnt->fate_action =
16391 						MLX5_FLOW_FATE_DROP;
16392 				}
16393 				if (i == RTE_COLOR_RED)
16394 					mtr_policy->dr_drop_action[domain] =
16395 						tbl_data->jump.action;
16396 				action_flags |= MLX5_FLOW_ACTION_DROP;
16397 				break;
16398 			}
16399 			case RTE_FLOW_ACTION_TYPE_QUEUE:
16400 			{
16401 				if (i >= MLX5_MTR_RTE_COLORS)
16402 					return -rte_mtr_error_set(error,
16403 					ENOTSUP,
16404 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16405 					NULL, "cannot create policy "
16406 					"fate queue for this color");
16407 				act_cnt->queue =
16408 				((const struct rte_flow_action_queue *)
16409 					(act->conf))->index;
16410 				act_cnt->fate_action =
16411 					MLX5_FLOW_FATE_QUEUE;
16412 				dev_flow.handle->fate_action =
16413 					MLX5_FLOW_FATE_QUEUE;
16414 				mtr_policy->is_queue = 1;
16415 				action_flags |= MLX5_FLOW_ACTION_QUEUE;
16416 				break;
16417 			}
16418 			case RTE_FLOW_ACTION_TYPE_RSS:
16419 			{
16420 				int rss_size;
16421 
16422 				if (i >= MLX5_MTR_RTE_COLORS)
16423 					return -rte_mtr_error_set(error,
16424 					  ENOTSUP,
16425 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
16426 					  NULL,
16427 					  "cannot create policy "
16428 					  "rss action for this color");
16429 				/*
16430 				 * Save RSS conf into policy struct
16431 				 * for translate stage.
16432 				 */
16433 				rss_size = (int)rte_flow_conv
16434 					(RTE_FLOW_CONV_OP_ACTION,
16435 					NULL, 0, act, &flow_err);
16436 				if (rss_size <= 0)
16437 					return -rte_mtr_error_set(error,
16438 					  ENOTSUP,
16439 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
16440 					  NULL, "Get the wrong "
16441 					  "rss action struct size");
16442 				act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
16443 						rss_size, 0, SOCKET_ID_ANY);
16444 				if (!act_cnt->rss)
16445 					return -rte_mtr_error_set(error,
16446 					  ENOTSUP,
16447 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
16448 					  NULL,
16449 					  "Fail to malloc rss action memory");
16450 				ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
16451 					act_cnt->rss, rss_size,
16452 					act, &flow_err);
16453 				if (ret < 0)
16454 					return -rte_mtr_error_set(error,
16455 					  ENOTSUP,
16456 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
16457 					  NULL, "Fail to save "
16458 					  "rss action into policy struct");
16459 				act_cnt->fate_action =
16460 					MLX5_FLOW_FATE_SHARED_RSS;
16461 				action_flags |= MLX5_FLOW_ACTION_RSS;
16462 				break;
16463 			}
16464 			case RTE_FLOW_ACTION_TYPE_PORT_ID:
16465 			case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
16466 			{
16467 				struct mlx5_flow_dv_port_id_action_resource
16468 					port_id_resource;
16469 				uint32_t port_id = 0;
16470 
16471 				if (i >= MLX5_MTR_RTE_COLORS)
16472 					return -rte_mtr_error_set(error,
16473 					ENOTSUP,
16474 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16475 					NULL, "cannot create policy "
16476 					"port action for this color");
16477 				memset(&port_id_resource, 0,
16478 					sizeof(port_id_resource));
16479 				if (flow_dv_translate_action_port_id(dev, act,
16480 						&port_id, &flow_err))
16481 					return -rte_mtr_error_set(error,
16482 					ENOTSUP,
16483 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16484 					NULL, "cannot translate "
16485 					"policy port action");
16486 				port_id_resource.port_id = port_id;
16487 				if (flow_dv_port_id_action_resource_register
16488 					(dev, &port_id_resource,
16489 					&dev_flow, &flow_err))
16490 					return -rte_mtr_error_set(error,
16491 					ENOTSUP,
16492 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16493 					NULL, "cannot setup "
16494 					"policy port action");
16495 				act_cnt->rix_port_id_action =
16496 					dev_flow.handle->rix_port_id_action;
16497 				act_cnt->fate_action =
16498 					MLX5_FLOW_FATE_PORT_ID;
16499 				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
16500 				break;
16501 			}
16502 			case RTE_FLOW_ACTION_TYPE_JUMP:
16503 			{
16504 				uint32_t jump_group = 0;
16505 				uint32_t table = 0;
16506 				struct mlx5_flow_tbl_data_entry *tbl_data;
16507 				struct flow_grp_info grp_info = {
16508 					.external = !!dev_flow.external,
16509 					.transfer = !!transfer,
16510 					.fdb_def_rule = !!priv->fdb_def_rule,
16511 					.std_tbl_fix = 0,
16512 					.skip_scale = dev_flow.skip_scale &
16513 					(1 << MLX5_SCALE_FLOW_GROUP_BIT),
16514 				};
16515 				struct mlx5_flow_meter_sub_policy *sub_policy =
16516 					mtr_policy->sub_policys[domain][0];
16517 
16518 				if (i >= MLX5_MTR_RTE_COLORS)
16519 					return -rte_mtr_error_set(error,
16520 					  ENOTSUP,
16521 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
16522 					  NULL,
16523 					  "cannot create policy "
16524 					  "jump action for this color");
16525 				jump_group =
16526 				((const struct rte_flow_action_jump *)
16527 							act->conf)->group;
16528 				if (mlx5_flow_group_to_table(dev, NULL,
16529 						       jump_group,
16530 						       &table,
16531 						       &grp_info, &flow_err))
16532 					return -rte_mtr_error_set(error,
16533 					ENOTSUP,
16534 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16535 					NULL, "cannot setup "
16536 					"policy jump action");
16537 				sub_policy->jump_tbl[i] =
16538 				flow_dv_tbl_resource_get(dev,
16539 					table, egress,
16540 					transfer,
16541 					!!dev_flow.external,
16542 					NULL, jump_group, 0,
16543 					0, &flow_err);
16544 				if
16545 				(!sub_policy->jump_tbl[i])
16546 					return  -rte_mtr_error_set(error,
16547 					ENOTSUP,
16548 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16549 					NULL, "cannot create jump action.");
16550 				tbl_data = container_of
16551 				(sub_policy->jump_tbl[i],
16552 				struct mlx5_flow_tbl_data_entry, tbl);
16553 				act_cnt->dr_jump_action[domain] =
16554 					tbl_data->jump.action;
16555 				act_cnt->fate_action =
16556 					MLX5_FLOW_FATE_JUMP;
16557 				action_flags |= MLX5_FLOW_ACTION_JUMP;
16558 				break;
16559 			}
16560 			case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
16561 			{
16562 				if (i >= MLX5_MTR_RTE_COLORS)
16563 					return -rte_mtr_error_set(error,
16564 					  ENOTSUP,
16565 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
16566 					  NULL,
16567 					  "cannot create policy modify field for this color");
16568 				if (flow_dv_convert_action_modify_field
16569 					(dev, mhdr_res, act, attr, &flow_err))
16570 					return -rte_mtr_error_set(error,
16571 					ENOTSUP,
16572 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16573 					NULL, "cannot setup policy modify field action");
16574 				if (!mhdr_res->actions_num)
16575 					return -rte_mtr_error_set(error,
16576 					ENOTSUP,
16577 					RTE_MTR_ERROR_TYPE_METER_POLICY,
16578 					NULL, "cannot find policy modify field action");
16579 				action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
16580 				break;
16581 			}
16582 			/*
16583 			 * No need to check meter hierarchy for R colors
16584 			 * here since it is done in the validation stage.
16585 			 */
16586 			case RTE_FLOW_ACTION_TYPE_METER:
16587 			{
16588 				const struct rte_flow_action_meter *mtr;
16589 				struct mlx5_flow_meter_info *next_fm;
16590 				struct mlx5_flow_meter_policy *next_policy;
16591 				struct rte_flow_action tag_action;
16592 				struct mlx5_rte_flow_action_set_tag set_tag;
16593 				uint32_t next_mtr_idx = 0;
16594 
16595 				mtr = act->conf;
16596 				next_fm = mlx5_flow_meter_find(priv,
16597 							mtr->mtr_id,
16598 							&next_mtr_idx);
16599 				if (!next_fm)
16600 					return -rte_mtr_error_set(error, EINVAL,
16601 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
16602 						"Fail to find next meter.");
16603 				if (next_fm->def_policy)
16604 					return -rte_mtr_error_set(error, EINVAL,
16605 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
16606 				"Hierarchy only supports termination meter.");
16607 				next_policy = mlx5_flow_meter_policy_find(dev,
16608 						next_fm->policy_id, NULL);
16609 				MLX5_ASSERT(next_policy);
16610 				if (next_fm->drop_cnt) {
16611 					set_tag.id =
16612 						(enum modify_reg)
16613 						mlx5_flow_get_reg_id(dev,
16614 						MLX5_MTR_ID,
16615 						0,
16616 						(struct rte_flow_error *)error);
16617 					set_tag.offset = (priv->mtr_reg_share ?
16618 						MLX5_MTR_COLOR_BITS : 0);
16619 					set_tag.length = (priv->mtr_reg_share ?
16620 					       MLX5_MTR_IDLE_BITS_IN_COLOR_REG :
16621 					       MLX5_REG_BITS);
16622 					set_tag.data = next_mtr_idx;
16623 					tag_action.type =
16624 						(enum rte_flow_action_type)
16625 						MLX5_RTE_FLOW_ACTION_TYPE_TAG;
16626 					tag_action.conf = &set_tag;
16627 					if (flow_dv_convert_action_set_reg
16628 						(mhdr_res, &tag_action,
16629 						(struct rte_flow_error *)error))
16630 						return -rte_errno;
16631 					action_flags |=
16632 						MLX5_FLOW_ACTION_SET_TAG;
16633 				}
16634 				if (i == RTE_COLOR_YELLOW && next_fm->color_aware &&
16635 				    !next_fm->meter_action_y)
16636 					if (__flow_dv_create_mtr_yellow_action(dev, next_fm, error))
16637 						return -rte_errno;
16638 				act_cnt->fate_action = MLX5_FLOW_FATE_MTR;
16639 				act_cnt->next_mtr_id = next_fm->meter_id;
16640 				act_cnt->next_sub_policy = NULL;
16641 				mtr_policy->is_hierarchy = 1;
16642 				if (next_policy->mark)
16643 					mtr_policy->mark = 1;
16644 				mtr_policy->hierarchy_match_port =
16645 							next_policy->hierarchy_match_port;
16646 				action_flags |=
16647 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
16648 				break;
16649 			}
16650 			default:
16651 				return -rte_mtr_error_set(error, ENOTSUP,
16652 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
16653 					  NULL, "action type not supported");
16654 			}
16655 			if ((action_flags & MLX5_FLOW_ACTION_SET_TAG) ||
16656 			    (action_flags & MLX5_FLOW_ACTION_MODIFY_FIELD)) {
16657 				/* create modify action if needed. */
16658 				dev_flow.dv.group = 1;
16659 				if (flow_dv_modify_hdr_resource_register
16660 					(dev, mhdr_res, &dev_flow, &flow_err))
16661 					return -rte_mtr_error_set(error,
16662 						ENOTSUP,
16663 						RTE_MTR_ERROR_TYPE_METER_POLICY,
16664 						NULL, "cannot register policy set tag/modify field action");
16665 				act_cnt->modify_hdr =
16666 					dev_flow.handle->dvh.modify_hdr;
16667 			}
16668 		}
16669 	}
16670 	return 0;
16671 }
16672 
16673 /**
16674  * Create policy action per domain, lock free,
16675  * (mutex should be acquired by caller).
16676  * Dispatcher for action type specific call.
16677  *
16678  * @param[in] dev
16679  *   Pointer to the Ethernet device structure.
16680  * @param[in] mtr_policy
16681  *   Meter policy struct.
16682  * @param[in] action
16683  *   Action specification used to create meter actions.
16684  * @param[in] attr
16685  *   Pointer to the flow attributes.
16686  * @param[out] error
16687  *   Perform verbose error reporting if not NULL. Initialized in case of
16688  *   error only.
16689  *
16690  * @return
16691  *   0 on success, otherwise negative errno value.
16692  */
16693 static int
16694 flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
16695 		      struct mlx5_flow_meter_policy *mtr_policy,
16696 		      const struct rte_flow_action *actions[RTE_COLORS],
16697 		      struct rte_flow_attr *attr,
16698 		      struct rte_mtr_error *error)
16699 {
16700 	int ret, i;
16701 	uint16_t sub_policy_num;
16702 
16703 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16704 		sub_policy_num = (mtr_policy->sub_policy_num >>
16705 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
16706 			MLX5_MTR_SUB_POLICY_NUM_MASK;
16707 		if (sub_policy_num) {
16708 			ret = __flow_dv_create_domain_policy_acts(dev,
16709 				mtr_policy, actions, attr,
16710 				(enum mlx5_meter_domain)i, error);
16711 			/* Cleaning resource is done in the caller level. */
16712 			if (ret)
16713 				return ret;
16714 		}
16715 	}
16716 	return 0;
16717 }
16718 
16719 /**
16720  * Query a DV flow rule for its statistics via DevX.
16721  *
16722  * @param[in] dev
16723  *   Pointer to Ethernet device.
16724  * @param[in] cnt_idx
16725  *   Index to the flow counter.
16726  * @param[out] data
16727  *   Data retrieved by the query.
16728  * @param[out] error
16729  *   Perform verbose error reporting if not NULL.
16730  *
16731  * @return
16732  *   0 on success, a negative errno value otherwise and rte_errno is set.
16733  */
16734 static int
16735 flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data,
16736 		    struct rte_flow_error *error)
16737 {
16738 	struct mlx5_priv *priv = dev->data->dev_private;
16739 	struct rte_flow_query_count *qc = data;
16740 
16741 	if (!priv->sh->cdev->config.devx)
16742 		return rte_flow_error_set(error, ENOTSUP,
16743 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16744 					  NULL,
16745 					  "counters are not supported");
16746 	if (cnt_idx) {
16747 		uint64_t pkts, bytes;
16748 		struct mlx5_flow_counter *cnt;
16749 		int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes);
16750 
16751 		if (err)
16752 			return rte_flow_error_set(error, -err,
16753 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16754 					NULL, "cannot read counters");
16755 		cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL);
16756 		qc->hits_set = 1;
16757 		qc->bytes_set = 1;
16758 		qc->hits = pkts - cnt->hits;
16759 		qc->bytes = bytes - cnt->bytes;
16760 		if (qc->reset) {
16761 			cnt->hits = pkts;
16762 			cnt->bytes = bytes;
16763 		}
16764 		return 0;
16765 	}
16766 	return rte_flow_error_set(error, EINVAL,
16767 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16768 				  NULL,
16769 				  "counters are not available");
16770 }
16771 
16772 int
16773 flow_dv_action_query(struct rte_eth_dev *dev,
16774 		     const struct rte_flow_action_handle *handle, void *data,
16775 		     struct rte_flow_error *error)
16776 {
16777 	struct mlx5_age_param *age_param;
16778 	struct rte_flow_query_age *resp;
16779 	uint32_t act_idx = (uint32_t)(uintptr_t)handle;
16780 	uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
16781 	uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
16782 	struct mlx5_priv *priv = dev->data->dev_private;
16783 	struct mlx5_aso_ct_action *ct;
16784 	uint16_t owner;
16785 	uint32_t dev_idx;
16786 
16787 	switch (type) {
16788 	case MLX5_INDIRECT_ACTION_TYPE_AGE:
16789 		age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params;
16790 		resp = data;
16791 		resp->aged = __atomic_load_n(&age_param->state,
16792 					      __ATOMIC_RELAXED) == AGE_TMOUT ?
16793 									  1 : 0;
16794 		resp->sec_since_last_hit_valid = !resp->aged;
16795 		if (resp->sec_since_last_hit_valid)
16796 			resp->sec_since_last_hit = __atomic_load_n
16797 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
16798 		return 0;
16799 	case MLX5_INDIRECT_ACTION_TYPE_COUNT:
16800 		return flow_dv_query_count(dev, idx, data, error);
16801 	case MLX5_INDIRECT_ACTION_TYPE_CT:
16802 		owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
16803 		if (owner != PORT_ID(priv))
16804 			return rte_flow_error_set(error, EACCES,
16805 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16806 					NULL,
16807 					"CT object owned by another port");
16808 		dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
16809 		ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
16810 		MLX5_ASSERT(ct);
16811 		if (!ct->refcnt)
16812 			return rte_flow_error_set(error, EFAULT,
16813 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16814 					NULL,
16815 					"CT object is inactive");
16816 		((struct rte_flow_action_conntrack *)data)->peer_port =
16817 							ct->peer;
16818 		((struct rte_flow_action_conntrack *)data)->is_original_dir =
16819 							ct->is_original;
16820 		if (mlx5_aso_ct_query_by_wqe(priv->sh, MLX5_HW_INV_QUEUE, ct,
16821 					data, NULL, true))
16822 			return rte_flow_error_set(error, EIO,
16823 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16824 					NULL,
16825 					"Failed to query CT context");
16826 		return 0;
16827 	default:
16828 		return rte_flow_error_set(error, ENOTSUP,
16829 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
16830 					  "action type query not supported");
16831 	}
16832 }
16833 
16834 /**
16835  * Query a flow rule AGE action for aging information.
16836  *
16837  * @param[in] dev
16838  *   Pointer to Ethernet device.
16839  * @param[in] flow
16840  *   Pointer to the sub flow.
16841  * @param[out] data
16842  *   data retrieved by the query.
16843  * @param[out] error
16844  *   Perform verbose error reporting if not NULL.
16845  *
16846  * @return
16847  *   0 on success, a negative errno value otherwise and rte_errno is set.
16848  */
16849 static int
16850 flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow,
16851 		  void *data, struct rte_flow_error *error)
16852 {
16853 	struct rte_flow_query_age *resp = data;
16854 	struct mlx5_age_param *age_param;
16855 
16856 	if (flow->age) {
16857 		struct mlx5_aso_age_action *act =
16858 				     flow_aso_age_get_by_idx(dev, flow->age);
16859 
16860 		age_param = &act->age_params;
16861 	} else if (flow->counter) {
16862 		age_param = flow_dv_counter_idx_get_age(dev, flow->counter);
16863 
16864 		if (!age_param || !age_param->timeout)
16865 			return rte_flow_error_set
16866 					(error, EINVAL,
16867 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16868 					 NULL, "cannot read age data");
16869 	} else {
16870 		return rte_flow_error_set(error, EINVAL,
16871 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
16872 					  NULL, "age data not available");
16873 	}
16874 	resp->aged = __atomic_load_n(&age_param->state, __ATOMIC_RELAXED) ==
16875 				     AGE_TMOUT ? 1 : 0;
16876 	resp->sec_since_last_hit_valid = !resp->aged;
16877 	if (resp->sec_since_last_hit_valid)
16878 		resp->sec_since_last_hit = __atomic_load_n
16879 			     (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
16880 	return 0;
16881 }
16882 
16883 /**
16884  * Query a flow.
16885  *
16886  * @see rte_flow_query()
16887  * @see rte_flow_ops
16888  */
16889 static int
16890 flow_dv_query(struct rte_eth_dev *dev,
16891 	      struct rte_flow *flow __rte_unused,
16892 	      const struct rte_flow_action *actions __rte_unused,
16893 	      void *data __rte_unused,
16894 	      struct rte_flow_error *error __rte_unused)
16895 {
16896 	int ret = -EINVAL;
16897 
16898 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
16899 		switch (actions->type) {
16900 		case RTE_FLOW_ACTION_TYPE_VOID:
16901 			break;
16902 		case RTE_FLOW_ACTION_TYPE_COUNT:
16903 			ret = flow_dv_query_count(dev, flow->counter, data,
16904 						  error);
16905 			break;
16906 		case RTE_FLOW_ACTION_TYPE_AGE:
16907 			ret = flow_dv_query_age(dev, flow, data, error);
16908 			break;
16909 		default:
16910 			return rte_flow_error_set(error, ENOTSUP,
16911 						  RTE_FLOW_ERROR_TYPE_ACTION,
16912 						  actions,
16913 						  "action not supported");
16914 		}
16915 	}
16916 	return ret;
16917 }
16918 
16919 /**
16920  * Destroy the meter table set.
16921  * Lock free, (mutex should be acquired by caller).
16922  *
16923  * @param[in] dev
16924  *   Pointer to Ethernet device.
16925  * @param[in] fm
16926  *   Meter information table.
16927  */
16928 static void
16929 flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
16930 			struct mlx5_flow_meter_info *fm)
16931 {
16932 	struct mlx5_priv *priv = dev->data->dev_private;
16933 	int i;
16934 
16935 	if (!fm || !priv->sh->config.dv_flow_en)
16936 		return;
16937 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16938 		if (fm->drop_rule[i]) {
16939 			claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
16940 			fm->drop_rule[i] = NULL;
16941 		}
16942 	}
16943 }
16944 
16945 static void
16946 flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
16947 {
16948 	struct mlx5_priv *priv = dev->data->dev_private;
16949 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
16950 	struct mlx5_flow_tbl_data_entry *tbl;
16951 	int i, j;
16952 
16953 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
16954 		if (mtrmng->def_rule[i]) {
16955 			claim_zero(mlx5_flow_os_destroy_flow
16956 					(mtrmng->def_rule[i]));
16957 			mtrmng->def_rule[i] = NULL;
16958 		}
16959 		if (mtrmng->def_matcher[i]) {
16960 			tbl = container_of(mtrmng->def_matcher[i]->tbl,
16961 				struct mlx5_flow_tbl_data_entry, tbl);
16962 			mlx5_list_unregister(tbl->matchers,
16963 					     &mtrmng->def_matcher[i]->entry);
16964 			mtrmng->def_matcher[i] = NULL;
16965 		}
16966 		for (j = 0; j < MLX5_REG_BITS; j++) {
16967 			if (mtrmng->drop_matcher[i][j]) {
16968 				tbl =
16969 				container_of(mtrmng->drop_matcher[i][j]->tbl,
16970 					     struct mlx5_flow_tbl_data_entry,
16971 					     tbl);
16972 				mlx5_list_unregister(tbl->matchers,
16973 					    &mtrmng->drop_matcher[i][j]->entry);
16974 				mtrmng->drop_matcher[i][j] = NULL;
16975 			}
16976 		}
16977 		if (mtrmng->drop_tbl[i]) {
16978 			flow_dv_tbl_resource_release(MLX5_SH(dev),
16979 				mtrmng->drop_tbl[i]);
16980 			mtrmng->drop_tbl[i] = NULL;
16981 		}
16982 	}
16983 }
16984 
16985 /* Number of meter flow actions, count and jump or count and drop. */
16986 #define METER_ACTIONS 2
16987 
16988 static void
16989 __flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
16990 				    enum mlx5_meter_domain domain)
16991 {
16992 	struct mlx5_priv *priv = dev->data->dev_private;
16993 	struct mlx5_flow_meter_def_policy *def_policy =
16994 			priv->sh->mtrmng->def_policy[domain];
16995 
16996 	__flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
16997 	mlx5_free(def_policy);
16998 	priv->sh->mtrmng->def_policy[domain] = NULL;
16999 }
17000 
17001 /**
17002  * Destroy the default policy table set.
17003  *
17004  * @param[in] dev
17005  *   Pointer to Ethernet device.
17006  */
17007 static void
17008 flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
17009 {
17010 	struct mlx5_priv *priv = dev->data->dev_private;
17011 	int i;
17012 
17013 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
17014 		if (priv->sh->mtrmng->def_policy[i])
17015 			__flow_dv_destroy_domain_def_policy(dev,
17016 					(enum mlx5_meter_domain)i);
17017 	priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
17018 }
17019 
17020 static int
17021 __flow_dv_create_policy_flow(struct rte_eth_dev *dev,
17022 			uint32_t color_reg_c_idx,
17023 			enum rte_color color, void *matcher_object,
17024 			int actions_n, void *actions,
17025 			bool match_src_port, const struct rte_flow_item *item,
17026 			void **rule, const struct rte_flow_attr *attr)
17027 {
17028 	int ret;
17029 	struct mlx5_flow_dv_match_params value = {
17030 		.size = sizeof(value.buf),
17031 	};
17032 	struct mlx5_priv *priv = dev->data->dev_private;
17033 	uint8_t misc_mask;
17034 
17035 	if (match_src_port && priv->sh->esw_mode) {
17036 		if (item && item->type == RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT)
17037 			ret = flow_dv_translate_item_represented_port(dev, value.buf,
17038 						item, attr, MLX5_SET_MATCHER_SW_V);
17039 		else if (item && item->type == RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR)
17040 			ret = flow_dv_translate_item_port_representor(dev, value.buf,
17041 								      MLX5_SET_MATCHER_SW_V);
17042 		else
17043 			ret = flow_dv_translate_item_port_id(dev, value.buf,
17044 						item, attr, MLX5_SET_MATCHER_SW_V);
17045 		if (ret) {
17046 			DRV_LOG(ERR, "Failed to create meter policy%d flow's"
17047 				" value with port.", color);
17048 			return -1;
17049 		}
17050 	}
17051 	flow_dv_match_meta_reg(value.buf, (enum modify_reg)color_reg_c_idx,
17052 			       rte_col_2_mlx5_col(color), UINT32_MAX);
17053 	misc_mask = flow_dv_matcher_enable(value.buf);
17054 	__flow_dv_adjust_buf_size(&value.size, misc_mask);
17055 	ret = mlx5_flow_os_create_flow(matcher_object, (void *)&value,
17056 				       actions_n, actions, rule);
17057 	if (ret) {
17058 		DRV_LOG(ERR, "Failed to create meter policy%d flow.", color);
17059 		return -1;
17060 	}
17061 	return 0;
17062 }
17063 
17064 static int
17065 __flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
17066 			uint32_t color_reg_c_idx,
17067 			uint16_t priority,
17068 			struct mlx5_flow_meter_sub_policy *sub_policy,
17069 			const struct rte_flow_attr *attr,
17070 			bool match_src_port,
17071 			const struct rte_flow_item *item,
17072 			struct mlx5_flow_dv_matcher **policy_matcher,
17073 			struct rte_flow_error *error)
17074 {
17075 	struct mlx5_list_entry *entry;
17076 	struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
17077 	struct mlx5_flow_dv_matcher matcher = {
17078 		.mask = {
17079 			.size = sizeof(matcher.mask.buf),
17080 		},
17081 		.tbl = tbl_rsc,
17082 	};
17083 	struct mlx5_flow_cb_ctx ctx = {
17084 		.error = error,
17085 		.data = &matcher,
17086 	};
17087 	struct mlx5_flow_tbl_data_entry *tbl_data;
17088 	struct mlx5_priv *priv = dev->data->dev_private;
17089 	const uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
17090 	int ret;
17091 
17092 	if (match_src_port && priv->sh->esw_mode) {
17093 		if (item && item->type == RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT)
17094 			ret = flow_dv_translate_item_represented_port(dev, matcher.mask.buf,
17095 						item, attr, MLX5_SET_MATCHER_SW_M);
17096 		else if (item && item->type == RTE_FLOW_ITEM_TYPE_PORT_REPRESENTOR)
17097 			ret = flow_dv_translate_item_port_representor(dev, matcher.mask.buf,
17098 								      MLX5_SET_MATCHER_SW_M);
17099 		else
17100 			ret = flow_dv_translate_item_port_id(dev, matcher.mask.buf,
17101 						item, attr, MLX5_SET_MATCHER_SW_M);
17102 		if (ret) {
17103 			DRV_LOG(ERR, "Failed to register meter policy%d matcher"
17104 				" with port.", priority);
17105 			return -1;
17106 		}
17107 	}
17108 	tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
17109 	if (priority < RTE_COLOR_RED)
17110 		flow_dv_match_meta_reg(matcher.mask.buf,
17111 			(enum modify_reg)color_reg_c_idx, color_mask, color_mask);
17112 	matcher.priority = priority;
17113 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
17114 				    matcher.mask.size);
17115 	entry = mlx5_list_register(tbl_data->matchers, &ctx);
17116 	if (!entry) {
17117 		DRV_LOG(ERR, "Failed to register meter drop matcher.");
17118 		return -1;
17119 	}
17120 	*policy_matcher =
17121 		container_of(entry, struct mlx5_flow_dv_matcher, entry);
17122 	return 0;
17123 }
17124 
17125 /**
17126  * Create the policy rules per domain.
17127  *
17128  * @param[in] dev
17129  *   Pointer to Ethernet device.
17130  * @param[in] sub_policy
17131  *    Pointer to sub policy table..
17132  * @param[in] egress
17133  *   Direction of the table.
17134  * @param[in] transfer
17135  *   E-Switch or NIC flow.
17136  * @param[in] acts
17137  *   Pointer to policy action list per color.
17138  *
17139  * @return
17140  *   0 on success, -1 otherwise.
17141  */
17142 static int
17143 __flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
17144 		struct mlx5_flow_meter_sub_policy *sub_policy,
17145 		uint8_t egress, uint8_t transfer, bool match_src_port,
17146 		struct mlx5_meter_policy_acts acts[RTE_COLORS])
17147 {
17148 	struct mlx5_priv *priv = dev->data->dev_private;
17149 	struct rte_flow_error flow_err;
17150 	uint32_t color_reg_c_idx;
17151 	struct rte_flow_attr attr = {
17152 		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
17153 		.priority = 0,
17154 		.ingress = 0,
17155 		.egress = !!egress,
17156 		.transfer = !!transfer,
17157 		.reserved = 0,
17158 	};
17159 	int i;
17160 	int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
17161 	struct mlx5_sub_policy_color_rule *color_rule;
17162 	bool svport_match;
17163 	struct mlx5_sub_policy_color_rule *tmp_rules[RTE_COLORS] = {NULL};
17164 
17165 	if (ret < 0)
17166 		return -1;
17167 	/* Create policy table with POLICY level. */
17168 	if (!sub_policy->tbl_rsc)
17169 		sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
17170 				MLX5_FLOW_TABLE_LEVEL_POLICY,
17171 				egress, transfer, false, NULL, 0, 0,
17172 				sub_policy->idx, &flow_err);
17173 	if (!sub_policy->tbl_rsc) {
17174 		DRV_LOG(ERR,
17175 			"Failed to create meter sub policy table.");
17176 		return -1;
17177 	}
17178 	/* Prepare matchers. */
17179 	color_reg_c_idx = ret;
17180 	for (i = 0; i < RTE_COLORS; i++) {
17181 		TAILQ_INIT(&sub_policy->color_rules[i]);
17182 		if (!acts[i].actions_n)
17183 			continue;
17184 		color_rule = mlx5_malloc(MLX5_MEM_ZERO,
17185 				sizeof(struct mlx5_sub_policy_color_rule),
17186 				0, SOCKET_ID_ANY);
17187 		if (!color_rule) {
17188 			DRV_LOG(ERR, "No memory to create color rule.");
17189 			goto err_exit;
17190 		}
17191 		tmp_rules[i] = color_rule;
17192 		TAILQ_INSERT_TAIL(&sub_policy->color_rules[i],
17193 				  color_rule, next_port);
17194 		color_rule->src_port = priv->representor_id;
17195 		/* No use. */
17196 		attr.priority = i;
17197 		/* Create matchers for colors. */
17198 		svport_match = (i != RTE_COLOR_RED) ? match_src_port : false;
17199 		if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
17200 				MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
17201 				&attr, svport_match, NULL,
17202 				&color_rule->matcher, &flow_err)) {
17203 			DRV_LOG(ERR, "Failed to create color%u matcher.", i);
17204 			goto err_exit;
17205 		}
17206 		/* Create flow, matching color. */
17207 		if (__flow_dv_create_policy_flow(dev,
17208 				color_reg_c_idx, (enum rte_color)i,
17209 				color_rule->matcher->matcher_object,
17210 				acts[i].actions_n, acts[i].dv_actions,
17211 				svport_match, NULL, &color_rule->rule,
17212 				&attr)) {
17213 			DRV_LOG(ERR, "Failed to create color%u rule.", i);
17214 			goto err_exit;
17215 		}
17216 	}
17217 	return 0;
17218 err_exit:
17219 	/* All the policy rules will be cleared. */
17220 	do {
17221 		color_rule = tmp_rules[i];
17222 		if (color_rule) {
17223 			if (color_rule->rule)
17224 				mlx5_flow_os_destroy_flow(color_rule->rule);
17225 			if (color_rule->matcher) {
17226 				struct mlx5_flow_tbl_data_entry *tbl =
17227 					container_of(color_rule->matcher->tbl,
17228 						     typeof(*tbl), tbl);
17229 				mlx5_list_unregister(tbl->matchers,
17230 						&color_rule->matcher->entry);
17231 			}
17232 			TAILQ_REMOVE(&sub_policy->color_rules[i],
17233 				     color_rule, next_port);
17234 			mlx5_free(color_rule);
17235 		}
17236 	} while (i--);
17237 	return -1;
17238 }
17239 
17240 static int
17241 __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
17242 			struct mlx5_flow_meter_policy *mtr_policy,
17243 			struct mlx5_flow_meter_sub_policy *sub_policy,
17244 			uint32_t domain)
17245 {
17246 	struct mlx5_priv *priv = dev->data->dev_private;
17247 	struct mlx5_meter_policy_acts acts[RTE_COLORS];
17248 	struct mlx5_flow_dv_tag_resource *tag;
17249 	struct mlx5_flow_dv_port_id_action_resource *port_action;
17250 	struct mlx5_hrxq *hrxq;
17251 	struct mlx5_flow_meter_info *next_fm[RTE_COLORS] = {NULL};
17252 	struct mlx5_flow_meter_policy *next_policy;
17253 	struct mlx5_flow_meter_sub_policy *next_sub_policy;
17254 	struct mlx5_flow_tbl_data_entry *tbl_data;
17255 	struct rte_flow_error error;
17256 	uint8_t egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
17257 	uint8_t transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
17258 	bool mtr_first = egress || (transfer && priv->representor_id != UINT16_MAX);
17259 	bool match_src_port = false;
17260 	int i;
17261 
17262 	/* If RSS or Queue, no previous actions / rules is created. */
17263 	for (i = 0; i < RTE_COLORS; i++) {
17264 		acts[i].actions_n = 0;
17265 		if (i == RTE_COLOR_RED) {
17266 			/* Only support drop on red. */
17267 			acts[i].dv_actions[0] =
17268 				mtr_policy->dr_drop_action[domain];
17269 			acts[i].actions_n = 1;
17270 			continue;
17271 		}
17272 		if (mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) {
17273 			struct rte_flow_attr attr = {
17274 				.transfer = transfer
17275 			};
17276 
17277 			next_fm[i] = mlx5_flow_meter_find(priv,
17278 					mtr_policy->act_cnt[i].next_mtr_id,
17279 					NULL);
17280 			if (!next_fm[i]) {
17281 				DRV_LOG(ERR,
17282 					"Failed to get next hierarchy meter.");
17283 				goto err_exit;
17284 			}
17285 			if (mlx5_flow_meter_attach(priv, next_fm[i],
17286 						   &attr, &error)) {
17287 				DRV_LOG(ERR, "%s", error.message);
17288 				next_fm[i] = NULL;
17289 				goto err_exit;
17290 			}
17291 			/* Meter action must be the first for TX. */
17292 			if (mtr_first) {
17293 				acts[i].dv_actions[acts[i].actions_n] =
17294 					(next_fm[i]->color_aware && i == RTE_COLOR_YELLOW) ?
17295 						next_fm[i]->meter_action_y :
17296 						next_fm[i]->meter_action_g;
17297 				acts[i].actions_n++;
17298 			}
17299 		}
17300 		if (mtr_policy->act_cnt[i].rix_mark) {
17301 			tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
17302 					mtr_policy->act_cnt[i].rix_mark);
17303 			if (!tag) {
17304 				DRV_LOG(ERR, "Failed to find "
17305 				"mark action for policy.");
17306 				goto err_exit;
17307 			}
17308 			acts[i].dv_actions[acts[i].actions_n] = tag->action;
17309 			acts[i].actions_n++;
17310 		}
17311 		if (mtr_policy->act_cnt[i].modify_hdr) {
17312 			acts[i].dv_actions[acts[i].actions_n] =
17313 				mtr_policy->act_cnt[i].modify_hdr->action;
17314 			acts[i].actions_n++;
17315 		}
17316 		if (mtr_policy->act_cnt[i].fate_action) {
17317 			switch (mtr_policy->act_cnt[i].fate_action) {
17318 			case MLX5_FLOW_FATE_PORT_ID:
17319 				port_action = mlx5_ipool_get
17320 					(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
17321 				mtr_policy->act_cnt[i].rix_port_id_action);
17322 				if (!port_action) {
17323 					DRV_LOG(ERR, "Failed to find "
17324 						"port action for policy.");
17325 					goto err_exit;
17326 				}
17327 				acts[i].dv_actions[acts[i].actions_n] =
17328 					port_action->action;
17329 				acts[i].actions_n++;
17330 				match_src_port = true;
17331 				break;
17332 			case MLX5_FLOW_FATE_DROP:
17333 			case MLX5_FLOW_FATE_JUMP:
17334 				acts[i].dv_actions[acts[i].actions_n] =
17335 				mtr_policy->act_cnt[i].dr_jump_action[domain];
17336 				acts[i].actions_n++;
17337 				break;
17338 			case MLX5_FLOW_FATE_SHARED_RSS:
17339 			case MLX5_FLOW_FATE_QUEUE:
17340 				hrxq = mlx5_ipool_get
17341 					(priv->sh->ipool[MLX5_IPOOL_HRXQ],
17342 					 sub_policy->rix_hrxq[i]);
17343 				if (!hrxq) {
17344 					DRV_LOG(ERR, "Failed to find "
17345 						"queue action for policy.");
17346 					goto err_exit;
17347 				}
17348 				acts[i].dv_actions[acts[i].actions_n] =
17349 					hrxq->action;
17350 				acts[i].actions_n++;
17351 				break;
17352 			case MLX5_FLOW_FATE_MTR:
17353 				if (!next_fm[i]) {
17354 					DRV_LOG(ERR,
17355 						"No next hierarchy meter.");
17356 					goto err_exit;
17357 				}
17358 				if (!mtr_first) {
17359 					acts[i].dv_actions[acts[i].actions_n] =
17360 						(next_fm[i]->color_aware && i == RTE_COLOR_YELLOW) ?
17361 							next_fm[i]->meter_action_y :
17362 							next_fm[i]->meter_action_g;
17363 					acts[i].actions_n++;
17364 				}
17365 				if (mtr_policy->act_cnt[i].next_sub_policy) {
17366 					next_sub_policy =
17367 					mtr_policy->act_cnt[i].next_sub_policy;
17368 				} else {
17369 					next_policy =
17370 						mlx5_flow_meter_policy_find(dev,
17371 								next_fm[i]->policy_id, NULL);
17372 					MLX5_ASSERT(next_policy);
17373 					next_sub_policy =
17374 					next_policy->sub_policys[domain][0];
17375 				}
17376 				tbl_data =
17377 					container_of(next_sub_policy->tbl_rsc,
17378 					struct mlx5_flow_tbl_data_entry, tbl);
17379 				acts[i].dv_actions[acts[i].actions_n++] =
17380 							tbl_data->jump.action;
17381 				if (mtr_policy->act_cnt[i].modify_hdr)
17382 					match_src_port = !!transfer;
17383 				break;
17384 			default:
17385 				/*Queue action do nothing*/
17386 				break;
17387 			}
17388 		}
17389 	}
17390 	if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
17391 				egress, transfer, match_src_port, acts)) {
17392 		DRV_LOG(ERR,
17393 			"Failed to create policy rules per domain.");
17394 		goto err_exit;
17395 	}
17396 	if (match_src_port) {
17397 		mtr_policy->match_port = match_src_port;
17398 		mtr_policy->hierarchy_match_port = match_src_port;
17399 	}
17400 	return 0;
17401 err_exit:
17402 	for (i = 0; i < RTE_COLORS; i++)
17403 		if (next_fm[i])
17404 			mlx5_flow_meter_detach(priv, next_fm[i]);
17405 	return -1;
17406 }
17407 
17408 /**
17409  * Create the policy rules.
17410  *
17411  * @param[in] dev
17412  *   Pointer to Ethernet device.
17413  * @param[in,out] mtr_policy
17414  *   Pointer to meter policy table.
17415  *
17416  * @return
17417  *   0 on success, -1 otherwise.
17418  */
17419 static int
17420 flow_dv_create_policy_rules(struct rte_eth_dev *dev,
17421 			     struct mlx5_flow_meter_policy *mtr_policy)
17422 {
17423 	int i;
17424 	int ret = 0;
17425 	uint16_t sub_policy_num;
17426 	struct mlx5_flow_workspace *wks = mlx5_flow_push_thread_workspace();
17427 
17428 	RTE_SET_USED(wks);
17429 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
17430 		sub_policy_num = (mtr_policy->sub_policy_num >>
17431 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
17432 			MLX5_MTR_SUB_POLICY_NUM_MASK;
17433 		if (!sub_policy_num)
17434 			continue;
17435 		/* Prepare actions list and create policy rules. */
17436 		if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
17437 			mtr_policy->sub_policys[i][0], i)) {
17438 			DRV_LOG(ERR, "Failed to create policy action "
17439 				"list per domain.");
17440 			ret = -1;
17441 			goto exit;
17442 		}
17443 	}
17444 exit:
17445 	mlx5_flow_pop_thread_workspace();
17446 	return ret;
17447 }
17448 
17449 static int
17450 __flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
17451 {
17452 	struct mlx5_priv *priv = dev->data->dev_private;
17453 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
17454 	struct mlx5_flow_meter_def_policy *def_policy;
17455 	struct mlx5_flow_tbl_resource *jump_tbl;
17456 	struct mlx5_flow_tbl_data_entry *tbl_data;
17457 	uint8_t egress, transfer;
17458 	struct rte_flow_error error;
17459 	struct mlx5_meter_policy_acts acts[RTE_COLORS];
17460 	int ret;
17461 
17462 	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
17463 	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
17464 	def_policy = mtrmng->def_policy[domain];
17465 	if (!def_policy) {
17466 		def_policy = mlx5_malloc(MLX5_MEM_ZERO,
17467 			sizeof(struct mlx5_flow_meter_def_policy),
17468 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
17469 		if (!def_policy) {
17470 			DRV_LOG(ERR, "Failed to alloc default policy table.");
17471 			goto def_policy_error;
17472 		}
17473 		mtrmng->def_policy[domain] = def_policy;
17474 		/* Create the meter suffix table with SUFFIX level. */
17475 		jump_tbl = flow_dv_tbl_resource_get(dev,
17476 				MLX5_FLOW_TABLE_LEVEL_METER,
17477 				egress, transfer, false, NULL, 0,
17478 				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
17479 		if (!jump_tbl) {
17480 			DRV_LOG(ERR,
17481 				"Failed to create meter suffix table.");
17482 			goto def_policy_error;
17483 		}
17484 		def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
17485 		tbl_data = container_of(jump_tbl,
17486 					struct mlx5_flow_tbl_data_entry, tbl);
17487 		def_policy->dr_jump_action[RTE_COLOR_GREEN] =
17488 						tbl_data->jump.action;
17489 		acts[RTE_COLOR_GREEN].dv_actions[0] = tbl_data->jump.action;
17490 		acts[RTE_COLOR_GREEN].actions_n = 1;
17491 		/*
17492 		 * YELLOW has the same default policy as GREEN does.
17493 		 * G & Y share the same table and action. The 2nd time of table
17494 		 * resource getting is just to update the reference count for
17495 		 * the releasing stage.
17496 		 */
17497 		jump_tbl = flow_dv_tbl_resource_get(dev,
17498 				MLX5_FLOW_TABLE_LEVEL_METER,
17499 				egress, transfer, false, NULL, 0,
17500 				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
17501 		if (!jump_tbl) {
17502 			DRV_LOG(ERR,
17503 				"Failed to get meter suffix table.");
17504 			goto def_policy_error;
17505 		}
17506 		def_policy->sub_policy.jump_tbl[RTE_COLOR_YELLOW] = jump_tbl;
17507 		tbl_data = container_of(jump_tbl,
17508 					struct mlx5_flow_tbl_data_entry, tbl);
17509 		def_policy->dr_jump_action[RTE_COLOR_YELLOW] =
17510 						tbl_data->jump.action;
17511 		acts[RTE_COLOR_YELLOW].dv_actions[0] = tbl_data->jump.action;
17512 		acts[RTE_COLOR_YELLOW].actions_n = 1;
17513 		/* Create jump action to the drop table. */
17514 		if (!mtrmng->drop_tbl[domain]) {
17515 			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
17516 				(dev, MLX5_FLOW_TABLE_LEVEL_METER,
17517 				 egress, transfer, false, NULL, 0,
17518 				 0, MLX5_MTR_TABLE_ID_DROP, &error);
17519 			if (!mtrmng->drop_tbl[domain]) {
17520 				DRV_LOG(ERR, "Failed to create meter "
17521 					"drop table for default policy.");
17522 				goto def_policy_error;
17523 			}
17524 		}
17525 		/* all RED: unique Drop table for jump action. */
17526 		tbl_data = container_of(mtrmng->drop_tbl[domain],
17527 					struct mlx5_flow_tbl_data_entry, tbl);
17528 		def_policy->dr_jump_action[RTE_COLOR_RED] =
17529 						tbl_data->jump.action;
17530 		acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
17531 		acts[RTE_COLOR_RED].actions_n = 1;
17532 		/* Create default policy rules. */
17533 		ret = __flow_dv_create_domain_policy_rules(dev,
17534 					&def_policy->sub_policy,
17535 					egress, transfer, false, acts);
17536 		if (ret) {
17537 			DRV_LOG(ERR, "Failed to create default policy rules.");
17538 			goto def_policy_error;
17539 		}
17540 	}
17541 	return 0;
17542 def_policy_error:
17543 	__flow_dv_destroy_domain_def_policy(dev,
17544 					    (enum mlx5_meter_domain)domain);
17545 	return -1;
17546 }
17547 
17548 /**
17549  * Create the default policy table set.
17550  *
17551  * @param[in] dev
17552  *   Pointer to Ethernet device.
17553  * @return
17554  *   0 on success, -1 otherwise.
17555  */
17556 static int
17557 flow_dv_create_def_policy(struct rte_eth_dev *dev)
17558 {
17559 	struct mlx5_priv *priv = dev->data->dev_private;
17560 	int i;
17561 
17562 	/* Non-termination policy table. */
17563 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
17564 		if (!priv->sh->config.dv_esw_en &&
17565 		    i == MLX5_MTR_DOMAIN_TRANSFER)
17566 			continue;
17567 		if (__flow_dv_create_domain_def_policy(dev, i)) {
17568 			DRV_LOG(ERR, "Failed to create default policy");
17569 			/* Rollback the created default policies for others. */
17570 			flow_dv_destroy_def_policy(dev);
17571 			return -1;
17572 		}
17573 	}
17574 	return 0;
17575 }
17576 
17577 /**
17578  * Create the needed meter tables.
17579  * Lock free, (mutex should be acquired by caller).
17580  *
17581  * @param[in] dev
17582  *   Pointer to Ethernet device.
17583  * @param[in] fm
17584  *   Meter information table.
17585  * @param[in] mtr_idx
17586  *   Meter index.
17587  * @param[in] domain_bitmap
17588  *   Domain bitmap.
17589  * @return
17590  *   0 on success, -1 otherwise.
17591  */
17592 static int
17593 flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
17594 			struct mlx5_flow_meter_info *fm,
17595 			uint32_t mtr_idx,
17596 			uint8_t domain_bitmap)
17597 {
17598 	struct mlx5_priv *priv = dev->data->dev_private;
17599 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
17600 	struct rte_flow_error error;
17601 	struct mlx5_flow_tbl_data_entry *tbl_data;
17602 	uint8_t egress, transfer;
17603 	void *actions[METER_ACTIONS];
17604 	int domain, ret, i;
17605 	struct mlx5_flow_counter *cnt;
17606 	struct mlx5_flow_dv_match_params value = {
17607 		.size = sizeof(value.buf),
17608 	};
17609 	struct mlx5_flow_dv_match_params matcher_para = {
17610 		.size = sizeof(matcher_para.buf),
17611 	};
17612 	int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
17613 						     0, &error);
17614 	uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1;
17615 	uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
17616 	struct mlx5_list_entry *entry;
17617 	struct mlx5_flow_dv_matcher matcher = {
17618 		.mask = {
17619 			.size = sizeof(matcher.mask.buf),
17620 		},
17621 	};
17622 	struct mlx5_flow_dv_matcher *drop_matcher;
17623 	struct mlx5_flow_cb_ctx ctx = {
17624 		.error = &error,
17625 		.data = &matcher,
17626 	};
17627 	uint8_t misc_mask;
17628 
17629 	if (!priv->mtr_en || mtr_id_reg_c < 0) {
17630 		rte_errno = ENOTSUP;
17631 		return -1;
17632 	}
17633 	for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
17634 		if (!(domain_bitmap & (1 << domain)) ||
17635 			(mtrmng->def_rule[domain] && !fm->drop_cnt))
17636 			continue;
17637 		egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
17638 		transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
17639 		/* Create the drop table with METER DROP level. */
17640 		if (!mtrmng->drop_tbl[domain]) {
17641 			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev,
17642 					MLX5_FLOW_TABLE_LEVEL_METER,
17643 					egress, transfer, false, NULL, 0,
17644 					0, MLX5_MTR_TABLE_ID_DROP, &error);
17645 			if (!mtrmng->drop_tbl[domain]) {
17646 				DRV_LOG(ERR, "Failed to create meter drop table.");
17647 				goto policy_error;
17648 			}
17649 		}
17650 		/* Create default matcher in drop table. */
17651 		matcher.tbl = mtrmng->drop_tbl[domain],
17652 		tbl_data = container_of(mtrmng->drop_tbl[domain],
17653 				struct mlx5_flow_tbl_data_entry, tbl);
17654 		if (!mtrmng->def_matcher[domain]) {
17655 			flow_dv_match_meta_reg_all(matcher.mask.buf, value.buf,
17656 				       (enum modify_reg)mtr_id_reg_c,
17657 				       0, 0);
17658 			matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
17659 			matcher.crc = rte_raw_cksum
17660 					((const void *)matcher.mask.buf,
17661 					matcher.mask.size);
17662 			entry = mlx5_list_register(tbl_data->matchers, &ctx);
17663 			if (!entry) {
17664 				DRV_LOG(ERR, "Failed to register meter "
17665 				"drop default matcher.");
17666 				goto policy_error;
17667 			}
17668 			mtrmng->def_matcher[domain] = container_of(entry,
17669 			struct mlx5_flow_dv_matcher, entry);
17670 		}
17671 		/* Create default rule in drop table. */
17672 		if (!mtrmng->def_rule[domain]) {
17673 			i = 0;
17674 			actions[i++] = priv->sh->dr_drop_action;
17675 			flow_dv_match_meta_reg_all(matcher_para.buf, value.buf,
17676 				(enum modify_reg)mtr_id_reg_c, 0, 0);
17677 			misc_mask = flow_dv_matcher_enable(value.buf);
17678 			__flow_dv_adjust_buf_size(&value.size, misc_mask);
17679 			ret = mlx5_flow_os_create_flow
17680 				(mtrmng->def_matcher[domain]->matcher_object,
17681 				(void *)&value, i, actions,
17682 				&mtrmng->def_rule[domain]);
17683 			if (ret) {
17684 				DRV_LOG(ERR, "Failed to create meter "
17685 				"default drop rule for drop table.");
17686 				goto policy_error;
17687 			}
17688 		}
17689 		if (!fm->drop_cnt)
17690 			continue;
17691 		MLX5_ASSERT(mtrmng->max_mtr_bits);
17692 		if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) {
17693 			/* Create matchers for Drop. */
17694 			flow_dv_match_meta_reg_all(matcher.mask.buf, value.buf,
17695 					(enum modify_reg)mtr_id_reg_c, 0,
17696 					(mtr_id_mask << mtr_id_offset));
17697 			matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
17698 			matcher.crc = rte_raw_cksum
17699 					((const void *)matcher.mask.buf,
17700 					matcher.mask.size);
17701 			entry = mlx5_list_register(tbl_data->matchers, &ctx);
17702 			if (!entry) {
17703 				DRV_LOG(ERR,
17704 				"Failed to register meter drop matcher.");
17705 				goto policy_error;
17706 			}
17707 			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] =
17708 				container_of(entry, struct mlx5_flow_dv_matcher,
17709 					     entry);
17710 		}
17711 		drop_matcher =
17712 			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1];
17713 		/* Create drop rule, matching meter_id only. */
17714 		flow_dv_match_meta_reg_all(matcher_para.buf, value.buf,
17715 				(enum modify_reg)mtr_id_reg_c,
17716 				(mtr_idx << mtr_id_offset), UINT32_MAX);
17717 		i = 0;
17718 		cnt = flow_dv_counter_get_by_idx(dev,
17719 					fm->drop_cnt, NULL);
17720 		actions[i++] = cnt->action;
17721 		actions[i++] = priv->sh->dr_drop_action;
17722 		misc_mask = flow_dv_matcher_enable(value.buf);
17723 		__flow_dv_adjust_buf_size(&value.size, misc_mask);
17724 		ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
17725 					       (void *)&value, i, actions,
17726 					       &fm->drop_rule[domain]);
17727 		if (ret) {
17728 			DRV_LOG(ERR, "Failed to create meter "
17729 				"drop rule for drop table.");
17730 				goto policy_error;
17731 		}
17732 	}
17733 	return 0;
17734 policy_error:
17735 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
17736 		if (fm->drop_rule[i]) {
17737 			claim_zero(mlx5_flow_os_destroy_flow
17738 				(fm->drop_rule[i]));
17739 			fm->drop_rule[i] = NULL;
17740 		}
17741 	}
17742 	return -1;
17743 }
17744 
17745 static struct mlx5_flow_meter_sub_policy *
17746 __flow_dv_meter_get_rss_sub_policy(struct rte_eth_dev *dev,
17747 		struct mlx5_flow_meter_policy *mtr_policy,
17748 		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS],
17749 		struct mlx5_flow_meter_sub_policy *next_sub_policy,
17750 		bool *is_reuse)
17751 {
17752 	struct mlx5_priv *priv = dev->data->dev_private;
17753 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
17754 	uint32_t sub_policy_idx = 0;
17755 	uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
17756 	uint32_t i, j;
17757 	struct mlx5_hrxq *hrxq;
17758 	struct mlx5_flow_handle dh;
17759 	struct mlx5_meter_policy_action_container *act_cnt;
17760 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
17761 	uint16_t sub_policy_num;
17762 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
17763 
17764 	MLX5_ASSERT(wks);
17765 	rte_spinlock_lock(&mtr_policy->sl);
17766 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
17767 		if (!rss_desc[i])
17768 			continue;
17769 		hrxq = mlx5_hrxq_get(dev, rss_desc[i]);
17770 		if (!hrxq) {
17771 			rte_spinlock_unlock(&mtr_policy->sl);
17772 			return NULL;
17773 		}
17774 		hrxq_idx[i] = hrxq->idx;
17775 	}
17776 	sub_policy_num = (mtr_policy->sub_policy_num >>
17777 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
17778 			MLX5_MTR_SUB_POLICY_NUM_MASK;
17779 	for (j = 0; j < sub_policy_num; j++) {
17780 		for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
17781 			if (rss_desc[i] &&
17782 			    hrxq_idx[i] !=
17783 			    mtr_policy->sub_policys[domain][j]->rix_hrxq[i])
17784 				break;
17785 		}
17786 		if (i >= MLX5_MTR_RTE_COLORS) {
17787 			/*
17788 			 * Found the sub policy table with
17789 			 * the same queue per color.
17790 			 */
17791 			rte_spinlock_unlock(&mtr_policy->sl);
17792 			for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
17793 				mlx5_hrxq_release(dev, hrxq_idx[i]);
17794 			*is_reuse = true;
17795 			return mtr_policy->sub_policys[domain][j];
17796 		}
17797 	}
17798 	/* Create sub policy. */
17799 	if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[RTE_COLOR_GREEN] &&
17800 	    !mtr_policy->sub_policys[domain][0]->rix_hrxq[RTE_COLOR_YELLOW]) {
17801 		/* Reuse the first pre-allocated sub_policy. */
17802 		sub_policy = mtr_policy->sub_policys[domain][0];
17803 		sub_policy_idx = sub_policy->idx;
17804 	} else {
17805 		sub_policy = mlx5_ipool_zmalloc
17806 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
17807 				 &sub_policy_idx);
17808 		if (!sub_policy ||
17809 		    sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM) {
17810 			for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
17811 				mlx5_hrxq_release(dev, hrxq_idx[i]);
17812 			goto rss_sub_policy_error;
17813 		}
17814 		sub_policy->idx = sub_policy_idx;
17815 		sub_policy->main_policy = mtr_policy;
17816 	}
17817 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
17818 		if (!rss_desc[i])
17819 			continue;
17820 		sub_policy->rix_hrxq[i] = hrxq_idx[i];
17821 		if (mtr_policy->is_hierarchy) {
17822 			act_cnt = &mtr_policy->act_cnt[i];
17823 			act_cnt->next_sub_policy = next_sub_policy;
17824 			mlx5_hrxq_release(dev, hrxq_idx[i]);
17825 		} else {
17826 			/*
17827 			 * Overwrite the last action from
17828 			 * RSS action to Queue action.
17829 			 */
17830 			hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
17831 					      hrxq_idx[i]);
17832 			if (!hrxq) {
17833 				DRV_LOG(ERR, "Failed to get policy hrxq");
17834 				goto rss_sub_policy_error;
17835 			}
17836 			act_cnt = &mtr_policy->act_cnt[i];
17837 			if (act_cnt->rix_mark || act_cnt->modify_hdr) {
17838 				memset(&dh, 0, sizeof(struct mlx5_flow_handle));
17839 				if (act_cnt->rix_mark)
17840 					wks->mark = 1;
17841 				dh.fate_action = MLX5_FLOW_FATE_QUEUE;
17842 				dh.rix_hrxq = hrxq_idx[i];
17843 				flow_drv_rxq_flags_set(dev, &dh);
17844 			}
17845 		}
17846 	}
17847 	if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
17848 					       sub_policy, domain)) {
17849 		DRV_LOG(ERR, "Failed to create policy "
17850 			"rules for ingress domain.");
17851 		goto rss_sub_policy_error;
17852 	}
17853 	if (sub_policy != mtr_policy->sub_policys[domain][0]) {
17854 		i = (mtr_policy->sub_policy_num >>
17855 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
17856 			MLX5_MTR_SUB_POLICY_NUM_MASK;
17857 		if (i >= MLX5_MTR_RSS_MAX_SUB_POLICY) {
17858 			DRV_LOG(ERR, "No free sub-policy slot.");
17859 			goto rss_sub_policy_error;
17860 		}
17861 		mtr_policy->sub_policys[domain][i] = sub_policy;
17862 		i++;
17863 		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
17864 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
17865 		mtr_policy->sub_policy_num |=
17866 			(i & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
17867 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
17868 	}
17869 	rte_spinlock_unlock(&mtr_policy->sl);
17870 	*is_reuse = false;
17871 	return sub_policy;
17872 rss_sub_policy_error:
17873 	if (sub_policy) {
17874 		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
17875 		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
17876 			i = (mtr_policy->sub_policy_num >>
17877 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
17878 			MLX5_MTR_SUB_POLICY_NUM_MASK;
17879 			mtr_policy->sub_policys[domain][i] = NULL;
17880 			mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
17881 					sub_policy->idx);
17882 		}
17883 	}
17884 	rte_spinlock_unlock(&mtr_policy->sl);
17885 	return NULL;
17886 }
17887 
17888 /**
17889  * Find the policy table for prefix table with RSS.
17890  *
17891  * @param[in] dev
17892  *   Pointer to Ethernet device.
17893  * @param[in] mtr_policy
17894  *   Pointer to meter policy table.
17895  * @param[in] rss_desc
17896  *   Pointer to rss_desc
17897  * @return
17898  *   Pointer to table set on success, NULL otherwise and rte_errno is set.
17899  */
17900 static struct mlx5_flow_meter_sub_policy *
17901 flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
17902 		struct mlx5_flow_meter_policy *mtr_policy,
17903 		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
17904 {
17905 	struct mlx5_priv *priv = dev->data->dev_private;
17906 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
17907 	struct mlx5_flow_meter_info *next_fm;
17908 	struct mlx5_flow_meter_policy *next_policy;
17909 	struct mlx5_flow_meter_sub_policy *next_sub_policy = NULL;
17910 	struct mlx5_flow_meter_policy *policies[MLX5_MTR_CHAIN_MAX_NUM];
17911 	struct mlx5_flow_meter_sub_policy *sub_policies[MLX5_MTR_CHAIN_MAX_NUM];
17912 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
17913 	bool reuse_sub_policy;
17914 	uint32_t i = 0;
17915 	uint32_t j = 0;
17916 
17917 	while (true) {
17918 		/* Iterate hierarchy to get all policies in this hierarchy. */
17919 		policies[i++] = mtr_policy;
17920 		if (!mtr_policy->is_hierarchy)
17921 			break;
17922 		if (i >= MLX5_MTR_CHAIN_MAX_NUM) {
17923 			DRV_LOG(ERR, "Exceed max meter number in hierarchy.");
17924 			return NULL;
17925 		}
17926 		rte_spinlock_lock(&mtr_policy->sl);
17927 		next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, mtr_policy, NULL);
17928 		rte_spinlock_unlock(&mtr_policy->sl);
17929 		if (!next_fm) {
17930 			DRV_LOG(ERR, "Failed to get next meter in hierarchy.");
17931 			return NULL;
17932 		}
17933 		next_policy =
17934 			mlx5_flow_meter_policy_find(dev, next_fm->policy_id,
17935 						    NULL);
17936 		MLX5_ASSERT(next_policy);
17937 		mtr_policy = next_policy;
17938 	}
17939 	while (i) {
17940 		/**
17941 		 * From last policy to the first one in hierarchy,
17942 		 * create / get the sub policy for each of them.
17943 		 */
17944 		sub_policy = __flow_dv_meter_get_rss_sub_policy(dev,
17945 							policies[--i],
17946 							rss_desc,
17947 							next_sub_policy,
17948 							&reuse_sub_policy);
17949 		if (!sub_policy) {
17950 			DRV_LOG(ERR, "Failed to get the sub policy.");
17951 			goto err_exit;
17952 		}
17953 		if (!reuse_sub_policy)
17954 			sub_policies[j++] = sub_policy;
17955 		next_sub_policy = sub_policy;
17956 	}
17957 	return sub_policy;
17958 err_exit:
17959 	while (j) {
17960 		uint16_t sub_policy_num;
17961 
17962 		sub_policy = sub_policies[--j];
17963 		mtr_policy = sub_policy->main_policy;
17964 		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
17965 		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
17966 			sub_policy_num = (mtr_policy->sub_policy_num >>
17967 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
17968 				MLX5_MTR_SUB_POLICY_NUM_MASK;
17969 			mtr_policy->sub_policys[domain][sub_policy_num - 1] =
17970 									NULL;
17971 			sub_policy_num--;
17972 			mtr_policy->sub_policy_num &=
17973 				~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
17974 				  (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
17975 			mtr_policy->sub_policy_num |=
17976 			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
17977 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
17978 			mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
17979 					sub_policy->idx);
17980 		}
17981 	}
17982 	return NULL;
17983 }
17984 
17985 /**
17986  * Check if need to create hierarchy tag rule.
17987  *
17988  * @param[in] priv
17989  *   Pointer to mlx5_priv.
17990  * @param[in] mtr_policy
17991  *   Pointer to current meter policy.
17992  * @param[in] src_port
17993  *   The src port this extra rule should use.
17994  * @param[out] next_fm
17995  *   Pointer to next meter in hierarchy.
17996  * @param[out] skip
17997  *   Indicate if skip the tag rule creation.
17998  * @param[out] error
17999  *   Perform verbose error reporting if not NULL.
18000  * @return
18001  *   0 on success, a negative errno value otherwise and rte_errno is set.
18002  */
18003 static int
18004 mlx5_meter_hierarchy_skip_tag_rule(struct mlx5_priv *priv,
18005 				   struct mlx5_flow_meter_policy *mtr_policy,
18006 				   int32_t src_port,
18007 				   struct mlx5_flow_meter_info **next_fm,
18008 				   bool *skip,
18009 				   struct rte_flow_error *error)
18010 {
18011 	struct mlx5_flow_meter_sub_policy *sub_policy;
18012 	struct mlx5_sub_policy_color_rule *color_rule;
18013 	uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER;
18014 	int ret = 0;
18015 	int i;
18016 
18017 	*next_fm = NULL;
18018 	*skip = false;
18019 	rte_spinlock_lock(&mtr_policy->sl);
18020 	if (mtr_policy->is_hierarchy) {
18021 		*next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, mtr_policy, NULL);
18022 		if (!*next_fm) {
18023 			ret = rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
18024 						NULL, "Failed to find next meter in hierarchy.");
18025 			goto exit;
18026 		}
18027 	}
18028 	if (!mtr_policy->match_port) {
18029 		*skip = true;
18030 		goto exit;
18031 	}
18032 	sub_policy = mtr_policy->sub_policys[domain][0];
18033 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
18034 		if (mtr_policy->act_cnt[i].fate_action != MLX5_FLOW_FATE_MTR &&
18035 		    mtr_policy->act_cnt[i].fate_action != MLX5_FLOW_FATE_PORT_ID)
18036 			continue;
18037 		TAILQ_FOREACH(color_rule, &sub_policy->color_rules[i], next_port)
18038 			if (color_rule->src_port == src_port) {
18039 				*skip = true;
18040 				goto exit;
18041 			}
18042 	}
18043 exit:
18044 	rte_spinlock_unlock(&mtr_policy->sl);
18045 	return ret;
18046 }
18047 
18048 /**
18049  * Create the sub policy tag rule for all meters in hierarchy.
18050  *
18051  * @param[in] dev
18052  *   Pointer to Ethernet device.
18053  * @param[in] fm
18054  *   Meter information table.
18055  * @param[in] src_port
18056  *   The src port this extra rule should use.
18057  * @param[in] item
18058  *   The src port match item.
18059  * @param[out] error
18060  *   Perform verbose error reporting if not NULL.
18061  * @return
18062  *   0 on success, a negative errno value otherwise and rte_errno is set.
18063  */
18064 static int
18065 flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev,
18066 				struct mlx5_flow_meter_info *fm,
18067 				int32_t src_port,
18068 				const struct rte_flow_item *item,
18069 				struct rte_flow_error *error)
18070 {
18071 	struct mlx5_priv *priv = dev->data->dev_private;
18072 	struct mlx5_flow_meter_policy *mtr_policy;
18073 	struct mlx5_flow_meter_sub_policy *sub_policy;
18074 	struct mlx5_flow_meter_info *next_fm = NULL;
18075 	struct mlx5_flow_meter_policy *next_policy;
18076 	struct mlx5_flow_meter_sub_policy *next_sub_policy;
18077 	struct mlx5_flow_tbl_data_entry *tbl_data;
18078 	struct mlx5_sub_policy_color_rule *color_rule;
18079 	struct mlx5_meter_policy_acts acts;
18080 	uint32_t color_reg_c_idx;
18081 	bool mtr_first = (src_port != UINT16_MAX) ? true : false;
18082 	struct rte_flow_attr attr = {
18083 		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
18084 		.priority = 0,
18085 		.ingress = 0,
18086 		.egress = 0,
18087 		.transfer = 1,
18088 		.reserved = 0,
18089 	};
18090 	uint32_t domain = MLX5_MTR_DOMAIN_TRANSFER;
18091 	struct {
18092 		struct mlx5_flow_meter_policy *fm_policy;
18093 		struct mlx5_flow_meter_info *next_fm;
18094 		struct mlx5_sub_policy_color_rule *tag_rule[MLX5_MTR_RTE_COLORS];
18095 	} fm_info[MLX5_MTR_CHAIN_MAX_NUM] = { {0} };
18096 	uint32_t fm_cnt = 0;
18097 	uint32_t i, j;
18098 
18099 	color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, error);
18100 	/* Get all fms who need to create the tag color rule. */
18101 	do {
18102 		bool skip = false;
18103 
18104 		mtr_policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
18105 		MLX5_ASSERT(mtr_policy);
18106 		if (mlx5_meter_hierarchy_skip_tag_rule(priv, mtr_policy, src_port,
18107 						       &next_fm, &skip, error))
18108 			goto err_exit;
18109 		if (!skip) {
18110 			fm_info[fm_cnt].fm_policy = mtr_policy;
18111 			fm_info[fm_cnt].next_fm = next_fm;
18112 			if (++fm_cnt >= MLX5_MTR_CHAIN_MAX_NUM) {
18113 				rte_flow_error_set(error, errno,
18114 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
18115 					"Exceed max meter number in hierarchy.");
18116 				goto err_exit;
18117 			}
18118 		}
18119 		fm = next_fm;
18120 	} while (fm);
18121 	/* Create tag color rules for all needed fms. */
18122 	for (i = 0; i < fm_cnt; i++) {
18123 		void *mtr_action;
18124 
18125 		mtr_policy = fm_info[i].fm_policy;
18126 		rte_spinlock_lock(&mtr_policy->sl);
18127 		sub_policy = mtr_policy->sub_policys[domain][0];
18128 		for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) {
18129 			uint8_t act_n = 0;
18130 			struct mlx5_flow_dv_modify_hdr_resource *modify_hdr;
18131 			struct mlx5_flow_dv_port_id_action_resource *port_action;
18132 
18133 			if (mtr_policy->act_cnt[j].fate_action != MLX5_FLOW_FATE_MTR &&
18134 			    mtr_policy->act_cnt[j].fate_action != MLX5_FLOW_FATE_PORT_ID)
18135 				continue;
18136 			color_rule = mlx5_malloc(MLX5_MEM_ZERO,
18137 						 sizeof(struct mlx5_sub_policy_color_rule),
18138 						 0, SOCKET_ID_ANY);
18139 			if (!color_rule) {
18140 				rte_spinlock_unlock(&mtr_policy->sl);
18141 				rte_flow_error_set(error, ENOMEM,
18142 						   RTE_FLOW_ERROR_TYPE_ACTION, NULL,
18143 						   "No memory to create tag color rule.");
18144 				goto err_exit;
18145 			}
18146 			color_rule->src_port = src_port;
18147 			modify_hdr = mtr_policy->act_cnt[j].modify_hdr;
18148 			/* Prepare to create color rule. */
18149 			if (mtr_policy->act_cnt[j].fate_action == MLX5_FLOW_FATE_MTR) {
18150 				next_fm = fm_info[i].next_fm;
18151 				if (mlx5_flow_meter_attach(priv, next_fm, &attr, error)) {
18152 					mlx5_free(color_rule);
18153 					rte_spinlock_unlock(&mtr_policy->sl);
18154 					goto err_exit;
18155 				}
18156 				mtr_action = (next_fm->color_aware && j == RTE_COLOR_YELLOW) ?
18157 									next_fm->meter_action_y :
18158 									next_fm->meter_action_g;
18159 				next_policy = mlx5_flow_meter_policy_find(dev, next_fm->policy_id,
18160 									  NULL);
18161 				MLX5_ASSERT(next_policy);
18162 				next_sub_policy = next_policy->sub_policys[domain][0];
18163 				tbl_data = container_of(next_sub_policy->tbl_rsc,
18164 							struct mlx5_flow_tbl_data_entry, tbl);
18165 				if (mtr_first) {
18166 					acts.dv_actions[act_n++] = mtr_action;
18167 					if (modify_hdr)
18168 						acts.dv_actions[act_n++] = modify_hdr->action;
18169 				} else {
18170 					if (modify_hdr)
18171 						acts.dv_actions[act_n++] = modify_hdr->action;
18172 					acts.dv_actions[act_n++] = mtr_action;
18173 				}
18174 				acts.dv_actions[act_n++] = tbl_data->jump.action;
18175 				acts.actions_n = act_n;
18176 			} else {
18177 				port_action =
18178 					mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
18179 						       mtr_policy->act_cnt[j].rix_port_id_action);
18180 				if (!port_action) {
18181 					mlx5_free(color_rule);
18182 					rte_spinlock_unlock(&mtr_policy->sl);
18183 					goto err_exit;
18184 				}
18185 				if (modify_hdr)
18186 					acts.dv_actions[act_n++] = modify_hdr->action;
18187 				acts.dv_actions[act_n++] = port_action->action;
18188 				acts.actions_n = act_n;
18189 			}
18190 			fm_info[i].tag_rule[j] = color_rule;
18191 			TAILQ_INSERT_TAIL(&sub_policy->color_rules[j], color_rule, next_port);
18192 			if (__flow_dv_create_policy_matcher(dev, color_reg_c_idx,
18193 						MLX5_MTR_POLICY_MATCHER_PRIO, sub_policy,
18194 						&attr, true, item, &color_rule->matcher, error)) {
18195 				rte_spinlock_unlock(&mtr_policy->sl);
18196 				rte_flow_error_set(error, errno,
18197 						   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
18198 						   "Failed to create hierarchy meter matcher.");
18199 				goto err_exit;
18200 			}
18201 			if (__flow_dv_create_policy_flow(dev, color_reg_c_idx, (enum rte_color)j,
18202 						color_rule->matcher->matcher_object,
18203 						acts.actions_n, acts.dv_actions,
18204 						true, item, &color_rule->rule, &attr)) {
18205 				rte_spinlock_unlock(&mtr_policy->sl);
18206 				rte_flow_error_set(error, errno,
18207 						   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
18208 						   "Failed to create hierarchy meter rule.");
18209 				goto err_exit;
18210 			}
18211 		}
18212 		rte_spinlock_unlock(&mtr_policy->sl);
18213 	}
18214 	return 0;
18215 err_exit:
18216 	for (i = 0; i < fm_cnt; i++) {
18217 		mtr_policy = fm_info[i].fm_policy;
18218 		rte_spinlock_lock(&mtr_policy->sl);
18219 		sub_policy = mtr_policy->sub_policys[domain][0];
18220 		for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) {
18221 			color_rule = fm_info[i].tag_rule[j];
18222 			if (!color_rule)
18223 				continue;
18224 			if (color_rule->rule)
18225 				mlx5_flow_os_destroy_flow(color_rule->rule);
18226 			if (color_rule->matcher) {
18227 				struct mlx5_flow_tbl_data_entry *tbl =
18228 					container_of(color_rule->matcher->tbl, typeof(*tbl), tbl);
18229 				mlx5_list_unregister(tbl->matchers, &color_rule->matcher->entry);
18230 			}
18231 			if (fm_info[i].next_fm)
18232 				mlx5_flow_meter_detach(priv, fm_info[i].next_fm);
18233 			TAILQ_REMOVE(&sub_policy->color_rules[j], color_rule, next_port);
18234 			mlx5_free(color_rule);
18235 		}
18236 		rte_spinlock_unlock(&mtr_policy->sl);
18237 	}
18238 	return -rte_errno;
18239 }
18240 
18241 /**
18242  * Destroy the sub policy table with RX queue.
18243  *
18244  * @param[in] dev
18245  *   Pointer to Ethernet device.
18246  * @param[in] mtr_policy
18247  *   Pointer to meter policy table.
18248  */
18249 static void
18250 flow_dv_destroy_sub_policy_with_rxq(struct rte_eth_dev *dev,
18251 				    struct mlx5_flow_meter_policy *mtr_policy)
18252 {
18253 	struct mlx5_priv *priv = dev->data->dev_private;
18254 	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
18255 	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
18256 	uint32_t i, j;
18257 	uint16_t sub_policy_num, new_policy_num;
18258 
18259 	rte_spinlock_lock(&mtr_policy->sl);
18260 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
18261 		switch (mtr_policy->act_cnt[i].fate_action) {
18262 		case MLX5_FLOW_FATE_SHARED_RSS:
18263 			sub_policy_num = (mtr_policy->sub_policy_num >>
18264 			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
18265 			MLX5_MTR_SUB_POLICY_NUM_MASK;
18266 			new_policy_num = sub_policy_num;
18267 			for (j = 0; j < sub_policy_num; j++) {
18268 				sub_policy =
18269 					mtr_policy->sub_policys[domain][j];
18270 				if (sub_policy) {
18271 					__flow_dv_destroy_sub_policy_rules(dev,
18272 						sub_policy);
18273 				if (sub_policy !=
18274 					mtr_policy->sub_policys[domain][0]) {
18275 					mtr_policy->sub_policys[domain][j] =
18276 								NULL;
18277 					mlx5_ipool_free
18278 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
18279 						sub_policy->idx);
18280 						new_policy_num--;
18281 					}
18282 				}
18283 			}
18284 			if (new_policy_num != sub_policy_num) {
18285 				mtr_policy->sub_policy_num &=
18286 				~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
18287 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
18288 				mtr_policy->sub_policy_num |=
18289 				(new_policy_num &
18290 					MLX5_MTR_SUB_POLICY_NUM_MASK) <<
18291 				(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
18292 			}
18293 			break;
18294 		case MLX5_FLOW_FATE_QUEUE:
18295 			sub_policy = mtr_policy->sub_policys[domain][0];
18296 			__flow_dv_destroy_sub_policy_rules(dev,
18297 							   sub_policy);
18298 			break;
18299 		default:
18300 			/*Other actions without queue and do nothing*/
18301 			break;
18302 		}
18303 	}
18304 	rte_spinlock_unlock(&mtr_policy->sl);
18305 }
18306 /**
18307  * Check whether the DR drop action is supported on the root table or not.
18308  *
18309  * Create a simple flow with DR drop action on root table to validate
18310  * if DR drop action on root table is supported or not.
18311  *
18312  * @param[in] dev
18313  *   Pointer to rte_eth_dev structure.
18314  *
18315  * @return
18316  *   0 on success, a negative errno value otherwise and rte_errno is set.
18317  */
18318 int
18319 mlx5_flow_discover_dr_action_support(struct rte_eth_dev *dev)
18320 {
18321 	struct mlx5_priv *priv = dev->data->dev_private;
18322 	struct mlx5_dev_ctx_shared *sh = priv->sh;
18323 	struct mlx5_flow_dv_match_params mask = {
18324 		.size = sizeof(mask.buf),
18325 	};
18326 	struct mlx5_flow_dv_match_params value = {
18327 		.size = sizeof(value.buf),
18328 	};
18329 	struct mlx5dv_flow_matcher_attr dv_attr = {
18330 		.type = IBV_FLOW_ATTR_NORMAL,
18331 		.priority = 0,
18332 		.match_criteria_enable = 0,
18333 		.match_mask = (void *)&mask,
18334 	};
18335 	struct mlx5_flow_tbl_resource *tbl = NULL;
18336 	void *matcher = NULL;
18337 	void *flow = NULL;
18338 	int ret = -1;
18339 
18340 	tbl = flow_dv_tbl_resource_get(dev, 0, 0, 0, false, NULL,
18341 					0, 0, 0, NULL);
18342 	if (!tbl)
18343 		goto err;
18344 	dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
18345 	__flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
18346 	ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr,
18347 					       tbl->obj, &matcher);
18348 	if (ret)
18349 		goto err;
18350 	__flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
18351 	ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
18352 				       &sh->dr_drop_action, &flow);
18353 err:
18354 	/*
18355 	 * If DR drop action is not supported on root table, flow create will
18356 	 * be failed with EOPNOTSUPP or EPROTONOSUPPORT.
18357 	 */
18358 	if (!flow) {
18359 		if (matcher &&
18360 		    (errno == EPROTONOSUPPORT || errno == EOPNOTSUPP))
18361 			DRV_LOG(INFO, "DR drop action is not supported in root table.");
18362 		else
18363 			DRV_LOG(ERR, "Unexpected error in DR drop action support detection");
18364 		ret = -1;
18365 	} else {
18366 		claim_zero(mlx5_flow_os_destroy_flow(flow));
18367 	}
18368 	if (matcher)
18369 		claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
18370 	if (tbl)
18371 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
18372 	return ret;
18373 }
18374 
18375 /**
18376  * Validate the batch counter support in root table.
18377  *
18378  * Create a simple flow with invalid counter and drop action on root table to
18379  * validate if batch counter with offset on root table is supported or not.
18380  *
18381  * @param[in] dev
18382  *   Pointer to rte_eth_dev structure.
18383  *
18384  * @return
18385  *   0 on success, a negative errno value otherwise and rte_errno is set.
18386  */
18387 int
18388 mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev)
18389 {
18390 	struct mlx5_priv *priv = dev->data->dev_private;
18391 	struct mlx5_dev_ctx_shared *sh = priv->sh;
18392 	struct mlx5_flow_dv_match_params mask = {
18393 		.size = sizeof(mask.buf),
18394 	};
18395 	struct mlx5_flow_dv_match_params value = {
18396 		.size = sizeof(value.buf),
18397 	};
18398 	struct mlx5dv_flow_matcher_attr dv_attr = {
18399 		.type = IBV_FLOW_ATTR_NORMAL | IBV_FLOW_ATTR_FLAGS_EGRESS,
18400 		.priority = 0,
18401 		.match_criteria_enable = 0,
18402 		.match_mask = (void *)&mask,
18403 	};
18404 	void *actions[2] = { 0 };
18405 	struct mlx5_flow_tbl_resource *tbl = NULL;
18406 	struct mlx5_devx_obj *dcs = NULL;
18407 	void *matcher = NULL;
18408 	void *flow = NULL;
18409 	int ret = -1;
18410 
18411 	tbl = flow_dv_tbl_resource_get(dev, 0, 1, 0, false, NULL,
18412 					0, 0, 0, NULL);
18413 	if (!tbl)
18414 		goto err;
18415 	dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->cdev->ctx, 0x4);
18416 	if (!dcs)
18417 		goto err;
18418 	ret = mlx5_flow_os_create_flow_action_count(dcs->obj, UINT16_MAX,
18419 						    &actions[0]);
18420 	if (ret)
18421 		goto err;
18422 	dv_attr.match_criteria_enable = flow_dv_matcher_enable(mask.buf);
18423 	__flow_dv_adjust_buf_size(&mask.size, dv_attr.match_criteria_enable);
18424 	ret = mlx5_flow_os_create_flow_matcher(sh->cdev->ctx, &dv_attr,
18425 					       tbl->obj, &matcher);
18426 	if (ret)
18427 		goto err;
18428 	__flow_dv_adjust_buf_size(&value.size, dv_attr.match_criteria_enable);
18429 	ret = mlx5_flow_os_create_flow(matcher, (void *)&value, 1,
18430 				       actions, &flow);
18431 err:
18432 	/*
18433 	 * If batch counter with offset is not supported, the driver will not
18434 	 * validate the invalid offset value, flow create should success.
18435 	 * In this case, it means batch counter is not supported in root table.
18436 	 *
18437 	 * Otherwise, if flow create is failed, counter offset is supported.
18438 	 */
18439 	if (flow) {
18440 		DRV_LOG(INFO, "Batch counter is not supported in root "
18441 			      "table. Switch to fallback mode.");
18442 		rte_errno = ENOTSUP;
18443 		ret = -rte_errno;
18444 		claim_zero(mlx5_flow_os_destroy_flow(flow));
18445 	} else {
18446 		/* Check matcher to make sure validate fail at flow create. */
18447 		if (!matcher || (matcher && errno != EINVAL))
18448 			DRV_LOG(ERR, "Unexpected error in counter offset "
18449 				     "support detection");
18450 		ret = 0;
18451 	}
18452 	if (actions[0])
18453 		claim_zero(mlx5_flow_os_destroy_flow_action(actions[0]));
18454 	if (matcher)
18455 		claim_zero(mlx5_flow_os_destroy_flow_matcher(matcher));
18456 	if (tbl)
18457 		flow_dv_tbl_resource_release(MLX5_SH(dev), tbl);
18458 	if (dcs)
18459 		claim_zero(mlx5_devx_cmd_destroy(dcs));
18460 	return ret;
18461 }
18462 
18463 /**
18464  * Query a devx counter.
18465  *
18466  * @param[in] dev
18467  *   Pointer to the Ethernet device structure.
18468  * @param[in] cnt
18469  *   Index to the flow counter.
18470  * @param[in] clear
18471  *   Set to clear the counter statistics.
18472  * @param[out] pkts
18473  *   The statistics value of packets.
18474  * @param[out] bytes
18475  *   The statistics value of bytes.
18476  *
18477  * @return
18478  *   0 on success, otherwise return -1.
18479  */
18480 static int
18481 flow_dv_counter_query(struct rte_eth_dev *dev, uint32_t counter, bool clear,
18482 		      uint64_t *pkts, uint64_t *bytes, void **action)
18483 {
18484 	struct mlx5_priv *priv = dev->data->dev_private;
18485 	struct mlx5_flow_counter *cnt;
18486 	uint64_t inn_pkts, inn_bytes;
18487 	int ret;
18488 
18489 	if (!priv->sh->cdev->config.devx)
18490 		return -1;
18491 
18492 	ret = _flow_dv_query_count(dev, counter, &inn_pkts, &inn_bytes);
18493 	if (ret)
18494 		return -1;
18495 	cnt = flow_dv_counter_get_by_idx(dev, counter, NULL);
18496 	if (cnt && action)
18497 		*action = cnt->action;
18498 
18499 	*pkts = inn_pkts - cnt->hits;
18500 	*bytes = inn_bytes - cnt->bytes;
18501 	if (clear) {
18502 		cnt->hits = inn_pkts;
18503 		cnt->bytes = inn_bytes;
18504 	}
18505 	return 0;
18506 }
18507 
18508 /**
18509  * Get aged-out flows.
18510  *
18511  * @param[in] dev
18512  *   Pointer to the Ethernet device structure.
18513  * @param[in] context
18514  *   The address of an array of pointers to the aged-out flows contexts.
18515  * @param[in] nb_contexts
18516  *   The length of context array pointers.
18517  * @param[out] error
18518  *   Perform verbose error reporting if not NULL. Initialized in case of
18519  *   error only.
18520  *
18521  * @return
18522  *   how many contexts get in success, otherwise negative errno value.
18523  *   if nb_contexts is 0, return the amount of all aged contexts.
18524  *   if nb_contexts is not 0 , return the amount of aged flows reported
18525  *   in the context array.
18526  * @note: only stub for now
18527  */
18528 static int
18529 flow_dv_get_aged_flows(struct rte_eth_dev *dev,
18530 		    void **context,
18531 		    uint32_t nb_contexts,
18532 		    struct rte_flow_error *error)
18533 {
18534 	struct mlx5_priv *priv = dev->data->dev_private;
18535 	struct mlx5_age_info *age_info;
18536 	struct mlx5_age_param *age_param;
18537 	struct mlx5_flow_counter *counter;
18538 	struct mlx5_aso_age_action *act;
18539 	int nb_flows = 0;
18540 
18541 	if (nb_contexts && !context)
18542 		return rte_flow_error_set(error, EINVAL,
18543 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
18544 					  NULL, "empty context");
18545 	age_info = GET_PORT_AGE_INFO(priv);
18546 	rte_spinlock_lock(&age_info->aged_sl);
18547 	LIST_FOREACH(act, &age_info->aged_aso, next) {
18548 		nb_flows++;
18549 		if (nb_contexts) {
18550 			context[nb_flows - 1] =
18551 						act->age_params.context;
18552 			if (!(--nb_contexts))
18553 				break;
18554 		}
18555 	}
18556 	TAILQ_FOREACH(counter, &age_info->aged_counters, next) {
18557 		nb_flows++;
18558 		if (nb_contexts) {
18559 			age_param = MLX5_CNT_TO_AGE(counter);
18560 			context[nb_flows - 1] = age_param->context;
18561 			if (!(--nb_contexts))
18562 				break;
18563 		}
18564 	}
18565 	rte_spinlock_unlock(&age_info->aged_sl);
18566 	MLX5_AGE_SET(age_info, MLX5_AGE_TRIGGER);
18567 	return nb_flows;
18568 }
18569 
18570 /*
18571  * Mutex-protected thunk to lock-free flow_dv_counter_alloc().
18572  */
18573 static uint32_t
18574 flow_dv_counter_allocate(struct rte_eth_dev *dev)
18575 {
18576 	return flow_dv_counter_alloc(dev, 0);
18577 }
18578 
18579 /**
18580  * Validate indirect action.
18581  * Dispatcher for action type specific validation.
18582  *
18583  * @param[in] dev
18584  *   Pointer to the Ethernet device structure.
18585  * @param[in] conf
18586  *   Indirect action configuration.
18587  * @param[in] action
18588  *   The indirect action object to validate.
18589  * @param[out] error
18590  *   Perform verbose error reporting if not NULL. Initialized in case of
18591  *   error only.
18592  *
18593  * @return
18594  *   0 on success, otherwise negative errno value.
18595  */
18596 int
18597 flow_dv_action_validate(struct rte_eth_dev *dev,
18598 			const struct rte_flow_indir_action_conf *conf,
18599 			const struct rte_flow_action *action,
18600 			struct rte_flow_error *err)
18601 {
18602 	struct mlx5_priv *priv = dev->data->dev_private;
18603 	/* called from RTE API */
18604 
18605 	RTE_SET_USED(conf);
18606 	switch (action->type) {
18607 	case RTE_FLOW_ACTION_TYPE_RSS:
18608 		/*
18609 		 * priv->obj_ops is set according to driver capabilities.
18610 		 * When DevX capabilities are
18611 		 * sufficient, it is set to devx_obj_ops.
18612 		 * Otherwise, it is set to ibv_obj_ops.
18613 		 * ibv_obj_ops doesn't support ind_table_modify operation.
18614 		 * In this case the indirect RSS action can't be used.
18615 		 */
18616 		if (priv->obj_ops.ind_table_modify == NULL)
18617 			return rte_flow_error_set
18618 					(err, ENOTSUP,
18619 					 RTE_FLOW_ERROR_TYPE_ACTION,
18620 					 NULL,
18621 					 "Indirect RSS action not supported");
18622 		return mlx5_validate_action_rss(dev, action, err);
18623 	case RTE_FLOW_ACTION_TYPE_AGE:
18624 		if (!priv->sh->aso_age_mng)
18625 			return rte_flow_error_set(err, ENOTSUP,
18626 						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
18627 						NULL,
18628 						"Indirect age action not supported");
18629 		return flow_dv_validate_action_age(0, action, dev, err);
18630 	case RTE_FLOW_ACTION_TYPE_COUNT:
18631 		return flow_dv_validate_action_count(dev, true, 0, false, err);
18632 	case RTE_FLOW_ACTION_TYPE_CONNTRACK:
18633 		if (!priv->sh->ct_aso_en)
18634 			return rte_flow_error_set(err, ENOTSUP,
18635 					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
18636 					"ASO CT is not supported");
18637 		return mlx5_validate_action_ct(dev, action->conf, err);
18638 	default:
18639 		return rte_flow_error_set(err, ENOTSUP,
18640 					  RTE_FLOW_ERROR_TYPE_ACTION,
18641 					  NULL,
18642 					  "action type not supported");
18643 	}
18644 }
18645 
18646 /*
18647  * Check if the RSS configurations for colors of a meter policy match
18648  * each other, except the queues.
18649  *
18650  * @param[in] r1
18651  *   Pointer to the first RSS flow action.
18652  * @param[in] r2
18653  *   Pointer to the second RSS flow action.
18654  *
18655  * @return
18656  *   0 on match, 1 on conflict.
18657  */
18658 static inline int
18659 flow_dv_mtr_policy_rss_compare(const struct rte_flow_action_rss *r1,
18660 			       const struct rte_flow_action_rss *r2)
18661 {
18662 	if (r1 == NULL || r2 == NULL)
18663 		return 0;
18664 	if (!(r1->level <= 1 && r2->level <= 1) &&
18665 	    !(r1->level > 1 && r2->level > 1))
18666 		return 1;
18667 	if (r1->types != r2->types &&
18668 	    !((r1->types == 0 || r1->types == RTE_ETH_RSS_IP) &&
18669 	      (r2->types == 0 || r2->types == RTE_ETH_RSS_IP)))
18670 		return 1;
18671 	if (r1->key || r2->key) {
18672 		const void *key1 = r1->key ? r1->key : rss_hash_default_key;
18673 		const void *key2 = r2->key ? r2->key : rss_hash_default_key;
18674 
18675 		if (memcmp(key1, key2, MLX5_RSS_HASH_KEY_LEN))
18676 			return 1;
18677 	}
18678 	return 0;
18679 }
18680 
18681 /**
18682  * Validate the meter hierarchy chain for meter policy.
18683  *
18684  * @param[in] dev
18685  *   Pointer to the Ethernet device structure.
18686  * @param[in] meter_id
18687  *   Meter id.
18688  * @param[in] action_flags
18689  *   Holds the actions detected until now.
18690  * @param[out] is_rss
18691  *   Is RSS or not.
18692  * @param[out] hierarchy_domain
18693  *   The domain bitmap for hierarchy policy.
18694  * @param[out] error
18695  *   Perform verbose error reporting if not NULL. Initialized in case of
18696  *   error only.
18697  *
18698  * @return
18699  *   0 on success, otherwise negative errno value with error set.
18700  */
18701 static int
18702 flow_dv_validate_policy_mtr_hierarchy(struct rte_eth_dev *dev,
18703 				  uint32_t meter_id,
18704 				  uint64_t action_flags,
18705 				  bool *is_rss,
18706 				  uint8_t *hierarchy_domain,
18707 				  struct rte_mtr_error *error)
18708 {
18709 	struct mlx5_priv *priv = dev->data->dev_private;
18710 	struct mlx5_flow_meter_info *fm;
18711 	struct mlx5_flow_meter_policy *policy;
18712 	uint8_t cnt = 1;
18713 
18714 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
18715 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
18716 		return -rte_mtr_error_set(error, EINVAL,
18717 					RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN,
18718 					NULL,
18719 					"Multiple fate actions not supported.");
18720 	*hierarchy_domain = 0;
18721 	fm = mlx5_flow_meter_find(priv, meter_id, NULL);
18722 	while (true) {
18723 		if (!fm)
18724 			return -rte_mtr_error_set(error, EINVAL,
18725 						RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
18726 					"Meter not found in meter hierarchy.");
18727 		if (fm->def_policy)
18728 			return -rte_mtr_error_set(error, EINVAL,
18729 					RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
18730 			"Non termination meter not supported in hierarchy.");
18731 		if (!fm->shared)
18732 			return -rte_mtr_error_set(error, EINVAL,
18733 					RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
18734 					"Only shared meter supported in hierarchy.");
18735 		policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
18736 		MLX5_ASSERT(policy);
18737 		/**
18738 		 * Only inherit the supported domains of the first meter in
18739 		 * hierarchy.
18740 		 * One meter supports at least one domain.
18741 		 */
18742 		if (!*hierarchy_domain) {
18743 			if (policy->transfer)
18744 				*hierarchy_domain |=
18745 						MLX5_MTR_DOMAIN_TRANSFER_BIT;
18746 			if (policy->ingress)
18747 				*hierarchy_domain |=
18748 						MLX5_MTR_DOMAIN_INGRESS_BIT;
18749 			if (policy->egress)
18750 				*hierarchy_domain |= MLX5_MTR_DOMAIN_EGRESS_BIT;
18751 		}
18752 		if (!policy->is_hierarchy) {
18753 			*is_rss = policy->is_rss;
18754 			break;
18755 		}
18756 		rte_spinlock_lock(&policy->sl);
18757 		fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, NULL);
18758 		rte_spinlock_unlock(&policy->sl);
18759 		if (++cnt >= MLX5_MTR_CHAIN_MAX_NUM)
18760 			return -rte_mtr_error_set(error, EINVAL,
18761 					RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
18762 					"Exceed max hierarchy meter number.");
18763 	}
18764 	return 0;
18765 }
18766 
18767 /**
18768  * Validate meter policy actions.
18769  * Dispatcher for action type specific validation.
18770  *
18771  * @param[in] dev
18772  *   Pointer to the Ethernet device structure.
18773  * @param[in] action
18774  *   The meter policy action object to validate.
18775  * @param[in] attr
18776  *   Attributes of flow to determine steering domain.
18777  * @param[out] error
18778  *   Perform verbose error reporting if not NULL. Initialized in case of
18779  *   error only.
18780  *
18781  * @return
18782  *   0 on success, otherwise negative errno value.
18783  */
18784 static int
18785 flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
18786 			const struct rte_flow_action *actions[RTE_COLORS],
18787 			struct rte_flow_attr *attr,
18788 			bool *is_rss,
18789 			uint8_t *domain_bitmap,
18790 			uint8_t *policy_mode,
18791 			struct rte_mtr_error *error)
18792 {
18793 	struct mlx5_priv *priv = dev->data->dev_private;
18794 	struct mlx5_sh_config *dev_conf = &priv->sh->config;
18795 	const struct rte_flow_action *act;
18796 	uint64_t action_flags[RTE_COLORS] = {0};
18797 	int actions_n;
18798 	int i, ret;
18799 	struct rte_flow_error flow_err;
18800 	uint8_t domain_color[RTE_COLORS] = {0};
18801 	uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
18802 	uint8_t hierarchy_domain = 0;
18803 	const struct rte_flow_action_meter *mtr;
18804 	const struct rte_flow_action_meter *next_mtr = NULL;
18805 	bool def_green = false;
18806 	bool def_yellow = false;
18807 	const struct rte_flow_action_rss *rss_color[RTE_COLORS] = {NULL};
18808 	/* Called from RTE API */
18809 	bool is_root = !(attr->group || (attr->transfer && priv->fdb_def_rule));
18810 
18811 	if (!dev_conf->dv_esw_en)
18812 		def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
18813 	*domain_bitmap = def_domain;
18814 	/* Red color could only support DROP action. */
18815 	if (!actions[RTE_COLOR_RED] ||
18816 	    actions[RTE_COLOR_RED]->type != RTE_FLOW_ACTION_TYPE_DROP)
18817 		return -rte_mtr_error_set(error, ENOTSUP,
18818 				RTE_MTR_ERROR_TYPE_METER_POLICY,
18819 				NULL, "Red color only supports drop action.");
18820 	/*
18821 	 * Check default policy actions:
18822 	 * Green / Yellow: no action, Red: drop action
18823 	 * Either G or Y will trigger default policy actions to be created.
18824 	 */
18825 	if (!actions[RTE_COLOR_GREEN] ||
18826 	    actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END)
18827 		def_green = true;
18828 	if (!actions[RTE_COLOR_YELLOW] ||
18829 	    actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END)
18830 		def_yellow = true;
18831 	if (def_green && def_yellow) {
18832 		*policy_mode = MLX5_MTR_POLICY_MODE_DEF;
18833 		return 0;
18834 	} else if (!def_green && def_yellow) {
18835 		*policy_mode = MLX5_MTR_POLICY_MODE_OG;
18836 	} else if (def_green && !def_yellow) {
18837 		*policy_mode = MLX5_MTR_POLICY_MODE_OY;
18838 	} else {
18839 		*policy_mode = MLX5_MTR_POLICY_MODE_ALL;
18840 	}
18841 	/* Set to empty string in case of NULL pointer access by user. */
18842 	flow_err.message = "";
18843 	for (i = 0; i < RTE_COLORS; i++) {
18844 		act = actions[i];
18845 		for (action_flags[i] = 0, actions_n = 0;
18846 		     act && act->type != RTE_FLOW_ACTION_TYPE_END;
18847 		     act++) {
18848 			if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
18849 				return -rte_mtr_error_set(error, ENOTSUP,
18850 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
18851 					  NULL, "too many actions");
18852 			switch (act->type) {
18853 			case RTE_FLOW_ACTION_TYPE_PORT_ID:
18854 			case RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT:
18855 				if (!dev_conf->dv_esw_en)
18856 					return -rte_mtr_error_set(error,
18857 					ENOTSUP,
18858 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18859 					NULL, "PORT action validate check"
18860 					" fail for ESW disable");
18861 				ret = flow_dv_validate_action_port_id(dev,
18862 						action_flags[i],
18863 						act, attr, &flow_err);
18864 				if (ret)
18865 					return -rte_mtr_error_set(error,
18866 					ENOTSUP,
18867 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18868 					NULL, flow_err.message ?
18869 					flow_err.message :
18870 					"PORT action validate check fail");
18871 				++actions_n;
18872 				action_flags[i] |= MLX5_FLOW_ACTION_PORT_ID;
18873 				break;
18874 			case RTE_FLOW_ACTION_TYPE_MARK:
18875 				ret = flow_dv_validate_action_mark(dev, act,
18876 							   action_flags[i],
18877 							   attr, &flow_err);
18878 				if (ret < 0)
18879 					return -rte_mtr_error_set(error,
18880 					ENOTSUP,
18881 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18882 					NULL, flow_err.message ?
18883 					flow_err.message :
18884 					"Mark action validate check fail");
18885 				if (dev_conf->dv_xmeta_en !=
18886 					MLX5_XMETA_MODE_LEGACY)
18887 					return -rte_mtr_error_set(error,
18888 					ENOTSUP,
18889 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18890 					NULL, "Extend MARK action is "
18891 					"not supported. Please try use "
18892 					"default policy for meter.");
18893 				action_flags[i] |= MLX5_FLOW_ACTION_MARK;
18894 				++actions_n;
18895 				break;
18896 			case RTE_FLOW_ACTION_TYPE_SET_TAG:
18897 				ret = flow_dv_validate_action_set_tag(dev,
18898 							act, action_flags[i],
18899 							attr, &flow_err);
18900 				if (ret)
18901 					return -rte_mtr_error_set(error,
18902 					ENOTSUP,
18903 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18904 					NULL, flow_err.message ?
18905 					flow_err.message :
18906 					"Set tag action validate check fail");
18907 				action_flags[i] |= MLX5_FLOW_ACTION_SET_TAG;
18908 				++actions_n;
18909 				break;
18910 			case RTE_FLOW_ACTION_TYPE_DROP:
18911 				ret = mlx5_flow_validate_action_drop
18912 					(action_flags[i], attr, &flow_err);
18913 				if (ret < 0)
18914 					return -rte_mtr_error_set(error,
18915 					ENOTSUP,
18916 					RTE_MTR_ERROR_TYPE_METER_POLICY,
18917 					NULL, flow_err.message ?
18918 					flow_err.message :
18919 					"Drop action validate check fail");
18920 				action_flags[i] |= MLX5_FLOW_ACTION_DROP;
18921 				++actions_n;
18922 				break;
18923 			case RTE_FLOW_ACTION_TYPE_QUEUE:
18924 				/*
18925 				 * Check whether extensive
18926 				 * metadata feature is engaged.
18927 				 */
18928 				if (dev_conf->dv_flow_en &&
18929 				    (dev_conf->dv_xmeta_en !=
18930 				     MLX5_XMETA_MODE_LEGACY) &&
18931 				    mlx5_flow_ext_mreg_supported(dev))
18932 					return -rte_mtr_error_set(error,
18933 					  ENOTSUP,
18934 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
18935 					  NULL, "Queue action with meta "
18936 					  "is not supported. Please try use "
18937 					  "default policy for meter.");
18938 				ret = mlx5_flow_validate_action_queue(act,
18939 							action_flags[i], dev,
18940 							attr, &flow_err);
18941 				if (ret < 0)
18942 					return -rte_mtr_error_set(error,
18943 					  ENOTSUP,
18944 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
18945 					  NULL, flow_err.message ?
18946 					  flow_err.message :
18947 					  "Queue action validate check fail");
18948 				action_flags[i] |= MLX5_FLOW_ACTION_QUEUE;
18949 				++actions_n;
18950 				break;
18951 			case RTE_FLOW_ACTION_TYPE_RSS:
18952 				if (dev_conf->dv_flow_en &&
18953 				    (dev_conf->dv_xmeta_en !=
18954 				     MLX5_XMETA_MODE_LEGACY) &&
18955 				    mlx5_flow_ext_mreg_supported(dev))
18956 					return -rte_mtr_error_set(error,
18957 					  ENOTSUP,
18958 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
18959 					  NULL, "RSS action with meta "
18960 					  "is not supported. Please try use "
18961 					  "default policy for meter.");
18962 				ret = mlx5_validate_action_rss(dev, act,
18963 							       &flow_err);
18964 				if (ret < 0)
18965 					return -rte_mtr_error_set(error,
18966 					  ENOTSUP,
18967 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
18968 					  NULL, flow_err.message ?
18969 					  flow_err.message :
18970 					  "RSS action validate check fail");
18971 				action_flags[i] |= MLX5_FLOW_ACTION_RSS;
18972 				++actions_n;
18973 				/* Either G or Y will set the RSS. */
18974 				rss_color[i] = act->conf;
18975 				break;
18976 			case RTE_FLOW_ACTION_TYPE_JUMP:
18977 				ret = flow_dv_validate_action_jump(dev,
18978 					NULL, act, action_flags[i],
18979 					attr, true, &flow_err);
18980 				if (ret)
18981 					return -rte_mtr_error_set(error,
18982 					  ENOTSUP,
18983 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
18984 					  NULL, flow_err.message ?
18985 					  flow_err.message :
18986 					  "Jump action validate check fail");
18987 				++actions_n;
18988 				action_flags[i] |= MLX5_FLOW_ACTION_JUMP;
18989 				break;
18990 			case RTE_FLOW_ACTION_TYPE_METER:
18991 				mtr = act->conf;
18992 				if (next_mtr && next_mtr->mtr_id != mtr->mtr_id)
18993 					return -rte_mtr_error_set(error, ENOTSUP,
18994 						RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
18995 						"Green and Yellow must use the same meter.");
18996 				ret = flow_dv_validate_policy_mtr_hierarchy(dev,
18997 							mtr->mtr_id,
18998 							action_flags[i],
18999 							is_rss,
19000 							&hierarchy_domain,
19001 							error);
19002 				if (ret)
19003 					return ret;
19004 				++actions_n;
19005 				action_flags[i] |=
19006 				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
19007 				next_mtr = mtr;
19008 				break;
19009 			case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
19010 				ret = flow_dv_validate_action_modify_field(dev,
19011 					action_flags[i], act, attr, is_root, &flow_err);
19012 				if (ret < 0)
19013 					return -rte_mtr_error_set(error,
19014 					  ENOTSUP,
19015 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
19016 					  NULL, flow_err.message ?
19017 					  flow_err.message :
19018 					  "Modify field action validate check fail");
19019 				++actions_n;
19020 				action_flags[i] |= MLX5_FLOW_ACTION_MODIFY_FIELD;
19021 				break;
19022 			default:
19023 				return -rte_mtr_error_set(error, ENOTSUP,
19024 					RTE_MTR_ERROR_TYPE_METER_POLICY,
19025 					NULL,
19026 					"Doesn't support optional action");
19027 			}
19028 		}
19029 		if (action_flags[i] & MLX5_FLOW_ACTION_PORT_ID) {
19030 			domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
19031 		} else if ((action_flags[i] &
19032 			  (MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
19033 			  (action_flags[i] & MLX5_FLOW_ACTION_MARK)) {
19034 			/*
19035 			 * Only support MLX5_XMETA_MODE_LEGACY
19036 			 * so MARK action is only in ingress domain.
19037 			 */
19038 			domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
19039 		} else {
19040 			domain_color[i] = def_domain;
19041 			if (action_flags[i] &&
19042 			    !(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
19043 				domain_color[i] &=
19044 				~MLX5_MTR_DOMAIN_TRANSFER_BIT;
19045 		}
19046 		if (action_flags[i] &
19047 		    MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
19048 			domain_color[i] &= hierarchy_domain;
19049 		/*
19050 		 * Non-termination actions only support NIC Tx domain.
19051 		 * The adjustion should be skipped when there is no
19052 		 * action or only END is provided. The default domains
19053 		 * bit-mask is set to find the MIN intersection.
19054 		 * The action flags checking should also be skipped.
19055 		 */
19056 		if ((def_green && i == RTE_COLOR_GREEN) ||
19057 		    (def_yellow && i == RTE_COLOR_YELLOW))
19058 			continue;
19059 		/*
19060 		 * Validate the drop action mutual exclusion
19061 		 * with other actions. Drop action is mutually-exclusive
19062 		 * with any other action, except for Count action.
19063 		 */
19064 		if ((action_flags[i] & MLX5_FLOW_ACTION_DROP) &&
19065 		    (action_flags[i] & ~MLX5_FLOW_ACTION_DROP)) {
19066 			return -rte_mtr_error_set(error, ENOTSUP,
19067 				RTE_MTR_ERROR_TYPE_METER_POLICY,
19068 				NULL, "Drop action is mutually-exclusive "
19069 				"with any other action");
19070 		}
19071 		/* Eswitch has few restrictions on using items and actions */
19072 		if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
19073 			if (!mlx5_flow_ext_mreg_supported(dev) &&
19074 			    action_flags[i] & MLX5_FLOW_ACTION_MARK)
19075 				return -rte_mtr_error_set(error, ENOTSUP,
19076 					RTE_MTR_ERROR_TYPE_METER_POLICY,
19077 					NULL, "unsupported action MARK");
19078 			if (action_flags[i] & MLX5_FLOW_ACTION_QUEUE)
19079 				return -rte_mtr_error_set(error, ENOTSUP,
19080 					RTE_MTR_ERROR_TYPE_METER_POLICY,
19081 					NULL, "unsupported action QUEUE");
19082 			if (action_flags[i] & MLX5_FLOW_ACTION_RSS)
19083 				return -rte_mtr_error_set(error, ENOTSUP,
19084 					RTE_MTR_ERROR_TYPE_METER_POLICY,
19085 					NULL, "unsupported action RSS");
19086 			if (!(action_flags[i] & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
19087 				return -rte_mtr_error_set(error, ENOTSUP,
19088 					RTE_MTR_ERROR_TYPE_METER_POLICY,
19089 					NULL, "no fate action is found");
19090 		} else {
19091 			if (!(action_flags[i] & MLX5_FLOW_FATE_ACTIONS) &&
19092 			    (domain_color[i] & MLX5_MTR_DOMAIN_INGRESS_BIT)) {
19093 				if ((domain_color[i] &
19094 				     MLX5_MTR_DOMAIN_EGRESS_BIT))
19095 					domain_color[i] =
19096 						MLX5_MTR_DOMAIN_EGRESS_BIT;
19097 				else
19098 					return -rte_mtr_error_set(error,
19099 						ENOTSUP,
19100 						RTE_MTR_ERROR_TYPE_METER_POLICY,
19101 						NULL,
19102 						"no fate action is found");
19103 			}
19104 		}
19105 	}
19106 	if (next_mtr && *policy_mode == MLX5_MTR_POLICY_MODE_ALL) {
19107 		if (!(action_flags[RTE_COLOR_GREEN] & action_flags[RTE_COLOR_YELLOW] &
19108 		      MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY))
19109 			return -rte_mtr_error_set(error, EINVAL, RTE_MTR_ERROR_TYPE_METER_POLICY,
19110 						  NULL,
19111 						  "Meter hierarchy supports meter action only.");
19112 	}
19113 	/* If both colors have RSS, the attributes should be the same. */
19114 	if (flow_dv_mtr_policy_rss_compare(rss_color[RTE_COLOR_GREEN],
19115 					   rss_color[RTE_COLOR_YELLOW]))
19116 		return -rte_mtr_error_set(error, EINVAL,
19117 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
19118 					  NULL, "policy RSS attr conflict");
19119 	if (rss_color[RTE_COLOR_GREEN] || rss_color[RTE_COLOR_YELLOW])
19120 		*is_rss = true;
19121 	/* "domain_color[C]" is non-zero for each color, default is ALL. */
19122 	if (!def_green && !def_yellow &&
19123 	    domain_color[RTE_COLOR_GREEN] != domain_color[RTE_COLOR_YELLOW] &&
19124 	    !(action_flags[RTE_COLOR_GREEN] & MLX5_FLOW_ACTION_DROP) &&
19125 	    !(action_flags[RTE_COLOR_YELLOW] & MLX5_FLOW_ACTION_DROP))
19126 		return -rte_mtr_error_set(error, EINVAL,
19127 					  RTE_MTR_ERROR_TYPE_METER_POLICY,
19128 					  NULL, "policy domains conflict");
19129 	/*
19130 	 * At least one color policy is listed in the actions, the domains
19131 	 * to be supported should be the intersection.
19132 	 */
19133 	*domain_bitmap = domain_color[RTE_COLOR_GREEN] &
19134 			 domain_color[RTE_COLOR_YELLOW];
19135 	return 0;
19136 }
19137 
19138 static int
19139 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
19140 {
19141 	struct mlx5_priv *priv = dev->data->dev_private;
19142 	int ret = 0;
19143 
19144 	if ((domains & MLX5_DOMAIN_BIT_NIC_RX) && priv->sh->rx_domain != NULL) {
19145 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->rx_domain,
19146 						flags);
19147 		if (ret != 0)
19148 			return ret;
19149 	}
19150 	if ((domains & MLX5_DOMAIN_BIT_NIC_TX) && priv->sh->tx_domain != NULL) {
19151 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->tx_domain, flags);
19152 		if (ret != 0)
19153 			return ret;
19154 	}
19155 	if ((domains & MLX5_DOMAIN_BIT_FDB) && priv->sh->fdb_domain != NULL) {
19156 		ret = mlx5_os_flow_dr_sync_domain(priv->sh->fdb_domain, flags);
19157 		if (ret != 0)
19158 			return ret;
19159 	}
19160 	return 0;
19161 }
19162 
19163 /**
19164  * Discover the number of available flow priorities
19165  * by trying to create a flow with the highest priority value
19166  * for each possible number.
19167  *
19168  * @param[in] dev
19169  *   Ethernet device.
19170  * @param[in] vprio
19171  *   List of possible number of available priorities.
19172  * @param[in] vprio_n
19173  *   Size of @p vprio array.
19174  * @return
19175  *   On success, number of available flow priorities.
19176  *   On failure, a negative errno-style code and rte_errno is set.
19177  */
19178 static int
19179 flow_dv_discover_priorities(struct rte_eth_dev *dev,
19180 			    const uint16_t *vprio, int vprio_n)
19181 {
19182 	struct mlx5_priv *priv = dev->data->dev_private;
19183 	struct mlx5_indexed_pool *pool = priv->sh->ipool[MLX5_IPOOL_MLX5_FLOW];
19184 	struct rte_flow_item_eth eth;
19185 	struct rte_flow_item item = {
19186 		.type = RTE_FLOW_ITEM_TYPE_ETH,
19187 		.spec = &eth,
19188 		.mask = &eth,
19189 	};
19190 	struct mlx5_flow_dv_matcher matcher = {
19191 		.mask = {
19192 			.size = sizeof(matcher.mask.buf),
19193 		},
19194 	};
19195 	union mlx5_flow_tbl_key tbl_key;
19196 	struct mlx5_flow flow;
19197 	void *action;
19198 	struct rte_flow_error error;
19199 	uint8_t misc_mask;
19200 	int i, err, ret = -ENOTSUP;
19201 
19202 	/*
19203 	 * Prepare a flow with a catch-all pattern and a drop action.
19204 	 * Use drop queue, because shared drop action may be unavailable.
19205 	 */
19206 	action = priv->drop_queue.hrxq->action;
19207 	if (action == NULL) {
19208 		DRV_LOG(ERR, "Priority discovery requires a drop action");
19209 		rte_errno = ENOTSUP;
19210 		return -rte_errno;
19211 	}
19212 	memset(&flow, 0, sizeof(flow));
19213 	flow.handle = mlx5_ipool_zmalloc(pool, &flow.handle_idx);
19214 	if (flow.handle == NULL) {
19215 		DRV_LOG(ERR, "Cannot create flow handle");
19216 		rte_errno = ENOMEM;
19217 		return -rte_errno;
19218 	}
19219 	flow.ingress = true;
19220 	flow.dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
19221 	flow.dv.actions[0] = action;
19222 	flow.dv.actions_n = 1;
19223 	memset(&eth, 0, sizeof(eth));
19224 	flow_dv_translate_item_eth(matcher.mask.buf, &item,
19225 				   /* inner */ false, /* group */ 0,
19226 				   MLX5_SET_MATCHER_SW_M);
19227 	flow_dv_translate_item_eth(flow.dv.value.buf, &item,
19228 				   /* inner */ false, /* group */ 0,
19229 				   MLX5_SET_MATCHER_SW_V);
19230 	matcher.crc = rte_raw_cksum(matcher.mask.buf, matcher.mask.size);
19231 	for (i = 0; i < vprio_n; i++) {
19232 		/* Configure the next proposed maximum priority. */
19233 		matcher.priority = vprio[i] - 1;
19234 		memset(&tbl_key, 0, sizeof(tbl_key));
19235 		err = flow_dv_matcher_register(dev, &matcher, &tbl_key, &flow,
19236 					       /* tunnel */ NULL,
19237 					       /* group */ 0,
19238 					       &error);
19239 		if (err != 0) {
19240 			/* This action is pure SW and must always succeed. */
19241 			DRV_LOG(ERR, "Cannot register matcher");
19242 			ret = -rte_errno;
19243 			break;
19244 		}
19245 		/* Try to apply the flow to HW. */
19246 		misc_mask = flow_dv_matcher_enable(flow.dv.value.buf);
19247 		__flow_dv_adjust_buf_size(&flow.dv.value.size, misc_mask);
19248 		err = mlx5_flow_os_create_flow
19249 				(flow.handle->dvh.matcher->matcher_object,
19250 				 (void *)&flow.dv.value, flow.dv.actions_n,
19251 				 flow.dv.actions, &flow.handle->drv_flow);
19252 		if (err == 0) {
19253 			claim_zero(mlx5_flow_os_destroy_flow
19254 						(flow.handle->drv_flow));
19255 			flow.handle->drv_flow = NULL;
19256 		}
19257 		claim_zero(flow_dv_matcher_release(dev, flow.handle));
19258 		if (err != 0)
19259 			break;
19260 		ret = vprio[i];
19261 	}
19262 	mlx5_ipool_free(pool, flow.handle_idx);
19263 	/* Set rte_errno if no expected priority value matched. */
19264 	if (ret < 0)
19265 		rte_errno = -ret;
19266 	return ret;
19267 }
19268 
19269 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
19270 	.validate = flow_dv_validate,
19271 	.prepare = flow_dv_prepare,
19272 	.translate = flow_dv_translate,
19273 	.apply = flow_dv_apply,
19274 	.remove = flow_dv_remove,
19275 	.destroy = flow_dv_destroy,
19276 	.query = flow_dv_query,
19277 	.create_mtr_tbls = flow_dv_create_mtr_tbls,
19278 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
19279 	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
19280 	.create_meter = flow_dv_mtr_alloc,
19281 	.free_meter = flow_dv_aso_mtr_release_to_pool,
19282 	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
19283 	.create_mtr_acts = flow_dv_create_mtr_policy_acts,
19284 	.destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
19285 	.create_policy_rules = flow_dv_create_policy_rules,
19286 	.destroy_policy_rules = flow_dv_destroy_policy_rules,
19287 	.create_def_policy = flow_dv_create_def_policy,
19288 	.destroy_def_policy = flow_dv_destroy_def_policy,
19289 	.meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare,
19290 	.meter_hierarchy_rule_create = flow_dv_meter_hierarchy_rule_create,
19291 	.destroy_sub_policy_with_rxq = flow_dv_destroy_sub_policy_with_rxq,
19292 	.counter_alloc = flow_dv_counter_allocate,
19293 	.counter_free = flow_dv_counter_free,
19294 	.counter_query = flow_dv_counter_query,
19295 	.get_aged_flows = flow_dv_get_aged_flows,
19296 	.action_validate = flow_dv_action_validate,
19297 	.action_create = flow_dv_action_create,
19298 	.action_destroy = flow_dv_action_destroy,
19299 	.action_update = flow_dv_action_update,
19300 	.action_query = flow_dv_action_query,
19301 	.sync_domain = flow_dv_sync_domain,
19302 	.discover_priorities = flow_dv_discover_priorities,
19303 	.item_create = flow_dv_item_create,
19304 	.item_release = flow_dv_item_release,
19305 };
19306 
19307 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
19308