f048920c1da0f5955a25ce1ce86ad70c7ce33b58
[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 static uint32_t matcher_zero[MLX5_ST_SZ_DW(fte_match_param)] = { 0 };
3089
3090 #define HEADER_IS_ZERO(match_criteria, headers)                              \
3091         !(memcmp(MLX5_ADDR_OF(fte_match_param, match_criteria, headers),     \
3092                  matcher_zero, MLX5_FLD_SZ_BYTES(fte_match_param, headers))) \
3093
3094 /**
3095  * Calculate flow matcher enable bitmap.
3096  *
3097  * @param match_criteria
3098  *   Pointer to flow matcher criteria.
3099  *
3100  * @return
3101  *   Bitmap of enabled fields.
3102  */
3103 static uint8_t
3104 flow_dv_matcher_enable(uint32_t *match_criteria)
3105 {
3106         uint8_t match_criteria_enable;
3107
3108         match_criteria_enable =
3109                 (!HEADER_IS_ZERO(match_criteria, outer_headers)) <<
3110                 MLX5_MATCH_CRITERIA_ENABLE_OUTER_BIT;
3111         match_criteria_enable |=
3112                 (!HEADER_IS_ZERO(match_criteria, misc_parameters)) <<
3113                 MLX5_MATCH_CRITERIA_ENABLE_MISC_BIT;
3114         match_criteria_enable |=
3115                 (!HEADER_IS_ZERO(match_criteria, inner_headers)) <<
3116                 MLX5_MATCH_CRITERIA_ENABLE_INNER_BIT;
3117         match_criteria_enable |=
3118                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_2)) <<
3119                 MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
3120 #ifdef HAVE_MLX5DV_DR
3121         match_criteria_enable |=
3122                 (!HEADER_IS_ZERO(match_criteria, misc_parameters_3)) <<
3123                 MLX5_MATCH_CRITERIA_ENABLE_MISC3_BIT;
3124 #endif
3125         return match_criteria_enable;
3126 }
3127
3128
3129 /**
3130  * Get a flow table.
3131  *
3132  * @param dev[in, out]
3133  *   Pointer to rte_eth_dev structure.
3134  * @param[in] table_id
3135  *   Table id to use.
3136  * @param[in] egress
3137  *   Direction of the table.
3138  * @param[out] error
3139  *   pointer to error structure.
3140  *
3141  * @return
3142  *   Returns tables resource based on the index, NULL in case of failed.
3143  */
3144 static struct mlx5_flow_tbl_resource *
3145 flow_dv_tbl_resource_get(struct rte_eth_dev *dev,
3146                          uint32_t table_id, uint8_t egress,
3147                          struct rte_flow_error *error)
3148 {
3149         struct mlx5_priv *priv = dev->data->dev_private;
3150         struct mlx5_ibv_shared *sh = priv->sh;
3151         struct mlx5_flow_tbl_resource *tbl;
3152
3153 #ifdef HAVE_MLX5DV_DR
3154         if (egress) {
3155                 tbl = &sh->tx_tbl[table_id];
3156                 if (!tbl->obj)
3157                         tbl->obj = mlx5_glue->dr_create_flow_tbl
3158                                 (sh->tx_ns, table_id);
3159         } else {
3160                 tbl = &sh->rx_tbl[table_id];
3161                 if (!tbl->obj)
3162                         tbl->obj = mlx5_glue->dr_create_flow_tbl
3163                                 (sh->rx_ns, table_id);
3164         }
3165         if (!tbl->obj) {
3166                 rte_flow_error_set(error, ENOMEM,
3167                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3168                                    NULL, "cannot create table");
3169                 return NULL;
3170         }
3171         rte_atomic32_inc(&tbl->refcnt);
3172         return tbl;
3173 #else
3174         (void)error;
3175         (void)tbl;
3176         if (egress)
3177                 return &sh->tx_tbl[table_id];
3178         else
3179                 return &sh->rx_tbl[table_id];
3180 #endif
3181 }
3182
3183 /**
3184  * Release a flow table.
3185  *
3186  * @param[in] tbl
3187  *   Table resource to be released.
3188  *
3189  * @return
3190  *   Returns 0 if table was released, else return 1;
3191  */
3192 static int
3193 flow_dv_tbl_resource_release(struct mlx5_flow_tbl_resource *tbl)
3194 {
3195         if (!tbl)
3196                 return 0;
3197         if (rte_atomic32_dec_and_test(&tbl->refcnt)) {
3198                 mlx5_glue->dr_destroy_flow_tbl(tbl->obj);
3199                 tbl->obj = NULL;
3200                 return 0;
3201         }
3202         return 1;
3203 }
3204
3205 /**
3206  * Register the flow matcher.
3207  *
3208  * @param dev[in, out]
3209  *   Pointer to rte_eth_dev structure.
3210  * @param[in, out] matcher
3211  *   Pointer to flow matcher.
3212  * @parm[in, out] dev_flow
3213  *   Pointer to the dev_flow.
3214  * @param[out] error
3215  *   pointer to error structure.
3216  *
3217  * @return
3218  *   0 on success otherwise -errno and errno is set.
3219  */
3220 static int
3221 flow_dv_matcher_register(struct rte_eth_dev *dev,
3222                          struct mlx5_flow_dv_matcher *matcher,
3223                          struct mlx5_flow *dev_flow,
3224                          struct rte_flow_error *error)
3225 {
3226         struct mlx5_priv *priv = dev->data->dev_private;
3227         struct mlx5_ibv_shared *sh = priv->sh;
3228         struct mlx5_flow_dv_matcher *cache_matcher;
3229         struct mlx5dv_flow_matcher_attr dv_attr = {
3230                 .type = IBV_FLOW_ATTR_NORMAL,
3231                 .match_mask = (void *)&matcher->mask,
3232         };
3233         struct mlx5_flow_tbl_resource *tbl = NULL;
3234
3235         /* Lookup from cache. */
3236         LIST_FOREACH(cache_matcher, &sh->matchers, next) {
3237                 if (matcher->crc == cache_matcher->crc &&
3238                     matcher->priority == cache_matcher->priority &&
3239                     matcher->egress == cache_matcher->egress &&
3240                     matcher->group == cache_matcher->group &&
3241                     !memcmp((const void *)matcher->mask.buf,
3242                             (const void *)cache_matcher->mask.buf,
3243                             cache_matcher->mask.size)) {
3244                         DRV_LOG(DEBUG,
3245                                 "priority %hd use %s matcher %p: refcnt %d++",
3246                                 cache_matcher->priority,
3247                                 cache_matcher->egress ? "tx" : "rx",
3248                                 (void *)cache_matcher,
3249                                 rte_atomic32_read(&cache_matcher->refcnt));
3250                         rte_atomic32_inc(&cache_matcher->refcnt);
3251                         dev_flow->dv.matcher = cache_matcher;
3252                         return 0;
3253                 }
3254         }
3255         /* Register new matcher. */
3256         cache_matcher = rte_calloc(__func__, 1, sizeof(*cache_matcher), 0);
3257         if (!cache_matcher)
3258                 return rte_flow_error_set(error, ENOMEM,
3259                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3260                                           "cannot allocate matcher memory");
3261         tbl = flow_dv_tbl_resource_get(dev, matcher->group * MLX5_GROUP_FACTOR,
3262                                        matcher->egress, error);
3263         if (!tbl) {
3264                 rte_free(cache_matcher);
3265                 return rte_flow_error_set(error, ENOMEM,
3266                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3267                                           NULL, "cannot create table");
3268         }
3269         *cache_matcher = *matcher;
3270         dv_attr.match_criteria_enable =
3271                 flow_dv_matcher_enable(cache_matcher->mask.buf);
3272         dv_attr.priority = matcher->priority;
3273         if (matcher->egress)
3274                 dv_attr.flags |= IBV_FLOW_ATTR_FLAGS_EGRESS;
3275         cache_matcher->matcher_object =
3276                 mlx5_glue->dv_create_flow_matcher(sh->ctx, &dv_attr, tbl->obj);
3277         if (!cache_matcher->matcher_object) {
3278                 rte_free(cache_matcher);
3279 #ifdef HAVE_MLX5DV_DR
3280                 flow_dv_tbl_resource_release(tbl);
3281 #endif
3282                 return rte_flow_error_set(error, ENOMEM,
3283                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3284                                           NULL, "cannot create matcher");
3285         }
3286         rte_atomic32_inc(&cache_matcher->refcnt);
3287         LIST_INSERT_HEAD(&sh->matchers, cache_matcher, next);
3288         dev_flow->dv.matcher = cache_matcher;
3289         DRV_LOG(DEBUG, "priority %hd new %s matcher %p: refcnt %d",
3290                 cache_matcher->priority,
3291                 cache_matcher->egress ? "tx" : "rx", (void *)cache_matcher,
3292                 rte_atomic32_read(&cache_matcher->refcnt));
3293         rte_atomic32_inc(&tbl->refcnt);
3294         return 0;
3295 }
3296
3297 /**
3298  * Add source vport match to the specified matcher.
3299  *
3300  * @param[in, out] matcher
3301  *   Flow matcher.
3302  * @param[in, out] key
3303  *   Flow matcher value.
3304  * @param[in] port
3305  *   Source vport value to match
3306  * @param[in] mask
3307  *   Mask
3308  */
3309 static void
3310 flow_dv_translate_item_source_vport(void *matcher, void *key,
3311                                     int16_t port, uint16_t mask)
3312 {
3313         void *misc_m = MLX5_ADDR_OF(fte_match_param, matcher, misc_parameters);
3314         void *misc_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters);
3315
3316         MLX5_SET(fte_match_set_misc, misc_m, source_port, mask);
3317         MLX5_SET(fte_match_set_misc, misc_v, source_port, port);
3318 }
3319
3320 /**
3321  * Find existing tag resource or create and register a new one.
3322  *
3323  * @param dev[in, out]
3324  *   Pointer to rte_eth_dev structure.
3325  * @param[in, out] resource
3326  *   Pointer to tag resource.
3327  * @parm[in, out] dev_flow
3328  *   Pointer to the dev_flow.
3329  * @param[out] error
3330  *   pointer to error structure.
3331  *
3332  * @return
3333  *   0 on success otherwise -errno and errno is set.
3334  */
3335 static int
3336 flow_dv_tag_resource_register
3337                         (struct rte_eth_dev *dev,
3338                          struct mlx5_flow_dv_tag_resource *resource,
3339                          struct mlx5_flow *dev_flow,
3340                          struct rte_flow_error *error)
3341 {
3342         struct mlx5_priv *priv = dev->data->dev_private;
3343         struct mlx5_ibv_shared *sh = priv->sh;
3344         struct mlx5_flow_dv_tag_resource *cache_resource;
3345
3346         /* Lookup a matching resource from cache. */
3347         LIST_FOREACH(cache_resource, &sh->tags, next) {
3348                 if (resource->tag == cache_resource->tag) {
3349                         DRV_LOG(DEBUG, "tag resource %p: refcnt %d++",
3350                                 (void *)cache_resource,
3351                                 rte_atomic32_read(&cache_resource->refcnt));
3352                         rte_atomic32_inc(&cache_resource->refcnt);
3353                         dev_flow->flow->tag_resource = cache_resource;
3354                         return 0;
3355                 }
3356         }
3357         /* Register new  resource. */
3358         cache_resource = rte_calloc(__func__, 1, sizeof(*cache_resource), 0);
3359         if (!cache_resource)
3360                 return rte_flow_error_set(error, ENOMEM,
3361                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3362                                           "cannot allocate resource memory");
3363         *cache_resource = *resource;
3364         cache_resource->action = mlx5_glue->dv_create_flow_action_tag
3365                 (resource->tag);
3366         if (!cache_resource->action) {
3367                 rte_free(cache_resource);
3368                 return rte_flow_error_set(error, ENOMEM,
3369                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3370                                           NULL, "cannot create action");
3371         }
3372         rte_atomic32_init(&cache_resource->refcnt);
3373         rte_atomic32_inc(&cache_resource->refcnt);
3374         LIST_INSERT_HEAD(&sh->tags, cache_resource, next);
3375         dev_flow->flow->tag_resource = cache_resource;
3376         DRV_LOG(DEBUG, "new tag resource %p: refcnt %d++",
3377                 (void *)cache_resource,
3378                 rte_atomic32_read(&cache_resource->refcnt));
3379         return 0;
3380 }
3381
3382 /**
3383  * Release the tag.
3384  *
3385  * @param dev
3386  *   Pointer to Ethernet device.
3387  * @param flow
3388  *   Pointer to mlx5_flow.
3389  *
3390  * @return
3391  *   1 while a reference on it exists, 0 when freed.
3392  */
3393 static int
3394 flow_dv_tag_release(struct rte_eth_dev *dev,
3395                     struct mlx5_flow_dv_tag_resource *tag)
3396 {
3397         assert(tag);
3398         DRV_LOG(DEBUG, "port %u tag %p: refcnt %d--",
3399                 dev->data->port_id, (void *)tag,
3400                 rte_atomic32_read(&tag->refcnt));
3401         if (rte_atomic32_dec_and_test(&tag->refcnt)) {
3402                 claim_zero(mlx5_glue->destroy_flow_action(tag->action));
3403                 LIST_REMOVE(tag, next);
3404                 DRV_LOG(DEBUG, "port %u tag %p: removed",
3405                         dev->data->port_id, (void *)tag);
3406                 rte_free(tag);
3407                 return 0;
3408         }
3409         return 1;
3410 }
3411
3412 /**
3413  * Fill the flow with DV spec.
3414  *
3415  * @param[in] dev
3416  *   Pointer to rte_eth_dev structure.
3417  * @param[in, out] dev_flow
3418  *   Pointer to the sub flow.
3419  * @param[in] attr
3420  *   Pointer to the flow attributes.
3421  * @param[in] items
3422  *   Pointer to the list of items.
3423  * @param[in] actions
3424  *   Pointer to the list of actions.
3425  * @param[out] error
3426  *   Pointer to the error structure.
3427  *
3428  * @return
3429  *   0 on success, a negative errno value otherwise and rte_errno is set.
3430  */
3431 static int
3432 flow_dv_translate(struct rte_eth_dev *dev,
3433                   struct mlx5_flow *dev_flow,
3434                   const struct rte_flow_attr *attr,
3435                   const struct rte_flow_item items[],
3436                   const struct rte_flow_action actions[],
3437                   struct rte_flow_error *error)
3438 {
3439         struct mlx5_priv *priv = dev->data->dev_private;
3440         struct rte_flow *flow = dev_flow->flow;
3441         uint64_t item_flags = 0;
3442         uint64_t last_item = 0;
3443         uint64_t action_flags = 0;
3444         uint64_t priority = attr->priority;
3445         struct mlx5_flow_dv_matcher matcher = {
3446                 .mask = {
3447                         .size = sizeof(matcher.mask.buf),
3448                 },
3449         };
3450         int actions_n = 0;
3451         bool actions_end = false;
3452         struct mlx5_flow_dv_modify_hdr_resource res = {
3453                 .ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
3454                                           MLX5DV_FLOW_TABLE_TYPE_NIC_RX
3455         };
3456         union flow_dv_attr flow_attr = { .attr = 0 };
3457         struct mlx5_flow_dv_tag_resource tag_resource;
3458         uint32_t modify_action_position = UINT32_MAX;
3459
3460         if (priority == MLX5_FLOW_PRIO_RSVD)
3461                 priority = priv->config.flow_prio - 1;
3462         for (; !actions_end ; actions++) {
3463                 const struct rte_flow_action_queue *queue;
3464                 const struct rte_flow_action_rss *rss;
3465                 const struct rte_flow_action *action = actions;
3466                 const struct rte_flow_action_count *count = action->conf;
3467                 const uint8_t *rss_key;
3468                 const struct rte_flow_action_jump *jump_data;
3469                 struct mlx5_flow_dv_jump_tbl_resource jump_tbl_resource;
3470                 struct mlx5_flow_tbl_resource *tbl;
3471
3472                 switch (actions->type) {
3473                 case RTE_FLOW_ACTION_TYPE_VOID:
3474                         break;
3475                 case RTE_FLOW_ACTION_TYPE_FLAG:
3476                         tag_resource.tag =
3477                                 mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT);
3478                         if (!flow->tag_resource)
3479                                 if (flow_dv_tag_resource_register
3480                                     (dev, &tag_resource, dev_flow, error))
3481                                         return errno;
3482                         dev_flow->dv.actions[actions_n++] =
3483                                 flow->tag_resource->action;
3484                         action_flags |= MLX5_FLOW_ACTION_FLAG;
3485                         break;
3486                 case RTE_FLOW_ACTION_TYPE_MARK:
3487                         tag_resource.tag = mlx5_flow_mark_set
3488                               (((const struct rte_flow_action_mark *)
3489                                (actions->conf))->id);
3490                         if (!flow->tag_resource)
3491                                 if (flow_dv_tag_resource_register
3492                                     (dev, &tag_resource, dev_flow, error))
3493                                         return errno;
3494                         dev_flow->dv.actions[actions_n++] =
3495                                 flow->tag_resource->action;
3496                         action_flags |= MLX5_FLOW_ACTION_MARK;
3497                         break;
3498                 case RTE_FLOW_ACTION_TYPE_DROP:
3499                         action_flags |= MLX5_FLOW_ACTION_DROP;
3500                         break;
3501                 case RTE_FLOW_ACTION_TYPE_QUEUE:
3502                         queue = actions->conf;
3503                         flow->rss.queue_num = 1;
3504                         (*flow->queue)[0] = queue->index;
3505                         action_flags |= MLX5_FLOW_ACTION_QUEUE;
3506                         break;
3507                 case RTE_FLOW_ACTION_TYPE_RSS:
3508                         rss = actions->conf;
3509                         if (flow->queue)
3510                                 memcpy((*flow->queue), rss->queue,
3511                                        rss->queue_num * sizeof(uint16_t));
3512                         flow->rss.queue_num = rss->queue_num;
3513                         /* NULL RSS key indicates default RSS key. */
3514                         rss_key = !rss->key ? rss_hash_default_key : rss->key;
3515                         memcpy(flow->key, rss_key, MLX5_RSS_HASH_KEY_LEN);
3516                         /* RSS type 0 indicates default RSS type ETH_RSS_IP. */
3517                         flow->rss.types = !rss->types ? ETH_RSS_IP : rss->types;
3518                         flow->rss.level = rss->level;
3519                         action_flags |= MLX5_FLOW_ACTION_RSS;
3520                         break;
3521                 case RTE_FLOW_ACTION_TYPE_COUNT:
3522                         if (!priv->config.devx) {
3523                                 rte_errno = ENOTSUP;
3524                                 goto cnt_err;
3525                         }
3526                         flow->counter = flow_dv_counter_new(dev, count->shared,
3527                                                             count->id);
3528                         if (flow->counter == NULL)
3529                                 goto cnt_err;
3530                         dev_flow->dv.actions[actions_n++] =
3531                                 flow->counter->action;
3532                         action_flags |= MLX5_FLOW_ACTION_COUNT;
3533                         break;
3534 cnt_err:
3535                         if (rte_errno == ENOTSUP)
3536                                 return rte_flow_error_set
3537                                               (error, ENOTSUP,
3538                                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3539                                                NULL,
3540                                                "count action not supported");
3541                         else
3542                                 return rte_flow_error_set
3543                                                 (error, rte_errno,
3544                                                  RTE_FLOW_ERROR_TYPE_ACTION,
3545                                                  action,
3546                                                  "cannot create counter"
3547                                                   " object.");
3548                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
3549                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
3550                         if (flow_dv_create_action_l2_encap(dev, actions,
3551                                                            dev_flow, error))
3552                                 return -rte_errno;
3553                         dev_flow->dv.actions[actions_n++] =
3554                                 dev_flow->dv.encap_decap->verbs_action;
3555                         action_flags |= actions->type ==
3556                                         RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP ?
3557                                         MLX5_FLOW_ACTION_VXLAN_ENCAP :
3558                                         MLX5_FLOW_ACTION_NVGRE_ENCAP;
3559                         break;
3560                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
3561                 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
3562                         if (flow_dv_create_action_l2_decap(dev, dev_flow,
3563                                                            error))
3564                                 return -rte_errno;
3565                         dev_flow->dv.actions[actions_n++] =
3566                                 dev_flow->dv.encap_decap->verbs_action;
3567                         action_flags |= actions->type ==
3568                                         RTE_FLOW_ACTION_TYPE_VXLAN_DECAP ?
3569                                         MLX5_FLOW_ACTION_VXLAN_DECAP :
3570                                         MLX5_FLOW_ACTION_NVGRE_DECAP;
3571                         break;
3572                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
3573                         /* Handle encap with preceding decap. */
3574                         if (action_flags & MLX5_FLOW_ACTION_RAW_DECAP) {
3575                                 if (flow_dv_create_action_raw_encap
3576                                         (dev, actions, dev_flow, attr, error))
3577                                         return -rte_errno;
3578                                 dev_flow->dv.actions[actions_n++] =
3579                                         dev_flow->dv.encap_decap->verbs_action;
3580                         } else {
3581                                 /* Handle encap without preceding decap. */
3582                                 if (flow_dv_create_action_l2_encap(dev, actions,
3583                                                                    dev_flow,
3584                                                                    error))
3585                                         return -rte_errno;
3586                                 dev_flow->dv.actions[actions_n++] =
3587                                         dev_flow->dv.encap_decap->verbs_action;
3588                         }
3589                         action_flags |= MLX5_FLOW_ACTION_RAW_ENCAP;
3590                         break;
3591                 case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
3592                         /* Check if this decap is followed by encap. */
3593                         for (; action->type != RTE_FLOW_ACTION_TYPE_END &&
3594                                action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP;
3595                                action++) {
3596                         }
3597                         /* Handle decap only if it isn't followed by encap. */
3598                         if (action->type != RTE_FLOW_ACTION_TYPE_RAW_ENCAP) {
3599                                 if (flow_dv_create_action_l2_decap(dev,
3600                                                                    dev_flow,
3601                                                                    error))
3602                                         return -rte_errno;
3603                                 dev_flow->dv.actions[actions_n++] =
3604                                         dev_flow->dv.encap_decap->verbs_action;
3605                         }
3606                         /* If decap is followed by encap, handle it at encap. */
3607                         action_flags |= MLX5_FLOW_ACTION_RAW_DECAP;
3608                         break;
3609                 case RTE_FLOW_ACTION_TYPE_JUMP:
3610                         jump_data = action->conf;
3611                         tbl = flow_dv_tbl_resource_get(dev, jump_data->group *
3612                                                        MLX5_GROUP_FACTOR,
3613                                                        attr->egress, error);
3614                         if (!tbl)
3615                                 return rte_flow_error_set
3616                                                 (error, errno,
3617                                                  RTE_FLOW_ERROR_TYPE_ACTION,
3618                                                  NULL,
3619                                                  "cannot create jump action.");
3620                         jump_tbl_resource.tbl = tbl;
3621                         if (flow_dv_jump_tbl_resource_register
3622                             (dev, &jump_tbl_resource, dev_flow, error)) {
3623                                 flow_dv_tbl_resource_release(tbl);
3624                                 return rte_flow_error_set
3625                                                 (error, errno,
3626                                                  RTE_FLOW_ERROR_TYPE_ACTION,
3627                                                  NULL,
3628                                                  "cannot create jump action.");
3629                         }
3630                         dev_flow->dv.actions[actions_n++] =
3631                                 dev_flow->dv.jump->action;
3632                         action_flags |= MLX5_FLOW_ACTION_JUMP;
3633                         break;
3634                 case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
3635                 case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
3636                         if (flow_dv_convert_action_modify_mac(&res, actions,
3637                                                               error))
3638                                 return -rte_errno;
3639                         action_flags |= actions->type ==
3640                                         RTE_FLOW_ACTION_TYPE_SET_MAC_SRC ?
3641                                         MLX5_FLOW_ACTION_SET_MAC_SRC :
3642                                         MLX5_FLOW_ACTION_SET_MAC_DST;
3643                         break;
3644                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
3645                 case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
3646                         if (flow_dv_convert_action_modify_ipv4(&res, actions,
3647                                                                error))
3648                                 return -rte_errno;
3649                         action_flags |= actions->type ==
3650                                         RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC ?
3651                                         MLX5_FLOW_ACTION_SET_IPV4_SRC :
3652                                         MLX5_FLOW_ACTION_SET_IPV4_DST;
3653                         break;
3654                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
3655                 case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
3656                         if (flow_dv_convert_action_modify_ipv6(&res, actions,
3657                                                                error))
3658                                 return -rte_errno;
3659                         action_flags |= actions->type ==
3660                                         RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC ?
3661                                         MLX5_FLOW_ACTION_SET_IPV6_SRC :
3662                                         MLX5_FLOW_ACTION_SET_IPV6_DST;
3663                         break;
3664                 case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
3665                 case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
3666                         if (flow_dv_convert_action_modify_tp(&res, actions,
3667                                                              items, &flow_attr,
3668                                                              error))
3669                                 return -rte_errno;
3670                         action_flags |= actions->type ==
3671                                         RTE_FLOW_ACTION_TYPE_SET_TP_SRC ?
3672                                         MLX5_FLOW_ACTION_SET_TP_SRC :
3673                                         MLX5_FLOW_ACTION_SET_TP_DST;
3674                         break;
3675                 case RTE_FLOW_ACTION_TYPE_DEC_TTL:
3676                         if (flow_dv_convert_action_modify_dec_ttl(&res, items,
3677                                                                   &flow_attr,
3678                                                                   error))
3679                                 return -rte_errno;
3680                         action_flags |= MLX5_FLOW_ACTION_DEC_TTL;
3681                         break;
3682                 case RTE_FLOW_ACTION_TYPE_SET_TTL:
3683                         if (flow_dv_convert_action_modify_ttl(&res, actions,
3684                                                              items, &flow_attr,
3685                                                              error))
3686                                 return -rte_errno;
3687                         action_flags |= MLX5_FLOW_ACTION_SET_TTL;
3688                         break;
3689                 case RTE_FLOW_ACTION_TYPE_END:
3690                         actions_end = true;
3691                         if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) {
3692                                 /* create modify action if needed. */
3693                                 if (flow_dv_modify_hdr_resource_register
3694                                                                 (dev, &res,
3695                                                                  dev_flow,
3696                                                                  error))
3697                                         return -rte_errno;
3698                                 dev_flow->dv.actions[modify_action_position] =
3699                                         dev_flow->dv.modify_hdr->verbs_action;
3700                         }
3701                         break;
3702                 default:
3703                         break;
3704                 }
3705                 if ((action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS) &&
3706                     modify_action_position == UINT32_MAX)
3707                         modify_action_position = actions_n++;
3708         }
3709         dev_flow->dv.actions_n = actions_n;
3710         flow->actions = action_flags;
3711         if (attr->ingress && !attr->transfer &&
3712             (priv->representor || priv->master)) {
3713                 /* It was validated - we support unidirection flows only. */
3714                 assert(!attr->egress);
3715                 /*
3716                  * Add matching on source vport index only
3717                  * for ingress rules in E-Switch configurations.
3718                  */
3719                 flow_dv_translate_item_source_vport(matcher.mask.buf,
3720                                                     dev_flow->dv.value.buf,
3721                                                     priv->vport_id,
3722                                                     0xffff);
3723         }
3724         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
3725                 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
3726                 void *match_mask = matcher.mask.buf;
3727                 void *match_value = dev_flow->dv.value.buf;
3728
3729                 switch (items->type) {
3730                 case RTE_FLOW_ITEM_TYPE_ETH:
3731                         flow_dv_translate_item_eth(match_mask, match_value,
3732                                                    items, tunnel);
3733                         matcher.priority = MLX5_PRIORITY_MAP_L2;
3734                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
3735                                              MLX5_FLOW_LAYER_OUTER_L2;
3736                         break;
3737                 case RTE_FLOW_ITEM_TYPE_VLAN:
3738                         flow_dv_translate_item_vlan(match_mask, match_value,
3739                                                     items, tunnel);
3740                         matcher.priority = MLX5_PRIORITY_MAP_L2;
3741                         last_item = tunnel ? (MLX5_FLOW_LAYER_INNER_L2 |
3742                                               MLX5_FLOW_LAYER_INNER_VLAN) :
3743                                              (MLX5_FLOW_LAYER_OUTER_L2 |
3744                                               MLX5_FLOW_LAYER_OUTER_VLAN);
3745                         break;
3746                 case RTE_FLOW_ITEM_TYPE_IPV4:
3747                         flow_dv_translate_item_ipv4(match_mask, match_value,
3748                                                     items, tunnel, attr->group);
3749                         matcher.priority = MLX5_PRIORITY_MAP_L3;
3750                         dev_flow->dv.hash_fields |=
3751                                 mlx5_flow_hashfields_adjust
3752                                         (dev_flow, tunnel,
3753                                          MLX5_IPV4_LAYER_TYPES,
3754                                          MLX5_IPV4_IBV_RX_HASH);
3755                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
3756                                              MLX5_FLOW_LAYER_OUTER_L3_IPV4;
3757                         break;
3758                 case RTE_FLOW_ITEM_TYPE_IPV6:
3759                         flow_dv_translate_item_ipv6(match_mask, match_value,
3760                                                     items, tunnel, attr->group);
3761                         matcher.priority = MLX5_PRIORITY_MAP_L3;
3762                         dev_flow->dv.hash_fields |=
3763                                 mlx5_flow_hashfields_adjust
3764                                         (dev_flow, tunnel,
3765                                          MLX5_IPV6_LAYER_TYPES,
3766                                          MLX5_IPV6_IBV_RX_HASH);
3767                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
3768                                              MLX5_FLOW_LAYER_OUTER_L3_IPV6;
3769                         break;
3770                 case RTE_FLOW_ITEM_TYPE_TCP:
3771                         flow_dv_translate_item_tcp(match_mask, match_value,
3772                                                    items, tunnel);
3773                         matcher.priority = MLX5_PRIORITY_MAP_L4;
3774                         dev_flow->dv.hash_fields |=
3775                                 mlx5_flow_hashfields_adjust
3776                                         (dev_flow, tunnel, ETH_RSS_TCP,
3777                                          IBV_RX_HASH_SRC_PORT_TCP |
3778                                          IBV_RX_HASH_DST_PORT_TCP);
3779                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
3780                                              MLX5_FLOW_LAYER_OUTER_L4_TCP;
3781                         break;
3782                 case RTE_FLOW_ITEM_TYPE_UDP:
3783                         flow_dv_translate_item_udp(match_mask, match_value,
3784                                                    items, tunnel);
3785                         matcher.priority = MLX5_PRIORITY_MAP_L4;
3786                         dev_flow->dv.hash_fields |=
3787                                 mlx5_flow_hashfields_adjust
3788                                         (dev_flow, tunnel, ETH_RSS_UDP,
3789                                          IBV_RX_HASH_SRC_PORT_UDP |
3790                                          IBV_RX_HASH_DST_PORT_UDP);
3791                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
3792                                              MLX5_FLOW_LAYER_OUTER_L4_UDP;
3793                         break;
3794                 case RTE_FLOW_ITEM_TYPE_GRE:
3795                         flow_dv_translate_item_gre(match_mask, match_value,
3796                                                    items, tunnel);
3797                         last_item = MLX5_FLOW_LAYER_GRE;
3798                         break;
3799                 case RTE_FLOW_ITEM_TYPE_NVGRE:
3800                         flow_dv_translate_item_nvgre(match_mask, match_value,
3801                                                      items, tunnel);
3802                         last_item = MLX5_FLOW_LAYER_GRE;
3803                         break;
3804                 case RTE_FLOW_ITEM_TYPE_VXLAN:
3805                         flow_dv_translate_item_vxlan(match_mask, match_value,
3806                                                      items, tunnel);
3807                         last_item = MLX5_FLOW_LAYER_VXLAN;
3808                         break;
3809                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
3810                         flow_dv_translate_item_vxlan(match_mask, match_value,
3811                                                      items, tunnel);
3812                         last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
3813                         break;
3814                 case RTE_FLOW_ITEM_TYPE_MPLS:
3815                         flow_dv_translate_item_mpls(match_mask, match_value,
3816                                                     items, last_item, tunnel);
3817                         last_item = MLX5_FLOW_LAYER_MPLS;
3818                         break;
3819                 case RTE_FLOW_ITEM_TYPE_META:
3820                         flow_dv_translate_item_meta(match_mask, match_value,
3821                                                     items);
3822                         last_item = MLX5_FLOW_ITEM_METADATA;
3823                         break;
3824                 default:
3825                         break;
3826                 }
3827                 item_flags |= last_item;
3828         }
3829         assert(!flow_dv_check_valid_spec(matcher.mask.buf,
3830                                          dev_flow->dv.value.buf));
3831         dev_flow->layers = item_flags;
3832         /* Register matcher. */
3833         matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
3834                                     matcher.mask.size);
3835         matcher.priority = mlx5_flow_adjust_priority(dev, priority,
3836                                                      matcher.priority);
3837         matcher.egress = attr->egress;
3838         matcher.group = attr->group;
3839         if (flow_dv_matcher_register(dev, &matcher, dev_flow, error))
3840                 return -rte_errno;
3841         return 0;
3842 }
3843
3844 /**
3845  * Apply the flow to the NIC.
3846  *
3847  * @param[in] dev
3848  *   Pointer to the Ethernet device structure.
3849  * @param[in, out] flow
3850  *   Pointer to flow structure.
3851  * @param[out] error
3852  *   Pointer to error structure.
3853  *
3854  * @return
3855  *   0 on success, a negative errno value otherwise and rte_errno is set.
3856  */
3857 static int
3858 flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
3859               struct rte_flow_error *error)
3860 {
3861         struct mlx5_flow_dv *dv;
3862         struct mlx5_flow *dev_flow;
3863         int n;
3864         int err;
3865
3866         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
3867                 dv = &dev_flow->dv;
3868                 n = dv->actions_n;
3869                 if (flow->actions & MLX5_FLOW_ACTION_DROP) {
3870                         dv->hrxq = mlx5_hrxq_drop_new(dev);
3871                         if (!dv->hrxq) {
3872                                 rte_flow_error_set
3873                                         (error, errno,
3874                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3875                                          "cannot get drop hash queue");
3876                                 goto error;
3877                         }
3878                         dv->actions[n++] = dv->hrxq->action;
3879                 } else if (flow->actions &
3880                            (MLX5_FLOW_ACTION_QUEUE | MLX5_FLOW_ACTION_RSS)) {
3881                         struct mlx5_hrxq *hrxq;
3882
3883                         hrxq = mlx5_hrxq_get(dev, flow->key,
3884                                              MLX5_RSS_HASH_KEY_LEN,
3885                                              dv->hash_fields,
3886                                              (*flow->queue),
3887                                              flow->rss.queue_num);
3888                         if (!hrxq)
3889                                 hrxq = mlx5_hrxq_new
3890                                         (dev, flow->key, MLX5_RSS_HASH_KEY_LEN,
3891                                          dv->hash_fields, (*flow->queue),
3892                                          flow->rss.queue_num,
3893                                          !!(dev_flow->layers &
3894                                             MLX5_FLOW_LAYER_TUNNEL));
3895                         if (!hrxq) {
3896                                 rte_flow_error_set
3897                                         (error, rte_errno,
3898                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
3899                                          "cannot get hash queue");
3900                                 goto error;
3901                         }
3902                         dv->hrxq = hrxq;
3903                         dv->actions[n++] = dv->hrxq->action;
3904                 }
3905                 dv->flow =
3906                         mlx5_glue->dv_create_flow(dv->matcher->matcher_object,
3907                                                   (void *)&dv->value, n,
3908                                                   dv->actions);
3909                 if (!dv->flow) {
3910                         rte_flow_error_set(error, errno,
3911                                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
3912                                            NULL,
3913                                            "hardware refuses to create flow");
3914                         goto error;
3915                 }
3916         }
3917         return 0;
3918 error:
3919         err = rte_errno; /* Save rte_errno before cleanup. */
3920         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
3921                 struct mlx5_flow_dv *dv = &dev_flow->dv;
3922                 if (dv->hrxq) {
3923                         if (flow->actions & MLX5_FLOW_ACTION_DROP)
3924                                 mlx5_hrxq_drop_release(dev);
3925                         else
3926                                 mlx5_hrxq_release(dev, dv->hrxq);
3927                         dv->hrxq = NULL;
3928                 }
3929         }
3930         rte_errno = err; /* Restore rte_errno. */
3931         return -rte_errno;
3932 }
3933
3934 /**
3935  * Release the flow matcher.
3936  *
3937  * @param dev
3938  *   Pointer to Ethernet device.
3939  * @param flow
3940  *   Pointer to mlx5_flow.
3941  *
3942  * @return
3943  *   1 while a reference on it exists, 0 when freed.
3944  */
3945 static int
3946 flow_dv_matcher_release(struct rte_eth_dev *dev,
3947                         struct mlx5_flow *flow)
3948 {
3949         struct mlx5_flow_dv_matcher *matcher = flow->dv.matcher;
3950         struct mlx5_priv *priv = dev->data->dev_private;
3951         struct mlx5_ibv_shared *sh = priv->sh;
3952         struct mlx5_flow_tbl_resource *tbl;
3953
3954         assert(matcher->matcher_object);
3955         DRV_LOG(DEBUG, "port %u matcher %p: refcnt %d--",
3956                 dev->data->port_id, (void *)matcher,
3957                 rte_atomic32_read(&matcher->refcnt));
3958         if (rte_atomic32_dec_and_test(&matcher->refcnt)) {
3959                 claim_zero(mlx5_glue->dv_destroy_flow_matcher
3960                            (matcher->matcher_object));
3961                 LIST_REMOVE(matcher, next);
3962                 if (matcher->egress)
3963                         tbl = &sh->tx_tbl[matcher->group];
3964                 else
3965                         tbl = &sh->rx_tbl[matcher->group];
3966                 flow_dv_tbl_resource_release(tbl);
3967                 rte_free(matcher);
3968                 DRV_LOG(DEBUG, "port %u matcher %p: removed",
3969                         dev->data->port_id, (void *)matcher);
3970                 return 0;
3971         }
3972         return 1;
3973 }
3974
3975 /**
3976  * Release an encap/decap resource.
3977  *
3978  * @param flow
3979  *   Pointer to mlx5_flow.
3980  *
3981  * @return
3982  *   1 while a reference on it exists, 0 when freed.
3983  */
3984 static int
3985 flow_dv_encap_decap_resource_release(struct mlx5_flow *flow)
3986 {
3987         struct mlx5_flow_dv_encap_decap_resource *cache_resource =
3988                                                 flow->dv.encap_decap;
3989
3990         assert(cache_resource->verbs_action);
3991         DRV_LOG(DEBUG, "encap/decap resource %p: refcnt %d--",
3992                 (void *)cache_resource,
3993                 rte_atomic32_read(&cache_resource->refcnt));
3994         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
3995                 claim_zero(mlx5_glue->destroy_flow_action
3996                                 (cache_resource->verbs_action));
3997                 LIST_REMOVE(cache_resource, next);
3998                 rte_free(cache_resource);
3999                 DRV_LOG(DEBUG, "encap/decap resource %p: removed",
4000                         (void *)cache_resource);
4001                 return 0;
4002         }
4003         return 1;
4004 }
4005
4006 /**
4007  * Release an jump to table action resource.
4008  *
4009  * @param flow
4010  *   Pointer to mlx5_flow.
4011  *
4012  * @return
4013  *   1 while a reference on it exists, 0 when freed.
4014  */
4015 static int
4016 flow_dv_jump_tbl_resource_release(struct mlx5_flow *flow)
4017 {
4018         struct mlx5_flow_dv_jump_tbl_resource *cache_resource =
4019                                                 flow->dv.jump;
4020
4021         assert(cache_resource->action);
4022         DRV_LOG(DEBUG, "jump table resource %p: refcnt %d--",
4023                 (void *)cache_resource,
4024                 rte_atomic32_read(&cache_resource->refcnt));
4025         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
4026                 claim_zero(mlx5_glue->destroy_flow_action
4027                                 (cache_resource->action));
4028                 LIST_REMOVE(cache_resource, next);
4029                 flow_dv_tbl_resource_release(cache_resource->tbl);
4030                 rte_free(cache_resource);
4031                 DRV_LOG(DEBUG, "jump table resource %p: removed",
4032                         (void *)cache_resource);
4033                 return 0;
4034         }
4035         return 1;
4036 }
4037
4038 /**
4039  * Release a modify-header resource.
4040  *
4041  * @param flow
4042  *   Pointer to mlx5_flow.
4043  *
4044  * @return
4045  *   1 while a reference on it exists, 0 when freed.
4046  */
4047 static int
4048 flow_dv_modify_hdr_resource_release(struct mlx5_flow *flow)
4049 {
4050         struct mlx5_flow_dv_modify_hdr_resource *cache_resource =
4051                                                 flow->dv.modify_hdr;
4052
4053         assert(cache_resource->verbs_action);
4054         DRV_LOG(DEBUG, "modify-header resource %p: refcnt %d--",
4055                 (void *)cache_resource,
4056                 rte_atomic32_read(&cache_resource->refcnt));
4057         if (rte_atomic32_dec_and_test(&cache_resource->refcnt)) {
4058                 claim_zero(mlx5_glue->destroy_flow_action
4059                                 (cache_resource->verbs_action));
4060                 LIST_REMOVE(cache_resource, next);
4061                 rte_free(cache_resource);
4062                 DRV_LOG(DEBUG, "modify-header resource %p: removed",
4063                         (void *)cache_resource);
4064                 return 0;
4065         }
4066         return 1;
4067 }
4068
4069 /**
4070  * Remove the flow from the NIC but keeps it in memory.
4071  *
4072  * @param[in] dev
4073  *   Pointer to Ethernet device.
4074  * @param[in, out] flow
4075  *   Pointer to flow structure.
4076  */
4077 static void
4078 flow_dv_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
4079 {
4080         struct mlx5_flow_dv *dv;
4081         struct mlx5_flow *dev_flow;
4082
4083         if (!flow)
4084                 return;
4085         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
4086                 dv = &dev_flow->dv;
4087                 if (dv->flow) {
4088                         claim_zero(mlx5_glue->dv_destroy_flow(dv->flow));
4089                         dv->flow = NULL;
4090                 }
4091                 if (dv->hrxq) {
4092                         if (flow->actions & MLX5_FLOW_ACTION_DROP)
4093                                 mlx5_hrxq_drop_release(dev);
4094                         else
4095                                 mlx5_hrxq_release(dev, dv->hrxq);
4096                         dv->hrxq = NULL;
4097                 }
4098         }
4099 }
4100
4101 /**
4102  * Remove the flow from the NIC and the memory.
4103  *
4104  * @param[in] dev
4105  *   Pointer to the Ethernet device structure.
4106  * @param[in, out] flow
4107  *   Pointer to flow structure.
4108  */
4109 static void
4110 flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
4111 {
4112         struct mlx5_flow *dev_flow;
4113
4114         if (!flow)
4115                 return;
4116         flow_dv_remove(dev, flow);
4117         if (flow->counter) {
4118                 flow_dv_counter_release(flow->counter);
4119                 flow->counter = NULL;
4120         }
4121         if (flow->tag_resource) {
4122                 flow_dv_tag_release(dev, flow->tag_resource);
4123                 flow->tag_resource = NULL;
4124         }
4125         while (!LIST_EMPTY(&flow->dev_flows)) {
4126                 dev_flow = LIST_FIRST(&flow->dev_flows);
4127                 LIST_REMOVE(dev_flow, next);
4128                 if (dev_flow->dv.matcher)
4129                         flow_dv_matcher_release(dev, dev_flow);
4130                 if (dev_flow->dv.encap_decap)
4131                         flow_dv_encap_decap_resource_release(dev_flow);
4132                 if (dev_flow->dv.modify_hdr)
4133                         flow_dv_modify_hdr_resource_release(dev_flow);
4134                 if (dev_flow->dv.jump)
4135                         flow_dv_jump_tbl_resource_release(dev_flow);
4136                 rte_free(dev_flow);
4137         }
4138 }
4139
4140 /**
4141  * Query a dv flow  rule for its statistics via devx.
4142  *
4143  * @param[in] dev
4144  *   Pointer to Ethernet device.
4145  * @param[in] flow
4146  *   Pointer to the sub flow.
4147  * @param[out] data
4148  *   data retrieved by the query.
4149  * @param[out] error
4150  *   Perform verbose error reporting if not NULL.
4151  *
4152  * @return
4153  *   0 on success, a negative errno value otherwise and rte_errno is set.
4154  */
4155 static int
4156 flow_dv_query_count(struct rte_eth_dev *dev, struct rte_flow *flow,
4157                     void *data, struct rte_flow_error *error)
4158 {
4159         struct mlx5_priv *priv = dev->data->dev_private;
4160         struct rte_flow_query_count *qc = data;
4161         uint64_t pkts = 0;
4162         uint64_t bytes = 0;
4163         int err;
4164
4165         if (!priv->config.devx)
4166                 return rte_flow_error_set(error, ENOTSUP,
4167                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4168                                           NULL,
4169                                           "counters are not supported");
4170         if (flow->counter) {
4171                 err = mlx5_devx_cmd_flow_counter_query
4172                                                 (flow->counter->dcs,
4173                                                  qc->reset, &pkts, &bytes);
4174                 if (err)
4175                         return rte_flow_error_set
4176                                 (error, err,
4177                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4178                                  NULL,
4179                                  "cannot read counters");
4180                 qc->hits_set = 1;
4181                 qc->bytes_set = 1;
4182                 qc->hits = pkts - flow->counter->hits;
4183                 qc->bytes = bytes - flow->counter->bytes;
4184                 if (qc->reset) {
4185                         flow->counter->hits = pkts;
4186                         flow->counter->bytes = bytes;
4187                 }
4188                 return 0;
4189         }
4190         return rte_flow_error_set(error, EINVAL,
4191                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
4192                                   NULL,
4193                                   "counters are not available");
4194 }
4195
4196 /**
4197  * Query a flow.
4198  *
4199  * @see rte_flow_query()
4200  * @see rte_flow_ops
4201  */
4202 static int
4203 flow_dv_query(struct rte_eth_dev *dev,
4204               struct rte_flow *flow __rte_unused,
4205               const struct rte_flow_action *actions __rte_unused,
4206               void *data __rte_unused,
4207               struct rte_flow_error *error __rte_unused)
4208 {
4209         int ret = -EINVAL;
4210
4211         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
4212                 switch (actions->type) {
4213                 case RTE_FLOW_ACTION_TYPE_VOID:
4214                         break;
4215                 case RTE_FLOW_ACTION_TYPE_COUNT:
4216                         ret = flow_dv_query_count(dev, flow, data, error);
4217                         break;
4218                 default:
4219                         return rte_flow_error_set(error, ENOTSUP,
4220                                                   RTE_FLOW_ERROR_TYPE_ACTION,
4221                                                   actions,
4222                                                   "action not supported");
4223                 }
4224         }
4225         return ret;
4226 }
4227
4228 /*
4229  * Mutex-protected thunk to flow_dv_translate().
4230  */
4231 static int
4232 flow_d_translate(struct rte_eth_dev *dev,
4233                  struct mlx5_flow *dev_flow,
4234                  const struct rte_flow_attr *attr,
4235                  const struct rte_flow_item items[],
4236                  const struct rte_flow_action actions[],
4237                  struct rte_flow_error *error)
4238 {
4239         int ret;
4240
4241         flow_d_shared_lock(dev);
4242         ret = flow_dv_translate(dev, dev_flow, attr, items, actions, error);
4243         flow_d_shared_unlock(dev);
4244         return ret;
4245 }
4246
4247 /*
4248  * Mutex-protected thunk to flow_dv_apply().
4249  */
4250 static int
4251 flow_d_apply(struct rte_eth_dev *dev,
4252              struct rte_flow *flow,
4253              struct rte_flow_error *error)
4254 {
4255         int ret;
4256
4257         flow_d_shared_lock(dev);
4258         ret = flow_dv_apply(dev, flow, error);
4259         flow_d_shared_unlock(dev);
4260         return ret;
4261 }
4262
4263 /*
4264  * Mutex-protected thunk to flow_dv_remove().
4265  */
4266 static void
4267 flow_d_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
4268 {
4269         flow_d_shared_lock(dev);
4270         flow_dv_remove(dev, flow);
4271         flow_d_shared_unlock(dev);
4272 }
4273
4274 /*
4275  * Mutex-protected thunk to flow_dv_destroy().
4276  */
4277 static void
4278 flow_d_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
4279 {
4280         flow_d_shared_lock(dev);
4281         flow_dv_destroy(dev, flow);
4282         flow_d_shared_unlock(dev);
4283 }
4284
4285 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
4286         .validate = flow_dv_validate,
4287         .prepare = flow_dv_prepare,
4288         .translate = flow_d_translate,
4289         .apply = flow_d_apply,
4290         .remove = flow_d_remove,
4291         .destroy = flow_d_destroy,
4292         .query = flow_dv_query,
4293 };
4294
4295 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */