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