330a86812be3159a4ce93fb677300ca25ddcbc74
[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] group
2370  *   The group of the current flow.
2371  * @param[out] error
2372  *   Pointer to error structure.
2373  *
2374  * @return
2375  *   0 on success, a negative errno value otherwise and rte_errno is set.
2376  */
2377 static int
2378 flow_dv_validate_action_jump(const struct rte_flow_action *action,
2379                              uint64_t action_flags,
2380                              uint32_t group,
2381                              struct rte_flow_error *error)
2382 {
2383         if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
2384                             MLX5_FLOW_FATE_ESWITCH_ACTIONS))
2385                 return rte_flow_error_set(error, EINVAL,
2386                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2387                                           "can't have 2 fate actions in"
2388                                           " same flow");
2389         if (!action->conf)
2390                 return rte_flow_error_set(error, EINVAL,
2391                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
2392                                           NULL, "action configuration not set");
2393         if (group >= ((const struct rte_flow_action_jump *)action->conf)->group)
2394                 return rte_flow_error_set(error, EINVAL,
2395                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2396                                           "target group must be higher then"
2397                                           " the current flow group");
2398         return 0;
2399 }
2400
2401 /*
2402  * Validate the port_id action.
2403  *
2404  * @param[in] dev
2405  *   Pointer to rte_eth_dev structure.
2406  * @param[in] action_flags
2407  *   Bit-fields that holds the actions detected until now.
2408  * @param[in] action
2409  *   Port_id RTE action structure.
2410  * @param[in] attr
2411  *   Attributes of flow that includes this action.
2412  * @param[out] error
2413  *   Pointer to error structure.
2414  *
2415  * @return
2416  *   0 on success, a negative errno value otherwise and rte_errno is set.
2417  */
2418 static int
2419 flow_dv_validate_action_port_id(struct rte_eth_dev *dev,
2420                                 uint64_t action_flags,
2421                                 const struct rte_flow_action *action,
2422                                 const struct rte_flow_attr *attr,
2423                                 struct rte_flow_error *error)
2424 {
2425         const struct rte_flow_action_port_id *port_id;
2426         uint16_t port;
2427         uint16_t esw_domain_id;
2428         uint16_t act_port_domain_id;
2429         int ret;
2430
2431         if (!attr->transfer)
2432                 return rte_flow_error_set(error, ENOTSUP,
2433                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2434                                           NULL,
2435                                           "port id action is valid in transfer"
2436                                           " mode only");
2437         if (!action || !action->conf)
2438                 return rte_flow_error_set(error, ENOTSUP,
2439                                           RTE_FLOW_ERROR_TYPE_ACTION_CONF,
2440                                           NULL,
2441                                           "port id action parameters must be"
2442                                           " specified");
2443         if (action_flags & (MLX5_FLOW_FATE_ACTIONS |
2444                             MLX5_FLOW_FATE_ESWITCH_ACTIONS))
2445                 return rte_flow_error_set(error, EINVAL,
2446                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2447                                           "can have only one fate actions in"
2448                                           " a flow");
2449         ret = mlx5_port_to_eswitch_info(dev->data->port_id,
2450                                         &esw_domain_id, NULL);
2451         if (ret < 0)
2452                 return rte_flow_error_set(error, -ret,
2453                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2454                                           NULL,
2455                                           "failed to obtain E-Switch info");
2456         port_id = action->conf;
2457         port = port_id->original ? dev->data->port_id : port_id->id;
2458         ret = mlx5_port_to_eswitch_info(port, &act_port_domain_id, NULL);
2459         if (ret)
2460                 return rte_flow_error_set
2461                                 (error, -ret,
2462                                  RTE_FLOW_ERROR_TYPE_ACTION_CONF, port_id,
2463                                  "failed to obtain E-Switch port id for port");
2464         if (act_port_domain_id != esw_domain_id)
2465                 return rte_flow_error_set
2466                                 (error, -ret,
2467                                  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
2468                                  "port does not belong to"
2469                                  " E-Switch being configured");
2470         return 0;
2471 }
2472
2473 /**
2474  * Find existing modify-header resource or create and register a new one.
2475  *
2476  * @param dev[in, out]
2477  *   Pointer to rte_eth_dev structure.
2478  * @param[in, out] resource
2479  *   Pointer to modify-header resource.
2480  * @parm[in, out] dev_flow
2481  *   Pointer to the dev_flow.
2482  * @param[out] error
2483  *   pointer to error structure.
2484  *
2485  * @return
2486  *   0 on success otherwise -errno and errno is set.
2487  */
2488 static int
2489 flow_dv_modify_hdr_resource_register
2490                         (struct rte_eth_dev *dev,
2491                          struct mlx5_flow_dv_modify_hdr_resource *resource,
2492                          struct mlx5_flow *dev_flow,
2493                          struct rte_flow_error *error)
2494 {
2495         struct mlx5_priv *priv = dev->data->dev_private;
2496         struct mlx5_ibv_shared *sh = priv->sh;
2497         struct mlx5_flow_dv_modify_hdr_resource *cache_resource;
2498         struct mlx5dv_dr_domain *ns;
2499
2500         if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_FDB)
2501                 ns = sh->fdb_domain;
2502         else if (resource->ft_type == MLX5DV_FLOW_TABLE_TYPE_NIC_TX)
2503                 ns = sh->tx_domain;
2504         else
2505                 ns = sh->rx_domain;
2506         resource->flags =
2507                 dev_flow->flow->group ? 0 : MLX5DV_DR_ACTION_FLAGS_ROOT_LEVEL;
2508         /* Lookup a matching resource from cache. */
2509         LIST_FOREACH(cache_resource, &sh->modify_cmds, next) {
2510                 if (resource->ft_type == cache_resource->ft_type &&
2511                     resource->actions_num == cache_resource->actions_num &&
2512                     resource->flags == cache_resource->flags &&
2513                     !memcmp((const void *)resource->actions,
2514                             (const void *)cache_resource->actions,
2515                             (resource->actions_num *
2516                                             sizeof(resource->actions[0])))) {
2517                         DRV_LOG(DEBUG, "modify-header resource %p: refcnt %d++",
2518                                 (void *)cache_resource,
2519                                 rte_atomic32_read(&cache_resource->refcnt));
2520                         rte_atomic32_inc(&cache_resource->refcnt);
2521                         dev_flow->dv.modify_hdr = cache_resource;
2522                         return 0;
2523                 }
2524         }
2525         /* Register new modify-header resource. */
2526         cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
2527         if (!cache_resource)
2528                 return rte_flow_error_set(error, ENOMEM,
2529                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2530                                           "cannot allocate resource memory");
2531         *cache_resource = *resource;
2532         cache_resource->verbs_action =
2533                 mlx5_glue->dv_create_flow_action_modify_header
2534                                         (sh->ctx, cache_resource->ft_type,
2535                                          ns, cache_resource->flags,
2536                                          cache_resource->actions_num *
2537                                          sizeof(cache_resource->actions[0]),
2538                                          (uint64_t *)cache_resource->actions);
2539         if (!cache_resource->verbs_action) {
2540                 rte_free(cache_resource);
2541                 return rte_flow_error_set(error, ENOMEM,
2542                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2543                                           NULL, "cannot create action");
2544         }
2545         rte_atomic32_init(&cache_resource->refcnt);
2546         rte_atomic32_inc(&cache_resource->refcnt);
2547         LIST_INSERT_HEAD(&sh->modify_cmds, cache_resource, next);
2548         dev_flow->dv.modify_hdr = cache_resource;
2549         DRV_LOG(DEBUG, "new modify-header resource %p: refcnt %d++",
2550                 (void *)cache_resource,
2551                 rte_atomic32_read(&cache_resource->refcnt));
2552         return 0;
2553 }
2554
2555 #define MLX5_CNT_CONTAINER_RESIZE 64
2556
2557 /**
2558  * Get or create a flow counter.
2559  *
2560  * @param[in] dev
2561  *   Pointer to the Ethernet device structure.
2562  * @param[in] shared
2563  *   Indicate if this counter is shared with other flows.
2564  * @param[in] id
2565  *   Counter identifier.
2566  *
2567  * @return
2568  *   pointer to flow counter on success, NULL otherwise and rte_errno is set.
2569  */
2570 static struct mlx5_flow_counter *
2571 flow_dv_counter_alloc_fallback(struct rte_eth_dev *dev, uint32_t shared,
2572                                uint32_t id)
2573 {
2574         struct mlx5_priv *priv = dev->data->dev_private;
2575         struct mlx5_flow_counter *cnt = NULL;
2576         struct mlx5_devx_obj *dcs = NULL;
2577
2578         if (!priv->config.devx) {
2579                 rte_errno = ENOTSUP;
2580                 return NULL;
2581         }
2582         if (shared) {
2583                 TAILQ_FOREACH(cnt, &priv->sh->cmng.flow_counters, next) {
2584                         if (cnt->shared && cnt->id == id) {
2585                                 cnt->ref_cnt++;
2586                                 return cnt;
2587                         }
2588                 }
2589         }
2590         dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
2591         if (!dcs)
2592                 return NULL;
2593         cnt = rte_calloc(__func__, 1, sizeof(*cnt), 0);
2594         if (!cnt) {
2595                 claim_zero(mlx5_devx_cmd_destroy(cnt->dcs));
2596                 rte_errno = ENOMEM;
2597                 return NULL;
2598         }
2599         struct mlx5_flow_counter tmpl = {
2600                 .shared = shared,
2601                 .ref_cnt = 1,
2602                 .id = id,
2603                 .dcs = dcs,
2604         };
2605         tmpl.action = mlx5_glue->dv_create_flow_action_counter(dcs->obj, 0);
2606         if (!tmpl.action) {
2607                 claim_zero(mlx5_devx_cmd_destroy(cnt->dcs));
2608                 rte_errno = errno;
2609                 rte_free(cnt);
2610                 return NULL;
2611         }
2612         *cnt = tmpl;
2613         TAILQ_INSERT_HEAD(&priv->sh->cmng.flow_counters, cnt, next);
2614         return cnt;
2615 }
2616
2617 /**
2618  * Release a flow counter.
2619  *
2620  * @param[in] dev
2621  *   Pointer to the Ethernet device structure.
2622  * @param[in] counter
2623  *   Pointer to the counter handler.
2624  */
2625 static void
2626 flow_dv_counter_release_fallback(struct rte_eth_dev *dev,
2627                                  struct mlx5_flow_counter *counter)
2628 {
2629         struct mlx5_priv *priv = dev->data->dev_private;
2630
2631         if (!counter)
2632                 return;
2633         if (--counter->ref_cnt == 0) {
2634                 TAILQ_REMOVE(&priv->sh->cmng.flow_counters, counter, next);
2635                 claim_zero(mlx5_devx_cmd_destroy(counter->dcs));
2636                 rte_free(counter);
2637         }
2638 }
2639
2640 /**
2641  * Query a devx flow counter.
2642  *
2643  * @param[in] dev
2644  *   Pointer to the Ethernet device structure.
2645  * @param[in] cnt
2646  *   Pointer to the flow counter.
2647  * @param[out] pkts
2648  *   The statistics value of packets.
2649  * @param[out] bytes
2650  *   The statistics value of bytes.
2651  *
2652  * @return
2653  *   0 on success, otherwise a negative errno value and rte_errno is set.
2654  */
2655 static inline int
2656 _flow_dv_query_count_fallback(struct rte_eth_dev *dev __rte_unused,
2657                      struct mlx5_flow_counter *cnt, uint64_t *pkts,
2658                      uint64_t *bytes)
2659 {
2660         return mlx5_devx_cmd_flow_counter_query(cnt->dcs, 0, 0, pkts, bytes,
2661                                                 0, NULL, NULL, 0);
2662 }
2663
2664 /**
2665  * Get a pool by a counter.
2666  *
2667  * @param[in] cnt
2668  *   Pointer to the counter.
2669  *
2670  * @return
2671  *   The counter pool.
2672  */
2673 static struct mlx5_flow_counter_pool *
2674 flow_dv_counter_pool_get(struct mlx5_flow_counter *cnt)
2675 {
2676         if (!cnt->batch) {
2677                 cnt -= cnt->dcs->id % MLX5_COUNTERS_PER_POOL;
2678                 return (struct mlx5_flow_counter_pool *)cnt - 1;
2679         }
2680         return cnt->pool;
2681 }
2682
2683 /**
2684  * Get a pool by devx counter ID.
2685  *
2686  * @param[in] cont
2687  *   Pointer to the counter container.
2688  * @param[in] id
2689  *   The counter devx ID.
2690  *
2691  * @return
2692  *   The counter pool pointer if exists, NULL otherwise,
2693  */
2694 static struct mlx5_flow_counter_pool *
2695 flow_dv_find_pool_by_id(struct mlx5_pools_container *cont, int id)
2696 {
2697         struct mlx5_flow_counter_pool *pool;
2698
2699         TAILQ_FOREACH(pool, &cont->pool_list, next) {
2700                 int base = (pool->min_dcs->id / MLX5_COUNTERS_PER_POOL) *
2701                                 MLX5_COUNTERS_PER_POOL;
2702
2703                 if (id >= base && id < base + MLX5_COUNTERS_PER_POOL)
2704                         return pool;
2705         };
2706         return NULL;
2707 }
2708
2709 /**
2710  * Allocate a new memory for the counter values wrapped by all the needed
2711  * management.
2712  *
2713  * @param[in] dev
2714  *   Pointer to the Ethernet device structure.
2715  * @param[in] raws_n
2716  *   The raw memory areas - each one for MLX5_COUNTERS_PER_POOL counters.
2717  *
2718  * @return
2719  *   The new memory management pointer on success, otherwise NULL and rte_errno
2720  *   is set.
2721  */
2722 static struct mlx5_counter_stats_mem_mng *
2723 flow_dv_create_counter_stat_mem_mng(struct rte_eth_dev *dev, int raws_n)
2724 {
2725         struct mlx5_ibv_shared *sh = ((struct mlx5_priv *)
2726                                         (dev->data->dev_private))->sh;
2727         struct mlx5_devx_mkey_attr mkey_attr;
2728         struct mlx5_counter_stats_mem_mng *mem_mng;
2729         volatile struct flow_counter_stats *raw_data;
2730         int size = (sizeof(struct flow_counter_stats) *
2731                         MLX5_COUNTERS_PER_POOL +
2732                         sizeof(struct mlx5_counter_stats_raw)) * raws_n +
2733                         sizeof(struct mlx5_counter_stats_mem_mng);
2734         uint8_t *mem = rte_calloc(__func__, 1, size, sysconf(_SC_PAGESIZE));
2735         int i;
2736
2737         if (!mem) {
2738                 rte_errno = ENOMEM;
2739                 return NULL;
2740         }
2741         mem_mng = (struct mlx5_counter_stats_mem_mng *)(mem + size) - 1;
2742         size = sizeof(*raw_data) * MLX5_COUNTERS_PER_POOL * raws_n;
2743         mem_mng->umem = mlx5_glue->devx_umem_reg(sh->ctx, mem, size,
2744                                                  IBV_ACCESS_LOCAL_WRITE);
2745         if (!mem_mng->umem) {
2746                 rte_errno = errno;
2747                 rte_free(mem);
2748                 return NULL;
2749         }
2750         mkey_attr.addr = (uintptr_t)mem;
2751         mkey_attr.size = size;
2752         mkey_attr.umem_id = mem_mng->umem->umem_id;
2753         mkey_attr.pd = sh->pdn;
2754         mem_mng->dm = mlx5_devx_cmd_mkey_create(sh->ctx, &mkey_attr);
2755         if (!mem_mng->dm) {
2756                 mlx5_glue->devx_umem_dereg(mem_mng->umem);
2757                 rte_errno = errno;
2758                 rte_free(mem);
2759                 return NULL;
2760         }
2761         mem_mng->raws = (struct mlx5_counter_stats_raw *)(mem + size);
2762         raw_data = (volatile struct flow_counter_stats *)mem;
2763         for (i = 0; i < raws_n; ++i) {
2764                 mem_mng->raws[i].mem_mng = mem_mng;
2765                 mem_mng->raws[i].data = raw_data + i * MLX5_COUNTERS_PER_POOL;
2766         }
2767         LIST_INSERT_HEAD(&sh->cmng.mem_mngs, mem_mng, next);
2768         return mem_mng;
2769 }
2770
2771 /**
2772  * Resize a counter container.
2773  *
2774  * @param[in] dev
2775  *   Pointer to the Ethernet device structure.
2776  * @param[in] batch
2777  *   Whether the pool is for counter that was allocated by batch command.
2778  *
2779  * @return
2780  *   The new container pointer on success, otherwise NULL and rte_errno is set.
2781  */
2782 static struct mlx5_pools_container *
2783 flow_dv_container_resize(struct rte_eth_dev *dev, uint32_t batch)
2784 {
2785         struct mlx5_priv *priv = dev->data->dev_private;
2786         struct mlx5_pools_container *cont =
2787                         MLX5_CNT_CONTAINER(priv->sh, batch, 0);
2788         struct mlx5_pools_container *new_cont =
2789                         MLX5_CNT_CONTAINER_UNUSED(priv->sh, batch, 0);
2790         struct mlx5_counter_stats_mem_mng *mem_mng;
2791         uint32_t resize = cont->n + MLX5_CNT_CONTAINER_RESIZE;
2792         uint32_t mem_size = sizeof(struct mlx5_flow_counter_pool *) * resize;
2793         int i;
2794
2795         if (cont != MLX5_CNT_CONTAINER(priv->sh, batch, 1)) {
2796                 /* The last resize still hasn't detected by the host thread. */
2797                 rte_errno = EAGAIN;
2798                 return NULL;
2799         }
2800         new_cont->pools = rte_calloc(__func__, 1, mem_size, 0);
2801         if (!new_cont->pools) {
2802                 rte_errno = ENOMEM;
2803                 return NULL;
2804         }
2805         if (cont->n)
2806                 memcpy(new_cont->pools, cont->pools, cont->n *
2807                        sizeof(struct mlx5_flow_counter_pool *));
2808         mem_mng = flow_dv_create_counter_stat_mem_mng(dev,
2809                 MLX5_CNT_CONTAINER_RESIZE + MLX5_MAX_PENDING_QUERIES);
2810         if (!mem_mng) {
2811                 rte_free(new_cont->pools);
2812                 return NULL;
2813         }
2814         for (i = 0; i < MLX5_MAX_PENDING_QUERIES; ++i)
2815                 LIST_INSERT_HEAD(&priv->sh->cmng.free_stat_raws,
2816                                  mem_mng->raws + MLX5_CNT_CONTAINER_RESIZE +
2817                                  i, next);
2818         new_cont->n = resize;
2819         rte_atomic16_set(&new_cont->n_valid, rte_atomic16_read(&cont->n_valid));
2820         TAILQ_INIT(&new_cont->pool_list);
2821         TAILQ_CONCAT(&new_cont->pool_list, &cont->pool_list, next);
2822         new_cont->init_mem_mng = mem_mng;
2823         rte_cio_wmb();
2824          /* Flip the master container. */
2825         priv->sh->cmng.mhi[batch] ^= (uint8_t)1;
2826         return new_cont;
2827 }
2828
2829 /**
2830  * Query a devx flow counter.
2831  *
2832  * @param[in] dev
2833  *   Pointer to the Ethernet device structure.
2834  * @param[in] cnt
2835  *   Pointer to the flow counter.
2836  * @param[out] pkts
2837  *   The statistics value of packets.
2838  * @param[out] bytes
2839  *   The statistics value of bytes.
2840  *
2841  * @return
2842  *   0 on success, otherwise a negative errno value and rte_errno is set.
2843  */
2844 static inline int
2845 _flow_dv_query_count(struct rte_eth_dev *dev,
2846                      struct mlx5_flow_counter *cnt, uint64_t *pkts,
2847                      uint64_t *bytes)
2848 {
2849         struct mlx5_priv *priv = dev->data->dev_private;
2850         struct mlx5_flow_counter_pool *pool =
2851                         flow_dv_counter_pool_get(cnt);
2852         int offset = cnt - &pool->counters_raw[0];
2853
2854         if (priv->counter_fallback)
2855                 return _flow_dv_query_count_fallback(dev, cnt, pkts, bytes);
2856
2857         rte_spinlock_lock(&pool->sl);
2858         /*
2859          * The single counters allocation may allocate smaller ID than the
2860          * current allocated in parallel to the host reading.
2861          * In this case the new counter values must be reported as 0.
2862          */
2863         if (unlikely(!cnt->batch && cnt->dcs->id < pool->raw->min_dcs_id)) {
2864                 *pkts = 0;
2865                 *bytes = 0;
2866         } else {
2867                 *pkts = rte_be_to_cpu_64(pool->raw->data[offset].hits);
2868                 *bytes = rte_be_to_cpu_64(pool->raw->data[offset].bytes);
2869         }
2870         rte_spinlock_unlock(&pool->sl);
2871         return 0;
2872 }
2873
2874 /**
2875  * Create and initialize a new counter pool.
2876  *
2877  * @param[in] dev
2878  *   Pointer to the Ethernet device structure.
2879  * @param[out] dcs
2880  *   The devX counter handle.
2881  * @param[in] batch
2882  *   Whether the pool is for counter that was allocated by batch command.
2883  *
2884  * @return
2885  *   A new pool pointer on success, NULL otherwise and rte_errno is set.
2886  */
2887 static struct mlx5_flow_counter_pool *
2888 flow_dv_pool_create(struct rte_eth_dev *dev, struct mlx5_devx_obj *dcs,
2889                     uint32_t batch)
2890 {
2891         struct mlx5_priv *priv = dev->data->dev_private;
2892         struct mlx5_flow_counter_pool *pool;
2893         struct mlx5_pools_container *cont = MLX5_CNT_CONTAINER(priv->sh, batch,
2894                                                                0);
2895         int16_t n_valid = rte_atomic16_read(&cont->n_valid);
2896         uint32_t size;
2897
2898         if (cont->n == n_valid) {
2899                 cont = flow_dv_container_resize(dev, batch);
2900                 if (!cont)
2901                         return NULL;
2902         }
2903         size = sizeof(*pool) + MLX5_COUNTERS_PER_POOL *
2904                         sizeof(struct mlx5_flow_counter);
2905         pool = rte_calloc(__func__, 1, size, 0);
2906         if (!pool) {
2907                 rte_errno = ENOMEM;
2908                 return NULL;
2909         }
2910         pool->min_dcs = dcs;
2911         pool->raw = cont->init_mem_mng->raws + n_valid %
2912                                                      MLX5_CNT_CONTAINER_RESIZE;
2913         pool->raw_hw = NULL;
2914         rte_spinlock_init(&pool->sl);
2915         /*
2916          * The generation of the new allocated counters in this pool is 0, 2 in
2917          * the pool generation makes all the counters valid for allocation.
2918          */
2919         rte_atomic64_set(&pool->query_gen, 0x2);
2920         TAILQ_INIT(&pool->counters);
2921         TAILQ_INSERT_TAIL(&cont->pool_list, pool, next);
2922         cont->pools[n_valid] = pool;
2923         /* Pool initialization must be updated before host thread access. */
2924         rte_cio_wmb();
2925         rte_atomic16_add(&cont->n_valid, 1);
2926         return pool;
2927 }
2928
2929 /**
2930  * Prepare a new counter and/or a new counter pool.
2931  *
2932  * @param[in] dev
2933  *   Pointer to the Ethernet device structure.
2934  * @param[out] cnt_free
2935  *   Where to put the pointer of a new counter.
2936  * @param[in] batch
2937  *   Whether the pool is for counter that was allocated by batch command.
2938  *
2939  * @return
2940  *   The free counter pool pointer and @p cnt_free is set on success,
2941  *   NULL otherwise and rte_errno is set.
2942  */
2943 static struct mlx5_flow_counter_pool *
2944 flow_dv_counter_pool_prepare(struct rte_eth_dev *dev,
2945                              struct mlx5_flow_counter **cnt_free,
2946                              uint32_t batch)
2947 {
2948         struct mlx5_priv *priv = dev->data->dev_private;
2949         struct mlx5_flow_counter_pool *pool;
2950         struct mlx5_devx_obj *dcs = NULL;
2951         struct mlx5_flow_counter *cnt;
2952         uint32_t i;
2953
2954         if (!batch) {
2955                 /* bulk_bitmap must be 0 for single counter allocation. */
2956                 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0);
2957                 if (!dcs)
2958                         return NULL;
2959                 pool = flow_dv_find_pool_by_id
2960                         (MLX5_CNT_CONTAINER(priv->sh, batch, 0), dcs->id);
2961                 if (!pool) {
2962                         pool = flow_dv_pool_create(dev, dcs, batch);
2963                         if (!pool) {
2964                                 mlx5_devx_cmd_destroy(dcs);
2965                                 return NULL;
2966                         }
2967                 } else if (dcs->id < pool->min_dcs->id) {
2968                         rte_atomic64_set(&pool->a64_dcs,
2969                                          (int64_t)(uintptr_t)dcs);
2970                 }
2971                 cnt = &pool->counters_raw[dcs->id % MLX5_COUNTERS_PER_POOL];
2972                 TAILQ_INSERT_HEAD(&pool->counters, cnt, next);
2973                 cnt->dcs = dcs;
2974                 *cnt_free = cnt;
2975                 return pool;
2976         }
2977         /* bulk_bitmap is in 128 counters units. */
2978         if (priv->config.hca_attr.flow_counter_bulk_alloc_bitmap & 0x4)
2979                 dcs = mlx5_devx_cmd_flow_counter_alloc(priv->sh->ctx, 0x4);
2980         if (!dcs) {
2981                 rte_errno = ENODATA;
2982                 return NULL;
2983         }
2984         pool = flow_dv_pool_create(dev, dcs, batch);
2985         if (!pool) {
2986                 mlx5_devx_cmd_destroy(dcs);
2987                 return NULL;
2988         }
2989         for (i = 0; i < MLX5_COUNTERS_PER_POOL; ++i) {
2990                 cnt = &pool->counters_raw[i];
2991                 cnt->pool = pool;
2992                 TAILQ_INSERT_HEAD(&pool->counters, cnt, next);
2993         }
2994         *cnt_free = &pool->counters_raw[0];
2995         return pool;
2996 }
2997
2998 /**
2999  * Search for existed shared counter.
3000  *
3001  * @param[in] cont
3002  *   Pointer to the relevant counter pool container.
3003  * @param[in] id
3004  *   The shared counter ID to search.
3005  *
3006  * @return
3007  *   NULL if not existed, otherwise pointer to the shared counter.
3008  */
3009 static struct mlx5_flow_counter *
3010 flow_dv_counter_shared_search(struct mlx5_pools_container *cont,
3011                               uint32_t id)
3012 {
3013         static struct mlx5_flow_counter *cnt;
3014         struct mlx5_flow_counter_pool *pool;
3015         int i;
3016
3017         TAILQ_FOREACH(pool, &cont->pool_list, next) {
3018                 for (i = 0; i < MLX5_COUNTERS_PER_POOL; ++i) {
3019                         cnt = &pool->counters_raw[i];
3020                         if (cnt->ref_cnt && cnt->shared && cnt->id == id)
3021                                 return cnt;
3022                 }
3023         }
3024         return NULL;
3025 }
3026
3027 /**
3028  * Allocate a flow counter.
3029  *
3030  * @param[in] dev
3031  *   Pointer to the Ethernet device structure.
3032  * @param[in] shared
3033  *   Indicate if this counter is shared with other flows.
3034  * @param[in] id
3035  *   Counter identifier.
3036  * @param[in] group
3037  *   Counter flow group.
3038  *
3039  * @return
3040  *   pointer to flow counter on success, NULL otherwise and rte_errno is set.
3041  */
3042 static struct mlx5_flow_counter *
3043 flow_dv_counter_alloc(struct rte_eth_dev *dev, uint32_t shared, uint32_t id,
3044                       uint16_t group)
3045 {
3046         struct mlx5_priv *priv = dev->data->dev_private;
3047         struct mlx5_flow_counter_pool *pool = NULL;
3048         struct mlx5_flow_counter *cnt_free = NULL;
3049         /*
3050          * Currently group 0 flow counter cannot be assigned to a flow if it is
3051          * not the first one in the batch counter allocation, so it is better
3052          * to allocate counters one by one for these flows in a separate
3053          * container.
3054          * A counter can be shared between different groups so need to take
3055          * shared counters from the single container.
3056          */
3057         uint32_t batch = (group && !shared) ? 1 : 0;
3058         struct mlx5_pools_container *cont = MLX5_CNT_CONTAINER(priv->sh, batch,
3059                                                                0);
3060
3061         if (priv->counter_fallback)
3062                 return flow_dv_counter_alloc_fallback(dev, shared, id);
3063         if (!priv->config.devx) {
3064                 rte_errno = ENOTSUP;
3065                 return NULL;
3066         }
3067         if (shared) {
3068                 cnt_free = flow_dv_counter_shared_search(cont, id);
3069                 if (cnt_free) {
3070                         if (cnt_free->ref_cnt + 1 == 0) {
3071                                 rte_errno = E2BIG;
3072                                 return NULL;
3073                         }
3074                         cnt_free->ref_cnt++;
3075                         return cnt_free;
3076                 }
3077         }
3078         /* Pools which has a free counters are in the start. */
3079         TAILQ_FOREACH(pool, &cont->pool_list, next) {
3080                 /*
3081                  * The free counter reset values must be updated between the
3082                  * counter release to the counter allocation, so, at least one
3083                  * query must be done in this time. ensure it by saving the
3084                  * query generation in the release time.
3085                  * The free list is sorted according to the generation - so if
3086                  * the first one is not updated, all the others are not
3087                  * updated too.
3088                  */
3089                 cnt_free = TAILQ_FIRST(&pool->counters);
3090                 if (cnt_free && cnt_free->query_gen + 1 <
3091                     rte_atomic64_read(&pool->query_gen))
3092                         break;
3093                 cnt_free = NULL;
3094         }
3095         if (!cnt_free) {
3096                 pool = flow_dv_counter_pool_prepare(dev, &cnt_free, batch);
3097                 if (!pool)
3098                         return NULL;
3099         }
3100         cnt_free->batch = batch;
3101         /* Create a DV counter action only in the first time usage. */
3102         if (!cnt_free->action) {
3103                 uint16_t offset;
3104                 struct mlx5_devx_obj *dcs;
3105
3106                 if (batch) {
3107                         offset = cnt_free - &pool->counters_raw[0];
3108                         dcs = pool->min_dcs;
3109                 } else {
3110                         offset = 0;
3111                         dcs = cnt_free->dcs;
3112                 }
3113                 cnt_free->action = mlx5_glue->dv_create_flow_action_counter
3114                                         (dcs->obj, offset);
3115                 if (!cnt_free->action) {
3116                         rte_errno = errno;
3117                         return NULL;
3118                 }
3119         }
3120         /* Update the counter reset values. */
3121         if (_flow_dv_query_count(dev, cnt_free, &cnt_free->hits,
3122                                  &cnt_free->bytes))
3123                 return NULL;
3124         cnt_free->shared = shared;
3125         cnt_free->ref_cnt = 1;
3126         cnt_free->id = id;
3127         if (!priv->sh->cmng.query_thread_on)
3128                 /* Start the asynchronous batch query by the host thread. */
3129                 mlx5_set_query_alarm(priv->sh);
3130         TAILQ_REMOVE(&pool->counters, cnt_free, next);
3131         if (TAILQ_EMPTY(&pool->counters)) {
3132                 /* Move the pool to the end of the container pool list. */
3133                 TAILQ_REMOVE(&cont->pool_list, pool, next);
3134                 TAILQ_INSERT_TAIL(&cont->pool_list, pool, next);
3135         }
3136         return cnt_free;
3137 }
3138
3139 /**
3140  * Release a flow counter.
3141  *
3142  * @param[in] dev
3143  *   Pointer to the Ethernet device structure.
3144  * @param[in] counter
3145  *   Pointer to the counter handler.
3146  */
3147 static void
3148 flow_dv_counter_release(struct rte_eth_dev *dev,
3149                         struct mlx5_flow_counter *counter)
3150 {
3151         struct mlx5_priv *priv = dev->data->dev_private;
3152
3153         if (!counter)
3154                 return;
3155         if (priv->counter_fallback) {
3156                 flow_dv_counter_release_fallback(dev, counter);
3157                 return;
3158         }
3159         if (--counter->ref_cnt == 0) {
3160                 struct mlx5_flow_counter_pool *pool =
3161                                 flow_dv_counter_pool_get(counter);
3162
3163                 /* Put the counter in the end - the last updated one. */
3164                 TAILQ_INSERT_TAIL(&pool->counters, counter, next);
3165                 counter->query_gen = rte_atomic64_read(&pool->query_gen);
3166         }
3167 }
3168
3169 /**
3170  * Verify the @p attributes will be correctly understood by the NIC and store
3171  * them in the @p flow if everything is correct.
3172  *
3173  * @param[in] dev
3174  *   Pointer to dev struct.
3175  * @param[in] attributes
3176  *   Pointer to flow attributes
3177  * @param[out] error
3178  *   Pointer to error structure.
3179  *
3180  * @return
3181  *   0 on success, a negative errno value otherwise and rte_errno is set.
3182  */
3183 static int
3184 flow_dv_validate_attributes(struct rte_eth_dev *dev,
3185                             const struct rte_flow_attr *attributes,
3186                             struct rte_flow_error *error)
3187 {
3188         struct mlx5_priv *priv = dev->data->dev_private;
3189         uint32_t priority_max = priv->config.flow_prio - 1;
3190
3191 #ifndef HAVE_MLX5DV_DR
3192         if (attributes->group)
3193                 return rte_flow_error_set(error, ENOTSUP,
3194                                           RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
3195                                           NULL,
3196                                           "groups is not supported");
3197 #endif
3198         if (attributes->priority != MLX5_FLOW_PRIO_RSVD &&
3199             attributes->priority >= priority_max)
3200                 return rte_flow_error_set(error, ENOTSUP,
3201                                           RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
3202                                           NULL,
3203                                           "priority out of range");
3204         if (attributes->transfer) {
3205                 if (!priv->config.dv_esw_en)
3206                         return rte_flow_error_set
3207                                 (error, ENOTSUP,
3208                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3209                                  "E-Switch dr is not supported");
3210                 if (!(priv->representor || priv->master))
3211                         return rte_flow_error_set
3212                                 (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3213                                  NULL, "E-Switch configuration can only be"
3214                                  " done by a master or a representor device");
3215                 if (attributes->egress)
3216                         return rte_flow_error_set
3217                                 (error, ENOTSUP,
3218                                  RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, attributes,
3219                                  "egress is not supported");
3220                 if (attributes->group >= MLX5_MAX_TABLES_FDB)
3221                         return rte_flow_error_set
3222                                 (error, EINVAL,
3223                                  RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER,
3224                                  NULL, "group must be smaller than "
3225                                  RTE_STR(MLX5_MAX_TABLES_FDB));
3226         }
3227         if (!(attributes->egress ^ attributes->ingress))
3228                 return rte_flow_error_set(error, ENOTSUP,
3229                                           RTE_FLOW_ERROR_TYPE_ATTR, NULL,
3230                                           "must specify exactly one of "
3231                                           "ingress or egress");
3232         return 0;
3233 }
3234
3235 /**
3236  * Internal validation function. For validating both actions and items.
3237  *
3238  * @param[in] dev
3239  *   Pointer to the rte_eth_dev structure.
3240  * @param[in] attr
3241  *   Pointer to the flow attributes.
3242  * @param[in] items
3243  *   Pointer to the list of items.
3244  * @param[in] actions
3245  *   Pointer to the list of actions.
3246  * @param[out] error
3247  *   Pointer to the error structure.
3248  *
3249  * @return
3250  *   0 on success, a negative errno value otherwise and rte_errno is set.
3251  */
3252 static int
3253 flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
3254                  const struct rte_flow_item items[],
3255                  const struct rte_flow_action actions[],
3256                  struct rte_flow_error *error)
3257 {
3258         int ret;
3259         uint64_t action_flags = 0;
3260         uint64_t item_flags = 0;
3261         uint64_t last_item = 0;
3262         uint8_t next_protocol = 0xff;
3263         int actions_n = 0;
3264         const struct rte_flow_item *gre_item = NULL;
3265         struct rte_flow_item_tcp nic_tcp_mask = {
3266                 .hdr = {
3267                         .tcp_flags = 0xFF,
3268                         .src_port = RTE_BE16(UINT16_MAX),
3269                         .dst_port = RTE_BE16(UINT16_MAX),
3270                 }
3271         };
3272
3273         if (items == NULL)
3274                 return -1;
3275         ret = flow_dv_validate_attributes(dev, attr, error);
3276         if (ret < 0)
3277                 return ret;
3278         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
3279                 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
3280                 switch (items->type) {
3281                 case RTE_FLOW_ITEM_TYPE_VOID:
3282                         break;
3283                 case RTE_FLOW_ITEM_TYPE_PORT_ID:
3284                         ret = flow_dv_validate_item_port_id
3285                                         (dev, items, attr, item_flags, error);
3286                         if (ret < 0)
3287                                 return ret;
3288                         last_item = MLX5_FLOW_ITEM_PORT_ID;
3289                         break;
3290                 case RTE_FLOW_ITEM_TYPE_ETH:
3291                         ret = mlx5_flow_validate_item_eth(items, item_flags,
3292                                                           error);
3293                         if (ret < 0)
3294                                 return ret;
3295                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
3296                                              MLX5_FLOW_LAYER_OUTER_L2;
3297                         break;
3298                 case RTE_FLOW_ITEM_TYPE_VLAN:
3299                         ret = mlx5_flow_validate_item_vlan(items, item_flags,
3300                                                            dev, error);
3301                         if (ret < 0)
3302                                 return ret;
3303                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
3304                                              MLX5_FLOW_LAYER_OUTER_VLAN;
3305                         break;
3306                 case RTE_FLOW_ITEM_TYPE_IPV4:
3307                         mlx5_flow_tunnel_ip_check(items, next_protocol,
3308                                                   &item_flags, &tunnel);
3309                         ret = mlx5_flow_validate_item_ipv4(items, item_flags,
3310                                                            NULL, error);
3311                         if (ret < 0)
3312                                 return ret;
3313                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
3314                                              MLX5_FLOW_LAYER_OUTER_L3_IPV4;
3315                         if (items->mask != NULL &&
3316                             ((const struct rte_flow_item_ipv4 *)
3317                              items->mask)->hdr.next_proto_id) {
3318                                 next_protocol =
3319                                         ((const struct rte_flow_item_ipv4 *)
3320                                          (items->spec))->hdr.next_proto_id;
3321                                 next_protocol &=
3322                                         ((const struct rte_flow_item_ipv4 *)
3323                                          (items->mask))->hdr.next_proto_id;
3324                         } else {
3325                                 /* Reset for inner layer. */
3326                                 next_protocol = 0xff;
3327                         }
3328                         break;
3329                 case RTE_FLOW_ITEM_TYPE_IPV6:
3330                         mlx5_flow_tunnel_ip_check(items, next_protocol,
3331                                                   &item_flags, &tunnel);
3332                         ret = mlx5_flow_validate_item_ipv6(items, item_flags,
3333                                                            NULL, error);
3334                         if (ret < 0)
3335                                 return ret;
3336                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
3337                                              MLX5_FLOW_LAYER_OUTER_L3_IPV6;
3338                         if (items->mask != NULL &&
3339                             ((const struct rte_flow_item_ipv6 *)
3340                              items->mask)->hdr.proto) {
3341                                 next_protocol =
3342                                         ((const struct rte_flow_item_ipv6 *)
3343                                          items->spec)->hdr.proto;
3344                                 next_protocol &=
3345                                         ((const struct rte_flow_item_ipv6 *)
3346                                          items->mask)->hdr.proto;
3347                         } else {
3348                                 /* Reset for inner layer. */
3349                                 next_protocol = 0xff;
3350                         }
3351                         break;
3352                 case RTE_FLOW_ITEM_TYPE_TCP:
3353                         ret = mlx5_flow_validate_item_tcp
3354                                                 (items, item_flags,
3355                                                  next_protocol,
3356                                                  &nic_tcp_mask,
3357                                                  error);
3358                         if (ret < 0)
3359                                 return ret;
3360                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
3361                                              MLX5_FLOW_LAYER_OUTER_L4_TCP;
3362                         break;
3363                 case RTE_FLOW_ITEM_TYPE_UDP:
3364                         ret = mlx5_flow_validate_item_udp(items, item_flags,
3365                                                           next_protocol,
3366                                                           error);
3367                         if (ret < 0)
3368                                 return ret;
3369                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
3370                                              MLX5_FLOW_LAYER_OUTER_L4_UDP;
3371                         break;
3372                 case RTE_FLOW_ITEM_TYPE_GRE:
3373                         ret = mlx5_flow_validate_item_gre(items, item_flags,
3374                                                           next_protocol, error);
3375                         if (ret < 0)
3376                                 return ret;
3377                         gre_item = items;
3378                         last_item = MLX5_FLOW_LAYER_GRE;
3379                         break;
3380                 case RTE_FLOW_ITEM_TYPE_NVGRE:
3381                         ret = mlx5_flow_validate_item_nvgre(items, item_flags,
3382                                                             next_protocol,
3383                                                             error);
3384                         if (ret < 0)
3385                                 return ret;
3386                         last_item = MLX5_FLOW_LAYER_NVGRE;
3387                         break;
3388                 case RTE_FLOW_ITEM_TYPE_GRE_KEY:
3389                         ret = mlx5_flow_validate_item_gre_key
3390                                 (items, item_flags, gre_item, error);
3391                         if (ret < 0)
3392                                 return ret;
3393                         last_item = MLX5_FLOW_LAYER_GRE_KEY;
3394                         break;
3395                 case RTE_FLOW_ITEM_TYPE_VXLAN:
3396                         ret = mlx5_flow_validate_item_vxlan(items, item_flags,
3397                                                             error);
3398                         if (ret < 0)
3399                                 return ret;
3400                         last_item = MLX5_FLOW_LAYER_VXLAN;
3401                         break;
3402                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
3403                         ret = mlx5_flow_validate_item_vxlan_gpe(items,
3404                                                                 item_flags, dev,
3405                                                                 error);
3406                         if (ret < 0)
3407                                 return ret;
3408                         last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
3409                         break;
3410                 case RTE_FLOW_ITEM_TYPE_MPLS:
3411                         ret = mlx5_flow_validate_item_mpls(dev, items,
3412                                                            item_flags,
3413                                                            last_item, error);
3414                         if (ret < 0)
3415                                 return ret;
3416                         last_item = MLX5_FLOW_LAYER_MPLS;
3417                         break;
3418                 case RTE_FLOW_ITEM_TYPE_META:
3419                         ret = flow_dv_validate_item_meta(dev, items, attr,
3420                                                          error);
3421                         if (ret < 0)
3422                                 return ret;
3423                         last_item = MLX5_FLOW_ITEM_METADATA;
3424                         break;
3425                 case RTE_FLOW_ITEM_TYPE_ICMP:
3426                         ret = mlx5_flow_validate_item_icmp(items, item_flags,
3427                                                            next_protocol,
3428                                                            error);
3429                         if (ret < 0)
3430                                 return ret;
3431                         last_item = MLX5_FLOW_LAYER_ICMP;
3432                         break;
3433                 case RTE_FLOW_ITEM_TYPE_ICMP6:
3434                         ret = mlx5_flow_validate_item_icmp6(items, item_flags,
3435                                                             next_protocol,
3436                                                             error);
3437                         if (ret < 0)
3438                                 return ret;
3439                         last_item = MLX5_FLOW_LAYER_ICMP6;
3440                         break;
3441                 default:
3442                         return rte_flow_error_set(error, ENOTSUP,
3443                                                   RTE_FLOW_ERROR_TYPE_ITEM,
3444                                                   NULL, "item not supported");
3445                 }
3446                 item_flags |= last_item;
3447         }
3448         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
3449                 if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
3450                         return rte_flow_error_set(error, ENOTSUP,
3451                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3452                                                   actions, "too many actions");
3453                 switch (actions->type) {
3454                 case RTE_FLOW_ACTION_TYPE_VOID:
3455                         break;
3456                 case RTE_FLOW_ACTION_TYPE_PORT_ID:
3457                         ret = flow_dv_validate_action_port_id(dev,
3458                                                               action_flags,
3459                                                               actions,
3460                                                               attr,
3461                                                               error);
3462                         if (ret)
3463                                 return ret;
3464                         action_flags |= MLX5_FLOW_ACTION_PORT_ID;
3465                         ++actions_n;
3466                         break;
3467                 case RTE_FLOW_ACTION_TYPE_FLAG:
3468                         ret = mlx5_flow_validate_action_flag(action_flags,
3469                                                              attr, error);
3470                         if (ret < 0)
3471                                 return ret;
3472                         action_flags |= MLX5_FLOW_ACTION_FLAG;
3473                         ++actions_n;
3474                         break;
3475                 case RTE_FLOW_ACTION_TYPE_MARK:
3476                         ret = mlx5_flow_validate_action_mark(actions,
3477                                                              action_flags,
3478                                                              attr, error);
3479                         if (ret < 0)
3480                                 return ret;
3481                         action_flags |= MLX5_FLOW_ACTION_MARK;
3482                         ++actions_n;
3483                         break;
3484                 case RTE_FLOW_ACTION_TYPE_DROP:
3485                         ret = mlx5_flow_validate_action_drop(action_flags,
3486                                                              attr, error);
3487                         if (ret < 0)
3488                                 return ret;
3489                         action_flags |= MLX5_FLOW_ACTION_DROP;
3490                         ++actions_n;
3491                         break;
3492                 case RTE_FLOW_ACTION_TYPE_QUEUE:
3493                         ret = mlx5_flow_validate_action_queue(actions,
3494                                                               action_flags, dev,
3495                                                               attr, error);
3496                         if (ret < 0)
3497                                 return ret;
3498                         action_flags |= MLX5_FLOW_ACTION_QUEUE;
3499                         ++actions_n;
3500                         break;
3501                 case RTE_FLOW_ACTION_TYPE_RSS:
3502                         ret = mlx5_flow_validate_action_rss(actions,
3503                                                             action_flags, dev,
3504                                                             attr, item_flags,
3505                                                             error);
3506                         if (ret < 0)
3507                                 return ret;
3508                         action_flags |= MLX5_FLOW_ACTION_RSS;
3509                         ++actions_n;
3510                         break;
3511                 case RTE_FLOW_ACTION_TYPE_COUNT:
3512                         ret = flow_dv_validate_action_count(dev, error);
3513                         if (ret < 0)
3514                                 return ret;
3515                         action_flags |= MLX5_FLOW_ACTION_COUNT;
3516                         ++actions_n;
3517                         break;
3518                 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
3519                         if (flow_dv_validate_action_pop_vlan(dev,
3520                                                              action_flags,
3521                                                              actions,
3522                                                              item_flags, attr,
3523                                                              error))
3524                                 return -rte_errno;
3525                         action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
3526                         ++actions_n;
3527                         break;
3528                 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
3529                         ret = flow_dv_validate_action_push_vlan(action_flags,
3530                                                                 actions, attr,
3531                                                                 error);
3532                         if (ret < 0)
3533                                 return ret;
3534                         action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
3535                         ++actions_n;
3536                         break;
3537                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
3538                         ret = flow_dv_validate_action_set_vlan_pcp
3539                                                 (action_flags, actions, error);
3540                         if (ret < 0)
3541                                 return ret;
3542                         /* Count PCP with push_vlan command. */
3543                         break;
3544                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
3545                         ret = flow_dv_validate_action_set_vlan_vid
3546                                                 (item_flags, actions, error);
3547                         if (ret < 0)
3548                                 return ret;
3549                         /* Count VID with push_vlan command. */
3550                         break;
3551                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
3552                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
3553                         ret = flow_dv_validate_action_l2_encap(action_flags,
3554                                                                actions, attr,
3555                                                                error);
3556                         if (ret < 0)
3557                                 return ret;
3558                         action_flags |= actions->type ==
3559                                         RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP ?
3560                                         MLX5_FLOW_ACTION_VXLAN_ENCAP :
3561                                         MLX5_FLOW_ACTION_NVGRE_ENCAP;
3562                         ++actions_n;
3563                         break;
3564                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
3565                 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
3566                         ret = flow_dv_validate_action_l2_decap(action_flags,
3567                                                                attr, error);
3568                         if (ret < 0)
3569                                 return ret;
3570                         action_flags |= actions->type ==
3571                                         RTE_FLOW_ACTION_TYPE_VXLAN_DECAP ?
3572                                         MLX5_FLOW_ACTION_VXLAN_DECAP :
3573                                         MLX5_FLOW_ACTION_NVGRE_DECAP;
3574                         ++actions_n;
3575                         break;
3576                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
3577                         ret = flow_dv_validate_action_raw_encap(action_flags,
3578                                                                 actions, attr,
3579                                                                 error);
3580                         if (ret < 0)
3581                                 return ret;
3582                         action_flags |= MLX5_FLOW_ACTION_RAW_ENCAP;
3583                         ++actions_n;
3584                         break;
3585                 case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
3586                         ret = flow_dv_validate_action_raw_decap(action_flags,
3587                                                                 actions, attr,
3588                                                                 error);
3589                         if (ret < 0)
3590                                 return ret;
3591                         action_flags |= MLX5_FLOW_ACTION_RAW_DECAP;
3592                         ++actions_n;
3593                         break;
3594                 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
3595                 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
3596                         ret = flow_dv_validate_action_modify_mac(action_flags,
3597                                                                  actions,
3598                                                                  item_flags,
3599                                                                  error);
3600                         if (ret < 0)
3601                                 return ret;
3602                         /* Count all modify-header actions as one action. */
3603                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3604                                 ++actions_n;
3605                         action_flags |= actions->type ==
3606                                         RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
3607                                                 MLX5_FLOW_ACTION_SET_MAC_SRC :
3608                                                 MLX5_FLOW_ACTION_SET_MAC_DST;
3609                         break;
3610
3611                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
3612                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
3613                         ret = flow_dv_validate_action_modify_ipv4(action_flags,
3614                                                                   actions,
3615                                                                   item_flags,
3616                                                                   error);
3617                         if (ret < 0)
3618                                 return ret;
3619                         /* Count all modify-header actions as one action. */
3620                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3621                                 ++actions_n;
3622                         action_flags |= actions->type ==
3623                                         RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
3624                                                 MLX5_FLOW_ACTION_SET_IPV4_SRC :
3625                                                 MLX5_FLOW_ACTION_SET_IPV4_DST;
3626                         break;
3627                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
3628                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
3629                         ret = flow_dv_validate_action_modify_ipv6(action_flags,
3630                                                                   actions,
3631                                                                   item_flags,
3632                                                                   error);
3633                         if (ret < 0)
3634                                 return ret;
3635                         /* Count all modify-header actions as one action. */
3636                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3637                                 ++actions_n;
3638                         action_flags |= actions->type ==
3639                                         RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
3640                                                 MLX5_FLOW_ACTION_SET_IPV6_SRC :
3641                                                 MLX5_FLOW_ACTION_SET_IPV6_DST;
3642                         break;
3643                 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
3644                 case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
3645                         ret = flow_dv_validate_action_modify_tp(action_flags,
3646                                                                 actions,
3647                                                                 item_flags,
3648                                                                 error);
3649                         if (ret < 0)
3650                                 return ret;
3651                         /* Count all modify-header actions as one action. */
3652                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3653                                 ++actions_n;
3654                         action_flags |= actions->type ==
3655                                         RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
3656                                                 MLX5_FLOW_ACTION_SET_TP_SRC :
3657                                                 MLX5_FLOW_ACTION_SET_TP_DST;
3658                         break;
3659                 case RTE_FLOW_ACTION_TYPE_DEC_TTL:
3660                 case RTE_FLOW_ACTION_TYPE_SET_TTL:
3661                         ret = flow_dv_validate_action_modify_ttl(action_flags,
3662                                                                  actions,
3663                                                                  item_flags,
3664                                                                  error);
3665                         if (ret < 0)
3666                                 return ret;
3667                         /* Count all modify-header actions as one action. */
3668                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3669                                 ++actions_n;
3670                         action_flags |= actions->type ==
3671                                         RTE_FLOW_ACTION_TYPE_SET_TTL ?
3672                                                 MLX5_FLOW_ACTION_SET_TTL :
3673                                                 MLX5_FLOW_ACTION_DEC_TTL;
3674                         break;
3675                 case RTE_FLOW_ACTION_TYPE_JUMP:
3676                         ret = flow_dv_validate_action_jump(actions,
3677                                                            action_flags,
3678                                                            attr->group, error);
3679                         if (ret)
3680                                 return ret;
3681                         ++actions_n;
3682                         action_flags |= MLX5_FLOW_ACTION_JUMP;
3683                         break;
3684                 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
3685                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
3686                         ret = flow_dv_validate_action_modify_tcp_seq
3687                                                                 (action_flags,
3688                                                                  actions,
3689                                                                  item_flags,
3690                                                                  error);
3691                         if (ret < 0)
3692                                 return ret;
3693                         /* Count all modify-header actions as one action. */
3694                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3695                                 ++actions_n;
3696                         action_flags |= actions->type ==
3697                                         RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
3698                                                 MLX5_FLOW_ACTION_INC_TCP_SEQ :
3699                                                 MLX5_FLOW_ACTION_DEC_TCP_SEQ;
3700                         break;
3701                 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
3702                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
3703                         ret = flow_dv_validate_action_modify_tcp_ack
3704                                                                 (action_flags,
3705                                                                  actions,
3706                                                                  item_flags,
3707                                                                  error);
3708                         if (ret < 0)
3709                                 return ret;
3710                         /* Count all modify-header actions as one action. */
3711                         if (!(action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS))
3712                                 ++actions_n;
3713                         action_flags |= actions->type ==
3714                                         RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
3715                                                 MLX5_FLOW_ACTION_INC_TCP_ACK :
3716                                                 MLX5_FLOW_ACTION_DEC_TCP_ACK;
3717                         break;
3718                 default:
3719                         return rte_flow_error_set(error, ENOTSUP,
3720                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3721                                                   actions,
3722                                                   "action not supported");
3723                 }
3724         }
3725         if ((action_flags & MLX5_FLOW_LAYER_TUNNEL) &&
3726             (action_flags & MLX5_FLOW_VLAN_ACTIONS))
3727                 return rte_flow_error_set(error, ENOTSUP,
3728                                           RTE_FLOW_ERROR_TYPE_ACTION,
3729                                           actions,
3730                                           "can't have vxlan and vlan"
3731                                           " actions in the same rule");
3732         /* Eswitch has few restrictions on using items and actions */
3733         if (attr->transfer) {
3734                 if (action_flags & MLX5_FLOW_ACTION_FLAG)
3735                         return rte_flow_error_set(error, ENOTSUP,
3736                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3737                                                   NULL,
3738                                                   "unsupported action FLAG");
3739                 if (action_flags & MLX5_FLOW_ACTION_MARK)
3740                         return rte_flow_error_set(error, ENOTSUP,
3741                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3742                                                   NULL,
3743                                                   "unsupported action MARK");
3744                 if (action_flags & MLX5_FLOW_ACTION_QUEUE)
3745                         return rte_flow_error_set(error, ENOTSUP,
3746                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3747                                                   NULL,
3748                                                   "unsupported action QUEUE");
3749                 if (action_flags & MLX5_FLOW_ACTION_RSS)
3750                         return rte_flow_error_set(error, ENOTSUP,
3751                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3752                                                   NULL,
3753                                                   "unsupported action RSS");
3754                 if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
3755                         return rte_flow_error_set(error, EINVAL,
3756                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3757                                                   actions,
3758                                                   "no fate action is found");
3759         } else {
3760                 if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) && attr->ingress)
3761                         return rte_flow_error_set(error, EINVAL,
3762                                                   RTE_FLOW_ERROR_TYPE_ACTION,
3763                                                   actions,
3764                                                   "no fate action is found");
3765         }
3766         return 0;
3767 }
3768
3769 /**
3770  * Internal preparation function. Allocates the DV flow size,
3771  * this size is constant.
3772  *
3773  * @param[in] attr
3774  *   Pointer to the flow attributes.
3775  * @param[in] items
3776  *   Pointer to the list of items.
3777  * @param[in] actions
3778  *   Pointer to the list of actions.
3779  * @param[out] error
3780  *   Pointer to the error structure.
3781  *
3782  * @return
3783  *   Pointer to mlx5_flow object on success,
3784  *   otherwise NULL and rte_errno is set.
3785  */
3786 static struct mlx5_flow *
3787 flow_dv_prepare(const struct rte_flow_attr *attr __rte_unused,
3788                 const struct rte_flow_item items[] __rte_unused,
3789                 const struct rte_flow_action actions[] __rte_unused,
3790                 struct rte_flow_error *error)
3791 {
3792         uint32_t size = sizeof(struct mlx5_flow);
3793         struct mlx5_flow *flow;
3794
3795         flow = rte_calloc(__func__, 1, size, 0);
3796         if (!flow) {
3797                 rte_flow_error_set(error, ENOMEM,
3798                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3799                                    "not enough memory to create flow");
3800                 return NULL;
3801         }
3802         flow->dv.value.size = MLX5_ST_SZ_BYTES(fte_match_param);
3803         return flow;
3804 }
3805
3806 #ifndef NDEBUG
3807 /**
3808  * Sanity check for match mask and value. Similar to check_valid_spec() in
3809  * kernel driver. If unmasked bit is present in value, it returns failure.
3810  *
3811  * @param match_mask
3812  *   pointer to match mask buffer.
3813  * @param match_value
3814  *   pointer to match value buffer.
3815  *
3816  * @return
3817  *   0 if valid, -EINVAL otherwise.
3818  */
3819 static int
3820 flow_dv_check_valid_spec(void *match_mask, void *match_value)
3821 {
3822         uint8_t *m = match_mask;
3823         uint8_t *v = match_value;
3824         unsigned int i;
3825
3826         for (i = 0; i < MLX5_ST_SZ_BYTES(fte_match_param); ++i) {
3827                 if (v[i] & ~m[i]) {
3828                         DRV_LOG(ERR,
3829                                 "match_value differs from match_criteria"
3830                                 " %p[%u] != %p[%u]",
3831                                 match_value, i, match_mask, i);
3832                         return -EINVAL;
3833                 }
3834         }
3835         return 0;
3836 }
3837 #endif
3838
3839 /**
3840  * Add Ethernet item to matcher and to the value.
3841  *
3842  * @param[in, out] matcher
3843  *   Flow matcher.
3844  * @param[in, out] key
3845  *   Flow matcher value.
3846  * @param[in] item
3847  *   Flow pattern to translate.
3848  * @param[in] inner
3849  *   Item is inner pattern.
3850  */
3851 static void
3852 flow_dv_translate_item_eth(void *matcher, void *key,
3853                            const struct rte_flow_item *item, int inner)
3854 {
3855         const struct rte_flow_item_eth *eth_m = item->mask;
3856         const struct rte_flow_item_eth *eth_v = item->spec;
3857         const struct rte_flow_item_eth nic_mask = {
3858                 .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
3859                 .src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
3860                 .type = RTE_BE16(0xffff),
3861         };
3862         void *headers_m;
3863         void *headers_v;
3864         char *l24_v;
3865         unsigned int i;
3866
3867         if (!eth_v)
3868                 return;
3869         if (!eth_m)
3870                 eth_m = &nic_mask;
3871         if (inner) {
3872                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3873                                          inner_headers);
3874                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
3875         } else {
3876                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3877                                          outer_headers);
3878                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
3879         }
3880         memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, dmac_47_16),
3881                &eth_m->dst, sizeof(eth_m->dst));
3882         /* The value must be in the range of the mask. */
3883         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, dmac_47_16);
3884         for (i = 0; i < sizeof(eth_m->dst); ++i)
3885                 l24_v[i] = eth_m->dst.addr_bytes[i] & eth_v->dst.addr_bytes[i];
3886         memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m, smac_47_16),
3887                &eth_m->src, sizeof(eth_m->src));
3888         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, smac_47_16);
3889         /* The value must be in the range of the mask. */
3890         for (i = 0; i < sizeof(eth_m->dst); ++i)
3891                 l24_v[i] = eth_m->src.addr_bytes[i] & eth_v->src.addr_bytes[i];
3892         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype,
3893                  rte_be_to_cpu_16(eth_m->type));
3894         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, ethertype);
3895         *(uint16_t *)(l24_v) = eth_m->type & eth_v->type;
3896 }
3897
3898 /**
3899  * Add VLAN item to matcher and to the value.
3900  *
3901  * @param[in, out] dev_flow
3902  *   Flow descriptor.
3903  * @param[in, out] matcher
3904  *   Flow matcher.
3905  * @param[in, out] key
3906  *   Flow matcher value.
3907  * @param[in] item
3908  *   Flow pattern to translate.
3909  * @param[in] inner
3910  *   Item is inner pattern.
3911  */
3912 static void
3913 flow_dv_translate_item_vlan(struct mlx5_flow *dev_flow,
3914                             void *matcher, void *key,
3915                             const struct rte_flow_item *item,
3916                             int inner)
3917 {
3918         const struct rte_flow_item_vlan *vlan_m = item->mask;
3919         const struct rte_flow_item_vlan *vlan_v = item->spec;
3920         void *headers_m;
3921         void *headers_v;
3922         uint16_t tci_m;
3923         uint16_t tci_v;
3924
3925         if (!vlan_v)
3926                 return;
3927         if (!vlan_m)
3928                 vlan_m = &rte_flow_item_vlan_mask;
3929         if (inner) {
3930                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3931                                          inner_headers);
3932                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
3933         } else {
3934                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3935                                          outer_headers);
3936                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
3937                 /*
3938                  * This is workaround, masks are not supported,
3939                  * and pre-validated.
3940                  */
3941                 dev_flow->dv.vf_vlan.tag =
3942                         rte_be_to_cpu_16(vlan_v->tci) & 0x0fff;
3943         }
3944         tci_m = rte_be_to_cpu_16(vlan_m->tci);
3945         tci_v = rte_be_to_cpu_16(vlan_m->tci & vlan_v->tci);
3946         MLX5_SET(fte_match_set_lyr_2_4, headers_m, cvlan_tag, 1);
3947         MLX5_SET(fte_match_set_lyr_2_4, headers_v, cvlan_tag, 1);
3948         MLX5_SET(fte_match_set_lyr_2_4, headers_m, first_vid, tci_m);
3949         MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, tci_v);
3950         MLX5_SET(fte_match_set_lyr_2_4, headers_m, first_cfi, tci_m >> 12);
3951         MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_cfi, tci_v >> 12);
3952         MLX5_SET(fte_match_set_lyr_2_4, headers_m, first_prio, tci_m >> 13);
3953         MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, tci_v >> 13);
3954         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ethertype,
3955                  rte_be_to_cpu_16(vlan_m->inner_type));
3956         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype,
3957                  rte_be_to_cpu_16(vlan_m->inner_type & vlan_v->inner_type));
3958 }
3959
3960 /**
3961  * Add IPV4 item to matcher and to the value.
3962  *
3963  * @param[in, out] matcher
3964  *   Flow matcher.
3965  * @param[in, out] key
3966  *   Flow matcher value.
3967  * @param[in] item
3968  *   Flow pattern to translate.
3969  * @param[in] inner
3970  *   Item is inner pattern.
3971  * @param[in] group
3972  *   The group to insert the rule.
3973  */
3974 static void
3975 flow_dv_translate_item_ipv4(void *matcher, void *key,
3976                             const struct rte_flow_item *item,
3977                             int inner, uint32_t group)
3978 {
3979         const struct rte_flow_item_ipv4 *ipv4_m = item->mask;
3980         const struct rte_flow_item_ipv4 *ipv4_v = item->spec;
3981         const struct rte_flow_item_ipv4 nic_mask = {
3982                 .hdr = {
3983                         .src_addr = RTE_BE32(0xffffffff),
3984                         .dst_addr = RTE_BE32(0xffffffff),
3985                         .type_of_service = 0xff,
3986                         .next_proto_id = 0xff,
3987                 },
3988         };
3989         void *headers_m;
3990         void *headers_v;
3991         char *l24_m;
3992         char *l24_v;
3993         uint8_t tos;
3994
3995         if (inner) {
3996                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
3997                                          inner_headers);
3998                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
3999         } else {
4000                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4001                                          outer_headers);
4002                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4003         }
4004         if (group == 0)
4005                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
4006         else
4007                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0x4);
4008         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, 4);
4009         if (!ipv4_v)
4010                 return;
4011         if (!ipv4_m)
4012                 ipv4_m = &nic_mask;
4013         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
4014                              dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
4015         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
4016                              dst_ipv4_dst_ipv6.ipv4_layout.ipv4);
4017         *(uint32_t *)l24_m = ipv4_m->hdr.dst_addr;
4018         *(uint32_t *)l24_v = ipv4_m->hdr.dst_addr & ipv4_v->hdr.dst_addr;
4019         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
4020                           src_ipv4_src_ipv6.ipv4_layout.ipv4);
4021         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
4022                           src_ipv4_src_ipv6.ipv4_layout.ipv4);
4023         *(uint32_t *)l24_m = ipv4_m->hdr.src_addr;
4024         *(uint32_t *)l24_v = ipv4_m->hdr.src_addr & ipv4_v->hdr.src_addr;
4025         tos = ipv4_m->hdr.type_of_service & ipv4_v->hdr.type_of_service;
4026         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn,
4027                  ipv4_m->hdr.type_of_service);
4028         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, tos);
4029         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp,
4030                  ipv4_m->hdr.type_of_service >> 2);
4031         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, tos >> 2);
4032         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
4033                  ipv4_m->hdr.next_proto_id);
4034         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
4035                  ipv4_v->hdr.next_proto_id & ipv4_m->hdr.next_proto_id);
4036 }
4037
4038 /**
4039  * Add IPV6 item to matcher and to the value.
4040  *
4041  * @param[in, out] matcher
4042  *   Flow matcher.
4043  * @param[in, out] key
4044  *   Flow matcher value.
4045  * @param[in] item
4046  *   Flow pattern to translate.
4047  * @param[in] inner
4048  *   Item is inner pattern.
4049  * @param[in] group
4050  *   The group to insert the rule.
4051  */
4052 static void
4053 flow_dv_translate_item_ipv6(void *matcher, void *key,
4054                             const struct rte_flow_item *item,
4055                             int inner, uint32_t group)
4056 {
4057         const struct rte_flow_item_ipv6 *ipv6_m = item->mask;
4058         const struct rte_flow_item_ipv6 *ipv6_v = item->spec;
4059         const struct rte_flow_item_ipv6 nic_mask = {
4060                 .hdr = {
4061                         .src_addr =
4062                                 "\xff\xff\xff\xff\xff\xff\xff\xff"
4063                                 "\xff\xff\xff\xff\xff\xff\xff\xff",
4064                         .dst_addr =
4065                                 "\xff\xff\xff\xff\xff\xff\xff\xff"
4066                                 "\xff\xff\xff\xff\xff\xff\xff\xff",
4067                         .vtc_flow = RTE_BE32(0xffffffff),
4068                         .proto = 0xff,
4069                         .hop_limits = 0xff,
4070                 },
4071         };
4072         void *headers_m;
4073         void *headers_v;
4074         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4075         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4076         char *l24_m;
4077         char *l24_v;
4078         uint32_t vtc_m;
4079         uint32_t vtc_v;
4080         int i;
4081         int size;
4082
4083         if (inner) {
4084                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4085                                          inner_headers);
4086                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4087         } else {
4088                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4089                                          outer_headers);
4090                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4091         }
4092         if (group == 0)
4093                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0xf);
4094         else
4095                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_version, 0x6);
4096         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_version, 6);
4097         if (!ipv6_v)
4098                 return;
4099         if (!ipv6_m)
4100                 ipv6_m = &nic_mask;
4101         size = sizeof(ipv6_m->hdr.dst_addr);
4102         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
4103                              dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
4104         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
4105                              dst_ipv4_dst_ipv6.ipv6_layout.ipv6);
4106         memcpy(l24_m, ipv6_m->hdr.dst_addr, size);
4107         for (i = 0; i < size; ++i)
4108                 l24_v[i] = l24_m[i] & ipv6_v->hdr.dst_addr[i];
4109         l24_m = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_m,
4110                              src_ipv4_src_ipv6.ipv6_layout.ipv6);
4111         l24_v = MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v,
4112                              src_ipv4_src_ipv6.ipv6_layout.ipv6);
4113         memcpy(l24_m, ipv6_m->hdr.src_addr, size);
4114         for (i = 0; i < size; ++i)
4115                 l24_v[i] = l24_m[i] & ipv6_v->hdr.src_addr[i];
4116         /* TOS. */
4117         vtc_m = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow);
4118         vtc_v = rte_be_to_cpu_32(ipv6_m->hdr.vtc_flow & ipv6_v->hdr.vtc_flow);
4119         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_ecn, vtc_m >> 20);
4120         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_ecn, vtc_v >> 20);
4121         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_dscp, vtc_m >> 22);
4122         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_dscp, vtc_v >> 22);
4123         /* Label. */
4124         if (inner) {
4125                 MLX5_SET(fte_match_set_misc, misc_m, inner_ipv6_flow_label,
4126                          vtc_m);
4127                 MLX5_SET(fte_match_set_misc, misc_v, inner_ipv6_flow_label,
4128                          vtc_v);
4129         } else {
4130                 MLX5_SET(fte_match_set_misc, misc_m, outer_ipv6_flow_label,
4131                          vtc_m);
4132                 MLX5_SET(fte_match_set_misc, misc_v, outer_ipv6_flow_label,
4133                          vtc_v);
4134         }
4135         /* Protocol. */
4136         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol,
4137                  ipv6_m->hdr.proto);
4138         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
4139                  ipv6_v->hdr.proto & ipv6_m->hdr.proto);
4140 }
4141
4142 /**
4143  * Add TCP item to matcher and to the value.
4144  *
4145  * @param[in, out] matcher
4146  *   Flow matcher.
4147  * @param[in, out] key
4148  *   Flow matcher value.
4149  * @param[in] item
4150  *   Flow pattern to translate.
4151  * @param[in] inner
4152  *   Item is inner pattern.
4153  */
4154 static void
4155 flow_dv_translate_item_tcp(void *matcher, void *key,
4156                            const struct rte_flow_item *item,
4157                            int inner)
4158 {
4159         const struct rte_flow_item_tcp *tcp_m = item->mask;
4160         const struct rte_flow_item_tcp *tcp_v = item->spec;
4161         void *headers_m;
4162         void *headers_v;
4163
4164         if (inner) {
4165                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4166                                          inner_headers);
4167                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4168         } else {
4169                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4170                                          outer_headers);
4171                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4172         }
4173         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
4174         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP);
4175         if (!tcp_v)
4176                 return;
4177         if (!tcp_m)
4178                 tcp_m = &rte_flow_item_tcp_mask;
4179         MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_sport,
4180                  rte_be_to_cpu_16(tcp_m->hdr.src_port));
4181         MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport,
4182                  rte_be_to_cpu_16(tcp_v->hdr.src_port & tcp_m->hdr.src_port));
4183         MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_dport,
4184                  rte_be_to_cpu_16(tcp_m->hdr.dst_port));
4185         MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport,
4186                  rte_be_to_cpu_16(tcp_v->hdr.dst_port & tcp_m->hdr.dst_port));
4187         MLX5_SET(fte_match_set_lyr_2_4, headers_m, tcp_flags,
4188                  tcp_m->hdr.tcp_flags);
4189         MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_flags,
4190                  (tcp_v->hdr.tcp_flags & tcp_m->hdr.tcp_flags));
4191 }
4192
4193 /**
4194  * Add UDP item to matcher and to the value.
4195  *
4196  * @param[in, out] matcher
4197  *   Flow matcher.
4198  * @param[in, out] key
4199  *   Flow matcher value.
4200  * @param[in] item
4201  *   Flow pattern to translate.
4202  * @param[in] inner
4203  *   Item is inner pattern.
4204  */
4205 static void
4206 flow_dv_translate_item_udp(void *matcher, void *key,
4207                            const struct rte_flow_item *item,
4208                            int inner)
4209 {
4210         const struct rte_flow_item_udp *udp_m = item->mask;
4211         const struct rte_flow_item_udp *udp_v = item->spec;
4212         void *headers_m;
4213         void *headers_v;
4214
4215         if (inner) {
4216                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4217                                          inner_headers);
4218                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4219         } else {
4220                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4221                                          outer_headers);
4222                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4223         }
4224         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
4225         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
4226         if (!udp_v)
4227                 return;
4228         if (!udp_m)
4229                 udp_m = &rte_flow_item_udp_mask;
4230         MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_sport,
4231                  rte_be_to_cpu_16(udp_m->hdr.src_port));
4232         MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
4233                  rte_be_to_cpu_16(udp_v->hdr.src_port & udp_m->hdr.src_port));
4234         MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport,
4235                  rte_be_to_cpu_16(udp_m->hdr.dst_port));
4236         MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
4237                  rte_be_to_cpu_16(udp_v->hdr.dst_port & udp_m->hdr.dst_port));
4238 }
4239
4240 /**
4241  * Add GRE optional Key item to matcher and to the value.
4242  *
4243  * @param[in, out] matcher
4244  *   Flow matcher.
4245  * @param[in, out] key
4246  *   Flow matcher value.
4247  * @param[in] item
4248  *   Flow pattern to translate.
4249  * @param[in] inner
4250  *   Item is inner pattern.
4251  */
4252 static void
4253 flow_dv_translate_item_gre_key(void *matcher, void *key,
4254                                    const struct rte_flow_item *item)
4255 {
4256         const rte_be32_t *key_m = item->mask;
4257         const rte_be32_t *key_v = item->spec;
4258         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4259         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4260         rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX);
4261
4262         if (!key_v)
4263                 return;
4264         if (!key_m)
4265                 key_m = &gre_key_default_mask;
4266         /* GRE K bit must be on and should already be validated */
4267         MLX5_SET(fte_match_set_misc, misc_m, gre_k_present, 1);
4268         MLX5_SET(fte_match_set_misc, misc_v, gre_k_present, 1);
4269         MLX5_SET(fte_match_set_misc, misc_m, gre_key_h,
4270                  rte_be_to_cpu_32(*key_m) >> 8);
4271         MLX5_SET(fte_match_set_misc, misc_v, gre_key_h,
4272                  rte_be_to_cpu_32((*key_v) & (*key_m)) >> 8);
4273         MLX5_SET(fte_match_set_misc, misc_m, gre_key_l,
4274                  rte_be_to_cpu_32(*key_m) & 0xFF);
4275         MLX5_SET(fte_match_set_misc, misc_v, gre_key_l,
4276                  rte_be_to_cpu_32((*key_v) & (*key_m)) & 0xFF);
4277 }
4278
4279 /**
4280  * Add GRE item to matcher and to the value.
4281  *
4282  * @param[in, out] matcher
4283  *   Flow matcher.
4284  * @param[in, out] key
4285  *   Flow matcher value.
4286  * @param[in] item
4287  *   Flow pattern to translate.
4288  * @param[in] inner
4289  *   Item is inner pattern.
4290  */
4291 static void
4292 flow_dv_translate_item_gre(void *matcher, void *key,
4293                            const struct rte_flow_item *item,
4294                            int inner)
4295 {
4296         const struct rte_flow_item_gre *gre_m = item->mask;
4297         const struct rte_flow_item_gre *gre_v = item->spec;
4298         void *headers_m;
4299         void *headers_v;
4300         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4301         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4302         struct {
4303                 union {
4304                         __extension__
4305                         struct {
4306                                 uint16_t version:3;
4307                                 uint16_t rsvd0:9;
4308                                 uint16_t s_present:1;
4309                                 uint16_t k_present:1;
4310                                 uint16_t rsvd_bit1:1;
4311                                 uint16_t c_present:1;
4312                         };
4313                         uint16_t value;
4314                 };
4315         } gre_crks_rsvd0_ver_m, gre_crks_rsvd0_ver_v;
4316
4317         if (inner) {
4318                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4319                                          inner_headers);
4320                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4321         } else {
4322                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4323                                          outer_headers);
4324                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4325         }
4326         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
4327         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
4328         if (!gre_v)
4329                 return;
4330         if (!gre_m)
4331                 gre_m = &rte_flow_item_gre_mask;
4332         MLX5_SET(fte_match_set_misc, misc_m, gre_protocol,
4333                  rte_be_to_cpu_16(gre_m->protocol));
4334         MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
4335                  rte_be_to_cpu_16(gre_v->protocol & gre_m->protocol));
4336         gre_crks_rsvd0_ver_m.value = rte_be_to_cpu_16(gre_m->c_rsvd0_ver);
4337         gre_crks_rsvd0_ver_v.value = rte_be_to_cpu_16(gre_v->c_rsvd0_ver);
4338         MLX5_SET(fte_match_set_misc, misc_m, gre_c_present,
4339                  gre_crks_rsvd0_ver_m.c_present);
4340         MLX5_SET(fte_match_set_misc, misc_v, gre_c_present,
4341                  gre_crks_rsvd0_ver_v.c_present &
4342                  gre_crks_rsvd0_ver_m.c_present);
4343         MLX5_SET(fte_match_set_misc, misc_m, gre_k_present,
4344                  gre_crks_rsvd0_ver_m.k_present);
4345         MLX5_SET(fte_match_set_misc, misc_v, gre_k_present,
4346                  gre_crks_rsvd0_ver_v.k_present &
4347                  gre_crks_rsvd0_ver_m.k_present);
4348         MLX5_SET(fte_match_set_misc, misc_m, gre_s_present,
4349                  gre_crks_rsvd0_ver_m.s_present);
4350         MLX5_SET(fte_match_set_misc, misc_v, gre_s_present,
4351                  gre_crks_rsvd0_ver_v.s_present &
4352                  gre_crks_rsvd0_ver_m.s_present);
4353 }
4354
4355 /**
4356  * Add NVGRE item to matcher and to the value.
4357  *
4358  * @param[in, out] matcher
4359  *   Flow matcher.
4360  * @param[in, out] key
4361  *   Flow matcher value.
4362  * @param[in] item
4363  *   Flow pattern to translate.
4364  * @param[in] inner
4365  *   Item is inner pattern.
4366  */
4367 static void
4368 flow_dv_translate_item_nvgre(void *matcher, void *key,
4369                              const struct rte_flow_item *item,
4370                              int inner)
4371 {
4372         const struct rte_flow_item_nvgre *nvgre_m = item->mask;
4373         const struct rte_flow_item_nvgre *nvgre_v = item->spec;
4374         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4375         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4376         const char *tni_flow_id_m = (const char *)nvgre_m->tni;
4377         const char *tni_flow_id_v = (const char *)nvgre_v->tni;
4378         char *gre_key_m;
4379         char *gre_key_v;
4380         int size;
4381         int i;
4382
4383         /* For NVGRE, GRE header fields must be set with defined values. */
4384         const struct rte_flow_item_gre gre_spec = {
4385                 .c_rsvd0_ver = RTE_BE16(0x2000),
4386                 .protocol = RTE_BE16(RTE_ETHER_TYPE_TEB)
4387         };
4388         const struct rte_flow_item_gre gre_mask = {
4389                 .c_rsvd0_ver = RTE_BE16(0xB000),
4390                 .protocol = RTE_BE16(UINT16_MAX),
4391         };
4392         const struct rte_flow_item gre_item = {
4393                 .spec = &gre_spec,
4394                 .mask = &gre_mask,
4395                 .last = NULL,
4396         };
4397         flow_dv_translate_item_gre(matcher, key, &gre_item, inner);
4398         if (!nvgre_v)
4399                 return;
4400         if (!nvgre_m)
4401                 nvgre_m = &rte_flow_item_nvgre_mask;
4402         size = sizeof(nvgre_m->tni) + sizeof(nvgre_m->flow_id);
4403         gre_key_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, gre_key_h);
4404         gre_key_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, gre_key_h);
4405         memcpy(gre_key_m, tni_flow_id_m, size);
4406         for (i = 0; i < size; ++i)
4407                 gre_key_v[i] = gre_key_m[i] & tni_flow_id_v[i];
4408 }
4409
4410 /**
4411  * Add VXLAN item to matcher and to the value.
4412  *
4413  * @param[in, out] matcher
4414  *   Flow matcher.
4415  * @param[in, out] key
4416  *   Flow matcher value.
4417  * @param[in] item
4418  *   Flow pattern to translate.
4419  * @param[in] inner
4420  *   Item is inner pattern.
4421  */
4422 static void
4423 flow_dv_translate_item_vxlan(void *matcher, void *key,
4424                              const struct rte_flow_item *item,
4425                              int inner)
4426 {
4427         const struct rte_flow_item_vxlan *vxlan_m = item->mask;
4428         const struct rte_flow_item_vxlan *vxlan_v = item->spec;
4429         void *headers_m;
4430         void *headers_v;
4431         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4432         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4433         char *vni_m;
4434         char *vni_v;
4435         uint16_t dport;
4436         int size;
4437         int i;
4438
4439         if (inner) {
4440                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4441                                          inner_headers);
4442                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4443         } else {
4444                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4445                                          outer_headers);
4446                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4447         }
4448         dport = item->type == RTE_FLOW_ITEM_TYPE_VXLAN ?
4449                 MLX5_UDP_PORT_VXLAN : MLX5_UDP_PORT_VXLAN_GPE;
4450         if (!MLX5_GET16(fte_match_set_lyr_2_4, headers_v, udp_dport)) {
4451                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xFFFF);
4452                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, dport);
4453         }
4454         if (!vxlan_v)
4455                 return;
4456         if (!vxlan_m)
4457                 vxlan_m = &rte_flow_item_vxlan_mask;
4458         size = sizeof(vxlan_m->vni);
4459         vni_m = MLX5_ADDR_OF(fte_match_set_misc, misc_m, vxlan_vni);
4460         vni_v = MLX5_ADDR_OF(fte_match_set_misc, misc_v, vxlan_vni);
4461         memcpy(vni_m, vxlan_m->vni, size);
4462         for (i = 0; i < size; ++i)
4463                 vni_v[i] = vni_m[i] & vxlan_v->vni[i];
4464 }
4465
4466 /**
4467  * Add MPLS item to matcher and to the value.
4468  *
4469  * @param[in, out] matcher
4470  *   Flow matcher.
4471  * @param[in, out] key
4472  *   Flow matcher value.
4473  * @param[in] item
4474  *   Flow pattern to translate.
4475  * @param[in] prev_layer
4476  *   The protocol layer indicated in previous item.
4477  * @param[in] inner
4478  *   Item is inner pattern.
4479  */
4480 static void
4481 flow_dv_translate_item_mpls(void *matcher, void *key,
4482                             const struct rte_flow_item *item,
4483                             uint64_t prev_layer,
4484                             int inner)
4485 {
4486         const uint32_t *in_mpls_m = item->mask;
4487         const uint32_t *in_mpls_v = item->spec;
4488         uint32_t *out_mpls_m = 0;
4489         uint32_t *out_mpls_v = 0;
4490         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4491         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4492         void *misc2_m = MLX5_ADDR_OF(fte_match_param, matcher,
4493                                      misc_parameters_2);
4494         void *misc2_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
4495         void *headers_m = MLX5_ADDR_OF(fte_match_param, matcher, outer_headers);
4496         void *headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4497
4498         switch (prev_layer) {
4499         case MLX5_FLOW_LAYER_OUTER_L4_UDP:
4500                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, udp_dport, 0xffff);
4501                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
4502                          MLX5_UDP_PORT_MPLS);
4503                 break;
4504         case MLX5_FLOW_LAYER_GRE:
4505                 MLX5_SET(fte_match_set_misc, misc_m, gre_protocol, 0xffff);
4506                 MLX5_SET(fte_match_set_misc, misc_v, gre_protocol,
4507                          RTE_ETHER_TYPE_MPLS);
4508                 break;
4509         default:
4510                 MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xff);
4511                 MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol,
4512                          IPPROTO_MPLS);
4513                 break;
4514         }
4515         if (!in_mpls_v)
4516                 return;
4517         if (!in_mpls_m)
4518                 in_mpls_m = (const uint32_t *)&rte_flow_item_mpls_mask;
4519         switch (prev_layer) {
4520         case MLX5_FLOW_LAYER_OUTER_L4_UDP:
4521                 out_mpls_m =
4522                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
4523                                                  outer_first_mpls_over_udp);
4524                 out_mpls_v =
4525                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
4526                                                  outer_first_mpls_over_udp);
4527                 break;
4528         case MLX5_FLOW_LAYER_GRE:
4529                 out_mpls_m =
4530                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_m,
4531                                                  outer_first_mpls_over_gre);
4532                 out_mpls_v =
4533                         (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2, misc2_v,
4534                                                  outer_first_mpls_over_gre);
4535                 break;
4536         default:
4537                 /* Inner MPLS not over GRE is not supported. */
4538                 if (!inner) {
4539                         out_mpls_m =
4540                                 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
4541                                                          misc2_m,
4542                                                          outer_first_mpls);
4543                         out_mpls_v =
4544                                 (uint32_t *)MLX5_ADDR_OF(fte_match_set_misc2,
4545                                                          misc2_v,
4546                                                          outer_first_mpls);
4547                 }
4548                 break;
4549         }
4550         if (out_mpls_m && out_mpls_v) {
4551                 *out_mpls_m = *in_mpls_m;
4552                 *out_mpls_v = *in_mpls_v & *in_mpls_m;
4553         }
4554 }
4555
4556 /**
4557  * Add META item to matcher
4558  *
4559  * @param[in, out] matcher
4560  *   Flow matcher.
4561  * @param[in, out] key
4562  *   Flow matcher value.
4563  * @param[in] item
4564  *   Flow pattern to translate.
4565  * @param[in] inner
4566  *   Item is inner pattern.
4567  */
4568 static void
4569 flow_dv_translate_item_meta(void *matcher, void *key,
4570                             const struct rte_flow_item *item)
4571 {
4572         const struct rte_flow_item_meta *meta_m;
4573         const struct rte_flow_item_meta *meta_v;
4574         void *misc2_m =
4575                 MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters_2);
4576         void *misc2_v =
4577                 MLX5_ADDR_OF(fte_match_param, key, misc_parameters_2);
4578
4579         meta_m = (const void *)item->mask;
4580         if (!meta_m)
4581                 meta_m = &rte_flow_item_meta_mask;
4582         meta_v = (const void *)item->spec;
4583         if (meta_v) {
4584                 MLX5_SET(fte_match_set_misc2, misc2_m, metadata_reg_a,
4585                          rte_be_to_cpu_32(meta_m->data));
4586                 MLX5_SET(fte_match_set_misc2, misc2_v, metadata_reg_a,
4587                          rte_be_to_cpu_32(meta_v->data & meta_m->data));
4588         }
4589 }
4590
4591 /**
4592  * Add source vport match to the specified matcher.
4593  *
4594  * @param[in, out] matcher
4595  *   Flow matcher.
4596  * @param[in, out] key
4597  *   Flow matcher value.
4598  * @param[in] port
4599  *   Source vport value to match
4600  * @param[in] mask
4601  *   Mask
4602  */
4603 static void
4604 flow_dv_translate_item_source_vport(void *matcher, void *key,
4605                                     int16_t port, uint16_t mask)
4606 {
4607         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
4608         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
4609
4610         MLX5_SET(fte_match_set_misc, misc_m, source_port, mask);
4611         MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
4612 }
4613
4614 /**
4615  * Translate port-id item to eswitch match on  port-id.
4616  *
4617  * @param[in] dev
4618  *   The devich to configure through.
4619  * @param[in, out] matcher
4620  *   Flow matcher.
4621  * @param[in, out] key
4622  *   Flow matcher value.
4623  * @param[in] item
4624  *   Flow pattern to translate.
4625  *
4626  * @return
4627  *   0 on success, a negative errno value otherwise.
4628  */
4629 static int
4630 flow_dv_translate_item_port_id(struct rte_eth_dev *dev, void *matcher,
4631                                void *key, const struct rte_flow_item *item)
4632 {
4633         const struct rte_flow_item_port_id *pid_m = item ? item->mask : NULL;
4634         const struct rte_flow_item_port_id *pid_v = item ? item->spec : NULL;
4635         uint16_t mask, val, id;
4636         int ret;
4637
4638         mask = pid_m ? pid_m->id : 0xffff;
4639         id = pid_v ? pid_v->id : dev->data->port_id;
4640         ret = mlx5_port_to_eswitch_info(id, NULL, &val);
4641         if (ret)
4642                 return ret;
4643         flow_dv_translate_item_source_vport(matcher, key, val, mask);
4644         return 0;
4645 }
4646
4647 /**
4648  * Add ICMP6 item to matcher and to the value.
4649  *
4650  * @param[in, out] matcher
4651  *   Flow matcher.
4652  * @param[in, out] key
4653  *   Flow matcher value.
4654  * @param[in] item
4655  *   Flow pattern to translate.
4656  * @param[in] inner
4657  *   Item is inner pattern.
4658  */
4659 static void
4660 flow_dv_translate_item_icmp6(void *matcher, void *key,
4661                               const struct rte_flow_item *item,
4662                               int inner)
4663 {
4664         const struct rte_flow_item_icmp6 *icmp6_m = item->mask;
4665         const struct rte_flow_item_icmp6 *icmp6_v = item->spec;
4666         void *headers_m;
4667         void *headers_v;
4668         void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
4669                                      misc_parameters_3);
4670         void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
4671         if (inner) {
4672                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4673                                          inner_headers);
4674                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4675         } else {
4676                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4677                                          outer_headers);
4678                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4679         }
4680         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
4681         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMPV6);
4682         if (!icmp6_v)
4683                 return;
4684         if (!icmp6_m)
4685                 icmp6_m = &rte_flow_item_icmp6_mask;
4686         MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_type, icmp6_m->type);
4687         MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_type,
4688                  icmp6_v->type & icmp6_m->type);
4689         MLX5_SET(fte_match_set_misc3, misc3_m, icmpv6_code, icmp6_m->code);
4690         MLX5_SET(fte_match_set_misc3, misc3_v, icmpv6_code,
4691                  icmp6_v->code & icmp6_m->code);
4692 }
4693
4694 /**
4695  * Add ICMP item to matcher and to the value.
4696  *
4697  * @param[in, out] matcher
4698  *   Flow matcher.
4699  * @param[in, out] key
4700  *   Flow matcher value.
4701  * @param[in] item
4702  *   Flow pattern to translate.
4703  * @param[in] inner
4704  *   Item is inner pattern.
4705  */
4706 static void
4707 flow_dv_translate_item_icmp(void *matcher, void *key,
4708                             const struct rte_flow_item *item,
4709                             int inner)
4710 {
4711         const struct rte_flow_item_icmp *icmp_m = item->mask;
4712         const struct rte_flow_item_icmp *icmp_v = item->spec;
4713         void *headers_m;
4714         void *headers_v;
4715         void *misc3_m = MLX5_ADDR_OF(fte_match_param, matcher,
4716                                      misc_parameters_3);
4717         void *misc3_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_3);
4718         if (inner) {
4719                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4720                                          inner_headers);
4721                 headers_v = MLX5_ADDR_OF(fte_match_param, key, inner_headers);
4722         } else {
4723                 headers_m = MLX5_ADDR_OF(fte_match_param, matcher,
4724                                          outer_headers);
4725                 headers_v = MLX5_ADDR_OF(fte_match_param, key, outer_headers);
4726         }
4727         MLX5_SET(fte_match_set_lyr_2_4, headers_m, ip_protocol, 0xFF);
4728         MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_ICMP);
4729         if (!icmp_v)
4730                 return;
4731         if (!icmp_m)
4732                 icmp_m = &rte_flow_item_icmp_mask;
4733         MLX5_SET(fte_match_set_misc3, misc3_m, icmp_type,
4734                  icmp_m->hdr.icmp_type);
4735         MLX5_SET(fte_match_set_misc3, misc3_v, icmp_type,
4736                  icmp_v->hdr.icmp_type & icmp_m->hdr.icmp_type);
4737         MLX5_SET(fte_match_set_misc3, misc3_m, icmp_code,
4738                  icmp_m->hdr.icmp_code);
4739         MLX5_SET(fte_match_set_misc3, misc3_v, icmp_code,
4740                  icmp_v->hdr.icmp_code & icmp_m->hdr.icmp_code);
4741 }
4742
4743 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
4744
4745 #define HEADER_IS_ZERO(match_criteria, headers)                              \
4746         !(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
4747                  matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
4748
4749 /**
4750  * Calculate flow matcher enable bitmap.
4751  *
4752  * @param match_criteria
4753  *   Pointer to flow matcher criteria.
4754  *
4755  * @return
4756  *   Bitmap of enabled fields.
4757  */
4758 static uint8_t
4759 flow_dv_matcher_enable(uint32_t *match_criteria)
4760 {
4761         uint8_t match_criteria_enable;
4762
4763         match_criteria_enable =
4764                 (!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
4765                 MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
4766         match_criteria_enable |=
4767                 (!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
4768                 MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
4769         match_criteria_enable |=
4770                 (!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
4771                 MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
4772         match_criteria_enable |=
4773                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
4774                 MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
4775         match_criteria_enable |=
4776                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
4777                 MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
4778         return match_criteria_enable;
4779 }
4780
4781
4782 /**
4783  * Get a flow table.
4784  *
4785  * @param dev[in, out]
4786  *   Pointer to rte_eth_dev structure.
4787  * @param[in] table_id
4788  *   Table id to use.
4789  * @param[in] egress
4790  *   Direction of the table.
4791  * @param[in] transfer
4792  *   E-Switch or NIC flow.
4793  * @param[out] error
4794  *   pointer to error structure.
4795  *
4796  * @return
4797  *   Returns tables resource based on the index, NULL in case of failed.
4798  */
4799 static struct mlx5_flow_tbl_resource *
4800 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
4801                          uint32_t table_id, uint8_t egress,
4802                          uint8_t transfer,
4803                          struct rte_flow_error *error)
4804 {
4805         struct mlx5_priv *priv = dev->data->dev_private;
4806         struct mlx5_ibv_shared *sh = priv->sh;
4807         struct mlx5_flow_tbl_resource *tbl;
4808
4809 #ifdef HAVE_MLX5DV_DR
4810         if (transfer) {
4811                 tbl = &sh->fdb_tbl[table_id];
4812                 if (!tbl->obj)
4813                         tbl->obj = mlx5_glue->dr_create_flow_tbl
4814                                 (sh->fdb_domain, table_id);
4815         } else if (egress) {
4816                 tbl = &sh->tx_tbl[table_id];
4817                 if (!tbl->obj)
4818                         tbl->obj = mlx5_glue->dr_create_flow_tbl
4819                                 (sh->tx_domain, table_id);
4820         } else {
4821                 tbl = &sh->rx_tbl[table_id];
4822                 if (!tbl->obj)
4823                         tbl->obj = mlx5_glue->dr_create_flow_tbl
4824                                 (sh->rx_domain, table_id);
4825         }
4826         if (!tbl->obj) {
4827                 rte_flow_error_set(error, ENOMEM,
4828                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4829                                    NULL, "cannot create table");
4830                 return NULL;
4831         }
4832         rte_atomic32_inc(&tbl->refcnt);
4833         return tbl;
4834 #else
4835         (void)error;
4836         (void)tbl;
4837         if (transfer)
4838                 return &sh->fdb_tbl[table_id];
4839         else if (egress)
4840                 return &sh->tx_tbl[table_id];
4841         else
4842                 return &sh->rx_tbl[table_id];
4843 #endif
4844 }
4845
4846 /**
4847  * Release a flow table.
4848  *
4849  * @param[in] tbl
4850  *   Table resource to be released.
4851  *
4852  * @return
4853  *   Returns 0 if table was released, else return 1;
4854  */
4855 static int
4856 flow_dv_tbl_resource_release(struct mlx5_flow_tbl_resource *tbl)
4857 {
4858         if (!tbl)
4859                 return 0;
4860         if (rte_atomic32_dec_and_test(&tbl->refcnt)) {
4861                 mlx5_glue->dr_destroy_flow_tbl(tbl->obj);
4862                 tbl->obj = NULL;
4863                 return 0;
4864         }
4865         return 1;
4866 }
4867
4868 /**
4869  * Register the flow matcher.
4870  *
4871  * @param dev[in, out]
4872  *   Pointer to rte_eth_dev structure.
4873  * @param[in, out] matcher
4874  *   Pointer to flow matcher.
4875  * @parm[in, out] dev_flow
4876  *   Pointer to the dev_flow.
4877  * @param[out] error
4878  *   pointer to error structure.
4879  *
4880  * @return
4881  *   0 on success otherwise -errno and errno is set.
4882  */
4883 static int
4884 flow_dv_matcher_register(struct rte_eth_dev *dev,
4885                          struct mlx5_flow_dv_matcher *matcher,
4886                          struct mlx5_flow *dev_flow,
4887                          struct rte_flow_error *error)
4888 {
4889         struct mlx5_priv *priv = dev->data->dev_private;
4890         struct mlx5_ibv_shared *sh = priv->sh;
4891         struct mlx5_flow_dv_matcher *cache_matcher;
4892         struct mlx5dv_flow_matcher_attr dv_attr = {
4893                 .type = IBV_FLOW_ATTR_NORMAL,
4894                 .match_mask = (void *)&matcher->mask,
4895         };
4896         struct mlx5_flow_tbl_resource *tbl = NULL;
4897
4898         /* Lookup from cache. */
4899         LIST_FOREACH(cache_matcher, &sh->matchers, next) {
4900                 if (matcher->crc == cache_matcher->crc &&
4901                     matcher->priority == cache_matcher->priority &&
4902                     matcher->egress == cache_matcher->egress &&
4903                     matcher->group == cache_matcher->group &&
4904                     matcher->transfer == cache_matcher->transfer &&
4905                     !memcmp((const void *)matcher->mask.buf,
4906                             (const void *)cache_matcher->mask.buf,
4907                             cache_matcher->mask.size)) {
4908                         DRV_LOG(DEBUG,
4909                                 "priority %hd use %s matcher %p: refcnt %d++",
4910                                 cache_matcher->priority,
4911                                 cache_matcher->egress ? "tx" : "rx",
4912                                 (void *)cache_matcher,
4913                                 rte_atomic32_read(&cache_matcher->refcnt));
4914                         rte_atomic32_inc(&cache_matcher->refcnt);
4915                         dev_flow->dv.matcher = cache_matcher;
4916                         return 0;
4917                 }
4918         }
4919         /* Register new matcher. */
4920         cache_matcher = rte_calloc(__func__, 1, sizeof(*cache_matcher), 0);
4921         if (!cache_matcher)
4922                 return rte_flow_error_set(error, ENOMEM,
4923                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
4924                                           "cannot allocate matcher memory");
4925         tbl = flow_dv_tbl_resource_get(dev, matcher->group,
4926                                        matcher->egress, matcher->transfer,
4927                                        error);
4928         if (!tbl) {
4929                 rte_free(cache_matcher);
4930                 return rte_flow_error_set(error, ENOMEM,
4931                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4932                                           NULL, "cannot create table");
4933         }
4934         *cache_matcher = *matcher;
4935         dv_attr.match_criteria_enable =
4936                 flow_dv_matcher_enable(cache_matcher->mask.buf);
4937         dv_attr.priority = matcher->priority;
4938         if (matcher->egress)
4939                 dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
4940         cache_matcher->matcher_object =
4941                 mlx5_glue->dv_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj);
4942         if (!cache_matcher->matcher_object) {
4943                 rte_free(cache_matcher);
4944 #ifdef HAVE_MLX5DV_DR
4945                 flow_dv_tbl_resource_release(tbl);
4946 #endif
4947                 return rte_flow_error_set(error, ENOMEM,
4948                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4949                                           NULL, "cannot create matcher");
4950         }
4951         rte_atomic32_inc(&cache_matcher->refcnt);
4952         LIST_INSERT_HEAD(&sh->matchers, cache_matcher, next);
4953         dev_flow->dv.matcher = cache_matcher;
4954         DRV_LOG(DEBUG, "priority %hd new %s matcher %p: refcnt %d",
4955                 cache_matcher->priority,
4956                 cache_matcher->egress ? "tx" : "rx", (void *)cache_matcher,
4957                 rte_atomic32_read(&cache_matcher->refcnt));
4958         rte_atomic32_inc(&tbl->refcnt);
4959         return 0;
4960 }
4961
4962 /**
4963  * Find existing tag resource or create and register a new one.
4964  *
4965  * @param dev[in, out]
4966  *   Pointer to rte_eth_dev structure.
4967  * @param[in, out] resource
4968  *   Pointer to tag resource.
4969  * @parm[in, out] dev_flow
4970  *   Pointer to the dev_flow.
4971  * @param[out] error
4972  *   pointer to error structure.
4973  *
4974  * @return
4975  *   0 on success otherwise -errno and errno is set.
4976  */
4977 static int
4978 flow_dv_tag_resource_register
4979                         (struct rte_eth_dev *dev,
4980                          struct mlx5_flow_dv_tag_resource *resource,
4981                          struct mlx5_flow *dev_flow,
4982                          struct rte_flow_error *error)
4983 {
4984         struct mlx5_priv *priv = dev->data->dev_private;
4985         struct mlx5_ibv_shared *sh = priv->sh;
4986         struct mlx5_flow_dv_tag_resource *cache_resource;
4987
4988         /* Lookup a matching resource from cache. */
4989         LIST_FOREACH(cache_resource, &sh->tags, next) {
4990                 if (resource->tag == cache_resource->tag) {
4991                         DRV_LOG(DEBUG, "tag resource %p: refcnt %d++",
4992                                 (void *)cache_resource,
4993                                 rte_atomic32_read(&cache_resource->refcnt));
4994                         rte_atomic32_inc(&cache_resource->refcnt);
4995                         dev_flow->flow->tag_resource = cache_resource;
4996                         return 0;
4997                 }
4998         }
4999         /* Register new  resource. */
5000         cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
5001         if (!cache_resource)
5002                 return rte_flow_error_set(error, ENOMEM,
5003                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5004                                           "cannot allocate resource memory");
5005         *cache_resource = *resource;
5006         cache_resource->action = mlx5_glue->dv_create_flow_action_tag
5007                 (resource->tag);
5008         if (!cache_resource->action) {
5009                 rte_free(cache_resource);
5010                 return rte_flow_error_set(error, ENOMEM,
5011                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5012                                           NULL, "cannot create action");
5013         }
5014         rte_atomic32_init(&cache_resource->refcnt);
5015         rte_atomic32_inc(&cache_resource->refcnt);
5016         LIST_INSERT_HEAD(&sh->tags, cache_resource, next);
5017         dev_flow->flow->tag_resource = cache_resource;
5018         DRV_LOG(DEBUG, "new tag resource %p: refcnt %d++",
5019                 (void *)cache_resource,
5020                 rte_atomic32_read(&cache_resource->refcnt));
5021         return 0;
5022 }
5023
5024 /**
5025  * Release the tag.
5026  *
5027  * @param dev
5028  *   Pointer to Ethernet device.
5029  * @param flow
5030  *   Pointer to mlx5_flow.
5031  *
5032  * @return
5033  *   1 while a reference on it exists, 0 when freed.
5034  */
5035 static int
5036 flow_dv_tag_release(struct rte_eth_dev *dev,
5037                     struct mlx5_flow_dv_tag_resource *tag)
5038 {
5039         assert(tag);
5040         DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
5041                 dev->data->port_id, (void *)tag,
5042                 rte_atomic32_read(&tag->refcnt));
5043         if (rte_atomic32_dec_and_test(&tag->refcnt)) {
5044                 claim_zero(mlx5_glue->destroy_flow_action(tag->action));
5045                 LIST_REMOVE(tag, next);
5046                 DRV_LOG(DEBUG, "port %u tag %p: removed",
5047                         dev->data->port_id, (void *)tag);
5048                 rte_free(tag);
5049                 return 0;
5050         }
5051         return 1;
5052 }
5053
5054 /**
5055  * Translate port ID action to vport.
5056  *
5057  * @param[in] dev
5058  *   Pointer to rte_eth_dev structure.
5059  * @param[in] action
5060  *   Pointer to the port ID action.
5061  * @param[out] dst_port_id
5062  *   The target port ID.
5063  * @param[out] error
5064  *   Pointer to the error structure.
5065  *
5066  * @return
5067  *   0 on success, a negative errno value otherwise and rte_errno is set.
5068  */
5069 static int
5070 flow_dv_translate_action_port_id(struct rte_eth_dev *dev,
5071                                  const struct rte_flow_action *action,
5072                                  uint32_t *dst_port_id,
5073                                  struct rte_flow_error *error)
5074 {
5075         uint32_t port;
5076         uint16_t port_id;
5077         int ret;
5078         const struct rte_flow_action_port_id *conf =
5079                         (const struct rte_flow_action_port_id *)action->conf;
5080
5081         port = conf->original ? dev->data->port_id : conf->id;
5082         ret = mlx5_port_to_eswitch_info(port, NULL, &port_id);
5083         if (ret)
5084                 return rte_flow_error_set(error, -ret,
5085                                           RTE_FLOW_ERROR_TYPE_ACTION,
5086                                           NULL,
5087                                           "No eswitch info was found for port");
5088         *dst_port_id = port_id;
5089         return 0;
5090 }
5091
5092 /**
5093  * Fill the flow with DV spec.
5094  *
5095  * @param[in] dev
5096  *   Pointer to rte_eth_dev structure.
5097  * @param[in, out] dev_flow
5098  *   Pointer to the sub flow.
5099  * @param[in] attr
5100  *   Pointer to the flow attributes.
5101  * @param[in] items
5102  *   Pointer to the list of items.
5103  * @param[in] actions
5104  *   Pointer to the list of actions.
5105  * @param[out] error
5106  *   Pointer to the error structure.
5107  *
5108  * @return
5109  *   0 on success, a negative errno value otherwise and rte_errno is set.
5110  */
5111 static int
5112 flow_dv_translate(struct rte_eth_dev *dev,
5113                   struct mlx5_flow *dev_flow,
5114                   const struct rte_flow_attr *attr,
5115                   const struct rte_flow_item items[],
5116                   const struct rte_flow_action actions[],
5117                   struct rte_flow_error *error)
5118 {
5119         struct mlx5_priv *priv = dev->data->dev_private;
5120         struct rte_flow *flow = dev_flow->flow;
5121         uint64_t item_flags = 0;
5122         uint64_t last_item = 0;
5123         uint64_t action_flags = 0;
5124         uint64_t priority = attr->priority;
5125         struct mlx5_flow_dv_matcher matcher = {
5126                 .mask = {
5127                         .size = sizeof(matcher.mask.buf),
5128                 },
5129         };
5130         int actions_n = 0;
5131         bool actions_end = false;
5132         struct mlx5_flow_dv_modify_hdr_resource res = {
5133                 .ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
5134                                           MLX5DV_FLOW_TABLE_TYPE_NIC_RX
5135         };
5136         union flow_dv_attr flow_attr = { .attr = 0 };
5137         struct mlx5_flow_dv_tag_resource tag_resource;
5138         uint32_t modify_action_position = UINT32_MAX;
5139         void *match_mask = matcher.mask.buf;
5140         void *match_value = dev_flow->dv.value.buf;
5141         uint8_t next_protocol = 0xff;
5142         struct rte_vlan_hdr vlan = { 0 };
5143         bool vlan_inherited = false;
5144         uint16_t vlan_tci;
5145
5146         flow->group = attr->group;
5147         if (attr->transfer)
5148                 res.ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
5149         if (priority == MLX5_FLOW_PRIO_RSVD)
5150                 priority = priv->config.flow_prio - 1;
5151         for (; !actions_end ; actions++) {
5152                 const struct rte_flow_action_queue *queue;
5153                 const struct rte_flow_action_rss *rss;
5154                 const struct rte_flow_action *action = actions;
5155                 const struct rte_flow_action_count *count = action->conf;
5156                 const uint8_t *rss_key;
5157                 const struct rte_flow_action_jump *jump_data;
5158                 struct mlx5_flow_dv_jump_tbl_resource jump_tbl_resource;
5159                 struct mlx5_flow_tbl_resource *tbl;
5160                 uint32_t port_id = 0;
5161                 struct mlx5_flow_dv_port_id_action_resource port_id_resource;
5162
5163                 switch (actions->type) {
5164                 case RTE_FLOW_ACTION_TYPE_VOID:
5165                         break;
5166                 case RTE_FLOW_ACTION_TYPE_PORT_ID:
5167                         if (flow_dv_translate_action_port_id(dev, action,
5168                                                              &port_id, error))
5169                                 return -rte_errno;
5170                         port_id_resource.port_id = port_id;
5171                         if (flow_dv_port_id_action_resource_register
5172                             (dev, &port_id_resource, dev_flow, error))
5173                                 return -rte_errno;
5174                         dev_flow->dv.actions[actions_n++] =
5175                                 dev_flow->dv.port_id_action->action;
5176                         action_flags |= MLX5_FLOW_ACTION_PORT_ID;
5177                         break;
5178                 case RTE_FLOW_ACTION_TYPE_FLAG:
5179                         tag_resource.tag =
5180                                 mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
5181                         if (!flow->tag_resource)
5182                                 if (flow_dv_tag_resource_register
5183                                     (dev, &tag_resource, dev_flow, error))
5184                                         return errno;
5185                         dev_flow->dv.actions[actions_n++] =
5186                                 flow->tag_resource->action;
5187                         action_flags |= MLX5_FLOW_ACTION_FLAG;
5188                         break;
5189                 case RTE_FLOW_ACTION_TYPE_MARK:
5190                         tag_resource.tag = mlx5_flow_mark_set
5191                               (((const struct rte_flow_action_mark *)
5192                                (actions->conf))->id);
5193                         if (!flow->tag_resource)
5194                                 if (flow_dv_tag_resource_register
5195                                     (dev, &tag_resource, dev_flow, error))
5196                                         return errno;
5197                         dev_flow->dv.actions[actions_n++] =
5198                                 flow->tag_resource->action;
5199                         action_flags |= MLX5_FLOW_ACTION_MARK;
5200                         break;
5201                 case RTE_FLOW_ACTION_TYPE_DROP:
5202                         action_flags |= MLX5_FLOW_ACTION_DROP;
5203                         break;
5204                 case RTE_FLOW_ACTION_TYPE_QUEUE:
5205                         queue = actions->conf;
5206                         flow->rss.queue_num = 1;
5207                         (*flow->queue)[0] = queue->index;
5208                         action_flags |= MLX5_FLOW_ACTION_QUEUE;
5209                         break;
5210                 case RTE_FLOW_ACTION_TYPE_RSS:
5211                         rss = actions->conf;
5212                         if (flow->queue)
5213                                 memcpy((*flow->queue), rss->queue,
5214                                        rss->queue_num * sizeof(uint16_t));
5215                         flow->rss.queue_num = rss->queue_num;
5216                         /* NULL RSS key indicates default RSS key. */
5217                         rss_key = !rss->key ? rss_hash_default_key : rss->key;
5218                         memcpy(flow->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
5219                         /* RSS type 0 indicates default RSS type ETH_RSS_IP. */
5220                         flow->rss.types = !rss->types ? ETH_RSS_IP : rss->types;
5221                         flow->rss.level = rss->level;
5222                         action_flags |= MLX5_FLOW_ACTION_RSS;
5223                         break;
5224                 case RTE_FLOW_ACTION_TYPE_COUNT:
5225                         if (!priv->config.devx) {
5226                                 rte_errno = ENOTSUP;
5227                                 goto cnt_err;
5228                         }
5229                         flow->counter = flow_dv_counter_alloc(dev,
5230                                                               count->shared,
5231                                                               count->id,
5232                                                               attr->group);
5233                         if (flow->counter == NULL)
5234                                 goto cnt_err;
5235                         dev_flow->dv.actions[actions_n++] =
5236                                 flow->counter->action;
5237                         action_flags |= MLX5_FLOW_ACTION_COUNT;
5238                         break;
5239 cnt_err:
5240                         if (rte_errno == ENOTSUP)
5241                                 return rte_flow_error_set
5242                                               (error, ENOTSUP,
5243                                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5244                                                NULL,
5245                                                "count action not supported");
5246                         else
5247                                 return rte_flow_error_set
5248                                                 (error, rte_errno,
5249                                                  RTE_FLOW_ERROR_TYPE_ACTION,
5250                                                  action,
5251                                                  "cannot create counter"
5252                                                   " object.");
5253                         break;
5254                 case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
5255                         dev_flow->dv.actions[actions_n++] =
5256                                                 priv->sh->pop_vlan_action;
5257                         action_flags |= MLX5_FLOW_ACTION_OF_POP_VLAN;
5258                         break;
5259                 case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
5260                         if (!vlan_inherited) {
5261                                 flow_dev_get_vlan_info_from_items(items, &vlan);
5262                                 vlan_inherited = true;
5263                         }
5264                         vlan.eth_proto = rte_be_to_cpu_16
5265                              ((((const struct rte_flow_action_of_push_vlan *)
5266                                                    actions->conf)->ethertype));
5267                         if (flow_dv_create_action_push_vlan
5268                                             (dev, attr, &vlan, dev_flow, error))
5269                                 return -rte_errno;
5270                         dev_flow->dv.actions[actions_n++] =
5271                                            dev_flow->dv.push_vlan_res->action;
5272                         action_flags |= MLX5_FLOW_ACTION_OF_PUSH_VLAN;
5273                         /* Push VLAN command is also handling this VLAN_VID */
5274                         action_flags &= ~MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
5275                         break;
5276                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
5277                         if (!vlan_inherited) {
5278                                 flow_dev_get_vlan_info_from_items(items, &vlan);
5279                                 vlan_inherited = true;
5280                         }
5281                         vlan_tci =
5282                             ((const struct rte_flow_action_of_set_vlan_pcp *)
5283                                                        actions->conf)->vlan_pcp;
5284                         vlan_tci = vlan_tci << MLX5DV_FLOW_VLAN_PCP_SHIFT;
5285                         vlan.vlan_tci &= ~MLX5DV_FLOW_VLAN_PCP_MASK;
5286                         vlan.vlan_tci |= vlan_tci;
5287                         /* Push VLAN command will use this value */
5288                         break;
5289                 case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
5290                         if (!vlan_inherited) {
5291                                 flow_dev_get_vlan_info_from_items(items, &vlan);
5292                                 vlan_inherited = true;
5293                         }
5294                         vlan.vlan_tci &= ~MLX5DV_FLOW_VLAN_VID_MASK;
5295                         vlan.vlan_tci |= rte_be_to_cpu_16
5296                             (((const struct rte_flow_action_of_set_vlan_vid *)
5297                                                      actions->conf)->vlan_vid);
5298                         /* Push VLAN command will use this value */
5299                         if (mlx5_flow_find_action
5300                                 (actions,
5301                                  RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN))
5302                                 break;
5303                         /* If no VLAN push - this is a modify header action */
5304                         if (flow_dv_convert_action_modify_vlan_vid
5305                                                         (&res, actions, error))
5306                                 return -rte_errno;
5307                         action_flags |= MLX5_FLOW_ACTION_OF_SET_VLAN_VID;
5308                         break;
5309                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
5310                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
5311                         if (flow_dv_create_action_l2_encap(dev, actions,
5312                                                            dev_flow,
5313                                                            attr->transfer,
5314                                                            error))
5315                                 return -rte_errno;
5316                         dev_flow->dv.actions[actions_n++] =
5317                                 dev_flow->dv.encap_decap->verbs_action;
5318                         action_flags |= actions->type ==
5319                                         RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP ?
5320                                         MLX5_FLOW_ACTION_VXLAN_ENCAP :
5321                                         MLX5_FLOW_ACTION_NVGRE_ENCAP;
5322                         break;
5323                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
5324                 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
5325                         if (flow_dv_create_action_l2_decap(dev, dev_flow,
5326                                                            attr->transfer,
5327                                                            error))
5328                                 return -rte_errno;
5329                         dev_flow->dv.actions[actions_n++] =
5330                                 dev_flow->dv.encap_decap->verbs_action;
5331                         action_flags |= actions->type ==
5332                                         RTE_FLOW_ACTION_TYPE_VXLAN_DECAP ?
5333                                         MLX5_FLOW_ACTION_VXLAN_DECAP :
5334                                         MLX5_FLOW_ACTION_NVGRE_DECAP;
5335                         break;
5336                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
5337                         /* Handle encap with preceding decap. */
5338                         if (action_flags & MLX5_FLOW_ACTION_RAW_DECAP) {
5339                                 if (flow_dv_create_action_raw_encap
5340                                         (dev, actions, dev_flow, attr, error))
5341                                         return -rte_errno;
5342                                 dev_flow->dv.actions[actions_n++] =
5343                                         dev_flow->dv.encap_decap->verbs_action;
5344                         } else {
5345                                 /* Handle encap without preceding decap. */
5346                                 if (flow_dv_create_action_l2_encap
5347                                     (dev, actions, dev_flow, attr->transfer,
5348                                      error))
5349                                         return -rte_errno;
5350                                 dev_flow->dv.actions[actions_n++] =
5351                                         dev_flow->dv.encap_decap->verbs_action;
5352                         }
5353                         action_flags |= MLX5_FLOW_ACTION_RAW_ENCAP;
5354                         break;
5355                 case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
5356                         /* Check if this decap is followed by encap. */
5357                         for (; action->type != RTE_FLOW_ACTION_TYPE_END &&
5358                                action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP;
5359                                action++) {
5360                         }
5361                         /* Handle decap only if it isn't followed by encap. */
5362                         if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
5363                                 if (flow_dv_create_action_l2_decap
5364                                     (dev, dev_flow, attr->transfer, error))
5365                                         return -rte_errno;
5366                                 dev_flow->dv.actions[actions_n++] =
5367                                         dev_flow->dv.encap_decap->verbs_action;
5368                         }
5369                         /* If decap is followed by encap, handle it at encap. */
5370                         action_flags |= MLX5_FLOW_ACTION_RAW_DECAP;
5371                         break;
5372                 case RTE_FLOW_ACTION_TYPE_JUMP:
5373                         jump_data = action->conf;
5374                         tbl = flow_dv_tbl_resource_get(dev, jump_data->group,
5375                                                        attr->egress,
5376                                                        attr->transfer, error);
5377                         if (!tbl)
5378                                 return rte_flow_error_set
5379                                                 (error, errno,
5380                                                  RTE_FLOW_ERROR_TYPE_ACTION,
5381                                                  NULL,
5382                                                  "cannot create jump action.");
5383                         jump_tbl_resource.tbl = tbl;
5384                         if (flow_dv_jump_tbl_resource_register
5385                             (dev, &jump_tbl_resource, dev_flow, error)) {
5386                                 flow_dv_tbl_resource_release(tbl);
5387                                 return rte_flow_error_set
5388                                                 (error, errno,
5389                                                  RTE_FLOW_ERROR_TYPE_ACTION,
5390                                                  NULL,
5391                                                  "cannot create jump action.");
5392                         }
5393                         dev_flow->dv.actions[actions_n++] =
5394                                 dev_flow->dv.jump->action;
5395                         action_flags |= MLX5_FLOW_ACTION_JUMP;
5396                         break;
5397                 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
5398                 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
5399                         if (flow_dv_convert_action_modify_mac(&res, actions,
5400                                                               error))
5401                                 return -rte_errno;
5402                         action_flags |= actions->type ==
5403                                         RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
5404                                         MLX5_FLOW_ACTION_SET_MAC_SRC :
5405                                         MLX5_FLOW_ACTION_SET_MAC_DST;
5406                         break;
5407                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
5408                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
5409                         if (flow_dv_convert_action_modify_ipv4(&res, actions,
5410                                                                error))
5411                                 return -rte_errno;
5412                         action_flags |= actions->type ==
5413                                         RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
5414                                         MLX5_FLOW_ACTION_SET_IPV4_SRC :
5415                                         MLX5_FLOW_ACTION_SET_IPV4_DST;
5416                         break;
5417                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
5418                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
5419                         if (flow_dv_convert_action_modify_ipv6(&res, actions,
5420                                                                error))
5421                                 return -rte_errno;
5422                         action_flags |= actions->type ==
5423                                         RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
5424                                         MLX5_FLOW_ACTION_SET_IPV6_SRC :
5425                                         MLX5_FLOW_ACTION_SET_IPV6_DST;
5426                         break;
5427                 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
5428                 case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
5429                         if (flow_dv_convert_action_modify_tp(&res, actions,
5430                                                              items, &flow_attr,
5431                                                              error))
5432                                 return -rte_errno;
5433                         action_flags |= actions->type ==
5434                                         RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
5435                                         MLX5_FLOW_ACTION_SET_TP_SRC :
5436                                         MLX5_FLOW_ACTION_SET_TP_DST;
5437                         break;
5438                 case RTE_FLOW_ACTION_TYPE_DEC_TTL:
5439                         if (flow_dv_convert_action_modify_dec_ttl(&res, items,
5440                                                                   &flow_attr,
5441                                                                   error))
5442                                 return -rte_errno;
5443                         action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
5444                         break;
5445                 case RTE_FLOW_ACTION_TYPE_SET_TTL:
5446                         if (flow_dv_convert_action_modify_ttl(&res, actions,
5447                                                              items, &flow_attr,
5448                                                              error))
5449                                 return -rte_errno;
5450                         action_flags |= MLX5_FLOW_ACTION_SET_TTL;
5451                         break;
5452                 case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
5453                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
5454                         if (flow_dv_convert_action_modify_tcp_seq(&res, actions,
5455                                                                   error))
5456                                 return -rte_errno;
5457                         action_flags |= actions->type ==
5458                                         RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ ?
5459                                         MLX5_FLOW_ACTION_INC_TCP_SEQ :
5460                                         MLX5_FLOW_ACTION_DEC_TCP_SEQ;
5461                         break;
5462
5463                 case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
5464                 case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
5465                         if (flow_dv_convert_action_modify_tcp_ack(&res, actions,
5466                                                                   error))
5467                                 return -rte_errno;
5468                         action_flags |= actions->type ==
5469                                         RTE_FLOW_ACTION_TYPE_INC_TCP_ACK ?
5470                                         MLX5_FLOW_ACTION_INC_TCP_ACK :
5471                                         MLX5_FLOW_ACTION_DEC_TCP_ACK;
5472                         break;
5473                 case RTE_FLOW_ACTION_TYPE_END:
5474                         actions_end = true;
5475                         if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) {
5476                                 /* create modify action if needed. */
5477                                 if (flow_dv_modify_hdr_resource_register
5478                                                                 (dev, &res,
5479                                                                  dev_flow,
5480                                                                  error))
5481                                         return -rte_errno;
5482                                 dev_flow->dv.actions[modify_action_position] =
5483                                         dev_flow->dv.modify_hdr->verbs_action;
5484                         }
5485                         break;
5486                 default:
5487                         break;
5488                 }
5489                 if ((action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) &&
5490                     modify_action_position == UINT32_MAX)
5491                         modify_action_position = actions_n++;
5492         }
5493         dev_flow->dv.actions_n = actions_n;
5494         flow->actions = action_flags;
5495         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
5496                 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
5497
5498                 switch (items->type) {
5499                 case RTE_FLOW_ITEM_TYPE_PORT_ID:
5500                         flow_dv_translate_item_port_id(dev, match_mask,
5501                                                        match_value, items);
5502                         last_item = MLX5_FLOW_ITEM_PORT_ID;
5503                         break;
5504                 case RTE_FLOW_ITEM_TYPE_ETH:
5505                         flow_dv_translate_item_eth(match_mask, match_value,
5506                                                    items, tunnel);
5507                         matcher.priority = MLX5_PRIORITY_MAP_L2;
5508                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
5509                                              MLX5_FLOW_LAYER_OUTER_L2;
5510                         break;
5511                 case RTE_FLOW_ITEM_TYPE_VLAN:
5512                         flow_dv_translate_item_vlan(dev_flow,
5513                                                     match_mask, match_value,
5514                                                     items, tunnel);
5515                         matcher.priority = MLX5_PRIORITY_MAP_L2;
5516                         last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
5517                                               MLX5_FLOW_LAYER_INNER_VLAN) :
5518                                              (MLX5_FLOW_LAYER_OUTER_L2 |
5519                                               MLX5_FLOW_LAYER_OUTER_VLAN);
5520                         break;
5521                 case RTE_FLOW_ITEM_TYPE_IPV4:
5522                         mlx5_flow_tunnel_ip_check(items, next_protocol,
5523                                                   &item_flags, &tunnel);
5524                         flow_dv_translate_item_ipv4(match_mask, match_value,
5525                                                     items, tunnel, attr->group);
5526                         matcher.priority = MLX5_PRIORITY_MAP_L3;
5527                         dev_flow->dv.hash_fields |=
5528                                 mlx5_flow_hashfields_adjust
5529                                         (dev_flow, tunnel,
5530                                          MLX5_IPV4_LAYER_TYPES,
5531                                          MLX5_IPV4_IBV_RX_HASH);
5532                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
5533                                              MLX5_FLOW_LAYER_OUTER_L3_IPV4;
5534                         if (items->mask != NULL &&
5535                             ((const struct rte_flow_item_ipv4 *)
5536                              items->mask)->hdr.next_proto_id) {
5537                                 next_protocol =
5538                                         ((const struct rte_flow_item_ipv4 *)
5539                                          (items->spec))->hdr.next_proto_id;
5540                                 next_protocol &=
5541                                         ((const struct rte_flow_item_ipv4 *)
5542                                          (items->mask))->hdr.next_proto_id;
5543                         } else {
5544                                 /* Reset for inner layer. */
5545                                 next_protocol = 0xff;
5546                         }
5547                         break;
5548                 case RTE_FLOW_ITEM_TYPE_IPV6:
5549                         mlx5_flow_tunnel_ip_check(items, next_protocol,
5550                                                   &item_flags, &tunnel);
5551                         flow_dv_translate_item_ipv6(match_mask, match_value,
5552                                                     items, tunnel, attr->group);
5553                         matcher.priority = MLX5_PRIORITY_MAP_L3;
5554                         dev_flow->dv.hash_fields |=
5555                                 mlx5_flow_hashfields_adjust
5556                                         (dev_flow, tunnel,
5557                                          MLX5_IPV6_LAYER_TYPES,
5558                                          MLX5_IPV6_IBV_RX_HASH);
5559                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
5560                                              MLX5_FLOW_LAYER_OUTER_L3_IPV6;
5561                         if (items->mask != NULL &&
5562                             ((const struct rte_flow_item_ipv6 *)
5563                              items->mask)->hdr.proto) {
5564                                 next_protocol =
5565                                         ((const struct rte_flow_item_ipv6 *)
5566                                          items->spec)->hdr.proto;
5567                                 next_protocol &=
5568                                         ((const struct rte_flow_item_ipv6 *)
5569                                          items->mask)->hdr.proto;
5570                         } else {
5571                                 /* Reset for inner layer. */
5572                                 next_protocol = 0xff;
5573                         }
5574                         break;
5575                 case RTE_FLOW_ITEM_TYPE_TCP:
5576                         flow_dv_translate_item_tcp(match_mask, match_value,
5577                                                    items, tunnel);
5578                         matcher.priority = MLX5_PRIORITY_MAP_L4;
5579                         dev_flow->dv.hash_fields |=
5580                                 mlx5_flow_hashfields_adjust
5581                                         (dev_flow, tunnel, ETH_RSS_TCP,
5582                                          IBV_RX_HASH_SRC_PORT_TCP |
5583                                          IBV_RX_HASH_DST_PORT_TCP);
5584                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
5585                                              MLX5_FLOW_LAYER_OUTER_L4_TCP;
5586                         break;
5587                 case RTE_FLOW_ITEM_TYPE_UDP:
5588                         flow_dv_translate_item_udp(match_mask, match_value,
5589                                                    items, tunnel);
5590                         matcher.priority = MLX5_PRIORITY_MAP_L4;
5591                         dev_flow->dv.hash_fields |=
5592                                 mlx5_flow_hashfields_adjust
5593                                         (dev_flow, tunnel, ETH_RSS_UDP,
5594                                          IBV_RX_HASH_SRC_PORT_UDP |
5595                                          IBV_RX_HASH_DST_PORT_UDP);
5596                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
5597                                              MLX5_FLOW_LAYER_OUTER_L4_UDP;
5598                         break;
5599                 case RTE_FLOW_ITEM_TYPE_GRE:
5600                         flow_dv_translate_item_gre(match_mask, match_value,
5601                                                    items, tunnel);
5602                         last_item = MLX5_FLOW_LAYER_GRE;
5603                         break;
5604                 case RTE_FLOW_ITEM_TYPE_GRE_KEY:
5605                         flow_dv_translate_item_gre_key(match_mask,
5606                                                        match_value, items);
5607                         last_item = MLX5_FLOW_LAYER_GRE_KEY;
5608                         break;
5609                 case RTE_FLOW_ITEM_TYPE_NVGRE:
5610                         flow_dv_translate_item_nvgre(match_mask, match_value,
5611                                                      items, tunnel);
5612                         last_item = MLX5_FLOW_LAYER_GRE;
5613                         break;
5614                 case RTE_FLOW_ITEM_TYPE_VXLAN:
5615                         flow_dv_translate_item_vxlan(match_mask, match_value,
5616                                                      items, tunnel);
5617                         last_item = MLX5_FLOW_LAYER_VXLAN;
5618                         break;
5619                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
5620                         flow_dv_translate_item_vxlan(match_mask, match_value,
5621                                                      items, tunnel);
5622                         last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
5623                         break;
5624                 case RTE_FLOW_ITEM_TYPE_MPLS:
5625                         flow_dv_translate_item_mpls(match_mask, match_value,
5626                                                     items, last_item, tunnel);
5627                         last_item = MLX5_FLOW_LAYER_MPLS;
5628                         break;
5629                 case RTE_FLOW_ITEM_TYPE_META:
5630                         flow_dv_translate_item_meta(match_mask, match_value,
5631                                                     items);
5632                         last_item = MLX5_FLOW_ITEM_METADATA;
5633                         break;
5634                 case RTE_FLOW_ITEM_TYPE_ICMP:
5635                         flow_dv_translate_item_icmp(match_mask, match_value,
5636                                                     items, tunnel);
5637                         last_item = MLX5_FLOW_LAYER_ICMP;
5638                         break;
5639                 case RTE_FLOW_ITEM_TYPE_ICMP6:
5640                         flow_dv_translate_item_icmp6(match_mask, match_value,
5641                                                       items, tunnel);
5642                         last_item = MLX5_FLOW_LAYER_ICMP6;
5643                         break;
5644                 default:
5645                         break;
5646                 }
5647                 item_flags |= last_item;
5648         }
5649         /*
5650          * In case of ingress traffic when E-Switch mode is enabled,
5651          * we have two cases where we need to set the source port manually.
5652          * The first one, is in case of Nic steering rule, and the second is
5653          * E-Switch rule where no port_id item was found. In both cases
5654          * the source port is set according the current port in use.
5655          */
5656         if ((attr->ingress && !(item_flags & MLX5_FLOW_ITEM_PORT_ID)) &&
5657             (priv->representor || priv->master)) {
5658                 if (flow_dv_translate_item_port_id(dev, match_mask,
5659                                                    match_value, NULL))
5660                         return -rte_errno;
5661         }
5662         assert(!flow_dv_check_valid_spec(matcher.mask.buf,
5663                                          dev_flow->dv.value.buf));
5664         dev_flow->layers = item_flags;
5665         /* Register matcher. */
5666         matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
5667                                     matcher.mask.size);
5668         matcher.priority = mlx5_flow_adjust_priority(dev, priority,
5669                                                      matcher.priority);
5670         matcher.egress = attr->egress;
5671         matcher.group = attr->group;
5672         matcher.transfer = attr->transfer;
5673         if (flow_dv_matcher_register(dev, &matcher, dev_flow, error))
5674                 return -rte_errno;
5675         return 0;
5676 }
5677
5678 /**
5679  * Apply the flow to the NIC.
5680  *
5681  * @param[in] dev
5682  *   Pointer to the Ethernet device structure.
5683  * @param[in, out] flow
5684  *   Pointer to flow structure.
5685  * @param[out] error
5686  *   Pointer to error structure.
5687  *
5688  * @return
5689  *   0 on success, a negative errno value otherwise and rte_errno is set.
5690  */
5691 static int
5692 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
5693               struct rte_flow_error *error)
5694 {
5695         struct mlx5_flow_dv *dv;
5696         struct mlx5_flow *dev_flow;
5697         struct mlx5_priv *priv = dev->data->dev_private;
5698         int n;
5699         int err;
5700
5701         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
5702                 dv = &dev_flow->dv;
5703                 n = dv->actions_n;
5704                 if (flow->actions & MLX5_FLOW_ACTION_DROP) {
5705                         if (flow->transfer) {
5706                                 dv->actions[n++] = priv->sh->esw_drop_action;
5707                         } else {
5708                                 dv->hrxq = mlx5_hrxq_drop_new(dev);
5709                                 if (!dv->hrxq) {
5710                                         rte_flow_error_set
5711                                                 (error, errno,
5712                                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5713                                                  NULL,
5714                                                  "cannot get drop hash queue");
5715                                         goto error;
5716                                 }
5717                                 dv->actions[n++] = dv->hrxq->action;
5718                         }
5719                 } else if (flow->actions &
5720                            (MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)) {
5721                         struct mlx5_hrxq *hrxq;
5722
5723                         hrxq = mlx5_hrxq_get(dev, flow->key,
5724                                              MLX5_RSS_HASH_KEY_LEN,
5725                                              dv->hash_fields,
5726                                              (*flow->queue),
5727                                              flow->rss.queue_num);
5728                         if (!hrxq) {
5729                                 hrxq = mlx5_hrxq_new
5730                                         (dev, flow->key, MLX5_RSS_HASH_KEY_LEN,
5731                                          dv->hash_fields, (*flow->queue),
5732                                          flow->rss.queue_num,
5733                                          !!(dev_flow->layers &
5734                                             MLX5_FLOW_LAYER_TUNNEL));
5735                         }
5736                         if (!hrxq) {
5737                                 rte_flow_error_set
5738                                         (error, rte_errno,
5739                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
5740                                          "cannot get hash queue");
5741                                 goto error;
5742                         }
5743                         dv->hrxq = hrxq;
5744                         dv->actions[n++] = dv->hrxq->action;
5745                 }
5746                 dv->flow =
5747                         mlx5_glue->dv_create_flow(dv->matcher->matcher_object,
5748                                                   (void *)&dv->value, n,
5749                                                   dv->actions);
5750                 if (!dv->flow) {
5751                         rte_flow_error_set(error, errno,
5752                                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5753                                            NULL,
5754                                            "hardware refuses to create flow");
5755                         goto error;
5756                 }
5757                 if (priv->vmwa_context &&
5758                     dev_flow->dv.vf_vlan.tag &&
5759                     !dev_flow->dv.vf_vlan.created) {
5760                         /*
5761                          * The rule contains the VLAN pattern.
5762                          * For VF we are going to create VLAN
5763                          * interface to make hypervisor set correct
5764                          * e-Switch vport context.
5765                          */
5766                         mlx5_vlan_vmwa_acquire(dev, &dev_flow->dv.vf_vlan);
5767                 }
5768         }
5769         return 0;
5770 error:
5771         err = rte_errno; /* Save rte_errno before cleanup. */
5772         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
5773                 struct mlx5_flow_dv *dv = &dev_flow->dv;
5774                 if (dv->hrxq) {
5775                         if (flow->actions & MLX5_FLOW_ACTION_DROP)
5776                                 mlx5_hrxq_drop_release(dev);
5777                         else
5778                                 mlx5_hrxq_release(dev, dv->hrxq);
5779                         dv->hrxq = NULL;
5780                 }
5781                 if (dev_flow->dv.vf_vlan.tag &&
5782                     dev_flow->dv.vf_vlan.created)
5783                         mlx5_vlan_vmwa_release(dev, &dev_flow->dv.vf_vlan);
5784         }
5785         rte_errno = err; /* Restore rte_errno. */
5786         return -rte_errno;
5787 }
5788
5789 /**
5790  * Release the flow matcher.
5791  *
5792  * @param dev
5793  *   Pointer to Ethernet device.
5794  * @param flow
5795  *   Pointer to mlx5_flow.
5796  *
5797  * @return
5798  *   1 while a reference on it exists, 0 when freed.
5799  */
5800 static int
5801 flow_dv_matcher_release(struct rte_eth_dev *dev,
5802                         struct mlx5_flow *flow)
5803 {
5804         struct mlx5_flow_dv_matcher *matcher = flow->dv.matcher;
5805         struct mlx5_priv *priv = dev->data->dev_private;
5806         struct mlx5_ibv_shared *sh = priv->sh;
5807         struct mlx5_flow_tbl_resource *tbl;
5808
5809         assert(matcher->matcher_object);
5810         DRV_LOG(DEBUG, "port %u matcher %p: refcnt %d--",
5811                 dev->data->port_id, (void *)matcher,
5812                 rte_atomic32_read(&matcher->refcnt));
5813         if (rte_atomic32_dec_and_test(&matcher->refcnt)) {
5814                 claim_zero(mlx5_glue->dv_destroy_flow_matcher
5815                            (matcher->matcher_object));
5816                 LIST_REMOVE(matcher, next);
5817                 if (matcher->egress)
5818                         tbl = &sh->tx_tbl[matcher->group];
5819                 else
5820                         tbl = &sh->rx_tbl[matcher->group];
5821                 flow_dv_tbl_resource_release(tbl);
5822                 rte_free(matcher);
5823                 DRV_LOG(DEBUG, "port %u matcher %p: removed",
5824                         dev->data->port_id, (void *)matcher);
5825                 return 0;
5826         }
5827         return 1;
5828 }
5829
5830 /**
5831  * Release an encap/decap resource.
5832  *
5833  * @param flow
5834  *   Pointer to mlx5_flow.
5835  *
5836  * @return
5837  *   1 while a reference on it exists, 0 when freed.
5838  */
5839 static int
5840 flow_dv_encap_decap_resource_release(struct mlx5_flow *flow)
5841 {
5842         struct mlx5_flow_dv_encap_decap_resource *cache_resource =
5843                                                 flow->dv.encap_decap;
5844
5845         assert(cache_resource->verbs_action);
5846         DRV_LOG(DEBUG, "encap/decap resource %p: refcnt %d--",
5847                 (void *)cache_resource,
5848                 rte_atomic32_read(&cache_resource->refcnt));
5849         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
5850                 claim_zero(mlx5_glue->destroy_flow_action
5851                                 (cache_resource->verbs_action));
5852                 LIST_REMOVE(cache_resource, next);
5853                 rte_free(cache_resource);
5854                 DRV_LOG(DEBUG, "encap/decap resource %p: removed",
5855                         (void *)cache_resource);
5856                 return 0;
5857         }
5858         return 1;
5859 }
5860
5861 /**
5862  * Release an jump to table action resource.
5863  *
5864  * @param flow
5865  *   Pointer to mlx5_flow.
5866  *
5867  * @return
5868  *   1 while a reference on it exists, 0 when freed.
5869  */
5870 static int
5871 flow_dv_jump_tbl_resource_release(struct mlx5_flow *flow)
5872 {
5873         struct mlx5_flow_dv_jump_tbl_resource *cache_resource =
5874                                                 flow->dv.jump;
5875
5876         assert(cache_resource->action);
5877         DRV_LOG(DEBUG, "jump table resource %p: refcnt %d--",
5878                 (void *)cache_resource,
5879                 rte_atomic32_read(&cache_resource->refcnt));
5880         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
5881                 claim_zero(mlx5_glue->destroy_flow_action
5882                                 (cache_resource->action));
5883                 LIST_REMOVE(cache_resource, next);
5884                 flow_dv_tbl_resource_release(cache_resource->tbl);
5885                 rte_free(cache_resource);
5886                 DRV_LOG(DEBUG, "jump table resource %p: removed",
5887                         (void *)cache_resource);
5888                 return 0;
5889         }
5890         return 1;
5891 }
5892
5893 /**
5894  * Release a modify-header resource.
5895  *
5896  * @param flow
5897  *   Pointer to mlx5_flow.
5898  *
5899  * @return
5900  *   1 while a reference on it exists, 0 when freed.
5901  */
5902 static int
5903 flow_dv_modify_hdr_resource_release(struct mlx5_flow *flow)
5904 {
5905         struct mlx5_flow_dv_modify_hdr_resource *cache_resource =
5906                                                 flow->dv.modify_hdr;
5907
5908         assert(cache_resource->verbs_action);
5909         DRV_LOG(DEBUG, "modify-header resource %p: refcnt %d--",
5910                 (void *)cache_resource,
5911                 rte_atomic32_read(&cache_resource->refcnt));
5912         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
5913                 claim_zero(mlx5_glue->destroy_flow_action
5914                                 (cache_resource->verbs_action));
5915                 LIST_REMOVE(cache_resource, next);
5916                 rte_free(cache_resource);
5917                 DRV_LOG(DEBUG, "modify-header resource %p: removed",
5918                         (void *)cache_resource);
5919                 return 0;
5920         }
5921         return 1;
5922 }
5923
5924 /**
5925  * Release port ID action resource.
5926  *
5927  * @param flow
5928  *   Pointer to mlx5_flow.
5929  *
5930  * @return
5931  *   1 while a reference on it exists, 0 when freed.
5932  */
5933 static int
5934 flow_dv_port_id_action_resource_release(struct mlx5_flow *flow)
5935 {
5936         struct mlx5_flow_dv_port_id_action_resource *cache_resource =
5937                 flow->dv.port_id_action;
5938
5939         assert(cache_resource->action);
5940         DRV_LOG(DEBUG, "port ID action resource %p: refcnt %d--",
5941                 (void *)cache_resource,
5942                 rte_atomic32_read(&cache_resource->refcnt));
5943         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
5944                 claim_zero(mlx5_glue->destroy_flow_action
5945                                 (cache_resource->action));
5946                 LIST_REMOVE(cache_resource, next);
5947                 rte_free(cache_resource);
5948                 DRV_LOG(DEBUG, "port id action resource %p: removed",
5949                         (void *)cache_resource);
5950                 return 0;
5951         }
5952         return 1;
5953 }
5954
5955 /**
5956  * Release push vlan action resource.
5957  *
5958  * @param flow
5959  *   Pointer to mlx5_flow.
5960  *
5961  * @return
5962  *   1 while a reference on it exists, 0 when freed.
5963  */
5964 static int
5965 flow_dv_push_vlan_action_resource_release(struct mlx5_flow *flow)
5966 {
5967         struct mlx5_flow_dv_push_vlan_action_resource *cache_resource =
5968                 flow->dv.push_vlan_res;
5969
5970         assert(cache_resource->action);
5971         DRV_LOG(DEBUG, "push VLAN action resource %p: refcnt %d--",
5972                 (void *)cache_resource,
5973                 rte_atomic32_read(&cache_resource->refcnt));
5974         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
5975                 claim_zero(mlx5_glue->destroy_flow_action
5976                                 (cache_resource->action));
5977                 LIST_REMOVE(cache_resource, next);
5978                 rte_free(cache_resource);
5979                 DRV_LOG(DEBUG, "push vlan action resource %p: removed",
5980                         (void *)cache_resource);
5981                 return 0;
5982         }
5983         return 1;
5984 }
5985
5986 /**
5987  * Remove the flow from the NIC but keeps it in memory.
5988  *
5989  * @param[in] dev
5990  *   Pointer to Ethernet device.
5991  * @param[in, out] flow
5992  *   Pointer to flow structure.
5993  */
5994 static void
5995 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
5996 {
5997         struct mlx5_flow_dv *dv;
5998         struct mlx5_flow *dev_flow;
5999
6000         if (!flow)
6001                 return;
6002         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
6003                 dv = &dev_flow->dv;
6004                 if (dv->flow) {
6005                         claim_zero(mlx5_glue->dv_destroy_flow(dv->flow));
6006                         dv->flow = NULL;
6007                 }
6008                 if (dv->hrxq) {
6009                         if (flow->actions & MLX5_FLOW_ACTION_DROP)
6010                                 mlx5_hrxq_drop_release(dev);
6011                         else
6012                                 mlx5_hrxq_release(dev, dv->hrxq);
6013                         dv->hrxq = NULL;
6014                 }
6015                 if (dev_flow->dv.vf_vlan.tag &&
6016                     dev_flow->dv.vf_vlan.created)
6017                         mlx5_vlan_vmwa_release(dev, &dev_flow->dv.vf_vlan);
6018         }
6019 }
6020
6021 /**
6022  * Remove the flow from the NIC and the memory.
6023  *
6024  * @param[in] dev
6025  *   Pointer to the Ethernet device structure.
6026  * @param[in, out] flow
6027  *   Pointer to flow structure.
6028  */
6029 static void
6030 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
6031 {
6032         struct mlx5_flow *dev_flow;
6033
6034         if (!flow)
6035                 return;
6036         flow_dv_remove(dev, flow);
6037         if (flow->counter) {
6038                 flow_dv_counter_release(dev, flow->counter);
6039                 flow->counter = NULL;
6040         }
6041         if (flow->tag_resource) {
6042                 flow_dv_tag_release(dev, flow->tag_resource);
6043                 flow->tag_resource = NULL;
6044         }
6045         while (!LIST_EMPTY(&flow->dev_flows)) {
6046                 dev_flow = LIST_FIRST(&flow->dev_flows);
6047                 LIST_REMOVE(dev_flow, next);
6048                 if (dev_flow->dv.matcher)
6049                         flow_dv_matcher_release(dev, dev_flow);
6050                 if (dev_flow->dv.encap_decap)
6051                         flow_dv_encap_decap_resource_release(dev_flow);
6052                 if (dev_flow->dv.modify_hdr)
6053                         flow_dv_modify_hdr_resource_release(dev_flow);
6054                 if (dev_flow->dv.jump)
6055                         flow_dv_jump_tbl_resource_release(dev_flow);
6056                 if (dev_flow->dv.port_id_action)
6057                         flow_dv_port_id_action_resource_release(dev_flow);
6058                 if (dev_flow->dv.push_vlan_res)
6059                         flow_dv_push_vlan_action_resource_release(dev_flow);
6060                 rte_free(dev_flow);
6061         }
6062 }
6063
6064 /**
6065  * Query a dv flow  rule for its statistics via devx.
6066  *
6067  * @param[in] dev
6068  *   Pointer to Ethernet device.
6069  * @param[in] flow
6070  *   Pointer to the sub flow.
6071  * @param[out] data
6072  *   data retrieved by the query.
6073  * @param[out] error
6074  *   Perform verbose error reporting if not NULL.
6075  *
6076  * @return
6077  *   0 on success, a negative errno value otherwise and rte_errno is set.
6078  */
6079 static int
6080 flow_dv_query_count(struct rte_eth_dev *dev, struct rte_flow *flow,
6081                     void *data, struct rte_flow_error *error)
6082 {
6083         struct mlx5_priv *priv = dev->data->dev_private;
6084         struct rte_flow_query_count *qc = data;
6085
6086         if (!priv->config.devx)
6087                 return rte_flow_error_set(error, ENOTSUP,
6088                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6089                                           NULL,
6090                                           "counters are not supported");
6091         if (flow->counter) {
6092                 uint64_t pkts, bytes;
6093                 int err = _flow_dv_query_count(dev, flow->counter, &pkts,
6094                                                &bytes);
6095
6096                 if (err)
6097                         return rte_flow_error_set(error, -err,
6098                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6099                                         NULL, "cannot read counters");
6100                 qc->hits_set = 1;
6101                 qc->bytes_set = 1;
6102                 qc->hits = pkts - flow->counter->hits;
6103                 qc->bytes = bytes - flow->counter->bytes;
6104                 if (qc->reset) {
6105                         flow->counter->hits = pkts;
6106                         flow->counter->bytes = bytes;
6107                 }
6108                 return 0;
6109         }
6110         return rte_flow_error_set(error, EINVAL,
6111                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
6112                                   NULL,
6113                                   "counters are not available");
6114 }
6115
6116 /**
6117  * Query a flow.
6118  *
6119  * @see rte_flow_query()
6120  * @see rte_flow_ops
6121  */
6122 static int
6123 flow_dv_query(struct rte_eth_dev *dev,
6124               struct rte_flow *flow __rte_unused,
6125               const struct rte_flow_action *actions __rte_unused,
6126               void *data __rte_unused,
6127               struct rte_flow_error *error __rte_unused)
6128 {
6129         int ret = -EINVAL;
6130
6131         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
6132                 switch (actions->type) {
6133                 case RTE_FLOW_ACTION_TYPE_VOID:
6134                         break;
6135                 case RTE_FLOW_ACTION_TYPE_COUNT:
6136                         ret = flow_dv_query_count(dev, flow, data, error);
6137                         break;
6138                 default:
6139                         return rte_flow_error_set(error, ENOTSUP,
6140                                                   RTE_FLOW_ERROR_TYPE_ACTION,
6141                                                   actions,
6142                                                   "action not supported");
6143                 }
6144         }
6145         return ret;
6146 }
6147
6148 /*
6149  * Mutex-protected thunk to flow_dv_translate().
6150  */
6151 static int
6152 flow_d_translate(struct rte_eth_dev *dev,
6153                  struct mlx5_flow *dev_flow,
6154                  const struct rte_flow_attr *attr,
6155                  const struct rte_flow_item items[],
6156                  const struct rte_flow_action actions[],
6157                  struct rte_flow_error *error)
6158 {
6159         int ret;
6160
6161         flow_d_shared_lock(dev);
6162         ret = flow_dv_translate(dev, dev_flow, attr, items, actions, error);
6163         flow_d_shared_unlock(dev);
6164         return ret;
6165 }
6166
6167 /*
6168  * Mutex-protected thunk to flow_dv_apply().
6169  */
6170 static int
6171 flow_d_apply(struct rte_eth_dev *dev,
6172              struct rte_flow *flow,
6173              struct rte_flow_error *error)
6174 {
6175         int ret;
6176
6177         flow_d_shared_lock(dev);
6178         ret = flow_dv_apply(dev, flow, error);
6179         flow_d_shared_unlock(dev);
6180         return ret;
6181 }
6182
6183 /*
6184  * Mutex-protected thunk to flow_dv_remove().
6185  */
6186 static void
6187 flow_d_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
6188 {
6189         flow_d_shared_lock(dev);
6190         flow_dv_remove(dev, flow);
6191         flow_d_shared_unlock(dev);
6192 }
6193
6194 /*
6195  * Mutex-protected thunk to flow_dv_destroy().
6196  */
6197 static void
6198 flow_d_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
6199 {
6200         flow_d_shared_lock(dev);
6201         flow_dv_destroy(dev, flow);
6202         flow_d_shared_unlock(dev);
6203 }
6204
6205 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
6206         .validate = flow_dv_validate,
6207         .prepare = flow_dv_prepare,
6208         .translate = flow_d_translate,
6209         .apply = flow_d_apply,
6210         .remove = flow_d_remove,
6211         .destroy = flow_d_destroy,
6212         .query = flow_dv_query,
6213 };
6214
6215 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */