xref: /dpdk/drivers/net/mlx5/mlx5_flow_dv.c (revision 200bc52e5aa0d72e70464c9cd22b55cf536ed13c)
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 
10 /* Verbs header. */
11 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
12 #ifdef PEDANTIC
13 #pragma GCC diagnostic ignored "-Wpedantic"
14 #endif
15 #include <infiniband/verbs.h>
16 #ifdef PEDANTIC
17 #pragma GCC diagnostic error "-Wpedantic"
18 #endif
19 
20 #include <rte_common.h>
21 #include <rte_ether.h>
22 #include <rte_ethdev_driver.h>
23 #include <rte_flow.h>
24 #include <rte_flow_driver.h>
25 #include <rte_malloc.h>
26 #include <rte_ip.h>
27 #include <rte_gre.h>
28 
29 #include "mlx5.h"
30 #include "mlx5_defs.h"
31 #include "mlx5_glue.h"
32 #include "mlx5_flow.h"
33 #include "mlx5_prm.h"
34 #include "mlx5_rxtx.h"
35 
36 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
37 
38 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS
39 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0
40 #endif
41 
42 #ifndef HAVE_MLX5DV_DR_ESWITCH
43 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB
44 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0
45 #endif
46 #endif
47 
48 #ifndef HAVE_MLX5DV_DR
49 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1
50 #endif
51 
52 union flow_dv_attr {
53 	struct {
54 		uint32_t valid:1;
55 		uint32_t ipv4:1;
56 		uint32_t ipv6:1;
57 		uint32_t tcp:1;
58 		uint32_t udp:1;
59 		uint32_t reserved:27;
60 	};
61 	uint32_t attr;
62 };
63 
64 /**
65  * Initialize flow attributes structure according to flow items' types.
66  *
67  * @param[in] item
68  *   Pointer to item specification.
69  * @param[out] attr
70  *   Pointer to flow attributes structure.
71  */
72 static void
73 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr)
74 {
75 	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
76 		switch (item->type) {
77 		case RTE_FLOW_ITEM_TYPE_IPV4:
78 			attr->ipv4 = 1;
79 			break;
80 		case RTE_FLOW_ITEM_TYPE_IPV6:
81 			attr->ipv6 = 1;
82 			break;
83 		case RTE_FLOW_ITEM_TYPE_UDP:
84 			attr->udp = 1;
85 			break;
86 		case RTE_FLOW_ITEM_TYPE_TCP:
87 			attr->tcp = 1;
88 			break;
89 		default:
90 			break;
91 		}
92 	}
93 	attr->valid = 1;
94 }
95 
96 struct field_modify_info {
97 	uint32_t size; /* Size of field in protocol header, in bytes. */
98 	uint32_t offset; /* Offset of field in protocol header, in bytes. */
99 	enum mlx5_modification_field id;
100 };
101 
102 struct field_modify_info modify_eth[] = {
103 	{4,  0, MLX5_MODI_OUT_DMAC_47_16},
104 	{2,  4, MLX5_MODI_OUT_DMAC_15_0},
105 	{4,  6, MLX5_MODI_OUT_SMAC_47_16},
106 	{2, 10, MLX5_MODI_OUT_SMAC_15_0},
107 	{0, 0, 0},
108 };
109 
110 struct field_modify_info modify_ipv4[] = {
111 	{1,  8, MLX5_MODI_OUT_IPV4_TTL},
112 	{4, 12, MLX5_MODI_OUT_SIPV4},
113 	{4, 16, MLX5_MODI_OUT_DIPV4},
114 	{0, 0, 0},
115 };
116 
117 struct field_modify_info modify_ipv6[] = {
118 	{1,  7, MLX5_MODI_OUT_IPV6_HOPLIMIT},
119 	{4,  8, MLX5_MODI_OUT_SIPV6_127_96},
120 	{4, 12, MLX5_MODI_OUT_SIPV6_95_64},
121 	{4, 16, MLX5_MODI_OUT_SIPV6_63_32},
122 	{4, 20, MLX5_MODI_OUT_SIPV6_31_0},
123 	{4, 24, MLX5_MODI_OUT_DIPV6_127_96},
124 	{4, 28, MLX5_MODI_OUT_DIPV6_95_64},
125 	{4, 32, MLX5_MODI_OUT_DIPV6_63_32},
126 	{4, 36, MLX5_MODI_OUT_DIPV6_31_0},
127 	{0, 0, 0},
128 };
129 
130 struct field_modify_info modify_udp[] = {
131 	{2, 0, MLX5_MODI_OUT_UDP_SPORT},
132 	{2, 2, MLX5_MODI_OUT_UDP_DPORT},
133 	{0, 0, 0},
134 };
135 
136 struct field_modify_info modify_tcp[] = {
137 	{2, 0, MLX5_MODI_OUT_TCP_SPORT},
138 	{2, 2, MLX5_MODI_OUT_TCP_DPORT},
139 	{0, 0, 0},
140 };
141 
142 /**
143  * Acquire the synchronizing object to protect multithreaded access
144  * to shared dv context. Lock occurs only if context is actually
145  * shared, i.e. we have multiport IB device and representors are
146  * created.
147  *
148  * @param[in] dev
149  *   Pointer to the rte_eth_dev structure.
150  */
151 static void
152 flow_d_shared_lock(struct rte_eth_dev *dev)
153 {
154 	struct mlx5_priv *priv = dev->data->dev_private;
155 	struct mlx5_ibv_shared *sh = priv->sh;
156 
157 	if (sh->dv_refcnt > 1) {
158 		int ret;
159 
160 		ret = pthread_mutex_lock(&sh->dv_mutex);
161 		assert(!ret);
162 		(void)ret;
163 	}
164 }
165 
166 static void
167 flow_d_shared_unlock(struct rte_eth_dev *dev)
168 {
169 	struct mlx5_priv *priv = dev->data->dev_private;
170 	struct mlx5_ibv_shared *sh = priv->sh;
171 
172 	if (sh->dv_refcnt > 1) {
173 		int ret;
174 
175 		ret = pthread_mutex_unlock(&sh->dv_mutex);
176 		assert(!ret);
177 		(void)ret;
178 	}
179 }
180 
181 /**
182  * Convert modify-header action to DV specification.
183  *
184  * @param[in] item
185  *   Pointer to item specification.
186  * @param[in] field
187  *   Pointer to field modification information.
188  * @param[in,out] resource
189  *   Pointer to the modify-header resource.
190  * @param[in] type
191  *   Type of modification.
192  * @param[out] error
193  *   Pointer to the error structure.
194  *
195  * @return
196  *   0 on success, a negative errno value otherwise and rte_errno is set.
197  */
198 static int
199 flow_dv_convert_modify_action(struct rte_flow_item *item,
200 			      struct field_modify_info *field,
201 			      struct mlx5_flow_dv_modify_hdr_resource *resource,
202 			      uint32_t type,
203 			      struct rte_flow_error *error)
204 {
205 	uint32_t i = resource->actions_num;
206 	struct mlx5_modification_cmd *actions = resource->actions;
207 	const uint8_t *spec = item->spec;
208 	const uint8_t *mask = item->mask;
209 	uint32_t set;
210 
211 	while (field->size) {
212 		set = 0;
213 		/* Generate modify command for each mask segment. */
214 		memcpy(&set, &mask[field->offset], field->size);
215 		if (set) {
216 			if (i >= MLX5_MODIFY_NUM)
217 				return rte_flow_error_set(error, EINVAL,
218 					 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
219 					 "too many items to modify");
220 			actions[i].action_type = type;
221 			actions[i].field = field->id;
222 			actions[i].length = field->size ==
223 					4 ? 0 : field->size * 8;
224 			rte_memcpy(&actions[i].data[4 - field->size],
225 				   &spec[field->offset], field->size);
226 			actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
227 			++i;
228 		}
229 		if (resource->actions_num != i)
230 			resource->actions_num = i;
231 		field++;
232 	}
233 	if (!resource->actions_num)
234 		return rte_flow_error_set(error, EINVAL,
235 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
236 					  "invalid modification flow item");
237 	return 0;
238 }
239 
240 /**
241  * Convert modify-header set IPv4 address action to DV specification.
242  *
243  * @param[in,out] resource
244  *   Pointer to the modify-header resource.
245  * @param[in] action
246  *   Pointer to action specification.
247  * @param[out] error
248  *   Pointer to the error structure.
249  *
250  * @return
251  *   0 on success, a negative errno value otherwise and rte_errno is set.
252  */
253 static int
254 flow_dv_convert_action_modify_ipv4
255 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
256 			 const struct rte_flow_action *action,
257 			 struct rte_flow_error *error)
258 {
259 	const struct rte_flow_action_set_ipv4 *conf =
260 		(const struct rte_flow_action_set_ipv4 *)(action->conf);
261 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
262 	struct rte_flow_item_ipv4 ipv4;
263 	struct rte_flow_item_ipv4 ipv4_mask;
264 
265 	memset(&ipv4, 0, sizeof(ipv4));
266 	memset(&ipv4_mask, 0, sizeof(ipv4_mask));
267 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) {
268 		ipv4.hdr.src_addr = conf->ipv4_addr;
269 		ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr;
270 	} else {
271 		ipv4.hdr.dst_addr = conf->ipv4_addr;
272 		ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr;
273 	}
274 	item.spec = &ipv4;
275 	item.mask = &ipv4_mask;
276 	return flow_dv_convert_modify_action(&item, modify_ipv4, resource,
277 					     MLX5_MODIFICATION_TYPE_SET, error);
278 }
279 
280 /**
281  * Convert modify-header set IPv6 address action to DV specification.
282  *
283  * @param[in,out] resource
284  *   Pointer to the modify-header resource.
285  * @param[in] action
286  *   Pointer to action specification.
287  * @param[out] error
288  *   Pointer to the error structure.
289  *
290  * @return
291  *   0 on success, a negative errno value otherwise and rte_errno is set.
292  */
293 static int
294 flow_dv_convert_action_modify_ipv6
295 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
296 			 const struct rte_flow_action *action,
297 			 struct rte_flow_error *error)
298 {
299 	const struct rte_flow_action_set_ipv6 *conf =
300 		(const struct rte_flow_action_set_ipv6 *)(action->conf);
301 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
302 	struct rte_flow_item_ipv6 ipv6;
303 	struct rte_flow_item_ipv6 ipv6_mask;
304 
305 	memset(&ipv6, 0, sizeof(ipv6));
306 	memset(&ipv6_mask, 0, sizeof(ipv6_mask));
307 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) {
308 		memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr,
309 		       sizeof(ipv6.hdr.src_addr));
310 		memcpy(&ipv6_mask.hdr.src_addr,
311 		       &rte_flow_item_ipv6_mask.hdr.src_addr,
312 		       sizeof(ipv6.hdr.src_addr));
313 	} else {
314 		memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr,
315 		       sizeof(ipv6.hdr.dst_addr));
316 		memcpy(&ipv6_mask.hdr.dst_addr,
317 		       &rte_flow_item_ipv6_mask.hdr.dst_addr,
318 		       sizeof(ipv6.hdr.dst_addr));
319 	}
320 	item.spec = &ipv6;
321 	item.mask = &ipv6_mask;
322 	return flow_dv_convert_modify_action(&item, modify_ipv6, resource,
323 					     MLX5_MODIFICATION_TYPE_SET, error);
324 }
325 
326 /**
327  * Convert modify-header set MAC address action to DV specification.
328  *
329  * @param[in,out] resource
330  *   Pointer to the modify-header resource.
331  * @param[in] action
332  *   Pointer to action specification.
333  * @param[out] error
334  *   Pointer to the error structure.
335  *
336  * @return
337  *   0 on success, a negative errno value otherwise and rte_errno is set.
338  */
339 static int
340 flow_dv_convert_action_modify_mac
341 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
342 			 const struct rte_flow_action *action,
343 			 struct rte_flow_error *error)
344 {
345 	const struct rte_flow_action_set_mac *conf =
346 		(const struct rte_flow_action_set_mac *)(action->conf);
347 	struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH };
348 	struct rte_flow_item_eth eth;
349 	struct rte_flow_item_eth eth_mask;
350 
351 	memset(&eth, 0, sizeof(eth));
352 	memset(&eth_mask, 0, sizeof(eth_mask));
353 	if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) {
354 		memcpy(&eth.src.addr_bytes, &conf->mac_addr,
355 		       sizeof(eth.src.addr_bytes));
356 		memcpy(&eth_mask.src.addr_bytes,
357 		       &rte_flow_item_eth_mask.src.addr_bytes,
358 		       sizeof(eth_mask.src.addr_bytes));
359 	} else {
360 		memcpy(&eth.dst.addr_bytes, &conf->mac_addr,
361 		       sizeof(eth.dst.addr_bytes));
362 		memcpy(&eth_mask.dst.addr_bytes,
363 		       &rte_flow_item_eth_mask.dst.addr_bytes,
364 		       sizeof(eth_mask.dst.addr_bytes));
365 	}
366 	item.spec = &eth;
367 	item.mask = &eth_mask;
368 	return flow_dv_convert_modify_action(&item, modify_eth, resource,
369 					     MLX5_MODIFICATION_TYPE_SET, error);
370 }
371 
372 /**
373  * Convert modify-header set TP action to DV specification.
374  *
375  * @param[in,out] resource
376  *   Pointer to the modify-header resource.
377  * @param[in] action
378  *   Pointer to action specification.
379  * @param[in] items
380  *   Pointer to rte_flow_item objects list.
381  * @param[in] attr
382  *   Pointer to flow attributes structure.
383  * @param[out] error
384  *   Pointer to the error structure.
385  *
386  * @return
387  *   0 on success, a negative errno value otherwise and rte_errno is set.
388  */
389 static int
390 flow_dv_convert_action_modify_tp
391 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
392 			 const struct rte_flow_action *action,
393 			 const struct rte_flow_item *items,
394 			 union flow_dv_attr *attr,
395 			 struct rte_flow_error *error)
396 {
397 	const struct rte_flow_action_set_tp *conf =
398 		(const struct rte_flow_action_set_tp *)(action->conf);
399 	struct rte_flow_item item;
400 	struct rte_flow_item_udp udp;
401 	struct rte_flow_item_udp udp_mask;
402 	struct rte_flow_item_tcp tcp;
403 	struct rte_flow_item_tcp tcp_mask;
404 	struct field_modify_info *field;
405 
406 	if (!attr->valid)
407 		flow_dv_attr_init(items, attr);
408 	if (attr->udp) {
409 		memset(&udp, 0, sizeof(udp));
410 		memset(&udp_mask, 0, sizeof(udp_mask));
411 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
412 			udp.hdr.src_port = conf->port;
413 			udp_mask.hdr.src_port =
414 					rte_flow_item_udp_mask.hdr.src_port;
415 		} else {
416 			udp.hdr.dst_port = conf->port;
417 			udp_mask.hdr.dst_port =
418 					rte_flow_item_udp_mask.hdr.dst_port;
419 		}
420 		item.type = RTE_FLOW_ITEM_TYPE_UDP;
421 		item.spec = &udp;
422 		item.mask = &udp_mask;
423 		field = modify_udp;
424 	}
425 	if (attr->tcp) {
426 		memset(&tcp, 0, sizeof(tcp));
427 		memset(&tcp_mask, 0, sizeof(tcp_mask));
428 		if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
429 			tcp.hdr.src_port = conf->port;
430 			tcp_mask.hdr.src_port =
431 					rte_flow_item_tcp_mask.hdr.src_port;
432 		} else {
433 			tcp.hdr.dst_port = conf->port;
434 			tcp_mask.hdr.dst_port =
435 					rte_flow_item_tcp_mask.hdr.dst_port;
436 		}
437 		item.type = RTE_FLOW_ITEM_TYPE_TCP;
438 		item.spec = &tcp;
439 		item.mask = &tcp_mask;
440 		field = modify_tcp;
441 	}
442 	return flow_dv_convert_modify_action(&item, field, resource,
443 					     MLX5_MODIFICATION_TYPE_SET, error);
444 }
445 
446 /**
447  * Convert modify-header set TTL action to DV specification.
448  *
449  * @param[in,out] resource
450  *   Pointer to the modify-header resource.
451  * @param[in] action
452  *   Pointer to action specification.
453  * @param[in] items
454  *   Pointer to rte_flow_item objects list.
455  * @param[in] attr
456  *   Pointer to flow attributes structure.
457  * @param[out] error
458  *   Pointer to the error structure.
459  *
460  * @return
461  *   0 on success, a negative errno value otherwise and rte_errno is set.
462  */
463 static int
464 flow_dv_convert_action_modify_ttl
465 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
466 			 const struct rte_flow_action *action,
467 			 const struct rte_flow_item *items,
468 			 union flow_dv_attr *attr,
469 			 struct rte_flow_error *error)
470 {
471 	const struct rte_flow_action_set_ttl *conf =
472 		(const struct rte_flow_action_set_ttl *)(action->conf);
473 	struct rte_flow_item item;
474 	struct rte_flow_item_ipv4 ipv4;
475 	struct rte_flow_item_ipv4 ipv4_mask;
476 	struct rte_flow_item_ipv6 ipv6;
477 	struct rte_flow_item_ipv6 ipv6_mask;
478 	struct field_modify_info *field;
479 
480 	if (!attr->valid)
481 		flow_dv_attr_init(items, attr);
482 	if (attr->ipv4) {
483 		memset(&ipv4, 0, sizeof(ipv4));
484 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
485 		ipv4.hdr.time_to_live = conf->ttl_value;
486 		ipv4_mask.hdr.time_to_live = 0xFF;
487 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
488 		item.spec = &ipv4;
489 		item.mask = &ipv4_mask;
490 		field = modify_ipv4;
491 	}
492 	if (attr->ipv6) {
493 		memset(&ipv6, 0, sizeof(ipv6));
494 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
495 		ipv6.hdr.hop_limits = conf->ttl_value;
496 		ipv6_mask.hdr.hop_limits = 0xFF;
497 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
498 		item.spec = &ipv6;
499 		item.mask = &ipv6_mask;
500 		field = modify_ipv6;
501 	}
502 	return flow_dv_convert_modify_action(&item, field, resource,
503 					     MLX5_MODIFICATION_TYPE_SET, error);
504 }
505 
506 /**
507  * Convert modify-header decrement TTL action to DV specification.
508  *
509  * @param[in,out] resource
510  *   Pointer to the modify-header resource.
511  * @param[in] action
512  *   Pointer to action specification.
513  * @param[in] items
514  *   Pointer to rte_flow_item objects list.
515  * @param[in] attr
516  *   Pointer to flow attributes structure.
517  * @param[out] error
518  *   Pointer to the error structure.
519  *
520  * @return
521  *   0 on success, a negative errno value otherwise and rte_errno is set.
522  */
523 static int
524 flow_dv_convert_action_modify_dec_ttl
525 			(struct mlx5_flow_dv_modify_hdr_resource *resource,
526 			 const struct rte_flow_item *items,
527 			 union flow_dv_attr *attr,
528 			 struct rte_flow_error *error)
529 {
530 	struct rte_flow_item item;
531 	struct rte_flow_item_ipv4 ipv4;
532 	struct rte_flow_item_ipv4 ipv4_mask;
533 	struct rte_flow_item_ipv6 ipv6;
534 	struct rte_flow_item_ipv6 ipv6_mask;
535 	struct field_modify_info *field;
536 
537 	if (!attr->valid)
538 		flow_dv_attr_init(items, attr);
539 	if (attr->ipv4) {
540 		memset(&ipv4, 0, sizeof(ipv4));
541 		memset(&ipv4_mask, 0, sizeof(ipv4_mask));
542 		ipv4.hdr.time_to_live = 0xFF;
543 		ipv4_mask.hdr.time_to_live = 0xFF;
544 		item.type = RTE_FLOW_ITEM_TYPE_IPV4;
545 		item.spec = &ipv4;
546 		item.mask = &ipv4_mask;
547 		field = modify_ipv4;
548 	}
549 	if (attr->ipv6) {
550 		memset(&ipv6, 0, sizeof(ipv6));
551 		memset(&ipv6_mask, 0, sizeof(ipv6_mask));
552 		ipv6.hdr.hop_limits = 0xFF;
553 		ipv6_mask.hdr.hop_limits = 0xFF;
554 		item.type = RTE_FLOW_ITEM_TYPE_IPV6;
555 		item.spec = &ipv6;
556 		item.mask = &ipv6_mask;
557 		field = modify_ipv6;
558 	}
559 	return flow_dv_convert_modify_action(&item, field, resource,
560 					     MLX5_MODIFICATION_TYPE_ADD, error);
561 }
562 
563 /**
564  * Validate META item.
565  *
566  * @param[in] dev
567  *   Pointer to the rte_eth_dev structure.
568  * @param[in] item
569  *   Item specification.
570  * @param[in] attr
571  *   Attributes of flow that includes this item.
572  * @param[out] error
573  *   Pointer to error structure.
574  *
575  * @return
576  *   0 on success, a negative errno value otherwise and rte_errno is set.
577  */
578 static int
579 flow_dv_validate_item_meta(struct rte_eth_dev *dev,
580 			   const struct rte_flow_item *item,
581 			   const struct rte_flow_attr *attr,
582 			   struct rte_flow_error *error)
583 {
584 	const struct rte_flow_item_meta *spec = item->spec;
585 	const struct rte_flow_item_meta *mask = item->mask;
586 	const struct rte_flow_item_meta nic_mask = {
587 		.data = RTE_BE32(UINT32_MAX)
588 	};
589 	int ret;
590 	uint64_t offloads = dev->data->dev_conf.txmode.offloads;
591 
592 	if (!(offloads & DEV_TX_OFFLOAD_MATCH_METADATA))
593 		return rte_flow_error_set(error, EPERM,
594 					  RTE_FLOW_ERROR_TYPE_ITEM,
595 					  NULL,
596 					  "match on metadata offload "
597 					  "configuration is off for this port");
598 	if (!spec)
599 		return rte_flow_error_set(error, EINVAL,
600 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
601 					  item->spec,
602 					  "data cannot be empty");
603 	if (!spec->data)
604 		return rte_flow_error_set(error, EINVAL,
605 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
606 					  NULL,
607 					  "data cannot be zero");
608 	if (!mask)
609 		mask = &rte_flow_item_meta_mask;
610 	ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
611 					(const uint8_t *)&nic_mask,
612 					sizeof(struct rte_flow_item_meta),
613 					error);
614 	if (ret < 0)
615 		return ret;
616 	if (attr->ingress)
617 		return rte_flow_error_set(error, ENOTSUP,
618 					  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
619 					  NULL,
620 					  "pattern not supported for ingress");
621 	return 0;
622 }
623 
624 /**
625  * Validate vport item.
626  *
627  * @param[in] dev
628  *   Pointer to the rte_eth_dev structure.
629  * @param[in] item
630  *   Item specification.
631  * @param[in] attr
632  *   Attributes of flow that includes this item.
633  * @param[in] item_flags
634  *   Bit-fields that holds the items detected until now.
635  * @param[out] error
636  *   Pointer to error structure.
637  *
638  * @return
639  *   0 on success, a negative errno value otherwise and rte_errno is set.
640  */
641 static int
642 flow_dv_validate_item_port_id(struct rte_eth_dev *dev,
643 			      const struct rte_flow_item *item,
644 			      const struct rte_flow_attr *attr,
645 			      uint64_t item_flags,
646 			      struct rte_flow_error *error)
647 {
648 	const struct rte_flow_item_port_id *spec = item->spec;
649 	const struct rte_flow_item_port_id *mask = item->mask;
650 	const struct rte_flow_item_port_id switch_mask = {
651 			.id = 0xffffffff,
652 	};
653 	uint16_t esw_domain_id;
654 	uint16_t item_port_esw_domain_id;
655 	int ret;
656 
657 	if (!attr->transfer)
658 		return rte_flow_error_set(error, EINVAL,
659 					  RTE_FLOW_ERROR_TYPE_ITEM,
660 					  NULL,
661 					  "match on port id is valid only"
662 					  " when transfer flag is enabled");
663 	if (item_flags & MLX5_FLOW_ITEM_PORT_ID)
664 		return rte_flow_error_set(error, ENOTSUP,
665 					  RTE_FLOW_ERROR_TYPE_ITEM, item,
666 					  "multiple source ports are not"
667 					  " supported");
668 	if (!mask)
669 		mask = &switch_mask;
670 	if (mask->id != 0xffffffff)
671 		return rte_flow_error_set(error, ENOTSUP,
672 					   RTE_FLOW_ERROR_TYPE_ITEM_MASK,
673 					   mask,
674 					   "no support for partial mask on"
675 					   " \"id\" field");
676 	ret = mlx5_flow_item_acceptable
677 				(item, (const uint8_t *)mask,
678 				 (const uint8_t *)&rte_flow_item_port_id_mask,
679 				 sizeof(struct rte_flow_item_port_id),
680 				 error);
681 	if (ret)
682 		return ret;
683 	if (!spec)
684 		return 0;
685 	ret = mlx5_port_to_eswitch_info(spec->id, &item_port_esw_domain_id,
686 					NULL);
687 	if (ret)
688 		return rte_flow_error_set(error, -ret,
689 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
690 					  "failed to obtain E-Switch info for"
691 					  " port");
692 	ret = mlx5_port_to_eswitch_info(dev->data->port_id,
693 					&esw_domain_id, NULL);
694 	if (ret < 0)
695 		return rte_flow_error_set(error, -ret,
696 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
697 					  NULL,
698 					  "failed to obtain E-Switch info");
699 	if (item_port_esw_domain_id != esw_domain_id)
700 		return rte_flow_error_set(error, -ret,
701 					  RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
702 					  "cannot match on a port from a"
703 					  " different E-Switch");
704 	return 0;
705 }
706 
707 /**
708  * Validate count action.
709  *
710  * @param[in] dev
711  *   device otr.
712  * @param[out] error
713  *   Pointer to error structure.
714  *
715  * @return
716  *   0 on success, a negative errno value otherwise and rte_errno is set.
717  */
718 static int
719 flow_dv_validate_action_count(struct rte_eth_dev *dev,
720 			      struct rte_flow_error *error)
721 {
722 	struct mlx5_priv *priv = dev->data->dev_private;
723 
724 	if (!priv->config.devx)
725 		goto notsup_err;
726 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
727 	return 0;
728 #endif
729 notsup_err:
730 	return rte_flow_error_set
731 		      (error, ENOTSUP,
732 		       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
733 		       NULL,
734 		       "count action not supported");
735 }
736 
737 /**
738  * Validate the L2 encap action.
739  *
740  * @param[in] action_flags
741  *   Holds the actions detected until now.
742  * @param[in] action
743  *   Pointer to the encap action.
744  * @param[in] attr
745  *   Pointer to flow attributes
746  * @param[out] error
747  *   Pointer to error structure.
748  *
749  * @return
750  *   0 on success, a negative errno value otherwise and rte_errno is set.
751  */
752 static int
753 flow_dv_validate_action_l2_encap(uint64_t action_flags,
754 				 const struct rte_flow_action *action,
755 				 const struct rte_flow_attr *attr,
756 				 struct rte_flow_error *error)
757 {
758 	if (!(action->conf))
759 		return rte_flow_error_set(error, EINVAL,
760 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
761 					  "configuration cannot be null");
762 	if (action_flags & MLX5_FLOW_ACTION_DROP)
763 		return rte_flow_error_set(error, EINVAL,
764 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
765 					  "can't drop and encap in same flow");
766 	if (action_flags & (MLX5_FLOW_ENCAP_ACTIONS | MLX5_FLOW_DECAP_ACTIONS))
767 		return rte_flow_error_set(error, EINVAL,
768 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
769 					  "can only have a single encap or"
770 					  " decap action in a flow");
771 	if (!attr->transfer && attr->ingress)
772 		return rte_flow_error_set(error, ENOTSUP,
773 					  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
774 					  NULL,
775 					  "encap action not supported for "
776 					  "ingress");
777 	return 0;
778 }
779 
780 /**
781  * Validate the L2 decap action.
782  *
783  * @param[in] action_flags
784  *   Holds the actions detected until now.
785  * @param[in] attr
786  *   Pointer to flow attributes
787  * @param[out] error
788  *   Pointer to error structure.
789  *
790  * @return
791  *   0 on success, a negative errno value otherwise and rte_errno is set.
792  */
793 static int
794 flow_dv_validate_action_l2_decap(uint64_t action_flags,
795 				 const struct rte_flow_attr *attr,
796 				 struct rte_flow_error *error)
797 {
798 	if (action_flags & MLX5_FLOW_ACTION_DROP)
799 		return rte_flow_error_set(error, EINVAL,
800 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
801 					  "can't drop and decap in same flow");
802 	if (action_flags & (MLX5_FLOW_ENCAP_ACTIONS | MLX5_FLOW_DECAP_ACTIONS))
803 		return rte_flow_error_set(error, EINVAL,
804 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
805 					  "can only have a single encap or"
806 					  " decap action in a flow");
807 	if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
808 		return rte_flow_error_set(error, EINVAL,
809 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
810 					  "can't have decap action after"
811 					  " modify action");
812 	if (attr->egress)
813 		return rte_flow_error_set(error, ENOTSUP,
814 					  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
815 					  NULL,
816 					  "decap action not supported for "
817 					  "egress");
818 	return 0;
819 }
820 
821 /**
822  * Validate the raw encap action.
823  *
824  * @param[in] action_flags
825  *   Holds the actions detected until now.
826  * @param[in] action
827  *   Pointer to the encap action.
828  * @param[in] attr
829  *   Pointer to flow attributes
830  * @param[out] error
831  *   Pointer to error structure.
832  *
833  * @return
834  *   0 on success, a negative errno value otherwise and rte_errno is set.
835  */
836 static int
837 flow_dv_validate_action_raw_encap(uint64_t action_flags,
838 				  const struct rte_flow_action *action,
839 				  const struct rte_flow_attr *attr,
840 				  struct rte_flow_error *error)
841 {
842 	if (!(action->conf))
843 		return rte_flow_error_set(error, EINVAL,
844 					  RTE_FLOW_ERROR_TYPE_ACTION, action,
845 					  "configuration cannot be null");
846 	if (action_flags & MLX5_FLOW_ACTION_DROP)
847 		return rte_flow_error_set(error, EINVAL,
848 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
849 					  "can't drop and encap in same flow");
850 	if (action_flags & MLX5_FLOW_ENCAP_ACTIONS)
851 		return rte_flow_error_set(error, EINVAL,
852 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
853 					  "can only have a single encap"
854 					  " action in a flow");
855 	/* encap without preceding decap is not supported for ingress */
856 	if (!attr->transfer &&  attr->ingress &&
857 	    !(action_flags & MLX5_FLOW_ACTION_RAW_DECAP))
858 		return rte_flow_error_set(error, ENOTSUP,
859 					  RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
860 					  NULL,
861 					  "encap action not supported for "
862 					  "ingress");
863 	return 0;
864 }
865 
866 /**
867  * Validate the raw decap action.
868  *
869  * @param[in] action_flags
870  *   Holds the actions detected until now.
871  * @param[in] action
872  *   Pointer to the encap action.
873  * @param[in] attr
874  *   Pointer to flow attributes
875  * @param[out] error
876  *   Pointer to error structure.
877  *
878  * @return
879  *   0 on success, a negative errno value otherwise and rte_errno is set.
880  */
881 static int
882 flow_dv_validate_action_raw_decap(uint64_t action_flags,
883 				  const struct rte_flow_action *action,
884 				  const struct rte_flow_attr *attr,
885 				  struct rte_flow_error *error)
886 {
887 	if (action_flags & MLX5_FLOW_ACTION_DROP)
888 		return rte_flow_error_set(error, EINVAL,
889 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
890 					  "can't drop and decap in same flow");
891 	if (action_flags & MLX5_FLOW_ENCAP_ACTIONS)
892 		return rte_flow_error_set(error, EINVAL,
893 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
894 					  "can't have encap action before"
895 					  " decap action");
896 	if (action_flags & MLX5_FLOW_DECAP_ACTIONS)
897 		return rte_flow_error_set(error, EINVAL,
898 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
899 					  "can only have a single decap"
900 					  " action in a flow");
901 	if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
902 		return rte_flow_error_set(error, EINVAL,
903 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
904 					  "can't have decap action after"
905 					  " modify action");
906 	/* decap action is valid on egress only if it is followed by encap */
907 	if (attr->egress) {
908 		for (; action->type != RTE_FLOW_ACTION_TYPE_END &&
909 		       action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP;
910 		       action++) {
911 		}
912 		if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP)
913 			return rte_flow_error_set
914 					(error, ENOTSUP,
915 					 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
916 					 NULL, "decap action not supported"
917 					 " for egress");
918 	}
919 	return 0;
920 }
921 
922 /**
923  * Find existing encap/decap resource or create and register a new one.
924  *
925  * @param dev[in, out]
926  *   Pointer to rte_eth_dev structure.
927  * @param[in, out] resource
928  *   Pointer to encap/decap resource.
929  * @parm[in, out] dev_flow
930  *   Pointer to the dev_flow.
931  * @param[out] error
932  *   pointer to error structure.
933  *
934  * @return
935  *   0 on success otherwise -errno and errno is set.
936  */
937 static int
938 flow_dv_encap_decap_resource_register
939 			(struct rte_eth_dev *dev,
940 			 struct mlx5_flow_dv_encap_decap_resource *resource,
941 			 struct mlx5_flow *dev_flow,
942 			 struct rte_flow_error *error)
943 {
944 	struct mlx5_priv *priv = dev->data->dev_private;
945 	struct mlx5_ibv_shared *sh = priv->sh;
946 	struct mlx5_flow_dv_encap_decap_resource *cache_resource;
947 	struct rte_flow *flow = dev_flow->flow;
948 	struct mlx5dv_dr_domain *domain;
949 
950 	resource->flags = flow->group ? 0 : 1;
951 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
952 		domain = sh->fdb_domain;
953 	else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
954 		domain = sh->rx_domain;
955 	else
956 		domain = sh->tx_domain;
957 
958 	/* Lookup a matching resource from cache. */
959 	LIST_FOREACH(cache_resource, &sh->encaps_decaps, next) {
960 		if (resource->reformat_type == cache_resource->reformat_type &&
961 		    resource->ft_type == cache_resource->ft_type &&
962 		    resource->flags == cache_resource->flags &&
963 		    resource->size == cache_resource->size &&
964 		    !memcmp((const void *)resource->buf,
965 			    (const void *)cache_resource->buf,
966 			    resource->size)) {
967 			DRV_LOG(DEBUG, "encap/decap resource %p: refcnt %d++",
968 				(void *)cache_resource,
969 				rte_atomic32_read(&cache_resource->refcnt));
970 			rte_atomic32_inc(&cache_resource->refcnt);
971 			dev_flow->dv.encap_decap = cache_resource;
972 			return 0;
973 		}
974 	}
975 	/* Register new encap/decap resource. */
976 	cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
977 	if (!cache_resource)
978 		return rte_flow_error_set(error, ENOMEM,
979 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
980 					  "cannot allocate resource memory");
981 	*cache_resource = *resource;
982 	cache_resource->verbs_action =
983 		mlx5_glue->dv_create_flow_action_packet_reformat
984 			(sh->ctx, cache_resource->reformat_type,
985 			 cache_resource->ft_type, domain, cache_resource->flags,
986 			 cache_resource->size,
987 			 (cache_resource->size ? cache_resource->buf : NULL));
988 	if (!cache_resource->verbs_action) {
989 		rte_free(cache_resource);
990 		return rte_flow_error_set(error, ENOMEM,
991 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
992 					  NULL, "cannot create action");
993 	}
994 	rte_atomic32_init(&cache_resource->refcnt);
995 	rte_atomic32_inc(&cache_resource->refcnt);
996 	LIST_INSERT_HEAD(&sh->encaps_decaps, cache_resource, next);
997 	dev_flow->dv.encap_decap = cache_resource;
998 	DRV_LOG(DEBUG, "new encap/decap resource %p: refcnt %d++",
999 		(void *)cache_resource,
1000 		rte_atomic32_read(&cache_resource->refcnt));
1001 	return 0;
1002 }
1003 
1004 /**
1005  * Find existing table jump resource or create and register a new one.
1006  *
1007  * @param dev[in, out]
1008  *   Pointer to rte_eth_dev structure.
1009  * @param[in, out] resource
1010  *   Pointer to jump table resource.
1011  * @parm[in, out] dev_flow
1012  *   Pointer to the dev_flow.
1013  * @param[out] error
1014  *   pointer to error structure.
1015  *
1016  * @return
1017  *   0 on success otherwise -errno and errno is set.
1018  */
1019 static int
1020 flow_dv_jump_tbl_resource_register
1021 			(struct rte_eth_dev *dev,
1022 			 struct mlx5_flow_dv_jump_tbl_resource *resource,
1023 			 struct mlx5_flow *dev_flow,
1024 			 struct rte_flow_error *error)
1025 {
1026 	struct mlx5_priv *priv = dev->data->dev_private;
1027 	struct mlx5_ibv_shared *sh = priv->sh;
1028 	struct mlx5_flow_dv_jump_tbl_resource *cache_resource;
1029 
1030 	/* Lookup a matching resource from cache. */
1031 	LIST_FOREACH(cache_resource, &sh->jump_tbl, next) {
1032 		if (resource->tbl == cache_resource->tbl) {
1033 			DRV_LOG(DEBUG, "jump table resource resource %p: refcnt %d++",
1034 				(void *)cache_resource,
1035 				rte_atomic32_read(&cache_resource->refcnt));
1036 			rte_atomic32_inc(&cache_resource->refcnt);
1037 			dev_flow->dv.jump = cache_resource;
1038 			return 0;
1039 		}
1040 	}
1041 	/* Register new jump table resource. */
1042 	cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
1043 	if (!cache_resource)
1044 		return rte_flow_error_set(error, ENOMEM,
1045 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1046 					  "cannot allocate resource memory");
1047 	*cache_resource = *resource;
1048 	cache_resource->action =
1049 		mlx5_glue->dr_create_flow_action_dest_flow_tbl
1050 		(resource->tbl->obj);
1051 	if (!cache_resource->action) {
1052 		rte_free(cache_resource);
1053 		return rte_flow_error_set(error, ENOMEM,
1054 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1055 					  NULL, "cannot create action");
1056 	}
1057 	rte_atomic32_init(&cache_resource->refcnt);
1058 	rte_atomic32_inc(&cache_resource->refcnt);
1059 	LIST_INSERT_HEAD(&sh->jump_tbl, cache_resource, next);
1060 	dev_flow->dv.jump = cache_resource;
1061 	DRV_LOG(DEBUG, "new jump table  resource %p: refcnt %d++",
1062 		(void *)cache_resource,
1063 		rte_atomic32_read(&cache_resource->refcnt));
1064 	return 0;
1065 }
1066 
1067 /**
1068  * Find existing table port ID resource or create and register a new one.
1069  *
1070  * @param dev[in, out]
1071  *   Pointer to rte_eth_dev structure.
1072  * @param[in, out] resource
1073  *   Pointer to port ID action resource.
1074  * @parm[in, out] dev_flow
1075  *   Pointer to the dev_flow.
1076  * @param[out] error
1077  *   pointer to error structure.
1078  *
1079  * @return
1080  *   0 on success otherwise -errno and errno is set.
1081  */
1082 static int
1083 flow_dv_port_id_action_resource_register
1084 			(struct rte_eth_dev *dev,
1085 			 struct mlx5_flow_dv_port_id_action_resource *resource,
1086 			 struct mlx5_flow *dev_flow,
1087 			 struct rte_flow_error *error)
1088 {
1089 	struct mlx5_priv *priv = dev->data->dev_private;
1090 	struct mlx5_ibv_shared *sh = priv->sh;
1091 	struct mlx5_flow_dv_port_id_action_resource *cache_resource;
1092 
1093 	/* Lookup a matching resource from cache. */
1094 	LIST_FOREACH(cache_resource, &sh->port_id_action_list, next) {
1095 		if (resource->port_id == cache_resource->port_id) {
1096 			DRV_LOG(DEBUG, "port id action resource resource %p: "
1097 				"refcnt %d++",
1098 				(void *)cache_resource,
1099 				rte_atomic32_read(&cache_resource->refcnt));
1100 			rte_atomic32_inc(&cache_resource->refcnt);
1101 			dev_flow->dv.port_id_action = cache_resource;
1102 			return 0;
1103 		}
1104 	}
1105 	/* Register new port id action resource. */
1106 	cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
1107 	if (!cache_resource)
1108 		return rte_flow_error_set(error, ENOMEM,
1109 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1110 					  "cannot allocate resource memory");
1111 	*cache_resource = *resource;
1112 	cache_resource->action =
1113 		mlx5_glue->dr_create_flow_action_dest_vport
1114 			(priv->sh->fdb_domain, resource->port_id);
1115 	if (!cache_resource->action) {
1116 		rte_free(cache_resource);
1117 		return rte_flow_error_set(error, ENOMEM,
1118 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1119 					  NULL, "cannot create action");
1120 	}
1121 	rte_atomic32_init(&cache_resource->refcnt);
1122 	rte_atomic32_inc(&cache_resource->refcnt);
1123 	LIST_INSERT_HEAD(&sh->port_id_action_list, cache_resource, next);
1124 	dev_flow->dv.port_id_action = cache_resource;
1125 	DRV_LOG(DEBUG, "new port id action resource %p: refcnt %d++",
1126 		(void *)cache_resource,
1127 		rte_atomic32_read(&cache_resource->refcnt));
1128 	return 0;
1129 }
1130 
1131 /**
1132  * Get the size of specific rte_flow_item_type
1133  *
1134  * @param[in] item_type
1135  *   Tested rte_flow_item_type.
1136  *
1137  * @return
1138  *   sizeof struct item_type, 0 if void or irrelevant.
1139  */
1140 static size_t
1141 flow_dv_get_item_len(const enum rte_flow_item_type item_type)
1142 {
1143 	size_t retval;
1144 
1145 	switch (item_type) {
1146 	case RTE_FLOW_ITEM_TYPE_ETH:
1147 		retval = sizeof(struct rte_flow_item_eth);
1148 		break;
1149 	case RTE_FLOW_ITEM_TYPE_VLAN:
1150 		retval = sizeof(struct rte_flow_item_vlan);
1151 		break;
1152 	case RTE_FLOW_ITEM_TYPE_IPV4:
1153 		retval = sizeof(struct rte_flow_item_ipv4);
1154 		break;
1155 	case RTE_FLOW_ITEM_TYPE_IPV6:
1156 		retval = sizeof(struct rte_flow_item_ipv6);
1157 		break;
1158 	case RTE_FLOW_ITEM_TYPE_UDP:
1159 		retval = sizeof(struct rte_flow_item_udp);
1160 		break;
1161 	case RTE_FLOW_ITEM_TYPE_TCP:
1162 		retval = sizeof(struct rte_flow_item_tcp);
1163 		break;
1164 	case RTE_FLOW_ITEM_TYPE_VXLAN:
1165 		retval = sizeof(struct rte_flow_item_vxlan);
1166 		break;
1167 	case RTE_FLOW_ITEM_TYPE_GRE:
1168 		retval = sizeof(struct rte_flow_item_gre);
1169 		break;
1170 	case RTE_FLOW_ITEM_TYPE_NVGRE:
1171 		retval = sizeof(struct rte_flow_item_nvgre);
1172 		break;
1173 	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1174 		retval = sizeof(struct rte_flow_item_vxlan_gpe);
1175 		break;
1176 	case RTE_FLOW_ITEM_TYPE_MPLS:
1177 		retval = sizeof(struct rte_flow_item_mpls);
1178 		break;
1179 	case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */
1180 	default:
1181 		retval = 0;
1182 		break;
1183 	}
1184 	return retval;
1185 }
1186 
1187 #define MLX5_ENCAP_IPV4_VERSION		0x40
1188 #define MLX5_ENCAP_IPV4_IHL_MIN		0x05
1189 #define MLX5_ENCAP_IPV4_TTL_DEF		0x40
1190 #define MLX5_ENCAP_IPV6_VTC_FLOW	0x60000000
1191 #define MLX5_ENCAP_IPV6_HOP_LIMIT	0xff
1192 #define MLX5_ENCAP_VXLAN_FLAGS		0x08000000
1193 #define MLX5_ENCAP_VXLAN_GPE_FLAGS	0x04
1194 
1195 /**
1196  * Convert the encap action data from list of rte_flow_item to raw buffer
1197  *
1198  * @param[in] items
1199  *   Pointer to rte_flow_item objects list.
1200  * @param[out] buf
1201  *   Pointer to the output buffer.
1202  * @param[out] size
1203  *   Pointer to the output buffer size.
1204  * @param[out] error
1205  *   Pointer to the error structure.
1206  *
1207  * @return
1208  *   0 on success, a negative errno value otherwise and rte_errno is set.
1209  */
1210 static int
1211 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf,
1212 			   size_t *size, struct rte_flow_error *error)
1213 {
1214 	struct rte_ether_hdr *eth = NULL;
1215 	struct rte_vlan_hdr *vlan = NULL;
1216 	struct rte_ipv4_hdr *ipv4 = NULL;
1217 	struct rte_ipv6_hdr *ipv6 = NULL;
1218 	struct rte_udp_hdr *udp = NULL;
1219 	struct rte_vxlan_hdr *vxlan = NULL;
1220 	struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL;
1221 	struct rte_gre_hdr *gre = NULL;
1222 	size_t len;
1223 	size_t temp_size = 0;
1224 
1225 	if (!items)
1226 		return rte_flow_error_set(error, EINVAL,
1227 					  RTE_FLOW_ERROR_TYPE_ACTION,
1228 					  NULL, "invalid empty data");
1229 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1230 		len = flow_dv_get_item_len(items->type);
1231 		if (len + temp_size > MLX5_ENCAP_MAX_LEN)
1232 			return rte_flow_error_set(error, EINVAL,
1233 						  RTE_FLOW_ERROR_TYPE_ACTION,
1234 						  (void *)items->type,
1235 						  "items total size is too big"
1236 						  " for encap action");
1237 		rte_memcpy((void *)&buf[temp_size], items->spec, len);
1238 		switch (items->type) {
1239 		case RTE_FLOW_ITEM_TYPE_ETH:
1240 			eth = (struct rte_ether_hdr *)&buf[temp_size];
1241 			break;
1242 		case RTE_FLOW_ITEM_TYPE_VLAN:
1243 			vlan = (struct rte_vlan_hdr *)&buf[temp_size];
1244 			if (!eth)
1245 				return rte_flow_error_set(error, EINVAL,
1246 						RTE_FLOW_ERROR_TYPE_ACTION,
1247 						(void *)items->type,
1248 						"eth header not found");
1249 			if (!eth->ether_type)
1250 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN);
1251 			break;
1252 		case RTE_FLOW_ITEM_TYPE_IPV4:
1253 			ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size];
1254 			if (!vlan && !eth)
1255 				return rte_flow_error_set(error, EINVAL,
1256 						RTE_FLOW_ERROR_TYPE_ACTION,
1257 						(void *)items->type,
1258 						"neither eth nor vlan"
1259 						" header found");
1260 			if (vlan && !vlan->eth_proto)
1261 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPv4);
1262 			else if (eth && !eth->ether_type)
1263 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPv4);
1264 			if (!ipv4->version_ihl)
1265 				ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION |
1266 						    MLX5_ENCAP_IPV4_IHL_MIN;
1267 			if (!ipv4->time_to_live)
1268 				ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF;
1269 			break;
1270 		case RTE_FLOW_ITEM_TYPE_IPV6:
1271 			ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size];
1272 			if (!vlan && !eth)
1273 				return rte_flow_error_set(error, EINVAL,
1274 						RTE_FLOW_ERROR_TYPE_ACTION,
1275 						(void *)items->type,
1276 						"neither eth nor vlan"
1277 						" header found");
1278 			if (vlan && !vlan->eth_proto)
1279 				vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPv6);
1280 			else if (eth && !eth->ether_type)
1281 				eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPv6);
1282 			if (!ipv6->vtc_flow)
1283 				ipv6->vtc_flow =
1284 					RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW);
1285 			if (!ipv6->hop_limits)
1286 				ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT;
1287 			break;
1288 		case RTE_FLOW_ITEM_TYPE_UDP:
1289 			udp = (struct rte_udp_hdr *)&buf[temp_size];
1290 			if (!ipv4 && !ipv6)
1291 				return rte_flow_error_set(error, EINVAL,
1292 						RTE_FLOW_ERROR_TYPE_ACTION,
1293 						(void *)items->type,
1294 						"ip header not found");
1295 			if (ipv4 && !ipv4->next_proto_id)
1296 				ipv4->next_proto_id = IPPROTO_UDP;
1297 			else if (ipv6 && !ipv6->proto)
1298 				ipv6->proto = IPPROTO_UDP;
1299 			break;
1300 		case RTE_FLOW_ITEM_TYPE_VXLAN:
1301 			vxlan = (struct rte_vxlan_hdr *)&buf[temp_size];
1302 			if (!udp)
1303 				return rte_flow_error_set(error, EINVAL,
1304 						RTE_FLOW_ERROR_TYPE_ACTION,
1305 						(void *)items->type,
1306 						"udp header not found");
1307 			if (!udp->dst_port)
1308 				udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN);
1309 			if (!vxlan->vx_flags)
1310 				vxlan->vx_flags =
1311 					RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS);
1312 			break;
1313 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1314 			vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size];
1315 			if (!udp)
1316 				return rte_flow_error_set(error, EINVAL,
1317 						RTE_FLOW_ERROR_TYPE_ACTION,
1318 						(void *)items->type,
1319 						"udp header not found");
1320 			if (!vxlan_gpe->proto)
1321 				return rte_flow_error_set(error, EINVAL,
1322 						RTE_FLOW_ERROR_TYPE_ACTION,
1323 						(void *)items->type,
1324 						"next protocol not found");
1325 			if (!udp->dst_port)
1326 				udp->dst_port =
1327 					RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE);
1328 			if (!vxlan_gpe->vx_flags)
1329 				vxlan_gpe->vx_flags =
1330 						MLX5_ENCAP_VXLAN_GPE_FLAGS;
1331 			break;
1332 		case RTE_FLOW_ITEM_TYPE_GRE:
1333 		case RTE_FLOW_ITEM_TYPE_NVGRE:
1334 			gre = (struct rte_gre_hdr *)&buf[temp_size];
1335 			if (!gre->proto)
1336 				return rte_flow_error_set(error, EINVAL,
1337 						RTE_FLOW_ERROR_TYPE_ACTION,
1338 						(void *)items->type,
1339 						"next protocol not found");
1340 			if (!ipv4 && !ipv6)
1341 				return rte_flow_error_set(error, EINVAL,
1342 						RTE_FLOW_ERROR_TYPE_ACTION,
1343 						(void *)items->type,
1344 						"ip header not found");
1345 			if (ipv4 && !ipv4->next_proto_id)
1346 				ipv4->next_proto_id = IPPROTO_GRE;
1347 			else if (ipv6 && !ipv6->proto)
1348 				ipv6->proto = IPPROTO_GRE;
1349 			break;
1350 		case RTE_FLOW_ITEM_TYPE_VOID:
1351 			break;
1352 		default:
1353 			return rte_flow_error_set(error, EINVAL,
1354 						  RTE_FLOW_ERROR_TYPE_ACTION,
1355 						  (void *)items->type,
1356 						  "unsupported item type");
1357 			break;
1358 		}
1359 		temp_size += len;
1360 	}
1361 	*size = temp_size;
1362 	return 0;
1363 }
1364 
1365 /**
1366  * Convert L2 encap action to DV specification.
1367  *
1368  * @param[in] dev
1369  *   Pointer to rte_eth_dev structure.
1370  * @param[in] action
1371  *   Pointer to action structure.
1372  * @param[in, out] dev_flow
1373  *   Pointer to the mlx5_flow.
1374  * @param[in] transfer
1375  *   Mark if the flow is E-Switch flow.
1376  * @param[out] error
1377  *   Pointer to the error structure.
1378  *
1379  * @return
1380  *   0 on success, a negative errno value otherwise and rte_errno is set.
1381  */
1382 static int
1383 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev,
1384 			       const struct rte_flow_action *action,
1385 			       struct mlx5_flow *dev_flow,
1386 			       uint8_t transfer,
1387 			       struct rte_flow_error *error)
1388 {
1389 	const struct rte_flow_item *encap_data;
1390 	const struct rte_flow_action_raw_encap *raw_encap_data;
1391 	struct mlx5_flow_dv_encap_decap_resource res = {
1392 		.reformat_type =
1393 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL,
1394 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
1395 				      MLX5DV_FLOW_TABLE_TYPE_NIC_TX,
1396 	};
1397 
1398 	if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
1399 		raw_encap_data =
1400 			(const struct rte_flow_action_raw_encap *)action->conf;
1401 		res.size = raw_encap_data->size;
1402 		memcpy(res.buf, raw_encap_data->data, res.size);
1403 	} else {
1404 		if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
1405 			encap_data =
1406 				((const struct rte_flow_action_vxlan_encap *)
1407 						action->conf)->definition;
1408 		else
1409 			encap_data =
1410 				((const struct rte_flow_action_nvgre_encap *)
1411 						action->conf)->definition;
1412 		if (flow_dv_convert_encap_data(encap_data, res.buf,
1413 					       &res.size, error))
1414 			return -rte_errno;
1415 	}
1416 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
1417 		return rte_flow_error_set(error, EINVAL,
1418 					  RTE_FLOW_ERROR_TYPE_ACTION,
1419 					  NULL, "can't create L2 encap action");
1420 	return 0;
1421 }
1422 
1423 /**
1424  * Convert L2 decap action to DV specification.
1425  *
1426  * @param[in] dev
1427  *   Pointer to rte_eth_dev structure.
1428  * @param[in, out] dev_flow
1429  *   Pointer to the mlx5_flow.
1430  * @param[in] transfer
1431  *   Mark if the flow is E-Switch flow.
1432  * @param[out] error
1433  *   Pointer to the error structure.
1434  *
1435  * @return
1436  *   0 on success, a negative errno value otherwise and rte_errno is set.
1437  */
1438 static int
1439 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev,
1440 			       struct mlx5_flow *dev_flow,
1441 			       uint8_t transfer,
1442 			       struct rte_flow_error *error)
1443 {
1444 	struct mlx5_flow_dv_encap_decap_resource res = {
1445 		.size = 0,
1446 		.reformat_type =
1447 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2,
1448 		.ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
1449 				      MLX5DV_FLOW_TABLE_TYPE_NIC_RX,
1450 	};
1451 
1452 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
1453 		return rte_flow_error_set(error, EINVAL,
1454 					  RTE_FLOW_ERROR_TYPE_ACTION,
1455 					  NULL, "can't create L2 decap action");
1456 	return 0;
1457 }
1458 
1459 /**
1460  * Convert raw decap/encap (L3 tunnel) action to DV specification.
1461  *
1462  * @param[in] dev
1463  *   Pointer to rte_eth_dev structure.
1464  * @param[in] action
1465  *   Pointer to action structure.
1466  * @param[in, out] dev_flow
1467  *   Pointer to the mlx5_flow.
1468  * @param[in] attr
1469  *   Pointer to the flow attributes.
1470  * @param[out] error
1471  *   Pointer to the error structure.
1472  *
1473  * @return
1474  *   0 on success, a negative errno value otherwise and rte_errno is set.
1475  */
1476 static int
1477 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
1478 				const struct rte_flow_action *action,
1479 				struct mlx5_flow *dev_flow,
1480 				const struct rte_flow_attr *attr,
1481 				struct rte_flow_error *error)
1482 {
1483 	const struct rte_flow_action_raw_encap *encap_data;
1484 	struct mlx5_flow_dv_encap_decap_resource res;
1485 
1486 	encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
1487 	res.size = encap_data->size;
1488 	memcpy(res.buf, encap_data->data, res.size);
1489 	res.reformat_type = attr->egress ?
1490 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL :
1491 		MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
1492 	if (attr->transfer)
1493 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
1494 	else
1495 		res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
1496 					     MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
1497 	if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
1498 		return rte_flow_error_set(error, EINVAL,
1499 					  RTE_FLOW_ERROR_TYPE_ACTION,
1500 					  NULL, "can't create encap action");
1501 	return 0;
1502 }
1503 
1504 /**
1505  * Validate the modify-header actions.
1506  *
1507  * @param[in] action_flags
1508  *   Holds the actions detected until now.
1509  * @param[in] action
1510  *   Pointer to the modify action.
1511  * @param[out] error
1512  *   Pointer to error structure.
1513  *
1514  * @return
1515  *   0 on success, a negative errno value otherwise and rte_errno is set.
1516  */
1517 static int
1518 flow_dv_validate_action_modify_hdr(const uint64_t action_flags,
1519 				   const struct rte_flow_action *action,
1520 				   struct rte_flow_error *error)
1521 {
1522 	if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf)
1523 		return rte_flow_error_set(error, EINVAL,
1524 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1525 					  NULL, "action configuration not set");
1526 	if (action_flags & MLX5_FLOW_ENCAP_ACTIONS)
1527 		return rte_flow_error_set(error, EINVAL,
1528 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1529 					  "can't have encap action before"
1530 					  " modify action");
1531 	return 0;
1532 }
1533 
1534 /**
1535  * Validate the modify-header MAC address actions.
1536  *
1537  * @param[in] action_flags
1538  *   Holds the actions detected until now.
1539  * @param[in] action
1540  *   Pointer to the modify action.
1541  * @param[in] item_flags
1542  *   Holds the items detected.
1543  * @param[out] error
1544  *   Pointer to error structure.
1545  *
1546  * @return
1547  *   0 on success, a negative errno value otherwise and rte_errno is set.
1548  */
1549 static int
1550 flow_dv_validate_action_modify_mac(const uint64_t action_flags,
1551 				   const struct rte_flow_action *action,
1552 				   const uint64_t item_flags,
1553 				   struct rte_flow_error *error)
1554 {
1555 	int ret = 0;
1556 
1557 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
1558 	if (!ret) {
1559 		if (!(item_flags & MLX5_FLOW_LAYER_L2))
1560 			return rte_flow_error_set(error, EINVAL,
1561 						  RTE_FLOW_ERROR_TYPE_ACTION,
1562 						  NULL,
1563 						  "no L2 item in pattern");
1564 	}
1565 	return ret;
1566 }
1567 
1568 /**
1569  * Validate the modify-header IPv4 address actions.
1570  *
1571  * @param[in] action_flags
1572  *   Holds the actions detected until now.
1573  * @param[in] action
1574  *   Pointer to the modify action.
1575  * @param[in] item_flags
1576  *   Holds the items detected.
1577  * @param[out] error
1578  *   Pointer to error structure.
1579  *
1580  * @return
1581  *   0 on success, a negative errno value otherwise and rte_errno is set.
1582  */
1583 static int
1584 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags,
1585 				    const struct rte_flow_action *action,
1586 				    const uint64_t item_flags,
1587 				    struct rte_flow_error *error)
1588 {
1589 	int ret = 0;
1590 
1591 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
1592 	if (!ret) {
1593 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4))
1594 			return rte_flow_error_set(error, EINVAL,
1595 						  RTE_FLOW_ERROR_TYPE_ACTION,
1596 						  NULL,
1597 						  "no ipv4 item in pattern");
1598 	}
1599 	return ret;
1600 }
1601 
1602 /**
1603  * Validate the modify-header IPv6 address actions.
1604  *
1605  * @param[in] action_flags
1606  *   Holds the actions detected until now.
1607  * @param[in] action
1608  *   Pointer to the modify action.
1609  * @param[in] item_flags
1610  *   Holds the items detected.
1611  * @param[out] error
1612  *   Pointer to error structure.
1613  *
1614  * @return
1615  *   0 on success, a negative errno value otherwise and rte_errno is set.
1616  */
1617 static int
1618 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags,
1619 				    const struct rte_flow_action *action,
1620 				    const uint64_t item_flags,
1621 				    struct rte_flow_error *error)
1622 {
1623 	int ret = 0;
1624 
1625 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
1626 	if (!ret) {
1627 		if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6))
1628 			return rte_flow_error_set(error, EINVAL,
1629 						  RTE_FLOW_ERROR_TYPE_ACTION,
1630 						  NULL,
1631 						  "no ipv6 item in pattern");
1632 	}
1633 	return ret;
1634 }
1635 
1636 /**
1637  * Validate the modify-header TP actions.
1638  *
1639  * @param[in] action_flags
1640  *   Holds the actions detected until now.
1641  * @param[in] action
1642  *   Pointer to the modify action.
1643  * @param[in] item_flags
1644  *   Holds the items detected.
1645  * @param[out] error
1646  *   Pointer to error structure.
1647  *
1648  * @return
1649  *   0 on success, a negative errno value otherwise and rte_errno is set.
1650  */
1651 static int
1652 flow_dv_validate_action_modify_tp(const uint64_t action_flags,
1653 				  const struct rte_flow_action *action,
1654 				  const uint64_t item_flags,
1655 				  struct rte_flow_error *error)
1656 {
1657 	int ret = 0;
1658 
1659 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
1660 	if (!ret) {
1661 		if (!(item_flags & MLX5_FLOW_LAYER_L4))
1662 			return rte_flow_error_set(error, EINVAL,
1663 						  RTE_FLOW_ERROR_TYPE_ACTION,
1664 						  NULL, "no transport layer "
1665 						  "in pattern");
1666 	}
1667 	return ret;
1668 }
1669 
1670 /**
1671  * Validate the modify-header TTL actions.
1672  *
1673  * @param[in] action_flags
1674  *   Holds the actions detected until now.
1675  * @param[in] action
1676  *   Pointer to the modify action.
1677  * @param[in] item_flags
1678  *   Holds the items detected.
1679  * @param[out] error
1680  *   Pointer to error structure.
1681  *
1682  * @return
1683  *   0 on success, a negative errno value otherwise and rte_errno is set.
1684  */
1685 static int
1686 flow_dv_validate_action_modify_ttl(const uint64_t action_flags,
1687 				   const struct rte_flow_action *action,
1688 				   const uint64_t item_flags,
1689 				   struct rte_flow_error *error)
1690 {
1691 	int ret = 0;
1692 
1693 	ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
1694 	if (!ret) {
1695 		if (!(item_flags & MLX5_FLOW_LAYER_L3))
1696 			return rte_flow_error_set(error, EINVAL,
1697 						  RTE_FLOW_ERROR_TYPE_ACTION,
1698 						  NULL,
1699 						  "no IP protocol in pattern");
1700 	}
1701 	return ret;
1702 }
1703 
1704 /**
1705  * Validate jump action.
1706  *
1707  * @param[in] action
1708  *   Pointer to the modify action.
1709  * @param[in] group
1710  *   The group of the current flow.
1711  * @param[out] error
1712  *   Pointer to error structure.
1713  *
1714  * @return
1715  *   0 on success, a negative errno value otherwise and rte_errno is set.
1716  */
1717 static int
1718 flow_dv_validate_action_jump(const struct rte_flow_action *action,
1719 			     uint32_t group,
1720 			     struct rte_flow_error *error)
1721 {
1722 	if (action->type != RTE_FLOW_ACTION_TYPE_JUMP && !action->conf)
1723 		return rte_flow_error_set(error, EINVAL,
1724 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1725 					  NULL, "action configuration not set");
1726 	if (group >= ((const struct rte_flow_action_jump *)action->conf)->group)
1727 		return rte_flow_error_set(error, EINVAL,
1728 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1729 					  "target group must be higher then"
1730 					  " the current flow group");
1731 	return 0;
1732 }
1733 
1734 /*
1735  * Validate the port_id action.
1736  *
1737  * @param[in] dev
1738  *   Pointer to rte_eth_dev structure.
1739  * @param[in] action_flags
1740  *   Bit-fields that holds the actions detected until now.
1741  * @param[in] action
1742  *   Port_id RTE action structure.
1743  * @param[in] attr
1744  *   Attributes of flow that includes this action.
1745  * @param[out] error
1746  *   Pointer to error structure.
1747  *
1748  * @return
1749  *   0 on success, a negative errno value otherwise and rte_errno is set.
1750  */
1751 static int
1752 flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
1753 				uint64_t action_flags,
1754 				const struct rte_flow_action *action,
1755 				const struct rte_flow_attr *attr,
1756 				struct rte_flow_error *error)
1757 {
1758 	const struct rte_flow_action_port_id *port_id;
1759 	uint16_t port;
1760 	uint16_t esw_domain_id;
1761 	uint16_t act_port_domain_id;
1762 	int ret;
1763 
1764 	if (!attr->transfer)
1765 		return rte_flow_error_set(error, ENOTSUP,
1766 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1767 					  NULL,
1768 					  "port id action is valid in transfer"
1769 					  " mode only");
1770 	if (!action || !action->conf)
1771 		return rte_flow_error_set(error, ENOTSUP,
1772 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
1773 					  NULL,
1774 					  "port id action parameters must be"
1775 					  " specified");
1776 	if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
1777 			    MLX5_FLOW_FATE_ESWITCH_ACTIONS))
1778 		return rte_flow_error_set(error, EINVAL,
1779 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1780 					  "can have only one fate actions in"
1781 					  " a flow");
1782 	ret = mlx5_port_to_eswitch_info(dev->data->port_id,
1783 					&esw_domain_id, NULL);
1784 	if (ret < 0)
1785 		return rte_flow_error_set(error, -ret,
1786 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1787 					  NULL,
1788 					  "failed to obtain E-Switch info");
1789 	port_id = action->conf;
1790 	port = port_id->original ? dev->data->port_id : port_id->id;
1791 	ret = mlx5_port_to_eswitch_info(port, &act_port_domain_id, NULL);
1792 	if (ret)
1793 		return rte_flow_error_set
1794 				(error, -ret,
1795 				 RTE_FLOW_ERROR_TYPE_ACTION_CONF, port_id,
1796 				 "failed to obtain E-Switch port id for port");
1797 	if (act_port_domain_id != esw_domain_id)
1798 		return rte_flow_error_set
1799 				(error, -ret,
1800 				 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1801 				 "port does not belong to"
1802 				 " E-Switch being configured");
1803 	return 0;
1804 }
1805 
1806 /**
1807  * Find existing modify-header resource or create and register a new one.
1808  *
1809  * @param dev[in, out]
1810  *   Pointer to rte_eth_dev structure.
1811  * @param[in, out] resource
1812  *   Pointer to modify-header resource.
1813  * @parm[in, out] dev_flow
1814  *   Pointer to the dev_flow.
1815  * @param[out] error
1816  *   pointer to error structure.
1817  *
1818  * @return
1819  *   0 on success otherwise -errno and errno is set.
1820  */
1821 static int
1822 flow_dv_modify_hdr_resource_register
1823 			(struct rte_eth_dev *dev,
1824 			 struct mlx5_flow_dv_modify_hdr_resource *resource,
1825 			 struct mlx5_flow *dev_flow,
1826 			 struct rte_flow_error *error)
1827 {
1828 	struct mlx5_priv *priv = dev->data->dev_private;
1829 	struct mlx5_ibv_shared *sh = priv->sh;
1830 	struct mlx5_flow_dv_modify_hdr_resource *cache_resource;
1831 	struct mlx5dv_dr_domain *ns;
1832 
1833 	if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
1834 		ns = sh->fdb_domain;
1835 	else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
1836 		ns = sh->tx_domain;
1837 	else
1838 		ns = sh->rx_domain;
1839 	resource->flags =
1840 		dev_flow->flow->group ? 0 : MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
1841 	/* Lookup a matching resource from cache. */
1842 	LIST_FOREACH(cache_resource, &sh->modify_cmds, next) {
1843 		if (resource->ft_type == cache_resource->ft_type &&
1844 		    resource->actions_num == cache_resource->actions_num &&
1845 		    resource->flags == cache_resource->flags &&
1846 		    !memcmp((const void *)resource->actions,
1847 			    (const void *)cache_resource->actions,
1848 			    (resource->actions_num *
1849 					    sizeof(resource->actions[0])))) {
1850 			DRV_LOG(DEBUG, "modify-header resource %p: refcnt %d++",
1851 				(void *)cache_resource,
1852 				rte_atomic32_read(&cache_resource->refcnt));
1853 			rte_atomic32_inc(&cache_resource->refcnt);
1854 			dev_flow->dv.modify_hdr = cache_resource;
1855 			return 0;
1856 		}
1857 	}
1858 	/* Register new modify-header resource. */
1859 	cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
1860 	if (!cache_resource)
1861 		return rte_flow_error_set(error, ENOMEM,
1862 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1863 					  "cannot allocate resource memory");
1864 	*cache_resource = *resource;
1865 	cache_resource->verbs_action =
1866 		mlx5_glue->dv_create_flow_action_modify_header
1867 					(sh->ctx, cache_resource->ft_type,
1868 					 ns, cache_resource->flags,
1869 					 cache_resource->actions_num *
1870 					 sizeof(cache_resource->actions[0]),
1871 					 (uint64_t *)cache_resource->actions);
1872 	if (!cache_resource->verbs_action) {
1873 		rte_free(cache_resource);
1874 		return rte_flow_error_set(error, ENOMEM,
1875 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1876 					  NULL, "cannot create action");
1877 	}
1878 	rte_atomic32_init(&cache_resource->refcnt);
1879 	rte_atomic32_inc(&cache_resource->refcnt);
1880 	LIST_INSERT_HEAD(&sh->modify_cmds, cache_resource, next);
1881 	dev_flow->dv.modify_hdr = cache_resource;
1882 	DRV_LOG(DEBUG, "new modify-header resource %p: refcnt %d++",
1883 		(void *)cache_resource,
1884 		rte_atomic32_read(&cache_resource->refcnt));
1885 	return 0;
1886 }
1887 
1888 /**
1889  * Get or create a flow counter.
1890  *
1891  * @param[in] dev
1892  *   Pointer to the Ethernet device structure.
1893  * @param[in] shared
1894  *   Indicate if this counter is shared with other flows.
1895  * @param[in] id
1896  *   Counter identifier.
1897  *
1898  * @return
1899  *   pointer to flow counter on success, NULL otherwise and rte_errno is set.
1900  */
1901 static struct mlx5_flow_counter *
1902 flow_dv_counter_new(struct rte_eth_dev *dev, uint32_t shared, uint32_t id)
1903 {
1904 	struct mlx5_priv *priv = dev->data->dev_private;
1905 	struct mlx5_flow_counter *cnt = NULL;
1906 	struct mlx5_devx_counter_set *dcs = NULL;
1907 	int ret;
1908 
1909 	if (!priv->config.devx) {
1910 		ret = -ENOTSUP;
1911 		goto error_exit;
1912 	}
1913 	if (shared) {
1914 		LIST_FOREACH(cnt, &priv->flow_counters, next) {
1915 			if (cnt->shared && cnt->id == id) {
1916 				cnt->ref_cnt++;
1917 				return cnt;
1918 			}
1919 		}
1920 	}
1921 	cnt = rte_calloc(__func__, 1, sizeof(*cnt), 0);
1922 	dcs = rte_calloc(__func__, 1, sizeof(*dcs), 0);
1923 	if (!dcs || !cnt) {
1924 		ret = -ENOMEM;
1925 		goto error_exit;
1926 	}
1927 	ret = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, dcs);
1928 	if (ret)
1929 		goto error_exit;
1930 	struct mlx5_flow_counter tmpl = {
1931 		.shared = shared,
1932 		.ref_cnt = 1,
1933 		.id = id,
1934 		.dcs = dcs,
1935 	};
1936 	tmpl.action = mlx5_glue->dv_create_flow_action_counter(dcs->obj, 0);
1937 	if (!tmpl.action) {
1938 		ret = errno;
1939 		goto error_exit;
1940 	}
1941 	*cnt = tmpl;
1942 	LIST_INSERT_HEAD(&priv->flow_counters, cnt, next);
1943 	return cnt;
1944 error_exit:
1945 	rte_free(cnt);
1946 	rte_free(dcs);
1947 	rte_errno = -ret;
1948 	return NULL;
1949 }
1950 
1951 /**
1952  * Release a flow counter.
1953  *
1954  * @param[in] counter
1955  *   Pointer to the counter handler.
1956  */
1957 static void
1958 flow_dv_counter_release(struct mlx5_flow_counter *counter)
1959 {
1960 	int ret;
1961 
1962 	if (!counter)
1963 		return;
1964 	if (--counter->ref_cnt == 0) {
1965 		ret = mlx5_devx_cmd_flow_counter_free(counter->dcs->obj);
1966 		if (ret)
1967 			DRV_LOG(ERR, "Failed to free devx counters, %d", ret);
1968 		LIST_REMOVE(counter, next);
1969 		rte_free(counter->dcs);
1970 		rte_free(counter);
1971 	}
1972 }
1973 
1974 /**
1975  * Verify the @p attributes will be correctly understood by the NIC and store
1976  * them in the @p flow if everything is correct.
1977  *
1978  * @param[in] dev
1979  *   Pointer to dev struct.
1980  * @param[in] attributes
1981  *   Pointer to flow attributes
1982  * @param[out] error
1983  *   Pointer to error structure.
1984  *
1985  * @return
1986  *   0 on success, a negative errno value otherwise and rte_errno is set.
1987  */
1988 static int
1989 flow_dv_validate_attributes(struct rte_eth_dev *dev,
1990 			    const struct rte_flow_attr *attributes,
1991 			    struct rte_flow_error *error)
1992 {
1993 	struct mlx5_priv *priv = dev->data->dev_private;
1994 	uint32_t priority_max = priv->config.flow_prio - 1;
1995 
1996 #ifndef HAVE_MLX5DV_DR
1997 	if (attributes->group)
1998 		return rte_flow_error_set(error, ENOTSUP,
1999 					  RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
2000 					  NULL,
2001 					  "groups is not supported");
2002 #endif
2003 	if (attributes->priority != MLX5_FLOW_PRIO_RSVD &&
2004 	    attributes->priority >= priority_max)
2005 		return rte_flow_error_set(error, ENOTSUP,
2006 					  RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
2007 					  NULL,
2008 					  "priority out of range");
2009 	if (attributes->transfer) {
2010 		if (!priv->config.dv_esw_en)
2011 			return rte_flow_error_set
2012 				(error, ENOTSUP,
2013 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2014 				 "E-Switch dr is not supported");
2015 		if (!(priv->representor || priv->master))
2016 			return rte_flow_error_set
2017 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2018 				 NULL, "E-Switch configurationd can only be"
2019 				 " done by a master or a representor device");
2020 		if (attributes->egress)
2021 			return rte_flow_error_set
2022 				(error, ENOTSUP,
2023 				 RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes,
2024 				 "egress is not supported");
2025 		if (attributes->group >= MLX5_MAX_TABLES_FDB)
2026 			return rte_flow_error_set
2027 				(error, EINVAL,
2028 				 RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
2029 				 NULL, "group must be smaller than "
2030 				 RTE_STR(MLX5_MAX_FDB_TABLES));
2031 	}
2032 	if (!(attributes->egress ^ attributes->ingress))
2033 		return rte_flow_error_set(error, ENOTSUP,
2034 					  RTE_FLOW_ERROR_TYPE_ATTR, NULL,
2035 					  "must specify exactly one of "
2036 					  "ingress or egress");
2037 	return 0;
2038 }
2039 
2040 /**
2041  * Internal validation function. For validating both actions and items.
2042  *
2043  * @param[in] dev
2044  *   Pointer to the rte_eth_dev structure.
2045  * @param[in] attr
2046  *   Pointer to the flow attributes.
2047  * @param[in] items
2048  *   Pointer to the list of items.
2049  * @param[in] actions
2050  *   Pointer to the list of actions.
2051  * @param[out] error
2052  *   Pointer to the error structure.
2053  *
2054  * @return
2055  *   0 on success, a negative errno value otherwise and rte_errno is set.
2056  */
2057 static int
2058 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
2059 		 const struct rte_flow_item items[],
2060 		 const struct rte_flow_action actions[],
2061 		 struct rte_flow_error *error)
2062 {
2063 	int ret;
2064 	uint64_t action_flags = 0;
2065 	uint64_t item_flags = 0;
2066 	uint64_t last_item = 0;
2067 	uint8_t next_protocol = 0xff;
2068 	int actions_n = 0;
2069 	struct rte_flow_item_tcp nic_tcp_mask = {
2070 		.hdr = {
2071 			.tcp_flags = 0xFF,
2072 			.src_port = RTE_BE16(UINT16_MAX),
2073 			.dst_port = RTE_BE16(UINT16_MAX),
2074 		}
2075 	};
2076 
2077 	if (items == NULL)
2078 		return -1;
2079 	ret = flow_dv_validate_attributes(dev, attr, error);
2080 	if (ret < 0)
2081 		return ret;
2082 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
2083 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
2084 		switch (items->type) {
2085 		case RTE_FLOW_ITEM_TYPE_VOID:
2086 			break;
2087 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
2088 			ret = flow_dv_validate_item_port_id
2089 					(dev, items, attr, item_flags, error);
2090 			if (ret < 0)
2091 				return ret;
2092 			last_item |= MLX5_FLOW_ITEM_PORT_ID;
2093 			break;
2094 		case RTE_FLOW_ITEM_TYPE_ETH:
2095 			ret = mlx5_flow_validate_item_eth(items, item_flags,
2096 							  error);
2097 			if (ret < 0)
2098 				return ret;
2099 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
2100 					     MLX5_FLOW_LAYER_OUTER_L2;
2101 			break;
2102 		case RTE_FLOW_ITEM_TYPE_VLAN:
2103 			ret = mlx5_flow_validate_item_vlan(items, item_flags,
2104 							   error);
2105 			if (ret < 0)
2106 				return ret;
2107 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
2108 					     MLX5_FLOW_LAYER_OUTER_VLAN;
2109 			break;
2110 		case RTE_FLOW_ITEM_TYPE_IPV4:
2111 			ret = mlx5_flow_validate_item_ipv4(items, item_flags,
2112 							   NULL, error);
2113 			if (ret < 0)
2114 				return ret;
2115 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
2116 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
2117 			if (items->mask != NULL &&
2118 			    ((const struct rte_flow_item_ipv4 *)
2119 			     items->mask)->hdr.next_proto_id) {
2120 				next_protocol =
2121 					((const struct rte_flow_item_ipv4 *)
2122 					 (items->spec))->hdr.next_proto_id;
2123 				next_protocol &=
2124 					((const struct rte_flow_item_ipv4 *)
2125 					 (items->mask))->hdr.next_proto_id;
2126 			} else {
2127 				/* Reset for inner layer. */
2128 				next_protocol = 0xff;
2129 			}
2130 			break;
2131 		case RTE_FLOW_ITEM_TYPE_IPV6:
2132 			ret = mlx5_flow_validate_item_ipv6(items, item_flags,
2133 							   NULL, error);
2134 			if (ret < 0)
2135 				return ret;
2136 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
2137 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
2138 			if (items->mask != NULL &&
2139 			    ((const struct rte_flow_item_ipv6 *)
2140 			     items->mask)->hdr.proto) {
2141 				next_protocol =
2142 					((const struct rte_flow_item_ipv6 *)
2143 					 items->spec)->hdr.proto;
2144 				next_protocol &=
2145 					((const struct rte_flow_item_ipv6 *)
2146 					 items->mask)->hdr.proto;
2147 			} else {
2148 				/* Reset for inner layer. */
2149 				next_protocol = 0xff;
2150 			}
2151 			break;
2152 		case RTE_FLOW_ITEM_TYPE_TCP:
2153 			ret = mlx5_flow_validate_item_tcp
2154 						(items, item_flags,
2155 						 next_protocol,
2156 						 &nic_tcp_mask,
2157 						 error);
2158 			if (ret < 0)
2159 				return ret;
2160 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
2161 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
2162 			break;
2163 		case RTE_FLOW_ITEM_TYPE_UDP:
2164 			ret = mlx5_flow_validate_item_udp(items, item_flags,
2165 							  next_protocol,
2166 							  error);
2167 			if (ret < 0)
2168 				return ret;
2169 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
2170 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
2171 			break;
2172 		case RTE_FLOW_ITEM_TYPE_GRE:
2173 		case RTE_FLOW_ITEM_TYPE_NVGRE:
2174 			ret = mlx5_flow_validate_item_gre(items, item_flags,
2175 							  next_protocol, error);
2176 			if (ret < 0)
2177 				return ret;
2178 			last_item = MLX5_FLOW_LAYER_GRE;
2179 			break;
2180 		case RTE_FLOW_ITEM_TYPE_VXLAN:
2181 			ret = mlx5_flow_validate_item_vxlan(items, item_flags,
2182 							    error);
2183 			if (ret < 0)
2184 				return ret;
2185 			last_item = MLX5_FLOW_LAYER_VXLAN;
2186 			break;
2187 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
2188 			ret = mlx5_flow_validate_item_vxlan_gpe(items,
2189 								item_flags, dev,
2190 								error);
2191 			if (ret < 0)
2192 				return ret;
2193 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
2194 			break;
2195 		case RTE_FLOW_ITEM_TYPE_MPLS:
2196 			ret = mlx5_flow_validate_item_mpls(dev, items,
2197 							   item_flags,
2198 							   last_item, error);
2199 			if (ret < 0)
2200 				return ret;
2201 			last_item = MLX5_FLOW_LAYER_MPLS;
2202 			break;
2203 		case RTE_FLOW_ITEM_TYPE_META:
2204 			ret = flow_dv_validate_item_meta(dev, items, attr,
2205 							 error);
2206 			if (ret < 0)
2207 				return ret;
2208 			last_item = MLX5_FLOW_ITEM_METADATA;
2209 			break;
2210 		default:
2211 			return rte_flow_error_set(error, ENOTSUP,
2212 						  RTE_FLOW_ERROR_TYPE_ITEM,
2213 						  NULL, "item not supported");
2214 		}
2215 		item_flags |= last_item;
2216 	}
2217 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
2218 		if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
2219 			return rte_flow_error_set(error, ENOTSUP,
2220 						  RTE_FLOW_ERROR_TYPE_ACTION,
2221 						  actions, "too many actions");
2222 		switch (actions->type) {
2223 		case RTE_FLOW_ACTION_TYPE_VOID:
2224 			break;
2225 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
2226 			ret = flow_dv_validate_action_port_id(dev,
2227 							      action_flags,
2228 							      actions,
2229 							      attr,
2230 							      error);
2231 			if (ret)
2232 				return ret;
2233 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
2234 			++actions_n;
2235 			break;
2236 		case RTE_FLOW_ACTION_TYPE_FLAG:
2237 			ret = mlx5_flow_validate_action_flag(action_flags,
2238 							     attr, error);
2239 			if (ret < 0)
2240 				return ret;
2241 			action_flags |= MLX5_FLOW_ACTION_FLAG;
2242 			++actions_n;
2243 			break;
2244 		case RTE_FLOW_ACTION_TYPE_MARK:
2245 			ret = mlx5_flow_validate_action_mark(actions,
2246 							     action_flags,
2247 							     attr, error);
2248 			if (ret < 0)
2249 				return ret;
2250 			action_flags |= MLX5_FLOW_ACTION_MARK;
2251 			++actions_n;
2252 			break;
2253 		case RTE_FLOW_ACTION_TYPE_DROP:
2254 			ret = mlx5_flow_validate_action_drop(action_flags,
2255 							     attr, error);
2256 			if (ret < 0)
2257 				return ret;
2258 			action_flags |= MLX5_FLOW_ACTION_DROP;
2259 			++actions_n;
2260 			break;
2261 		case RTE_FLOW_ACTION_TYPE_QUEUE:
2262 			ret = mlx5_flow_validate_action_queue(actions,
2263 							      action_flags, dev,
2264 							      attr, error);
2265 			if (ret < 0)
2266 				return ret;
2267 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
2268 			++actions_n;
2269 			break;
2270 		case RTE_FLOW_ACTION_TYPE_RSS:
2271 			ret = mlx5_flow_validate_action_rss(actions,
2272 							    action_flags, dev,
2273 							    attr, item_flags,
2274 							    error);
2275 			if (ret < 0)
2276 				return ret;
2277 			action_flags |= MLX5_FLOW_ACTION_RSS;
2278 			++actions_n;
2279 			break;
2280 		case RTE_FLOW_ACTION_TYPE_COUNT:
2281 			ret = flow_dv_validate_action_count(dev, error);
2282 			if (ret < 0)
2283 				return ret;
2284 			action_flags |= MLX5_FLOW_ACTION_COUNT;
2285 			++actions_n;
2286 			break;
2287 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
2288 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
2289 			ret = flow_dv_validate_action_l2_encap(action_flags,
2290 							       actions, attr,
2291 							       error);
2292 			if (ret < 0)
2293 				return ret;
2294 			action_flags |= actions->type ==
2295 					RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP ?
2296 					MLX5_FLOW_ACTION_VXLAN_ENCAP :
2297 					MLX5_FLOW_ACTION_NVGRE_ENCAP;
2298 			++actions_n;
2299 			break;
2300 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
2301 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
2302 			ret = flow_dv_validate_action_l2_decap(action_flags,
2303 							       attr, error);
2304 			if (ret < 0)
2305 				return ret;
2306 			action_flags |= actions->type ==
2307 					RTE_FLOW_ACTION_TYPE_VXLAN_DECAP ?
2308 					MLX5_FLOW_ACTION_VXLAN_DECAP :
2309 					MLX5_FLOW_ACTION_NVGRE_DECAP;
2310 			++actions_n;
2311 			break;
2312 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
2313 			ret = flow_dv_validate_action_raw_encap(action_flags,
2314 								actions, attr,
2315 								error);
2316 			if (ret < 0)
2317 				return ret;
2318 			action_flags |= MLX5_FLOW_ACTION_RAW_ENCAP;
2319 			++actions_n;
2320 			break;
2321 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
2322 			ret = flow_dv_validate_action_raw_decap(action_flags,
2323 								actions, attr,
2324 								error);
2325 			if (ret < 0)
2326 				return ret;
2327 			action_flags |= MLX5_FLOW_ACTION_RAW_DECAP;
2328 			++actions_n;
2329 			break;
2330 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
2331 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
2332 			ret = flow_dv_validate_action_modify_mac(action_flags,
2333 								 actions,
2334 								 item_flags,
2335 								 error);
2336 			if (ret < 0)
2337 				return ret;
2338 			/* Count all modify-header actions as one action. */
2339 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
2340 				++actions_n;
2341 			action_flags |= actions->type ==
2342 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
2343 						MLX5_FLOW_ACTION_SET_MAC_SRC :
2344 						MLX5_FLOW_ACTION_SET_MAC_DST;
2345 			break;
2346 
2347 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
2348 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
2349 			ret = flow_dv_validate_action_modify_ipv4(action_flags,
2350 								  actions,
2351 								  item_flags,
2352 								  error);
2353 			if (ret < 0)
2354 				return ret;
2355 			/* Count all modify-header actions as one action. */
2356 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
2357 				++actions_n;
2358 			action_flags |= actions->type ==
2359 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
2360 						MLX5_FLOW_ACTION_SET_IPV4_SRC :
2361 						MLX5_FLOW_ACTION_SET_IPV4_DST;
2362 			break;
2363 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
2364 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
2365 			ret = flow_dv_validate_action_modify_ipv6(action_flags,
2366 								  actions,
2367 								  item_flags,
2368 								  error);
2369 			if (ret < 0)
2370 				return ret;
2371 			/* Count all modify-header actions as one action. */
2372 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
2373 				++actions_n;
2374 			action_flags |= actions->type ==
2375 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
2376 						MLX5_FLOW_ACTION_SET_IPV6_SRC :
2377 						MLX5_FLOW_ACTION_SET_IPV6_DST;
2378 			break;
2379 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
2380 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
2381 			ret = flow_dv_validate_action_modify_tp(action_flags,
2382 								actions,
2383 								item_flags,
2384 								error);
2385 			if (ret < 0)
2386 				return ret;
2387 			/* Count all modify-header actions as one action. */
2388 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
2389 				++actions_n;
2390 			action_flags |= actions->type ==
2391 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
2392 						MLX5_FLOW_ACTION_SET_TP_SRC :
2393 						MLX5_FLOW_ACTION_SET_TP_DST;
2394 			break;
2395 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
2396 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
2397 			ret = flow_dv_validate_action_modify_ttl(action_flags,
2398 								 actions,
2399 								 item_flags,
2400 								 error);
2401 			if (ret < 0)
2402 				return ret;
2403 			/* Count all modify-header actions as one action. */
2404 			if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
2405 				++actions_n;
2406 			action_flags |= actions->type ==
2407 					RTE_FLOW_ACTION_TYPE_SET_TTL ?
2408 						MLX5_FLOW_ACTION_SET_TTL :
2409 						MLX5_FLOW_ACTION_DEC_TTL;
2410 			break;
2411 		case RTE_FLOW_ACTION_TYPE_JUMP:
2412 			ret = flow_dv_validate_action_jump(actions,
2413 							   attr->group, error);
2414 			if (ret)
2415 				return ret;
2416 			++actions_n;
2417 			action_flags |= MLX5_FLOW_ACTION_JUMP;
2418 			break;
2419 		default:
2420 			return rte_flow_error_set(error, ENOTSUP,
2421 						  RTE_FLOW_ERROR_TYPE_ACTION,
2422 						  actions,
2423 						  "action not supported");
2424 		}
2425 	}
2426 	/* Eswitch has few restrictions on using items and actions */
2427 	if (attr->transfer) {
2428 		if (action_flags & MLX5_FLOW_ACTION_FLAG)
2429 			return rte_flow_error_set(error, ENOTSUP,
2430 						  RTE_FLOW_ERROR_TYPE_ACTION,
2431 						  NULL,
2432 						  "unsupported action FLAG");
2433 		if (action_flags & MLX5_FLOW_ACTION_MARK)
2434 			return rte_flow_error_set(error, ENOTSUP,
2435 						  RTE_FLOW_ERROR_TYPE_ACTION,
2436 						  NULL,
2437 						  "unsupported action MARK");
2438 		if (action_flags & MLX5_FLOW_ACTION_QUEUE)
2439 			return rte_flow_error_set(error, ENOTSUP,
2440 						  RTE_FLOW_ERROR_TYPE_ACTION,
2441 						  NULL,
2442 						  "unsupported action QUEUE");
2443 		if (action_flags & MLX5_FLOW_ACTION_RSS)
2444 			return rte_flow_error_set(error, ENOTSUP,
2445 						  RTE_FLOW_ERROR_TYPE_ACTION,
2446 						  NULL,
2447 						  "unsupported action RSS");
2448 		if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
2449 			return rte_flow_error_set(error, EINVAL,
2450 						  RTE_FLOW_ERROR_TYPE_ACTION,
2451 						  actions,
2452 						  "no fate action is found");
2453 	} else {
2454 		if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress)
2455 			return rte_flow_error_set(error, EINVAL,
2456 						  RTE_FLOW_ERROR_TYPE_ACTION,
2457 						  actions,
2458 						  "no fate action is found");
2459 	}
2460 	return 0;
2461 }
2462 
2463 /**
2464  * Internal preparation function. Allocates the DV flow size,
2465  * this size is constant.
2466  *
2467  * @param[in] attr
2468  *   Pointer to the flow attributes.
2469  * @param[in] items
2470  *   Pointer to the list of items.
2471  * @param[in] actions
2472  *   Pointer to the list of actions.
2473  * @param[out] error
2474  *   Pointer to the error structure.
2475  *
2476  * @return
2477  *   Pointer to mlx5_flow object on success,
2478  *   otherwise NULL and rte_errno is set.
2479  */
2480 static struct mlx5_flow *
2481 flow_dv_prepare(const struct rte_flow_attr *attr __rte_unused,
2482 		const struct rte_flow_item items[] __rte_unused,
2483 		const struct rte_flow_action actions[] __rte_unused,
2484 		struct rte_flow_error *error)
2485 {
2486 	uint32_t size = sizeof(struct mlx5_flow);
2487 	struct mlx5_flow *flow;
2488 
2489 	flow = rte_calloc(__func__, 1, size, 0);
2490 	if (!flow) {
2491 		rte_flow_error_set(error, ENOMEM,
2492 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2493 				   "not enough memory to create flow");
2494 		return NULL;
2495 	}
2496 	flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
2497 	return flow;
2498 }
2499 
2500 #ifndef NDEBUG
2501 /**
2502  * Sanity check for match mask and value. Similar to check_valid_spec() in
2503  * kernel driver. If unmasked bit is present in value, it returns failure.
2504  *
2505  * @param match_mask
2506  *   pointer to match mask buffer.
2507  * @param match_value
2508  *   pointer to match value buffer.
2509  *
2510  * @return
2511  *   0 if valid, -EINVAL otherwise.
2512  */
2513 static int
2514 flow_dv_check_valid_spec(void *match_mask, void *match_value)
2515 {
2516 	uint8_t *m = match_mask;
2517 	uint8_t *v = match_value;
2518 	unsigned int i;
2519 
2520 	for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) {
2521 		if (v[i] & ~m[i]) {
2522 			DRV_LOG(ERR,
2523 				"match_value differs from match_criteria"
2524 				" %p[%u] != %p[%u]",
2525 				match_value, i, match_mask, i);
2526 			return -EINVAL;
2527 		}
2528 	}
2529 	return 0;
2530 }
2531 #endif
2532 
2533 /**
2534  * Add Ethernet item to matcher and to the value.
2535  *
2536  * @param[in, out] matcher
2537  *   Flow matcher.
2538  * @param[in, out] key
2539  *   Flow matcher value.
2540  * @param[in] item
2541  *   Flow pattern to translate.
2542  * @param[in] inner
2543  *   Item is inner pattern.
2544  */
2545 static void
2546 flow_dv_translate_item_eth(void *matcher, void *key,
2547 			   const struct rte_flow_item *item, int inner)
2548 {
2549 	const struct rte_flow_item_eth *eth_m = item->mask;
2550 	const struct rte_flow_item_eth *eth_v = item->spec;
2551 	const struct rte_flow_item_eth nic_mask = {
2552 		.dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
2553 		.src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
2554 		.type = RTE_BE16(0xffff),
2555 	};
2556 	void *headers_m;
2557 	void *headers_v;
2558 	char *l24_v;
2559 	unsigned int i;
2560 
2561 	if (!eth_v)
2562 		return;
2563 	if (!eth_m)
2564 		eth_m = &nic_mask;
2565 	if (inner) {
2566 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2567 					 inner_headers);
2568 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
2569 	} else {
2570 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2571 					 outer_headers);
2572 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
2573 	}
2574 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, dmac_47_16),
2575 	       &eth_m->dst, sizeof(eth_m->dst));
2576 	/* The value must be in the range of the mask. */
2577 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, dmac_47_16);
2578 	for (i = 0; i < sizeof(eth_m->dst); ++i)
2579 		l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i];
2580 	memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, smac_47_16),
2581 	       &eth_m->src, sizeof(eth_m->src));
2582 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, smac_47_16);
2583 	/* The value must be in the range of the mask. */
2584 	for (i = 0; i < sizeof(eth_m->dst); ++i)
2585 		l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i];
2586 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype,
2587 		 rte_be_to_cpu_16(eth_m->type));
2588 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, ethertype);
2589 	*(uint16_t *)(l24_v) = eth_m->type & eth_v->type;
2590 }
2591 
2592 /**
2593  * Add VLAN item to matcher and to the value.
2594  *
2595  * @param[in, out] matcher
2596  *   Flow matcher.
2597  * @param[in, out] key
2598  *   Flow matcher value.
2599  * @param[in] item
2600  *   Flow pattern to translate.
2601  * @param[in] inner
2602  *   Item is inner pattern.
2603  */
2604 static void
2605 flow_dv_translate_item_vlan(void *matcher, void *key,
2606 			    const struct rte_flow_item *item,
2607 			    int inner)
2608 {
2609 	const struct rte_flow_item_vlan *vlan_m = item->mask;
2610 	const struct rte_flow_item_vlan *vlan_v = item->spec;
2611 	const struct rte_flow_item_vlan nic_mask = {
2612 		.tci = RTE_BE16(0x0fff),
2613 		.inner_type = RTE_BE16(0xffff),
2614 	};
2615 	void *headers_m;
2616 	void *headers_v;
2617 	uint16_t tci_m;
2618 	uint16_t tci_v;
2619 
2620 	if (!vlan_v)
2621 		return;
2622 	if (!vlan_m)
2623 		vlan_m = &nic_mask;
2624 	if (inner) {
2625 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2626 					 inner_headers);
2627 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
2628 	} else {
2629 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2630 					 outer_headers);
2631 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
2632 	}
2633 	tci_m = rte_be_to_cpu_16(vlan_m->tci);
2634 	tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci);
2635 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, cvlan_tag, 1);
2636 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1);
2637 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, first_vid, tci_m);
2638 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, tci_v);
2639 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, first_cfi, tci_m >> 12);
2640 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_cfi, tci_v >> 12);
2641 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, first_prio, tci_m >> 13);
2642 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, tci_v >> 13);
2643 }
2644 
2645 /**
2646  * Add IPV4 item to matcher and to the value.
2647  *
2648  * @param[in, out] matcher
2649  *   Flow matcher.
2650  * @param[in, out] key
2651  *   Flow matcher value.
2652  * @param[in] item
2653  *   Flow pattern to translate.
2654  * @param[in] inner
2655  *   Item is inner pattern.
2656  * @param[in] group
2657  *   The group to insert the rule.
2658  */
2659 static void
2660 flow_dv_translate_item_ipv4(void *matcher, void *key,
2661 			    const struct rte_flow_item *item,
2662 			    int inner, uint32_t group)
2663 {
2664 	const struct rte_flow_item_ipv4 *ipv4_m = item->mask;
2665 	const struct rte_flow_item_ipv4 *ipv4_v = item->spec;
2666 	const struct rte_flow_item_ipv4 nic_mask = {
2667 		.hdr = {
2668 			.src_addr = RTE_BE32(0xffffffff),
2669 			.dst_addr = RTE_BE32(0xffffffff),
2670 			.type_of_service = 0xff,
2671 			.next_proto_id = 0xff,
2672 		},
2673 	};
2674 	void *headers_m;
2675 	void *headers_v;
2676 	char *l24_m;
2677 	char *l24_v;
2678 	uint8_t tos;
2679 
2680 	if (inner) {
2681 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2682 					 inner_headers);
2683 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
2684 	} else {
2685 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2686 					 outer_headers);
2687 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
2688 	}
2689 	if (group == 0)
2690 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
2691 	else
2692 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0x4);
2693 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, 4);
2694 	if (!ipv4_v)
2695 		return;
2696 	if (!ipv4_m)
2697 		ipv4_m = &nic_mask;
2698 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
2699 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
2700 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
2701 			     dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
2702 	*(uint32_t *)l24_m = ipv4_m->hdr.dst_addr;
2703 	*(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr;
2704 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
2705 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
2706 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
2707 			  src_ipv4_src_ipv6.ipv4_layout.ipv4);
2708 	*(uint32_t *)l24_m = ipv4_m->hdr.src_addr;
2709 	*(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr;
2710 	tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service;
2711 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn,
2712 		 ipv4_m->hdr.type_of_service);
2713 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos);
2714 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp,
2715 		 ipv4_m->hdr.type_of_service >> 2);
2716 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2);
2717 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
2718 		 ipv4_m->hdr.next_proto_id);
2719 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
2720 		 ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id);
2721 }
2722 
2723 /**
2724  * Add IPV6 item to matcher and to the value.
2725  *
2726  * @param[in, out] matcher
2727  *   Flow matcher.
2728  * @param[in, out] key
2729  *   Flow matcher value.
2730  * @param[in] item
2731  *   Flow pattern to translate.
2732  * @param[in] inner
2733  *   Item is inner pattern.
2734  * @param[in] group
2735  *   The group to insert the rule.
2736  */
2737 static void
2738 flow_dv_translate_item_ipv6(void *matcher, void *key,
2739 			    const struct rte_flow_item *item,
2740 			    int inner, uint32_t group)
2741 {
2742 	const struct rte_flow_item_ipv6 *ipv6_m = item->mask;
2743 	const struct rte_flow_item_ipv6 *ipv6_v = item->spec;
2744 	const struct rte_flow_item_ipv6 nic_mask = {
2745 		.hdr = {
2746 			.src_addr =
2747 				"\xff\xff\xff\xff\xff\xff\xff\xff"
2748 				"\xff\xff\xff\xff\xff\xff\xff\xff",
2749 			.dst_addr =
2750 				"\xff\xff\xff\xff\xff\xff\xff\xff"
2751 				"\xff\xff\xff\xff\xff\xff\xff\xff",
2752 			.vtc_flow = RTE_BE32(0xffffffff),
2753 			.proto = 0xff,
2754 			.hop_limits = 0xff,
2755 		},
2756 	};
2757 	void *headers_m;
2758 	void *headers_v;
2759 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
2760 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
2761 	char *l24_m;
2762 	char *l24_v;
2763 	uint32_t vtc_m;
2764 	uint32_t vtc_v;
2765 	int i;
2766 	int size;
2767 
2768 	if (inner) {
2769 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2770 					 inner_headers);
2771 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
2772 	} else {
2773 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2774 					 outer_headers);
2775 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
2776 	}
2777 	if (group == 0)
2778 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
2779 	else
2780 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0x6);
2781 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, 6);
2782 	if (!ipv6_v)
2783 		return;
2784 	if (!ipv6_m)
2785 		ipv6_m = &nic_mask;
2786 	size = sizeof(ipv6_m->hdr.dst_addr);
2787 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
2788 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
2789 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
2790 			     dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
2791 	memcpy(l24_m, ipv6_m->hdr.dst_addr, size);
2792 	for (i = 0; i < size; ++i)
2793 		l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i];
2794 	l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
2795 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
2796 	l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
2797 			     src_ipv4_src_ipv6.ipv6_layout.ipv6);
2798 	memcpy(l24_m, ipv6_m->hdr.src_addr, size);
2799 	for (i = 0; i < size; ++i)
2800 		l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i];
2801 	/* TOS. */
2802 	vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow);
2803 	vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow);
2804 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20);
2805 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20);
2806 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22);
2807 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22);
2808 	/* Label. */
2809 	if (inner) {
2810 		MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label,
2811 			 vtc_m);
2812 		MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label,
2813 			 vtc_v);
2814 	} else {
2815 		MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label,
2816 			 vtc_m);
2817 		MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label,
2818 			 vtc_v);
2819 	}
2820 	/* Protocol. */
2821 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
2822 		 ipv6_m->hdr.proto);
2823 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
2824 		 ipv6_v->hdr.proto & ipv6_m->hdr.proto);
2825 }
2826 
2827 /**
2828  * Add TCP item to matcher and to the value.
2829  *
2830  * @param[in, out] matcher
2831  *   Flow matcher.
2832  * @param[in, out] key
2833  *   Flow matcher value.
2834  * @param[in] item
2835  *   Flow pattern to translate.
2836  * @param[in] inner
2837  *   Item is inner pattern.
2838  */
2839 static void
2840 flow_dv_translate_item_tcp(void *matcher, void *key,
2841 			   const struct rte_flow_item *item,
2842 			   int inner)
2843 {
2844 	const struct rte_flow_item_tcp *tcp_m = item->mask;
2845 	const struct rte_flow_item_tcp *tcp_v = item->spec;
2846 	void *headers_m;
2847 	void *headers_v;
2848 
2849 	if (inner) {
2850 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2851 					 inner_headers);
2852 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
2853 	} else {
2854 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2855 					 outer_headers);
2856 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
2857 	}
2858 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
2859 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP);
2860 	if (!tcp_v)
2861 		return;
2862 	if (!tcp_m)
2863 		tcp_m = &rte_flow_item_tcp_mask;
2864 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport,
2865 		 rte_be_to_cpu_16(tcp_m->hdr.src_port));
2866 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
2867 		 rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port));
2868 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport,
2869 		 rte_be_to_cpu_16(tcp_m->hdr.dst_port));
2870 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
2871 		 rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port));
2872 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags,
2873 		 tcp_m->hdr.tcp_flags);
2874 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
2875 		 (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags));
2876 }
2877 
2878 /**
2879  * Add UDP item to matcher and to the value.
2880  *
2881  * @param[in, out] matcher
2882  *   Flow matcher.
2883  * @param[in, out] key
2884  *   Flow matcher value.
2885  * @param[in] item
2886  *   Flow pattern to translate.
2887  * @param[in] inner
2888  *   Item is inner pattern.
2889  */
2890 static void
2891 flow_dv_translate_item_udp(void *matcher, void *key,
2892 			   const struct rte_flow_item *item,
2893 			   int inner)
2894 {
2895 	const struct rte_flow_item_udp *udp_m = item->mask;
2896 	const struct rte_flow_item_udp *udp_v = item->spec;
2897 	void *headers_m;
2898 	void *headers_v;
2899 
2900 	if (inner) {
2901 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2902 					 inner_headers);
2903 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
2904 	} else {
2905 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2906 					 outer_headers);
2907 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
2908 	}
2909 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
2910 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
2911 	if (!udp_v)
2912 		return;
2913 	if (!udp_m)
2914 		udp_m = &rte_flow_item_udp_mask;
2915 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport,
2916 		 rte_be_to_cpu_16(udp_m->hdr.src_port));
2917 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
2918 		 rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port));
2919 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport,
2920 		 rte_be_to_cpu_16(udp_m->hdr.dst_port));
2921 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
2922 		 rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port));
2923 }
2924 
2925 /**
2926  * Add GRE item to matcher and to the value.
2927  *
2928  * @param[in, out] matcher
2929  *   Flow matcher.
2930  * @param[in, out] key
2931  *   Flow matcher value.
2932  * @param[in] item
2933  *   Flow pattern to translate.
2934  * @param[in] inner
2935  *   Item is inner pattern.
2936  */
2937 static void
2938 flow_dv_translate_item_gre(void *matcher, void *key,
2939 			   const struct rte_flow_item *item,
2940 			   int inner)
2941 {
2942 	const struct rte_flow_item_gre *gre_m = item->mask;
2943 	const struct rte_flow_item_gre *gre_v = item->spec;
2944 	void *headers_m;
2945 	void *headers_v;
2946 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
2947 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
2948 
2949 	if (inner) {
2950 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2951 					 inner_headers);
2952 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
2953 	} else {
2954 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
2955 					 outer_headers);
2956 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
2957 	}
2958 	MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
2959 	MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
2960 	if (!gre_v)
2961 		return;
2962 	if (!gre_m)
2963 		gre_m = &rte_flow_item_gre_mask;
2964 	MLX5_SET(fte_match_set_misc, misc_m, gre_protocol,
2965 		 rte_be_to_cpu_16(gre_m->protocol));
2966 	MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
2967 		 rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol));
2968 }
2969 
2970 /**
2971  * Add NVGRE item to matcher and to the value.
2972  *
2973  * @param[in, out] matcher
2974  *   Flow matcher.
2975  * @param[in, out] key
2976  *   Flow matcher value.
2977  * @param[in] item
2978  *   Flow pattern to translate.
2979  * @param[in] inner
2980  *   Item is inner pattern.
2981  */
2982 static void
2983 flow_dv_translate_item_nvgre(void *matcher, void *key,
2984 			     const struct rte_flow_item *item,
2985 			     int inner)
2986 {
2987 	const struct rte_flow_item_nvgre *nvgre_m = item->mask;
2988 	const struct rte_flow_item_nvgre *nvgre_v = item->spec;
2989 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
2990 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
2991 	const char *tni_flow_id_m = (const char *)nvgre_m->tni;
2992 	const char *tni_flow_id_v = (const char *)nvgre_v->tni;
2993 	char *gre_key_m;
2994 	char *gre_key_v;
2995 	int size;
2996 	int i;
2997 
2998 	flow_dv_translate_item_gre(matcher, key, item, inner);
2999 	if (!nvgre_v)
3000 		return;
3001 	if (!nvgre_m)
3002 		nvgre_m = &rte_flow_item_nvgre_mask;
3003 	size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
3004 	gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h);
3005 	gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
3006 	memcpy(gre_key_m, tni_flow_id_m, size);
3007 	for (i = 0; i < size; ++i)
3008 		gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i];
3009 }
3010 
3011 /**
3012  * Add VXLAN item to matcher and to the value.
3013  *
3014  * @param[in, out] matcher
3015  *   Flow matcher.
3016  * @param[in, out] key
3017  *   Flow matcher value.
3018  * @param[in] item
3019  *   Flow pattern to translate.
3020  * @param[in] inner
3021  *   Item is inner pattern.
3022  */
3023 static void
3024 flow_dv_translate_item_vxlan(void *matcher, void *key,
3025 			     const struct rte_flow_item *item,
3026 			     int inner)
3027 {
3028 	const struct rte_flow_item_vxlan *vxlan_m = item->mask;
3029 	const struct rte_flow_item_vxlan *vxlan_v = item->spec;
3030 	void *headers_m;
3031 	void *headers_v;
3032 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
3033 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
3034 	char *vni_m;
3035 	char *vni_v;
3036 	uint16_t dport;
3037 	int size;
3038 	int i;
3039 
3040 	if (inner) {
3041 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3042 					 inner_headers);
3043 		headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
3044 	} else {
3045 		headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3046 					 outer_headers);
3047 		headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
3048 	}
3049 	dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
3050 		MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
3051 	if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
3052 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
3053 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
3054 	}
3055 	if (!vxlan_v)
3056 		return;
3057 	if (!vxlan_m)
3058 		vxlan_m = &rte_flow_item_vxlan_mask;
3059 	size = sizeof(vxlan_m->vni);
3060 	vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni);
3061 	vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni);
3062 	memcpy(vni_m, vxlan_m->vni, size);
3063 	for (i = 0; i < size; ++i)
3064 		vni_v[i] = vni_m[i] & vxlan_v->vni[i];
3065 }
3066 
3067 /**
3068  * Add MPLS item to matcher and to the value.
3069  *
3070  * @param[in, out] matcher
3071  *   Flow matcher.
3072  * @param[in, out] key
3073  *   Flow matcher value.
3074  * @param[in] item
3075  *   Flow pattern to translate.
3076  * @param[in] prev_layer
3077  *   The protocol layer indicated in previous item.
3078  * @param[in] inner
3079  *   Item is inner pattern.
3080  */
3081 static void
3082 flow_dv_translate_item_mpls(void *matcher, void *key,
3083 			    const struct rte_flow_item *item,
3084 			    uint64_t prev_layer,
3085 			    int inner)
3086 {
3087 	const uint32_t *in_mpls_m = item->mask;
3088 	const uint32_t *in_mpls_v = item->spec;
3089 	uint32_t *out_mpls_m = 0;
3090 	uint32_t *out_mpls_v = 0;
3091 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
3092 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
3093 	void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher,
3094 				     misc_parameters_2);
3095 	void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
3096 	void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
3097 	void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
3098 
3099 	switch (prev_layer) {
3100 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
3101 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff);
3102 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
3103 			 MLX5_UDP_PORT_MPLS);
3104 		break;
3105 	case MLX5_FLOW_LAYER_GRE:
3106 		MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff);
3107 		MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
3108 			 RTE_ETHER_TYPE_MPLS);
3109 		break;
3110 	default:
3111 		MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
3112 		MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
3113 			 IPPROTO_MPLS);
3114 		break;
3115 	}
3116 	if (!in_mpls_v)
3117 		return;
3118 	if (!in_mpls_m)
3119 		in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask;
3120 	switch (prev_layer) {
3121 	case MLX5_FLOW_LAYER_OUTER_L4_UDP:
3122 		out_mpls_m =
3123 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
3124 						 outer_first_mpls_over_udp);
3125 		out_mpls_v =
3126 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
3127 						 outer_first_mpls_over_udp);
3128 		break;
3129 	case MLX5_FLOW_LAYER_GRE:
3130 		out_mpls_m =
3131 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
3132 						 outer_first_mpls_over_gre);
3133 		out_mpls_v =
3134 			(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
3135 						 outer_first_mpls_over_gre);
3136 		break;
3137 	default:
3138 		/* Inner MPLS not over GRE is not supported. */
3139 		if (!inner) {
3140 			out_mpls_m =
3141 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
3142 							 misc2_m,
3143 							 outer_first_mpls);
3144 			out_mpls_v =
3145 				(uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
3146 							 misc2_v,
3147 							 outer_first_mpls);
3148 		}
3149 		break;
3150 	}
3151 	if (out_mpls_m && out_mpls_v) {
3152 		*out_mpls_m = *in_mpls_m;
3153 		*out_mpls_v = *in_mpls_v & *in_mpls_m;
3154 	}
3155 }
3156 
3157 /**
3158  * Add META item to matcher
3159  *
3160  * @param[in, out] matcher
3161  *   Flow matcher.
3162  * @param[in, out] key
3163  *   Flow matcher value.
3164  * @param[in] item
3165  *   Flow pattern to translate.
3166  * @param[in] inner
3167  *   Item is inner pattern.
3168  */
3169 static void
3170 flow_dv_translate_item_meta(void *matcher, void *key,
3171 			    const struct rte_flow_item *item)
3172 {
3173 	const struct rte_flow_item_meta *meta_m;
3174 	const struct rte_flow_item_meta *meta_v;
3175 	void *misc2_m =
3176 		MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2);
3177 	void *misc2_v =
3178 		MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
3179 
3180 	meta_m = (const void *)item->mask;
3181 	if (!meta_m)
3182 		meta_m = &rte_flow_item_meta_mask;
3183 	meta_v = (const void *)item->spec;
3184 	if (meta_v) {
3185 		MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a,
3186 			 rte_be_to_cpu_32(meta_m->data));
3187 		MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a,
3188 			 rte_be_to_cpu_32(meta_v->data & meta_m->data));
3189 	}
3190 }
3191 
3192 /**
3193  * Add source vport match to the specified matcher.
3194  *
3195  * @param[in, out] matcher
3196  *   Flow matcher.
3197  * @param[in, out] key
3198  *   Flow matcher value.
3199  * @param[in] port
3200  *   Source vport value to match
3201  * @param[in] mask
3202  *   Mask
3203  */
3204 static void
3205 flow_dv_translate_item_source_vport(void *matcher, void *key,
3206 				    int16_t port, uint16_t mask)
3207 {
3208 	void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
3209 	void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
3210 
3211 	MLX5_SET(fte_match_set_misc, misc_m, source_port, mask);
3212 	MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
3213 }
3214 
3215 /**
3216  * Translate port-id item to eswitch match on  port-id.
3217  *
3218  * @param[in] dev
3219  *   The devich to configure through.
3220  * @param[in, out] matcher
3221  *   Flow matcher.
3222  * @param[in, out] key
3223  *   Flow matcher value.
3224  * @param[in] item
3225  *   Flow pattern to translate.
3226  *
3227  * @return
3228  *   0 on success, a negative errno value otherwise.
3229  */
3230 static int
3231 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher,
3232 			       void *key, const struct rte_flow_item *item)
3233 {
3234 	const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL;
3235 	const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL;
3236 	uint16_t mask, val, id;
3237 	int ret;
3238 
3239 	mask = pid_m ? pid_m->id : 0xffff;
3240 	id = pid_v ? pid_v->id : dev->data->port_id;
3241 	ret = mlx5_port_to_eswitch_info(id, NULL, &val);
3242 	if (ret)
3243 		return ret;
3244 	flow_dv_translate_item_source_vport(matcher, key, val, mask);
3245 	return 0;
3246 }
3247 
3248 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
3249 
3250 #define HEADER_IS_ZERO(match_criteria, headers)				     \
3251 	!(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
3252 		 matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
3253 
3254 /**
3255  * Calculate flow matcher enable bitmap.
3256  *
3257  * @param match_criteria
3258  *   Pointer to flow matcher criteria.
3259  *
3260  * @return
3261  *   Bitmap of enabled fields.
3262  */
3263 static uint8_t
3264 flow_dv_matcher_enable(uint32_t *match_criteria)
3265 {
3266 	uint8_t match_criteria_enable;
3267 
3268 	match_criteria_enable =
3269 		(!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
3270 		MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
3271 	match_criteria_enable |=
3272 		(!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
3273 		MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
3274 	match_criteria_enable |=
3275 		(!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
3276 		MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
3277 	match_criteria_enable |=
3278 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
3279 		MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
3280 #ifdef HAVE_MLX5DV_DR
3281 	match_criteria_enable |=
3282 		(!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
3283 		MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
3284 #endif
3285 	return match_criteria_enable;
3286 }
3287 
3288 
3289 /**
3290  * Get a flow table.
3291  *
3292  * @param dev[in, out]
3293  *   Pointer to rte_eth_dev structure.
3294  * @param[in] table_id
3295  *   Table id to use.
3296  * @param[in] egress
3297  *   Direction of the table.
3298  * @param[in] transfer
3299  *   E-Switch or NIC flow.
3300  * @param[out] error
3301  *   pointer to error structure.
3302  *
3303  * @return
3304  *   Returns tables resource based on the index, NULL in case of failed.
3305  */
3306 static struct mlx5_flow_tbl_resource *
3307 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
3308 			 uint32_t table_id, uint8_t egress,
3309 			 uint8_t transfer,
3310 			 struct rte_flow_error *error)
3311 {
3312 	struct mlx5_priv *priv = dev->data->dev_private;
3313 	struct mlx5_ibv_shared *sh = priv->sh;
3314 	struct mlx5_flow_tbl_resource *tbl;
3315 
3316 #ifdef HAVE_MLX5DV_DR
3317 	if (transfer) {
3318 		tbl = &sh->fdb_tbl[table_id];
3319 		if (!tbl->obj)
3320 			tbl->obj = mlx5_glue->dr_create_flow_tbl
3321 				(sh->fdb_domain, table_id);
3322 	} else if (egress) {
3323 		tbl = &sh->tx_tbl[table_id];
3324 		if (!tbl->obj)
3325 			tbl->obj = mlx5_glue->dr_create_flow_tbl
3326 				(sh->tx_domain, table_id);
3327 	} else {
3328 		tbl = &sh->rx_tbl[table_id];
3329 		if (!tbl->obj)
3330 			tbl->obj = mlx5_glue->dr_create_flow_tbl
3331 				(sh->rx_domain, table_id);
3332 	}
3333 	if (!tbl->obj) {
3334 		rte_flow_error_set(error, ENOMEM,
3335 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3336 				   NULL, "cannot create table");
3337 		return NULL;
3338 	}
3339 	rte_atomic32_inc(&tbl->refcnt);
3340 	return tbl;
3341 #else
3342 	(void)error;
3343 	(void)tbl;
3344 	if (transfer)
3345 		return &sh->fdb_tbl[table_id];
3346 	else if (egress)
3347 		return &sh->tx_tbl[table_id];
3348 	else
3349 		return &sh->rx_tbl[table_id];
3350 #endif
3351 }
3352 
3353 /**
3354  * Release a flow table.
3355  *
3356  * @param[in] tbl
3357  *   Table resource to be released.
3358  *
3359  * @return
3360  *   Returns 0 if table was released, else return 1;
3361  */
3362 static int
3363 flow_dv_tbl_resource_release(struct mlx5_flow_tbl_resource *tbl)
3364 {
3365 	if (!tbl)
3366 		return 0;
3367 	if (rte_atomic32_dec_and_test(&tbl->refcnt)) {
3368 		mlx5_glue->dr_destroy_flow_tbl(tbl->obj);
3369 		tbl->obj = NULL;
3370 		return 0;
3371 	}
3372 	return 1;
3373 }
3374 
3375 /**
3376  * Register the flow matcher.
3377  *
3378  * @param dev[in, out]
3379  *   Pointer to rte_eth_dev structure.
3380  * @param[in, out] matcher
3381  *   Pointer to flow matcher.
3382  * @parm[in, out] dev_flow
3383  *   Pointer to the dev_flow.
3384  * @param[out] error
3385  *   pointer to error structure.
3386  *
3387  * @return
3388  *   0 on success otherwise -errno and errno is set.
3389  */
3390 static int
3391 flow_dv_matcher_register(struct rte_eth_dev *dev,
3392 			 struct mlx5_flow_dv_matcher *matcher,
3393 			 struct mlx5_flow *dev_flow,
3394 			 struct rte_flow_error *error)
3395 {
3396 	struct mlx5_priv *priv = dev->data->dev_private;
3397 	struct mlx5_ibv_shared *sh = priv->sh;
3398 	struct mlx5_flow_dv_matcher *cache_matcher;
3399 	struct mlx5dv_flow_matcher_attr dv_attr = {
3400 		.type = IBV_FLOW_ATTR_NORMAL,
3401 		.match_mask = (void *)&matcher->mask,
3402 	};
3403 	struct mlx5_flow_tbl_resource *tbl = NULL;
3404 
3405 	/* Lookup from cache. */
3406 	LIST_FOREACH(cache_matcher, &sh->matchers, next) {
3407 		if (matcher->crc == cache_matcher->crc &&
3408 		    matcher->priority == cache_matcher->priority &&
3409 		    matcher->egress == cache_matcher->egress &&
3410 		    matcher->group == cache_matcher->group &&
3411 		    matcher->transfer == cache_matcher->transfer &&
3412 		    !memcmp((const void *)matcher->mask.buf,
3413 			    (const void *)cache_matcher->mask.buf,
3414 			    cache_matcher->mask.size)) {
3415 			DRV_LOG(DEBUG,
3416 				"priority %hd use %s matcher %p: refcnt %d++",
3417 				cache_matcher->priority,
3418 				cache_matcher->egress ? "tx" : "rx",
3419 				(void *)cache_matcher,
3420 				rte_atomic32_read(&cache_matcher->refcnt));
3421 			rte_atomic32_inc(&cache_matcher->refcnt);
3422 			dev_flow->dv.matcher = cache_matcher;
3423 			return 0;
3424 		}
3425 	}
3426 	/* Register new matcher. */
3427 	cache_matcher = rte_calloc(__func__, 1, sizeof(*cache_matcher), 0);
3428 	if (!cache_matcher)
3429 		return rte_flow_error_set(error, ENOMEM,
3430 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3431 					  "cannot allocate matcher memory");
3432 	tbl = flow_dv_tbl_resource_get(dev, matcher->group * MLX5_GROUP_FACTOR,
3433 				       matcher->egress, matcher->transfer,
3434 				       error);
3435 	if (!tbl) {
3436 		rte_free(cache_matcher);
3437 		return rte_flow_error_set(error, ENOMEM,
3438 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3439 					  NULL, "cannot create table");
3440 	}
3441 	*cache_matcher = *matcher;
3442 	dv_attr.match_criteria_enable =
3443 		flow_dv_matcher_enable(cache_matcher->mask.buf);
3444 	dv_attr.priority = matcher->priority;
3445 	if (matcher->egress)
3446 		dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
3447 	cache_matcher->matcher_object =
3448 		mlx5_glue->dv_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj);
3449 	if (!cache_matcher->matcher_object) {
3450 		rte_free(cache_matcher);
3451 #ifdef HAVE_MLX5DV_DR
3452 		flow_dv_tbl_resource_release(tbl);
3453 #endif
3454 		return rte_flow_error_set(error, ENOMEM,
3455 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3456 					  NULL, "cannot create matcher");
3457 	}
3458 	rte_atomic32_inc(&cache_matcher->refcnt);
3459 	LIST_INSERT_HEAD(&sh->matchers, cache_matcher, next);
3460 	dev_flow->dv.matcher = cache_matcher;
3461 	DRV_LOG(DEBUG, "priority %hd new %s matcher %p: refcnt %d",
3462 		cache_matcher->priority,
3463 		cache_matcher->egress ? "tx" : "rx", (void *)cache_matcher,
3464 		rte_atomic32_read(&cache_matcher->refcnt));
3465 	rte_atomic32_inc(&tbl->refcnt);
3466 	return 0;
3467 }
3468 
3469 /**
3470  * Find existing tag resource or create and register a new one.
3471  *
3472  * @param dev[in, out]
3473  *   Pointer to rte_eth_dev structure.
3474  * @param[in, out] resource
3475  *   Pointer to tag resource.
3476  * @parm[in, out] dev_flow
3477  *   Pointer to the dev_flow.
3478  * @param[out] error
3479  *   pointer to error structure.
3480  *
3481  * @return
3482  *   0 on success otherwise -errno and errno is set.
3483  */
3484 static int
3485 flow_dv_tag_resource_register
3486 			(struct rte_eth_dev *dev,
3487 			 struct mlx5_flow_dv_tag_resource *resource,
3488 			 struct mlx5_flow *dev_flow,
3489 			 struct rte_flow_error *error)
3490 {
3491 	struct mlx5_priv *priv = dev->data->dev_private;
3492 	struct mlx5_ibv_shared *sh = priv->sh;
3493 	struct mlx5_flow_dv_tag_resource *cache_resource;
3494 
3495 	/* Lookup a matching resource from cache. */
3496 	LIST_FOREACH(cache_resource, &sh->tags, next) {
3497 		if (resource->tag == cache_resource->tag) {
3498 			DRV_LOG(DEBUG, "tag resource %p: refcnt %d++",
3499 				(void *)cache_resource,
3500 				rte_atomic32_read(&cache_resource->refcnt));
3501 			rte_atomic32_inc(&cache_resource->refcnt);
3502 			dev_flow->flow->tag_resource = cache_resource;
3503 			return 0;
3504 		}
3505 	}
3506 	/* Register new  resource. */
3507 	cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
3508 	if (!cache_resource)
3509 		return rte_flow_error_set(error, ENOMEM,
3510 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3511 					  "cannot allocate resource memory");
3512 	*cache_resource = *resource;
3513 	cache_resource->action = mlx5_glue->dv_create_flow_action_tag
3514 		(resource->tag);
3515 	if (!cache_resource->action) {
3516 		rte_free(cache_resource);
3517 		return rte_flow_error_set(error, ENOMEM,
3518 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3519 					  NULL, "cannot create action");
3520 	}
3521 	rte_atomic32_init(&cache_resource->refcnt);
3522 	rte_atomic32_inc(&cache_resource->refcnt);
3523 	LIST_INSERT_HEAD(&sh->tags, cache_resource, next);
3524 	dev_flow->flow->tag_resource = cache_resource;
3525 	DRV_LOG(DEBUG, "new tag resource %p: refcnt %d++",
3526 		(void *)cache_resource,
3527 		rte_atomic32_read(&cache_resource->refcnt));
3528 	return 0;
3529 }
3530 
3531 /**
3532  * Release the tag.
3533  *
3534  * @param dev
3535  *   Pointer to Ethernet device.
3536  * @param flow
3537  *   Pointer to mlx5_flow.
3538  *
3539  * @return
3540  *   1 while a reference on it exists, 0 when freed.
3541  */
3542 static int
3543 flow_dv_tag_release(struct rte_eth_dev *dev,
3544 		    struct mlx5_flow_dv_tag_resource *tag)
3545 {
3546 	assert(tag);
3547 	DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
3548 		dev->data->port_id, (void *)tag,
3549 		rte_atomic32_read(&tag->refcnt));
3550 	if (rte_atomic32_dec_and_test(&tag->refcnt)) {
3551 		claim_zero(mlx5_glue->destroy_flow_action(tag->action));
3552 		LIST_REMOVE(tag, next);
3553 		DRV_LOG(DEBUG, "port %u tag %p: removed",
3554 			dev->data->port_id, (void *)tag);
3555 		rte_free(tag);
3556 		return 0;
3557 	}
3558 	return 1;
3559 }
3560 
3561 /**
3562  * Translate port ID action to vport.
3563  *
3564  * @param[in] dev
3565  *   Pointer to rte_eth_dev structure.
3566  * @param[in] action
3567  *   Pointer to the port ID action.
3568  * @param[out] dst_port_id
3569  *   The target port ID.
3570  * @param[out] error
3571  *   Pointer to the error structure.
3572  *
3573  * @return
3574  *   0 on success, a negative errno value otherwise and rte_errno is set.
3575  */
3576 static int
3577 flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
3578 				 const struct rte_flow_action *action,
3579 				 uint32_t *dst_port_id,
3580 				 struct rte_flow_error *error)
3581 {
3582 	uint32_t port;
3583 	uint16_t port_id;
3584 	int ret;
3585 	const struct rte_flow_action_port_id *conf =
3586 			(const struct rte_flow_action_port_id *)action->conf;
3587 
3588 	port = conf->original ? dev->data->port_id : conf->id;
3589 	ret = mlx5_port_to_eswitch_info(port, NULL, &port_id);
3590 	if (ret)
3591 		return rte_flow_error_set(error, -ret,
3592 					  RTE_FLOW_ERROR_TYPE_ACTION,
3593 					  NULL,
3594 					  "No eswitch info was found for port");
3595 	*dst_port_id = port_id;
3596 	return 0;
3597 }
3598 
3599 /**
3600  * Fill the flow with DV spec.
3601  *
3602  * @param[in] dev
3603  *   Pointer to rte_eth_dev structure.
3604  * @param[in, out] dev_flow
3605  *   Pointer to the sub flow.
3606  * @param[in] attr
3607  *   Pointer to the flow attributes.
3608  * @param[in] items
3609  *   Pointer to the list of items.
3610  * @param[in] actions
3611  *   Pointer to the list of actions.
3612  * @param[out] error
3613  *   Pointer to the error structure.
3614  *
3615  * @return
3616  *   0 on success, a negative errno value otherwise and rte_errno is set.
3617  */
3618 static int
3619 flow_dv_translate(struct rte_eth_dev *dev,
3620 		  struct mlx5_flow *dev_flow,
3621 		  const struct rte_flow_attr *attr,
3622 		  const struct rte_flow_item items[],
3623 		  const struct rte_flow_action actions[],
3624 		  struct rte_flow_error *error)
3625 {
3626 	struct mlx5_priv *priv = dev->data->dev_private;
3627 	struct rte_flow *flow = dev_flow->flow;
3628 	uint64_t item_flags = 0;
3629 	uint64_t last_item = 0;
3630 	uint64_t action_flags = 0;
3631 	uint64_t priority = attr->priority;
3632 	struct mlx5_flow_dv_matcher matcher = {
3633 		.mask = {
3634 			.size = sizeof(matcher.mask.buf),
3635 		},
3636 	};
3637 	int actions_n = 0;
3638 	bool actions_end = false;
3639 	struct mlx5_flow_dv_modify_hdr_resource res = {
3640 		.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
3641 					  MLX5DV_FLOW_TABLE_TYPE_NIC_RX
3642 	};
3643 	union flow_dv_attr flow_attr = { .attr = 0 };
3644 	struct mlx5_flow_dv_tag_resource tag_resource;
3645 	uint32_t modify_action_position = UINT32_MAX;
3646 	void *match_mask = matcher.mask.buf;
3647 	void *match_value = dev_flow->dv.value.buf;
3648 
3649 	flow->group = attr->group;
3650 	if (attr->transfer)
3651 		res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
3652 	if (priority == MLX5_FLOW_PRIO_RSVD)
3653 		priority = priv->config.flow_prio - 1;
3654 	for (; !actions_end ; actions++) {
3655 		const struct rte_flow_action_queue *queue;
3656 		const struct rte_flow_action_rss *rss;
3657 		const struct rte_flow_action *action = actions;
3658 		const struct rte_flow_action_count *count = action->conf;
3659 		const uint8_t *rss_key;
3660 		const struct rte_flow_action_jump *jump_data;
3661 		struct mlx5_flow_dv_jump_tbl_resource jump_tbl_resource;
3662 		struct mlx5_flow_tbl_resource *tbl;
3663 		uint32_t port_id = 0;
3664 		struct mlx5_flow_dv_port_id_action_resource port_id_resource;
3665 
3666 		switch (actions->type) {
3667 		case RTE_FLOW_ACTION_TYPE_VOID:
3668 			break;
3669 		case RTE_FLOW_ACTION_TYPE_PORT_ID:
3670 			if (flow_dv_translate_action_port_id(dev, action,
3671 							     &port_id, error))
3672 				return -rte_errno;
3673 			port_id_resource.port_id = port_id;
3674 			if (flow_dv_port_id_action_resource_register
3675 			    (dev, &port_id_resource, dev_flow, error))
3676 				return -rte_errno;
3677 			dev_flow->dv.actions[actions_n++] =
3678 				dev_flow->dv.port_id_action->action;
3679 			action_flags |= MLX5_FLOW_ACTION_PORT_ID;
3680 			break;
3681 		case RTE_FLOW_ACTION_TYPE_FLAG:
3682 			tag_resource.tag =
3683 				mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
3684 			if (!flow->tag_resource)
3685 				if (flow_dv_tag_resource_register
3686 				    (dev, &tag_resource, dev_flow, error))
3687 					return errno;
3688 			dev_flow->dv.actions[actions_n++] =
3689 				flow->tag_resource->action;
3690 			action_flags |= MLX5_FLOW_ACTION_FLAG;
3691 			break;
3692 		case RTE_FLOW_ACTION_TYPE_MARK:
3693 			tag_resource.tag = mlx5_flow_mark_set
3694 			      (((const struct rte_flow_action_mark *)
3695 			       (actions->conf))->id);
3696 			if (!flow->tag_resource)
3697 				if (flow_dv_tag_resource_register
3698 				    (dev, &tag_resource, dev_flow, error))
3699 					return errno;
3700 			dev_flow->dv.actions[actions_n++] =
3701 				flow->tag_resource->action;
3702 			action_flags |= MLX5_FLOW_ACTION_MARK;
3703 			break;
3704 		case RTE_FLOW_ACTION_TYPE_DROP:
3705 			action_flags |= MLX5_FLOW_ACTION_DROP;
3706 			break;
3707 		case RTE_FLOW_ACTION_TYPE_QUEUE:
3708 			queue = actions->conf;
3709 			flow->rss.queue_num = 1;
3710 			(*flow->queue)[0] = queue->index;
3711 			action_flags |= MLX5_FLOW_ACTION_QUEUE;
3712 			break;
3713 		case RTE_FLOW_ACTION_TYPE_RSS:
3714 			rss = actions->conf;
3715 			if (flow->queue)
3716 				memcpy((*flow->queue), rss->queue,
3717 				       rss->queue_num * sizeof(uint16_t));
3718 			flow->rss.queue_num = rss->queue_num;
3719 			/* NULL RSS key indicates default RSS key. */
3720 			rss_key = !rss->key ? rss_hash_default_key : rss->key;
3721 			memcpy(flow->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
3722 			/* RSS type 0 indicates default RSS type ETH_RSS_IP. */
3723 			flow->rss.types = !rss->types ? ETH_RSS_IP : rss->types;
3724 			flow->rss.level = rss->level;
3725 			action_flags |= MLX5_FLOW_ACTION_RSS;
3726 			break;
3727 		case RTE_FLOW_ACTION_TYPE_COUNT:
3728 			if (!priv->config.devx) {
3729 				rte_errno = ENOTSUP;
3730 				goto cnt_err;
3731 			}
3732 			flow->counter = flow_dv_counter_new(dev, count->shared,
3733 							    count->id);
3734 			if (flow->counter == NULL)
3735 				goto cnt_err;
3736 			dev_flow->dv.actions[actions_n++] =
3737 				flow->counter->action;
3738 			action_flags |= MLX5_FLOW_ACTION_COUNT;
3739 			break;
3740 cnt_err:
3741 			if (rte_errno == ENOTSUP)
3742 				return rte_flow_error_set
3743 					      (error, ENOTSUP,
3744 					       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3745 					       NULL,
3746 					       "count action not supported");
3747 			else
3748 				return rte_flow_error_set
3749 						(error, rte_errno,
3750 						 RTE_FLOW_ERROR_TYPE_ACTION,
3751 						 action,
3752 						 "cannot create counter"
3753 						  " object.");
3754 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
3755 		case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
3756 			if (flow_dv_create_action_l2_encap(dev, actions,
3757 							   dev_flow,
3758 							   attr->transfer,
3759 							   error))
3760 				return -rte_errno;
3761 			dev_flow->dv.actions[actions_n++] =
3762 				dev_flow->dv.encap_decap->verbs_action;
3763 			action_flags |= actions->type ==
3764 					RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP ?
3765 					MLX5_FLOW_ACTION_VXLAN_ENCAP :
3766 					MLX5_FLOW_ACTION_NVGRE_ENCAP;
3767 			break;
3768 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
3769 		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
3770 			if (flow_dv_create_action_l2_decap(dev, dev_flow,
3771 							   attr->transfer,
3772 							   error))
3773 				return -rte_errno;
3774 			dev_flow->dv.actions[actions_n++] =
3775 				dev_flow->dv.encap_decap->verbs_action;
3776 			action_flags |= actions->type ==
3777 					RTE_FLOW_ACTION_TYPE_VXLAN_DECAP ?
3778 					MLX5_FLOW_ACTION_VXLAN_DECAP :
3779 					MLX5_FLOW_ACTION_NVGRE_DECAP;
3780 			break;
3781 		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
3782 			/* Handle encap with preceding decap. */
3783 			if (action_flags & MLX5_FLOW_ACTION_RAW_DECAP) {
3784 				if (flow_dv_create_action_raw_encap
3785 					(dev, actions, dev_flow, attr, error))
3786 					return -rte_errno;
3787 				dev_flow->dv.actions[actions_n++] =
3788 					dev_flow->dv.encap_decap->verbs_action;
3789 			} else {
3790 				/* Handle encap without preceding decap. */
3791 				if (flow_dv_create_action_l2_encap
3792 				    (dev, actions, dev_flow, attr->transfer,
3793 				     error))
3794 					return -rte_errno;
3795 				dev_flow->dv.actions[actions_n++] =
3796 					dev_flow->dv.encap_decap->verbs_action;
3797 			}
3798 			action_flags |= MLX5_FLOW_ACTION_RAW_ENCAP;
3799 			break;
3800 		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
3801 			/* Check if this decap is followed by encap. */
3802 			for (; action->type != RTE_FLOW_ACTION_TYPE_END &&
3803 			       action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP;
3804 			       action++) {
3805 			}
3806 			/* Handle decap only if it isn't followed by encap. */
3807 			if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
3808 				if (flow_dv_create_action_l2_decap
3809 				    (dev, dev_flow, attr->transfer, error))
3810 					return -rte_errno;
3811 				dev_flow->dv.actions[actions_n++] =
3812 					dev_flow->dv.encap_decap->verbs_action;
3813 			}
3814 			/* If decap is followed by encap, handle it at encap. */
3815 			action_flags |= MLX5_FLOW_ACTION_RAW_DECAP;
3816 			break;
3817 		case RTE_FLOW_ACTION_TYPE_JUMP:
3818 			jump_data = action->conf;
3819 			tbl = flow_dv_tbl_resource_get(dev, jump_data->group *
3820 						       MLX5_GROUP_FACTOR,
3821 						       attr->egress,
3822 						       attr->transfer, error);
3823 			if (!tbl)
3824 				return rte_flow_error_set
3825 						(error, errno,
3826 						 RTE_FLOW_ERROR_TYPE_ACTION,
3827 						 NULL,
3828 						 "cannot create jump action.");
3829 			jump_tbl_resource.tbl = tbl;
3830 			if (flow_dv_jump_tbl_resource_register
3831 			    (dev, &jump_tbl_resource, dev_flow, error)) {
3832 				flow_dv_tbl_resource_release(tbl);
3833 				return rte_flow_error_set
3834 						(error, errno,
3835 						 RTE_FLOW_ERROR_TYPE_ACTION,
3836 						 NULL,
3837 						 "cannot create jump action.");
3838 			}
3839 			dev_flow->dv.actions[actions_n++] =
3840 				dev_flow->dv.jump->action;
3841 			action_flags |= MLX5_FLOW_ACTION_JUMP;
3842 			break;
3843 		case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
3844 		case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
3845 			if (flow_dv_convert_action_modify_mac(&res, actions,
3846 							      error))
3847 				return -rte_errno;
3848 			action_flags |= actions->type ==
3849 					RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
3850 					MLX5_FLOW_ACTION_SET_MAC_SRC :
3851 					MLX5_FLOW_ACTION_SET_MAC_DST;
3852 			break;
3853 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
3854 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
3855 			if (flow_dv_convert_action_modify_ipv4(&res, actions,
3856 							       error))
3857 				return -rte_errno;
3858 			action_flags |= actions->type ==
3859 					RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
3860 					MLX5_FLOW_ACTION_SET_IPV4_SRC :
3861 					MLX5_FLOW_ACTION_SET_IPV4_DST;
3862 			break;
3863 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
3864 		case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
3865 			if (flow_dv_convert_action_modify_ipv6(&res, actions,
3866 							       error))
3867 				return -rte_errno;
3868 			action_flags |= actions->type ==
3869 					RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
3870 					MLX5_FLOW_ACTION_SET_IPV6_SRC :
3871 					MLX5_FLOW_ACTION_SET_IPV6_DST;
3872 			break;
3873 		case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
3874 		case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
3875 			if (flow_dv_convert_action_modify_tp(&res, actions,
3876 							     items, &flow_attr,
3877 							     error))
3878 				return -rte_errno;
3879 			action_flags |= actions->type ==
3880 					RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
3881 					MLX5_FLOW_ACTION_SET_TP_SRC :
3882 					MLX5_FLOW_ACTION_SET_TP_DST;
3883 			break;
3884 		case RTE_FLOW_ACTION_TYPE_DEC_TTL:
3885 			if (flow_dv_convert_action_modify_dec_ttl(&res, items,
3886 								  &flow_attr,
3887 								  error))
3888 				return -rte_errno;
3889 			action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
3890 			break;
3891 		case RTE_FLOW_ACTION_TYPE_SET_TTL:
3892 			if (flow_dv_convert_action_modify_ttl(&res, actions,
3893 							     items, &flow_attr,
3894 							     error))
3895 				return -rte_errno;
3896 			action_flags |= MLX5_FLOW_ACTION_SET_TTL;
3897 			break;
3898 		case RTE_FLOW_ACTION_TYPE_END:
3899 			actions_end = true;
3900 			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) {
3901 				/* create modify action if needed. */
3902 				if (flow_dv_modify_hdr_resource_register
3903 								(dev, &res,
3904 								 dev_flow,
3905 								 error))
3906 					return -rte_errno;
3907 				dev_flow->dv.actions[modify_action_position] =
3908 					dev_flow->dv.modify_hdr->verbs_action;
3909 			}
3910 			break;
3911 		default:
3912 			break;
3913 		}
3914 		if ((action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) &&
3915 		    modify_action_position == UINT32_MAX)
3916 			modify_action_position = actions_n++;
3917 	}
3918 	dev_flow->dv.actions_n = actions_n;
3919 	flow->actions = action_flags;
3920 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
3921 		int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
3922 
3923 		switch (items->type) {
3924 		case RTE_FLOW_ITEM_TYPE_PORT_ID:
3925 			flow_dv_translate_item_port_id(dev, match_mask,
3926 						       match_value, items);
3927 			last_item = MLX5_FLOW_ITEM_PORT_ID;
3928 			break;
3929 		case RTE_FLOW_ITEM_TYPE_ETH:
3930 			flow_dv_translate_item_eth(match_mask, match_value,
3931 						   items, tunnel);
3932 			matcher.priority = MLX5_PRIORITY_MAP_L2;
3933 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
3934 					     MLX5_FLOW_LAYER_OUTER_L2;
3935 			break;
3936 		case RTE_FLOW_ITEM_TYPE_VLAN:
3937 			flow_dv_translate_item_vlan(match_mask, match_value,
3938 						    items, tunnel);
3939 			matcher.priority = MLX5_PRIORITY_MAP_L2;
3940 			last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
3941 					      MLX5_FLOW_LAYER_INNER_VLAN) :
3942 					     (MLX5_FLOW_LAYER_OUTER_L2 |
3943 					      MLX5_FLOW_LAYER_OUTER_VLAN);
3944 			break;
3945 		case RTE_FLOW_ITEM_TYPE_IPV4:
3946 			flow_dv_translate_item_ipv4(match_mask, match_value,
3947 						    items, tunnel, attr->group);
3948 			matcher.priority = MLX5_PRIORITY_MAP_L3;
3949 			dev_flow->dv.hash_fields |=
3950 				mlx5_flow_hashfields_adjust
3951 					(dev_flow, tunnel,
3952 					 MLX5_IPV4_LAYER_TYPES,
3953 					 MLX5_IPV4_IBV_RX_HASH);
3954 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
3955 					     MLX5_FLOW_LAYER_OUTER_L3_IPV4;
3956 			break;
3957 		case RTE_FLOW_ITEM_TYPE_IPV6:
3958 			flow_dv_translate_item_ipv6(match_mask, match_value,
3959 						    items, tunnel, attr->group);
3960 			matcher.priority = MLX5_PRIORITY_MAP_L3;
3961 			dev_flow->dv.hash_fields |=
3962 				mlx5_flow_hashfields_adjust
3963 					(dev_flow, tunnel,
3964 					 MLX5_IPV6_LAYER_TYPES,
3965 					 MLX5_IPV6_IBV_RX_HASH);
3966 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
3967 					     MLX5_FLOW_LAYER_OUTER_L3_IPV6;
3968 			break;
3969 		case RTE_FLOW_ITEM_TYPE_TCP:
3970 			flow_dv_translate_item_tcp(match_mask, match_value,
3971 						   items, tunnel);
3972 			matcher.priority = MLX5_PRIORITY_MAP_L4;
3973 			dev_flow->dv.hash_fields |=
3974 				mlx5_flow_hashfields_adjust
3975 					(dev_flow, tunnel, ETH_RSS_TCP,
3976 					 IBV_RX_HASH_SRC_PORT_TCP |
3977 					 IBV_RX_HASH_DST_PORT_TCP);
3978 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
3979 					     MLX5_FLOW_LAYER_OUTER_L4_TCP;
3980 			break;
3981 		case RTE_FLOW_ITEM_TYPE_UDP:
3982 			flow_dv_translate_item_udp(match_mask, match_value,
3983 						   items, tunnel);
3984 			matcher.priority = MLX5_PRIORITY_MAP_L4;
3985 			dev_flow->dv.hash_fields |=
3986 				mlx5_flow_hashfields_adjust
3987 					(dev_flow, tunnel, ETH_RSS_UDP,
3988 					 IBV_RX_HASH_SRC_PORT_UDP |
3989 					 IBV_RX_HASH_DST_PORT_UDP);
3990 			last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
3991 					     MLX5_FLOW_LAYER_OUTER_L4_UDP;
3992 			break;
3993 		case RTE_FLOW_ITEM_TYPE_GRE:
3994 			flow_dv_translate_item_gre(match_mask, match_value,
3995 						   items, tunnel);
3996 			last_item = MLX5_FLOW_LAYER_GRE;
3997 			break;
3998 		case RTE_FLOW_ITEM_TYPE_NVGRE:
3999 			flow_dv_translate_item_nvgre(match_mask, match_value,
4000 						     items, tunnel);
4001 			last_item = MLX5_FLOW_LAYER_GRE;
4002 			break;
4003 		case RTE_FLOW_ITEM_TYPE_VXLAN:
4004 			flow_dv_translate_item_vxlan(match_mask, match_value,
4005 						     items, tunnel);
4006 			last_item = MLX5_FLOW_LAYER_VXLAN;
4007 			break;
4008 		case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
4009 			flow_dv_translate_item_vxlan(match_mask, match_value,
4010 						     items, tunnel);
4011 			last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
4012 			break;
4013 		case RTE_FLOW_ITEM_TYPE_MPLS:
4014 			flow_dv_translate_item_mpls(match_mask, match_value,
4015 						    items, last_item, tunnel);
4016 			last_item = MLX5_FLOW_LAYER_MPLS;
4017 			break;
4018 		case RTE_FLOW_ITEM_TYPE_META:
4019 			flow_dv_translate_item_meta(match_mask, match_value,
4020 						    items);
4021 			last_item = MLX5_FLOW_ITEM_METADATA;
4022 			break;
4023 		default:
4024 			break;
4025 		}
4026 		item_flags |= last_item;
4027 	}
4028 	/*
4029 	 * In case of ingress traffic when E-Switch mode is enabled,
4030 	 * we have two cases where we need to set the source port manually.
4031 	 * The first one, is in case of Nic steering rule, and the second is
4032 	 * E-Switch rule where no port_id item was found. In both cases
4033 	 * the source port is set according the current port in use.
4034 	 */
4035 	if ((attr->ingress && !(item_flags & MLX5_FLOW_ITEM_PORT_ID)) &&
4036 	    (priv->representor || priv->master)) {
4037 		if (flow_dv_translate_item_port_id(dev, match_mask,
4038 						   match_value, NULL))
4039 			return -rte_errno;
4040 	}
4041 	assert(!flow_dv_check_valid_spec(matcher.mask.buf,
4042 					 dev_flow->dv.value.buf));
4043 	dev_flow->layers = item_flags;
4044 	/* Register matcher. */
4045 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
4046 				    matcher.mask.size);
4047 	matcher.priority = mlx5_flow_adjust_priority(dev, priority,
4048 						     matcher.priority);
4049 	matcher.egress = attr->egress;
4050 	matcher.group = attr->group;
4051 	matcher.transfer = attr->transfer;
4052 	if (flow_dv_matcher_register(dev, &matcher, dev_flow, error))
4053 		return -rte_errno;
4054 	return 0;
4055 }
4056 
4057 /**
4058  * Apply the flow to the NIC.
4059  *
4060  * @param[in] dev
4061  *   Pointer to the Ethernet device structure.
4062  * @param[in, out] flow
4063  *   Pointer to flow structure.
4064  * @param[out] error
4065  *   Pointer to error structure.
4066  *
4067  * @return
4068  *   0 on success, a negative errno value otherwise and rte_errno is set.
4069  */
4070 static int
4071 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
4072 	      struct rte_flow_error *error)
4073 {
4074 	struct mlx5_flow_dv *dv;
4075 	struct mlx5_flow *dev_flow;
4076 	struct mlx5_priv *priv = dev->data->dev_private;
4077 	int n;
4078 	int err;
4079 
4080 	LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
4081 		dv = &dev_flow->dv;
4082 		n = dv->actions_n;
4083 		if (flow->actions & MLX5_FLOW_ACTION_DROP) {
4084 			if (flow->transfer) {
4085 				dv->actions[n++] = priv->sh->esw_drop_action;
4086 			} else {
4087 				dv->hrxq = mlx5_hrxq_drop_new(dev);
4088 				if (!dv->hrxq) {
4089 					rte_flow_error_set
4090 						(error, errno,
4091 						 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4092 						 NULL,
4093 						 "cannot get drop hash queue");
4094 					goto error;
4095 				}
4096 				dv->actions[n++] = dv->hrxq->action;
4097 			}
4098 		} else if (flow->actions &
4099 			   (MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)) {
4100 			struct mlx5_hrxq *hrxq;
4101 
4102 			hrxq = mlx5_hrxq_get(dev, flow->key,
4103 					     MLX5_RSS_HASH_KEY_LEN,
4104 					     dv->hash_fields,
4105 					     (*flow->queue),
4106 					     flow->rss.queue_num);
4107 			if (!hrxq)
4108 				hrxq = mlx5_hrxq_new
4109 					(dev, flow->key, MLX5_RSS_HASH_KEY_LEN,
4110 					 dv->hash_fields, (*flow->queue),
4111 					 flow->rss.queue_num,
4112 					 !!(dev_flow->layers &
4113 					    MLX5_FLOW_LAYER_TUNNEL));
4114 			if (!hrxq) {
4115 				rte_flow_error_set
4116 					(error, rte_errno,
4117 					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4118 					 "cannot get hash queue");
4119 				goto error;
4120 			}
4121 			dv->hrxq = hrxq;
4122 			dv->actions[n++] = dv->hrxq->action;
4123 		}
4124 		dv->flow =
4125 			mlx5_glue->dv_create_flow(dv->matcher->matcher_object,
4126 						  (void *)&dv->value, n,
4127 						  dv->actions);
4128 		if (!dv->flow) {
4129 			rte_flow_error_set(error, errno,
4130 					   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4131 					   NULL,
4132 					   "hardware refuses to create flow");
4133 			goto error;
4134 		}
4135 	}
4136 	return 0;
4137 error:
4138 	err = rte_errno; /* Save rte_errno before cleanup. */
4139 	LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
4140 		struct mlx5_flow_dv *dv = &dev_flow->dv;
4141 		if (dv->hrxq) {
4142 			if (flow->actions & MLX5_FLOW_ACTION_DROP)
4143 				mlx5_hrxq_drop_release(dev);
4144 			else
4145 				mlx5_hrxq_release(dev, dv->hrxq);
4146 			dv->hrxq = NULL;
4147 		}
4148 	}
4149 	rte_errno = err; /* Restore rte_errno. */
4150 	return -rte_errno;
4151 }
4152 
4153 /**
4154  * Release the flow matcher.
4155  *
4156  * @param dev
4157  *   Pointer to Ethernet device.
4158  * @param flow
4159  *   Pointer to mlx5_flow.
4160  *
4161  * @return
4162  *   1 while a reference on it exists, 0 when freed.
4163  */
4164 static int
4165 flow_dv_matcher_release(struct rte_eth_dev *dev,
4166 			struct mlx5_flow *flow)
4167 {
4168 	struct mlx5_flow_dv_matcher *matcher = flow->dv.matcher;
4169 	struct mlx5_priv *priv = dev->data->dev_private;
4170 	struct mlx5_ibv_shared *sh = priv->sh;
4171 	struct mlx5_flow_tbl_resource *tbl;
4172 
4173 	assert(matcher->matcher_object);
4174 	DRV_LOG(DEBUG, "port %u matcher %p: refcnt %d--",
4175 		dev->data->port_id, (void *)matcher,
4176 		rte_atomic32_read(&matcher->refcnt));
4177 	if (rte_atomic32_dec_and_test(&matcher->refcnt)) {
4178 		claim_zero(mlx5_glue->dv_destroy_flow_matcher
4179 			   (matcher->matcher_object));
4180 		LIST_REMOVE(matcher, next);
4181 		if (matcher->egress)
4182 			tbl = &sh->tx_tbl[matcher->group];
4183 		else
4184 			tbl = &sh->rx_tbl[matcher->group];
4185 		flow_dv_tbl_resource_release(tbl);
4186 		rte_free(matcher);
4187 		DRV_LOG(DEBUG, "port %u matcher %p: removed",
4188 			dev->data->port_id, (void *)matcher);
4189 		return 0;
4190 	}
4191 	return 1;
4192 }
4193 
4194 /**
4195  * Release an encap/decap resource.
4196  *
4197  * @param flow
4198  *   Pointer to mlx5_flow.
4199  *
4200  * @return
4201  *   1 while a reference on it exists, 0 when freed.
4202  */
4203 static int
4204 flow_dv_encap_decap_resource_release(struct mlx5_flow *flow)
4205 {
4206 	struct mlx5_flow_dv_encap_decap_resource *cache_resource =
4207 						flow->dv.encap_decap;
4208 
4209 	assert(cache_resource->verbs_action);
4210 	DRV_LOG(DEBUG, "encap/decap resource %p: refcnt %d--",
4211 		(void *)cache_resource,
4212 		rte_atomic32_read(&cache_resource->refcnt));
4213 	if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
4214 		claim_zero(mlx5_glue->destroy_flow_action
4215 				(cache_resource->verbs_action));
4216 		LIST_REMOVE(cache_resource, next);
4217 		rte_free(cache_resource);
4218 		DRV_LOG(DEBUG, "encap/decap resource %p: removed",
4219 			(void *)cache_resource);
4220 		return 0;
4221 	}
4222 	return 1;
4223 }
4224 
4225 /**
4226  * Release an jump to table action resource.
4227  *
4228  * @param flow
4229  *   Pointer to mlx5_flow.
4230  *
4231  * @return
4232  *   1 while a reference on it exists, 0 when freed.
4233  */
4234 static int
4235 flow_dv_jump_tbl_resource_release(struct mlx5_flow *flow)
4236 {
4237 	struct mlx5_flow_dv_jump_tbl_resource *cache_resource =
4238 						flow->dv.jump;
4239 
4240 	assert(cache_resource->action);
4241 	DRV_LOG(DEBUG, "jump table resource %p: refcnt %d--",
4242 		(void *)cache_resource,
4243 		rte_atomic32_read(&cache_resource->refcnt));
4244 	if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
4245 		claim_zero(mlx5_glue->destroy_flow_action
4246 				(cache_resource->action));
4247 		LIST_REMOVE(cache_resource, next);
4248 		flow_dv_tbl_resource_release(cache_resource->tbl);
4249 		rte_free(cache_resource);
4250 		DRV_LOG(DEBUG, "jump table resource %p: removed",
4251 			(void *)cache_resource);
4252 		return 0;
4253 	}
4254 	return 1;
4255 }
4256 
4257 /**
4258  * Release a modify-header resource.
4259  *
4260  * @param flow
4261  *   Pointer to mlx5_flow.
4262  *
4263  * @return
4264  *   1 while a reference on it exists, 0 when freed.
4265  */
4266 static int
4267 flow_dv_modify_hdr_resource_release(struct mlx5_flow *flow)
4268 {
4269 	struct mlx5_flow_dv_modify_hdr_resource *cache_resource =
4270 						flow->dv.modify_hdr;
4271 
4272 	assert(cache_resource->verbs_action);
4273 	DRV_LOG(DEBUG, "modify-header resource %p: refcnt %d--",
4274 		(void *)cache_resource,
4275 		rte_atomic32_read(&cache_resource->refcnt));
4276 	if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
4277 		claim_zero(mlx5_glue->destroy_flow_action
4278 				(cache_resource->verbs_action));
4279 		LIST_REMOVE(cache_resource, next);
4280 		rte_free(cache_resource);
4281 		DRV_LOG(DEBUG, "modify-header resource %p: removed",
4282 			(void *)cache_resource);
4283 		return 0;
4284 	}
4285 	return 1;
4286 }
4287 
4288 /**
4289  * Release port ID action resource.
4290  *
4291  * @param flow
4292  *   Pointer to mlx5_flow.
4293  *
4294  * @return
4295  *   1 while a reference on it exists, 0 when freed.
4296  */
4297 static int
4298 flow_dv_port_id_action_resource_release(struct mlx5_flow *flow)
4299 {
4300 	struct mlx5_flow_dv_port_id_action_resource *cache_resource =
4301 		flow->dv.port_id_action;
4302 
4303 	assert(cache_resource->action);
4304 	DRV_LOG(DEBUG, "port ID action resource %p: refcnt %d--",
4305 		(void *)cache_resource,
4306 		rte_atomic32_read(&cache_resource->refcnt));
4307 	if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
4308 		claim_zero(mlx5_glue->destroy_flow_action
4309 				(cache_resource->action));
4310 		LIST_REMOVE(cache_resource, next);
4311 		rte_free(cache_resource);
4312 		DRV_LOG(DEBUG, "port id action resource %p: removed",
4313 			(void *)cache_resource);
4314 		return 0;
4315 	}
4316 	return 1;
4317 }
4318 
4319 /**
4320  * Remove the flow from the NIC but keeps it in memory.
4321  *
4322  * @param[in] dev
4323  *   Pointer to Ethernet device.
4324  * @param[in, out] flow
4325  *   Pointer to flow structure.
4326  */
4327 static void
4328 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
4329 {
4330 	struct mlx5_flow_dv *dv;
4331 	struct mlx5_flow *dev_flow;
4332 
4333 	if (!flow)
4334 		return;
4335 	LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
4336 		dv = &dev_flow->dv;
4337 		if (dv->flow) {
4338 			claim_zero(mlx5_glue->dv_destroy_flow(dv->flow));
4339 			dv->flow = NULL;
4340 		}
4341 		if (dv->hrxq) {
4342 			if (flow->actions & MLX5_FLOW_ACTION_DROP)
4343 				mlx5_hrxq_drop_release(dev);
4344 			else
4345 				mlx5_hrxq_release(dev, dv->hrxq);
4346 			dv->hrxq = NULL;
4347 		}
4348 	}
4349 }
4350 
4351 /**
4352  * Remove the flow from the NIC and the memory.
4353  *
4354  * @param[in] dev
4355  *   Pointer to the Ethernet device structure.
4356  * @param[in, out] flow
4357  *   Pointer to flow structure.
4358  */
4359 static void
4360 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
4361 {
4362 	struct mlx5_flow *dev_flow;
4363 
4364 	if (!flow)
4365 		return;
4366 	flow_dv_remove(dev, flow);
4367 	if (flow->counter) {
4368 		flow_dv_counter_release(flow->counter);
4369 		flow->counter = NULL;
4370 	}
4371 	if (flow->tag_resource) {
4372 		flow_dv_tag_release(dev, flow->tag_resource);
4373 		flow->tag_resource = NULL;
4374 	}
4375 	while (!LIST_EMPTY(&flow->dev_flows)) {
4376 		dev_flow = LIST_FIRST(&flow->dev_flows);
4377 		LIST_REMOVE(dev_flow, next);
4378 		if (dev_flow->dv.matcher)
4379 			flow_dv_matcher_release(dev, dev_flow);
4380 		if (dev_flow->dv.encap_decap)
4381 			flow_dv_encap_decap_resource_release(dev_flow);
4382 		if (dev_flow->dv.modify_hdr)
4383 			flow_dv_modify_hdr_resource_release(dev_flow);
4384 		if (dev_flow->dv.jump)
4385 			flow_dv_jump_tbl_resource_release(dev_flow);
4386 		if (dev_flow->dv.port_id_action)
4387 			flow_dv_port_id_action_resource_release(dev_flow);
4388 		rte_free(dev_flow);
4389 	}
4390 }
4391 
4392 /**
4393  * Query a dv flow  rule for its statistics via devx.
4394  *
4395  * @param[in] dev
4396  *   Pointer to Ethernet device.
4397  * @param[in] flow
4398  *   Pointer to the sub flow.
4399  * @param[out] data
4400  *   data retrieved by the query.
4401  * @param[out] error
4402  *   Perform verbose error reporting if not NULL.
4403  *
4404  * @return
4405  *   0 on success, a negative errno value otherwise and rte_errno is set.
4406  */
4407 static int
4408 flow_dv_query_count(struct rte_eth_dev *dev, struct rte_flow *flow,
4409 		    void *data, struct rte_flow_error *error)
4410 {
4411 	struct mlx5_priv *priv = dev->data->dev_private;
4412 	struct rte_flow_query_count *qc = data;
4413 	uint64_t pkts = 0;
4414 	uint64_t bytes = 0;
4415 	int err;
4416 
4417 	if (!priv->config.devx)
4418 		return rte_flow_error_set(error, ENOTSUP,
4419 					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4420 					  NULL,
4421 					  "counters are not supported");
4422 	if (flow->counter) {
4423 		err = mlx5_devx_cmd_flow_counter_query
4424 						(flow->counter->dcs,
4425 						 qc->reset, &pkts, &bytes);
4426 		if (err)
4427 			return rte_flow_error_set
4428 				(error, err,
4429 				 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4430 				 NULL,
4431 				 "cannot read counters");
4432 		qc->hits_set = 1;
4433 		qc->bytes_set = 1;
4434 		qc->hits = pkts - flow->counter->hits;
4435 		qc->bytes = bytes - flow->counter->bytes;
4436 		if (qc->reset) {
4437 			flow->counter->hits = pkts;
4438 			flow->counter->bytes = bytes;
4439 		}
4440 		return 0;
4441 	}
4442 	return rte_flow_error_set(error, EINVAL,
4443 				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4444 				  NULL,
4445 				  "counters are not available");
4446 }
4447 
4448 /**
4449  * Query a flow.
4450  *
4451  * @see rte_flow_query()
4452  * @see rte_flow_ops
4453  */
4454 static int
4455 flow_dv_query(struct rte_eth_dev *dev,
4456 	      struct rte_flow *flow __rte_unused,
4457 	      const struct rte_flow_action *actions __rte_unused,
4458 	      void *data __rte_unused,
4459 	      struct rte_flow_error *error __rte_unused)
4460 {
4461 	int ret = -EINVAL;
4462 
4463 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
4464 		switch (actions->type) {
4465 		case RTE_FLOW_ACTION_TYPE_VOID:
4466 			break;
4467 		case RTE_FLOW_ACTION_TYPE_COUNT:
4468 			ret = flow_dv_query_count(dev, flow, data, error);
4469 			break;
4470 		default:
4471 			return rte_flow_error_set(error, ENOTSUP,
4472 						  RTE_FLOW_ERROR_TYPE_ACTION,
4473 						  actions,
4474 						  "action not supported");
4475 		}
4476 	}
4477 	return ret;
4478 }
4479 
4480 /*
4481  * Mutex-protected thunk to flow_dv_translate().
4482  */
4483 static int
4484 flow_d_translate(struct rte_eth_dev *dev,
4485 		 struct mlx5_flow *dev_flow,
4486 		 const struct rte_flow_attr *attr,
4487 		 const struct rte_flow_item items[],
4488 		 const struct rte_flow_action actions[],
4489 		 struct rte_flow_error *error)
4490 {
4491 	int ret;
4492 
4493 	flow_d_shared_lock(dev);
4494 	ret = flow_dv_translate(dev, dev_flow, attr, items, actions, error);
4495 	flow_d_shared_unlock(dev);
4496 	return ret;
4497 }
4498 
4499 /*
4500  * Mutex-protected thunk to flow_dv_apply().
4501  */
4502 static int
4503 flow_d_apply(struct rte_eth_dev *dev,
4504 	     struct rte_flow *flow,
4505 	     struct rte_flow_error *error)
4506 {
4507 	int ret;
4508 
4509 	flow_d_shared_lock(dev);
4510 	ret = flow_dv_apply(dev, flow, error);
4511 	flow_d_shared_unlock(dev);
4512 	return ret;
4513 }
4514 
4515 /*
4516  * Mutex-protected thunk to flow_dv_remove().
4517  */
4518 static void
4519 flow_d_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
4520 {
4521 	flow_d_shared_lock(dev);
4522 	flow_dv_remove(dev, flow);
4523 	flow_d_shared_unlock(dev);
4524 }
4525 
4526 /*
4527  * Mutex-protected thunk to flow_dv_destroy().
4528  */
4529 static void
4530 flow_d_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
4531 {
4532 	flow_d_shared_lock(dev);
4533 	flow_dv_destroy(dev, flow);
4534 	flow_d_shared_unlock(dev);
4535 }
4536 
4537 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
4538 	.validate = flow_dv_validate,
4539 	.prepare = flow_dv_prepare,
4540 	.translate = flow_d_translate,
4541 	.apply = flow_d_apply,
4542 	.remove = flow_d_remove,
4543 	.destroy = flow_d_destroy,
4544 	.query = flow_dv_query,
4545 };
4546 
4547 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
4548