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