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