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