net/mlx5: skip table zero to improve insertion rate
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_dv.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2018 Mellanox Technologies, Ltd
3  */
4
5 #include <sys/queue.h>
6 #include <stdalign.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <unistd.h>
10
11 /* Verbs header. */
12 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
13 #ifdef PEDANTIC
14 #pragma GCC diagnostic ignored "-Wpedantic"
15 #endif
16 #include <infiniband/verbs.h>
17 #ifdef PEDANTIC
18 #pragma GCC diagnostic error "-Wpedantic"
19 #endif
20
21 #include <rte_common.h>
22 #include <rte_ether.h>
23 #include <rte_ethdev_driver.h>
24 #include <rte_flow.h>
25 #include <rte_flow_driver.h>
26 #include <rte_malloc.h>
27 #include <rte_ip.h>
28 #include <rte_gre.h>
29
30 #include "mlx5.h"
31 #include "mlx5_defs.h"
32 #include "mlx5_glue.h"
33 #include "mlx5_flow.h"
34 #include "mlx5_prm.h"
35 #include "mlx5_rxtx.h"
36
37 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
38
39 #ifndef HAVE_IBV_FLOW_DEVX_COUNTERS
40 #define MLX5DV_FLOW_ACTION_COUNTERS_DEVX 0
41 #endif
42
43 #ifndef HAVE_MLX5DV_DR_ESWITCH
44 #ifndef MLX5DV_FLOW_TABLE_TYPE_FDB
45 #define MLX5DV_FLOW_TABLE_TYPE_FDB 0
46 #endif
47 #endif
48
49 #ifndef HAVE_MLX5DV_DR
50 #define MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL 1
51 #endif
52
53 /* VLAN header definitions */
54 #define MLX5DV_FLOW_VLAN_PCP_SHIFT 13
55 #define MLX5DV_FLOW_VLAN_PCP_MASK (0x7 << MLX5DV_FLOW_VLAN_PCP_SHIFT)
56 #define MLX5DV_FLOW_VLAN_VID_MASK 0x0fff
57 #define MLX5DV_FLOW_VLAN_PCP_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK)
58 #define MLX5DV_FLOW_VLAN_VID_MASK_BE RTE_BE16(MLX5DV_FLOW_VLAN_VID_MASK)
59
60 union flow_dv_attr {
61         struct {
62                 uint32_t valid:1;
63                 uint32_t ipv4:1;
64                 uint32_t ipv6:1;
65                 uint32_t tcp:1;
66                 uint32_t udp:1;
67                 uint32_t reserved:27;
68         };
69         uint32_t attr;
70 };
71
72 /**
73  * Initialize flow attributes structure according to flow items' types.
74  *
75  * @param[in] item
76  *   Pointer to item specification.
77  * @param[out] attr
78  *   Pointer to flow attributes structure.
79  */
80 static void
81 flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr)
82 {
83         for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
84                 switch (item->type) {
85                 case RTE_FLOW_ITEM_TYPE_IPV4:
86                         attr->ipv4 = 1;
87                         break;
88                 case RTE_FLOW_ITEM_TYPE_IPV6:
89                         attr->ipv6 = 1;
90                         break;
91                 case RTE_FLOW_ITEM_TYPE_UDP:
92                         attr->udp = 1;
93                         break;
94                 case RTE_FLOW_ITEM_TYPE_TCP:
95                         attr->tcp = 1;
96                         break;
97                 default:
98                         break;
99                 }
100         }
101         attr->valid = 1;
102 }
103
104 struct field_modify_info {
105         uint32_t size; /* Size of field in protocol header, in bytes. */
106         uint32_t offset; /* Offset of field in protocol header, in bytes. */
107         enum mlx5_modification_field id;
108 };
109
110 struct field_modify_info modify_eth[] = {
111         {4,  0, MLX5_MODI_OUT_DMAC_47_16},
112         {2,  4, MLX5_MODI_OUT_DMAC_15_0},
113         {4,  6, MLX5_MODI_OUT_SMAC_47_16},
114         {2, 10, MLX5_MODI_OUT_SMAC_15_0},
115         {0, 0, 0},
116 };
117
118 struct field_modify_info modify_vlan_out_first_vid[] = {
119         /* Size in bits !!! */
120         {12, 0, MLX5_MODI_OUT_FIRST_VID},
121         {0, 0, 0},
122 };
123
124 struct field_modify_info modify_ipv4[] = {
125         {1,  8, MLX5_MODI_OUT_IPV4_TTL},
126         {4, 12, MLX5_MODI_OUT_SIPV4},
127         {4, 16, MLX5_MODI_OUT_DIPV4},
128         {0, 0, 0},
129 };
130
131 struct field_modify_info modify_ipv6[] = {
132         {1,  7, MLX5_MODI_OUT_IPV6_HOPLIMIT},
133         {4,  8, MLX5_MODI_OUT_SIPV6_127_96},
134         {4, 12, MLX5_MODI_OUT_SIPV6_95_64},
135         {4, 16, MLX5_MODI_OUT_SIPV6_63_32},
136         {4, 20, MLX5_MODI_OUT_SIPV6_31_0},
137         {4, 24, MLX5_MODI_OUT_DIPV6_127_96},
138         {4, 28, MLX5_MODI_OUT_DIPV6_95_64},
139         {4, 32, MLX5_MODI_OUT_DIPV6_63_32},
140         {4, 36, MLX5_MODI_OUT_DIPV6_31_0},
141         {0, 0, 0},
142 };
143
144 struct field_modify_info modify_udp[] = {
145         {2, 0, MLX5_MODI_OUT_UDP_SPORT},
146         {2, 2, MLX5_MODI_OUT_UDP_DPORT},
147         {0, 0, 0},
148 };
149
150 struct field_modify_info modify_tcp[] = {
151         {2, 0, MLX5_MODI_OUT_TCP_SPORT},
152         {2, 2, MLX5_MODI_OUT_TCP_DPORT},
153         {4, 4, MLX5_MODI_OUT_TCP_SEQ_NUM},
154         {4, 8, MLX5_MODI_OUT_TCP_ACK_NUM},
155         {0, 0, 0},
156 };
157
158 static void
159 mlx5_flow_tunnel_ip_check(const struct rte_flow_item *item __rte_unused,
160                           uint8_t next_protocol, uint64_t *item_flags,
161                           int *tunnel)
162 {
163         assert(item->type == RTE_FLOW_ITEM_TYPE_IPV4 ||
164                item->type == RTE_FLOW_ITEM_TYPE_IPV6);
165         if (next_protocol == IPPROTO_IPIP) {
166                 *item_flags |= MLX5_FLOW_LAYER_IPIP;
167                 *tunnel = 1;
168         }
169         if (next_protocol == IPPROTO_IPV6) {
170                 *item_flags |= MLX5_FLOW_LAYER_IPV6_ENCAP;
171                 *tunnel = 1;
172         }
173 }
174
175 /**
176  * Acquire the synchronizing object to protect multithreaded access
177  * to shared dv context. Lock occurs only if context is actually
178  * shared, i.e. we have multiport IB device and representors are
179  * created.
180  *
181  * @param[in] dev
182  *   Pointer to the rte_eth_dev structure.
183  */
184 static void
185 flow_d_shared_lock(struct rte_eth_dev *dev)
186 {
187         struct mlx5_priv *priv = dev->data->dev_private;
188         struct mlx5_ibv_shared *sh = priv->sh;
189
190         if (sh->dv_refcnt > 1) {
191                 int ret;
192
193                 ret = pthread_mutex_lock(&sh->dv_mutex);
194                 assert(!ret);
195                 (void)ret;
196         }
197 }
198
199 static void
200 flow_d_shared_unlock(struct rte_eth_dev *dev)
201 {
202         struct mlx5_priv *priv = dev->data->dev_private;
203         struct mlx5_ibv_shared *sh = priv->sh;
204
205         if (sh->dv_refcnt > 1) {
206                 int ret;
207
208                 ret = pthread_mutex_unlock(&sh->dv_mutex);
209                 assert(!ret);
210                 (void)ret;
211         }
212 }
213
214 /**
215  * Convert modify-header action to DV specification.
216  *
217  * @param[in] item
218  *   Pointer to item specification.
219  * @param[in] field
220  *   Pointer to field modification information.
221  * @param[in,out] resource
222  *   Pointer to the modify-header resource.
223  * @param[in] type
224  *   Type of modification.
225  * @param[out] error
226  *   Pointer to the error structure.
227  *
228  * @return
229  *   0 on success, a negative errno value otherwise and rte_errno is set.
230  */
231 static int
232 flow_dv_convert_modify_action(struct rte_flow_item *item,
233                               struct field_modify_info *field,
234                               struct mlx5_flow_dv_modify_hdr_resource *resource,
235                               uint32_t type,
236                               struct rte_flow_error *error)
237 {
238         uint32_t i = resource->actions_num;
239         struct mlx5_modification_cmd *actions = resource->actions;
240         const uint8_t *spec = item->spec;
241         const uint8_t *mask = item->mask;
242         uint32_t set;
243
244         while (field->size) {
245                 set = 0;
246                 /* Generate modify command for each mask segment. */
247                 memcpy(&set, &mask[field->offset], field->size);
248                 if (set) {
249                         if (i >= MLX5_MODIFY_NUM)
250                                 return rte_flow_error_set(error, EINVAL,
251                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
252                                          "too many items to modify");
253                         actions[i].action_type = type;
254                         actions[i].field = field->id;
255                         actions[i].length = field->size ==
256                                         4 ? 0 : field->size * 8;
257                         rte_memcpy(&actions[i].data[4 - field->size],
258                                    &spec[field->offset], field->size);
259                         actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
260                         ++i;
261                 }
262                 if (resource->actions_num != i)
263                         resource->actions_num = i;
264                 field++;
265         }
266         if (!resource->actions_num)
267                 return rte_flow_error_set(error, EINVAL,
268                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
269                                           "invalid modification flow item");
270         return 0;
271 }
272
273 /**
274  * Convert modify-header set IPv4 address action to DV specification.
275  *
276  * @param[in,out] resource
277  *   Pointer to the modify-header resource.
278  * @param[in] action
279  *   Pointer to action specification.
280  * @param[out] error
281  *   Pointer to the error structure.
282  *
283  * @return
284  *   0 on success, a negative errno value otherwise and rte_errno is set.
285  */
286 static int
287 flow_dv_convert_action_modify_ipv4
288                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
289                          const struct rte_flow_action *action,
290                          struct rte_flow_error *error)
291 {
292         const struct rte_flow_action_set_ipv4 *conf =
293                 (const struct rte_flow_action_set_ipv4 *)(action->conf);
294         struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV4 };
295         struct rte_flow_item_ipv4 ipv4;
296         struct rte_flow_item_ipv4 ipv4_mask;
297
298         memset(&ipv4, 0, sizeof(ipv4));
299         memset(&ipv4_mask, 0, sizeof(ipv4_mask));
300         if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC) {
301                 ipv4.hdr.src_addr = conf->ipv4_addr;
302                 ipv4_mask.hdr.src_addr = rte_flow_item_ipv4_mask.hdr.src_addr;
303         } else {
304                 ipv4.hdr.dst_addr = conf->ipv4_addr;
305                 ipv4_mask.hdr.dst_addr = rte_flow_item_ipv4_mask.hdr.dst_addr;
306         }
307         item.spec = &ipv4;
308         item.mask = &ipv4_mask;
309         return flow_dv_convert_modify_action(&item, modify_ipv4, resource,
310                                              MLX5_MODIFICATION_TYPE_SET, error);
311 }
312
313 /**
314  * Convert modify-header set IPv6 address action to DV specification.
315  *
316  * @param[in,out] resource
317  *   Pointer to the modify-header resource.
318  * @param[in] action
319  *   Pointer to action specification.
320  * @param[out] error
321  *   Pointer to the error structure.
322  *
323  * @return
324  *   0 on success, a negative errno value otherwise and rte_errno is set.
325  */
326 static int
327 flow_dv_convert_action_modify_ipv6
328                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
329                          const struct rte_flow_action *action,
330                          struct rte_flow_error *error)
331 {
332         const struct rte_flow_action_set_ipv6 *conf =
333                 (const struct rte_flow_action_set_ipv6 *)(action->conf);
334         struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_IPV6 };
335         struct rte_flow_item_ipv6 ipv6;
336         struct rte_flow_item_ipv6 ipv6_mask;
337
338         memset(&ipv6, 0, sizeof(ipv6));
339         memset(&ipv6_mask, 0, sizeof(ipv6_mask));
340         if (action->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC) {
341                 memcpy(&ipv6.hdr.src_addr, &conf->ipv6_addr,
342                        sizeof(ipv6.hdr.src_addr));
343                 memcpy(&ipv6_mask.hdr.src_addr,
344                        &rte_flow_item_ipv6_mask.hdr.src_addr,
345                        sizeof(ipv6.hdr.src_addr));
346         } else {
347                 memcpy(&ipv6.hdr.dst_addr, &conf->ipv6_addr,
348                        sizeof(ipv6.hdr.dst_addr));
349                 memcpy(&ipv6_mask.hdr.dst_addr,
350                        &rte_flow_item_ipv6_mask.hdr.dst_addr,
351                        sizeof(ipv6.hdr.dst_addr));
352         }
353         item.spec = &ipv6;
354         item.mask = &ipv6_mask;
355         return flow_dv_convert_modify_action(&item, modify_ipv6, resource,
356                                              MLX5_MODIFICATION_TYPE_SET, error);
357 }
358
359 /**
360  * Convert modify-header set MAC address action to DV specification.
361  *
362  * @param[in,out] resource
363  *   Pointer to the modify-header resource.
364  * @param[in] action
365  *   Pointer to action specification.
366  * @param[out] error
367  *   Pointer to the error structure.
368  *
369  * @return
370  *   0 on success, a negative errno value otherwise and rte_errno is set.
371  */
372 static int
373 flow_dv_convert_action_modify_mac
374                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
375                          const struct rte_flow_action *action,
376                          struct rte_flow_error *error)
377 {
378         const struct rte_flow_action_set_mac *conf =
379                 (const struct rte_flow_action_set_mac *)(action->conf);
380         struct rte_flow_item item = { .type = RTE_FLOW_ITEM_TYPE_ETH };
381         struct rte_flow_item_eth eth;
382         struct rte_flow_item_eth eth_mask;
383
384         memset(&eth, 0, sizeof(eth));
385         memset(&eth_mask, 0, sizeof(eth_mask));
386         if (action->type == RTE_FLOW_ACTION_TYPE_SET_MAC_SRC) {
387                 memcpy(&eth.src.addr_bytes, &conf->mac_addr,
388                        sizeof(eth.src.addr_bytes));
389                 memcpy(&eth_mask.src.addr_bytes,
390                        &rte_flow_item_eth_mask.src.addr_bytes,
391                        sizeof(eth_mask.src.addr_bytes));
392         } else {
393                 memcpy(&eth.dst.addr_bytes, &conf->mac_addr,
394                        sizeof(eth.dst.addr_bytes));
395                 memcpy(&eth_mask.dst.addr_bytes,
396                        &rte_flow_item_eth_mask.dst.addr_bytes,
397                        sizeof(eth_mask.dst.addr_bytes));
398         }
399         item.spec = &eth;
400         item.mask = &eth_mask;
401         return flow_dv_convert_modify_action(&item, modify_eth, resource,
402                                              MLX5_MODIFICATION_TYPE_SET, error);
403 }
404
405 /**
406  * Convert modify-header set VLAN VID action to DV specification.
407  *
408  * @param[in,out] resource
409  *   Pointer to the modify-header resource.
410  * @param[in] action
411  *   Pointer to action specification.
412  * @param[out] error
413  *   Pointer to the error structure.
414  *
415  * @return
416  *   0 on success, a negative errno value otherwise and rte_errno is set.
417  */
418 static int
419 flow_dv_convert_action_modify_vlan_vid
420                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
421                          const struct rte_flow_action *action,
422                          struct rte_flow_error *error)
423 {
424         const struct rte_flow_action_of_set_vlan_vid *conf =
425                 (const struct rte_flow_action_of_set_vlan_vid *)(action->conf);
426         int i = resource->actions_num;
427         struct mlx5_modification_cmd *actions = &resource->actions[i];
428         struct field_modify_info *field = modify_vlan_out_first_vid;
429
430         if (i >= MLX5_MODIFY_NUM)
431                 return rte_flow_error_set(error, EINVAL,
432                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
433                          "too many items to modify");
434         actions[i].action_type = MLX5_MODIFICATION_TYPE_SET;
435         actions[i].field = field->id;
436         actions[i].length = field->size;
437         actions[i].offset = field->offset;
438         actions[i].data0 = rte_cpu_to_be_32(actions[i].data0);
439         actions[i].data1 = conf->vlan_vid;
440         actions[i].data1 = actions[i].data1 << 16;
441         resource->actions_num = ++i;
442         return 0;
443 }
444
445 /**
446  * Convert modify-header set TP action to DV specification.
447  *
448  * @param[in,out] resource
449  *   Pointer to the modify-header resource.
450  * @param[in] action
451  *   Pointer to action specification.
452  * @param[in] items
453  *   Pointer to rte_flow_item objects list.
454  * @param[in] attr
455  *   Pointer to flow attributes structure.
456  * @param[out] error
457  *   Pointer to the error structure.
458  *
459  * @return
460  *   0 on success, a negative errno value otherwise and rte_errno is set.
461  */
462 static int
463 flow_dv_convert_action_modify_tp
464                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
465                          const struct rte_flow_action *action,
466                          const struct rte_flow_item *items,
467                          union flow_dv_attr *attr,
468                          struct rte_flow_error *error)
469 {
470         const struct rte_flow_action_set_tp *conf =
471                 (const struct rte_flow_action_set_tp *)(action->conf);
472         struct rte_flow_item item;
473         struct rte_flow_item_udp udp;
474         struct rte_flow_item_udp udp_mask;
475         struct rte_flow_item_tcp tcp;
476         struct rte_flow_item_tcp tcp_mask;
477         struct field_modify_info *field;
478
479         if (!attr->valid)
480                 flow_dv_attr_init(items, attr);
481         if (attr->udp) {
482                 memset(&udp, 0, sizeof(udp));
483                 memset(&udp_mask, 0, sizeof(udp_mask));
484                 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
485                         udp.hdr.src_port = conf->port;
486                         udp_mask.hdr.src_port =
487                                         rte_flow_item_udp_mask.hdr.src_port;
488                 } else {
489                         udp.hdr.dst_port = conf->port;
490                         udp_mask.hdr.dst_port =
491                                         rte_flow_item_udp_mask.hdr.dst_port;
492                 }
493                 item.type = RTE_FLOW_ITEM_TYPE_UDP;
494                 item.spec = &udp;
495                 item.mask = &udp_mask;
496                 field = modify_udp;
497         }
498         if (attr->tcp) {
499                 memset(&tcp, 0, sizeof(tcp));
500                 memset(&tcp_mask, 0, sizeof(tcp_mask));
501                 if (action->type == RTE_FLOW_ACTION_TYPE_SET_TP_SRC) {
502                         tcp.hdr.src_port = conf->port;
503                         tcp_mask.hdr.src_port =
504                                         rte_flow_item_tcp_mask.hdr.src_port;
505                 } else {
506                         tcp.hdr.dst_port = conf->port;
507                         tcp_mask.hdr.dst_port =
508                                         rte_flow_item_tcp_mask.hdr.dst_port;
509                 }
510                 item.type = RTE_FLOW_ITEM_TYPE_TCP;
511                 item.spec = &tcp;
512                 item.mask = &tcp_mask;
513                 field = modify_tcp;
514         }
515         return flow_dv_convert_modify_action(&item, field, resource,
516                                              MLX5_MODIFICATION_TYPE_SET, error);
517 }
518
519 /**
520  * Convert modify-header set TTL action to DV specification.
521  *
522  * @param[in,out] resource
523  *   Pointer to the modify-header resource.
524  * @param[in] action
525  *   Pointer to action specification.
526  * @param[in] items
527  *   Pointer to rte_flow_item objects list.
528  * @param[in] attr
529  *   Pointer to flow attributes structure.
530  * @param[out] error
531  *   Pointer to the error structure.
532  *
533  * @return
534  *   0 on success, a negative errno value otherwise and rte_errno is set.
535  */
536 static int
537 flow_dv_convert_action_modify_ttl
538                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
539                          const struct rte_flow_action *action,
540                          const struct rte_flow_item *items,
541                          union flow_dv_attr *attr,
542                          struct rte_flow_error *error)
543 {
544         const struct rte_flow_action_set_ttl *conf =
545                 (const struct rte_flow_action_set_ttl *)(action->conf);
546         struct rte_flow_item item;
547         struct rte_flow_item_ipv4 ipv4;
548         struct rte_flow_item_ipv4 ipv4_mask;
549         struct rte_flow_item_ipv6 ipv6;
550         struct rte_flow_item_ipv6 ipv6_mask;
551         struct field_modify_info *field;
552
553         if (!attr->valid)
554                 flow_dv_attr_init(items, attr);
555         if (attr->ipv4) {
556                 memset(&ipv4, 0, sizeof(ipv4));
557                 memset(&ipv4_mask, 0, sizeof(ipv4_mask));
558                 ipv4.hdr.time_to_live = conf->ttl_value;
559                 ipv4_mask.hdr.time_to_live = 0xFF;
560                 item.type = RTE_FLOW_ITEM_TYPE_IPV4;
561                 item.spec = &ipv4;
562                 item.mask = &ipv4_mask;
563                 field = modify_ipv4;
564         }
565         if (attr->ipv6) {
566                 memset(&ipv6, 0, sizeof(ipv6));
567                 memset(&ipv6_mask, 0, sizeof(ipv6_mask));
568                 ipv6.hdr.hop_limits = conf->ttl_value;
569                 ipv6_mask.hdr.hop_limits = 0xFF;
570                 item.type = RTE_FLOW_ITEM_TYPE_IPV6;
571                 item.spec = &ipv6;
572                 item.mask = &ipv6_mask;
573                 field = modify_ipv6;
574         }
575         return flow_dv_convert_modify_action(&item, field, resource,
576                                              MLX5_MODIFICATION_TYPE_SET, error);
577 }
578
579 /**
580  * Convert modify-header decrement TTL action to DV specification.
581  *
582  * @param[in,out] resource
583  *   Pointer to the modify-header resource.
584  * @param[in] action
585  *   Pointer to action specification.
586  * @param[in] items
587  *   Pointer to rte_flow_item objects list.
588  * @param[in] attr
589  *   Pointer to flow attributes structure.
590  * @param[out] error
591  *   Pointer to the error structure.
592  *
593  * @return
594  *   0 on success, a negative errno value otherwise and rte_errno is set.
595  */
596 static int
597 flow_dv_convert_action_modify_dec_ttl
598                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
599                          const struct rte_flow_item *items,
600                          union flow_dv_attr *attr,
601                          struct rte_flow_error *error)
602 {
603         struct rte_flow_item item;
604         struct rte_flow_item_ipv4 ipv4;
605         struct rte_flow_item_ipv4 ipv4_mask;
606         struct rte_flow_item_ipv6 ipv6;
607         struct rte_flow_item_ipv6 ipv6_mask;
608         struct field_modify_info *field;
609
610         if (!attr->valid)
611                 flow_dv_attr_init(items, attr);
612         if (attr->ipv4) {
613                 memset(&ipv4, 0, sizeof(ipv4));
614                 memset(&ipv4_mask, 0, sizeof(ipv4_mask));
615                 ipv4.hdr.time_to_live = 0xFF;
616                 ipv4_mask.hdr.time_to_live = 0xFF;
617                 item.type = RTE_FLOW_ITEM_TYPE_IPV4;
618                 item.spec = &ipv4;
619                 item.mask = &ipv4_mask;
620                 field = modify_ipv4;
621         }
622         if (attr->ipv6) {
623                 memset(&ipv6, 0, sizeof(ipv6));
624                 memset(&ipv6_mask, 0, sizeof(ipv6_mask));
625                 ipv6.hdr.hop_limits = 0xFF;
626                 ipv6_mask.hdr.hop_limits = 0xFF;
627                 item.type = RTE_FLOW_ITEM_TYPE_IPV6;
628                 item.spec = &ipv6;
629                 item.mask = &ipv6_mask;
630                 field = modify_ipv6;
631         }
632         return flow_dv_convert_modify_action(&item, field, resource,
633                                              MLX5_MODIFICATION_TYPE_ADD, error);
634 }
635
636 /**
637  * Convert modify-header increment/decrement TCP Sequence number
638  * to DV specification.
639  *
640  * @param[in,out] resource
641  *   Pointer to the modify-header resource.
642  * @param[in] action
643  *   Pointer to action specification.
644  * @param[out] error
645  *   Pointer to the error structure.
646  *
647  * @return
648  *   0 on success, a negative errno value otherwise and rte_errno is set.
649  */
650 static int
651 flow_dv_convert_action_modify_tcp_seq
652                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
653                          const struct rte_flow_action *action,
654                          struct rte_flow_error *error)
655 {
656         const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
657         uint64_t value = rte_be_to_cpu_32(*conf);
658         struct rte_flow_item item;
659         struct rte_flow_item_tcp tcp;
660         struct rte_flow_item_tcp tcp_mask;
661
662         memset(&tcp, 0, sizeof(tcp));
663         memset(&tcp_mask, 0, sizeof(tcp_mask));
664         if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ)
665                 /*
666                  * The HW has no decrement operation, only increment operation.
667                  * To simulate decrement X from Y using increment operation
668                  * we need to add UINT32_MAX X times to Y.
669                  * Each adding of UINT32_MAX decrements Y by 1.
670                  */
671                 value *= UINT32_MAX;
672         tcp.hdr.sent_seq = rte_cpu_to_be_32((uint32_t)value);
673         tcp_mask.hdr.sent_seq = RTE_BE32(UINT32_MAX);
674         item.type = RTE_FLOW_ITEM_TYPE_TCP;
675         item.spec = &tcp;
676         item.mask = &tcp_mask;
677         return flow_dv_convert_modify_action(&item, modify_tcp, resource,
678                                              MLX5_MODIFICATION_TYPE_ADD, error);
679 }
680
681 /**
682  * Convert modify-header increment/decrement TCP Acknowledgment number
683  * to DV specification.
684  *
685  * @param[in,out] resource
686  *   Pointer to the modify-header resource.
687  * @param[in] action
688  *   Pointer to action specification.
689  * @param[out] error
690  *   Pointer to the error structure.
691  *
692  * @return
693  *   0 on success, a negative errno value otherwise and rte_errno is set.
694  */
695 static int
696 flow_dv_convert_action_modify_tcp_ack
697                         (struct mlx5_flow_dv_modify_hdr_resource *resource,
698                          const struct rte_flow_action *action,
699                          struct rte_flow_error *error)
700 {
701         const rte_be32_t *conf = (const rte_be32_t *)(action->conf);
702         uint64_t value = rte_be_to_cpu_32(*conf);
703         struct rte_flow_item item;
704         struct rte_flow_item_tcp tcp;
705         struct rte_flow_item_tcp tcp_mask;
706
707         memset(&tcp, 0, sizeof(tcp));
708         memset(&tcp_mask, 0, sizeof(tcp_mask));
709         if (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK)
710                 /*
711                  * The HW has no decrement operation, only increment operation.
712                  * To simulate decrement X from Y using increment operation
713                  * we need to add UINT32_MAX X times to Y.
714                  * Each adding of UINT32_MAX decrements Y by 1.
715                  */
716                 value *= UINT32_MAX;
717         tcp.hdr.recv_ack = rte_cpu_to_be_32((uint32_t)value);
718         tcp_mask.hdr.recv_ack = RTE_BE32(UINT32_MAX);
719         item.type = RTE_FLOW_ITEM_TYPE_TCP;
720         item.spec = &tcp;
721         item.mask = &tcp_mask;
722         return flow_dv_convert_modify_action(&item, modify_tcp, resource,
723                                              MLX5_MODIFICATION_TYPE_ADD, error);
724 }
725
726 /**
727  * Validate META item.
728  *
729  * @param[in] dev
730  *   Pointer to the rte_eth_dev structure.
731  * @param[in] item
732  *   Item specification.
733  * @param[in] attr
734  *   Attributes of flow that includes this item.
735  * @param[out] error
736  *   Pointer to error structure.
737  *
738  * @return
739  *   0 on success, a negative errno value otherwise and rte_errno is set.
740  */
741 static int
742 flow_dv_validate_item_meta(struct rte_eth_dev *dev,
743                            const struct rte_flow_item *item,
744                            const struct rte_flow_attr *attr,
745                            struct rte_flow_error *error)
746 {
747         const struct rte_flow_item_meta *spec = item->spec;
748         const struct rte_flow_item_meta *mask = item->mask;
749         const struct rte_flow_item_meta nic_mask = {
750                 .data = RTE_BE32(UINT32_MAX)
751         };
752         int ret;
753         uint64_t offloads = dev->data->dev_conf.txmode.offloads;
754
755         if (!(offloads & DEV_TX_OFFLOAD_MATCH_METADATA))
756                 return rte_flow_error_set(error, EPERM,
757                                           RTE_FLOW_ERROR_TYPE_ITEM,
758                                           NULL,
759                                           "match on metadata offload "
760                                           "configuration is off for this port");
761         if (!spec)
762                 return rte_flow_error_set(error, EINVAL,
763                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
764                                           item->spec,
765                                           "data cannot be empty");
766         if (!spec->data)
767                 return rte_flow_error_set(error, EINVAL,
768                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC,
769                                           NULL,
770                                           "data cannot be zero");
771         if (!mask)
772                 mask = &rte_flow_item_meta_mask;
773         ret = mlx5_flow_item_acceptable(item, (const uint8_t *)mask,
774                                         (const uint8_t *)&nic_mask,
775                                         sizeof(struct rte_flow_item_meta),
776                                         error);
777         if (ret < 0)
778                 return ret;
779         if (attr->ingress)
780                 return rte_flow_error_set(error, ENOTSUP,
781                                           RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
782                                           NULL,
783                                           "pattern not supported for ingress");
784         return 0;
785 }
786
787 /**
788  * Validate vport item.
789  *
790  * @param[in] dev
791  *   Pointer to the rte_eth_dev structure.
792  * @param[in] item
793  *   Item specification.
794  * @param[in] attr
795  *   Attributes of flow that includes this item.
796  * @param[in] item_flags
797  *   Bit-fields that holds the items detected until now.
798  * @param[out] error
799  *   Pointer to error structure.
800  *
801  * @return
802  *   0 on success, a negative errno value otherwise and rte_errno is set.
803  */
804 static int
805 flow_dv_validate_item_port_id(struct rte_eth_dev *dev,
806                               const struct rte_flow_item *item,
807                               const struct rte_flow_attr *attr,
808                               uint64_t item_flags,
809                               struct rte_flow_error *error)
810 {
811         const struct rte_flow_item_port_id *spec = item->spec;
812         const struct rte_flow_item_port_id *mask = item->mask;
813         const struct rte_flow_item_port_id switch_mask = {
814                         .id = 0xffffffff,
815         };
816         uint16_t esw_domain_id;
817         uint16_t item_port_esw_domain_id;
818         int ret;
819
820         if (!attr->transfer)
821                 return rte_flow_error_set(error, EINVAL,
822                                           RTE_FLOW_ERROR_TYPE_ITEM,
823                                           NULL,
824                                           "match on port id is valid only"
825                                           " when transfer flag is enabled");
826         if (item_flags & MLX5_FLOW_ITEM_PORT_ID)
827                 return rte_flow_error_set(error, ENOTSUP,
828                                           RTE_FLOW_ERROR_TYPE_ITEM, item,
829                                           "multiple source ports are not"
830                                           " supported");
831         if (!mask)
832                 mask = &switch_mask;
833         if (mask->id != 0xffffffff)
834                 return rte_flow_error_set(error, ENOTSUP,
835                                            RTE_FLOW_ERROR_TYPE_ITEM_MASK,
836                                            mask,
837                                            "no support for partial mask on"
838                                            " \"id\" field");
839         ret = mlx5_flow_item_acceptable
840                                 (item, (const uint8_t *)mask,
841                                  (const uint8_t *)&rte_flow_item_port_id_mask,
842                                  sizeof(struct rte_flow_item_port_id),
843                                  error);
844         if (ret)
845                 return ret;
846         if (!spec)
847                 return 0;
848         ret = mlx5_port_to_eswitch_info(spec->id, &item_port_esw_domain_id,
849                                         NULL);
850         if (ret)
851                 return rte_flow_error_set(error, -ret,
852                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
853                                           "failed to obtain E-Switch info for"
854                                           " port");
855         ret = mlx5_port_to_eswitch_info(dev->data->port_id,
856                                         &esw_domain_id, NULL);
857         if (ret < 0)
858                 return rte_flow_error_set(error, -ret,
859                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
860                                           NULL,
861                                           "failed to obtain E-Switch info");
862         if (item_port_esw_domain_id != esw_domain_id)
863                 return rte_flow_error_set(error, -ret,
864                                           RTE_FLOW_ERROR_TYPE_ITEM_SPEC, spec,
865                                           "cannot match on a port from a"
866                                           " different E-Switch");
867         return 0;
868 }
869
870 /**
871  * Validate the pop VLAN action.
872  *
873  * @param[in] dev
874  *   Pointer to the rte_eth_dev structure.
875  * @param[in] action_flags
876  *   Holds the actions detected until now.
877  * @param[in] action
878  *   Pointer to the pop vlan action.
879  * @param[in] item_flags
880  *   The items found in this flow rule.
881  * @param[in] attr
882  *   Pointer to flow attributes.
883  * @param[out] error
884  *   Pointer to error structure.
885  *
886  * @return
887  *   0 on success, a negative errno value otherwise and rte_errno is set.
888  */
889 static int
890 flow_dv_validate_action_pop_vlan(struct rte_eth_dev *dev,
891                                  uint64_t action_flags,
892                                  const struct rte_flow_action *action,
893                                  uint64_t item_flags,
894                                  const struct rte_flow_attr *attr,
895                                  struct rte_flow_error *error)
896 {
897         struct mlx5_priv *priv = dev->data->dev_private;
898
899         (void)action;
900         (void)attr;
901         if (!priv->sh->pop_vlan_action)
902                 return rte_flow_error_set(error, ENOTSUP,
903                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
904                                           NULL,
905                                           "pop vlan action is not supported");
906         /*
907          * Check for inconsistencies:
908          *  fail strip_vlan in a flow that matches packets without VLAN tags.
909          *  fail strip_vlan in a flow that matches packets without explicitly a
910          *  matching on VLAN tag ?
911          */
912         if (action_flags & MLX5_FLOW_ACTION_OF_POP_VLAN)
913                 return rte_flow_error_set(error, ENOTSUP,
914                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
915                                           NULL,
916                                           "no support for multiple vlan pop "
917                                           "actions");
918         if (!(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
919                 return rte_flow_error_set(error, ENOTSUP,
920                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
921                                           NULL,
922                                           "cannot pop vlan without a "
923                                           "match on (outer) vlan in the flow");
924         return 0;
925 }
926
927 /**
928  * Get VLAN default info from vlan match info.
929  *
930  * @param[in] dev
931  *   Pointer to the rte_eth_dev structure.
932  * @param[in] item
933  *   the list of item specifications.
934  * @param[out] vlan
935  *   pointer VLAN info to fill to.
936  * @param[out] error
937  *   Pointer to error structure.
938  *
939  * @return
940  *   0 on success, a negative errno value otherwise and rte_errno is set.
941  */
942 static void
943 flow_dev_get_vlan_info_from_items(const struct rte_flow_item *items,
944                                   struct rte_vlan_hdr *vlan)
945 {
946         const struct rte_flow_item_vlan nic_mask = {
947                 .tci = RTE_BE16(MLX5DV_FLOW_VLAN_PCP_MASK |
948                                 MLX5DV_FLOW_VLAN_VID_MASK),
949                 .inner_type = RTE_BE16(0xffff),
950         };
951
952         if (items == NULL)
953                 return;
954         for (; items->type != RTE_FLOW_ITEM_TYPE_END &&
955                items->type != RTE_FLOW_ITEM_TYPE_VLAN; items++)
956                 ;
957         if (items->type == RTE_FLOW_ITEM_TYPE_VLAN) {
958                 const struct rte_flow_item_vlan *vlan_m = items->mask;
959                 const struct rte_flow_item_vlan *vlan_v = items->spec;
960
961                 if (!vlan_m)
962                         vlan_m = &nic_mask;
963                 /* Only full match values are accepted */
964                 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_PCP_MASK_BE) ==
965                      MLX5DV_FLOW_VLAN_PCP_MASK_BE) {
966                         vlan->vlan_tci &= MLX5DV_FLOW_VLAN_PCP_MASK;
967                         vlan->vlan_tci |=
968                                 rte_be_to_cpu_16(vlan_v->tci &
969                                                  MLX5DV_FLOW_VLAN_PCP_MASK_BE);
970                 }
971                 if ((vlan_m->tci & MLX5DV_FLOW_VLAN_VID_MASK_BE) ==
972                      MLX5DV_FLOW_VLAN_VID_MASK_BE) {
973                         vlan->vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
974                         vlan->vlan_tci |=
975                                 rte_be_to_cpu_16(vlan_v->tci &
976                                                  MLX5DV_FLOW_VLAN_VID_MASK_BE);
977                 }
978                 if (vlan_m->inner_type == nic_mask.inner_type)
979                         vlan->eth_proto = rte_be_to_cpu_16(vlan_v->inner_type &
980                                                            vlan_m->inner_type);
981         }
982 }
983
984 /**
985  * Validate the push VLAN action.
986  *
987  * @param[in] action_flags
988  *   Holds the actions detected until now.
989  * @param[in] action
990  *   Pointer to the encap action.
991  * @param[in] attr
992  *   Pointer to flow attributes
993  * @param[out] error
994  *   Pointer to error structure.
995  *
996  * @return
997  *   0 on success, a negative errno value otherwise and rte_errno is set.
998  */
999 static int
1000 flow_dv_validate_action_push_vlan(uint64_t action_flags,
1001                                   const struct rte_flow_action *action,
1002                                   const struct rte_flow_attr *attr,
1003                                   struct rte_flow_error *error)
1004 {
1005         const struct rte_flow_action_of_push_vlan *push_vlan = action->conf;
1006
1007         if (push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_VLAN) &&
1008             push_vlan->ethertype != RTE_BE16(RTE_ETHER_TYPE_QINQ))
1009                 return rte_flow_error_set(error, EINVAL,
1010                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1011                                           "invalid vlan ethertype");
1012         if (action_flags &
1013                 (MLX5_FLOW_ACTION_OF_POP_VLAN | MLX5_FLOW_ACTION_OF_PUSH_VLAN))
1014                 return rte_flow_error_set(error, ENOTSUP,
1015                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1016                                           "no support for multiple VLAN "
1017                                           "actions");
1018         (void)attr;
1019         return 0;
1020 }
1021
1022 /**
1023  * Validate the set VLAN PCP.
1024  *
1025  * @param[in] action_flags
1026  *   Holds the actions detected until now.
1027  * @param[in] actions
1028  *   Pointer to the list of actions remaining in the flow rule.
1029  * @param[in] attr
1030  *   Pointer to flow attributes
1031  * @param[out] error
1032  *   Pointer to error structure.
1033  *
1034  * @return
1035  *   0 on success, a negative errno value otherwise and rte_errno is set.
1036  */
1037 static int
1038 flow_dv_validate_action_set_vlan_pcp(uint64_t action_flags,
1039                                      const struct rte_flow_action actions[],
1040                                      struct rte_flow_error *error)
1041 {
1042         const struct rte_flow_action *action = actions;
1043         const struct rte_flow_action_of_set_vlan_pcp *conf = action->conf;
1044
1045         if (conf->vlan_pcp > 7)
1046                 return rte_flow_error_set(error, EINVAL,
1047                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1048                                           "VLAN PCP value is too big");
1049         if (mlx5_flow_find_action(actions,
1050                                   RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN) == NULL)
1051                 return rte_flow_error_set(error, ENOTSUP,
1052                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1053                                           "set VLAN PCP can only be used "
1054                                           "with push VLAN action");
1055         if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
1056                 return rte_flow_error_set(error, ENOTSUP,
1057                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1058                                           "set VLAN PCP action must precede "
1059                                           "the push VLAN action");
1060         return 0;
1061 }
1062
1063 /**
1064  * Validate the set VLAN VID.
1065  *
1066  * @param[in] item_flags
1067  *   Holds the items detected in this rule.
1068  * @param[in] actions
1069  *   Pointer to the list of actions remaining in the flow rule.
1070  * @param[in] attr
1071  *   Pointer to flow attributes
1072  * @param[out] error
1073  *   Pointer to error structure.
1074  *
1075  * @return
1076  *   0 on success, a negative errno value otherwise and rte_errno is set.
1077  */
1078 static int
1079 flow_dv_validate_action_set_vlan_vid(uint64_t item_flags,
1080                                      const struct rte_flow_action actions[],
1081                                      struct rte_flow_error *error)
1082 {
1083         const struct rte_flow_action *action = actions;
1084         const struct rte_flow_action_of_set_vlan_vid *conf = action->conf;
1085
1086         if (conf->vlan_vid > RTE_BE16(0xFFE))
1087                 return rte_flow_error_set(error, EINVAL,
1088                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1089                                           "VLAN VID value is too big");
1090         /* If a push VLAN action follows then it will handle this action */
1091         if (mlx5_flow_find_action(actions,
1092                                   RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN))
1093                 return 0;
1094
1095         /*
1096          * Action is on an existing VLAN header:
1097          *    Need to verify this is a single modify CID action.
1098          *   Rule mast include a match on outer VLAN.
1099          */
1100         if (mlx5_flow_find_action(++action,
1101                                   RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID))
1102                 return rte_flow_error_set(error, ENOTSUP,
1103                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1104                                           "Multiple VLAN VID modifications are "
1105                                           "not supported");
1106         if (!(item_flags & MLX5_FLOW_LAYER_OUTER_VLAN))
1107                 return rte_flow_error_set(error, EINVAL,
1108                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1109                                           "match on VLAN is required in order "
1110                                           "to set VLAN VID");
1111         return 0;
1112 }
1113
1114 /**
1115  * Validate count action.
1116  *
1117  * @param[in] dev
1118  *   device otr.
1119  * @param[out] error
1120  *   Pointer to error structure.
1121  *
1122  * @return
1123  *   0 on success, a negative errno value otherwise and rte_errno is set.
1124  */
1125 static int
1126 flow_dv_validate_action_count(struct rte_eth_dev *dev,
1127                               struct rte_flow_error *error)
1128 {
1129         struct mlx5_priv *priv = dev->data->dev_private;
1130
1131         if (!priv->config.devx)
1132                 goto notsup_err;
1133 #ifdef HAVE_IBV_FLOW_DEVX_COUNTERS
1134         return 0;
1135 #endif
1136 notsup_err:
1137         return rte_flow_error_set
1138                       (error, ENOTSUP,
1139                        RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1140                        NULL,
1141                        "count action not supported");
1142 }
1143
1144 /**
1145  * Validate the L2 encap action.
1146  *
1147  * @param[in] action_flags
1148  *   Holds the actions detected until now.
1149  * @param[in] action
1150  *   Pointer to the encap action.
1151  * @param[in] attr
1152  *   Pointer to flow attributes
1153  * @param[out] error
1154  *   Pointer to error structure.
1155  *
1156  * @return
1157  *   0 on success, a negative errno value otherwise and rte_errno is set.
1158  */
1159 static int
1160 flow_dv_validate_action_l2_encap(uint64_t action_flags,
1161                                  const struct rte_flow_action *action,
1162                                  const struct rte_flow_attr *attr,
1163                                  struct rte_flow_error *error)
1164 {
1165         if (!(action->conf))
1166                 return rte_flow_error_set(error, EINVAL,
1167                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1168                                           "configuration cannot be null");
1169         if (action_flags & MLX5_FLOW_ACTION_DROP)
1170                 return rte_flow_error_set(error, EINVAL,
1171                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1172                                           "can't drop and encap in same flow");
1173         if (action_flags & (MLX5_FLOW_ENCAP_ACTIONS | MLX5_FLOW_DECAP_ACTIONS))
1174                 return rte_flow_error_set(error, EINVAL,
1175                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1176                                           "can only have a single encap or"
1177                                           " decap action in a flow");
1178         if (!attr->transfer && attr->ingress)
1179                 return rte_flow_error_set(error, ENOTSUP,
1180                                           RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
1181                                           NULL,
1182                                           "encap action not supported for "
1183                                           "ingress");
1184         return 0;
1185 }
1186
1187 /**
1188  * Validate the L2 decap action.
1189  *
1190  * @param[in] action_flags
1191  *   Holds the actions detected until now.
1192  * @param[in] attr
1193  *   Pointer to flow attributes
1194  * @param[out] error
1195  *   Pointer to error structure.
1196  *
1197  * @return
1198  *   0 on success, a negative errno value otherwise and rte_errno is set.
1199  */
1200 static int
1201 flow_dv_validate_action_l2_decap(uint64_t action_flags,
1202                                  const struct rte_flow_attr *attr,
1203                                  struct rte_flow_error *error)
1204 {
1205         if (action_flags & MLX5_FLOW_ACTION_DROP)
1206                 return rte_flow_error_set(error, EINVAL,
1207                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1208                                           "can't drop and decap in same flow");
1209         if (action_flags & (MLX5_FLOW_ENCAP_ACTIONS | MLX5_FLOW_DECAP_ACTIONS))
1210                 return rte_flow_error_set(error, EINVAL,
1211                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1212                                           "can only have a single encap or"
1213                                           " decap action in a flow");
1214         if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
1215                 return rte_flow_error_set(error, EINVAL,
1216                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1217                                           "can't have decap action after"
1218                                           " modify action");
1219         if (attr->egress)
1220                 return rte_flow_error_set(error, ENOTSUP,
1221                                           RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
1222                                           NULL,
1223                                           "decap action not supported for "
1224                                           "egress");
1225         return 0;
1226 }
1227
1228 /**
1229  * Validate the raw encap action.
1230  *
1231  * @param[in] action_flags
1232  *   Holds the actions detected until now.
1233  * @param[in] action
1234  *   Pointer to the encap action.
1235  * @param[in] attr
1236  *   Pointer to flow attributes
1237  * @param[out] error
1238  *   Pointer to error structure.
1239  *
1240  * @return
1241  *   0 on success, a negative errno value otherwise and rte_errno is set.
1242  */
1243 static int
1244 flow_dv_validate_action_raw_encap(uint64_t action_flags,
1245                                   const struct rte_flow_action *action,
1246                                   const struct rte_flow_attr *attr,
1247                                   struct rte_flow_error *error)
1248 {
1249         const struct rte_flow_action_raw_encap *raw_encap =
1250                 (const struct rte_flow_action_raw_encap *)action->conf;
1251         if (!(action->conf))
1252                 return rte_flow_error_set(error, EINVAL,
1253                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1254                                           "configuration cannot be null");
1255         if (action_flags & MLX5_FLOW_ACTION_DROP)
1256                 return rte_flow_error_set(error, EINVAL,
1257                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1258                                           "can't drop and encap in same flow");
1259         if (action_flags & MLX5_FLOW_ENCAP_ACTIONS)
1260                 return rte_flow_error_set(error, EINVAL,
1261                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1262                                           "can only have a single encap"
1263                                           " action in a flow");
1264         /* encap without preceding decap is not supported for ingress */
1265         if (!attr->transfer &&  attr->ingress &&
1266             !(action_flags & MLX5_FLOW_ACTION_RAW_DECAP))
1267                 return rte_flow_error_set(error, ENOTSUP,
1268                                           RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
1269                                           NULL,
1270                                           "encap action not supported for "
1271                                           "ingress");
1272         if (!raw_encap->size || !raw_encap->data)
1273                 return rte_flow_error_set(error, EINVAL,
1274                                           RTE_FLOW_ERROR_TYPE_ACTION, action,
1275                                           "raw encap data cannot be empty");
1276         return 0;
1277 }
1278
1279 /**
1280  * Validate the raw decap action.
1281  *
1282  * @param[in] action_flags
1283  *   Holds the actions detected until now.
1284  * @param[in] action
1285  *   Pointer to the encap action.
1286  * @param[in] attr
1287  *   Pointer to flow attributes
1288  * @param[out] error
1289  *   Pointer to error structure.
1290  *
1291  * @return
1292  *   0 on success, a negative errno value otherwise and rte_errno is set.
1293  */
1294 static int
1295 flow_dv_validate_action_raw_decap(uint64_t action_flags,
1296                                   const struct rte_flow_action *action,
1297                                   const struct rte_flow_attr *attr,
1298                                   struct rte_flow_error *error)
1299 {
1300         if (action_flags & MLX5_FLOW_ACTION_DROP)
1301                 return rte_flow_error_set(error, EINVAL,
1302                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1303                                           "can't drop and decap in same flow");
1304         if (action_flags & MLX5_FLOW_ENCAP_ACTIONS)
1305                 return rte_flow_error_set(error, EINVAL,
1306                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1307                                           "can't have encap action before"
1308                                           " decap action");
1309         if (action_flags & MLX5_FLOW_DECAP_ACTIONS)
1310                 return rte_flow_error_set(error, EINVAL,
1311                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1312                                           "can only have a single decap"
1313                                           " action in a flow");
1314         if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
1315                 return rte_flow_error_set(error, EINVAL,
1316                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
1317                                           "can't have decap action after"
1318                                           " modify action");
1319         /* decap action is valid on egress only if it is followed by encap */
1320         if (attr->egress) {
1321                 for (; action->type != RTE_FLOW_ACTION_TYPE_END &&
1322                        action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP;
1323                        action++) {
1324                 }
1325                 if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP)
1326                         return rte_flow_error_set
1327                                         (error, ENOTSUP,
1328                                          RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
1329                                          NULL, "decap action not supported"
1330                                          " for egress");
1331         }
1332         return 0;
1333 }
1334
1335 /**
1336  * Find existing encap/decap resource or create and register a new one.
1337  *
1338  * @param dev[in, out]
1339  *   Pointer to rte_eth_dev structure.
1340  * @param[in, out] resource
1341  *   Pointer to encap/decap resource.
1342  * @parm[in, out] dev_flow
1343  *   Pointer to the dev_flow.
1344  * @param[out] error
1345  *   pointer to error structure.
1346  *
1347  * @return
1348  *   0 on success otherwise -errno and errno is set.
1349  */
1350 static int
1351 flow_dv_encap_decap_resource_register
1352                         (struct rte_eth_dev *dev,
1353                          struct mlx5_flow_dv_encap_decap_resource *resource,
1354                          struct mlx5_flow *dev_flow,
1355                          struct rte_flow_error *error)
1356 {
1357         struct mlx5_priv *priv = dev->data->dev_private;
1358         struct mlx5_ibv_shared *sh = priv->sh;
1359         struct mlx5_flow_dv_encap_decap_resource *cache_resource;
1360         struct rte_flow *flow = dev_flow->flow;
1361         struct mlx5dv_dr_domain *domain;
1362
1363         resource->flags = flow->group ? 0 : 1;
1364         if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
1365                 domain = sh->fdb_domain;
1366         else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
1367                 domain = sh->rx_domain;
1368         else
1369                 domain = sh->tx_domain;
1370
1371         /* Lookup a matching resource from cache. */
1372         LIST_FOREACH(cache_resource, &sh->encaps_decaps, next) {
1373                 if (resource->reformat_type == cache_resource->reformat_type &&
1374                     resource->ft_type == cache_resource->ft_type &&
1375                     resource->flags == cache_resource->flags &&
1376                     resource->size == cache_resource->size &&
1377                     !memcmp((const void *)resource->buf,
1378                             (const void *)cache_resource->buf,
1379                             resource->size)) {
1380                         DRV_LOG(DEBUG, "encap/decap resource %p: refcnt %d++",
1381                                 (void *)cache_resource,
1382                                 rte_atomic32_read(&cache_resource->refcnt));
1383                         rte_atomic32_inc(&cache_resource->refcnt);
1384                         dev_flow->dv.encap_decap = cache_resource;
1385                         return 0;
1386                 }
1387         }
1388         /* Register new encap/decap resource. */
1389         cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
1390         if (!cache_resource)
1391                 return rte_flow_error_set(error, ENOMEM,
1392                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1393                                           "cannot allocate resource memory");
1394         *cache_resource = *resource;
1395         cache_resource->verbs_action =
1396                 mlx5_glue->dv_create_flow_action_packet_reformat
1397                         (sh->ctx, cache_resource->reformat_type,
1398                          cache_resource->ft_type, domain, cache_resource->flags,
1399                          cache_resource->size,
1400                          (cache_resource->size ? cache_resource->buf : NULL));
1401         if (!cache_resource->verbs_action) {
1402                 rte_free(cache_resource);
1403                 return rte_flow_error_set(error, ENOMEM,
1404                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1405                                           NULL, "cannot create action");
1406         }
1407         rte_atomic32_init(&cache_resource->refcnt);
1408         rte_atomic32_inc(&cache_resource->refcnt);
1409         LIST_INSERT_HEAD(&sh->encaps_decaps, cache_resource, next);
1410         dev_flow->dv.encap_decap = cache_resource;
1411         DRV_LOG(DEBUG, "new encap/decap resource %p: refcnt %d++",
1412                 (void *)cache_resource,
1413                 rte_atomic32_read(&cache_resource->refcnt));
1414         return 0;
1415 }
1416
1417 /**
1418  * Find existing table jump resource or create and register a new one.
1419  *
1420  * @param dev[in, out]
1421  *   Pointer to rte_eth_dev structure.
1422  * @param[in, out] resource
1423  *   Pointer to jump table resource.
1424  * @parm[in, out] dev_flow
1425  *   Pointer to the dev_flow.
1426  * @param[out] error
1427  *   pointer to error structure.
1428  *
1429  * @return
1430  *   0 on success otherwise -errno and errno is set.
1431  */
1432 static int
1433 flow_dv_jump_tbl_resource_register
1434                         (struct rte_eth_dev *dev,
1435                          struct mlx5_flow_dv_jump_tbl_resource *resource,
1436                          struct mlx5_flow *dev_flow,
1437                          struct rte_flow_error *error)
1438 {
1439         struct mlx5_priv *priv = dev->data->dev_private;
1440         struct mlx5_ibv_shared *sh = priv->sh;
1441         struct mlx5_flow_dv_jump_tbl_resource *cache_resource;
1442
1443         /* Lookup a matching resource from cache. */
1444         LIST_FOREACH(cache_resource, &sh->jump_tbl, next) {
1445                 if (resource->tbl == cache_resource->tbl) {
1446                         DRV_LOG(DEBUG, "jump table resource resource %p: refcnt %d++",
1447                                 (void *)cache_resource,
1448                                 rte_atomic32_read(&cache_resource->refcnt));
1449                         rte_atomic32_inc(&cache_resource->refcnt);
1450                         dev_flow->dv.jump = cache_resource;
1451                         return 0;
1452                 }
1453         }
1454         /* Register new jump table resource. */
1455         cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
1456         if (!cache_resource)
1457                 return rte_flow_error_set(error, ENOMEM,
1458                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1459                                           "cannot allocate resource memory");
1460         *cache_resource = *resource;
1461         cache_resource->action =
1462                 mlx5_glue->dr_create_flow_action_dest_flow_tbl
1463                 (resource->tbl->obj);
1464         if (!cache_resource->action) {
1465                 rte_free(cache_resource);
1466                 return rte_flow_error_set(error, ENOMEM,
1467                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1468                                           NULL, "cannot create action");
1469         }
1470         rte_atomic32_init(&cache_resource->refcnt);
1471         rte_atomic32_inc(&cache_resource->refcnt);
1472         LIST_INSERT_HEAD(&sh->jump_tbl, cache_resource, next);
1473         dev_flow->dv.jump = cache_resource;
1474         DRV_LOG(DEBUG, "new jump table  resource %p: refcnt %d++",
1475                 (void *)cache_resource,
1476                 rte_atomic32_read(&cache_resource->refcnt));
1477         return 0;
1478 }
1479
1480 /**
1481  * Find existing table port ID resource or create and register a new one.
1482  *
1483  * @param dev[in, out]
1484  *   Pointer to rte_eth_dev structure.
1485  * @param[in, out] resource
1486  *   Pointer to port ID action resource.
1487  * @parm[in, out] dev_flow
1488  *   Pointer to the dev_flow.
1489  * @param[out] error
1490  *   pointer to error structure.
1491  *
1492  * @return
1493  *   0 on success otherwise -errno and errno is set.
1494  */
1495 static int
1496 flow_dv_port_id_action_resource_register
1497                         (struct rte_eth_dev *dev,
1498                          struct mlx5_flow_dv_port_id_action_resource *resource,
1499                          struct mlx5_flow *dev_flow,
1500                          struct rte_flow_error *error)
1501 {
1502         struct mlx5_priv *priv = dev->data->dev_private;
1503         struct mlx5_ibv_shared *sh = priv->sh;
1504         struct mlx5_flow_dv_port_id_action_resource *cache_resource;
1505
1506         /* Lookup a matching resource from cache. */
1507         LIST_FOREACH(cache_resource, &sh->port_id_action_list, next) {
1508                 if (resource->port_id == cache_resource->port_id) {
1509                         DRV_LOG(DEBUG, "port id action resource resource %p: "
1510                                 "refcnt %d++",
1511                                 (void *)cache_resource,
1512                                 rte_atomic32_read(&cache_resource->refcnt));
1513                         rte_atomic32_inc(&cache_resource->refcnt);
1514                         dev_flow->dv.port_id_action = cache_resource;
1515                         return 0;
1516                 }
1517         }
1518         /* Register new port id action resource. */
1519         cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
1520         if (!cache_resource)
1521                 return rte_flow_error_set(error, ENOMEM,
1522                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1523                                           "cannot allocate resource memory");
1524         *cache_resource = *resource;
1525         cache_resource->action =
1526                 mlx5_glue->dr_create_flow_action_dest_vport
1527                         (priv->sh->fdb_domain, resource->port_id);
1528         if (!cache_resource->action) {
1529                 rte_free(cache_resource);
1530                 return rte_flow_error_set(error, ENOMEM,
1531                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1532                                           NULL, "cannot create action");
1533         }
1534         rte_atomic32_init(&cache_resource->refcnt);
1535         rte_atomic32_inc(&cache_resource->refcnt);
1536         LIST_INSERT_HEAD(&sh->port_id_action_list, cache_resource, next);
1537         dev_flow->dv.port_id_action = cache_resource;
1538         DRV_LOG(DEBUG, "new port id action resource %p: refcnt %d++",
1539                 (void *)cache_resource,
1540                 rte_atomic32_read(&cache_resource->refcnt));
1541         return 0;
1542 }
1543
1544 /**
1545  * Find existing push vlan resource or create and register a new one.
1546  *
1547  * @param dev[in, out]
1548  *   Pointer to rte_eth_dev structure.
1549  * @param[in, out] resource
1550  *   Pointer to port ID action resource.
1551  * @parm[in, out] dev_flow
1552  *   Pointer to the dev_flow.
1553  * @param[out] error
1554  *   pointer to error structure.
1555  *
1556  * @return
1557  *   0 on success otherwise -errno and errno is set.
1558  */
1559 static int
1560 flow_dv_push_vlan_action_resource_register
1561                        (struct rte_eth_dev *dev,
1562                         struct mlx5_flow_dv_push_vlan_action_resource *resource,
1563                         struct mlx5_flow *dev_flow,
1564                         struct rte_flow_error *error)
1565 {
1566         struct mlx5_priv *priv = dev->data->dev_private;
1567         struct mlx5_ibv_shared *sh = priv->sh;
1568         struct mlx5_flow_dv_push_vlan_action_resource *cache_resource;
1569         struct mlx5dv_dr_domain *domain;
1570
1571         /* Lookup a matching resource from cache. */
1572         LIST_FOREACH(cache_resource, &sh->push_vlan_action_list, next) {
1573                 if (resource->vlan_tag == cache_resource->vlan_tag &&
1574                     resource->ft_type == cache_resource->ft_type) {
1575                         DRV_LOG(DEBUG, "push-VLAN action resource resource %p: "
1576                                 "refcnt %d++",
1577                                 (void *)cache_resource,
1578                                 rte_atomic32_read(&cache_resource->refcnt));
1579                         rte_atomic32_inc(&cache_resource->refcnt);
1580                         dev_flow->dv.push_vlan_res = cache_resource;
1581                         return 0;
1582                 }
1583         }
1584         /* Register new push_vlan action resource. */
1585         cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
1586         if (!cache_resource)
1587                 return rte_flow_error_set(error, ENOMEM,
1588                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1589                                           "cannot allocate resource memory");
1590         *cache_resource = *resource;
1591         if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
1592                 domain = sh->fdb_domain;
1593         else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_RX)
1594                 domain = sh->rx_domain;
1595         else
1596                 domain = sh->tx_domain;
1597         cache_resource->action =
1598                 mlx5_glue->dr_create_flow_action_push_vlan(domain,
1599                                                            resource->vlan_tag);
1600         if (!cache_resource->action) {
1601                 rte_free(cache_resource);
1602                 return rte_flow_error_set(error, ENOMEM,
1603                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1604                                           NULL, "cannot create action");
1605         }
1606         rte_atomic32_init(&cache_resource->refcnt);
1607         rte_atomic32_inc(&cache_resource->refcnt);
1608         LIST_INSERT_HEAD(&sh->push_vlan_action_list, cache_resource, next);
1609         dev_flow->dv.push_vlan_res = cache_resource;
1610         DRV_LOG(DEBUG, "new push vlan action resource %p: refcnt %d++",
1611                 (void *)cache_resource,
1612                 rte_atomic32_read(&cache_resource->refcnt));
1613         return 0;
1614 }
1615 /**
1616  * Get the size of specific rte_flow_item_type
1617  *
1618  * @param[in] item_type
1619  *   Tested rte_flow_item_type.
1620  *
1621  * @return
1622  *   sizeof struct item_type, 0 if void or irrelevant.
1623  */
1624 static size_t
1625 flow_dv_get_item_len(const enum rte_flow_item_type item_type)
1626 {
1627         size_t retval;
1628
1629         switch (item_type) {
1630         case RTE_FLOW_ITEM_TYPE_ETH:
1631                 retval = sizeof(struct rte_flow_item_eth);
1632                 break;
1633         case RTE_FLOW_ITEM_TYPE_VLAN:
1634                 retval = sizeof(struct rte_flow_item_vlan);
1635                 break;
1636         case RTE_FLOW_ITEM_TYPE_IPV4:
1637                 retval = sizeof(struct rte_flow_item_ipv4);
1638                 break;
1639         case RTE_FLOW_ITEM_TYPE_IPV6:
1640                 retval = sizeof(struct rte_flow_item_ipv6);
1641                 break;
1642         case RTE_FLOW_ITEM_TYPE_UDP:
1643                 retval = sizeof(struct rte_flow_item_udp);
1644                 break;
1645         case RTE_FLOW_ITEM_TYPE_TCP:
1646                 retval = sizeof(struct rte_flow_item_tcp);
1647                 break;
1648         case RTE_FLOW_ITEM_TYPE_VXLAN:
1649                 retval = sizeof(struct rte_flow_item_vxlan);
1650                 break;
1651         case RTE_FLOW_ITEM_TYPE_GRE:
1652                 retval = sizeof(struct rte_flow_item_gre);
1653                 break;
1654         case RTE_FLOW_ITEM_TYPE_NVGRE:
1655                 retval = sizeof(struct rte_flow_item_nvgre);
1656                 break;
1657         case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1658                 retval = sizeof(struct rte_flow_item_vxlan_gpe);
1659                 break;
1660         case RTE_FLOW_ITEM_TYPE_MPLS:
1661                 retval = sizeof(struct rte_flow_item_mpls);
1662                 break;
1663         case RTE_FLOW_ITEM_TYPE_VOID: /* Fall through. */
1664         default:
1665                 retval = 0;
1666                 break;
1667         }
1668         return retval;
1669 }
1670
1671 #define MLX5_ENCAP_IPV4_VERSION         0x40
1672 #define MLX5_ENCAP_IPV4_IHL_MIN         0x05
1673 #define MLX5_ENCAP_IPV4_TTL_DEF         0x40
1674 #define MLX5_ENCAP_IPV6_VTC_FLOW        0x60000000
1675 #define MLX5_ENCAP_IPV6_HOP_LIMIT       0xff
1676 #define MLX5_ENCAP_VXLAN_FLAGS          0x08000000
1677 #define MLX5_ENCAP_VXLAN_GPE_FLAGS      0x04
1678
1679 /**
1680  * Convert the encap action data from list of rte_flow_item to raw buffer
1681  *
1682  * @param[in] items
1683  *   Pointer to rte_flow_item objects list.
1684  * @param[out] buf
1685  *   Pointer to the output buffer.
1686  * @param[out] size
1687  *   Pointer to the output buffer size.
1688  * @param[out] error
1689  *   Pointer to the error structure.
1690  *
1691  * @return
1692  *   0 on success, a negative errno value otherwise and rte_errno is set.
1693  */
1694 static int
1695 flow_dv_convert_encap_data(const struct rte_flow_item *items, uint8_t *buf,
1696                            size_t *size, struct rte_flow_error *error)
1697 {
1698         struct rte_ether_hdr *eth = NULL;
1699         struct rte_vlan_hdr *vlan = NULL;
1700         struct rte_ipv4_hdr *ipv4 = NULL;
1701         struct rte_ipv6_hdr *ipv6 = NULL;
1702         struct rte_udp_hdr *udp = NULL;
1703         struct rte_vxlan_hdr *vxlan = NULL;
1704         struct rte_vxlan_gpe_hdr *vxlan_gpe = NULL;
1705         struct rte_gre_hdr *gre = NULL;
1706         size_t len;
1707         size_t temp_size = 0;
1708
1709         if (!items)
1710                 return rte_flow_error_set(error, EINVAL,
1711                                           RTE_FLOW_ERROR_TYPE_ACTION,
1712                                           NULL, "invalid empty data");
1713         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1714                 len = flow_dv_get_item_len(items->type);
1715                 if (len + temp_size > MLX5_ENCAP_MAX_LEN)
1716                         return rte_flow_error_set(error, EINVAL,
1717                                                   RTE_FLOW_ERROR_TYPE_ACTION,
1718                                                   (void *)items->type,
1719                                                   "items total size is too big"
1720                                                   " for encap action");
1721                 rte_memcpy((void *)&buf[temp_size], items->spec, len);
1722                 switch (items->type) {
1723                 case RTE_FLOW_ITEM_TYPE_ETH:
1724                         eth = (struct rte_ether_hdr *)&buf[temp_size];
1725                         break;
1726                 case RTE_FLOW_ITEM_TYPE_VLAN:
1727                         vlan = (struct rte_vlan_hdr *)&buf[temp_size];
1728                         if (!eth)
1729                                 return rte_flow_error_set(error, EINVAL,
1730                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1731                                                 (void *)items->type,
1732                                                 "eth header not found");
1733                         if (!eth->ether_type)
1734                                 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_VLAN);
1735                         break;
1736                 case RTE_FLOW_ITEM_TYPE_IPV4:
1737                         ipv4 = (struct rte_ipv4_hdr *)&buf[temp_size];
1738                         if (!vlan && !eth)
1739                                 return rte_flow_error_set(error, EINVAL,
1740                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1741                                                 (void *)items->type,
1742                                                 "neither eth nor vlan"
1743                                                 " header found");
1744                         if (vlan && !vlan->eth_proto)
1745                                 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV4);
1746                         else if (eth && !eth->ether_type)
1747                                 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV4);
1748                         if (!ipv4->version_ihl)
1749                                 ipv4->version_ihl = MLX5_ENCAP_IPV4_VERSION |
1750                                                     MLX5_ENCAP_IPV4_IHL_MIN;
1751                         if (!ipv4->time_to_live)
1752                                 ipv4->time_to_live = MLX5_ENCAP_IPV4_TTL_DEF;
1753                         break;
1754                 case RTE_FLOW_ITEM_TYPE_IPV6:
1755                         ipv6 = (struct rte_ipv6_hdr *)&buf[temp_size];
1756                         if (!vlan && !eth)
1757                                 return rte_flow_error_set(error, EINVAL,
1758                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1759                                                 (void *)items->type,
1760                                                 "neither eth nor vlan"
1761                                                 " header found");
1762                         if (vlan && !vlan->eth_proto)
1763                                 vlan->eth_proto = RTE_BE16(RTE_ETHER_TYPE_IPV6);
1764                         else if (eth && !eth->ether_type)
1765                                 eth->ether_type = RTE_BE16(RTE_ETHER_TYPE_IPV6);
1766                         if (!ipv6->vtc_flow)
1767                                 ipv6->vtc_flow =
1768                                         RTE_BE32(MLX5_ENCAP_IPV6_VTC_FLOW);
1769                         if (!ipv6->hop_limits)
1770                                 ipv6->hop_limits = MLX5_ENCAP_IPV6_HOP_LIMIT;
1771                         break;
1772                 case RTE_FLOW_ITEM_TYPE_UDP:
1773                         udp = (struct rte_udp_hdr *)&buf[temp_size];
1774                         if (!ipv4 && !ipv6)
1775                                 return rte_flow_error_set(error, EINVAL,
1776                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1777                                                 (void *)items->type,
1778                                                 "ip header not found");
1779                         if (ipv4 && !ipv4->next_proto_id)
1780                                 ipv4->next_proto_id = IPPROTO_UDP;
1781                         else if (ipv6 && !ipv6->proto)
1782                                 ipv6->proto = IPPROTO_UDP;
1783                         break;
1784                 case RTE_FLOW_ITEM_TYPE_VXLAN:
1785                         vxlan = (struct rte_vxlan_hdr *)&buf[temp_size];
1786                         if (!udp)
1787                                 return rte_flow_error_set(error, EINVAL,
1788                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1789                                                 (void *)items->type,
1790                                                 "udp header not found");
1791                         if (!udp->dst_port)
1792                                 udp->dst_port = RTE_BE16(MLX5_UDP_PORT_VXLAN);
1793                         if (!vxlan->vx_flags)
1794                                 vxlan->vx_flags =
1795                                         RTE_BE32(MLX5_ENCAP_VXLAN_FLAGS);
1796                         break;
1797                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1798                         vxlan_gpe = (struct rte_vxlan_gpe_hdr *)&buf[temp_size];
1799                         if (!udp)
1800                                 return rte_flow_error_set(error, EINVAL,
1801                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1802                                                 (void *)items->type,
1803                                                 "udp header not found");
1804                         if (!vxlan_gpe->proto)
1805                                 return rte_flow_error_set(error, EINVAL,
1806                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1807                                                 (void *)items->type,
1808                                                 "next protocol not found");
1809                         if (!udp->dst_port)
1810                                 udp->dst_port =
1811                                         RTE_BE16(MLX5_UDP_PORT_VXLAN_GPE);
1812                         if (!vxlan_gpe->vx_flags)
1813                                 vxlan_gpe->vx_flags =
1814                                                 MLX5_ENCAP_VXLAN_GPE_FLAGS;
1815                         break;
1816                 case RTE_FLOW_ITEM_TYPE_GRE:
1817                 case RTE_FLOW_ITEM_TYPE_NVGRE:
1818                         gre = (struct rte_gre_hdr *)&buf[temp_size];
1819                         if (!gre->proto)
1820                                 return rte_flow_error_set(error, EINVAL,
1821                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1822                                                 (void *)items->type,
1823                                                 "next protocol not found");
1824                         if (!ipv4 && !ipv6)
1825                                 return rte_flow_error_set(error, EINVAL,
1826                                                 RTE_FLOW_ERROR_TYPE_ACTION,
1827                                                 (void *)items->type,
1828                                                 "ip header not found");
1829                         if (ipv4 && !ipv4->next_proto_id)
1830                                 ipv4->next_proto_id = IPPROTO_GRE;
1831                         else if (ipv6 && !ipv6->proto)
1832                                 ipv6->proto = IPPROTO_GRE;
1833                         break;
1834                 case RTE_FLOW_ITEM_TYPE_VOID:
1835                         break;
1836                 default:
1837                         return rte_flow_error_set(error, EINVAL,
1838                                                   RTE_FLOW_ERROR_TYPE_ACTION,
1839                                                   (void *)items->type,
1840                                                   "unsupported item type");
1841                         break;
1842                 }
1843                 temp_size += len;
1844         }
1845         *size = temp_size;
1846         return 0;
1847 }
1848
1849 static int
1850 flow_dv_zero_encap_udp_csum(void *data, struct rte_flow_error *error)
1851 {
1852         struct rte_ether_hdr *eth = NULL;
1853         struct rte_vlan_hdr *vlan = NULL;
1854         struct rte_ipv6_hdr *ipv6 = NULL;
1855         struct rte_udp_hdr *udp = NULL;
1856         char *next_hdr;
1857         uint16_t proto;
1858
1859         eth = (struct rte_ether_hdr *)data;
1860         next_hdr = (char *)(eth + 1);
1861         proto = RTE_BE16(eth->ether_type);
1862
1863         /* VLAN skipping */
1864         while (proto == RTE_ETHER_TYPE_VLAN || proto == RTE_ETHER_TYPE_QINQ) {
1865                 vlan = (struct rte_vlan_hdr *)next_hdr;
1866                 proto = RTE_BE16(vlan->eth_proto);
1867                 next_hdr += sizeof(struct rte_vlan_hdr);
1868         }
1869
1870         /* HW calculates IPv4 csum. no need to proceed */
1871         if (proto == RTE_ETHER_TYPE_IPV4)
1872                 return 0;
1873
1874         /* non IPv4/IPv6 header. not supported */
1875         if (proto != RTE_ETHER_TYPE_IPV6) {
1876                 return rte_flow_error_set(error, ENOTSUP,
1877                                           RTE_FLOW_ERROR_TYPE_ACTION,
1878                                           NULL, "Cannot offload non IPv4/IPv6");
1879         }
1880
1881         ipv6 = (struct rte_ipv6_hdr *)next_hdr;
1882
1883         /* ignore non UDP */
1884         if (ipv6->proto != IPPROTO_UDP)
1885                 return 0;
1886
1887         udp = (struct rte_udp_hdr *)(ipv6 + 1);
1888         udp->dgram_cksum = 0;
1889
1890         return 0;
1891 }
1892
1893 /**
1894  * Convert L2 encap action to DV specification.
1895  *
1896  * @param[in] dev
1897  *   Pointer to rte_eth_dev structure.
1898  * @param[in] action
1899  *   Pointer to action structure.
1900  * @param[in, out] dev_flow
1901  *   Pointer to the mlx5_flow.
1902  * @param[in] transfer
1903  *   Mark if the flow is E-Switch flow.
1904  * @param[out] error
1905  *   Pointer to the error structure.
1906  *
1907  * @return
1908  *   0 on success, a negative errno value otherwise and rte_errno is set.
1909  */
1910 static int
1911 flow_dv_create_action_l2_encap(struct rte_eth_dev *dev,
1912                                const struct rte_flow_action *action,
1913                                struct mlx5_flow *dev_flow,
1914                                uint8_t transfer,
1915                                struct rte_flow_error *error)
1916 {
1917         const struct rte_flow_item *encap_data;
1918         const struct rte_flow_action_raw_encap *raw_encap_data;
1919         struct mlx5_flow_dv_encap_decap_resource res = {
1920                 .reformat_type =
1921                         MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL,
1922                 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
1923                                       MLX5DV_FLOW_TABLE_TYPE_NIC_TX,
1924         };
1925
1926         if (action->type == RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
1927                 raw_encap_data =
1928                         (const struct rte_flow_action_raw_encap *)action->conf;
1929                 res.size = raw_encap_data->size;
1930                 memcpy(res.buf, raw_encap_data->data, res.size);
1931                 if (flow_dv_zero_encap_udp_csum(res.buf, error))
1932                         return -rte_errno;
1933         } else {
1934                 if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP)
1935                         encap_data =
1936                                 ((const struct rte_flow_action_vxlan_encap *)
1937                                                 action->conf)->definition;
1938                 else
1939                         encap_data =
1940                                 ((const struct rte_flow_action_nvgre_encap *)
1941                                                 action->conf)->definition;
1942                 if (flow_dv_convert_encap_data(encap_data, res.buf,
1943                                                &res.size, error))
1944                         return -rte_errno;
1945         }
1946         if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
1947                 return rte_flow_error_set(error, EINVAL,
1948                                           RTE_FLOW_ERROR_TYPE_ACTION,
1949                                           NULL, "can't create L2 encap action");
1950         return 0;
1951 }
1952
1953 /**
1954  * Convert L2 decap action to DV specification.
1955  *
1956  * @param[in] dev
1957  *   Pointer to rte_eth_dev structure.
1958  * @param[in, out] dev_flow
1959  *   Pointer to the mlx5_flow.
1960  * @param[in] transfer
1961  *   Mark if the flow is E-Switch flow.
1962  * @param[out] error
1963  *   Pointer to the error structure.
1964  *
1965  * @return
1966  *   0 on success, a negative errno value otherwise and rte_errno is set.
1967  */
1968 static int
1969 flow_dv_create_action_l2_decap(struct rte_eth_dev *dev,
1970                                struct mlx5_flow *dev_flow,
1971                                uint8_t transfer,
1972                                struct rte_flow_error *error)
1973 {
1974         struct mlx5_flow_dv_encap_decap_resource res = {
1975                 .size = 0,
1976                 .reformat_type =
1977                         MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2,
1978                 .ft_type = transfer ? MLX5DV_FLOW_TABLE_TYPE_FDB :
1979                                       MLX5DV_FLOW_TABLE_TYPE_NIC_RX,
1980         };
1981
1982         if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
1983                 return rte_flow_error_set(error, EINVAL,
1984                                           RTE_FLOW_ERROR_TYPE_ACTION,
1985                                           NULL, "can't create L2 decap action");
1986         return 0;
1987 }
1988
1989 /**
1990  * Convert raw decap/encap (L3 tunnel) action to DV specification.
1991  *
1992  * @param[in] dev
1993  *   Pointer to rte_eth_dev structure.
1994  * @param[in] action
1995  *   Pointer to action structure.
1996  * @param[in, out] dev_flow
1997  *   Pointer to the mlx5_flow.
1998  * @param[in] attr
1999  *   Pointer to the flow attributes.
2000  * @param[out] error
2001  *   Pointer to the error structure.
2002  *
2003  * @return
2004  *   0 on success, a negative errno value otherwise and rte_errno is set.
2005  */
2006 static int
2007 flow_dv_create_action_raw_encap(struct rte_eth_dev *dev,
2008                                 const struct rte_flow_action *action,
2009                                 struct mlx5_flow *dev_flow,
2010                                 const struct rte_flow_attr *attr,
2011                                 struct rte_flow_error *error)
2012 {
2013         const struct rte_flow_action_raw_encap *encap_data;
2014         struct mlx5_flow_dv_encap_decap_resource res;
2015
2016         encap_data = (const struct rte_flow_action_raw_encap *)action->conf;
2017         res.size = encap_data->size;
2018         memcpy(res.buf, encap_data->data, res.size);
2019         res.reformat_type = attr->egress ?
2020                 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL :
2021                 MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
2022         if (attr->transfer)
2023                 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
2024         else
2025                 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
2026                                              MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
2027         if (flow_dv_encap_decap_resource_register(dev, &res, dev_flow, error))
2028                 return rte_flow_error_set(error, EINVAL,
2029                                           RTE_FLOW_ERROR_TYPE_ACTION,
2030                                           NULL, "can't create encap action");
2031         return 0;
2032 }
2033
2034 /**
2035  * Create action push VLAN.
2036  *
2037  * @param[in] dev
2038  *   Pointer to rte_eth_dev structure.
2039  * @param[in] vlan_tag
2040  *   the vlan tag to push to the Ethernet header.
2041  * @param[in, out] dev_flow
2042  *   Pointer to the mlx5_flow.
2043  * @param[in] attr
2044  *   Pointer to the flow attributes.
2045  * @param[out] error
2046  *   Pointer to the error structure.
2047  *
2048  * @return
2049  *   0 on success, a negative errno value otherwise and rte_errno is set.
2050  */
2051 static int
2052 flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
2053                                 const struct rte_flow_attr *attr,
2054                                 const struct rte_vlan_hdr *vlan,
2055                                 struct mlx5_flow *dev_flow,
2056                                 struct rte_flow_error *error)
2057 {
2058         struct mlx5_flow_dv_push_vlan_action_resource res;
2059
2060         res.vlan_tag =
2061                 rte_cpu_to_be_32(((uint32_t)vlan->eth_proto) << 16 |
2062                                  vlan->vlan_tci);
2063         if (attr->transfer)
2064                 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
2065         else
2066                 res.ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
2067                                              MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
2068         return flow_dv_push_vlan_action_resource_register
2069                                             (dev, &res, dev_flow, error);
2070 }
2071
2072 /**
2073  * Validate the modify-header actions.
2074  *
2075  * @param[in] action_flags
2076  *   Holds the actions detected until now.
2077  * @param[in] action
2078  *   Pointer to the modify action.
2079  * @param[out] error
2080  *   Pointer to error structure.
2081  *
2082  * @return
2083  *   0 on success, a negative errno value otherwise and rte_errno is set.
2084  */
2085 static int
2086 flow_dv_validate_action_modify_hdr(const uint64_t action_flags,
2087                                    const struct rte_flow_action *action,
2088                                    struct rte_flow_error *error)
2089 {
2090         if (action->type != RTE_FLOW_ACTION_TYPE_DEC_TTL && !action->conf)
2091                 return rte_flow_error_set(error, EINVAL,
2092                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
2093                                           NULL, "action configuration not set");
2094         if (action_flags & MLX5_FLOW_ENCAP_ACTIONS)
2095                 return rte_flow_error_set(error, EINVAL,
2096                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2097                                           "can't have encap action before"
2098                                           " modify action");
2099         return 0;
2100 }
2101
2102 /**
2103  * Validate the modify-header MAC address actions.
2104  *
2105  * @param[in] action_flags
2106  *   Holds the actions detected until now.
2107  * @param[in] action
2108  *   Pointer to the modify action.
2109  * @param[in] item_flags
2110  *   Holds the items detected.
2111  * @param[out] error
2112  *   Pointer to error structure.
2113  *
2114  * @return
2115  *   0 on success, a negative errno value otherwise and rte_errno is set.
2116  */
2117 static int
2118 flow_dv_validate_action_modify_mac(const uint64_t action_flags,
2119                                    const struct rte_flow_action *action,
2120                                    const uint64_t item_flags,
2121                                    struct rte_flow_error *error)
2122 {
2123         int ret = 0;
2124
2125         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
2126         if (!ret) {
2127                 if (!(item_flags & MLX5_FLOW_LAYER_L2))
2128                         return rte_flow_error_set(error, EINVAL,
2129                                                   RTE_FLOW_ERROR_TYPE_ACTION,
2130                                                   NULL,
2131                                                   "no L2 item in pattern");
2132         }
2133         return ret;
2134 }
2135
2136 /**
2137  * Validate the modify-header IPv4 address actions.
2138  *
2139  * @param[in] action_flags
2140  *   Holds the actions detected until now.
2141  * @param[in] action
2142  *   Pointer to the modify action.
2143  * @param[in] item_flags
2144  *   Holds the items detected.
2145  * @param[out] error
2146  *   Pointer to error structure.
2147  *
2148  * @return
2149  *   0 on success, a negative errno value otherwise and rte_errno is set.
2150  */
2151 static int
2152 flow_dv_validate_action_modify_ipv4(const uint64_t action_flags,
2153                                     const struct rte_flow_action *action,
2154                                     const uint64_t item_flags,
2155                                     struct rte_flow_error *error)
2156 {
2157         int ret = 0;
2158
2159         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
2160         if (!ret) {
2161                 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV4))
2162                         return rte_flow_error_set(error, EINVAL,
2163                                                   RTE_FLOW_ERROR_TYPE_ACTION,
2164                                                   NULL,
2165                                                   "no ipv4 item in pattern");
2166         }
2167         return ret;
2168 }
2169
2170 /**
2171  * Validate the modify-header IPv6 address actions.
2172  *
2173  * @param[in] action_flags
2174  *   Holds the actions detected until now.
2175  * @param[in] action
2176  *   Pointer to the modify action.
2177  * @param[in] item_flags
2178  *   Holds the items detected.
2179  * @param[out] error
2180  *   Pointer to error structure.
2181  *
2182  * @return
2183  *   0 on success, a negative errno value otherwise and rte_errno is set.
2184  */
2185 static int
2186 flow_dv_validate_action_modify_ipv6(const uint64_t action_flags,
2187                                     const struct rte_flow_action *action,
2188                                     const uint64_t item_flags,
2189                                     struct rte_flow_error *error)
2190 {
2191         int ret = 0;
2192
2193         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
2194         if (!ret) {
2195                 if (!(item_flags & MLX5_FLOW_LAYER_L3_IPV6))
2196                         return rte_flow_error_set(error, EINVAL,
2197                                                   RTE_FLOW_ERROR_TYPE_ACTION,
2198                                                   NULL,
2199                                                   "no ipv6 item in pattern");
2200         }
2201         return ret;
2202 }
2203
2204 /**
2205  * Validate the modify-header TP actions.
2206  *
2207  * @param[in] action_flags
2208  *   Holds the actions detected until now.
2209  * @param[in] action
2210  *   Pointer to the modify action.
2211  * @param[in] item_flags
2212  *   Holds the items detected.
2213  * @param[out] error
2214  *   Pointer to error structure.
2215  *
2216  * @return
2217  *   0 on success, a negative errno value otherwise and rte_errno is set.
2218  */
2219 static int
2220 flow_dv_validate_action_modify_tp(const uint64_t action_flags,
2221                                   const struct rte_flow_action *action,
2222                                   const uint64_t item_flags,
2223                                   struct rte_flow_error *error)
2224 {
2225         int ret = 0;
2226
2227         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
2228         if (!ret) {
2229                 if (!(item_flags & MLX5_FLOW_LAYER_L4))
2230                         return rte_flow_error_set(error, EINVAL,
2231                                                   RTE_FLOW_ERROR_TYPE_ACTION,
2232                                                   NULL, "no transport layer "
2233                                                   "in pattern");
2234         }
2235         return ret;
2236 }
2237
2238 /**
2239  * Validate the modify-header actions of increment/decrement
2240  * TCP Sequence-number.
2241  *
2242  * @param[in] action_flags
2243  *   Holds the actions detected until now.
2244  * @param[in] action
2245  *   Pointer to the modify action.
2246  * @param[in] item_flags
2247  *   Holds the items detected.
2248  * @param[out] error
2249  *   Pointer to error structure.
2250  *
2251  * @return
2252  *   0 on success, a negative errno value otherwise and rte_errno is set.
2253  */
2254 static int
2255 flow_dv_validate_action_modify_tcp_seq(const uint64_t action_flags,
2256                                        const struct rte_flow_action *action,
2257                                        const uint64_t item_flags,
2258                                        struct rte_flow_error *error)
2259 {
2260         int ret = 0;
2261
2262         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
2263         if (!ret) {
2264                 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP))
2265                         return rte_flow_error_set(error, EINVAL,
2266                                                   RTE_FLOW_ERROR_TYPE_ACTION,
2267                                                   NULL, "no TCP item in"
2268                                                   " pattern");
2269                 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ &&
2270                         (action_flags & MLX5_FLOW_ACTION_DEC_TCP_SEQ)) ||
2271                     (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ &&
2272                         (action_flags & MLX5_FLOW_ACTION_INC_TCP_SEQ)))
2273                         return rte_flow_error_set(error, EINVAL,
2274                                                   RTE_FLOW_ERROR_TYPE_ACTION,
2275                                                   NULL,
2276                                                   "cannot decrease and increase"
2277                                                   " TCP sequence number"
2278                                                   " at the same time");
2279         }
2280         return ret;
2281 }
2282
2283 /**
2284  * Validate the modify-header actions of increment/decrement
2285  * TCP Acknowledgment number.
2286  *
2287  * @param[in] action_flags
2288  *   Holds the actions detected until now.
2289  * @param[in] action
2290  *   Pointer to the modify action.
2291  * @param[in] item_flags
2292  *   Holds the items detected.
2293  * @param[out] error
2294  *   Pointer to error structure.
2295  *
2296  * @return
2297  *   0 on success, a negative errno value otherwise and rte_errno is set.
2298  */
2299 static int
2300 flow_dv_validate_action_modify_tcp_ack(const uint64_t action_flags,
2301                                        const struct rte_flow_action *action,
2302                                        const uint64_t item_flags,
2303                                        struct rte_flow_error *error)
2304 {
2305         int ret = 0;
2306
2307         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
2308         if (!ret) {
2309                 if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP))
2310                         return rte_flow_error_set(error, EINVAL,
2311                                                   RTE_FLOW_ERROR_TYPE_ACTION,
2312                                                   NULL, "no TCP item in"
2313                                                   " pattern");
2314                 if ((action->type == RTE_FLOW_ACTION_TYPE_INC_TCP_ACK &&
2315                         (action_flags & MLX5_FLOW_ACTION_DEC_TCP_ACK)) ||
2316                     (action->type == RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK &&
2317                         (action_flags & MLX5_FLOW_ACTION_INC_TCP_ACK)))
2318                         return rte_flow_error_set(error, EINVAL,
2319                                                   RTE_FLOW_ERROR_TYPE_ACTION,
2320                                                   NULL,
2321                                                   "cannot decrease and increase"
2322                                                   " TCP acknowledgment number"
2323                                                   " at the same time");
2324         }
2325         return ret;
2326 }
2327
2328 /**
2329  * Validate the modify-header TTL actions.
2330  *
2331  * @param[in] action_flags
2332  *   Holds the actions detected until now.
2333  * @param[in] action
2334  *   Pointer to the modify action.
2335  * @param[in] item_flags
2336  *   Holds the items detected.
2337  * @param[out] error
2338  *   Pointer to error structure.
2339  *
2340  * @return
2341  *   0 on success, a negative errno value otherwise and rte_errno is set.
2342  */
2343 static int
2344 flow_dv_validate_action_modify_ttl(const uint64_t action_flags,
2345                                    const struct rte_flow_action *action,
2346                                    const uint64_t item_flags,
2347                                    struct rte_flow_error *error)
2348 {
2349         int ret = 0;
2350
2351         ret = flow_dv_validate_action_modify_hdr(action_flags, action, error);
2352         if (!ret) {
2353                 if (!(item_flags & MLX5_FLOW_LAYER_L3))
2354                         return rte_flow_error_set(error, EINVAL,
2355                                                   RTE_FLOW_ERROR_TYPE_ACTION,
2356                                                   NULL,
2357                                                   "no IP protocol in pattern");
2358         }
2359         return ret;
2360 }
2361
2362 /**
2363  * Validate jump action.
2364  *
2365  * @param[in] action
2366  *   Pointer to the jump action.
2367  * @param[in] action_flags
2368  *   Holds the actions detected until now.
2369  * @param[in] attributes
2370  *   Pointer to flow attributes
2371  * @param[in] external
2372  *   Action belongs to flow rule created by request external to PMD.
2373  * @param[out] error
2374  *   Pointer to error structure.
2375  *
2376  * @return
2377  *   0 on success, a negative errno value otherwise and rte_errno is set.
2378  */
2379 static int
2380 flow_dv_validate_action_jump(const struct rte_flow_action *action,
2381                              uint64_t action_flags,
2382                              const struct rte_flow_attr *attributes,
2383                              bool external, struct rte_flow_error *error)
2384 {
2385         uint32_t max_group = attributes->transfer ? MLX5_MAX_TABLES_FDB :
2386                                                     MLX5_MAX_TABLES;
2387         uint32_t target_group, table;
2388         int ret = 0;
2389
2390         if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
2391                             MLX5_FLOW_FATE_ESWITCH_ACTIONS))
2392                 return rte_flow_error_set(error, EINVAL,
2393                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2394                                           "can't have 2 fate actions in"
2395                                           " same flow");
2396         if (!action->conf)
2397                 return rte_flow_error_set(error, EINVAL,
2398                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
2399                                           NULL, "action configuration not set");
2400         target_group =
2401                 ((const struct rte_flow_action_jump *)action->conf)->group;
2402         ret = mlx5_flow_group_to_table(attributes, external, target_group,
2403                                        &table, error);
2404         if (ret)
2405                 return ret;
2406         if (table >= max_group)
2407                 return rte_flow_error_set(error, EINVAL,
2408                                           RTE_FLOW_ERROR_TYPE_ATTR_GROUP, NULL,
2409                                           "target group index out of range");
2410         if (attributes->group >= target_group)
2411                 return rte_flow_error_set(error, EINVAL,
2412                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2413                                           "target group must be higher than"
2414                                           " the current flow group");
2415         return 0;
2416 }
2417
2418 /*
2419  * Validate the port_id action.
2420  *
2421  * @param[in] dev
2422  *   Pointer to rte_eth_dev structure.
2423  * @param[in] action_flags
2424  *   Bit-fields that holds the actions detected until now.
2425  * @param[in] action
2426  *   Port_id RTE action structure.
2427  * @param[in] attr
2428  *   Attributes of flow that includes this action.
2429  * @param[out] error
2430  *   Pointer to error structure.
2431  *
2432  * @return
2433  *   0 on success, a negative errno value otherwise and rte_errno is set.
2434  */
2435 static int
2436 flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
2437                                 uint64_t action_flags,
2438                                 const struct rte_flow_action *action,
2439                                 const struct rte_flow_attr *attr,
2440                                 struct rte_flow_error *error)
2441 {
2442         const struct rte_flow_action_port_id *port_id;
2443         uint16_t port;
2444         uint16_t esw_domain_id;
2445         uint16_t act_port_domain_id;
2446         int ret;
2447
2448         if (!attr->transfer)
2449                 return rte_flow_error_set(error, ENOTSUP,
2450                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2451                                           NULL,
2452                                           "port id action is valid in transfer"
2453                                           " mode only");
2454         if (!action || !action->conf)
2455                 return rte_flow_error_set(error, ENOTSUP,
2456                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
2457                                           NULL,
2458                                           "port id action parameters must be"
2459                                           " specified");
2460         if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
2461                             MLX5_FLOW_FATE_ESWITCH_ACTIONS))
2462                 return rte_flow_error_set(error, EINVAL,
2463                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2464                                           "can have only one fate actions in"
2465                                           " a flow");
2466         ret = mlx5_port_to_eswitch_info(dev->data->port_id,
2467                                         &esw_domain_id, NULL);
2468         if (ret < 0)
2469                 return rte_flow_error_set(error, -ret,
2470                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2471                                           NULL,
2472                                           "failed to obtain E-Switch info");
2473         port_id = action->conf;
2474         port = port_id->original ? dev->data->port_id : port_id->id;
2475         ret = mlx5_port_to_eswitch_info(port, &act_port_domain_id, NULL);
2476         if (ret)
2477                 return rte_flow_error_set
2478                                 (error, -ret,
2479                                  RTE_FLOW_ERROR_TYPE_ACTION_CONF, port_id,
2480                                  "failed to obtain E-Switch port id for port");
2481         if (act_port_domain_id != esw_domain_id)
2482                 return rte_flow_error_set
2483                                 (error, -ret,
2484                                  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2485                                  "port does not belong to"
2486                                  " E-Switch being configured");
2487         return 0;
2488 }
2489
2490 /**
2491  * Find existing modify-header resource or create and register a new one.
2492  *
2493  * @param dev[in, out]
2494  *   Pointer to rte_eth_dev structure.
2495  * @param[in, out] resource
2496  *   Pointer to modify-header resource.
2497  * @parm[in, out] dev_flow
2498  *   Pointer to the dev_flow.
2499  * @param[out] error
2500  *   pointer to error structure.
2501  *
2502  * @return
2503  *   0 on success otherwise -errno and errno is set.
2504  */
2505 static int
2506 flow_dv_modify_hdr_resource_register
2507                         (struct rte_eth_dev *dev,
2508                          struct mlx5_flow_dv_modify_hdr_resource *resource,
2509                          struct mlx5_flow *dev_flow,
2510                          struct rte_flow_error *error)
2511 {
2512         struct mlx5_priv *priv = dev->data->dev_private;
2513         struct mlx5_ibv_shared *sh = priv->sh;
2514         struct mlx5_flow_dv_modify_hdr_resource *cache_resource;
2515         struct mlx5dv_dr_domain *ns;
2516
2517         if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
2518                 ns = sh->fdb_domain;
2519         else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
2520                 ns = sh->tx_domain;
2521         else
2522                 ns = sh->rx_domain;
2523         resource->flags =
2524                 dev_flow->flow->group ? 0 : MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
2525         /* Lookup a matching resource from cache. */
2526         LIST_FOREACH(cache_resource, &sh->modify_cmds, next) {
2527                 if (resource->ft_type == cache_resource->ft_type &&
2528                     resource->actions_num == cache_resource->actions_num &&
2529                     resource->flags == cache_resource->flags &&
2530                     !memcmp((const void *)resource->actions,
2531                             (const void *)cache_resource->actions,
2532                             (resource->actions_num *
2533                                             sizeof(resource->actions[0])))) {
2534                         DRV_LOG(DEBUG, "modify-header resource %p: refcnt %d++",
2535                                 (void *)cache_resource,
2536                                 rte_atomic32_read(&cache_resource->refcnt));
2537                         rte_atomic32_inc(&cache_resource->refcnt);
2538                         dev_flow->dv.modify_hdr = cache_resource;
2539                         return 0;
2540                 }
2541         }
2542         /* Register new modify-header resource. */
2543         cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
2544         if (!cache_resource)
2545                 return rte_flow_error_set(error, ENOMEM,
2546                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2547                                           "cannot allocate resource memory");
2548         *cache_resource = *resource;
2549         cache_resource->verbs_action =
2550                 mlx5_glue->dv_create_flow_action_modify_header
2551                                         (sh->ctx, cache_resource->ft_type,
2552                                          ns, cache_resource->flags,
2553                                          cache_resource->actions_num *
2554                                          sizeof(cache_resource->actions[0]),
2555                                          (uint64_t *)cache_resource->actions);
2556         if (!cache_resource->verbs_action) {
2557                 rte_free(cache_resource);
2558                 return rte_flow_error_set(error, ENOMEM,
2559                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2560                                           NULL, "cannot create action");
2561         }
2562         rte_atomic32_init(&cache_resource->refcnt);
2563         rte_atomic32_inc(&cache_resource->refcnt);
2564         LIST_INSERT_HEAD(&sh->modify_cmds, cache_resource, next);
2565         dev_flow->dv.modify_hdr = cache_resource;
2566         DRV_LOG(DEBUG, "new modify-header resource %p: refcnt %d++",
2567                 (void *)cache_resource,
2568                 rte_atomic32_read(&cache_resource->refcnt));
2569         return 0;
2570 }
2571
2572 #define MLX5_CNT_CONTAINER_RESIZE 64
2573
2574 /**
2575  * Get or create a flow counter.
2576  *
2577  * @param[in] dev
2578  *   Pointer to the Ethernet device structure.
2579  * @param[in] shared
2580  *   Indicate if this counter is shared with other flows.
2581  * @param[in] id
2582  *   Counter identifier.
2583  *
2584  * @return
2585  *   pointer to flow counter on success, NULL otherwise and rte_errno is set.
2586  */
2587 static struct mlx5_flow_counter *
2588 flow_dv_counter_alloc_fallback(struct rte_eth_dev *dev, uint32_t shared,
2589                                uint32_t id)
2590 {
2591         struct mlx5_priv *priv = dev->data->dev_private;
2592         struct mlx5_flow_counter *cnt = NULL;
2593         struct mlx5_devx_obj *dcs = NULL;
2594
2595         if (!priv->config.devx) {
2596                 rte_errno = ENOTSUP;
2597                 return NULL;
2598         }
2599         if (shared) {
2600                 TAILQ_FOREACH(cnt, &priv->sh->cmng.flow_counters, next) {
2601                         if (cnt->shared && cnt->id == id) {
2602                                 cnt->ref_cnt++;
2603                                 return cnt;
2604                         }
2605                 }
2606         }
2607         dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
2608         if (!dcs)
2609                 return NULL;
2610         cnt = rte_calloc(__func__, 1, sizeof(*cnt), 0);
2611         if (!cnt) {
2612                 claim_zero(mlx5_devx_cmd_destroy(cnt->dcs));
2613                 rte_errno = ENOMEM;
2614                 return NULL;
2615         }
2616         struct mlx5_flow_counter tmpl = {
2617                 .shared = shared,
2618                 .ref_cnt = 1,
2619                 .id = id,
2620                 .dcs = dcs,
2621         };
2622         tmpl.action = mlx5_glue->dv_create_flow_action_counter(dcs->obj, 0);
2623         if (!tmpl.action) {
2624                 claim_zero(mlx5_devx_cmd_destroy(cnt->dcs));
2625                 rte_errno = errno;
2626                 rte_free(cnt);
2627                 return NULL;
2628         }
2629         *cnt = tmpl;
2630         TAILQ_INSERT_HEAD(&priv->sh->cmng.flow_counters, cnt, next);
2631         return cnt;
2632 }
2633
2634 /**
2635  * Release a flow counter.
2636  *
2637  * @param[in] dev
2638  *   Pointer to the Ethernet device structure.
2639  * @param[in] counter
2640  *   Pointer to the counter handler.
2641  */
2642 static void
2643 flow_dv_counter_release_fallback(struct rte_eth_dev *dev,
2644                                  struct mlx5_flow_counter *counter)
2645 {
2646         struct mlx5_priv *priv = dev->data->dev_private;
2647
2648         if (!counter)
2649                 return;
2650         if (--counter->ref_cnt == 0) {
2651                 TAILQ_REMOVE(&priv->sh->cmng.flow_counters, counter, next);
2652                 claim_zero(mlx5_devx_cmd_destroy(counter->dcs));
2653                 rte_free(counter);
2654         }
2655 }
2656
2657 /**
2658  * Query a devx flow counter.
2659  *
2660  * @param[in] dev
2661  *   Pointer to the Ethernet device structure.
2662  * @param[in] cnt
2663  *   Pointer to the flow counter.
2664  * @param[out] pkts
2665  *   The statistics value of packets.
2666  * @param[out] bytes
2667  *   The statistics value of bytes.
2668  *
2669  * @return
2670  *   0 on success, otherwise a negative errno value and rte_errno is set.
2671  */
2672 static inline int
2673 _flow_dv_query_count_fallback(struct rte_eth_dev *dev __rte_unused,
2674                      struct mlx5_flow_counter *cnt, uint64_t *pkts,
2675                      uint64_t *bytes)
2676 {
2677         return mlx5_devx_cmd_flow_counter_query(cnt->dcs, 0, 0, pkts, bytes,
2678                                                 0, NULL, NULL, 0);
2679 }
2680
2681 /**
2682  * Get a pool by a counter.
2683  *
2684  * @param[in] cnt
2685  *   Pointer to the counter.
2686  *
2687  * @return
2688  *   The counter pool.
2689  */
2690 static struct mlx5_flow_counter_pool *
2691 flow_dv_counter_pool_get(struct mlx5_flow_counter *cnt)
2692 {
2693         if (!cnt->batch) {
2694                 cnt -= cnt->dcs->id % MLX5_COUNTERS_PER_POOL;
2695                 return (struct mlx5_flow_counter_pool *)cnt - 1;
2696         }
2697         return cnt->pool;
2698 }
2699
2700 /**
2701  * Get a pool by devx counter ID.
2702  *
2703  * @param[in] cont
2704  *   Pointer to the counter container.
2705  * @param[in] id
2706  *   The counter devx ID.
2707  *
2708  * @return
2709  *   The counter pool pointer if exists, NULL otherwise,
2710  */
2711 static struct mlx5_flow_counter_pool *
2712 flow_dv_find_pool_by_id(struct mlx5_pools_container *cont, int id)
2713 {
2714         struct mlx5_flow_counter_pool *pool;
2715
2716         TAILQ_FOREACH(pool, &cont->pool_list, next) {
2717                 int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) *
2718                                 MLX5_COUNTERS_PER_POOL;
2719
2720                 if (id >= base && id < base + MLX5_COUNTERS_PER_POOL)
2721                         return pool;
2722         };
2723         return NULL;
2724 }
2725
2726 /**
2727  * Allocate a new memory for the counter values wrapped by all the needed
2728  * management.
2729  *
2730  * @param[in] dev
2731  *   Pointer to the Ethernet device structure.
2732  * @param[in] raws_n
2733  *   The raw memory areas - each one for MLX5_COUNTERS_PER_POOL counters.
2734  *
2735  * @return
2736  *   The new memory management pointer on success, otherwise NULL and rte_errno
2737  *   is set.
2738  */
2739 static struct mlx5_counter_stats_mem_mng *
2740 flow_dv_create_counter_stat_mem_mng(struct rte_eth_dev *dev, int raws_n)
2741 {
2742         struct mlx5_ibv_shared *sh = ((struct mlx5_priv *)
2743                                         (dev->data->dev_private))->sh;
2744         struct mlx5_devx_mkey_attr mkey_attr;
2745         struct mlx5_counter_stats_mem_mng *mem_mng;
2746         volatile struct flow_counter_stats *raw_data;
2747         int size = (sizeof(struct flow_counter_stats) *
2748                         MLX5_COUNTERS_PER_POOL +
2749                         sizeof(struct mlx5_counter_stats_raw)) * raws_n +
2750                         sizeof(struct mlx5_counter_stats_mem_mng);
2751         uint8_t *mem = rte_calloc(__func__, 1, size, sysconf(_SC_PAGESIZE));
2752         int i;
2753
2754         if (!mem) {
2755                 rte_errno = ENOMEM;
2756                 return NULL;
2757         }
2758         mem_mng = (struct mlx5_counter_stats_mem_mng *)(mem + size) - 1;
2759         size = sizeof(*raw_data) * MLX5_COUNTERS_PER_POOL * raws_n;
2760         mem_mng->umem = mlx5_glue->devx_umem_reg(sh->ctx, mem, size,
2761                                                  IBV_ACCESS_LOCAL_WRITE);
2762         if (!mem_mng->umem) {
2763                 rte_errno = errno;
2764                 rte_free(mem);
2765                 return NULL;
2766         }
2767         mkey_attr.addr = (uintptr_t)mem;
2768         mkey_attr.size = size;
2769         mkey_attr.umem_id = mem_mng->umem->umem_id;
2770         mkey_attr.pd = sh->pdn;
2771         mem_mng->dm = mlx5_devx_cmd_mkey_create(sh->ctx, &mkey_attr);
2772         if (!mem_mng->dm) {
2773                 mlx5_glue->devx_umem_dereg(mem_mng->umem);
2774                 rte_errno = errno;
2775                 rte_free(mem);
2776                 return NULL;
2777         }
2778         mem_mng->raws = (struct mlx5_counter_stats_raw *)(mem + size);
2779         raw_data = (volatile struct flow_counter_stats *)mem;
2780         for (i = 0; i < raws_n; ++i) {
2781                 mem_mng->raws[i].mem_mng = mem_mng;
2782                 mem_mng->raws[i].data = raw_data + i * MLX5_COUNTERS_PER_POOL;
2783         }
2784         LIST_INSERT_HEAD(&sh->cmng.mem_mngs, mem_mng, next);
2785         return mem_mng;
2786 }
2787
2788 /**
2789  * Resize a counter container.
2790  *
2791  * @param[in] dev
2792  *   Pointer to the Ethernet device structure.
2793  * @param[in] batch
2794  *   Whether the pool is for counter that was allocated by batch command.
2795  *
2796  * @return
2797  *   The new container pointer on success, otherwise NULL and rte_errno is set.
2798  */
2799 static struct mlx5_pools_container *
2800 flow_dv_container_resize(struct rte_eth_dev *dev, uint32_t batch)
2801 {
2802         struct mlx5_priv *priv = dev->data->dev_private;
2803         struct mlx5_pools_container *cont =
2804                         MLX5_CNT_CONTAINER(priv->sh, batch, 0);
2805         struct mlx5_pools_container *new_cont =
2806                         MLX5_CNT_CONTAINER_UNUSED(priv->sh, batch, 0);
2807         struct mlx5_counter_stats_mem_mng *mem_mng;
2808         uint32_t resize = cont->n + MLX5_CNT_CONTAINER_RESIZE;
2809         uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize;
2810         int i;
2811
2812         if (cont != MLX5_CNT_CONTAINER(priv->sh, batch, 1)) {
2813                 /* The last resize still hasn't detected by the host thread. */
2814                 rte_errno = EAGAIN;
2815                 return NULL;
2816         }
2817         new_cont->pools = rte_calloc(__func__, 1, mem_size, 0);
2818         if (!new_cont->pools) {
2819                 rte_errno = ENOMEM;
2820                 return NULL;
2821         }
2822         if (cont->n)
2823                 memcpy(new_cont->pools, cont->pools, cont->n *
2824                        sizeof(struct mlx5_flow_counter_pool *));
2825         mem_mng = flow_dv_create_counter_stat_mem_mng(dev,
2826                 MLX5_CNT_CONTAINER_RESIZE + MLX5_MAX_PENDING_QUERIES);
2827         if (!mem_mng) {
2828                 rte_free(new_cont->pools);
2829                 return NULL;
2830         }
2831         for (i = 0; i < MLX5_MAX_PENDING_QUERIES; ++i)
2832                 LIST_INSERT_HEAD(&priv->sh->cmng.free_stat_raws,
2833                                  mem_mng->raws + MLX5_CNT_CONTAINER_RESIZE +
2834                                  i, next);
2835         new_cont->n = resize;
2836         rte_atomic16_set(&new_cont->n_valid, rte_atomic16_read(&cont->n_valid));
2837         TAILQ_INIT(&new_cont->pool_list);
2838         TAILQ_CONCAT(&new_cont->pool_list, &cont->pool_list, next);
2839         new_cont->init_mem_mng = mem_mng;
2840         rte_cio_wmb();
2841          /* Flip the master container. */
2842         priv->sh->cmng.mhi[batch] ^= (uint8_t)1;
2843         return new_cont;
2844 }
2845
2846 /**
2847  * Query a devx flow counter.
2848  *
2849  * @param[in] dev
2850  *   Pointer to the Ethernet device structure.
2851  * @param[in] cnt
2852  *   Pointer to the flow counter.
2853  * @param[out] pkts
2854  *   The statistics value of packets.
2855  * @param[out] bytes
2856  *   The statistics value of bytes.
2857  *
2858  * @return
2859  *   0 on success, otherwise a negative errno value and rte_errno is set.
2860  */
2861 static inline int
2862 _flow_dv_query_count(struct rte_eth_dev *dev,
2863                      struct mlx5_flow_counter *cnt, uint64_t *pkts,
2864                      uint64_t *bytes)
2865 {
2866         struct mlx5_priv *priv = dev->data->dev_private;
2867         struct mlx5_flow_counter_pool *pool =
2868                         flow_dv_counter_pool_get(cnt);
2869         int offset = cnt - &pool->counters_raw[0];
2870
2871         if (priv->counter_fallback)
2872                 return _flow_dv_query_count_fallback(dev, cnt, pkts, bytes);
2873
2874         rte_spinlock_lock(&pool->sl);
2875         /*
2876          * The single counters allocation may allocate smaller ID than the
2877          * current allocated in parallel to the host reading.
2878          * In this case the new counter values must be reported as 0.
2879          */
2880         if (unlikely(!cnt->batch && cnt->dcs->id < pool->raw->min_dcs_id)) {
2881                 *pkts = 0;
2882                 *bytes = 0;
2883         } else {
2884                 *pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits);
2885                 *bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes);
2886         }
2887         rte_spinlock_unlock(&pool->sl);
2888         return 0;
2889 }
2890
2891 /**
2892  * Create and initialize a new counter pool.
2893  *
2894  * @param[in] dev
2895  *   Pointer to the Ethernet device structure.
2896  * @param[out] dcs
2897  *   The devX counter handle.
2898  * @param[in] batch
2899  *   Whether the pool is for counter that was allocated by batch command.
2900  *
2901  * @return
2902  *   A new pool pointer on success, NULL otherwise and rte_errno is set.
2903  */
2904 static struct mlx5_flow_counter_pool *
2905 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
2906                     uint32_t batch)
2907 {
2908         struct mlx5_priv *priv = dev->data->dev_private;
2909         struct mlx5_flow_counter_pool *pool;
2910         struct mlx5_pools_container *cont = MLX5_CNT_CONTAINER(priv->sh, batch,
2911                                                                0);
2912         int16_t n_valid = rte_atomic16_read(&cont->n_valid);
2913         uint32_t size;
2914
2915         if (cont->n == n_valid) {
2916                 cont = flow_dv_container_resize(dev, batch);
2917                 if (!cont)
2918                         return NULL;
2919         }
2920         size = sizeof(*pool) + MLX5_COUNTERS_PER_POOL *
2921                         sizeof(struct mlx5_flow_counter);
2922         pool = rte_calloc(__func__, 1, size, 0);
2923         if (!pool) {
2924                 rte_errno = ENOMEM;
2925                 return NULL;
2926         }
2927         pool->min_dcs = dcs;
2928         pool->raw = cont->init_mem_mng->raws + n_valid %
2929                                                      MLX5_CNT_CONTAINER_RESIZE;
2930         pool->raw_hw = NULL;
2931         rte_spinlock_init(&pool->sl);
2932         /*
2933          * The generation of the new allocated counters in this pool is 0, 2 in
2934          * the pool generation makes all the counters valid for allocation.
2935          */
2936         rte_atomic64_set(&pool->query_gen, 0x2);
2937         TAILQ_INIT(&pool->counters);
2938         TAILQ_INSERT_TAIL(&cont->pool_list, pool, next);
2939         cont->pools[n_valid] = pool;
2940         /* Pool initialization must be updated before host thread access. */
2941         rte_cio_wmb();
2942         rte_atomic16_add(&cont->n_valid, 1);
2943         return pool;
2944 }
2945
2946 /**
2947  * Prepare a new counter and/or a new counter pool.
2948  *
2949  * @param[in] dev
2950  *   Pointer to the Ethernet device structure.
2951  * @param[out] cnt_free
2952  *   Where to put the pointer of a new counter.
2953  * @param[in] batch
2954  *   Whether the pool is for counter that was allocated by batch command.
2955  *
2956  * @return
2957  *   The free counter pool pointer and @p cnt_free is set on success,
2958  *   NULL otherwise and rte_errno is set.
2959  */
2960 static struct mlx5_flow_counter_pool *
2961 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev,
2962                              struct mlx5_flow_counter **cnt_free,
2963                              uint32_t batch)
2964 {
2965         struct mlx5_priv *priv = dev->data->dev_private;
2966         struct mlx5_flow_counter_pool *pool;
2967         struct mlx5_devx_obj *dcs = NULL;
2968         struct mlx5_flow_counter *cnt;
2969         uint32_t i;
2970
2971         if (!batch) {
2972                 /* bulk_bitmap must be 0 for single counter allocation. */
2973                 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
2974                 if (!dcs)
2975                         return NULL;
2976                 pool = flow_dv_find_pool_by_id
2977                         (MLX5_CNT_CONTAINER(priv->sh, batch, 0), dcs->id);
2978                 if (!pool) {
2979                         pool = flow_dv_pool_create(dev, dcs, batch);
2980                         if (!pool) {
2981                                 mlx5_devx_cmd_destroy(dcs);
2982                                 return NULL;
2983                         }
2984                 } else if (dcs->id < pool->min_dcs->id) {
2985                         rte_atomic64_set(&pool->a64_dcs,
2986                                          (int64_t)(uintptr_t)dcs);
2987                 }
2988                 cnt = &pool->counters_raw[dcs->id % MLX5_COUNTERS_PER_POOL];
2989                 TAILQ_INSERT_HEAD(&pool->counters, cnt, next);
2990                 cnt->dcs = dcs;
2991                 *cnt_free = cnt;
2992                 return pool;
2993         }
2994         /* bulk_bitmap is in 128 counters units. */
2995         if (priv->config.hca_attr.flow_counter_bulk_alloc_bitmap & 0x4)
2996                 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4);
2997         if (!dcs) {
2998                 rte_errno = ENODATA;
2999                 return NULL;
3000         }
3001         pool = flow_dv_pool_create(dev, dcs, batch);
3002         if (!pool) {
3003                 mlx5_devx_cmd_destroy(dcs);
3004                 return NULL;
3005         }
3006         for (i = 0; i < MLX5_COUNTERS_PER_POOL; ++i) {
3007                 cnt = &pool->counters_raw[i];
3008                 cnt->pool = pool;
3009                 TAILQ_INSERT_HEAD(&pool->counters, cnt, next);
3010         }
3011         *cnt_free = &pool->counters_raw[0];
3012         return pool;
3013 }
3014
3015 /**
3016  * Search for existed shared counter.
3017  *
3018  * @param[in] cont
3019  *   Pointer to the relevant counter pool container.
3020  * @param[in] id
3021  *   The shared counter ID to search.
3022  *
3023  * @return
3024  *   NULL if not existed, otherwise pointer to the shared counter.
3025  */
3026 static struct mlx5_flow_counter *
3027 flow_dv_counter_shared_search(struct mlx5_pools_container *cont,
3028                               uint32_t id)
3029 {
3030         static struct mlx5_flow_counter *cnt;
3031         struct mlx5_flow_counter_pool *pool;
3032         int i;
3033
3034         TAILQ_FOREACH(pool, &cont->pool_list, next) {
3035                 for (i = 0; i < MLX5_COUNTERS_PER_POOL; ++i) {
3036                         cnt = &pool->counters_raw[i];
3037                         if (cnt->ref_cnt && cnt->shared && cnt->id == id)
3038                                 return cnt;
3039                 }
3040         }
3041         return NULL;
3042 }
3043
3044 /**
3045  * Allocate a flow counter.
3046  *
3047  * @param[in] dev
3048  *   Pointer to the Ethernet device structure.
3049  * @param[in] shared
3050  *   Indicate if this counter is shared with other flows.
3051  * @param[in] id
3052  *   Counter identifier.
3053  * @param[in] group
3054  *   Counter flow group.
3055  *
3056  * @return
3057  *   pointer to flow counter on success, NULL otherwise and rte_errno is set.
3058  */
3059 static struct mlx5_flow_counter *
3060 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t shared, uint32_t id,
3061                       uint16_t group)
3062 {
3063         struct mlx5_priv *priv = dev->data->dev_private;
3064         struct mlx5_flow_counter_pool *pool = NULL;
3065         struct mlx5_flow_counter *cnt_free = NULL;
3066         /*
3067          * Currently group 0 flow counter cannot be assigned to a flow if it is
3068          * not the first one in the batch counter allocation, so it is better
3069          * to allocate counters one by one for these flows in a separate
3070          * container.
3071          * A counter can be shared between different groups so need to take
3072          * shared counters from the single container.
3073          */
3074         uint32_t batch = (group && !shared) ? 1 : 0;
3075         struct mlx5_pools_container *cont = MLX5_CNT_CONTAINER(priv->sh, batch,
3076                                                                0);
3077
3078         if (priv->counter_fallback)
3079                 return flow_dv_counter_alloc_fallback(dev, shared, id);
3080         if (!priv->config.devx) {
3081                 rte_errno = ENOTSUP;
3082                 return NULL;
3083         }
3084         if (shared) {
3085                 cnt_free = flow_dv_counter_shared_search(cont, id);
3086                 if (cnt_free) {
3087                         if (cnt_free->ref_cnt + 1 == 0) {
3088                                 rte_errno = E2BIG;
3089                                 return NULL;
3090                         }
3091                         cnt_free->ref_cnt++;
3092                         return cnt_free;
3093                 }
3094         }
3095         /* Pools which has a free counters are in the start. */
3096         TAILQ_FOREACH(pool, &cont->pool_list, next) {
3097                 /*
3098                  * The free counter reset values must be updated between the
3099                  * counter release to the counter allocation, so, at least one
3100                  * query must be done in this time. ensure it by saving the
3101                  * query generation in the release time.
3102                  * The free list is sorted according to the generation - so if
3103                  * the first one is not updated, all the others are not
3104                  * updated too.
3105                  */
3106                 cnt_free = TAILQ_FIRST(&pool->counters);
3107                 if (cnt_free && cnt_free->query_gen + 1 <
3108                     rte_atomic64_read(&pool->query_gen))
3109                         break;
3110                 cnt_free = NULL;
3111         }
3112         if (!cnt_free) {
3113                 pool = flow_dv_counter_pool_prepare(dev, &cnt_free, batch);
3114                 if (!pool)
3115                         return NULL;
3116         }
3117         cnt_free->batch = batch;
3118         /* Create a DV counter action only in the first time usage. */
3119         if (!cnt_free->action) {
3120                 uint16_t offset;
3121                 struct mlx5_devx_obj *dcs;
3122
3123                 if (batch) {
3124                         offset = cnt_free - &pool->counters_raw[0];
3125                         dcs = pool->min_dcs;
3126                 } else {
3127                         offset = 0;
3128                         dcs = cnt_free->dcs;
3129                 }
3130                 cnt_free->action = mlx5_glue->dv_create_flow_action_counter
3131                                         (dcs->obj, offset);
3132                 if (!cnt_free->action) {
3133                         rte_errno = errno;
3134                         return NULL;
3135                 }
3136         }
3137         /* Update the counter reset values. */
3138         if (_flow_dv_query_count(dev, cnt_free, &cnt_free->hits,
3139                                  &cnt_free->bytes))
3140                 return NULL;
3141         cnt_free->shared = shared;
3142         cnt_free->ref_cnt = 1;
3143         cnt_free->id = id;
3144         if (!priv->sh->cmng.query_thread_on)
3145                 /* Start the asynchronous batch query by the host thread. */
3146                 mlx5_set_query_alarm(priv->sh);
3147         TAILQ_REMOVE(&pool->counters, cnt_free, next);
3148         if (TAILQ_EMPTY(&pool->counters)) {
3149                 /* Move the pool to the end of the container pool list. */
3150                 TAILQ_REMOVE(&cont->pool_list, pool, next);
3151                 TAILQ_INSERT_TAIL(&cont->pool_list, pool, next);
3152         }
3153         return cnt_free;
3154 }
3155
3156 /**
3157  * Release a flow counter.
3158  *
3159  * @param[in] dev
3160  *   Pointer to the Ethernet device structure.
3161  * @param[in] counter
3162  *   Pointer to the counter handler.
3163  */
3164 static void
3165 flow_dv_counter_release(struct rte_eth_dev *dev,
3166                         struct mlx5_flow_counter *counter)
3167 {
3168         struct mlx5_priv *priv = dev->data->dev_private;
3169
3170         if (!counter)
3171                 return;
3172         if (priv->counter_fallback) {
3173                 flow_dv_counter_release_fallback(dev, counter);
3174                 return;
3175         }
3176         if (--counter->ref_cnt == 0) {
3177                 struct mlx5_flow_counter_pool *pool =
3178                                 flow_dv_counter_pool_get(counter);
3179
3180                 /* Put the counter in the end - the last updated one. */
3181                 TAILQ_INSERT_TAIL(&pool->counters, counter, next);
3182                 counter->query_gen = rte_atomic64_read(&pool->query_gen);
3183         }
3184 }
3185
3186 /**
3187  * Verify the @p attributes will be correctly understood by the NIC and store
3188  * them in the @p flow if everything is correct.
3189  *
3190  * @param[in] dev
3191  *   Pointer to dev struct.
3192  * @param[in] attributes
3193  *   Pointer to flow attributes
3194  * @param[in] external
3195  *   This flow rule is created by request external to PMD.
3196  * @param[out] error
3197  *   Pointer to error structure.
3198  *
3199  * @return
3200  *   0 on success, a negative errno value otherwise and rte_errno is set.
3201  */
3202 static int
3203 flow_dv_validate_attributes(struct rte_eth_dev *dev,
3204                             const struct rte_flow_attr *attributes,
3205                             bool external __rte_unused,
3206                             struct rte_flow_error *error)
3207 {
3208         struct mlx5_priv *priv = dev->data->dev_private;
3209         uint32_t priority_max = priv->config.flow_prio - 1;
3210
3211 #ifndef HAVE_MLX5DV_DR
3212         if (attributes->group)
3213                 return rte_flow_error_set(error, ENOTSUP,
3214                                           RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
3215                                           NULL,
3216                                           "groups are not supported");
3217 #else
3218         uint32_t max_group = attributes->transfer ? MLX5_MAX_TABLES_FDB :
3219                                                     MLX5_MAX_TABLES;
3220         uint32_t table;
3221         int ret;
3222
3223         ret = mlx5_flow_group_to_table(attributes, external,
3224                                        attributes->group,
3225                                        &table, error);
3226         if (ret)
3227                 return ret;
3228         if (table >= max_group)
3229                 return rte_flow_error_set(error, EINVAL,
3230                                           RTE_FLOW_ERROR_TYPE_ATTR_GROUP, NULL,
3231                                           "group index out of range");
3232 #endif
3233         if (attributes->priority != MLX5_FLOW_PRIO_RSVD &&
3234             attributes->priority >= priority_max)
3235                 return rte_flow_error_set(error, ENOTSUP,
3236                                           RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
3237                                           NULL,
3238                                           "priority out of range");
3239         if (attributes->transfer) {
3240                 if (!priv->config.dv_esw_en)
3241                         return rte_flow_error_set
3242                                 (error, ENOTSUP,
3243                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3244                                  "E-Switch dr is not supported");
3245                 if (!(priv->representor || priv->master))
3246                         return rte_flow_error_set
3247                                 (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3248                                  NULL, "E-Switch configuration can only be"
3249                                  " done by a master or a representor device");
3250                 if (attributes->egress)
3251                         return rte_flow_error_set
3252                                 (error, ENOTSUP,
3253                                  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes,
3254                                  "egress is not supported");
3255         }
3256         if (!(attributes->egress ^ attributes->ingress))
3257                 return rte_flow_error_set(error, ENOTSUP,
3258                                           RTE_FLOW_ERROR_TYPE_ATTR, NULL,
3259                                           "must specify exactly one of "
3260                                           "ingress or egress");
3261         return 0;
3262 }
3263
3264 /**
3265  * Internal validation function. For validating both actions and items.
3266  *
3267  * @param[in] dev
3268  *   Pointer to the rte_eth_dev structure.
3269  * @param[in] attr
3270  *   Pointer to the flow attributes.
3271  * @param[in] items
3272  *   Pointer to the list of items.
3273  * @param[in] actions
3274  *   Pointer to the list of actions.
3275  * @param[in] external
3276  *   This flow rule is created by request external to PMD.
3277  * @param[out] error
3278  *   Pointer to the error structure.
3279  *
3280  * @return
3281  *   0 on success, a negative errno value otherwise and rte_errno is set.
3282  */
3283 static int
3284 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
3285                  const struct rte_flow_item items[],
3286                  const struct rte_flow_action actions[],
3287                  bool external, struct rte_flow_error *error)
3288 {
3289         int ret;
3290         uint64_t action_flags = 0;
3291         uint64_t item_flags = 0;
3292         uint64_t last_item = 0;
3293         uint8_t next_protocol = 0xff;
3294         int actions_n = 0;
3295         const struct rte_flow_item *gre_item = NULL;
3296         struct rte_flow_item_tcp nic_tcp_mask = {
3297                 .hdr = {
3298                         .tcp_flags = 0xFF,
3299                         .src_port = RTE_BE16(UINT16_MAX),
3300                         .dst_port = RTE_BE16(UINT16_MAX),
3301                 }
3302         };
3303
3304         if (items == NULL)
3305                 return -1;
3306         ret = flow_dv_validate_attributes(dev, attr, external, error);
3307         if (ret < 0)
3308                 return ret;
3309         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
3310                 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
3311                 switch (items->type) {
3312                 case RTE_FLOW_ITEM_TYPE_VOID:
3313                         break;
3314                 case RTE_FLOW_ITEM_TYPE_PORT_ID:
3315                         ret = flow_dv_validate_item_port_id
3316                                         (dev, items, attr, item_flags, error);
3317                         if (ret < 0)
3318                                 return ret;
3319                         last_item = MLX5_FLOW_ITEM_PORT_ID;
3320                         break;
3321                 case RTE_FLOW_ITEM_TYPE_ETH:
3322                         ret = mlx5_flow_validate_item_eth(items, item_flags,
3323                                                           error);
3324                         if (ret < 0)
3325                                 return ret;
3326                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
3327                                              MLX5_FLOW_LAYER_OUTER_L2;
3328                         break;
3329                 case RTE_FLOW_ITEM_TYPE_VLAN:
3330                         ret = mlx5_flow_validate_item_vlan(items, item_flags,
3331                                                            dev, error);
3332                         if (ret < 0)
3333                                 return ret;
3334                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
3335                                              MLX5_FLOW_LAYER_OUTER_VLAN;
3336                         break;
3337                 case RTE_FLOW_ITEM_TYPE_IPV4:
3338                         mlx5_flow_tunnel_ip_check(items, next_protocol,
3339                                                   &item_flags, &tunnel);
3340                         ret = mlx5_flow_validate_item_ipv4(items, item_flags,
3341                                                            NULL, error);
3342                         if (ret < 0)
3343                                 return ret;
3344                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
3345                                              MLX5_FLOW_LAYER_OUTER_L3_IPV4;
3346                         if (items->mask != NULL &&
3347                             ((const struct rte_flow_item_ipv4 *)
3348                              items->mask)->hdr.next_proto_id) {
3349                                 next_protocol =
3350                                         ((const struct rte_flow_item_ipv4 *)
3351                                          (items->spec))->hdr.next_proto_id;
3352                                 next_protocol &=
3353                                         ((const struct rte_flow_item_ipv4 *)
3354                                          (items->mask))->hdr.next_proto_id;
3355                         } else {
3356                                 /* Reset for inner layer. */
3357                                 next_protocol = 0xff;
3358                         }
3359                         break;
3360                 case RTE_FLOW_ITEM_TYPE_IPV6:
3361                         mlx5_flow_tunnel_ip_check(items, next_protocol,
3362                                                   &item_flags, &tunnel);
3363                         ret = mlx5_flow_validate_item_ipv6(items, item_flags,
3364                                                            NULL, error);
3365                         if (ret < 0)
3366                                 return ret;
3367                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
3368                                              MLX5_FLOW_LAYER_OUTER_L3_IPV6;
3369                         if (items->mask != NULL &&
3370                             ((const struct rte_flow_item_ipv6 *)
3371                              items->mask)->hdr.proto) {
3372                                 next_protocol =
3373                                         ((const struct rte_flow_item_ipv6 *)
3374                                          items->spec)->hdr.proto;
3375                                 next_protocol &=
3376                                         ((const struct rte_flow_item_ipv6 *)
3377                                          items->mask)->hdr.proto;
3378                         } else {
3379                                 /* Reset for inner layer. */
3380                                 next_protocol = 0xff;
3381                         }
3382                         break;
3383                 case RTE_FLOW_ITEM_TYPE_TCP:
3384                         ret = mlx5_flow_validate_item_tcp
3385                                                 (items, item_flags,
3386                                                  next_protocol,
3387                                                  &nic_tcp_mask,
3388                                                  error);
3389                         if (ret < 0)
3390                                 return ret;
3391                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
3392                                              MLX5_FLOW_LAYER_OUTER_L4_TCP;
3393                         break;
3394                 case RTE_FLOW_ITEM_TYPE_UDP:
3395                         ret = mlx5_flow_validate_item_udp(items, item_flags,
3396                                                           next_protocol,
3397                                                           error);
3398                         if (ret < 0)
3399                                 return ret;
3400                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
3401                                              MLX5_FLOW_LAYER_OUTER_L4_UDP;
3402                         break;
3403                 case RTE_FLOW_ITEM_TYPE_GRE:
3404                         ret = mlx5_flow_validate_item_gre(items, item_flags,
3405                                                           next_protocol, error);
3406                         if (ret < 0)
3407                                 return ret;
3408                         gre_item = items;
3409                         last_item = MLX5_FLOW_LAYER_GRE;
3410                         break;
3411                 case RTE_FLOW_ITEM_TYPE_NVGRE:
3412                         ret = mlx5_flow_validate_item_nvgre(items, item_flags,
3413                                                             next_protocol,
3414                                                             error);
3415                         if (ret < 0)
3416                                 return ret;
3417                         last_item = MLX5_FLOW_LAYER_NVGRE;
3418                         break;
3419                 case RTE_FLOW_ITEM_TYPE_GRE_KEY:
3420                         ret = mlx5_flow_validate_item_gre_key
3421                                 (items, item_flags, gre_item, error);
3422                         if (ret < 0)
3423                                 return ret;
3424                         last_item = MLX5_FLOW_LAYER_GRE_KEY;
3425                         break;
3426                 case RTE_FLOW_ITEM_TYPE_VXLAN:
3427                         ret = mlx5_flow_validate_item_vxlan(items, item_flags,
3428                                                             error);
3429                         if (ret < 0)
3430                                 return ret;
3431                         last_item = MLX5_FLOW_LAYER_VXLAN;
3432                         break;
3433                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
3434                         ret = mlx5_flow_validate_item_vxlan_gpe(items,
3435                                                                 item_flags, dev,
3436                                                                 error);
3437                         if (ret < 0)
3438                                 return ret;
3439                         last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
3440                         break;
3441                 case RTE_FLOW_ITEM_TYPE_MPLS:
3442                         ret = mlx5_flow_validate_item_mpls(dev, items,
3443                                                            item_flags,
3444                                                            last_item, error);
3445                         if (ret < 0)
3446                                 return ret;
3447                         last_item = MLX5_FLOW_LAYER_MPLS;
3448                         break;
3449                 case RTE_FLOW_ITEM_TYPE_META:
3450                         ret = flow_dv_validate_item_meta(dev, items, attr,
3451                                                          error);
3452                         if (ret < 0)
3453                                 return ret;
3454                         last_item = MLX5_FLOW_ITEM_METADATA;
3455                         break;
3456                 case RTE_FLOW_ITEM_TYPE_ICMP:
3457                         ret = mlx5_flow_validate_item_icmp(items, item_flags,
3458                                                            next_protocol,
3459                                                            error);
3460                         if (ret < 0)
3461                                 return ret;
3462                         last_item = MLX5_FLOW_LAYER_ICMP;
3463                         break;
3464                 case RTE_FLOW_ITEM_TYPE_ICMP6:
3465                         ret = mlx5_flow_validate_item_icmp6(items, item_flags,
3466                                                             next_protocol,
3467                                                             error);
3468                         if (ret < 0)
3469                                 return ret;
3470                         last_item = MLX5_FLOW_LAYER_ICMP6;
3471                         break;
3472                 default:
3473                         return rte_flow_error_set(error, ENOTSUP,
3474                                                   RTE_FLOW_ERROR_TYPE_ITEM,
3475                                                   NULL, "item not supported");
3476                 }
3477                 item_flags |= last_item;
3478         }
3479         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
3480                 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
3481                         return rte_flow_error_set(error, ENOTSUP,
3482                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3483                                                   actions, "too many actions");
3484                 switch (actions->type) {
3485                 case RTE_FLOW_ACTION_TYPE_VOID:
3486                         break;
3487                 case RTE_FLOW_ACTION_TYPE_PORT_ID:
3488                         ret = flow_dv_validate_action_port_id(dev,
3489                                                               action_flags,
3490                                                               actions,
3491                                                               attr,
3492                                                               error);
3493                         if (ret)
3494                                 return ret;
3495                         action_flags |= MLX5_FLOW_ACTION_PORT_ID;
3496                         ++actions_n;
3497                         break;
3498                 case RTE_FLOW_ACTION_TYPE_FLAG:
3499                         ret = mlx5_flow_validate_action_flag(action_flags,
3500                                                              attr, error);
3501                         if (ret < 0)
3502                                 return ret;
3503                         action_flags |= MLX5_FLOW_ACTION_FLAG;
3504                         ++actions_n;
3505                         break;
3506                 case RTE_FLOW_ACTION_TYPE_MARK:
3507                         ret = mlx5_flow_validate_action_mark(actions,
3508                                                              action_flags,
3509                                                              attr, error);
3510                         if (ret < 0)
3511                                 return ret;
3512                         action_flags |= MLX5_FLOW_ACTION_MARK;
3513                         ++actions_n;
3514                         break;
3515                 case RTE_FLOW_ACTION_TYPE_DROP:
3516                         ret = mlx5_flow_validate_action_drop(action_flags,
3517                                                              attr, error);
3518                         if (ret < 0)
3519                                 return ret;
3520                         action_flags |= MLX5_FLOW_ACTION_DROP;
3521                         ++actions_n;
3522                         break;
3523                 case RTE_FLOW_ACTION_TYPE_QUEUE:
3524                         ret = mlx5_flow_validate_action_queue(actions,
3525                                                               action_flags, dev,
3526                                                               attr, error);
3527                         if (ret < 0)
3528                                 return ret;
3529                         action_flags |= MLX5_FLOW_ACTION_QUEUE;
3530                         ++actions_n;
3531                         break;
3532                 case RTE_FLOW_ACTION_TYPE_RSS:
3533                         ret = mlx5_flow_validate_action_rss(actions,
3534                                                             action_flags, dev,
3535                                                             attr, item_flags,
3536                                                             error);
3537                         if (ret < 0)
3538                                 return ret;
3539                         action_flags |= MLX5_FLOW_ACTION_RSS;
3540                         ++actions_n;
3541                         break;
3542                 case RTE_FLOW_ACTION_TYPE_COUNT:
3543                         ret = flow_dv_validate_action_count(dev, error);
3544                         if (ret < 0)
3545                                 return ret;
3546                         action_flags |= MLX5_FLOW_ACTION_COUNT;
3547                         ++actions_n;
3548                         break;
3549                 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
3550                         if (flow_dv_validate_action_pop_vlan(dev,
3551                                                              action_flags,
3552                                                              actions,
3553                                                              item_flags, attr,
3554                                                              error))
3555                                 return -rte_errno;
3556                         action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
3557                         ++actions_n;
3558                         break;
3559                 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
3560                         ret = flow_dv_validate_action_push_vlan(action_flags,
3561                                                                 actions, attr,
3562                                                                 error);
3563                         if (ret < 0)
3564                                 return ret;
3565                         action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
3566                         ++actions_n;
3567                         break;
3568                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
3569                         ret = flow_dv_validate_action_set_vlan_pcp
3570                                                 (action_flags, actions, error);
3571                         if (ret < 0)
3572                                 return ret;
3573                         /* Count PCP with push_vlan command. */
3574                         break;
3575                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
3576                         ret = flow_dv_validate_action_set_vlan_vid
3577                                                 (item_flags, actions, error);
3578                         if (ret < 0)
3579                                 return ret;
3580                         /* Count VID with push_vlan command. */
3581                         break;
3582                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
3583                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
3584                         ret = flow_dv_validate_action_l2_encap(action_flags,
3585                                                                actions, attr,
3586                                                                error);
3587                         if (ret < 0)
3588                                 return ret;
3589                         action_flags |= actions->type ==
3590                                         RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP ?
3591                                         MLX5_FLOW_ACTION_VXLAN_ENCAP :
3592                                         MLX5_FLOW_ACTION_NVGRE_ENCAP;
3593                         ++actions_n;
3594                         break;
3595                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
3596                 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
3597                         ret = flow_dv_validate_action_l2_decap(action_flags,
3598                                                                attr, error);
3599                         if (ret < 0)
3600                                 return ret;
3601                         action_flags |= actions->type ==
3602                                         RTE_FLOW_ACTION_TYPE_VXLAN_DECAP ?
3603                                         MLX5_FLOW_ACTION_VXLAN_DECAP :
3604                                         MLX5_FLOW_ACTION_NVGRE_DECAP;
3605                         ++actions_n;
3606                         break;
3607                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
3608                         ret = flow_dv_validate_action_raw_encap(action_flags,
3609                                                                 actions, attr,
3610                                                                 error);
3611                         if (ret < 0)
3612                                 return ret;
3613                         action_flags |= MLX5_FLOW_ACTION_RAW_ENCAP;
3614                         ++actions_n;
3615                         break;
3616                 case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
3617                         ret = flow_dv_validate_action_raw_decap(action_flags,
3618                                                                 actions, attr,
3619                                                                 error);
3620                         if (ret < 0)
3621                                 return ret;
3622                         action_flags |= MLX5_FLOW_ACTION_RAW_DECAP;
3623                         ++actions_n;
3624                         break;
3625                 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
3626                 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
3627                         ret = flow_dv_validate_action_modify_mac(action_flags,
3628                                                                  actions,
3629                                                                  item_flags,
3630                                                                  error);
3631                         if (ret < 0)
3632                                 return ret;
3633                         /* Count all modify-header actions as one action. */
3634                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3635                                 ++actions_n;
3636                         action_flags |= actions->type ==
3637                                         RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
3638                                                 MLX5_FLOW_ACTION_SET_MAC_SRC :
3639                                                 MLX5_FLOW_ACTION_SET_MAC_DST;
3640                         break;
3641
3642                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
3643                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
3644                         ret = flow_dv_validate_action_modify_ipv4(action_flags,
3645                                                                   actions,
3646                                                                   item_flags,
3647                                                                   error);
3648                         if (ret < 0)
3649                                 return ret;
3650                         /* Count all modify-header actions as one action. */
3651                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3652                                 ++actions_n;
3653                         action_flags |= actions->type ==
3654                                         RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
3655                                                 MLX5_FLOW_ACTION_SET_IPV4_SRC :
3656                                                 MLX5_FLOW_ACTION_SET_IPV4_DST;
3657                         break;
3658                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
3659                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
3660                         ret = flow_dv_validate_action_modify_ipv6(action_flags,
3661                                                                   actions,
3662                                                                   item_flags,
3663                                                                   error);
3664                         if (ret < 0)
3665                                 return ret;
3666                         /* Count all modify-header actions as one action. */
3667                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3668                                 ++actions_n;
3669                         action_flags |= actions->type ==
3670                                         RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
3671                                                 MLX5_FLOW_ACTION_SET_IPV6_SRC :
3672                                                 MLX5_FLOW_ACTION_SET_IPV6_DST;
3673                         break;
3674                 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
3675                 case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
3676                         ret = flow_dv_validate_action_modify_tp(action_flags,
3677                                                                 actions,
3678                                                                 item_flags,
3679                                                                 error);
3680                         if (ret < 0)
3681                                 return ret;
3682                         /* Count all modify-header actions as one action. */
3683                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3684                                 ++actions_n;
3685                         action_flags |= actions->type ==
3686                                         RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
3687                                                 MLX5_FLOW_ACTION_SET_TP_SRC :
3688                                                 MLX5_FLOW_ACTION_SET_TP_DST;
3689                         break;
3690                 case RTE_FLOW_ACTION_TYPE_DEC_TTL:
3691                 case RTE_FLOW_ACTION_TYPE_SET_TTL:
3692                         ret = flow_dv_validate_action_modify_ttl(action_flags,
3693                                                                  actions,
3694                                                                  item_flags,
3695                                                                  error);
3696                         if (ret < 0)
3697                                 return ret;
3698                         /* Count all modify-header actions as one action. */
3699                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3700                                 ++actions_n;
3701                         action_flags |= actions->type ==
3702                                         RTE_FLOW_ACTION_TYPE_SET_TTL ?
3703                                                 MLX5_FLOW_ACTION_SET_TTL :
3704                                                 MLX5_FLOW_ACTION_DEC_TTL;
3705                         break;
3706                 case RTE_FLOW_ACTION_TYPE_JUMP:
3707                         ret = flow_dv_validate_action_jump(actions,
3708                                                            action_flags,
3709                                                            attr, external,
3710                                                            error);
3711                         if (ret)
3712                                 return ret;
3713                         ++actions_n;
3714                         action_flags |= MLX5_FLOW_ACTION_JUMP;
3715                         break;
3716                 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
3717                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
3718                         ret = flow_dv_validate_action_modify_tcp_seq
3719                                                                 (action_flags,
3720                                                                  actions,
3721                                                                  item_flags,
3722                                                                  error);
3723                         if (ret < 0)
3724                                 return ret;
3725                         /* Count all modify-header actions as one action. */
3726                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3727                                 ++actions_n;
3728                         action_flags |= actions->type ==
3729                                         RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
3730                                                 MLX5_FLOW_ACTION_INC_TCP_SEQ :
3731                                                 MLX5_FLOW_ACTION_DEC_TCP_SEQ;
3732                         break;
3733                 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
3734                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
3735                         ret = flow_dv_validate_action_modify_tcp_ack
3736                                                                 (action_flags,
3737                                                                  actions,
3738                                                                  item_flags,
3739                                                                  error);
3740                         if (ret < 0)
3741                                 return ret;
3742                         /* Count all modify-header actions as one action. */
3743                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3744                                 ++actions_n;
3745                         action_flags |= actions->type ==
3746                                         RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
3747                                                 MLX5_FLOW_ACTION_INC_TCP_ACK :
3748                                                 MLX5_FLOW_ACTION_DEC_TCP_ACK;
3749                         break;
3750                 default:
3751                         return rte_flow_error_set(error, ENOTSUP,
3752                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3753                                                   actions,
3754                                                   "action not supported");
3755                 }
3756         }
3757         if ((action_flags & MLX5_FLOW_LAYER_TUNNEL) &&
3758             (action_flags & MLX5_FLOW_VLAN_ACTIONS))
3759                 return rte_flow_error_set(error, ENOTSUP,
3760                                           RTE_FLOW_ERROR_TYPE_ACTION,
3761                                           actions,
3762                                           "can't have vxlan and vlan"
3763                                           " actions in the same rule");
3764         /* Eswitch has few restrictions on using items and actions */
3765         if (attr->transfer) {
3766                 if (action_flags & MLX5_FLOW_ACTION_FLAG)
3767                         return rte_flow_error_set(error, ENOTSUP,
3768                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3769                                                   NULL,
3770                                                   "unsupported action FLAG");
3771                 if (action_flags & MLX5_FLOW_ACTION_MARK)
3772                         return rte_flow_error_set(error, ENOTSUP,
3773                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3774                                                   NULL,
3775                                                   "unsupported action MARK");
3776                 if (action_flags & MLX5_FLOW_ACTION_QUEUE)
3777                         return rte_flow_error_set(error, ENOTSUP,
3778                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3779                                                   NULL,
3780                                                   "unsupported action QUEUE");
3781                 if (action_flags & MLX5_FLOW_ACTION_RSS)
3782                         return rte_flow_error_set(error, ENOTSUP,
3783                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3784                                                   NULL,
3785                                                   "unsupported action RSS");
3786                 if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
3787                         return rte_flow_error_set(error, EINVAL,
3788                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3789                                                   actions,
3790                                                   "no fate action is found");
3791         } else {
3792                 if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress)
3793                         return rte_flow_error_set(error, EINVAL,
3794                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3795                                                   actions,
3796                                                   "no fate action is found");
3797         }
3798         return 0;
3799 }
3800
3801 /**
3802  * Internal preparation function. Allocates the DV flow size,
3803  * this size is constant.
3804  *
3805  * @param[in] attr
3806  *   Pointer to the flow attributes.
3807  * @param[in] items
3808  *   Pointer to the list of items.
3809  * @param[in] actions
3810  *   Pointer to the list of actions.
3811  * @param[out] error
3812  *   Pointer to the error structure.
3813  *
3814  * @return
3815  *   Pointer to mlx5_flow object on success,
3816  *   otherwise NULL and rte_errno is set.
3817  */
3818 static struct mlx5_flow *
3819 flow_dv_prepare(const struct rte_flow_attr *attr __rte_unused,
3820                 const struct rte_flow_item items[] __rte_unused,
3821                 const struct rte_flow_action actions[] __rte_unused,
3822                 struct rte_flow_error *error)
3823 {
3824         uint32_t size = sizeof(struct mlx5_flow);
3825         struct mlx5_flow *flow;
3826
3827         flow = rte_calloc(__func__, 1, size, 0);
3828         if (!flow) {
3829                 rte_flow_error_set(error, ENOMEM,
3830                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3831                                    "not enough memory to create flow");
3832                 return NULL;
3833         }
3834         flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
3835         return flow;
3836 }
3837
3838 #ifndef NDEBUG
3839 /**
3840  * Sanity check for match mask and value. Similar to check_valid_spec() in
3841  * kernel driver. If unmasked bit is present in value, it returns failure.
3842  *
3843  * @param match_mask
3844  *   pointer to match mask buffer.
3845  * @param match_value
3846  *   pointer to match value buffer.
3847  *
3848  * @return
3849  *   0 if valid, -EINVAL otherwise.
3850  */
3851 static int
3852 flow_dv_check_valid_spec(void *match_mask, void *match_value)
3853 {
3854         uint8_t *m = match_mask;
3855         uint8_t *v = match_value;
3856         unsigned int i;
3857
3858         for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) {
3859                 if (v[i] & ~m[i]) {
3860                         DRV_LOG(ERR,
3861                                 "match_value differs from match_criteria"
3862                                 " %p[%u] != %p[%u]",
3863                                 match_value, i, match_mask, i);
3864                         return -EINVAL;
3865                 }
3866         }
3867         return 0;
3868 }
3869 #endif
3870
3871 /**
3872  * Add Ethernet item to matcher and to the value.
3873  *
3874  * @param[in, out] matcher
3875  *   Flow matcher.
3876  * @param[in, out] key
3877  *   Flow matcher value.
3878  * @param[in] item
3879  *   Flow pattern to translate.
3880  * @param[in] inner
3881  *   Item is inner pattern.
3882  */
3883 static void
3884 flow_dv_translate_item_eth(void *matcher, void *key,
3885                            const struct rte_flow_item *item, int inner)
3886 {
3887         const struct rte_flow_item_eth *eth_m = item->mask;
3888         const struct rte_flow_item_eth *eth_v = item->spec;
3889         const struct rte_flow_item_eth nic_mask = {
3890                 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
3891                 .src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
3892                 .type = RTE_BE16(0xffff),
3893         };
3894         void *headers_m;
3895         void *headers_v;
3896         char *l24_v;
3897         unsigned int i;
3898
3899         if (!eth_v)
3900                 return;
3901         if (!eth_m)
3902                 eth_m = &nic_mask;
3903         if (inner) {
3904                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3905                                          inner_headers);
3906                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
3907         } else {
3908                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3909                                          outer_headers);
3910                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
3911         }
3912         memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, dmac_47_16),
3913                &eth_m->dst, sizeof(eth_m->dst));
3914         /* The value must be in the range of the mask. */
3915         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, dmac_47_16);
3916         for (i = 0; i < sizeof(eth_m->dst); ++i)
3917                 l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i];
3918         memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, smac_47_16),
3919                &eth_m->src, sizeof(eth_m->src));
3920         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, smac_47_16);
3921         /* The value must be in the range of the mask. */
3922         for (i = 0; i < sizeof(eth_m->dst); ++i)
3923                 l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i];
3924         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype,
3925                  rte_be_to_cpu_16(eth_m->type));
3926         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, ethertype);
3927         *(uint16_t *)(l24_v) = eth_m->type & eth_v->type;
3928 }
3929
3930 /**
3931  * Add VLAN item to matcher and to the value.
3932  *
3933  * @param[in, out] dev_flow
3934  *   Flow descriptor.
3935  * @param[in, out] matcher
3936  *   Flow matcher.
3937  * @param[in, out] key
3938  *   Flow matcher value.
3939  * @param[in] item
3940  *   Flow pattern to translate.
3941  * @param[in] inner
3942  *   Item is inner pattern.
3943  */
3944 static void
3945 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow,
3946                             void *matcher, void *key,
3947                             const struct rte_flow_item *item,
3948                             int inner)
3949 {
3950         const struct rte_flow_item_vlan *vlan_m = item->mask;
3951         const struct rte_flow_item_vlan *vlan_v = item->spec;
3952         void *headers_m;
3953         void *headers_v;
3954         uint16_t tci_m;
3955         uint16_t tci_v;
3956
3957         if (!vlan_v)
3958                 return;
3959         if (!vlan_m)
3960                 vlan_m = &rte_flow_item_vlan_mask;
3961         if (inner) {
3962                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3963                                          inner_headers);
3964                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
3965         } else {
3966                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3967                                          outer_headers);
3968                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
3969                 /*
3970                  * This is workaround, masks are not supported,
3971                  * and pre-validated.
3972                  */
3973                 dev_flow->dv.vf_vlan.tag =
3974                         rte_be_to_cpu_16(vlan_v->tci) & 0x0fff;
3975         }
3976         tci_m = rte_be_to_cpu_16(vlan_m->tci);
3977         tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci);
3978         MLX5_SET(fte_match_set_lyr_2_4, headers_m, cvlan_tag, 1);
3979         MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1);
3980         MLX5_SET(fte_match_set_lyr_2_4, headers_m, first_vid, tci_m);
3981         MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, tci_v);
3982         MLX5_SET(fte_match_set_lyr_2_4, headers_m, first_cfi, tci_m >> 12);
3983         MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_cfi, tci_v >> 12);
3984         MLX5_SET(fte_match_set_lyr_2_4, headers_m, first_prio, tci_m >> 13);
3985         MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, tci_v >> 13);
3986         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype,
3987                  rte_be_to_cpu_16(vlan_m->inner_type));
3988         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
3989                  rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type));
3990 }
3991
3992 /**
3993  * Add IPV4 item to matcher and to the value.
3994  *
3995  * @param[in, out] matcher
3996  *   Flow matcher.
3997  * @param[in, out] key
3998  *   Flow matcher value.
3999  * @param[in] item
4000  *   Flow pattern to translate.
4001  * @param[in] inner
4002  *   Item is inner pattern.
4003  * @param[in] group
4004  *   The group to insert the rule.
4005  */
4006 static void
4007 flow_dv_translate_item_ipv4(void *matcher, void *key,
4008                             const struct rte_flow_item *item,
4009                             int inner, uint32_t group)
4010 {
4011         const struct rte_flow_item_ipv4 *ipv4_m = item->mask;
4012         const struct rte_flow_item_ipv4 *ipv4_v = item->spec;
4013         const struct rte_flow_item_ipv4 nic_mask = {
4014                 .hdr = {
4015                         .src_addr = RTE_BE32(0xffffffff),
4016                         .dst_addr = RTE_BE32(0xffffffff),
4017                         .type_of_service = 0xff,
4018                         .next_proto_id = 0xff,
4019                 },
4020         };
4021         void *headers_m;
4022         void *headers_v;
4023         char *l24_m;
4024         char *l24_v;
4025         uint8_t tos;
4026
4027         if (inner) {
4028                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4029                                          inner_headers);
4030                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4031         } else {
4032                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4033                                          outer_headers);
4034                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4035         }
4036         if (group == 0)
4037                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
4038         else
4039                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0x4);
4040         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, 4);
4041         if (!ipv4_v)
4042                 return;
4043         if (!ipv4_m)
4044                 ipv4_m = &nic_mask;
4045         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
4046                              dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
4047         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
4048                              dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
4049         *(uint32_t *)l24_m = ipv4_m->hdr.dst_addr;
4050         *(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr;
4051         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
4052                           src_ipv4_src_ipv6.ipv4_layout.ipv4);
4053         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
4054                           src_ipv4_src_ipv6.ipv4_layout.ipv4);
4055         *(uint32_t *)l24_m = ipv4_m->hdr.src_addr;
4056         *(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr;
4057         tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service;
4058         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn,
4059                  ipv4_m->hdr.type_of_service);
4060         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos);
4061         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp,
4062                  ipv4_m->hdr.type_of_service >> 2);
4063         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2);
4064         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
4065                  ipv4_m->hdr.next_proto_id);
4066         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
4067                  ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id);
4068 }
4069
4070 /**
4071  * Add IPV6 item to matcher and to the value.
4072  *
4073  * @param[in, out] matcher
4074  *   Flow matcher.
4075  * @param[in, out] key
4076  *   Flow matcher value.
4077  * @param[in] item
4078  *   Flow pattern to translate.
4079  * @param[in] inner
4080  *   Item is inner pattern.
4081  * @param[in] group
4082  *   The group to insert the rule.
4083  */
4084 static void
4085 flow_dv_translate_item_ipv6(void *matcher, void *key,
4086                             const struct rte_flow_item *item,
4087                             int inner, uint32_t group)
4088 {
4089         const struct rte_flow_item_ipv6 *ipv6_m = item->mask;
4090         const struct rte_flow_item_ipv6 *ipv6_v = item->spec;
4091         const struct rte_flow_item_ipv6 nic_mask = {
4092                 .hdr = {
4093                         .src_addr =
4094                                 "\xff\xff\xff\xff\xff\xff\xff\xff"
4095                                 "\xff\xff\xff\xff\xff\xff\xff\xff",
4096                         .dst_addr =
4097                                 "\xff\xff\xff\xff\xff\xff\xff\xff"
4098                                 "\xff\xff\xff\xff\xff\xff\xff\xff",
4099                         .vtc_flow = RTE_BE32(0xffffffff),
4100                         .proto = 0xff,
4101                         .hop_limits = 0xff,
4102                 },
4103         };
4104         void *headers_m;
4105         void *headers_v;
4106         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4107         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4108         char *l24_m;
4109         char *l24_v;
4110         uint32_t vtc_m;
4111         uint32_t vtc_v;
4112         int i;
4113         int size;
4114
4115         if (inner) {
4116                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4117                                          inner_headers);
4118                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4119         } else {
4120                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4121                                          outer_headers);
4122                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4123         }
4124         if (group == 0)
4125                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
4126         else
4127                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0x6);
4128         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, 6);
4129         if (!ipv6_v)
4130                 return;
4131         if (!ipv6_m)
4132                 ipv6_m = &nic_mask;
4133         size = sizeof(ipv6_m->hdr.dst_addr);
4134         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
4135                              dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
4136         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
4137                              dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
4138         memcpy(l24_m, ipv6_m->hdr.dst_addr, size);
4139         for (i = 0; i < size; ++i)
4140                 l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i];
4141         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
4142                              src_ipv4_src_ipv6.ipv6_layout.ipv6);
4143         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
4144                              src_ipv4_src_ipv6.ipv6_layout.ipv6);
4145         memcpy(l24_m, ipv6_m->hdr.src_addr, size);
4146         for (i = 0; i < size; ++i)
4147                 l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i];
4148         /* TOS. */
4149         vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow);
4150         vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow);
4151         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20);
4152         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20);
4153         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22);
4154         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22);
4155         /* Label. */
4156         if (inner) {
4157                 MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label,
4158                          vtc_m);
4159                 MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label,
4160                          vtc_v);
4161         } else {
4162                 MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label,
4163                          vtc_m);
4164                 MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label,
4165                          vtc_v);
4166         }
4167         /* Protocol. */
4168         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
4169                  ipv6_m->hdr.proto);
4170         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
4171                  ipv6_v->hdr.proto & ipv6_m->hdr.proto);
4172 }
4173
4174 /**
4175  * Add TCP item to matcher and to the value.
4176  *
4177  * @param[in, out] matcher
4178  *   Flow matcher.
4179  * @param[in, out] key
4180  *   Flow matcher value.
4181  * @param[in] item
4182  *   Flow pattern to translate.
4183  * @param[in] inner
4184  *   Item is inner pattern.
4185  */
4186 static void
4187 flow_dv_translate_item_tcp(void *matcher, void *key,
4188                            const struct rte_flow_item *item,
4189                            int inner)
4190 {
4191         const struct rte_flow_item_tcp *tcp_m = item->mask;
4192         const struct rte_flow_item_tcp *tcp_v = item->spec;
4193         void *headers_m;
4194         void *headers_v;
4195
4196         if (inner) {
4197                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4198                                          inner_headers);
4199                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4200         } else {
4201                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4202                                          outer_headers);
4203                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4204         }
4205         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
4206         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP);
4207         if (!tcp_v)
4208                 return;
4209         if (!tcp_m)
4210                 tcp_m = &rte_flow_item_tcp_mask;
4211         MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport,
4212                  rte_be_to_cpu_16(tcp_m->hdr.src_port));
4213         MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
4214                  rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port));
4215         MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport,
4216                  rte_be_to_cpu_16(tcp_m->hdr.dst_port));
4217         MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
4218                  rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port));
4219         MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags,
4220                  tcp_m->hdr.tcp_flags);
4221         MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
4222                  (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags));
4223 }
4224
4225 /**
4226  * Add UDP item to matcher and to the value.
4227  *
4228  * @param[in, out] matcher
4229  *   Flow matcher.
4230  * @param[in, out] key
4231  *   Flow matcher value.
4232  * @param[in] item
4233  *   Flow pattern to translate.
4234  * @param[in] inner
4235  *   Item is inner pattern.
4236  */
4237 static void
4238 flow_dv_translate_item_udp(void *matcher, void *key,
4239                            const struct rte_flow_item *item,
4240                            int inner)
4241 {
4242         const struct rte_flow_item_udp *udp_m = item->mask;
4243         const struct rte_flow_item_udp *udp_v = item->spec;
4244         void *headers_m;
4245         void *headers_v;
4246
4247         if (inner) {
4248                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4249                                          inner_headers);
4250                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4251         } else {
4252                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4253                                          outer_headers);
4254                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4255         }
4256         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
4257         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
4258         if (!udp_v)
4259                 return;
4260         if (!udp_m)
4261                 udp_m = &rte_flow_item_udp_mask;
4262         MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport,
4263                  rte_be_to_cpu_16(udp_m->hdr.src_port));
4264         MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
4265                  rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port));
4266         MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport,
4267                  rte_be_to_cpu_16(udp_m->hdr.dst_port));
4268         MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
4269                  rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port));
4270 }
4271
4272 /**
4273  * Add GRE optional Key item to matcher and to the value.
4274  *
4275  * @param[in, out] matcher
4276  *   Flow matcher.
4277  * @param[in, out] key
4278  *   Flow matcher value.
4279  * @param[in] item
4280  *   Flow pattern to translate.
4281  * @param[in] inner
4282  *   Item is inner pattern.
4283  */
4284 static void
4285 flow_dv_translate_item_gre_key(void *matcher, void *key,
4286                                    const struct rte_flow_item *item)
4287 {
4288         const rte_be32_t *key_m = item->mask;
4289         const rte_be32_t *key_v = item->spec;
4290         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4291         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4292         rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX);
4293
4294         if (!key_v)
4295                 return;
4296         if (!key_m)
4297                 key_m = &gre_key_default_mask;
4298         /* GRE K bit must be on and should already be validated */
4299         MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1);
4300         MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1);
4301         MLX5_SET(fte_match_set_misc, misc_m, gre_key_h,
4302                  rte_be_to_cpu_32(*key_m) >> 8);
4303         MLX5_SET(fte_match_set_misc, misc_v, gre_key_h,
4304                  rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8);
4305         MLX5_SET(fte_match_set_misc, misc_m, gre_key_l,
4306                  rte_be_to_cpu_32(*key_m) & 0xFF);
4307         MLX5_SET(fte_match_set_misc, misc_v, gre_key_l,
4308                  rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF);
4309 }
4310
4311 /**
4312  * Add GRE item to matcher and to the value.
4313  *
4314  * @param[in, out] matcher
4315  *   Flow matcher.
4316  * @param[in, out] key
4317  *   Flow matcher value.
4318  * @param[in] item
4319  *   Flow pattern to translate.
4320  * @param[in] inner
4321  *   Item is inner pattern.
4322  */
4323 static void
4324 flow_dv_translate_item_gre(void *matcher, void *key,
4325                            const struct rte_flow_item *item,
4326                            int inner)
4327 {
4328         const struct rte_flow_item_gre *gre_m = item->mask;
4329         const struct rte_flow_item_gre *gre_v = item->spec;
4330         void *headers_m;
4331         void *headers_v;
4332         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4333         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4334         struct {
4335                 union {
4336                         __extension__
4337                         struct {
4338                                 uint16_t version:3;
4339                                 uint16_t rsvd0:9;
4340                                 uint16_t s_present:1;
4341                                 uint16_t k_present:1;
4342                                 uint16_t rsvd_bit1:1;
4343                                 uint16_t c_present:1;
4344                         };
4345                         uint16_t value;
4346                 };
4347         } gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v;
4348
4349         if (inner) {
4350                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4351                                          inner_headers);
4352                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4353         } else {
4354                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4355                                          outer_headers);
4356                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4357         }
4358         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
4359         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
4360         if (!gre_v)
4361                 return;
4362         if (!gre_m)
4363                 gre_m = &rte_flow_item_gre_mask;
4364         MLX5_SET(fte_match_set_misc, misc_m, gre_protocol,
4365                  rte_be_to_cpu_16(gre_m->protocol));
4366         MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
4367                  rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol));
4368         gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver);
4369         gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver);
4370         MLX5_SET(fte_match_set_misc, misc_m, gre_c_present,
4371                  gre_crks_rsvd0_ver_m.c_present);
4372         MLX5_SET(fte_match_set_misc, misc_v, gre_c_present,
4373                  gre_crks_rsvd0_ver_v.c_present &
4374                  gre_crks_rsvd0_ver_m.c_present);
4375         MLX5_SET(fte_match_set_misc, misc_m, gre_k_present,
4376                  gre_crks_rsvd0_ver_m.k_present);
4377         MLX5_SET(fte_match_set_misc, misc_v, gre_k_present,
4378                  gre_crks_rsvd0_ver_v.k_present &
4379                  gre_crks_rsvd0_ver_m.k_present);
4380         MLX5_SET(fte_match_set_misc, misc_m, gre_s_present,
4381                  gre_crks_rsvd0_ver_m.s_present);
4382         MLX5_SET(fte_match_set_misc, misc_v, gre_s_present,
4383                  gre_crks_rsvd0_ver_v.s_present &
4384                  gre_crks_rsvd0_ver_m.s_present);
4385 }
4386
4387 /**
4388  * Add NVGRE item to matcher and to the value.
4389  *
4390  * @param[in, out] matcher
4391  *   Flow matcher.
4392  * @param[in, out] key
4393  *   Flow matcher value.
4394  * @param[in] item
4395  *   Flow pattern to translate.
4396  * @param[in] inner
4397  *   Item is inner pattern.
4398  */
4399 static void
4400 flow_dv_translate_item_nvgre(void *matcher, void *key,
4401                              const struct rte_flow_item *item,
4402                              int inner)
4403 {
4404         const struct rte_flow_item_nvgre *nvgre_m = item->mask;
4405         const struct rte_flow_item_nvgre *nvgre_v = item->spec;
4406         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4407         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4408         const char *tni_flow_id_m = (const char *)nvgre_m->tni;
4409         const char *tni_flow_id_v = (const char *)nvgre_v->tni;
4410         char *gre_key_m;
4411         char *gre_key_v;
4412         int size;
4413         int i;
4414
4415         /* For NVGRE, GRE header fields must be set with defined values. */
4416         const struct rte_flow_item_gre gre_spec = {
4417                 .c_rsvd0_ver = RTE_BE16(0x2000),
4418                 .protocol = RTE_BE16(RTE_ETHER_TYPE_TEB)
4419         };
4420         const struct rte_flow_item_gre gre_mask = {
4421                 .c_rsvd0_ver = RTE_BE16(0xB000),
4422                 .protocol = RTE_BE16(UINT16_MAX),
4423         };
4424         const struct rte_flow_item gre_item = {
4425                 .spec = &gre_spec,
4426                 .mask = &gre_mask,
4427                 .last = NULL,
4428         };
4429         flow_dv_translate_item_gre(matcher, key, &gre_item, inner);
4430         if (!nvgre_v)
4431                 return;
4432         if (!nvgre_m)
4433                 nvgre_m = &rte_flow_item_nvgre_mask;
4434         size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
4435         gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h);
4436         gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
4437         memcpy(gre_key_m, tni_flow_id_m, size);
4438         for (i = 0; i < size; ++i)
4439                 gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i];
4440 }
4441
4442 /**
4443  * Add VXLAN item to matcher and to the value.
4444  *
4445  * @param[in, out] matcher
4446  *   Flow matcher.
4447  * @param[in, out] key
4448  *   Flow matcher value.
4449  * @param[in] item
4450  *   Flow pattern to translate.
4451  * @param[in] inner
4452  *   Item is inner pattern.
4453  */
4454 static void
4455 flow_dv_translate_item_vxlan(void *matcher, void *key,
4456                              const struct rte_flow_item *item,
4457                              int inner)
4458 {
4459         const struct rte_flow_item_vxlan *vxlan_m = item->mask;
4460         const struct rte_flow_item_vxlan *vxlan_v = item->spec;
4461         void *headers_m;
4462         void *headers_v;
4463         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4464         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4465         char *vni_m;
4466         char *vni_v;
4467         uint16_t dport;
4468         int size;
4469         int i;
4470
4471         if (inner) {
4472                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4473                                          inner_headers);
4474                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4475         } else {
4476                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4477                                          outer_headers);
4478                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4479         }
4480         dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
4481                 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
4482         if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
4483                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
4484                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
4485         }
4486         if (!vxlan_v)
4487                 return;
4488         if (!vxlan_m)
4489                 vxlan_m = &rte_flow_item_vxlan_mask;
4490         size = sizeof(vxlan_m->vni);
4491         vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni);
4492         vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni);
4493         memcpy(vni_m, vxlan_m->vni, size);
4494         for (i = 0; i < size; ++i)
4495                 vni_v[i] = vni_m[i] & vxlan_v->vni[i];
4496 }
4497
4498 /**
4499  * Add MPLS item to matcher and to the value.
4500  *
4501  * @param[in, out] matcher
4502  *   Flow matcher.
4503  * @param[in, out] key
4504  *   Flow matcher value.
4505  * @param[in] item
4506  *   Flow pattern to translate.
4507  * @param[in] prev_layer
4508  *   The protocol layer indicated in previous item.
4509  * @param[in] inner
4510  *   Item is inner pattern.
4511  */
4512 static void
4513 flow_dv_translate_item_mpls(void *matcher, void *key,
4514                             const struct rte_flow_item *item,
4515                             uint64_t prev_layer,
4516                             int inner)
4517 {
4518         const uint32_t *in_mpls_m = item->mask;
4519         const uint32_t *in_mpls_v = item->spec;
4520         uint32_t *out_mpls_m = 0;
4521         uint32_t *out_mpls_v = 0;
4522         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4523         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4524         void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher,
4525                                      misc_parameters_2);
4526         void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
4527         void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
4528         void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4529
4530         switch (prev_layer) {
4531         case MLX5_FLOW_LAYER_OUTER_L4_UDP:
4532                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff);
4533                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
4534                          MLX5_UDP_PORT_MPLS);
4535                 break;
4536         case MLX5_FLOW_LAYER_GRE:
4537                 MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff);
4538                 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
4539                          RTE_ETHER_TYPE_MPLS);
4540                 break;
4541         default:
4542                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
4543                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
4544                          IPPROTO_MPLS);
4545                 break;
4546         }
4547         if (!in_mpls_v)
4548                 return;
4549         if (!in_mpls_m)
4550                 in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask;
4551         switch (prev_layer) {
4552         case MLX5_FLOW_LAYER_OUTER_L4_UDP:
4553                 out_mpls_m =
4554                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
4555                                                  outer_first_mpls_over_udp);
4556                 out_mpls_v =
4557                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
4558                                                  outer_first_mpls_over_udp);
4559                 break;
4560         case MLX5_FLOW_LAYER_GRE:
4561                 out_mpls_m =
4562                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
4563                                                  outer_first_mpls_over_gre);
4564                 out_mpls_v =
4565                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
4566                                                  outer_first_mpls_over_gre);
4567                 break;
4568         default:
4569                 /* Inner MPLS not over GRE is not supported. */
4570                 if (!inner) {
4571                         out_mpls_m =
4572                                 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
4573                                                          misc2_m,
4574                                                          outer_first_mpls);
4575                         out_mpls_v =
4576                                 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
4577                                                          misc2_v,
4578                                                          outer_first_mpls);
4579                 }
4580                 break;
4581         }
4582         if (out_mpls_m && out_mpls_v) {
4583                 *out_mpls_m = *in_mpls_m;
4584                 *out_mpls_v = *in_mpls_v & *in_mpls_m;
4585         }
4586 }
4587
4588 /**
4589  * Add META item to matcher
4590  *
4591  * @param[in, out] matcher
4592  *   Flow matcher.
4593  * @param[in, out] key
4594  *   Flow matcher value.
4595  * @param[in] item
4596  *   Flow pattern to translate.
4597  * @param[in] inner
4598  *   Item is inner pattern.
4599  */
4600 static void
4601 flow_dv_translate_item_meta(void *matcher, void *key,
4602                             const struct rte_flow_item *item)
4603 {
4604         const struct rte_flow_item_meta *meta_m;
4605         const struct rte_flow_item_meta *meta_v;
4606         void *misc2_m =
4607                 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2);
4608         void *misc2_v =
4609                 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
4610
4611         meta_m = (const void *)item->mask;
4612         if (!meta_m)
4613                 meta_m = &rte_flow_item_meta_mask;
4614         meta_v = (const void *)item->spec;
4615         if (meta_v) {
4616                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a,
4617                          rte_be_to_cpu_32(meta_m->data));
4618                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a,
4619                          rte_be_to_cpu_32(meta_v->data & meta_m->data));
4620         }
4621 }
4622
4623 /**
4624  * Add source vport match to the specified matcher.
4625  *
4626  * @param[in, out] matcher
4627  *   Flow matcher.
4628  * @param[in, out] key
4629  *   Flow matcher value.
4630  * @param[in] port
4631  *   Source vport value to match
4632  * @param[in] mask
4633  *   Mask
4634  */
4635 static void
4636 flow_dv_translate_item_source_vport(void *matcher, void *key,
4637                                     int16_t port, uint16_t mask)
4638 {
4639         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4640         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4641
4642         MLX5_SET(fte_match_set_misc, misc_m, source_port, mask);
4643         MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
4644 }
4645
4646 /**
4647  * Translate port-id item to eswitch match on  port-id.
4648  *
4649  * @param[in] dev
4650  *   The devich to configure through.
4651  * @param[in, out] matcher
4652  *   Flow matcher.
4653  * @param[in, out] key
4654  *   Flow matcher value.
4655  * @param[in] item
4656  *   Flow pattern to translate.
4657  *
4658  * @return
4659  *   0 on success, a negative errno value otherwise.
4660  */
4661 static int
4662 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher,
4663                                void *key, const struct rte_flow_item *item)
4664 {
4665         const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL;
4666         const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL;
4667         uint16_t mask, val, id;
4668         int ret;
4669
4670         mask = pid_m ? pid_m->id : 0xffff;
4671         id = pid_v ? pid_v->id : dev->data->port_id;
4672         ret = mlx5_port_to_eswitch_info(id, NULL, &val);
4673         if (ret)
4674                 return ret;
4675         flow_dv_translate_item_source_vport(matcher, key, val, mask);
4676         return 0;
4677 }
4678
4679 /**
4680  * Add ICMP6 item to matcher and to the value.
4681  *
4682  * @param[in, out] matcher
4683  *   Flow matcher.
4684  * @param[in, out] key
4685  *   Flow matcher value.
4686  * @param[in] item
4687  *   Flow pattern to translate.
4688  * @param[in] inner
4689  *   Item is inner pattern.
4690  */
4691 static void
4692 flow_dv_translate_item_icmp6(void *matcher, void *key,
4693                               const struct rte_flow_item *item,
4694                               int inner)
4695 {
4696         const struct rte_flow_item_icmp6 *icmp6_m = item->mask;
4697         const struct rte_flow_item_icmp6 *icmp6_v = item->spec;
4698         void *headers_m;
4699         void *headers_v;
4700         void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
4701                                      misc_parameters_3);
4702         void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
4703         if (inner) {
4704                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4705                                          inner_headers);
4706                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4707         } else {
4708                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4709                                          outer_headers);
4710                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4711         }
4712         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
4713         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6);
4714         if (!icmp6_v)
4715                 return;
4716         if (!icmp6_m)
4717                 icmp6_m = &rte_flow_item_icmp6_mask;
4718         MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type);
4719         MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type,
4720                  icmp6_v->type & icmp6_m->type);
4721         MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code);
4722         MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code,
4723                  icmp6_v->code & icmp6_m->code);
4724 }
4725
4726 /**
4727  * Add ICMP item to matcher and to the value.
4728  *
4729  * @param[in, out] matcher
4730  *   Flow matcher.
4731  * @param[in, out] key
4732  *   Flow matcher value.
4733  * @param[in] item
4734  *   Flow pattern to translate.
4735  * @param[in] inner
4736  *   Item is inner pattern.
4737  */
4738 static void
4739 flow_dv_translate_item_icmp(void *matcher, void *key,
4740                             const struct rte_flow_item *item,
4741                             int inner)
4742 {
4743         const struct rte_flow_item_icmp *icmp_m = item->mask;
4744         const struct rte_flow_item_icmp *icmp_v = item->spec;
4745         void *headers_m;
4746         void *headers_v;
4747         void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
4748                                      misc_parameters_3);
4749         void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
4750         if (inner) {
4751                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4752                                          inner_headers);
4753                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4754         } else {
4755                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4756                                          outer_headers);
4757                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4758         }
4759         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
4760         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP);
4761         if (!icmp_v)
4762                 return;
4763         if (!icmp_m)
4764                 icmp_m = &rte_flow_item_icmp_mask;
4765         MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type,
4766                  icmp_m->hdr.icmp_type);
4767         MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type,
4768                  icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type);
4769         MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code,
4770                  icmp_m->hdr.icmp_code);
4771         MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code,
4772                  icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code);
4773 }
4774
4775 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
4776
4777 #define HEADER_IS_ZERO(match_criteria, headers)                              \
4778         !(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
4779                  matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
4780
4781 /**
4782  * Calculate flow matcher enable bitmap.
4783  *
4784  * @param match_criteria
4785  *   Pointer to flow matcher criteria.
4786  *
4787  * @return
4788  *   Bitmap of enabled fields.
4789  */
4790 static uint8_t
4791 flow_dv_matcher_enable(uint32_t *match_criteria)
4792 {
4793         uint8_t match_criteria_enable;
4794
4795         match_criteria_enable =
4796                 (!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
4797                 MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
4798         match_criteria_enable |=
4799                 (!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
4800                 MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
4801         match_criteria_enable |=
4802                 (!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
4803                 MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
4804         match_criteria_enable |=
4805                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
4806                 MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
4807         match_criteria_enable |=
4808                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
4809                 MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
4810         return match_criteria_enable;
4811 }
4812
4813
4814 /**
4815  * Get a flow table.
4816  *
4817  * @param dev[in, out]
4818  *   Pointer to rte_eth_dev structure.
4819  * @param[in] table_id
4820  *   Table id to use.
4821  * @param[in] egress
4822  *   Direction of the table.
4823  * @param[in] transfer
4824  *   E-Switch or NIC flow.
4825  * @param[out] error
4826  *   pointer to error structure.
4827  *
4828  * @return
4829  *   Returns tables resource based on the index, NULL in case of failed.
4830  */
4831 static struct mlx5_flow_tbl_resource *
4832 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
4833                          uint32_t table_id, uint8_t egress,
4834                          uint8_t transfer,
4835                          struct rte_flow_error *error)
4836 {
4837         struct mlx5_priv *priv = dev->data->dev_private;
4838         struct mlx5_ibv_shared *sh = priv->sh;
4839         struct mlx5_flow_tbl_resource *tbl;
4840
4841 #ifdef HAVE_MLX5DV_DR
4842         if (transfer) {
4843                 tbl = &sh->fdb_tbl[table_id];
4844                 if (!tbl->obj)
4845                         tbl->obj = mlx5_glue->dr_create_flow_tbl
4846                                 (sh->fdb_domain, table_id);
4847         } else if (egress) {
4848                 tbl = &sh->tx_tbl[table_id];
4849                 if (!tbl->obj)
4850                         tbl->obj = mlx5_glue->dr_create_flow_tbl
4851                                 (sh->tx_domain, table_id);
4852         } else {
4853                 tbl = &sh->rx_tbl[table_id];
4854                 if (!tbl->obj)
4855                         tbl->obj = mlx5_glue->dr_create_flow_tbl
4856                                 (sh->rx_domain, table_id);
4857         }
4858         if (!tbl->obj) {
4859                 rte_flow_error_set(error, ENOMEM,
4860                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4861                                    NULL, "cannot create table");
4862                 return NULL;
4863         }
4864         rte_atomic32_inc(&tbl->refcnt);
4865         return tbl;
4866 #else
4867         (void)error;
4868         (void)tbl;
4869         if (transfer)
4870                 return &sh->fdb_tbl[table_id];
4871         else if (egress)
4872                 return &sh->tx_tbl[table_id];
4873         else
4874                 return &sh->rx_tbl[table_id];
4875 #endif
4876 }
4877
4878 /**
4879  * Release a flow table.
4880  *
4881  * @param[in] tbl
4882  *   Table resource to be released.
4883  *
4884  * @return
4885  *   Returns 0 if table was released, else return 1;
4886  */
4887 static int
4888 flow_dv_tbl_resource_release(struct mlx5_flow_tbl_resource *tbl)
4889 {
4890         if (!tbl)
4891                 return 0;
4892         if (rte_atomic32_dec_and_test(&tbl->refcnt)) {
4893                 mlx5_glue->dr_destroy_flow_tbl(tbl->obj);
4894                 tbl->obj = NULL;
4895                 return 0;
4896         }
4897         return 1;
4898 }
4899
4900 /**
4901  * Register the flow matcher.
4902  *
4903  * @param dev[in, out]
4904  *   Pointer to rte_eth_dev structure.
4905  * @param[in, out] matcher
4906  *   Pointer to flow matcher.
4907  * @parm[in, out] dev_flow
4908  *   Pointer to the dev_flow.
4909  * @param[out] error
4910  *   pointer to error structure.
4911  *
4912  * @return
4913  *   0 on success otherwise -errno and errno is set.
4914  */
4915 static int
4916 flow_dv_matcher_register(struct rte_eth_dev *dev,
4917                          struct mlx5_flow_dv_matcher *matcher,
4918                          struct mlx5_flow *dev_flow,
4919                          struct rte_flow_error *error)
4920 {
4921         struct mlx5_priv *priv = dev->data->dev_private;
4922         struct mlx5_ibv_shared *sh = priv->sh;
4923         struct mlx5_flow_dv_matcher *cache_matcher;
4924         struct mlx5dv_flow_matcher_attr dv_attr = {
4925                 .type = IBV_FLOW_ATTR_NORMAL,
4926                 .match_mask = (void *)&matcher->mask,
4927         };
4928         struct mlx5_flow_tbl_resource *tbl = NULL;
4929
4930         /* Lookup from cache. */
4931         LIST_FOREACH(cache_matcher, &sh->matchers, next) {
4932                 if (matcher->crc == cache_matcher->crc &&
4933                     matcher->priority == cache_matcher->priority &&
4934                     matcher->egress == cache_matcher->egress &&
4935                     matcher->group == cache_matcher->group &&
4936                     matcher->transfer == cache_matcher->transfer &&
4937                     !memcmp((const void *)matcher->mask.buf,
4938                             (const void *)cache_matcher->mask.buf,
4939                             cache_matcher->mask.size)) {
4940                         DRV_LOG(DEBUG,
4941                                 "priority %hd use %s matcher %p: refcnt %d++",
4942                                 cache_matcher->priority,
4943                                 cache_matcher->egress ? "tx" : "rx",
4944                                 (void *)cache_matcher,
4945                                 rte_atomic32_read(&cache_matcher->refcnt));
4946                         rte_atomic32_inc(&cache_matcher->refcnt);
4947                         dev_flow->dv.matcher = cache_matcher;
4948                         return 0;
4949                 }
4950         }
4951         /* Register new matcher. */
4952         cache_matcher = rte_calloc(__func__, 1, sizeof(*cache_matcher), 0);
4953         if (!cache_matcher)
4954                 return rte_flow_error_set(error, ENOMEM,
4955                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4956                                           "cannot allocate matcher memory");
4957         tbl = flow_dv_tbl_resource_get(dev, matcher->group,
4958                                        matcher->egress, matcher->transfer,
4959                                        error);
4960         if (!tbl) {
4961                 rte_free(cache_matcher);
4962                 return rte_flow_error_set(error, ENOMEM,
4963                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4964                                           NULL, "cannot create table");
4965         }
4966         *cache_matcher = *matcher;
4967         dv_attr.match_criteria_enable =
4968                 flow_dv_matcher_enable(cache_matcher->mask.buf);
4969         dv_attr.priority = matcher->priority;
4970         if (matcher->egress)
4971                 dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
4972         cache_matcher->matcher_object =
4973                 mlx5_glue->dv_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj);
4974         if (!cache_matcher->matcher_object) {
4975                 rte_free(cache_matcher);
4976 #ifdef HAVE_MLX5DV_DR
4977                 flow_dv_tbl_resource_release(tbl);
4978 #endif
4979                 return rte_flow_error_set(error, ENOMEM,
4980                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4981                                           NULL, "cannot create matcher");
4982         }
4983         rte_atomic32_inc(&cache_matcher->refcnt);
4984         LIST_INSERT_HEAD(&sh->matchers, cache_matcher, next);
4985         dev_flow->dv.matcher = cache_matcher;
4986         DRV_LOG(DEBUG, "priority %hd new %s matcher %p: refcnt %d",
4987                 cache_matcher->priority,
4988                 cache_matcher->egress ? "tx" : "rx", (void *)cache_matcher,
4989                 rte_atomic32_read(&cache_matcher->refcnt));
4990         rte_atomic32_inc(&tbl->refcnt);
4991         return 0;
4992 }
4993
4994 /**
4995  * Find existing tag resource or create and register a new one.
4996  *
4997  * @param dev[in, out]
4998  *   Pointer to rte_eth_dev structure.
4999  * @param[in, out] resource
5000  *   Pointer to tag resource.
5001  * @parm[in, out] dev_flow
5002  *   Pointer to the dev_flow.
5003  * @param[out] error
5004  *   pointer to error structure.
5005  *
5006  * @return
5007  *   0 on success otherwise -errno and errno is set.
5008  */
5009 static int
5010 flow_dv_tag_resource_register
5011                         (struct rte_eth_dev *dev,
5012                          struct mlx5_flow_dv_tag_resource *resource,
5013                          struct mlx5_flow *dev_flow,
5014                          struct rte_flow_error *error)
5015 {
5016         struct mlx5_priv *priv = dev->data->dev_private;
5017         struct mlx5_ibv_shared *sh = priv->sh;
5018         struct mlx5_flow_dv_tag_resource *cache_resource;
5019
5020         /* Lookup a matching resource from cache. */
5021         LIST_FOREACH(cache_resource, &sh->tags, next) {
5022                 if (resource->tag == cache_resource->tag) {
5023                         DRV_LOG(DEBUG, "tag resource %p: refcnt %d++",
5024                                 (void *)cache_resource,
5025                                 rte_atomic32_read(&cache_resource->refcnt));
5026                         rte_atomic32_inc(&cache_resource->refcnt);
5027                         dev_flow->flow->tag_resource = cache_resource;
5028                         return 0;
5029                 }
5030         }
5031         /* Register new  resource. */
5032         cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
5033         if (!cache_resource)
5034                 return rte_flow_error_set(error, ENOMEM,
5035                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5036                                           "cannot allocate resource memory");
5037         *cache_resource = *resource;
5038         cache_resource->action = mlx5_glue->dv_create_flow_action_tag
5039                 (resource->tag);
5040         if (!cache_resource->action) {
5041                 rte_free(cache_resource);
5042                 return rte_flow_error_set(error, ENOMEM,
5043                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5044                                           NULL, "cannot create action");
5045         }
5046         rte_atomic32_init(&cache_resource->refcnt);
5047         rte_atomic32_inc(&cache_resource->refcnt);
5048         LIST_INSERT_HEAD(&sh->tags, cache_resource, next);
5049         dev_flow->flow->tag_resource = cache_resource;
5050         DRV_LOG(DEBUG, "new tag resource %p: refcnt %d++",
5051                 (void *)cache_resource,
5052                 rte_atomic32_read(&cache_resource->refcnt));
5053         return 0;
5054 }
5055
5056 /**
5057  * Release the tag.
5058  *
5059  * @param dev
5060  *   Pointer to Ethernet device.
5061  * @param flow
5062  *   Pointer to mlx5_flow.
5063  *
5064  * @return
5065  *   1 while a reference on it exists, 0 when freed.
5066  */
5067 static int
5068 flow_dv_tag_release(struct rte_eth_dev *dev,
5069                     struct mlx5_flow_dv_tag_resource *tag)
5070 {
5071         assert(tag);
5072         DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
5073                 dev->data->port_id, (void *)tag,
5074                 rte_atomic32_read(&tag->refcnt));
5075         if (rte_atomic32_dec_and_test(&tag->refcnt)) {
5076                 claim_zero(mlx5_glue->destroy_flow_action(tag->action));
5077                 LIST_REMOVE(tag, next);
5078                 DRV_LOG(DEBUG, "port %u tag %p: removed",
5079                         dev->data->port_id, (void *)tag);
5080                 rte_free(tag);
5081                 return 0;
5082         }
5083         return 1;
5084 }
5085
5086 /**
5087  * Translate port ID action to vport.
5088  *
5089  * @param[in] dev
5090  *   Pointer to rte_eth_dev structure.
5091  * @param[in] action
5092  *   Pointer to the port ID action.
5093  * @param[out] dst_port_id
5094  *   The target port ID.
5095  * @param[out] error
5096  *   Pointer to the error structure.
5097  *
5098  * @return
5099  *   0 on success, a negative errno value otherwise and rte_errno is set.
5100  */
5101 static int
5102 flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
5103                                  const struct rte_flow_action *action,
5104                                  uint32_t *dst_port_id,
5105                                  struct rte_flow_error *error)
5106 {
5107         uint32_t port;
5108         uint16_t port_id;
5109         int ret;
5110         const struct rte_flow_action_port_id *conf =
5111                         (const struct rte_flow_action_port_id *)action->conf;
5112
5113         port = conf->original ? dev->data->port_id : conf->id;
5114         ret = mlx5_port_to_eswitch_info(port, NULL, &port_id);
5115         if (ret)
5116                 return rte_flow_error_set(error, -ret,
5117                                           RTE_FLOW_ERROR_TYPE_ACTION,
5118                                           NULL,
5119                                           "No eswitch info was found for port");
5120         *dst_port_id = port_id;
5121         return 0;
5122 }
5123
5124 /**
5125  * Fill the flow with DV spec.
5126  *
5127  * @param[in] dev
5128  *   Pointer to rte_eth_dev structure.
5129  * @param[in, out] dev_flow
5130  *   Pointer to the sub flow.
5131  * @param[in] attr
5132  *   Pointer to the flow attributes.
5133  * @param[in] items
5134  *   Pointer to the list of items.
5135  * @param[in] actions
5136  *   Pointer to the list of actions.
5137  * @param[out] error
5138  *   Pointer to the error structure.
5139  *
5140  * @return
5141  *   0 on success, a negative errno value otherwise and rte_errno is set.
5142  */
5143 static int
5144 flow_dv_translate(struct rte_eth_dev *dev,
5145                   struct mlx5_flow *dev_flow,
5146                   const struct rte_flow_attr *attr,
5147                   const struct rte_flow_item items[],
5148                   const struct rte_flow_action actions[],
5149                   struct rte_flow_error *error)
5150 {
5151         struct mlx5_priv *priv = dev->data->dev_private;
5152         struct rte_flow *flow = dev_flow->flow;
5153         uint64_t item_flags = 0;
5154         uint64_t last_item = 0;
5155         uint64_t action_flags = 0;
5156         uint64_t priority = attr->priority;
5157         struct mlx5_flow_dv_matcher matcher = {
5158                 .mask = {
5159                         .size = sizeof(matcher.mask.buf),
5160                 },
5161         };
5162         int actions_n = 0;
5163         bool actions_end = false;
5164         struct mlx5_flow_dv_modify_hdr_resource res = {
5165                 .ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
5166                                           MLX5DV_FLOW_TABLE_TYPE_NIC_RX
5167         };
5168         union flow_dv_attr flow_attr = { .attr = 0 };
5169         struct mlx5_flow_dv_tag_resource tag_resource;
5170         uint32_t modify_action_position = UINT32_MAX;
5171         void *match_mask = matcher.mask.buf;
5172         void *match_value = dev_flow->dv.value.buf;
5173         uint8_t next_protocol = 0xff;
5174         struct rte_vlan_hdr vlan = { 0 };
5175         bool vlan_inherited = false;
5176         uint16_t vlan_tci;
5177         uint32_t table;
5178         int ret = 0;
5179
5180         ret = mlx5_flow_group_to_table(attr, dev_flow->external, attr->group,
5181                                        &table, error);
5182         if (ret)
5183                 return ret;
5184         flow->group = table;
5185         if (attr->transfer)
5186                 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
5187         if (priority == MLX5_FLOW_PRIO_RSVD)
5188                 priority = priv->config.flow_prio - 1;
5189         for (; !actions_end ; actions++) {
5190                 const struct rte_flow_action_queue *queue;
5191                 const struct rte_flow_action_rss *rss;
5192                 const struct rte_flow_action *action = actions;
5193                 const struct rte_flow_action_count *count = action->conf;
5194                 const uint8_t *rss_key;
5195                 const struct rte_flow_action_jump *jump_data;
5196                 struct mlx5_flow_dv_jump_tbl_resource jump_tbl_resource;
5197                 struct mlx5_flow_tbl_resource *tbl;
5198                 uint32_t port_id = 0;
5199                 struct mlx5_flow_dv_port_id_action_resource port_id_resource;
5200
5201                 switch (actions->type) {
5202                 case RTE_FLOW_ACTION_TYPE_VOID:
5203                         break;
5204                 case RTE_FLOW_ACTION_TYPE_PORT_ID:
5205                         if (flow_dv_translate_action_port_id(dev, action,
5206                                                              &port_id, error))
5207                                 return -rte_errno;
5208                         port_id_resource.port_id = port_id;
5209                         if (flow_dv_port_id_action_resource_register
5210                             (dev, &port_id_resource, dev_flow, error))
5211                                 return -rte_errno;
5212                         dev_flow->dv.actions[actions_n++] =
5213                                 dev_flow->dv.port_id_action->action;
5214                         action_flags |= MLX5_FLOW_ACTION_PORT_ID;
5215                         break;
5216                 case RTE_FLOW_ACTION_TYPE_FLAG:
5217                         tag_resource.tag =
5218                                 mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
5219                         if (!flow->tag_resource)
5220                                 if (flow_dv_tag_resource_register
5221                                     (dev, &tag_resource, dev_flow, error))
5222                                         return errno;
5223                         dev_flow->dv.actions[actions_n++] =
5224                                 flow->tag_resource->action;
5225                         action_flags |= MLX5_FLOW_ACTION_FLAG;
5226                         break;
5227                 case RTE_FLOW_ACTION_TYPE_MARK:
5228                         tag_resource.tag = mlx5_flow_mark_set
5229                               (((const struct rte_flow_action_mark *)
5230                                (actions->conf))->id);
5231                         if (!flow->tag_resource)
5232                                 if (flow_dv_tag_resource_register
5233                                     (dev, &tag_resource, dev_flow, error))
5234                                         return errno;
5235                         dev_flow->dv.actions[actions_n++] =
5236                                 flow->tag_resource->action;
5237                         action_flags |= MLX5_FLOW_ACTION_MARK;
5238                         break;
5239                 case RTE_FLOW_ACTION_TYPE_DROP:
5240                         action_flags |= MLX5_FLOW_ACTION_DROP;
5241                         break;
5242                 case RTE_FLOW_ACTION_TYPE_QUEUE:
5243                         queue = actions->conf;
5244                         flow->rss.queue_num = 1;
5245                         (*flow->queue)[0] = queue->index;
5246                         action_flags |= MLX5_FLOW_ACTION_QUEUE;
5247                         break;
5248                 case RTE_FLOW_ACTION_TYPE_RSS:
5249                         rss = actions->conf;
5250                         if (flow->queue)
5251                                 memcpy((*flow->queue), rss->queue,
5252                                        rss->queue_num * sizeof(uint16_t));
5253                         flow->rss.queue_num = rss->queue_num;
5254                         /* NULL RSS key indicates default RSS key. */
5255                         rss_key = !rss->key ? rss_hash_default_key : rss->key;
5256                         memcpy(flow->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
5257                         /* RSS type 0 indicates default RSS type ETH_RSS_IP. */
5258                         flow->rss.types = !rss->types ? ETH_RSS_IP : rss->types;
5259                         flow->rss.level = rss->level;
5260                         action_flags |= MLX5_FLOW_ACTION_RSS;
5261                         break;
5262                 case RTE_FLOW_ACTION_TYPE_COUNT:
5263                         if (!priv->config.devx) {
5264                                 rte_errno = ENOTSUP;
5265                                 goto cnt_err;
5266                         }
5267                         flow->counter = flow_dv_counter_alloc(dev,
5268                                                               count->shared,
5269                                                               count->id,
5270                                                               flow->group);
5271                         if (flow->counter == NULL)
5272                                 goto cnt_err;
5273                         dev_flow->dv.actions[actions_n++] =
5274                                 flow->counter->action;
5275                         action_flags |= MLX5_FLOW_ACTION_COUNT;
5276                         break;
5277 cnt_err:
5278                         if (rte_errno == ENOTSUP)
5279                                 return rte_flow_error_set
5280                                               (error, ENOTSUP,
5281                                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5282                                                NULL,
5283                                                "count action not supported");
5284                         else
5285                                 return rte_flow_error_set
5286                                                 (error, rte_errno,
5287                                                  RTE_FLOW_ERROR_TYPE_ACTION,
5288                                                  action,
5289                                                  "cannot create counter"
5290                                                   " object.");
5291                         break;
5292                 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
5293                         dev_flow->dv.actions[actions_n++] =
5294                                                 priv->sh->pop_vlan_action;
5295                         action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
5296                         break;
5297                 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
5298                         if (!vlan_inherited) {
5299                                 flow_dev_get_vlan_info_from_items(items, &vlan);
5300                                 vlan_inherited = true;
5301                         }
5302                         vlan.eth_proto = rte_be_to_cpu_16
5303                              ((((const struct rte_flow_action_of_push_vlan *)
5304                                                    actions->conf)->ethertype));
5305                         if (flow_dv_create_action_push_vlan
5306                                             (dev, attr, &vlan, dev_flow, error))
5307                                 return -rte_errno;
5308                         dev_flow->dv.actions[actions_n++] =
5309                                            dev_flow->dv.push_vlan_res->action;
5310                         action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
5311                         /* Push VLAN command is also handling this VLAN_VID */
5312                         action_flags &= ~MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
5313                         break;
5314                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
5315                         if (!vlan_inherited) {
5316                                 flow_dev_get_vlan_info_from_items(items, &vlan);
5317                                 vlan_inherited = true;
5318                         }
5319                         vlan_tci =
5320                             ((const struct rte_flow_action_of_set_vlan_pcp *)
5321                                                        actions->conf)->vlan_pcp;
5322                         vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT;
5323                         vlan.vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
5324                         vlan.vlan_tci |= vlan_tci;
5325                         /* Push VLAN command will use this value */
5326                         break;
5327                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
5328                         if (!vlan_inherited) {
5329                                 flow_dev_get_vlan_info_from_items(items, &vlan);
5330                                 vlan_inherited = true;
5331                         }
5332                         vlan.vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
5333                         vlan.vlan_tci |= rte_be_to_cpu_16
5334                             (((const struct rte_flow_action_of_set_vlan_vid *)
5335                                                      actions->conf)->vlan_vid);
5336                         /* Push VLAN command will use this value */
5337                         if (mlx5_flow_find_action
5338                                 (actions,
5339                                  RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN))
5340                                 break;
5341                         /* If no VLAN push - this is a modify header action */
5342                         if (flow_dv_convert_action_modify_vlan_vid
5343                                                         (&res, actions, error))
5344                                 return -rte_errno;
5345                         action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
5346                         break;
5347                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5348                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
5349                         if (flow_dv_create_action_l2_encap(dev, actions,
5350                                                            dev_flow,
5351                                                            attr->transfer,
5352                                                            error))
5353                                 return -rte_errno;
5354                         dev_flow->dv.actions[actions_n++] =
5355                                 dev_flow->dv.encap_decap->verbs_action;
5356                         action_flags |= actions->type ==
5357                                         RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP ?
5358                                         MLX5_FLOW_ACTION_VXLAN_ENCAP :
5359                                         MLX5_FLOW_ACTION_NVGRE_ENCAP;
5360                         break;
5361                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
5362                 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
5363                         if (flow_dv_create_action_l2_decap(dev, dev_flow,
5364                                                            attr->transfer,
5365                                                            error))
5366                                 return -rte_errno;
5367                         dev_flow->dv.actions[actions_n++] =
5368                                 dev_flow->dv.encap_decap->verbs_action;
5369                         action_flags |= actions->type ==
5370                                         RTE_FLOW_ACTION_TYPE_VXLAN_DECAP ?
5371                                         MLX5_FLOW_ACTION_VXLAN_DECAP :
5372                                         MLX5_FLOW_ACTION_NVGRE_DECAP;
5373                         break;
5374                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
5375                         /* Handle encap with preceding decap. */
5376                         if (action_flags & MLX5_FLOW_ACTION_RAW_DECAP) {
5377                                 if (flow_dv_create_action_raw_encap
5378                                         (dev, actions, dev_flow, attr, error))
5379                                         return -rte_errno;
5380                                 dev_flow->dv.actions[actions_n++] =
5381                                         dev_flow->dv.encap_decap->verbs_action;
5382                         } else {
5383                                 /* Handle encap without preceding decap. */
5384                                 if (flow_dv_create_action_l2_encap
5385                                     (dev, actions, dev_flow, attr->transfer,
5386                                      error))
5387                                         return -rte_errno;
5388                                 dev_flow->dv.actions[actions_n++] =
5389                                         dev_flow->dv.encap_decap->verbs_action;
5390                         }
5391                         action_flags |= MLX5_FLOW_ACTION_RAW_ENCAP;
5392                         break;
5393                 case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
5394                         /* Check if this decap is followed by encap. */
5395                         for (; action->type != RTE_FLOW_ACTION_TYPE_END &&
5396                                action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP;
5397                                action++) {
5398                         }
5399                         /* Handle decap only if it isn't followed by encap. */
5400                         if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
5401                                 if (flow_dv_create_action_l2_decap
5402                                     (dev, dev_flow, attr->transfer, error))
5403                                         return -rte_errno;
5404                                 dev_flow->dv.actions[actions_n++] =
5405                                         dev_flow->dv.encap_decap->verbs_action;
5406                         }
5407                         /* If decap is followed by encap, handle it at encap. */
5408                         action_flags |= MLX5_FLOW_ACTION_RAW_DECAP;
5409                         break;
5410                 case RTE_FLOW_ACTION_TYPE_JUMP:
5411                         jump_data = action->conf;
5412                         ret = mlx5_flow_group_to_table(attr, dev_flow->external,
5413                                                        jump_data->group, &table,
5414                                                        error);
5415                         if (ret)
5416                                 return ret;
5417                         tbl = flow_dv_tbl_resource_get(dev, table,
5418                                                        attr->egress,
5419                                                        attr->transfer, error);
5420                         if (!tbl)
5421                                 return rte_flow_error_set
5422                                                 (error, errno,
5423                                                  RTE_FLOW_ERROR_TYPE_ACTION,
5424                                                  NULL,
5425                                                  "cannot create jump action.");
5426                         jump_tbl_resource.tbl = tbl;
5427                         if (flow_dv_jump_tbl_resource_register
5428                             (dev, &jump_tbl_resource, dev_flow, error)) {
5429                                 flow_dv_tbl_resource_release(tbl);
5430                                 return rte_flow_error_set
5431                                                 (error, errno,
5432                                                  RTE_FLOW_ERROR_TYPE_ACTION,
5433                                                  NULL,
5434                                                  "cannot create jump action.");
5435                         }
5436                         dev_flow->dv.actions[actions_n++] =
5437                                 dev_flow->dv.jump->action;
5438                         action_flags |= MLX5_FLOW_ACTION_JUMP;
5439                         break;
5440                 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
5441                 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
5442                         if (flow_dv_convert_action_modify_mac(&res, actions,
5443                                                               error))
5444                                 return -rte_errno;
5445                         action_flags |= actions->type ==
5446                                         RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
5447                                         MLX5_FLOW_ACTION_SET_MAC_SRC :
5448                                         MLX5_FLOW_ACTION_SET_MAC_DST;
5449                         break;
5450                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
5451                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
5452                         if (flow_dv_convert_action_modify_ipv4(&res, actions,
5453                                                                error))
5454                                 return -rte_errno;
5455                         action_flags |= actions->type ==
5456                                         RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
5457                                         MLX5_FLOW_ACTION_SET_IPV4_SRC :
5458                                         MLX5_FLOW_ACTION_SET_IPV4_DST;
5459                         break;
5460                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
5461                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
5462                         if (flow_dv_convert_action_modify_ipv6(&res, actions,
5463                                                                error))
5464                                 return -rte_errno;
5465                         action_flags |= actions->type ==
5466                                         RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
5467                                         MLX5_FLOW_ACTION_SET_IPV6_SRC :
5468                                         MLX5_FLOW_ACTION_SET_IPV6_DST;
5469                         break;
5470                 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
5471                 case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
5472                         if (flow_dv_convert_action_modify_tp(&res, actions,
5473                                                              items, &flow_attr,
5474                                                              error))
5475                                 return -rte_errno;
5476                         action_flags |= actions->type ==
5477                                         RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
5478                                         MLX5_FLOW_ACTION_SET_TP_SRC :
5479                                         MLX5_FLOW_ACTION_SET_TP_DST;
5480                         break;
5481                 case RTE_FLOW_ACTION_TYPE_DEC_TTL:
5482                         if (flow_dv_convert_action_modify_dec_ttl(&res, items,
5483                                                                   &flow_attr,
5484                                                                   error))
5485                                 return -rte_errno;
5486                         action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
5487                         break;
5488                 case RTE_FLOW_ACTION_TYPE_SET_TTL:
5489                         if (flow_dv_convert_action_modify_ttl(&res, actions,
5490                                                              items, &flow_attr,
5491                                                              error))
5492                                 return -rte_errno;
5493                         action_flags |= MLX5_FLOW_ACTION_SET_TTL;
5494                         break;
5495                 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
5496                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
5497                         if (flow_dv_convert_action_modify_tcp_seq(&res, actions,
5498                                                                   error))
5499                                 return -rte_errno;
5500                         action_flags |= actions->type ==
5501                                         RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
5502                                         MLX5_FLOW_ACTION_INC_TCP_SEQ :
5503                                         MLX5_FLOW_ACTION_DEC_TCP_SEQ;
5504                         break;
5505
5506                 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
5507                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
5508                         if (flow_dv_convert_action_modify_tcp_ack(&res, actions,
5509                                                                   error))
5510                                 return -rte_errno;
5511                         action_flags |= actions->type ==
5512                                         RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
5513                                         MLX5_FLOW_ACTION_INC_TCP_ACK :
5514                                         MLX5_FLOW_ACTION_DEC_TCP_ACK;
5515                         break;
5516                 case RTE_FLOW_ACTION_TYPE_END:
5517                         actions_end = true;
5518                         if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) {
5519                                 /* create modify action if needed. */
5520                                 if (flow_dv_modify_hdr_resource_register
5521                                                                 (dev, &res,
5522                                                                  dev_flow,
5523                                                                  error))
5524                                         return -rte_errno;
5525                                 dev_flow->dv.actions[modify_action_position] =
5526                                         dev_flow->dv.modify_hdr->verbs_action;
5527                         }
5528                         break;
5529                 default:
5530                         break;
5531                 }
5532                 if ((action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) &&
5533                     modify_action_position == UINT32_MAX)
5534                         modify_action_position = actions_n++;
5535         }
5536         dev_flow->dv.actions_n = actions_n;
5537         flow->actions = action_flags;
5538         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
5539                 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
5540
5541                 switch (items->type) {
5542                 case RTE_FLOW_ITEM_TYPE_PORT_ID:
5543                         flow_dv_translate_item_port_id(dev, match_mask,
5544                                                        match_value, items);
5545                         last_item = MLX5_FLOW_ITEM_PORT_ID;
5546                         break;
5547                 case RTE_FLOW_ITEM_TYPE_ETH:
5548                         flow_dv_translate_item_eth(match_mask, match_value,
5549                                                    items, tunnel);
5550                         matcher.priority = MLX5_PRIORITY_MAP_L2;
5551                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
5552                                              MLX5_FLOW_LAYER_OUTER_L2;
5553                         break;
5554                 case RTE_FLOW_ITEM_TYPE_VLAN:
5555                         flow_dv_translate_item_vlan(dev_flow,
5556                                                     match_mask, match_value,
5557                                                     items, tunnel);
5558                         matcher.priority = MLX5_PRIORITY_MAP_L2;
5559                         last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
5560                                               MLX5_FLOW_LAYER_INNER_VLAN) :
5561                                              (MLX5_FLOW_LAYER_OUTER_L2 |
5562                                               MLX5_FLOW_LAYER_OUTER_VLAN);
5563                         break;
5564                 case RTE_FLOW_ITEM_TYPE_IPV4:
5565                         mlx5_flow_tunnel_ip_check(items, next_protocol,
5566                                                   &item_flags, &tunnel);
5567                         flow_dv_translate_item_ipv4(match_mask, match_value,
5568                                                     items, tunnel, flow->group);
5569                         matcher.priority = MLX5_PRIORITY_MAP_L3;
5570                         dev_flow->dv.hash_fields |=
5571                                 mlx5_flow_hashfields_adjust
5572                                         (dev_flow, tunnel,
5573                                          MLX5_IPV4_LAYER_TYPES,
5574                                          MLX5_IPV4_IBV_RX_HASH);
5575                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
5576                                              MLX5_FLOW_LAYER_OUTER_L3_IPV4;
5577                         if (items->mask != NULL &&
5578                             ((const struct rte_flow_item_ipv4 *)
5579                              items->mask)->hdr.next_proto_id) {
5580                                 next_protocol =
5581                                         ((const struct rte_flow_item_ipv4 *)
5582                                          (items->spec))->hdr.next_proto_id;
5583                                 next_protocol &=
5584                                         ((const struct rte_flow_item_ipv4 *)
5585                                          (items->mask))->hdr.next_proto_id;
5586                         } else {
5587                                 /* Reset for inner layer. */
5588                                 next_protocol = 0xff;
5589                         }
5590                         break;
5591                 case RTE_FLOW_ITEM_TYPE_IPV6:
5592                         mlx5_flow_tunnel_ip_check(items, next_protocol,
5593                                                   &item_flags, &tunnel);
5594                         flow_dv_translate_item_ipv6(match_mask, match_value,
5595                                                     items, tunnel, flow->group);
5596                         matcher.priority = MLX5_PRIORITY_MAP_L3;
5597                         dev_flow->dv.hash_fields |=
5598                                 mlx5_flow_hashfields_adjust
5599                                         (dev_flow, tunnel,
5600                                          MLX5_IPV6_LAYER_TYPES,
5601                                          MLX5_IPV6_IBV_RX_HASH);
5602                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
5603                                              MLX5_FLOW_LAYER_OUTER_L3_IPV6;
5604                         if (items->mask != NULL &&
5605                             ((const struct rte_flow_item_ipv6 *)
5606                              items->mask)->hdr.proto) {
5607                                 next_protocol =
5608                                         ((const struct rte_flow_item_ipv6 *)
5609                                          items->spec)->hdr.proto;
5610                                 next_protocol &=
5611                                         ((const struct rte_flow_item_ipv6 *)
5612                                          items->mask)->hdr.proto;
5613                         } else {
5614                                 /* Reset for inner layer. */
5615                                 next_protocol = 0xff;
5616                         }
5617                         break;
5618                 case RTE_FLOW_ITEM_TYPE_TCP:
5619                         flow_dv_translate_item_tcp(match_mask, match_value,
5620                                                    items, tunnel);
5621                         matcher.priority = MLX5_PRIORITY_MAP_L4;
5622                         dev_flow->dv.hash_fields |=
5623                                 mlx5_flow_hashfields_adjust
5624                                         (dev_flow, tunnel, ETH_RSS_TCP,
5625                                          IBV_RX_HASH_SRC_PORT_TCP |
5626                                          IBV_RX_HASH_DST_PORT_TCP);
5627                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
5628                                              MLX5_FLOW_LAYER_OUTER_L4_TCP;
5629                         break;
5630                 case RTE_FLOW_ITEM_TYPE_UDP:
5631                         flow_dv_translate_item_udp(match_mask, match_value,
5632                                                    items, tunnel);
5633                         matcher.priority = MLX5_PRIORITY_MAP_L4;
5634                         dev_flow->dv.hash_fields |=
5635                                 mlx5_flow_hashfields_adjust
5636                                         (dev_flow, tunnel, ETH_RSS_UDP,
5637                                          IBV_RX_HASH_SRC_PORT_UDP |
5638                                          IBV_RX_HASH_DST_PORT_UDP);
5639                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
5640                                              MLX5_FLOW_LAYER_OUTER_L4_UDP;
5641                         break;
5642                 case RTE_FLOW_ITEM_TYPE_GRE:
5643                         flow_dv_translate_item_gre(match_mask, match_value,
5644                                                    items, tunnel);
5645                         last_item = MLX5_FLOW_LAYER_GRE;
5646                         break;
5647                 case RTE_FLOW_ITEM_TYPE_GRE_KEY:
5648                         flow_dv_translate_item_gre_key(match_mask,
5649                                                        match_value, items);
5650                         last_item = MLX5_FLOW_LAYER_GRE_KEY;
5651                         break;
5652                 case RTE_FLOW_ITEM_TYPE_NVGRE:
5653                         flow_dv_translate_item_nvgre(match_mask, match_value,
5654                                                      items, tunnel);
5655                         last_item = MLX5_FLOW_LAYER_GRE;
5656                         break;
5657                 case RTE_FLOW_ITEM_TYPE_VXLAN:
5658                         flow_dv_translate_item_vxlan(match_mask, match_value,
5659                                                      items, tunnel);
5660                         last_item = MLX5_FLOW_LAYER_VXLAN;
5661                         break;
5662                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
5663                         flow_dv_translate_item_vxlan(match_mask, match_value,
5664                                                      items, tunnel);
5665                         last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
5666                         break;
5667                 case RTE_FLOW_ITEM_TYPE_MPLS:
5668                         flow_dv_translate_item_mpls(match_mask, match_value,
5669                                                     items, last_item, tunnel);
5670                         last_item = MLX5_FLOW_LAYER_MPLS;
5671                         break;
5672                 case RTE_FLOW_ITEM_TYPE_META:
5673                         flow_dv_translate_item_meta(match_mask, match_value,
5674                                                     items);
5675                         last_item = MLX5_FLOW_ITEM_METADATA;
5676                         break;
5677                 case RTE_FLOW_ITEM_TYPE_ICMP:
5678                         flow_dv_translate_item_icmp(match_mask, match_value,
5679                                                     items, tunnel);
5680                         last_item = MLX5_FLOW_LAYER_ICMP;
5681                         break;
5682                 case RTE_FLOW_ITEM_TYPE_ICMP6:
5683                         flow_dv_translate_item_icmp6(match_mask, match_value,
5684                                                       items, tunnel);
5685                         last_item = MLX5_FLOW_LAYER_ICMP6;
5686                         break;
5687                 default:
5688                         break;
5689                 }
5690                 item_flags |= last_item;
5691         }
5692         /*
5693          * In case of ingress traffic when E-Switch mode is enabled,
5694          * we have two cases where we need to set the source port manually.
5695          * The first one, is in case of Nic steering rule, and the second is
5696          * E-Switch rule where no port_id item was found. In both cases
5697          * the source port is set according the current port in use.
5698          */
5699         if ((attr->ingress && !(item_flags & MLX5_FLOW_ITEM_PORT_ID)) &&
5700             (priv->representor || priv->master)) {
5701                 if (flow_dv_translate_item_port_id(dev, match_mask,
5702                                                    match_value, NULL))
5703                         return -rte_errno;
5704         }
5705         assert(!flow_dv_check_valid_spec(matcher.mask.buf,
5706                                          dev_flow->dv.value.buf));
5707         dev_flow->layers = item_flags;
5708         /* Register matcher. */
5709         matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
5710                                     matcher.mask.size);
5711         matcher.priority = mlx5_flow_adjust_priority(dev, priority,
5712                                                      matcher.priority);
5713         matcher.egress = attr->egress;
5714         matcher.group = flow->group;
5715         matcher.transfer = attr->transfer;
5716         if (flow_dv_matcher_register(dev, &matcher, dev_flow, error))
5717                 return -rte_errno;
5718         return 0;
5719 }
5720
5721 /**
5722  * Apply the flow to the NIC.
5723  *
5724  * @param[in] dev
5725  *   Pointer to the Ethernet device structure.
5726  * @param[in, out] flow
5727  *   Pointer to flow structure.
5728  * @param[out] error
5729  *   Pointer to error structure.
5730  *
5731  * @return
5732  *   0 on success, a negative errno value otherwise and rte_errno is set.
5733  */
5734 static int
5735 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
5736               struct rte_flow_error *error)
5737 {
5738         struct mlx5_flow_dv *dv;
5739         struct mlx5_flow *dev_flow;
5740         struct mlx5_priv *priv = dev->data->dev_private;
5741         int n;
5742         int err;
5743
5744         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
5745                 dv = &dev_flow->dv;
5746                 n = dv->actions_n;
5747                 if (flow->actions & MLX5_FLOW_ACTION_DROP) {
5748                         if (flow->transfer) {
5749                                 dv->actions[n++] = priv->sh->esw_drop_action;
5750                         } else {
5751                                 dv->hrxq = mlx5_hrxq_drop_new(dev);
5752                                 if (!dv->hrxq) {
5753                                         rte_flow_error_set
5754                                                 (error, errno,
5755                                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5756                                                  NULL,
5757                                                  "cannot get drop hash queue");
5758                                         goto error;
5759                                 }
5760                                 dv->actions[n++] = dv->hrxq->action;
5761                         }
5762                 } else if (flow->actions &
5763                            (MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)) {
5764                         struct mlx5_hrxq *hrxq;
5765
5766                         hrxq = mlx5_hrxq_get(dev, flow->key,
5767                                              MLX5_RSS_HASH_KEY_LEN,
5768                                              dv->hash_fields,
5769                                              (*flow->queue),
5770                                              flow->rss.queue_num);
5771                         if (!hrxq) {
5772                                 hrxq = mlx5_hrxq_new
5773                                         (dev, flow->key, MLX5_RSS_HASH_KEY_LEN,
5774                                          dv->hash_fields, (*flow->queue),
5775                                          flow->rss.queue_num,
5776                                          !!(dev_flow->layers &
5777                                             MLX5_FLOW_LAYER_TUNNEL));
5778                         }
5779                         if (!hrxq) {
5780                                 rte_flow_error_set
5781                                         (error, rte_errno,
5782                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5783                                          "cannot get hash queue");
5784                                 goto error;
5785                         }
5786                         dv->hrxq = hrxq;
5787                         dv->actions[n++] = dv->hrxq->action;
5788                 }
5789                 dv->flow =
5790                         mlx5_glue->dv_create_flow(dv->matcher->matcher_object,
5791                                                   (void *)&dv->value, n,
5792                                                   dv->actions);
5793                 if (!dv->flow) {
5794                         rte_flow_error_set(error, errno,
5795                                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5796                                            NULL,
5797                                            "hardware refuses to create flow");
5798                         goto error;
5799                 }
5800                 if (priv->vmwa_context &&
5801                     dev_flow->dv.vf_vlan.tag &&
5802                     !dev_flow->dv.vf_vlan.created) {
5803                         /*
5804                          * The rule contains the VLAN pattern.
5805                          * For VF we are going to create VLAN
5806                          * interface to make hypervisor set correct
5807                          * e-Switch vport context.
5808                          */
5809                         mlx5_vlan_vmwa_acquire(dev, &dev_flow->dv.vf_vlan);
5810                 }
5811         }
5812         return 0;
5813 error:
5814         err = rte_errno; /* Save rte_errno before cleanup. */
5815         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
5816                 struct mlx5_flow_dv *dv = &dev_flow->dv;
5817                 if (dv->hrxq) {
5818                         if (flow->actions & MLX5_FLOW_ACTION_DROP)
5819                                 mlx5_hrxq_drop_release(dev);
5820                         else
5821                                 mlx5_hrxq_release(dev, dv->hrxq);
5822                         dv->hrxq = NULL;
5823                 }
5824                 if (dev_flow->dv.vf_vlan.tag &&
5825                     dev_flow->dv.vf_vlan.created)
5826                         mlx5_vlan_vmwa_release(dev, &dev_flow->dv.vf_vlan);
5827         }
5828         rte_errno = err; /* Restore rte_errno. */
5829         return -rte_errno;
5830 }
5831
5832 /**
5833  * Release the flow matcher.
5834  *
5835  * @param dev
5836  *   Pointer to Ethernet device.
5837  * @param flow
5838  *   Pointer to mlx5_flow.
5839  *
5840  * @return
5841  *   1 while a reference on it exists, 0 when freed.
5842  */
5843 static int
5844 flow_dv_matcher_release(struct rte_eth_dev *dev,
5845                         struct mlx5_flow *flow)
5846 {
5847         struct mlx5_flow_dv_matcher *matcher = flow->dv.matcher;
5848         struct mlx5_priv *priv = dev->data->dev_private;
5849         struct mlx5_ibv_shared *sh = priv->sh;
5850         struct mlx5_flow_tbl_resource *tbl;
5851
5852         assert(matcher->matcher_object);
5853         DRV_LOG(DEBUG, "port %u matcher %p: refcnt %d--",
5854                 dev->data->port_id, (void *)matcher,
5855                 rte_atomic32_read(&matcher->refcnt));
5856         if (rte_atomic32_dec_and_test(&matcher->refcnt)) {
5857                 claim_zero(mlx5_glue->dv_destroy_flow_matcher
5858                            (matcher->matcher_object));
5859                 LIST_REMOVE(matcher, next);
5860                 if (matcher->egress)
5861                         tbl = &sh->tx_tbl[matcher->group];
5862                 else
5863                         tbl = &sh->rx_tbl[matcher->group];
5864                 flow_dv_tbl_resource_release(tbl);
5865                 rte_free(matcher);
5866                 DRV_LOG(DEBUG, "port %u matcher %p: removed",
5867                         dev->data->port_id, (void *)matcher);
5868                 return 0;
5869         }
5870         return 1;
5871 }
5872
5873 /**
5874  * Release an encap/decap resource.
5875  *
5876  * @param flow
5877  *   Pointer to mlx5_flow.
5878  *
5879  * @return
5880  *   1 while a reference on it exists, 0 when freed.
5881  */
5882 static int
5883 flow_dv_encap_decap_resource_release(struct mlx5_flow *flow)
5884 {
5885         struct mlx5_flow_dv_encap_decap_resource *cache_resource =
5886                                                 flow->dv.encap_decap;
5887
5888         assert(cache_resource->verbs_action);
5889         DRV_LOG(DEBUG, "encap/decap resource %p: refcnt %d--",
5890                 (void *)cache_resource,
5891                 rte_atomic32_read(&cache_resource->refcnt));
5892         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
5893                 claim_zero(mlx5_glue->destroy_flow_action
5894                                 (cache_resource->verbs_action));
5895                 LIST_REMOVE(cache_resource, next);
5896                 rte_free(cache_resource);
5897                 DRV_LOG(DEBUG, "encap/decap resource %p: removed",
5898                         (void *)cache_resource);
5899                 return 0;
5900         }
5901         return 1;
5902 }
5903
5904 /**
5905  * Release an jump to table action resource.
5906  *
5907  * @param flow
5908  *   Pointer to mlx5_flow.
5909  *
5910  * @return
5911  *   1 while a reference on it exists, 0 when freed.
5912  */
5913 static int
5914 flow_dv_jump_tbl_resource_release(struct mlx5_flow *flow)
5915 {
5916         struct mlx5_flow_dv_jump_tbl_resource *cache_resource =
5917                                                 flow->dv.jump;
5918
5919         assert(cache_resource->action);
5920         DRV_LOG(DEBUG, "jump table resource %p: refcnt %d--",
5921                 (void *)cache_resource,
5922                 rte_atomic32_read(&cache_resource->refcnt));
5923         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
5924                 claim_zero(mlx5_glue->destroy_flow_action
5925                                 (cache_resource->action));
5926                 LIST_REMOVE(cache_resource, next);
5927                 flow_dv_tbl_resource_release(cache_resource->tbl);
5928                 rte_free(cache_resource);
5929                 DRV_LOG(DEBUG, "jump table resource %p: removed",
5930                         (void *)cache_resource);
5931                 return 0;
5932         }
5933         return 1;
5934 }
5935
5936 /**
5937  * Release a modify-header resource.
5938  *
5939  * @param flow
5940  *   Pointer to mlx5_flow.
5941  *
5942  * @return
5943  *   1 while a reference on it exists, 0 when freed.
5944  */
5945 static int
5946 flow_dv_modify_hdr_resource_release(struct mlx5_flow *flow)
5947 {
5948         struct mlx5_flow_dv_modify_hdr_resource *cache_resource =
5949                                                 flow->dv.modify_hdr;
5950
5951         assert(cache_resource->verbs_action);
5952         DRV_LOG(DEBUG, "modify-header resource %p: refcnt %d--",
5953                 (void *)cache_resource,
5954                 rte_atomic32_read(&cache_resource->refcnt));
5955         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
5956                 claim_zero(mlx5_glue->destroy_flow_action
5957                                 (cache_resource->verbs_action));
5958                 LIST_REMOVE(cache_resource, next);
5959                 rte_free(cache_resource);
5960                 DRV_LOG(DEBUG, "modify-header resource %p: removed",
5961                         (void *)cache_resource);
5962                 return 0;
5963         }
5964         return 1;
5965 }
5966
5967 /**
5968  * Release port ID action resource.
5969  *
5970  * @param flow
5971  *   Pointer to mlx5_flow.
5972  *
5973  * @return
5974  *   1 while a reference on it exists, 0 when freed.
5975  */
5976 static int
5977 flow_dv_port_id_action_resource_release(struct mlx5_flow *flow)
5978 {
5979         struct mlx5_flow_dv_port_id_action_resource *cache_resource =
5980                 flow->dv.port_id_action;
5981
5982         assert(cache_resource->action);
5983         DRV_LOG(DEBUG, "port ID action resource %p: refcnt %d--",
5984                 (void *)cache_resource,
5985                 rte_atomic32_read(&cache_resource->refcnt));
5986         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
5987                 claim_zero(mlx5_glue->destroy_flow_action
5988                                 (cache_resource->action));
5989                 LIST_REMOVE(cache_resource, next);
5990                 rte_free(cache_resource);
5991                 DRV_LOG(DEBUG, "port id action resource %p: removed",
5992                         (void *)cache_resource);
5993                 return 0;
5994         }
5995         return 1;
5996 }
5997
5998 /**
5999  * Release push vlan action resource.
6000  *
6001  * @param flow
6002  *   Pointer to mlx5_flow.
6003  *
6004  * @return
6005  *   1 while a reference on it exists, 0 when freed.
6006  */
6007 static int
6008 flow_dv_push_vlan_action_resource_release(struct mlx5_flow *flow)
6009 {
6010         struct mlx5_flow_dv_push_vlan_action_resource *cache_resource =
6011                 flow->dv.push_vlan_res;
6012
6013         assert(cache_resource->action);
6014         DRV_LOG(DEBUG, "push VLAN action resource %p: refcnt %d--",
6015                 (void *)cache_resource,
6016                 rte_atomic32_read(&cache_resource->refcnt));
6017         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
6018                 claim_zero(mlx5_glue->destroy_flow_action
6019                                 (cache_resource->action));
6020                 LIST_REMOVE(cache_resource, next);
6021                 rte_free(cache_resource);
6022                 DRV_LOG(DEBUG, "push vlan action resource %p: removed",
6023                         (void *)cache_resource);
6024                 return 0;
6025         }
6026         return 1;
6027 }
6028
6029 /**
6030  * Remove the flow from the NIC but keeps it in memory.
6031  *
6032  * @param[in] dev
6033  *   Pointer to Ethernet device.
6034  * @param[in, out] flow
6035  *   Pointer to flow structure.
6036  */
6037 static void
6038 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
6039 {
6040         struct mlx5_flow_dv *dv;
6041         struct mlx5_flow *dev_flow;
6042
6043         if (!flow)
6044                 return;
6045         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
6046                 dv = &dev_flow->dv;
6047                 if (dv->flow) {
6048                         claim_zero(mlx5_glue->dv_destroy_flow(dv->flow));
6049                         dv->flow = NULL;
6050                 }
6051                 if (dv->hrxq) {
6052                         if (flow->actions & MLX5_FLOW_ACTION_DROP)
6053                                 mlx5_hrxq_drop_release(dev);
6054                         else
6055                                 mlx5_hrxq_release(dev, dv->hrxq);
6056                         dv->hrxq = NULL;
6057                 }
6058                 if (dev_flow->dv.vf_vlan.tag &&
6059                     dev_flow->dv.vf_vlan.created)
6060                         mlx5_vlan_vmwa_release(dev, &dev_flow->dv.vf_vlan);
6061         }
6062 }
6063
6064 /**
6065  * Remove the flow from the NIC and the memory.
6066  *
6067  * @param[in] dev
6068  *   Pointer to the Ethernet device structure.
6069  * @param[in, out] flow
6070  *   Pointer to flow structure.
6071  */
6072 static void
6073 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
6074 {
6075         struct mlx5_flow *dev_flow;
6076
6077         if (!flow)
6078                 return;
6079         flow_dv_remove(dev, flow);
6080         if (flow->counter) {
6081                 flow_dv_counter_release(dev, flow->counter);
6082                 flow->counter = NULL;
6083         }
6084         if (flow->tag_resource) {
6085                 flow_dv_tag_release(dev, flow->tag_resource);
6086                 flow->tag_resource = NULL;
6087         }
6088         while (!LIST_EMPTY(&flow->dev_flows)) {
6089                 dev_flow = LIST_FIRST(&flow->dev_flows);
6090                 LIST_REMOVE(dev_flow, next);
6091                 if (dev_flow->dv.matcher)
6092                         flow_dv_matcher_release(dev, dev_flow);
6093                 if (dev_flow->dv.encap_decap)
6094                         flow_dv_encap_decap_resource_release(dev_flow);
6095                 if (dev_flow->dv.modify_hdr)
6096                         flow_dv_modify_hdr_resource_release(dev_flow);
6097                 if (dev_flow->dv.jump)
6098                         flow_dv_jump_tbl_resource_release(dev_flow);
6099                 if (dev_flow->dv.port_id_action)
6100                         flow_dv_port_id_action_resource_release(dev_flow);
6101                 if (dev_flow->dv.push_vlan_res)
6102                         flow_dv_push_vlan_action_resource_release(dev_flow);
6103                 rte_free(dev_flow);
6104         }
6105 }
6106
6107 /**
6108  * Query a dv flow  rule for its statistics via devx.
6109  *
6110  * @param[in] dev
6111  *   Pointer to Ethernet device.
6112  * @param[in] flow
6113  *   Pointer to the sub flow.
6114  * @param[out] data
6115  *   data retrieved by the query.
6116  * @param[out] error
6117  *   Perform verbose error reporting if not NULL.
6118  *
6119  * @return
6120  *   0 on success, a negative errno value otherwise and rte_errno is set.
6121  */
6122 static int
6123 flow_dv_query_count(struct rte_eth_dev *dev, struct rte_flow *flow,
6124                     void *data, struct rte_flow_error *error)
6125 {
6126         struct mlx5_priv *priv = dev->data->dev_private;
6127         struct rte_flow_query_count *qc = data;
6128
6129         if (!priv->config.devx)
6130                 return rte_flow_error_set(error, ENOTSUP,
6131                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6132                                           NULL,
6133                                           "counters are not supported");
6134         if (flow->counter) {
6135                 uint64_t pkts, bytes;
6136                 int err = _flow_dv_query_count(dev, flow->counter, &pkts,
6137                                                &bytes);
6138
6139                 if (err)
6140                         return rte_flow_error_set(error, -err,
6141                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6142                                         NULL, "cannot read counters");
6143                 qc->hits_set = 1;
6144                 qc->bytes_set = 1;
6145                 qc->hits = pkts - flow->counter->hits;
6146                 qc->bytes = bytes - flow->counter->bytes;
6147                 if (qc->reset) {
6148                         flow->counter->hits = pkts;
6149                         flow->counter->bytes = bytes;
6150                 }
6151                 return 0;
6152         }
6153         return rte_flow_error_set(error, EINVAL,
6154                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6155                                   NULL,
6156                                   "counters are not available");
6157 }
6158
6159 /**
6160  * Query a flow.
6161  *
6162  * @see rte_flow_query()
6163  * @see rte_flow_ops
6164  */
6165 static int
6166 flow_dv_query(struct rte_eth_dev *dev,
6167               struct rte_flow *flow __rte_unused,
6168               const struct rte_flow_action *actions __rte_unused,
6169               void *data __rte_unused,
6170               struct rte_flow_error *error __rte_unused)
6171 {
6172         int ret = -EINVAL;
6173
6174         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
6175                 switch (actions->type) {
6176                 case RTE_FLOW_ACTION_TYPE_VOID:
6177                         break;
6178                 case RTE_FLOW_ACTION_TYPE_COUNT:
6179                         ret = flow_dv_query_count(dev, flow, data, error);
6180                         break;
6181                 default:
6182                         return rte_flow_error_set(error, ENOTSUP,
6183                                                   RTE_FLOW_ERROR_TYPE_ACTION,
6184                                                   actions,
6185                                                   "action not supported");
6186                 }
6187         }
6188         return ret;
6189 }
6190
6191 /*
6192  * Mutex-protected thunk to flow_dv_translate().
6193  */
6194 static int
6195 flow_d_translate(struct rte_eth_dev *dev,
6196                  struct mlx5_flow *dev_flow,
6197                  const struct rte_flow_attr *attr,
6198                  const struct rte_flow_item items[],
6199                  const struct rte_flow_action actions[],
6200                  struct rte_flow_error *error)
6201 {
6202         int ret;
6203
6204         flow_d_shared_lock(dev);
6205         ret = flow_dv_translate(dev, dev_flow, attr, items, actions, error);
6206         flow_d_shared_unlock(dev);
6207         return ret;
6208 }
6209
6210 /*
6211  * Mutex-protected thunk to flow_dv_apply().
6212  */
6213 static int
6214 flow_d_apply(struct rte_eth_dev *dev,
6215              struct rte_flow *flow,
6216              struct rte_flow_error *error)
6217 {
6218         int ret;
6219
6220         flow_d_shared_lock(dev);
6221         ret = flow_dv_apply(dev, flow, error);
6222         flow_d_shared_unlock(dev);
6223         return ret;
6224 }
6225
6226 /*
6227  * Mutex-protected thunk to flow_dv_remove().
6228  */
6229 static void
6230 flow_d_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
6231 {
6232         flow_d_shared_lock(dev);
6233         flow_dv_remove(dev, flow);
6234         flow_d_shared_unlock(dev);
6235 }
6236
6237 /*
6238  * Mutex-protected thunk to flow_dv_destroy().
6239  */
6240 static void
6241 flow_d_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
6242 {
6243         flow_d_shared_lock(dev);
6244         flow_dv_destroy(dev, flow);
6245         flow_d_shared_unlock(dev);
6246 }
6247
6248 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
6249         .validate = flow_dv_validate,
6250         .prepare = flow_dv_prepare,
6251         .translate = flow_d_translate,
6252         .apply = flow_d_apply,
6253         .remove = flow_d_remove,
6254         .destroy = flow_d_destroy,
6255         .query = flow_dv_query,
6256 };
6257
6258 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */