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