net/mlx5: add flow translate function
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_verbs.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2018 Mellanox Technologies, Ltd
3  */
4
5 #include <netinet/in.h>
6 #include <sys/queue.h>
7 #include <stdalign.h>
8 #include <stdint.h>
9 #include <string.h>
10
11 /* Verbs header. */
12 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
13 #ifdef PEDANTIC
14 #pragma GCC diagnostic ignored "-Wpedantic"
15 #endif
16 #include <infiniband/verbs.h>
17 #ifdef PEDANTIC
18 #pragma GCC diagnostic error "-Wpedantic"
19 #endif
20
21 #include <rte_common.h>
22 #include <rte_ether.h>
23 #include <rte_eth_ctrl.h>
24 #include <rte_ethdev_driver.h>
25 #include <rte_flow.h>
26 #include <rte_flow_driver.h>
27 #include <rte_malloc.h>
28 #include <rte_ip.h>
29
30 #include "mlx5.h"
31 #include "mlx5_defs.h"
32 #include "mlx5_prm.h"
33 #include "mlx5_glue.h"
34 #include "mlx5_flow.h"
35
36 /**
37  * Get a flow counter.
38  *
39  * @param[in] dev
40  *   Pointer to the Ethernet device structure.
41  * @param[in] shared
42  *   Indicate if this counter is shared with other flows.
43  * @param[in] id
44  *   Counter identifier.
45  *
46  * @return
47  *   A pointer to the counter, NULL otherwise and rte_errno is set.
48  */
49 static struct mlx5_flow_counter *
50 flow_verbs_counter_new(struct rte_eth_dev *dev, uint32_t shared, uint32_t id)
51 {
52         struct priv *priv = dev->data->dev_private;
53         struct mlx5_flow_counter *cnt;
54
55         LIST_FOREACH(cnt, &priv->flow_counters, next) {
56                 if (!cnt->shared || cnt->shared != shared)
57                         continue;
58                 if (cnt->id != id)
59                         continue;
60                 cnt->ref_cnt++;
61                 return cnt;
62         }
63 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
64
65         struct mlx5_flow_counter tmpl = {
66                 .shared = shared,
67                 .id = id,
68                 .cs = mlx5_glue->create_counter_set
69                         (priv->ctx,
70                          &(struct ibv_counter_set_init_attr){
71                                  .counter_set_id = id,
72                          }),
73                 .hits = 0,
74                 .bytes = 0,
75         };
76
77         if (!tmpl.cs) {
78                 rte_errno = errno;
79                 return NULL;
80         }
81         cnt = rte_calloc(__func__, 1, sizeof(*cnt), 0);
82         if (!cnt) {
83                 rte_errno = ENOMEM;
84                 return NULL;
85         }
86         *cnt = tmpl;
87         LIST_INSERT_HEAD(&priv->flow_counters, cnt, next);
88         return cnt;
89 #endif
90         rte_errno = ENOTSUP;
91         return NULL;
92 }
93
94 /**
95  * Release a flow counter.
96  *
97  * @param[in] counter
98  *   Pointer to the counter handler.
99  */
100 static void
101 flow_verbs_counter_release(struct mlx5_flow_counter *counter)
102 {
103         if (--counter->ref_cnt == 0) {
104                 claim_zero(mlx5_glue->destroy_counter_set(counter->cs));
105                 LIST_REMOVE(counter, next);
106                 rte_free(counter);
107         }
108 }
109
110 /**
111  * Add a verbs item specification into @p flow.
112  *
113  * @param[in, out] flow
114  *   Pointer to flow structure.
115  * @param[in] src
116  *   Create specification.
117  * @param[in] size
118  *   Size in bytes of the specification to copy.
119  */
120 static void
121 flow_verbs_spec_add(struct mlx5_flow *flow, void *src, unsigned int size)
122 {
123         struct mlx5_flow_verbs *verbs = &flow->verbs;
124
125         if (verbs->specs) {
126                 void *dst;
127
128                 dst = (void *)(verbs->specs + verbs->size);
129                 memcpy(dst, src, size);
130                 ++verbs->attr->num_of_specs;
131         }
132         verbs->size += size;
133 }
134
135 /**
136  * Adjust verbs hash fields according to the @p flow information.
137  *
138  * @param[in] dev_flow.
139  *   Pointer to dev flow structure.
140  * @param[in] tunnel
141  *   1 when the hash field is for a tunnel item.
142  * @param[in] layer_types
143  *   ETH_RSS_* types.
144  * @param[in] hash_fields
145  *   Item hash fields.
146  */
147 static void
148 flow_verbs_hashfields_adjust(struct mlx5_flow *dev_flow,
149                              int tunnel __rte_unused,
150                              uint32_t layer_types, uint64_t hash_fields)
151 {
152 #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
153         int rss_request_inner = dev_flow->flow->rss.level >= 2;
154
155         hash_fields |= (tunnel ? IBV_RX_HASH_INNER : 0);
156         if (rss_request_inner && !tunnel)
157                 hash_fields = 0;
158         else if (rss_request_inner < 2 && tunnel)
159                 hash_fields = 0;
160 #endif
161         if (!(dev_flow->flow->rss.types & layer_types))
162                 hash_fields = 0;
163         dev_flow->verbs.hash_fields |= hash_fields;
164 }
165
166 /**
167  * Convert the @p item into a Verbs specification. This function assumes that
168  * the input is valid and that there is space to insert the requested item
169  * into the flow.
170  *
171  * @param[in] item
172  *   Item specification.
173  * @param[in] item_flags
174  *   Bit field with all detected items.
175  * @param[in, out] dev_flow
176  *   Pointer to dev_flow structure.
177  */
178 static void
179 flow_verbs_translate_item_eth(const struct rte_flow_item *item,
180                               uint64_t *item_flags,
181                               struct mlx5_flow *dev_flow)
182 {
183         const struct rte_flow_item_eth *spec = item->spec;
184         const struct rte_flow_item_eth *mask = item->mask;
185         const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);
186         const unsigned int size = sizeof(struct ibv_flow_spec_eth);
187         struct ibv_flow_spec_eth eth = {
188                 .type = IBV_FLOW_SPEC_ETH | (tunnel ? IBV_FLOW_SPEC_INNER : 0),
189                 .size = size,
190         };
191
192         if (!mask)
193                 mask = &rte_flow_item_eth_mask;
194         if (spec) {
195                 unsigned int i;
196
197                 memcpy(&eth.val.dst_mac, spec->dst.addr_bytes, ETHER_ADDR_LEN);
198                 memcpy(&eth.val.src_mac, spec->src.addr_bytes, ETHER_ADDR_LEN);
199                 eth.val.ether_type = spec->type;
200                 memcpy(&eth.mask.dst_mac, mask->dst.addr_bytes, ETHER_ADDR_LEN);
201                 memcpy(&eth.mask.src_mac, mask->src.addr_bytes, ETHER_ADDR_LEN);
202                 eth.mask.ether_type = mask->type;
203                 /* Remove unwanted bits from values. */
204                 for (i = 0; i < ETHER_ADDR_LEN; ++i) {
205                         eth.val.dst_mac[i] &= eth.mask.dst_mac[i];
206                         eth.val.src_mac[i] &= eth.mask.src_mac[i];
207                 }
208                 eth.val.ether_type &= eth.mask.ether_type;
209                 dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;
210         }
211         flow_verbs_spec_add(dev_flow, &eth, size);
212         *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
213                                 MLX5_FLOW_LAYER_OUTER_L2;
214 }
215
216 /**
217  * Update the VLAN tag in the Verbs Ethernet specification.
218  * This function assumes that the input is valid and there is space to add
219  * the requested item.
220  *
221  * @param[in, out] attr
222  *   Pointer to Verbs attributes structure.
223  * @param[in] eth
224  *   Verbs structure containing the VLAN information to copy.
225  */
226 static void
227 flow_verbs_item_vlan_update(struct ibv_flow_attr *attr,
228                             struct ibv_flow_spec_eth *eth)
229 {
230         unsigned int i;
231         const enum ibv_flow_spec_type search = eth->type;
232         struct ibv_spec_header *hdr = (struct ibv_spec_header *)
233                 ((uint8_t *)attr + sizeof(struct ibv_flow_attr));
234
235         for (i = 0; i != attr->num_of_specs; ++i) {
236                 if (hdr->type == search) {
237                         struct ibv_flow_spec_eth *e =
238                                 (struct ibv_flow_spec_eth *)hdr;
239
240                         e->val.vlan_tag = eth->val.vlan_tag;
241                         e->mask.vlan_tag = eth->mask.vlan_tag;
242                         e->val.ether_type = eth->val.ether_type;
243                         e->mask.ether_type = eth->mask.ether_type;
244                         break;
245                 }
246                 hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
247         }
248 }
249
250 /**
251  * Convert the @p item into a Verbs specification. This function assumes that
252  * the input is valid and that there is space to insert the requested item
253  * into the flow.
254  *
255  * @param[in] item
256  *   Item specification.
257  * @param[in, out] item_flags
258  *   Bit mask that holds all detected items.
259  * @param[in, out] dev_flow
260  *   Pointer to dev_flow structure.
261  */
262 static void
263 flow_verbs_translate_item_vlan(const struct rte_flow_item *item,
264                                uint64_t *item_flags,
265                                struct mlx5_flow *dev_flow)
266 {
267         const struct rte_flow_item_vlan *spec = item->spec;
268         const struct rte_flow_item_vlan *mask = item->mask;
269         unsigned int size = sizeof(struct ibv_flow_spec_eth);
270         const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);
271         struct ibv_flow_spec_eth eth = {
272                 .type = IBV_FLOW_SPEC_ETH | (tunnel ? IBV_FLOW_SPEC_INNER : 0),
273                 .size = size,
274         };
275         const uint32_t l2m = tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
276                                       MLX5_FLOW_LAYER_OUTER_L2;
277
278         if (!mask)
279                 mask = &rte_flow_item_vlan_mask;
280         if (spec) {
281                 eth.val.vlan_tag = spec->tci;
282                 eth.mask.vlan_tag = mask->tci;
283                 eth.val.vlan_tag &= eth.mask.vlan_tag;
284                 eth.val.ether_type = spec->inner_type;
285                 eth.mask.ether_type = mask->inner_type;
286                 eth.val.ether_type &= eth.mask.ether_type;
287         }
288         if (!(*item_flags & l2m)) {
289                 dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;
290                 flow_verbs_spec_add(dev_flow, &eth, size);
291         } else {
292                 flow_verbs_item_vlan_update(dev_flow->verbs.attr, &eth);
293                 size = 0; /* Only an update is done in eth specification. */
294         }
295         *item_flags |= tunnel ?
296                        (MLX5_FLOW_LAYER_INNER_L2 | MLX5_FLOW_LAYER_INNER_VLAN) :
297                        (MLX5_FLOW_LAYER_OUTER_L2 | MLX5_FLOW_LAYER_OUTER_VLAN);
298 }
299
300 /**
301  * Convert the @p item into a Verbs specification. This function assumes that
302  * the input is valid and that there is space to insert the requested item
303  * into the flow.
304  *
305  * @param[in] item
306  *   Item specification.
307  * @param[in, out] item_flags
308  *   Bit mask that marks all detected items.
309  * @param[in, out] dev_flow
310  *   Pointer to sepacific flow structure.
311  */
312 static void
313 flow_verbs_translate_item_ipv4(const struct rte_flow_item *item,
314                                uint64_t *item_flags,
315                                struct mlx5_flow *dev_flow)
316 {
317         const struct rte_flow_item_ipv4 *spec = item->spec;
318         const struct rte_flow_item_ipv4 *mask = item->mask;
319         const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);
320         unsigned int size = sizeof(struct ibv_flow_spec_ipv4_ext);
321         struct ibv_flow_spec_ipv4_ext ipv4 = {
322                 .type = IBV_FLOW_SPEC_IPV4_EXT |
323                         (tunnel ? IBV_FLOW_SPEC_INNER : 0),
324                 .size = size,
325         };
326
327         if (!mask)
328                 mask = &rte_flow_item_ipv4_mask;
329         *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
330                                 MLX5_FLOW_LAYER_OUTER_L3_IPV4;
331         if (spec) {
332                 ipv4.val = (struct ibv_flow_ipv4_ext_filter){
333                         .src_ip = spec->hdr.src_addr,
334                         .dst_ip = spec->hdr.dst_addr,
335                         .proto = spec->hdr.next_proto_id,
336                         .tos = spec->hdr.type_of_service,
337                 };
338                 ipv4.mask = (struct ibv_flow_ipv4_ext_filter){
339                         .src_ip = mask->hdr.src_addr,
340                         .dst_ip = mask->hdr.dst_addr,
341                         .proto = mask->hdr.next_proto_id,
342                         .tos = mask->hdr.type_of_service,
343                 };
344                 /* Remove unwanted bits from values. */
345                 ipv4.val.src_ip &= ipv4.mask.src_ip;
346                 ipv4.val.dst_ip &= ipv4.mask.dst_ip;
347                 ipv4.val.proto &= ipv4.mask.proto;
348                 ipv4.val.tos &= ipv4.mask.tos;
349         }
350         flow_verbs_hashfields_adjust(dev_flow, tunnel,
351                                      (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |
352                                       ETH_RSS_NONFRAG_IPV4_TCP |
353                                       ETH_RSS_NONFRAG_IPV4_UDP |
354                                       ETH_RSS_NONFRAG_IPV4_OTHER),
355                                      (IBV_RX_HASH_SRC_IPV4 |
356                                       IBV_RX_HASH_DST_IPV4));
357         dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L3;
358         flow_verbs_spec_add(dev_flow, &ipv4, size);
359 }
360
361 /**
362  * Convert the @p item into a Verbs specification. This function assumes that
363  * the input is valid and that there is space to insert the requested item
364  * into the flow.
365  *
366  * @param[in] item
367  *   Item specification.
368  * @param[in, out] item_flags
369  *   Bit mask that marks all detected items.
370  * @param[in, out] dev_flow
371  *   Pointer to sepacific flow structure.
372  */
373 static void
374 flow_verbs_translate_item_ipv6(const struct rte_flow_item *item,
375                                uint64_t *item_flags,
376                                struct mlx5_flow *dev_flow)
377 {
378         const struct rte_flow_item_ipv6 *spec = item->spec;
379         const struct rte_flow_item_ipv6 *mask = item->mask;
380         const int tunnel = !!(dev_flow->flow->layers & MLX5_FLOW_LAYER_TUNNEL);
381         unsigned int size = sizeof(struct ibv_flow_spec_ipv6);
382         struct ibv_flow_spec_ipv6 ipv6 = {
383                 .type = IBV_FLOW_SPEC_IPV6 | (tunnel ? IBV_FLOW_SPEC_INNER : 0),
384                 .size = size,
385         };
386
387         if (!mask)
388                 mask = &rte_flow_item_ipv6_mask;
389          *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
390                                  MLX5_FLOW_LAYER_OUTER_L3_IPV6;
391         if (spec) {
392                 unsigned int i;
393                 uint32_t vtc_flow_val;
394                 uint32_t vtc_flow_mask;
395
396                 memcpy(&ipv6.val.src_ip, spec->hdr.src_addr,
397                        RTE_DIM(ipv6.val.src_ip));
398                 memcpy(&ipv6.val.dst_ip, spec->hdr.dst_addr,
399                        RTE_DIM(ipv6.val.dst_ip));
400                 memcpy(&ipv6.mask.src_ip, mask->hdr.src_addr,
401                        RTE_DIM(ipv6.mask.src_ip));
402                 memcpy(&ipv6.mask.dst_ip, mask->hdr.dst_addr,
403                        RTE_DIM(ipv6.mask.dst_ip));
404                 vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);
405                 vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);
406                 ipv6.val.flow_label =
407                         rte_cpu_to_be_32((vtc_flow_val & IPV6_HDR_FL_MASK) >>
408                                          IPV6_HDR_FL_SHIFT);
409                 ipv6.val.traffic_class = (vtc_flow_val & IPV6_HDR_TC_MASK) >>
410                                          IPV6_HDR_TC_SHIFT;
411                 ipv6.val.next_hdr = spec->hdr.proto;
412                 ipv6.val.hop_limit = spec->hdr.hop_limits;
413                 ipv6.mask.flow_label =
414                         rte_cpu_to_be_32((vtc_flow_mask & IPV6_HDR_FL_MASK) >>
415                                          IPV6_HDR_FL_SHIFT);
416                 ipv6.mask.traffic_class = (vtc_flow_mask & IPV6_HDR_TC_MASK) >>
417                                           IPV6_HDR_TC_SHIFT;
418                 ipv6.mask.next_hdr = mask->hdr.proto;
419                 ipv6.mask.hop_limit = mask->hdr.hop_limits;
420                 /* Remove unwanted bits from values. */
421                 for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {
422                         ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];
423                         ipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];
424                 }
425                 ipv6.val.flow_label &= ipv6.mask.flow_label;
426                 ipv6.val.traffic_class &= ipv6.mask.traffic_class;
427                 ipv6.val.next_hdr &= ipv6.mask.next_hdr;
428                 ipv6.val.hop_limit &= ipv6.mask.hop_limit;
429         }
430         flow_verbs_hashfields_adjust(dev_flow, tunnel,
431                                      (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6 |
432                                       ETH_RSS_NONFRAG_IPV6_TCP |
433                                       ETH_RSS_NONFRAG_IPV6_UDP |
434                                       ETH_RSS_IPV6_EX  |
435                                       ETH_RSS_IPV6_TCP_EX |
436                                       ETH_RSS_IPV6_UDP_EX |
437                                       ETH_RSS_NONFRAG_IPV6_OTHER),
438                                      (IBV_RX_HASH_SRC_IPV6 |
439                                       IBV_RX_HASH_DST_IPV6));
440         dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L3;
441         flow_verbs_spec_add(dev_flow, &ipv6, size);
442 }
443
444 /**
445  * Convert the @p item into a Verbs specification. This function assumes that
446  * the input is valid and that there is space to insert the requested item
447  * into the flow.
448  *
449  * @param[in] item
450  *   Item specification.
451  * @param[in, out] item_flags
452  *   Bit mask that marks all detected items.
453  * @param[in, out] dev_flow
454  *   Pointer to sepacific flow structure.
455  */
456 static void
457 flow_verbs_translate_item_udp(const struct rte_flow_item *item,
458                               uint64_t *item_flags,
459                               struct mlx5_flow *dev_flow)
460 {
461         const struct rte_flow_item_udp *spec = item->spec;
462         const struct rte_flow_item_udp *mask = item->mask;
463         const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);
464         unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
465         struct ibv_flow_spec_tcp_udp udp = {
466                 .type = IBV_FLOW_SPEC_UDP | (tunnel ? IBV_FLOW_SPEC_INNER : 0),
467                 .size = size,
468         };
469
470         if (!mask)
471                 mask = &rte_flow_item_udp_mask;
472         *item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
473                                 MLX5_FLOW_LAYER_OUTER_L4_UDP;
474         if (spec) {
475                 udp.val.dst_port = spec->hdr.dst_port;
476                 udp.val.src_port = spec->hdr.src_port;
477                 udp.mask.dst_port = mask->hdr.dst_port;
478                 udp.mask.src_port = mask->hdr.src_port;
479                 /* Remove unwanted bits from values. */
480                 udp.val.src_port &= udp.mask.src_port;
481                 udp.val.dst_port &= udp.mask.dst_port;
482         }
483         flow_verbs_hashfields_adjust(dev_flow,
484                                      tunnel, ETH_RSS_UDP,
485                                      (IBV_RX_HASH_SRC_PORT_UDP |
486                                       IBV_RX_HASH_DST_PORT_UDP));
487         dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L4;
488         flow_verbs_spec_add(dev_flow, &udp, size);
489 }
490
491 /**
492  * Convert the @p item into a Verbs specification. This function assumes that
493  * the input is valid and that there is space to insert the requested item
494  * into the flow.
495  *
496  * @param[in] item
497  *   Item specification.
498  * @param[in, out] item_flags
499  *   Bit mask that marks all detected items.
500  * @param[in, out] dev_flow
501  *   Pointer to sepacific flow structure.
502  */
503 static void
504 flow_verbs_translate_item_tcp(const struct rte_flow_item *item,
505                               uint64_t *item_flags,
506                               struct mlx5_flow *dev_flow)
507 {
508         const struct rte_flow_item_tcp *spec = item->spec;
509         const struct rte_flow_item_tcp *mask = item->mask;
510         const int tunnel = !!(dev_flow->flow->layers & MLX5_FLOW_LAYER_TUNNEL);
511         unsigned int size = sizeof(struct ibv_flow_spec_tcp_udp);
512         struct ibv_flow_spec_tcp_udp tcp = {
513                 .type = IBV_FLOW_SPEC_TCP | (tunnel ? IBV_FLOW_SPEC_INNER : 0),
514                 .size = size,
515         };
516
517         if (!mask)
518                 mask = &rte_flow_item_tcp_mask;
519         *item_flags |=  tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
520                                  MLX5_FLOW_LAYER_OUTER_L4_TCP;
521         if (spec) {
522                 tcp.val.dst_port = spec->hdr.dst_port;
523                 tcp.val.src_port = spec->hdr.src_port;
524                 tcp.mask.dst_port = mask->hdr.dst_port;
525                 tcp.mask.src_port = mask->hdr.src_port;
526                 /* Remove unwanted bits from values. */
527                 tcp.val.src_port &= tcp.mask.src_port;
528                 tcp.val.dst_port &= tcp.mask.dst_port;
529         }
530         flow_verbs_hashfields_adjust(dev_flow,
531                                      tunnel, ETH_RSS_TCP,
532                                      (IBV_RX_HASH_SRC_PORT_TCP |
533                                       IBV_RX_HASH_DST_PORT_TCP));
534         dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L4;
535         flow_verbs_spec_add(dev_flow, &tcp, size);
536 }
537
538 /**
539  * Convert the @p item into a Verbs specification. This function assumes that
540  * the input is valid and that there is space to insert the requested item
541  * into the flow.
542  *
543  * @param[in] item
544  *   Item specification.
545  * @param[in, out] item_flags
546  *   Bit mask that marks all detected items.
547  * @param[in, out] dev_flow
548  *   Pointer to sepacific flow structure.
549  */
550 static void
551 flow_verbs_translate_item_vxlan(const struct rte_flow_item *item,
552                                 uint64_t *item_flags,
553                                 struct mlx5_flow *dev_flow)
554 {
555         const struct rte_flow_item_vxlan *spec = item->spec;
556         const struct rte_flow_item_vxlan *mask = item->mask;
557         unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
558         struct ibv_flow_spec_tunnel vxlan = {
559                 .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
560                 .size = size,
561         };
562         union vni {
563                 uint32_t vlan_id;
564                 uint8_t vni[4];
565         } id = { .vlan_id = 0, };
566
567         if (!mask)
568                 mask = &rte_flow_item_vxlan_mask;
569         if (spec) {
570                 memcpy(&id.vni[1], spec->vni, 3);
571                 vxlan.val.tunnel_id = id.vlan_id;
572                 memcpy(&id.vni[1], mask->vni, 3);
573                 vxlan.mask.tunnel_id = id.vlan_id;
574                 /* Remove unwanted bits from values. */
575                 vxlan.val.tunnel_id &= vxlan.mask.tunnel_id;
576         }
577         flow_verbs_spec_add(dev_flow, &vxlan, size);
578         dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;
579         *item_flags |= MLX5_FLOW_LAYER_VXLAN;
580 }
581
582 /**
583  * Convert the @p item into a Verbs specification. This function assumes that
584  * the input is valid and that there is space to insert the requested item
585  * into the flow.
586  *
587  * @param[in] item
588  *   Item specification.
589  * @param[in, out] item_flags
590  *   Bit mask that marks all detected items.
591  * @param[in, out] dev_flow
592  *   Pointer to sepacific flow structure.
593  */
594 static void
595 flow_verbs_translate_item_vxlan_gpe(const struct rte_flow_item *item,
596                                     uint64_t *item_flags,
597                                     struct mlx5_flow *dev_flow)
598 {
599         const struct rte_flow_item_vxlan_gpe *spec = item->spec;
600         const struct rte_flow_item_vxlan_gpe *mask = item->mask;
601         unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
602         struct ibv_flow_spec_tunnel vxlan_gpe = {
603                 .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
604                 .size = size,
605         };
606         union vni {
607                 uint32_t vlan_id;
608                 uint8_t vni[4];
609         } id = { .vlan_id = 0, };
610
611         if (!mask)
612                 mask = &rte_flow_item_vxlan_gpe_mask;
613         if (spec) {
614                 memcpy(&id.vni[1], spec->vni, 3);
615                 vxlan_gpe.val.tunnel_id = id.vlan_id;
616                 memcpy(&id.vni[1], mask->vni, 3);
617                 vxlan_gpe.mask.tunnel_id = id.vlan_id;
618                 /* Remove unwanted bits from values. */
619                 vxlan_gpe.val.tunnel_id &= vxlan_gpe.mask.tunnel_id;
620         }
621         flow_verbs_spec_add(dev_flow, &vxlan_gpe, size);
622         dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;
623         *item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE;
624 }
625
626 /**
627  * Update the protocol in Verbs IPv4/IPv6 spec.
628  *
629  * @param[in, out] attr
630  *   Pointer to Verbs attributes structure.
631  * @param[in] search
632  *   Specification type to search in order to update the IP protocol.
633  * @param[in] protocol
634  *   Protocol value to set if none is present in the specification.
635  */
636 static void
637 flow_verbs_item_gre_ip_protocol_update(struct ibv_flow_attr *attr,
638                                        enum ibv_flow_spec_type search,
639                                        uint8_t protocol)
640 {
641         unsigned int i;
642         struct ibv_spec_header *hdr = (struct ibv_spec_header *)
643                 ((uint8_t *)attr + sizeof(struct ibv_flow_attr));
644
645         if (!attr)
646                 return;
647         for (i = 0; i != attr->num_of_specs; ++i) {
648                 if (hdr->type == search) {
649                         union {
650                                 struct ibv_flow_spec_ipv4_ext *ipv4;
651                                 struct ibv_flow_spec_ipv6 *ipv6;
652                         } ip;
653
654                         switch (search) {
655                         case IBV_FLOW_SPEC_IPV4_EXT:
656                                 ip.ipv4 = (struct ibv_flow_spec_ipv4_ext *)hdr;
657                                 if (!ip.ipv4->val.proto) {
658                                         ip.ipv4->val.proto = protocol;
659                                         ip.ipv4->mask.proto = 0xff;
660                                 }
661                                 break;
662                         case IBV_FLOW_SPEC_IPV6:
663                                 ip.ipv6 = (struct ibv_flow_spec_ipv6 *)hdr;
664                                 if (!ip.ipv6->val.next_hdr) {
665                                         ip.ipv6->val.next_hdr = protocol;
666                                         ip.ipv6->mask.next_hdr = 0xff;
667                                 }
668                                 break;
669                         default:
670                                 break;
671                         }
672                         break;
673                 }
674                 hdr = (struct ibv_spec_header *)((uint8_t *)hdr + hdr->size);
675         }
676 }
677
678 /**
679  * Convert the @p item into a Verbs specification. This function assumes that
680  * the input is valid and that there is space to insert the requested item
681  * into the flow.
682  *
683  * @param[in] item
684  *   Item specification.
685  * @param[in, out] item_flags
686  *   Bit mask that marks all detected items.
687  * @param[in, out] dev_flow
688  *   Pointer to sepacific flow structure.
689  */
690 static void
691 flow_verbs_translate_item_gre(const struct rte_flow_item *item __rte_unused,
692                               uint64_t *item_flags,
693                               struct mlx5_flow *dev_flow)
694 {
695         struct mlx5_flow_verbs *verbs = &dev_flow->verbs;
696 #ifndef HAVE_IBV_DEVICE_MPLS_SUPPORT
697         unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
698         struct ibv_flow_spec_tunnel tunnel = {
699                 .type = IBV_FLOW_SPEC_VXLAN_TUNNEL,
700                 .size = size,
701         };
702 #else
703         const struct rte_flow_item_gre *spec = item->spec;
704         const struct rte_flow_item_gre *mask = item->mask;
705         unsigned int size = sizeof(struct ibv_flow_spec_gre);
706         struct ibv_flow_spec_gre tunnel = {
707                 .type = IBV_FLOW_SPEC_GRE,
708                 .size = size,
709         };
710
711         if (!mask)
712                 mask = &rte_flow_item_gre_mask;
713         if (spec) {
714                 tunnel.val.c_ks_res0_ver = spec->c_rsvd0_ver;
715                 tunnel.val.protocol = spec->protocol;
716                 tunnel.mask.c_ks_res0_ver = mask->c_rsvd0_ver;
717                 tunnel.mask.protocol = mask->protocol;
718                 /* Remove unwanted bits from values. */
719                 tunnel.val.c_ks_res0_ver &= tunnel.mask.c_ks_res0_ver;
720                 tunnel.val.protocol &= tunnel.mask.protocol;
721                 tunnel.val.key &= tunnel.mask.key;
722         }
723 #endif
724         if (*item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)
725                 flow_verbs_item_gre_ip_protocol_update(verbs->attr,
726                                                        IBV_FLOW_SPEC_IPV4_EXT,
727                                                        IPPROTO_GRE);
728         else
729                 flow_verbs_item_gre_ip_protocol_update(verbs->attr,
730                                                        IBV_FLOW_SPEC_IPV6,
731                                                        IPPROTO_GRE);
732         flow_verbs_spec_add(dev_flow, &tunnel, size);
733         verbs->attr->priority = MLX5_PRIORITY_MAP_L2;
734         *item_flags |= MLX5_FLOW_LAYER_GRE;
735 }
736
737 /**
738  * Convert the @p action into a Verbs specification. This function assumes that
739  * the input is valid and that there is space to insert the requested action
740  * into the flow. This function also return the action that was added.
741  *
742  * @param[in] item
743  *   Item specification.
744  * @param[in, out] item_flags
745  *   Bit mask that marks all detected items.
746  * @param[in, out] dev_flow
747  *   Pointer to sepacific flow structure.
748  */
749 static void
750 flow_verbs_translate_item_mpls(const struct rte_flow_item *item __rte_unused,
751                                uint64_t *action_flags __rte_unused,
752                                struct mlx5_flow *dev_flow __rte_unused)
753 {
754 #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
755         const struct rte_flow_item_mpls *spec = item->spec;
756         const struct rte_flow_item_mpls *mask = item->mask;
757         unsigned int size = sizeof(struct ibv_flow_spec_mpls);
758         struct ibv_flow_spec_mpls mpls = {
759                 .type = IBV_FLOW_SPEC_MPLS,
760                 .size = size,
761         };
762
763         if (!mask)
764                 mask = &rte_flow_item_mpls_mask;
765         if (spec) {
766                 memcpy(&mpls.val.label, spec, sizeof(mpls.val.label));
767                 memcpy(&mpls.mask.label, mask, sizeof(mpls.mask.label));
768                 /* Remove unwanted bits from values.  */
769                 mpls.val.label &= mpls.mask.label;
770         }
771         flow_verbs_spec_add(dev_flow, &mpls, size);
772         dev_flow->verbs.attr->priority = MLX5_PRIORITY_MAP_L2;
773         *action_flags |= MLX5_FLOW_LAYER_MPLS;
774 #endif
775 }
776
777 /**
778  * Convert the @p action into a Verbs specification. This function assumes that
779  * the input is valid and that there is space to insert the requested action
780  * into the flow. This function also return the action that was added.
781  *
782  * @param[in, out] action_flags
783  *   Pointer to the detected actions.
784  * @param[in] dev_flow
785  *   Pointer to mlx5_flow.
786  */
787 static void
788 flow_verbs_translate_action_drop(uint64_t *action_flags,
789                                  struct mlx5_flow *dev_flow)
790 {
791         unsigned int size = sizeof(struct ibv_flow_spec_action_drop);
792         struct ibv_flow_spec_action_drop drop = {
793                         .type = IBV_FLOW_SPEC_ACTION_DROP,
794                         .size = size,
795         };
796
797         flow_verbs_spec_add(dev_flow, &drop, size);
798         *action_flags |= MLX5_FLOW_ACTION_DROP;
799 }
800
801 /**
802  * Convert the @p action into a Verbs specification. This function assumes that
803  * the input is valid and that there is space to insert the requested action
804  * into the flow. This function also return the action that was added.
805  *
806  * @param[in] action
807  *   Action configuration.
808  * @param[in, out] action_flags
809  *   Pointer to the detected actions.
810  * @param[in] dev_flow
811  *   Pointer to mlx5_flow.
812  */
813 static void
814 flow_verbs_translate_action_queue(const struct rte_flow_action *action,
815                                   uint64_t *action_flags,
816                                   struct mlx5_flow *dev_flow)
817 {
818         const struct rte_flow_action_queue *queue = action->conf;
819         struct rte_flow *flow = dev_flow->flow;
820
821         if (flow->queue)
822                 (*flow->queue)[0] = queue->index;
823         flow->rss.queue_num = 1;
824         *action_flags |= MLX5_FLOW_ACTION_QUEUE;
825 }
826
827 /**
828  * Convert the @p action into a Verbs specification. This function assumes that
829  * the input is valid and that there is space to insert the requested action
830  * into the flow. This function also return the action that was added.
831  *
832  * @param[in] action
833  *   Action configuration.
834  * @param[in, out] action_flags
835  *   Pointer to the detected actions.
836  * @param[in] dev_flow
837  *   Pointer to mlx5_flow.
838  */
839 static void
840 flow_verbs_translate_action_rss(const struct rte_flow_action *action,
841                                 uint64_t *action_flags,
842                                 struct mlx5_flow *dev_flow)
843 {
844         const struct rte_flow_action_rss *rss = action->conf;
845         struct rte_flow *flow = dev_flow->flow;
846
847         if (flow->queue)
848                 memcpy((*flow->queue), rss->queue,
849                        rss->queue_num * sizeof(uint16_t));
850         flow->rss.queue_num = rss->queue_num;
851         memcpy(flow->key, rss->key, MLX5_RSS_HASH_KEY_LEN);
852         flow->rss.types = rss->types;
853         flow->rss.level = rss->level;
854         *action_flags |= MLX5_FLOW_ACTION_RSS;
855 }
856
857 /**
858  * Convert the @p action into a Verbs specification. This function assumes that
859  * the input is valid and that there is space to insert the requested action
860  * into the flow. This function also return the action that was added.
861  *
862  * @param[in] action
863  *   Action configuration.
864  * @param[in, out] action_flags
865  *   Pointer to the detected actions.
866  * @param[in] dev_flow
867  *   Pointer to mlx5_flow.
868  */
869 static void
870 flow_verbs_translate_action_flag
871                         (const struct rte_flow_action *action __rte_unused,
872                          uint64_t *action_flags,
873                          struct mlx5_flow *dev_flow)
874 {
875         unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
876         struct ibv_flow_spec_action_tag tag = {
877                 .type = IBV_FLOW_SPEC_ACTION_TAG,
878                 .size = size,
879                 .tag_id = mlx5_flow_mark_set(MLX5_FLOW_MARK_DEFAULT),
880         };
881         *action_flags |= MLX5_FLOW_ACTION_MARK;
882         flow_verbs_spec_add(dev_flow, &tag, size);
883 }
884
885 /**
886  * Update verbs specification to modify the flag to mark.
887  *
888  * @param[in, out] verbs
889  *   Pointer to the mlx5_flow_verbs structure.
890  * @param[in] mark_id
891  *   Mark identifier to replace the flag.
892  */
893 static void
894 flow_verbs_mark_update(struct mlx5_flow_verbs *verbs, uint32_t mark_id)
895 {
896         struct ibv_spec_header *hdr;
897         int i;
898
899         if (!verbs)
900                 return;
901         /* Update Verbs specification. */
902         hdr = (struct ibv_spec_header *)verbs->specs;
903         if (!hdr)
904                 return;
905         for (i = 0; i != verbs->attr->num_of_specs; ++i) {
906                 if (hdr->type == IBV_FLOW_SPEC_ACTION_TAG) {
907                         struct ibv_flow_spec_action_tag *t =
908                                 (struct ibv_flow_spec_action_tag *)hdr;
909
910                         t->tag_id = mlx5_flow_mark_set(mark_id);
911                 }
912                 hdr = (struct ibv_spec_header *)((uintptr_t)hdr + hdr->size);
913         }
914 }
915
916 /**
917  * Convert the @p action into a Verbs specification. This function assumes that
918  * the input is valid and that there is space to insert the requested action
919  * into the flow. This function also return the action that was added.
920  *
921  * @param[in] action
922  *   Action configuration.
923  * @param[in, out] action_flags
924  *   Pointer to the detected actions.
925  * @param[in] dev_flow
926  *   Pointer to mlx5_flow.
927  */
928 static void
929 flow_verbs_translate_action_mark(const struct rte_flow_action *action,
930                                  uint64_t *action_flags,
931                                  struct mlx5_flow *dev_flow)
932 {
933         const struct rte_flow_action_mark *mark = action->conf;
934         unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
935         struct ibv_flow_spec_action_tag tag = {
936                 .type = IBV_FLOW_SPEC_ACTION_TAG,
937                 .size = size,
938         };
939         struct mlx5_flow_verbs *verbs = &dev_flow->verbs;
940
941         if (*action_flags & MLX5_FLOW_ACTION_FLAG) {
942                 flow_verbs_mark_update(verbs, mark->id);
943                 size = 0;
944         } else {
945                 tag.tag_id = mlx5_flow_mark_set(mark->id);
946                 flow_verbs_spec_add(dev_flow, &tag, size);
947         }
948         *action_flags |= MLX5_FLOW_ACTION_MARK;
949 }
950
951 /**
952  * Convert the @p action into a Verbs specification. This function assumes that
953  * the input is valid and that there is space to insert the requested action
954  * into the flow. This function also return the action that was added.
955  *
956  * @param[in] dev
957  *   Pointer to the Ethernet device structure.
958  * @param[in] action
959  *   Action configuration.
960  * @param[in, out] action_flags
961  *   Pointer to the detected actions.
962  * @param[in] dev_flow
963  *   Pointer to mlx5_flow.
964  * @param[out] error
965  *   Pointer to error structure.
966  *
967  * @return
968  *   0 On success else a negative errno value is returned and rte_errno is set.
969  */
970 static int
971 flow_verbs_translate_action_count(struct rte_eth_dev *dev,
972                                   const struct rte_flow_action *action,
973                                   uint64_t *action_flags,
974                                   struct mlx5_flow *dev_flow,
975                                   struct rte_flow_error *error)
976 {
977         const struct rte_flow_action_count *count = action->conf;
978         struct rte_flow *flow = dev_flow->flow;
979 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
980         unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
981         struct ibv_flow_spec_counter_action counter = {
982                 .type = IBV_FLOW_SPEC_ACTION_COUNT,
983                 .size = size,
984         };
985 #endif
986
987         if (!flow->counter) {
988                 flow->counter = flow_verbs_counter_new(dev, count->shared,
989                                                        count->id);
990                 if (!flow->counter)
991                         return rte_flow_error_set(error, rte_errno,
992                                                   RTE_FLOW_ERROR_TYPE_ACTION,
993                                                   action,
994                                                   "cannot get counter"
995                                                   " context.");
996         }
997         *action_flags |= MLX5_FLOW_ACTION_COUNT;
998 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
999         counter.counter_set_handle = flow->counter->cs->handle;
1000         flow_verbs_spec_add(dev_flow, &counter, size);
1001 #endif
1002         return 0;
1003 }
1004
1005 /**
1006  * Internal validation function. For validating both actions and items.
1007  *
1008  * @param[in] dev
1009  *   Pointer to the Ethernet device structure.
1010  * @param[in] attr
1011  *   Pointer to the flow attributes.
1012  * @param[in] items
1013  *   Pointer to the list of items.
1014  * @param[in] actions
1015  *   Pointer to the list of actions.
1016  * @param[out] error
1017  *   Pointer to the error structure.
1018  *
1019  * @return
1020  *   0 on success, a negative errno value otherwise and rte_errno is set.
1021  */
1022 static int
1023 flow_verbs_validate(struct rte_eth_dev *dev,
1024                     const struct rte_flow_attr *attr,
1025                     const struct rte_flow_item items[],
1026                     const struct rte_flow_action actions[],
1027                     struct rte_flow_error *error)
1028 {
1029         int ret;
1030         uint32_t action_flags = 0;
1031         uint32_t item_flags = 0;
1032         int tunnel = 0;
1033         uint8_t next_protocol = 0xff;
1034
1035         if (items == NULL)
1036                 return -1;
1037         ret = mlx5_flow_validate_attributes(dev, attr, error);
1038         if (ret < 0)
1039                 return ret;
1040         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1041                 int ret = 0;
1042                 switch (items->type) {
1043                 case RTE_FLOW_ITEM_TYPE_VOID:
1044                         break;
1045                 case RTE_FLOW_ITEM_TYPE_ETH:
1046                         ret = mlx5_flow_validate_item_eth(items, item_flags,
1047                                                           error);
1048                         if (ret < 0)
1049                                 return ret;
1050                         item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
1051                                                MLX5_FLOW_LAYER_OUTER_L2;
1052                         break;
1053                 case RTE_FLOW_ITEM_TYPE_VLAN:
1054                         ret = mlx5_flow_validate_item_vlan(items, item_flags,
1055                                                            error);
1056                         if (ret < 0)
1057                                 return ret;
1058                         item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
1059                                                MLX5_FLOW_LAYER_OUTER_VLAN;
1060                         break;
1061                 case RTE_FLOW_ITEM_TYPE_IPV4:
1062                         ret = mlx5_flow_validate_item_ipv4(items, item_flags,
1063                                                            error);
1064                         if (ret < 0)
1065                                 return ret;
1066                         item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
1067                                                MLX5_FLOW_LAYER_OUTER_L3_IPV4;
1068                         if (items->mask != NULL &&
1069                             ((const struct rte_flow_item_ipv4 *)
1070                              items->mask)->hdr.next_proto_id)
1071                                 next_protocol =
1072                                         ((const struct rte_flow_item_ipv4 *)
1073                                          (items->spec))->hdr.next_proto_id;
1074                         break;
1075                 case RTE_FLOW_ITEM_TYPE_IPV6:
1076                         ret = mlx5_flow_validate_item_ipv6(items, item_flags,
1077                                                            error);
1078                         if (ret < 0)
1079                                 return ret;
1080                         item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
1081                                                MLX5_FLOW_LAYER_OUTER_L3_IPV6;
1082                         if (items->mask != NULL &&
1083                             ((const struct rte_flow_item_ipv6 *)
1084                              items->mask)->hdr.proto)
1085                                 next_protocol =
1086                                         ((const struct rte_flow_item_ipv6 *)
1087                                          items->spec)->hdr.proto;
1088                         break;
1089                 case RTE_FLOW_ITEM_TYPE_UDP:
1090                         ret = mlx5_flow_validate_item_udp(items, item_flags,
1091                                                           next_protocol,
1092                                                           error);
1093                         if (ret < 0)
1094                                 return ret;
1095                         item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
1096                                                MLX5_FLOW_LAYER_OUTER_L4_UDP;
1097                         break;
1098                 case RTE_FLOW_ITEM_TYPE_TCP:
1099                         ret = mlx5_flow_validate_item_tcp(items, item_flags,
1100                                                           next_protocol, error);
1101                         if (ret < 0)
1102                                 return ret;
1103                         item_flags |= tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
1104                                                MLX5_FLOW_LAYER_OUTER_L4_TCP;
1105                         break;
1106                 case RTE_FLOW_ITEM_TYPE_VXLAN:
1107                         ret = mlx5_flow_validate_item_vxlan(items, item_flags,
1108                                                             error);
1109                         if (ret < 0)
1110                                 return ret;
1111                         item_flags |= MLX5_FLOW_LAYER_VXLAN;
1112                         break;
1113                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1114                         ret = mlx5_flow_validate_item_vxlan_gpe(items,
1115                                                                 item_flags,
1116                                                                 dev, error);
1117                         if (ret < 0)
1118                                 return ret;
1119                         item_flags |= MLX5_FLOW_LAYER_VXLAN_GPE;
1120                         break;
1121                 case RTE_FLOW_ITEM_TYPE_GRE:
1122                         ret = mlx5_flow_validate_item_gre(items, item_flags,
1123                                                           next_protocol, error);
1124                         if (ret < 0)
1125                                 return ret;
1126                         item_flags |= MLX5_FLOW_LAYER_GRE;
1127                         break;
1128                 case RTE_FLOW_ITEM_TYPE_MPLS:
1129                         ret = mlx5_flow_validate_item_mpls(items, item_flags,
1130                                                            next_protocol,
1131                                                            error);
1132                         if (ret < 0)
1133                                 return ret;
1134                         if (next_protocol != 0xff &&
1135                             next_protocol != IPPROTO_MPLS)
1136                                 return rte_flow_error_set
1137                                         (error, EINVAL,
1138                                          RTE_FLOW_ERROR_TYPE_ITEM, items,
1139                                          "protocol filtering not compatible"
1140                                          " with MPLS layer");
1141                         item_flags |= MLX5_FLOW_LAYER_MPLS;
1142                         break;
1143                 default:
1144                         return rte_flow_error_set(error, ENOTSUP,
1145                                                   RTE_FLOW_ERROR_TYPE_ITEM,
1146                                                   NULL, "item not supported");
1147                 }
1148         }
1149         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1150                 tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
1151                 switch (actions->type) {
1152                 case RTE_FLOW_ACTION_TYPE_VOID:
1153                         break;
1154                 case RTE_FLOW_ACTION_TYPE_FLAG:
1155                         ret = mlx5_flow_validate_action_flag(action_flags,
1156                                                              error);
1157                         if (ret < 0)
1158                                 return ret;
1159                         action_flags |= MLX5_FLOW_ACTION_FLAG;
1160                         break;
1161                 case RTE_FLOW_ACTION_TYPE_MARK:
1162                         ret = mlx5_flow_validate_action_mark(actions,
1163                                                              action_flags,
1164                                                              error);
1165                         if (ret < 0)
1166                                 return ret;
1167                         action_flags |= MLX5_FLOW_ACTION_MARK;
1168                         break;
1169                 case RTE_FLOW_ACTION_TYPE_DROP:
1170                         ret = mlx5_flow_validate_action_drop(action_flags,
1171                                                              error);
1172                         if (ret < 0)
1173                                 return ret;
1174                         action_flags |= MLX5_FLOW_ACTION_DROP;
1175                         break;
1176                 case RTE_FLOW_ACTION_TYPE_QUEUE:
1177                         ret = mlx5_flow_validate_action_queue(actions,
1178                                                               action_flags, dev,
1179                                                               error);
1180                         if (ret < 0)
1181                                 return ret;
1182                         action_flags |= MLX5_FLOW_ACTION_QUEUE;
1183                         break;
1184                 case RTE_FLOW_ACTION_TYPE_RSS:
1185                         ret = mlx5_flow_validate_action_rss(actions,
1186                                                             action_flags, dev,
1187                                                             error);
1188                         if (ret < 0)
1189                                 return ret;
1190                         action_flags |= MLX5_FLOW_ACTION_RSS;
1191                         break;
1192                 case RTE_FLOW_ACTION_TYPE_COUNT:
1193                         ret = mlx5_flow_validate_action_count(dev, error);
1194                         if (ret < 0)
1195                                 return ret;
1196                         action_flags |= MLX5_FLOW_ACTION_COUNT;
1197                         break;
1198                 default:
1199                         return rte_flow_error_set(error, ENOTSUP,
1200                                                   RTE_FLOW_ERROR_TYPE_ACTION,
1201                                                   actions,
1202                                                   "action not supported");
1203                 }
1204         }
1205         if (!(action_flags & MLX5_FLOW_FATE_ACTIONS))
1206                 return rte_flow_error_set(error, EINVAL,
1207                                           RTE_FLOW_ERROR_TYPE_ACTION, actions,
1208                                           "no fate action is found");
1209         return 0;
1210 }
1211
1212 /**
1213  * Calculate the required bytes that are needed for the action part of the verbs
1214  * flow, in addtion returns bit-fields with all the detected action, in order to
1215  * avoid another interation over the actions.
1216  *
1217  * @param[in] actions
1218  *   Pointer to the list of actions.
1219  * @param[out] action_flags
1220  *   Pointer to the detected actions.
1221  *
1222  * @return
1223  *   The size of the memory needed for all actions.
1224  */
1225 static int
1226 flow_verbs_get_actions_and_size(const struct rte_flow_action actions[],
1227                                 uint64_t *action_flags)
1228 {
1229         int size = 0;
1230         uint64_t detected_actions = 0;
1231
1232         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1233                 switch (actions->type) {
1234                 case RTE_FLOW_ACTION_TYPE_VOID:
1235                         break;
1236                 case RTE_FLOW_ACTION_TYPE_FLAG:
1237                         size += sizeof(struct ibv_flow_spec_action_tag);
1238                         detected_actions |= MLX5_FLOW_ACTION_FLAG;
1239                         break;
1240                 case RTE_FLOW_ACTION_TYPE_MARK:
1241                         size += sizeof(struct ibv_flow_spec_action_tag);
1242                         detected_actions |= MLX5_FLOW_ACTION_MARK;
1243                         break;
1244                 case RTE_FLOW_ACTION_TYPE_DROP:
1245                         size += sizeof(struct ibv_flow_spec_action_drop);
1246                         detected_actions |= MLX5_FLOW_ACTION_DROP;
1247                         break;
1248                 case RTE_FLOW_ACTION_TYPE_QUEUE:
1249                         detected_actions |= MLX5_FLOW_ACTION_QUEUE;
1250                         break;
1251                 case RTE_FLOW_ACTION_TYPE_RSS:
1252                         detected_actions |= MLX5_FLOW_ACTION_RSS;
1253                         break;
1254                 case RTE_FLOW_ACTION_TYPE_COUNT:
1255 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
1256                         size += sizeof(struct ibv_flow_spec_counter_action);
1257 #endif
1258                         detected_actions |= MLX5_FLOW_ACTION_COUNT;
1259                         break;
1260                 default:
1261                         break;
1262                 }
1263         }
1264         *action_flags = detected_actions;
1265         return size;
1266 }
1267
1268 /**
1269  * Calculate the required bytes that are needed for the item part of the verbs
1270  * flow, in addtion returns bit-fields with all the detected action, in order to
1271  * avoid another interation over the actions.
1272  *
1273  * @param[in] actions
1274  *   Pointer to the list of items.
1275  * @param[in, out] item_flags
1276  *   Pointer to the detected items.
1277  *
1278  * @return
1279  *   The size of the memory needed for all items.
1280  */
1281 static int
1282 flow_verbs_get_items_and_size(const struct rte_flow_item items[],
1283                               uint64_t *item_flags)
1284 {
1285         int size = 0;
1286         uint64_t detected_items = 0;
1287         const int tunnel = !!(*item_flags & MLX5_FLOW_LAYER_TUNNEL);
1288
1289         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1290                 switch (items->type) {
1291                 case RTE_FLOW_ITEM_TYPE_VOID:
1292                         break;
1293                 case RTE_FLOW_ITEM_TYPE_ETH:
1294                         size += sizeof(struct ibv_flow_spec_eth);
1295                         detected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_L2 :
1296                                                    MLX5_FLOW_LAYER_OUTER_L2;
1297                         break;
1298                 case RTE_FLOW_ITEM_TYPE_VLAN:
1299                         size += sizeof(struct ibv_flow_spec_eth);
1300                         detected_items |= tunnel ? MLX5_FLOW_LAYER_INNER_VLAN :
1301                                                    MLX5_FLOW_LAYER_OUTER_VLAN;
1302                         break;
1303                 case RTE_FLOW_ITEM_TYPE_IPV4:
1304                         size += sizeof(struct ibv_flow_spec_ipv4_ext);
1305                         detected_items |= tunnel ?
1306                                           MLX5_FLOW_LAYER_INNER_L3_IPV4 :
1307                                           MLX5_FLOW_LAYER_OUTER_L3_IPV4;
1308                         break;
1309                 case RTE_FLOW_ITEM_TYPE_IPV6:
1310                         size += sizeof(struct ibv_flow_spec_ipv6);
1311                         detected_items |= tunnel ?
1312                                           MLX5_FLOW_LAYER_INNER_L3_IPV6 :
1313                                           MLX5_FLOW_LAYER_OUTER_L3_IPV6;
1314                         break;
1315                 case RTE_FLOW_ITEM_TYPE_UDP:
1316                         size += sizeof(struct ibv_flow_spec_tcp_udp);
1317                         detected_items |= tunnel ?
1318                                           MLX5_FLOW_LAYER_INNER_L4_UDP :
1319                                           MLX5_FLOW_LAYER_OUTER_L4_UDP;
1320                         break;
1321                 case RTE_FLOW_ITEM_TYPE_TCP:
1322                         size += sizeof(struct ibv_flow_spec_tcp_udp);
1323                         detected_items |= tunnel ?
1324                                           MLX5_FLOW_LAYER_INNER_L4_TCP :
1325                                           MLX5_FLOW_LAYER_OUTER_L4_TCP;
1326                         break;
1327                 case RTE_FLOW_ITEM_TYPE_VXLAN:
1328                         size += sizeof(struct ibv_flow_spec_tunnel);
1329                         detected_items |= MLX5_FLOW_LAYER_VXLAN;
1330                         break;
1331                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1332                         size += sizeof(struct ibv_flow_spec_tunnel);
1333                         detected_items |= MLX5_FLOW_LAYER_VXLAN_GPE;
1334                         break;
1335 #ifdef HAVE_IBV_DEVICE_MPLS_SUPPORT
1336                 case RTE_FLOW_ITEM_TYPE_GRE:
1337                         size += sizeof(struct ibv_flow_spec_gre);
1338                         detected_items |= MLX5_FLOW_LAYER_GRE;
1339                         break;
1340                 case RTE_FLOW_ITEM_TYPE_MPLS:
1341                         size += sizeof(struct ibv_flow_spec_mpls);
1342                         detected_items |= MLX5_FLOW_LAYER_MPLS;
1343                         break;
1344 #else
1345                 case RTE_FLOW_ITEM_TYPE_GRE:
1346                         size += sizeof(struct ibv_flow_spec_tunnel);
1347                         detected_items |= MLX5_FLOW_LAYER_TUNNEL;
1348                         break;
1349 #endif
1350                 default:
1351                         break;
1352                 }
1353         }
1354         *item_flags = detected_items;
1355         return size;
1356 }
1357
1358 /**
1359  * Internal preparation function. Allocate mlx5_flow with the required size.
1360  * The required size is calculate based on the actions and items. This function
1361  * also returns the detected actions and items for later use.
1362  *
1363  * @param[in] attr
1364  *   Pointer to the flow attributes.
1365  * @param[in] items
1366  *   Pointer to the list of items.
1367  * @param[in] actions
1368  *   Pointer to the list of actions.
1369  * @param[out] item_flags
1370  *   Pointer to bit mask of all items detected.
1371  * @param[out] action_flags
1372  *   Pointer to bit mask of all actions detected.
1373  * @param[out] error
1374  *   Pointer to the error structure.
1375  *
1376  * @return
1377  *   Pointer to mlx5_flow object on success, otherwise NULL and rte_errno
1378  *   is set.
1379  */
1380 static struct mlx5_flow *
1381 flow_verbs_prepare(const struct rte_flow_attr *attr __rte_unused,
1382                    const struct rte_flow_item items[],
1383                    const struct rte_flow_action actions[],
1384                    uint64_t *item_flags,
1385                    uint64_t *action_flags,
1386                    struct rte_flow_error *error)
1387 {
1388         uint32_t size = sizeof(struct mlx5_flow) + sizeof(struct ibv_flow_attr);
1389         struct mlx5_flow *flow;
1390
1391         size += flow_verbs_get_actions_and_size(actions, action_flags);
1392         size += flow_verbs_get_items_and_size(items, item_flags);
1393         flow = rte_calloc(__func__, 1, size, 0);
1394         if (!flow) {
1395                 rte_flow_error_set(error, ENOMEM,
1396                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1397                                    "not enough memory to create flow");
1398                 return NULL;
1399         }
1400         flow->verbs.attr = (void *)(flow + 1);
1401         flow->verbs.specs =
1402                 (uint8_t *)(flow + 1) + sizeof(struct ibv_flow_attr);
1403         return flow;
1404 }
1405
1406 /**
1407  * Fill the flow with verb spec.
1408  *
1409  * @param[in] dev
1410  *   Pointer to Ethernet device.
1411  * @param[in, out] dev_flow
1412  *   Pointer to the mlx5 flow.
1413  * @param[in] attr
1414  *   Pointer to the flow attributes.
1415  * @param[in] items
1416  *   Pointer to the list of items.
1417  * @param[in] actions
1418  *   Pointer to the list of actions.
1419  * @param[out] error
1420  *   Pointer to the error structure.
1421  *
1422  * @return
1423  *   0 on success, else a negative errno value otherwise and rte_ernno is set.
1424  */
1425 static int
1426 flow_verbs_translate(struct rte_eth_dev *dev,
1427                      struct mlx5_flow *dev_flow,
1428                      const struct rte_flow_attr *attr,
1429                      const struct rte_flow_item items[],
1430                      const struct rte_flow_action actions[],
1431                      struct rte_flow_error *error)
1432 {
1433         uint64_t action_flags = 0;
1434         uint64_t item_flags = 0;
1435         uint64_t priority = attr->priority;
1436         struct priv *priv = dev->data->dev_private;
1437
1438         if (priority == MLX5_FLOW_PRIO_RSVD)
1439                 priority = priv->config.flow_prio - 1;
1440         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
1441                 int ret;
1442                 switch (actions->type) {
1443                 case RTE_FLOW_ACTION_TYPE_VOID:
1444                         break;
1445                 case RTE_FLOW_ACTION_TYPE_FLAG:
1446                         flow_verbs_translate_action_flag(actions,
1447                                                          &action_flags,
1448                                                          dev_flow);
1449                         break;
1450                 case RTE_FLOW_ACTION_TYPE_MARK:
1451                         flow_verbs_translate_action_mark(actions,
1452                                                          &action_flags,
1453                                                          dev_flow);
1454                         break;
1455                 case RTE_FLOW_ACTION_TYPE_DROP:
1456                         flow_verbs_translate_action_drop(&action_flags,
1457                                                          dev_flow);
1458                         break;
1459                 case RTE_FLOW_ACTION_TYPE_QUEUE:
1460                         flow_verbs_translate_action_queue(actions,
1461                                                           &action_flags,
1462                                                           dev_flow);
1463                         break;
1464                 case RTE_FLOW_ACTION_TYPE_RSS:
1465                         flow_verbs_translate_action_rss(actions,
1466                                                         &action_flags,
1467                                                         dev_flow);
1468                         break;
1469                 case RTE_FLOW_ACTION_TYPE_COUNT:
1470                         ret = flow_verbs_translate_action_count(dev,
1471                                                                 actions,
1472                                                                 &action_flags,
1473                                                                 dev_flow,
1474                                                                 error);
1475                         if (ret < 0)
1476                                 return ret;
1477                         break;
1478                 default:
1479                         return rte_flow_error_set(error, ENOTSUP,
1480                                                   RTE_FLOW_ERROR_TYPE_ACTION,
1481                                                   actions,
1482                                                   "action not supported");
1483                 }
1484         }
1485         dev_flow->flow->actions |= action_flags;
1486         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
1487                 switch (items->type) {
1488                 case RTE_FLOW_ITEM_TYPE_VOID:
1489                         break;
1490                 case RTE_FLOW_ITEM_TYPE_ETH:
1491                         flow_verbs_translate_item_eth(items, &item_flags,
1492                                                       dev_flow);
1493                         break;
1494                 case RTE_FLOW_ITEM_TYPE_VLAN:
1495                         flow_verbs_translate_item_vlan(items, &item_flags,
1496                                                        dev_flow);
1497                         break;
1498                 case RTE_FLOW_ITEM_TYPE_IPV4:
1499                         flow_verbs_translate_item_ipv4(items, &item_flags,
1500                                                        dev_flow);
1501                         break;
1502                 case RTE_FLOW_ITEM_TYPE_IPV6:
1503                         flow_verbs_translate_item_ipv6(items, &item_flags,
1504                                                        dev_flow);
1505                         break;
1506                 case RTE_FLOW_ITEM_TYPE_UDP:
1507                         flow_verbs_translate_item_udp(items, &item_flags,
1508                                                       dev_flow);
1509                         break;
1510                 case RTE_FLOW_ITEM_TYPE_TCP:
1511                         flow_verbs_translate_item_tcp(items, &item_flags,
1512                                                       dev_flow);
1513                         break;
1514                 case RTE_FLOW_ITEM_TYPE_VXLAN:
1515                         flow_verbs_translate_item_vxlan(items, &item_flags,
1516                                                         dev_flow);
1517                         break;
1518                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1519                         flow_verbs_translate_item_vxlan_gpe(items, &item_flags,
1520                                                             dev_flow);
1521                         break;
1522                 case RTE_FLOW_ITEM_TYPE_GRE:
1523                         flow_verbs_translate_item_gre(items, &item_flags,
1524                                                       dev_flow);
1525                         break;
1526                 case RTE_FLOW_ITEM_TYPE_MPLS:
1527                         flow_verbs_translate_item_mpls(items, &item_flags,
1528                                                        dev_flow);
1529                         break;
1530                 default:
1531                         return rte_flow_error_set(error, ENOTSUP,
1532                                                   RTE_FLOW_ERROR_TYPE_ITEM,
1533                                                   NULL,
1534                                                   "item not supported");
1535                 }
1536         }
1537         dev_flow->verbs.attr->priority =
1538                 mlx5_flow_adjust_priority(dev, priority,
1539                                           dev_flow->verbs.attr->priority);
1540         return 0;
1541 }
1542
1543 /**
1544  * Remove the flow from the NIC but keeps it in memory.
1545  *
1546  * @param[in] dev
1547  *   Pointer to the Ethernet device structure.
1548  * @param[in, out] flow
1549  *   Pointer to flow structure.
1550  */
1551 static void
1552 flow_verbs_remove(struct rte_eth_dev *dev, struct rte_flow *flow)
1553 {
1554         struct mlx5_flow_verbs *verbs;
1555         struct mlx5_flow *dev_flow;
1556
1557         if (!flow)
1558                 return;
1559         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
1560                 verbs = &dev_flow->verbs;
1561                 if (verbs->flow) {
1562                         claim_zero(mlx5_glue->destroy_flow(verbs->flow));
1563                         verbs->flow = NULL;
1564                 }
1565                 if (verbs->hrxq) {
1566                         if (flow->actions & MLX5_FLOW_ACTION_DROP)
1567                                 mlx5_hrxq_drop_release(dev);
1568                         else
1569                                 mlx5_hrxq_release(dev, verbs->hrxq);
1570                         verbs->hrxq = NULL;
1571                 }
1572         }
1573         if (flow->counter) {
1574                 flow_verbs_counter_release(flow->counter);
1575                 flow->counter = NULL;
1576         }
1577 }
1578
1579 /**
1580  * Remove the flow from the NIC and the memory.
1581  *
1582  * @param[in] dev
1583  *   Pointer to the Ethernet device structure.
1584  * @param[in, out] flow
1585  *   Pointer to flow structure.
1586  */
1587 static void
1588 flow_verbs_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
1589 {
1590         struct mlx5_flow *dev_flow;
1591
1592         if (!flow)
1593                 return;
1594         flow_verbs_remove(dev, flow);
1595         while (!LIST_EMPTY(&flow->dev_flows)) {
1596                 dev_flow = LIST_FIRST(&flow->dev_flows);
1597                 LIST_REMOVE(dev_flow, next);
1598                 rte_free(dev_flow);
1599         }
1600 }
1601
1602 /**
1603  * Apply the flow to the NIC.
1604  *
1605  * @param[in] dev
1606  *   Pointer to the Ethernet device structure.
1607  * @param[in, out] flow
1608  *   Pointer to flow structure.
1609  * @param[out] error
1610  *   Pointer to error structure.
1611  *
1612  * @return
1613  *   0 on success, a negative errno value otherwise and rte_errno is set.
1614  */
1615 static int
1616 flow_verbs_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
1617                  struct rte_flow_error *error)
1618 {
1619         struct mlx5_flow_verbs *verbs;
1620         struct mlx5_flow *dev_flow;
1621         int err;
1622
1623         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
1624                 verbs = &dev_flow->verbs;
1625                 if (flow->actions & MLX5_FLOW_ACTION_DROP) {
1626                         verbs->hrxq = mlx5_hrxq_drop_new(dev);
1627                         if (!verbs->hrxq) {
1628                                 rte_flow_error_set
1629                                         (error, errno,
1630                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1631                                          "cannot get drop hash queue");
1632                                 goto error;
1633                         }
1634                 } else {
1635                         struct mlx5_hrxq *hrxq;
1636
1637                         hrxq = mlx5_hrxq_get(dev, flow->key,
1638                                              MLX5_RSS_HASH_KEY_LEN,
1639                                              verbs->hash_fields,
1640                                              (*flow->queue),
1641                                              flow->rss.queue_num);
1642                         if (!hrxq)
1643                                 hrxq = mlx5_hrxq_new(dev, flow->key,
1644                                                      MLX5_RSS_HASH_KEY_LEN,
1645                                                      verbs->hash_fields,
1646                                                      (*flow->queue),
1647                                                      flow->rss.queue_num,
1648                                                      !!(flow->layers &
1649                                                       MLX5_FLOW_LAYER_TUNNEL));
1650                         if (!hrxq) {
1651                                 rte_flow_error_set
1652                                         (error, rte_errno,
1653                                          RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1654                                          "cannot get hash queue");
1655                                 goto error;
1656                         }
1657                         verbs->hrxq = hrxq;
1658                 }
1659                 verbs->flow = mlx5_glue->create_flow(verbs->hrxq->qp,
1660                                                      verbs->attr);
1661                 if (!verbs->flow) {
1662                         rte_flow_error_set(error, errno,
1663                                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1664                                            NULL,
1665                                            "hardware refuses to create flow");
1666                         goto error;
1667                 }
1668         }
1669         return 0;
1670 error:
1671         err = rte_errno; /* Save rte_errno before cleanup. */
1672         LIST_FOREACH(dev_flow, &flow->dev_flows, next) {
1673                 verbs = &dev_flow->verbs;
1674                 if (verbs->hrxq) {
1675                         if (flow->actions & MLX5_FLOW_ACTION_DROP)
1676                                 mlx5_hrxq_drop_release(dev);
1677                         else
1678                                 mlx5_hrxq_release(dev, verbs->hrxq);
1679                         verbs->hrxq = NULL;
1680                 }
1681         }
1682         rte_errno = err; /* Restore rte_errno. */
1683         return -rte_errno;
1684 }
1685
1686 void
1687 mlx5_flow_verbs_get_driver_ops(struct mlx5_flow_driver_ops *flow_ops)
1688 {
1689         *flow_ops = (struct mlx5_flow_driver_ops) {
1690                 .validate = flow_verbs_validate,
1691                 .prepare = flow_verbs_prepare,
1692                 .translate = flow_verbs_translate,
1693                 .apply = flow_verbs_apply,
1694                 .remove = flow_verbs_remove,
1695                 .destroy = flow_verbs_destroy,
1696         };
1697 }