ethdev: alter behavior of flow API actions
[dpdk.git] / drivers / net / mlx5 / mlx5_flow.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016 6WIND S.A.
3  * Copyright 2016 Mellanox Technologies, Ltd
4  */
5
6 #include <sys/queue.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_ethdev_driver.h>
22 #include <rte_flow.h>
23 #include <rte_flow_driver.h>
24 #include <rte_malloc.h>
25 #include <rte_ip.h>
26
27 #include "mlx5.h"
28 #include "mlx5_defs.h"
29 #include "mlx5_prm.h"
30 #include "mlx5_glue.h"
31
32 /* Define minimal priority for control plane flows. */
33 #define MLX5_CTRL_FLOW_PRIORITY 4
34
35 /* Internet Protocol versions. */
36 #define MLX5_IPV4 4
37 #define MLX5_IPV6 6
38
39 #ifndef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
40 struct ibv_flow_spec_counter_action {
41         int dummy;
42 };
43 #endif
44
45 /* Dev ops structure defined in mlx5.c */
46 extern const struct eth_dev_ops mlx5_dev_ops;
47 extern const struct eth_dev_ops mlx5_dev_ops_isolate;
48
49 /** Structure give to the conversion functions. */
50 struct mlx5_flow_data {
51         struct mlx5_flow_parse *parser; /** Parser context. */
52         struct rte_flow_error *error; /** Error context. */
53 };
54
55 static int
56 mlx5_flow_create_eth(const struct rte_flow_item *item,
57                      const void *default_mask,
58                      struct mlx5_flow_data *data);
59
60 static int
61 mlx5_flow_create_vlan(const struct rte_flow_item *item,
62                       const void *default_mask,
63                       struct mlx5_flow_data *data);
64
65 static int
66 mlx5_flow_create_ipv4(const struct rte_flow_item *item,
67                       const void *default_mask,
68                       struct mlx5_flow_data *data);
69
70 static int
71 mlx5_flow_create_ipv6(const struct rte_flow_item *item,
72                       const void *default_mask,
73                       struct mlx5_flow_data *data);
74
75 static int
76 mlx5_flow_create_udp(const struct rte_flow_item *item,
77                      const void *default_mask,
78                      struct mlx5_flow_data *data);
79
80 static int
81 mlx5_flow_create_tcp(const struct rte_flow_item *item,
82                      const void *default_mask,
83                      struct mlx5_flow_data *data);
84
85 static int
86 mlx5_flow_create_vxlan(const struct rte_flow_item *item,
87                        const void *default_mask,
88                        struct mlx5_flow_data *data);
89
90 struct mlx5_flow_parse;
91
92 static void
93 mlx5_flow_create_copy(struct mlx5_flow_parse *parser, void *src,
94                       unsigned int size);
95
96 static int
97 mlx5_flow_create_flag_mark(struct mlx5_flow_parse *parser, uint32_t mark_id);
98
99 static int
100 mlx5_flow_create_count(struct rte_eth_dev *dev, struct mlx5_flow_parse *parser);
101
102 /* Hash RX queue types. */
103 enum hash_rxq_type {
104         HASH_RXQ_TCPV4,
105         HASH_RXQ_UDPV4,
106         HASH_RXQ_IPV4,
107         HASH_RXQ_TCPV6,
108         HASH_RXQ_UDPV6,
109         HASH_RXQ_IPV6,
110         HASH_RXQ_ETH,
111 };
112
113 /* Initialization data for hash RX queue. */
114 struct hash_rxq_init {
115         uint64_t hash_fields; /* Fields that participate in the hash. */
116         uint64_t dpdk_rss_hf; /* Matching DPDK RSS hash fields. */
117         unsigned int flow_priority; /* Flow priority to use. */
118         unsigned int ip_version; /* Internet protocol. */
119 };
120
121 /* Initialization data for hash RX queues. */
122 const struct hash_rxq_init hash_rxq_init[] = {
123         [HASH_RXQ_TCPV4] = {
124                 .hash_fields = (IBV_RX_HASH_SRC_IPV4 |
125                                 IBV_RX_HASH_DST_IPV4 |
126                                 IBV_RX_HASH_SRC_PORT_TCP |
127                                 IBV_RX_HASH_DST_PORT_TCP),
128                 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV4_TCP,
129                 .flow_priority = 1,
130                 .ip_version = MLX5_IPV4,
131         },
132         [HASH_RXQ_UDPV4] = {
133                 .hash_fields = (IBV_RX_HASH_SRC_IPV4 |
134                                 IBV_RX_HASH_DST_IPV4 |
135                                 IBV_RX_HASH_SRC_PORT_UDP |
136                                 IBV_RX_HASH_DST_PORT_UDP),
137                 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV4_UDP,
138                 .flow_priority = 1,
139                 .ip_version = MLX5_IPV4,
140         },
141         [HASH_RXQ_IPV4] = {
142                 .hash_fields = (IBV_RX_HASH_SRC_IPV4 |
143                                 IBV_RX_HASH_DST_IPV4),
144                 .dpdk_rss_hf = (ETH_RSS_IPV4 |
145                                 ETH_RSS_FRAG_IPV4),
146                 .flow_priority = 2,
147                 .ip_version = MLX5_IPV4,
148         },
149         [HASH_RXQ_TCPV6] = {
150                 .hash_fields = (IBV_RX_HASH_SRC_IPV6 |
151                                 IBV_RX_HASH_DST_IPV6 |
152                                 IBV_RX_HASH_SRC_PORT_TCP |
153                                 IBV_RX_HASH_DST_PORT_TCP),
154                 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV6_TCP,
155                 .flow_priority = 1,
156                 .ip_version = MLX5_IPV6,
157         },
158         [HASH_RXQ_UDPV6] = {
159                 .hash_fields = (IBV_RX_HASH_SRC_IPV6 |
160                                 IBV_RX_HASH_DST_IPV6 |
161                                 IBV_RX_HASH_SRC_PORT_UDP |
162                                 IBV_RX_HASH_DST_PORT_UDP),
163                 .dpdk_rss_hf = ETH_RSS_NONFRAG_IPV6_UDP,
164                 .flow_priority = 1,
165                 .ip_version = MLX5_IPV6,
166         },
167         [HASH_RXQ_IPV6] = {
168                 .hash_fields = (IBV_RX_HASH_SRC_IPV6 |
169                                 IBV_RX_HASH_DST_IPV6),
170                 .dpdk_rss_hf = (ETH_RSS_IPV6 |
171                                 ETH_RSS_FRAG_IPV6),
172                 .flow_priority = 2,
173                 .ip_version = MLX5_IPV6,
174         },
175         [HASH_RXQ_ETH] = {
176                 .hash_fields = 0,
177                 .dpdk_rss_hf = 0,
178                 .flow_priority = 3,
179         },
180 };
181
182 /* Number of entries in hash_rxq_init[]. */
183 const unsigned int hash_rxq_init_n = RTE_DIM(hash_rxq_init);
184
185 /** Structure for holding counter stats. */
186 struct mlx5_flow_counter_stats {
187         uint64_t hits; /**< Number of packets matched by the rule. */
188         uint64_t bytes; /**< Number of bytes matched by the rule. */
189 };
190
191 /** Structure for Drop queue. */
192 struct mlx5_hrxq_drop {
193         struct ibv_rwq_ind_table *ind_table; /**< Indirection table. */
194         struct ibv_qp *qp; /**< Verbs queue pair. */
195         struct ibv_wq *wq; /**< Verbs work queue. */
196         struct ibv_cq *cq; /**< Verbs completion queue. */
197 };
198
199 /* Flows structures. */
200 struct mlx5_flow {
201         uint64_t hash_fields; /**< Fields that participate in the hash. */
202         struct ibv_flow_attr *ibv_attr; /**< Pointer to Verbs attributes. */
203         struct ibv_flow *ibv_flow; /**< Verbs flow. */
204         struct mlx5_hrxq *hrxq; /**< Hash Rx queues. */
205 };
206
207 /* Drop flows structures. */
208 struct mlx5_flow_drop {
209         struct ibv_flow_attr *ibv_attr; /**< Pointer to Verbs attributes. */
210         struct ibv_flow *ibv_flow; /**< Verbs flow. */
211 };
212
213 struct rte_flow {
214         TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */
215         uint32_t mark:1; /**< Set if the flow is marked. */
216         uint32_t drop:1; /**< Drop queue. */
217         uint16_t queues_n; /**< Number of entries in queue[]. */
218         uint16_t (*queues)[]; /**< Queues indexes to use. */
219         struct rte_eth_rss_conf rss_conf; /**< RSS configuration */
220         uint8_t rss_key[40]; /**< copy of the RSS key. */
221         struct ibv_counter_set *cs; /**< Holds the counters for the rule. */
222         struct mlx5_flow_counter_stats counter_stats;/**<The counter stats. */
223         struct mlx5_flow frxq[RTE_DIM(hash_rxq_init)];
224         /**< Flow with Rx queue. */
225 };
226
227 /** Static initializer for items. */
228 #define ITEMS(...) \
229         (const enum rte_flow_item_type []){ \
230                 __VA_ARGS__, RTE_FLOW_ITEM_TYPE_END, \
231         }
232
233 /** Structure to generate a simple graph of layers supported by the NIC. */
234 struct mlx5_flow_items {
235         /** List of possible actions for these items. */
236         const enum rte_flow_action_type *const actions;
237         /** Bit-masks corresponding to the possibilities for the item. */
238         const void *mask;
239         /**
240          * Default bit-masks to use when item->mask is not provided. When
241          * \default_mask is also NULL, the full supported bit-mask (\mask) is
242          * used instead.
243          */
244         const void *default_mask;
245         /** Bit-masks size in bytes. */
246         const unsigned int mask_sz;
247         /**
248          * Conversion function from rte_flow to NIC specific flow.
249          *
250          * @param item
251          *   rte_flow item to convert.
252          * @param default_mask
253          *   Default bit-masks to use when item->mask is not provided.
254          * @param data
255          *   Internal structure to store the conversion.
256          *
257          * @return
258          *   0 on success, a negative errno value otherwise and rte_errno is
259          *   set.
260          */
261         int (*convert)(const struct rte_flow_item *item,
262                        const void *default_mask,
263                        struct mlx5_flow_data *data);
264         /** Size in bytes of the destination structure. */
265         const unsigned int dst_sz;
266         /** List of possible following items.  */
267         const enum rte_flow_item_type *const items;
268 };
269
270 /** Valid action for this PMD. */
271 static const enum rte_flow_action_type valid_actions[] = {
272         RTE_FLOW_ACTION_TYPE_DROP,
273         RTE_FLOW_ACTION_TYPE_QUEUE,
274         RTE_FLOW_ACTION_TYPE_MARK,
275         RTE_FLOW_ACTION_TYPE_FLAG,
276 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
277         RTE_FLOW_ACTION_TYPE_COUNT,
278 #endif
279         RTE_FLOW_ACTION_TYPE_END,
280 };
281
282 /** Graph of supported items and associated actions. */
283 static const struct mlx5_flow_items mlx5_flow_items[] = {
284         [RTE_FLOW_ITEM_TYPE_END] = {
285                 .items = ITEMS(RTE_FLOW_ITEM_TYPE_ETH,
286                                RTE_FLOW_ITEM_TYPE_VXLAN),
287         },
288         [RTE_FLOW_ITEM_TYPE_ETH] = {
289                 .items = ITEMS(RTE_FLOW_ITEM_TYPE_VLAN,
290                                RTE_FLOW_ITEM_TYPE_IPV4,
291                                RTE_FLOW_ITEM_TYPE_IPV6),
292                 .actions = valid_actions,
293                 .mask = &(const struct rte_flow_item_eth){
294                         .dst.addr_bytes = "\xff\xff\xff\xff\xff\xff",
295                         .src.addr_bytes = "\xff\xff\xff\xff\xff\xff",
296                         .type = -1,
297                 },
298                 .default_mask = &rte_flow_item_eth_mask,
299                 .mask_sz = sizeof(struct rte_flow_item_eth),
300                 .convert = mlx5_flow_create_eth,
301                 .dst_sz = sizeof(struct ibv_flow_spec_eth),
302         },
303         [RTE_FLOW_ITEM_TYPE_VLAN] = {
304                 .items = ITEMS(RTE_FLOW_ITEM_TYPE_IPV4,
305                                RTE_FLOW_ITEM_TYPE_IPV6),
306                 .actions = valid_actions,
307                 .mask = &(const struct rte_flow_item_vlan){
308                         .tci = -1,
309                 },
310                 .default_mask = &rte_flow_item_vlan_mask,
311                 .mask_sz = sizeof(struct rte_flow_item_vlan),
312                 .convert = mlx5_flow_create_vlan,
313                 .dst_sz = 0,
314         },
315         [RTE_FLOW_ITEM_TYPE_IPV4] = {
316                 .items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
317                                RTE_FLOW_ITEM_TYPE_TCP),
318                 .actions = valid_actions,
319                 .mask = &(const struct rte_flow_item_ipv4){
320                         .hdr = {
321                                 .src_addr = -1,
322                                 .dst_addr = -1,
323                                 .type_of_service = -1,
324                                 .next_proto_id = -1,
325                         },
326                 },
327                 .default_mask = &rte_flow_item_ipv4_mask,
328                 .mask_sz = sizeof(struct rte_flow_item_ipv4),
329                 .convert = mlx5_flow_create_ipv4,
330                 .dst_sz = sizeof(struct ibv_flow_spec_ipv4_ext),
331         },
332         [RTE_FLOW_ITEM_TYPE_IPV6] = {
333                 .items = ITEMS(RTE_FLOW_ITEM_TYPE_UDP,
334                                RTE_FLOW_ITEM_TYPE_TCP),
335                 .actions = valid_actions,
336                 .mask = &(const struct rte_flow_item_ipv6){
337                         .hdr = {
338                                 .src_addr = {
339                                         0xff, 0xff, 0xff, 0xff,
340                                         0xff, 0xff, 0xff, 0xff,
341                                         0xff, 0xff, 0xff, 0xff,
342                                         0xff, 0xff, 0xff, 0xff,
343                                 },
344                                 .dst_addr = {
345                                         0xff, 0xff, 0xff, 0xff,
346                                         0xff, 0xff, 0xff, 0xff,
347                                         0xff, 0xff, 0xff, 0xff,
348                                         0xff, 0xff, 0xff, 0xff,
349                                 },
350                                 .vtc_flow = -1,
351                                 .proto = -1,
352                                 .hop_limits = -1,
353                         },
354                 },
355                 .default_mask = &rte_flow_item_ipv6_mask,
356                 .mask_sz = sizeof(struct rte_flow_item_ipv6),
357                 .convert = mlx5_flow_create_ipv6,
358                 .dst_sz = sizeof(struct ibv_flow_spec_ipv6),
359         },
360         [RTE_FLOW_ITEM_TYPE_UDP] = {
361                 .items = ITEMS(RTE_FLOW_ITEM_TYPE_VXLAN),
362                 .actions = valid_actions,
363                 .mask = &(const struct rte_flow_item_udp){
364                         .hdr = {
365                                 .src_port = -1,
366                                 .dst_port = -1,
367                         },
368                 },
369                 .default_mask = &rte_flow_item_udp_mask,
370                 .mask_sz = sizeof(struct rte_flow_item_udp),
371                 .convert = mlx5_flow_create_udp,
372                 .dst_sz = sizeof(struct ibv_flow_spec_tcp_udp),
373         },
374         [RTE_FLOW_ITEM_TYPE_TCP] = {
375                 .actions = valid_actions,
376                 .mask = &(const struct rte_flow_item_tcp){
377                         .hdr = {
378                                 .src_port = -1,
379                                 .dst_port = -1,
380                         },
381                 },
382                 .default_mask = &rte_flow_item_tcp_mask,
383                 .mask_sz = sizeof(struct rte_flow_item_tcp),
384                 .convert = mlx5_flow_create_tcp,
385                 .dst_sz = sizeof(struct ibv_flow_spec_tcp_udp),
386         },
387         [RTE_FLOW_ITEM_TYPE_VXLAN] = {
388                 .items = ITEMS(RTE_FLOW_ITEM_TYPE_ETH),
389                 .actions = valid_actions,
390                 .mask = &(const struct rte_flow_item_vxlan){
391                         .vni = "\xff\xff\xff",
392                 },
393                 .default_mask = &rte_flow_item_vxlan_mask,
394                 .mask_sz = sizeof(struct rte_flow_item_vxlan),
395                 .convert = mlx5_flow_create_vxlan,
396                 .dst_sz = sizeof(struct ibv_flow_spec_tunnel),
397         },
398 };
399
400 /** Structure to pass to the conversion function. */
401 struct mlx5_flow_parse {
402         uint32_t inner; /**< Set once VXLAN is encountered. */
403         uint32_t create:1;
404         /**< Whether resources should remain after a validate. */
405         uint32_t drop:1; /**< Target is a drop queue. */
406         uint32_t mark:1; /**< Mark is present in the flow. */
407         uint32_t count:1; /**< Count is present in the flow. */
408         uint32_t mark_id; /**< Mark identifier. */
409         uint16_t queues[RTE_MAX_QUEUES_PER_PORT]; /**< Queues indexes to use. */
410         uint16_t queues_n; /**< Number of entries in queue[]. */
411         struct rte_eth_rss_conf rss_conf; /**< RSS configuration */
412         uint8_t rss_key[40]; /**< copy of the RSS key. */
413         enum hash_rxq_type layer; /**< Last pattern layer detected. */
414         struct ibv_counter_set *cs; /**< Holds the counter set for the rule */
415         struct {
416                 struct ibv_flow_attr *ibv_attr;
417                 /**< Pointer to Verbs attributes. */
418                 unsigned int offset;
419                 /**< Current position or total size of the attribute. */
420         } queue[RTE_DIM(hash_rxq_init)];
421 };
422
423 static const struct rte_flow_ops mlx5_flow_ops = {
424         .validate = mlx5_flow_validate,
425         .create = mlx5_flow_create,
426         .destroy = mlx5_flow_destroy,
427         .flush = mlx5_flow_flush,
428 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
429         .query = mlx5_flow_query,
430 #else
431         .query = NULL,
432 #endif
433         .isolate = mlx5_flow_isolate,
434 };
435
436 /* Convert FDIR request to Generic flow. */
437 struct mlx5_fdir {
438         struct rte_flow_attr attr;
439         struct rte_flow_action actions[2];
440         struct rte_flow_item items[4];
441         struct rte_flow_item_eth l2;
442         struct rte_flow_item_eth l2_mask;
443         union {
444                 struct rte_flow_item_ipv4 ipv4;
445                 struct rte_flow_item_ipv6 ipv6;
446         } l3;
447         union {
448                 struct rte_flow_item_ipv4 ipv4;
449                 struct rte_flow_item_ipv6 ipv6;
450         } l3_mask;
451         union {
452                 struct rte_flow_item_udp udp;
453                 struct rte_flow_item_tcp tcp;
454         } l4;
455         union {
456                 struct rte_flow_item_udp udp;
457                 struct rte_flow_item_tcp tcp;
458         } l4_mask;
459         struct rte_flow_action_queue queue;
460 };
461
462 /* Verbs specification header. */
463 struct ibv_spec_header {
464         enum ibv_flow_spec_type type;
465         uint16_t size;
466 };
467
468 /**
469  * Check support for a given item.
470  *
471  * @param item[in]
472  *   Item specification.
473  * @param mask[in]
474  *   Bit-masks covering supported fields to compare with spec, last and mask in
475  *   \item.
476  * @param size
477  *   Bit-Mask size in bytes.
478  *
479  * @return
480  *   0 on success, a negative errno value otherwise and rte_errno is set.
481  */
482 static int
483 mlx5_flow_item_validate(const struct rte_flow_item *item,
484                         const uint8_t *mask, unsigned int size)
485 {
486         if (!item->spec && (item->mask || item->last)) {
487                 rte_errno = EINVAL;
488                 return -rte_errno;
489         }
490         if (item->spec && !item->mask) {
491                 unsigned int i;
492                 const uint8_t *spec = item->spec;
493
494                 for (i = 0; i < size; ++i)
495                         if ((spec[i] | mask[i]) != mask[i]) {
496                                 rte_errno = EINVAL;
497                                 return -rte_errno;
498                         }
499         }
500         if (item->last && !item->mask) {
501                 unsigned int i;
502                 const uint8_t *spec = item->last;
503
504                 for (i = 0; i < size; ++i)
505                         if ((spec[i] | mask[i]) != mask[i]) {
506                                 rte_errno = EINVAL;
507                                 return -rte_errno;
508                         }
509         }
510         if (item->mask) {
511                 unsigned int i;
512                 const uint8_t *spec = item->spec;
513
514                 for (i = 0; i < size; ++i)
515                         if ((spec[i] | mask[i]) != mask[i]) {
516                                 rte_errno = EINVAL;
517                                 return -rte_errno;
518                         }
519         }
520         if (item->spec && item->last) {
521                 uint8_t spec[size];
522                 uint8_t last[size];
523                 const uint8_t *apply = mask;
524                 unsigned int i;
525                 int ret;
526
527                 if (item->mask)
528                         apply = item->mask;
529                 for (i = 0; i < size; ++i) {
530                         spec[i] = ((const uint8_t *)item->spec)[i] & apply[i];
531                         last[i] = ((const uint8_t *)item->last)[i] & apply[i];
532                 }
533                 ret = memcmp(spec, last, size);
534                 if (ret != 0) {
535                         rte_errno = EINVAL;
536                         return -rte_errno;
537                 }
538         }
539         return 0;
540 }
541
542 /**
543  * Copy the RSS configuration from the user ones, of the rss_conf is null,
544  * uses the driver one.
545  *
546  * @param parser
547  *   Internal parser structure.
548  * @param rss_conf
549  *   User RSS configuration to save.
550  *
551  * @return
552  *   0 on success, a negative errno value otherwise and rte_errno is set.
553  */
554 static int
555 mlx5_flow_convert_rss_conf(struct mlx5_flow_parse *parser,
556                            const struct rte_eth_rss_conf *rss_conf)
557 {
558         /*
559          * This function is also called at the beginning of
560          * mlx5_flow_convert_actions() to initialize the parser with the
561          * device default RSS configuration.
562          */
563         if (rss_conf) {
564                 if (rss_conf->rss_hf & MLX5_RSS_HF_MASK) {
565                         rte_errno = EINVAL;
566                         return -rte_errno;
567                 }
568                 if (rss_conf->rss_key_len != 40) {
569                         rte_errno = EINVAL;
570                         return -rte_errno;
571                 }
572                 if (rss_conf->rss_key_len && rss_conf->rss_key) {
573                         parser->rss_conf.rss_key_len = rss_conf->rss_key_len;
574                         memcpy(parser->rss_key, rss_conf->rss_key,
575                                rss_conf->rss_key_len);
576                         parser->rss_conf.rss_key = parser->rss_key;
577                 }
578                 parser->rss_conf.rss_hf = rss_conf->rss_hf;
579         }
580         return 0;
581 }
582
583 /**
584  * Extract attribute to the parser.
585  *
586  * @param[in] attr
587  *   Flow rule attributes.
588  * @param[out] error
589  *   Perform verbose error reporting if not NULL.
590  *
591  * @return
592  *   0 on success, a negative errno value otherwise and rte_errno is set.
593  */
594 static int
595 mlx5_flow_convert_attributes(const struct rte_flow_attr *attr,
596                              struct rte_flow_error *error)
597 {
598         if (attr->group) {
599                 rte_flow_error_set(error, ENOTSUP,
600                                    RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
601                                    NULL,
602                                    "groups are not supported");
603                 return -rte_errno;
604         }
605         if (attr->priority && attr->priority != MLX5_CTRL_FLOW_PRIORITY) {
606                 rte_flow_error_set(error, ENOTSUP,
607                                    RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY,
608                                    NULL,
609                                    "priorities are not supported");
610                 return -rte_errno;
611         }
612         if (attr->egress) {
613                 rte_flow_error_set(error, ENOTSUP,
614                                    RTE_FLOW_ERROR_TYPE_ATTR_EGRESS,
615                                    NULL,
616                                    "egress is not supported");
617                 return -rte_errno;
618         }
619         if (!attr->ingress) {
620                 rte_flow_error_set(error, ENOTSUP,
621                                    RTE_FLOW_ERROR_TYPE_ATTR_INGRESS,
622                                    NULL,
623                                    "only ingress is supported");
624                 return -rte_errno;
625         }
626         return 0;
627 }
628
629 /**
630  * Extract actions request to the parser.
631  *
632  * @param dev
633  *   Pointer to Ethernet device.
634  * @param[in] actions
635  *   Associated actions (list terminated by the END action).
636  * @param[out] error
637  *   Perform verbose error reporting if not NULL.
638  * @param[in, out] parser
639  *   Internal parser structure.
640  *
641  * @return
642  *   0 on success, a negative errno value otherwise and rte_errno is set.
643  */
644 static int
645 mlx5_flow_convert_actions(struct rte_eth_dev *dev,
646                           const struct rte_flow_action actions[],
647                           struct rte_flow_error *error,
648                           struct mlx5_flow_parse *parser)
649 {
650         enum { FATE = 1, MARK = 2, COUNT = 4, };
651         uint32_t overlap = 0;
652         struct priv *priv = dev->data->dev_private;
653         int ret;
654
655         /*
656          * Add default RSS configuration necessary for Verbs to create QP even
657          * if no RSS is necessary.
658          */
659         ret = mlx5_flow_convert_rss_conf(parser,
660                                          (const struct rte_eth_rss_conf *)
661                                          &priv->rss_conf);
662         if (ret)
663                 return ret;
664         for (; actions->type != RTE_FLOW_ACTION_TYPE_END; ++actions) {
665                 if (actions->type == RTE_FLOW_ACTION_TYPE_VOID) {
666                         continue;
667                 } else if (actions->type == RTE_FLOW_ACTION_TYPE_DROP) {
668                         if (overlap & FATE)
669                                 goto exit_action_overlap;
670                         overlap |= FATE;
671                         parser->drop = 1;
672                 } else if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
673                         const struct rte_flow_action_queue *queue =
674                                 (const struct rte_flow_action_queue *)
675                                 actions->conf;
676
677                         if (overlap & FATE)
678                                 goto exit_action_overlap;
679                         overlap |= FATE;
680                         if (!queue || (queue->index > (priv->rxqs_n - 1)))
681                                 goto exit_action_not_supported;
682                         parser->queues_n = 1;
683                         parser->queues[0] = queue->index;
684                 } else if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
685                         const struct rte_flow_action_rss *rss =
686                                 (const struct rte_flow_action_rss *)
687                                 actions->conf;
688                         uint16_t n;
689
690                         if (overlap & FATE)
691                                 goto exit_action_overlap;
692                         overlap |= FATE;
693                         if (!rss || !rss->num) {
694                                 rte_flow_error_set(error, EINVAL,
695                                                    RTE_FLOW_ERROR_TYPE_ACTION,
696                                                    actions,
697                                                    "no valid queues");
698                                 return -rte_errno;
699                         }
700                         if (rss->num > RTE_DIM(parser->queues)) {
701                                 rte_flow_error_set(error, EINVAL,
702                                                    RTE_FLOW_ERROR_TYPE_ACTION,
703                                                    actions,
704                                                    "too many queues for RSS"
705                                                    " context");
706                                 return -rte_errno;
707                         }
708                         for (n = 0; n < rss->num; ++n) {
709                                 if (rss->queue[n] >= priv->rxqs_n) {
710                                         rte_flow_error_set(error, EINVAL,
711                                                    RTE_FLOW_ERROR_TYPE_ACTION,
712                                                    actions,
713                                                    "queue id > number of"
714                                                    " queues");
715                                         return -rte_errno;
716                                 }
717                         }
718                         for (n = 0; n < rss->num; ++n)
719                                 parser->queues[n] = rss->queue[n];
720                         parser->queues_n = rss->num;
721                         if (mlx5_flow_convert_rss_conf(parser, rss->rss_conf)) {
722                                 rte_flow_error_set(error, EINVAL,
723                                                    RTE_FLOW_ERROR_TYPE_ACTION,
724                                                    actions,
725                                                    "wrong RSS configuration");
726                                 return -rte_errno;
727                         }
728                 } else if (actions->type == RTE_FLOW_ACTION_TYPE_MARK) {
729                         const struct rte_flow_action_mark *mark =
730                                 (const struct rte_flow_action_mark *)
731                                 actions->conf;
732
733                         if (overlap & MARK)
734                                 goto exit_action_overlap;
735                         overlap |= MARK;
736                         if (!mark) {
737                                 rte_flow_error_set(error, EINVAL,
738                                                    RTE_FLOW_ERROR_TYPE_ACTION,
739                                                    actions,
740                                                    "mark must be defined");
741                                 return -rte_errno;
742                         } else if (mark->id >= MLX5_FLOW_MARK_MAX) {
743                                 rte_flow_error_set(error, ENOTSUP,
744                                                    RTE_FLOW_ERROR_TYPE_ACTION,
745                                                    actions,
746                                                    "mark must be between 0"
747                                                    " and 16777199");
748                                 return -rte_errno;
749                         }
750                         parser->mark = 1;
751                         parser->mark_id = mark->id;
752                 } else if (actions->type == RTE_FLOW_ACTION_TYPE_FLAG) {
753                         if (overlap & MARK)
754                                 goto exit_action_overlap;
755                         overlap |= MARK;
756                         parser->mark = 1;
757                 } else if (actions->type == RTE_FLOW_ACTION_TYPE_COUNT &&
758                            priv->config.flow_counter_en) {
759                         if (overlap & COUNT)
760                                 goto exit_action_overlap;
761                         overlap |= COUNT;
762                         parser->count = 1;
763                 } else {
764                         goto exit_action_not_supported;
765                 }
766         }
767         /* When fate is unknown, drop traffic. */
768         if (!(overlap & FATE))
769                 parser->drop = 1;
770         if (parser->drop && parser->mark)
771                 parser->mark = 0;
772         if (!parser->queues_n && !parser->drop) {
773                 rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE,
774                                    NULL, "no valid action");
775                 return -rte_errno;
776         }
777         return 0;
778 exit_action_not_supported:
779         rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
780                            actions, "action not supported");
781         return -rte_errno;
782 exit_action_overlap:
783         rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
784                            actions, "overlapping actions are not supported");
785         return -rte_errno;
786 }
787
788 /**
789  * Validate items.
790  *
791  * @param[in] items
792  *   Pattern specification (list terminated by the END pattern item).
793  * @param[out] error
794  *   Perform verbose error reporting if not NULL.
795  * @param[in, out] parser
796  *   Internal parser structure.
797  *
798  * @return
799  *   0 on success, a negative errno value otherwise and rte_errno is set.
800  */
801 static int
802 mlx5_flow_convert_items_validate(const struct rte_flow_item items[],
803                                  struct rte_flow_error *error,
804                                  struct mlx5_flow_parse *parser)
805 {
806         const struct mlx5_flow_items *cur_item = mlx5_flow_items;
807         unsigned int i;
808         int ret = 0;
809
810         /* Initialise the offsets to start after verbs attribute. */
811         for (i = 0; i != hash_rxq_init_n; ++i)
812                 parser->queue[i].offset = sizeof(struct ibv_flow_attr);
813         for (; items->type != RTE_FLOW_ITEM_TYPE_END; ++items) {
814                 const struct mlx5_flow_items *token = NULL;
815                 unsigned int n;
816
817                 if (items->type == RTE_FLOW_ITEM_TYPE_VOID)
818                         continue;
819                 for (i = 0;
820                      cur_item->items &&
821                      cur_item->items[i] != RTE_FLOW_ITEM_TYPE_END;
822                      ++i) {
823                         if (cur_item->items[i] == items->type) {
824                                 token = &mlx5_flow_items[items->type];
825                                 break;
826                         }
827                 }
828                 if (!token) {
829                         ret = -ENOTSUP;
830                         goto exit_item_not_supported;
831                 }
832                 cur_item = token;
833                 ret = mlx5_flow_item_validate(items,
834                                               (const uint8_t *)cur_item->mask,
835                                               cur_item->mask_sz);
836                 if (ret)
837                         goto exit_item_not_supported;
838                 if (items->type == RTE_FLOW_ITEM_TYPE_VXLAN) {
839                         if (parser->inner) {
840                                 rte_flow_error_set(error, ENOTSUP,
841                                                    RTE_FLOW_ERROR_TYPE_ITEM,
842                                                    items,
843                                                    "cannot recognize multiple"
844                                                    " VXLAN encapsulations");
845                                 return -rte_errno;
846                         }
847                         parser->inner = IBV_FLOW_SPEC_INNER;
848                 }
849                 if (parser->drop) {
850                         parser->queue[HASH_RXQ_ETH].offset += cur_item->dst_sz;
851                 } else {
852                         for (n = 0; n != hash_rxq_init_n; ++n)
853                                 parser->queue[n].offset += cur_item->dst_sz;
854                 }
855         }
856         if (parser->drop) {
857                 parser->queue[HASH_RXQ_ETH].offset +=
858                         sizeof(struct ibv_flow_spec_action_drop);
859         }
860         if (parser->mark) {
861                 for (i = 0; i != hash_rxq_init_n; ++i)
862                         parser->queue[i].offset +=
863                                 sizeof(struct ibv_flow_spec_action_tag);
864         }
865         if (parser->count) {
866                 unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
867
868                 for (i = 0; i != hash_rxq_init_n; ++i)
869                         parser->queue[i].offset += size;
870         }
871         return 0;
872 exit_item_not_supported:
873         return rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_ITEM,
874                                   items, "item not supported");
875 }
876
877 /**
878  * Allocate memory space to store verbs flow attributes.
879  *
880  * @param[in] size
881  *   Amount of byte to allocate.
882  * @param[out] error
883  *   Perform verbose error reporting if not NULL.
884  *
885  * @return
886  *   A verbs flow attribute on success, NULL otherwise and rte_errno is set.
887  */
888 static struct ibv_flow_attr *
889 mlx5_flow_convert_allocate(unsigned int size, struct rte_flow_error *error)
890 {
891         struct ibv_flow_attr *ibv_attr;
892
893         ibv_attr = rte_calloc(__func__, 1, size, 0);
894         if (!ibv_attr) {
895                 rte_flow_error_set(error, ENOMEM,
896                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
897                                    NULL,
898                                    "cannot allocate verbs spec attributes");
899                 return NULL;
900         }
901         return ibv_attr;
902 }
903
904 /**
905  * Make inner packet matching with an higher priority from the non Inner
906  * matching.
907  *
908  * @param[in, out] parser
909  *   Internal parser structure.
910  * @param attr
911  *   User flow attribute.
912  */
913 static void
914 mlx5_flow_update_priority(struct mlx5_flow_parse *parser,
915                           const struct rte_flow_attr *attr)
916 {
917         unsigned int i;
918
919         if (parser->drop) {
920                 parser->queue[HASH_RXQ_ETH].ibv_attr->priority =
921                         attr->priority +
922                         hash_rxq_init[HASH_RXQ_ETH].flow_priority;
923                 return;
924         }
925         for (i = 0; i != hash_rxq_init_n; ++i) {
926                 if (parser->queue[i].ibv_attr) {
927                         parser->queue[i].ibv_attr->priority =
928                                 attr->priority +
929                                 hash_rxq_init[i].flow_priority -
930                                 (parser->inner ? 1 : 0);
931                 }
932         }
933 }
934
935 /**
936  * Finalise verbs flow attributes.
937  *
938  * @param[in, out] parser
939  *   Internal parser structure.
940  */
941 static void
942 mlx5_flow_convert_finalise(struct mlx5_flow_parse *parser)
943 {
944         const unsigned int ipv4 =
945                 hash_rxq_init[parser->layer].ip_version == MLX5_IPV4;
946         const enum hash_rxq_type hmin = ipv4 ? HASH_RXQ_TCPV4 : HASH_RXQ_TCPV6;
947         const enum hash_rxq_type hmax = ipv4 ? HASH_RXQ_IPV4 : HASH_RXQ_IPV6;
948         const enum hash_rxq_type ohmin = ipv4 ? HASH_RXQ_TCPV6 : HASH_RXQ_TCPV4;
949         const enum hash_rxq_type ohmax = ipv4 ? HASH_RXQ_IPV6 : HASH_RXQ_IPV4;
950         const enum hash_rxq_type ip = ipv4 ? HASH_RXQ_IPV4 : HASH_RXQ_IPV6;
951         unsigned int i;
952
953         /* Remove any other flow not matching the pattern. */
954         if (parser->queues_n == 1 && !parser->rss_conf.rss_hf) {
955                 for (i = 0; i != hash_rxq_init_n; ++i) {
956                         if (i == HASH_RXQ_ETH)
957                                 continue;
958                         rte_free(parser->queue[i].ibv_attr);
959                         parser->queue[i].ibv_attr = NULL;
960                 }
961                 return;
962         }
963         if (parser->layer == HASH_RXQ_ETH) {
964                 goto fill;
965         } else {
966                 /*
967                  * This layer becomes useless as the pattern define under
968                  * layers.
969                  */
970                 rte_free(parser->queue[HASH_RXQ_ETH].ibv_attr);
971                 parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
972         }
973         /* Remove opposite kind of layer e.g. IPv6 if the pattern is IPv4. */
974         for (i = ohmin; i != (ohmax + 1); ++i) {
975                 if (!parser->queue[i].ibv_attr)
976                         continue;
977                 rte_free(parser->queue[i].ibv_attr);
978                 parser->queue[i].ibv_attr = NULL;
979         }
980         /* Remove impossible flow according to the RSS configuration. */
981         if (hash_rxq_init[parser->layer].dpdk_rss_hf &
982             parser->rss_conf.rss_hf) {
983                 /* Remove any other flow. */
984                 for (i = hmin; i != (hmax + 1); ++i) {
985                         if ((i == parser->layer) ||
986                              (!parser->queue[i].ibv_attr))
987                                 continue;
988                         rte_free(parser->queue[i].ibv_attr);
989                         parser->queue[i].ibv_attr = NULL;
990                 }
991         } else  if (!parser->queue[ip].ibv_attr) {
992                 /* no RSS possible with the current configuration. */
993                 parser->queues_n = 1;
994                 return;
995         }
996 fill:
997         /*
998          * Fill missing layers in verbs specifications, or compute the correct
999          * offset to allocate the memory space for the attributes and
1000          * specifications.
1001          */
1002         for (i = 0; i != hash_rxq_init_n - 1; ++i) {
1003                 union {
1004                         struct ibv_flow_spec_ipv4_ext ipv4;
1005                         struct ibv_flow_spec_ipv6 ipv6;
1006                         struct ibv_flow_spec_tcp_udp udp_tcp;
1007                 } specs;
1008                 void *dst;
1009                 uint16_t size;
1010
1011                 if (i == parser->layer)
1012                         continue;
1013                 if (parser->layer == HASH_RXQ_ETH) {
1014                         if (hash_rxq_init[i].ip_version == MLX5_IPV4) {
1015                                 size = sizeof(struct ibv_flow_spec_ipv4_ext);
1016                                 specs.ipv4 = (struct ibv_flow_spec_ipv4_ext){
1017                                         .type = IBV_FLOW_SPEC_IPV4_EXT,
1018                                         .size = size,
1019                                 };
1020                         } else {
1021                                 size = sizeof(struct ibv_flow_spec_ipv6);
1022                                 specs.ipv6 = (struct ibv_flow_spec_ipv6){
1023                                         .type = IBV_FLOW_SPEC_IPV6,
1024                                         .size = size,
1025                                 };
1026                         }
1027                         if (parser->queue[i].ibv_attr) {
1028                                 dst = (void *)((uintptr_t)
1029                                                parser->queue[i].ibv_attr +
1030                                                parser->queue[i].offset);
1031                                 memcpy(dst, &specs, size);
1032                                 ++parser->queue[i].ibv_attr->num_of_specs;
1033                         }
1034                         parser->queue[i].offset += size;
1035                 }
1036                 if ((i == HASH_RXQ_UDPV4) || (i == HASH_RXQ_TCPV4) ||
1037                     (i == HASH_RXQ_UDPV6) || (i == HASH_RXQ_TCPV6)) {
1038                         size = sizeof(struct ibv_flow_spec_tcp_udp);
1039                         specs.udp_tcp = (struct ibv_flow_spec_tcp_udp) {
1040                                 .type = ((i == HASH_RXQ_UDPV4 ||
1041                                           i == HASH_RXQ_UDPV6) ?
1042                                          IBV_FLOW_SPEC_UDP :
1043                                          IBV_FLOW_SPEC_TCP),
1044                                 .size = size,
1045                         };
1046                         if (parser->queue[i].ibv_attr) {
1047                                 dst = (void *)((uintptr_t)
1048                                                parser->queue[i].ibv_attr +
1049                                                parser->queue[i].offset);
1050                                 memcpy(dst, &specs, size);
1051                                 ++parser->queue[i].ibv_attr->num_of_specs;
1052                         }
1053                         parser->queue[i].offset += size;
1054                 }
1055         }
1056 }
1057
1058 /**
1059  * Validate and convert a flow supported by the NIC.
1060  *
1061  * @param dev
1062  *   Pointer to Ethernet device.
1063  * @param[in] attr
1064  *   Flow rule attributes.
1065  * @param[in] pattern
1066  *   Pattern specification (list terminated by the END pattern item).
1067  * @param[in] actions
1068  *   Associated actions (list terminated by the END action).
1069  * @param[out] error
1070  *   Perform verbose error reporting if not NULL.
1071  * @param[in, out] parser
1072  *   Internal parser structure.
1073  *
1074  * @return
1075  *   0 on success, a negative errno value otherwise and rte_errno is set.
1076  */
1077 static int
1078 mlx5_flow_convert(struct rte_eth_dev *dev,
1079                   const struct rte_flow_attr *attr,
1080                   const struct rte_flow_item items[],
1081                   const struct rte_flow_action actions[],
1082                   struct rte_flow_error *error,
1083                   struct mlx5_flow_parse *parser)
1084 {
1085         const struct mlx5_flow_items *cur_item = mlx5_flow_items;
1086         unsigned int i;
1087         int ret;
1088
1089         /* First step. Validate the attributes, items and actions. */
1090         *parser = (struct mlx5_flow_parse){
1091                 .create = parser->create,
1092                 .layer = HASH_RXQ_ETH,
1093                 .mark_id = MLX5_FLOW_MARK_DEFAULT,
1094         };
1095         ret = mlx5_flow_convert_attributes(attr, error);
1096         if (ret)
1097                 return ret;
1098         ret = mlx5_flow_convert_actions(dev, actions, error, parser);
1099         if (ret)
1100                 return ret;
1101         ret = mlx5_flow_convert_items_validate(items, error, parser);
1102         if (ret)
1103                 return ret;
1104         mlx5_flow_convert_finalise(parser);
1105         /*
1106          * Second step.
1107          * Allocate the memory space to store verbs specifications.
1108          */
1109         if (parser->drop) {
1110                 unsigned int offset = parser->queue[HASH_RXQ_ETH].offset;
1111
1112                 parser->queue[HASH_RXQ_ETH].ibv_attr =
1113                         mlx5_flow_convert_allocate(offset, error);
1114                 if (!parser->queue[HASH_RXQ_ETH].ibv_attr)
1115                         goto exit_enomem;
1116                 parser->queue[HASH_RXQ_ETH].offset =
1117                         sizeof(struct ibv_flow_attr);
1118         } else {
1119                 for (i = 0; i != hash_rxq_init_n; ++i) {
1120                         unsigned int offset;
1121
1122                         if (!(parser->rss_conf.rss_hf &
1123                               hash_rxq_init[i].dpdk_rss_hf) &&
1124                             (i != HASH_RXQ_ETH))
1125                                 continue;
1126                         offset = parser->queue[i].offset;
1127                         parser->queue[i].ibv_attr =
1128                                 mlx5_flow_convert_allocate(offset, error);
1129                         if (!parser->queue[i].ibv_attr)
1130                                 goto exit_enomem;
1131                         parser->queue[i].offset = sizeof(struct ibv_flow_attr);
1132                 }
1133         }
1134         /* Third step. Conversion parse, fill the specifications. */
1135         parser->inner = 0;
1136         for (; items->type != RTE_FLOW_ITEM_TYPE_END; ++items) {
1137                 struct mlx5_flow_data data = {
1138                         .parser = parser,
1139                         .error = error,
1140                 };
1141
1142                 if (items->type == RTE_FLOW_ITEM_TYPE_VOID)
1143                         continue;
1144                 cur_item = &mlx5_flow_items[items->type];
1145                 ret = cur_item->convert(items,
1146                                         (cur_item->default_mask ?
1147                                          cur_item->default_mask :
1148                                          cur_item->mask),
1149                                          &data);
1150                 if (ret)
1151                         goto exit_free;
1152         }
1153         if (parser->mark)
1154                 mlx5_flow_create_flag_mark(parser, parser->mark_id);
1155         if (parser->count && parser->create) {
1156                 mlx5_flow_create_count(dev, parser);
1157                 if (!parser->cs)
1158                         goto exit_count_error;
1159         }
1160         /*
1161          * Last step. Complete missing specification to reach the RSS
1162          * configuration.
1163          */
1164         if (!parser->drop)
1165                 mlx5_flow_convert_finalise(parser);
1166         mlx5_flow_update_priority(parser, attr);
1167 exit_free:
1168         /* Only verification is expected, all resources should be released. */
1169         if (!parser->create) {
1170                 for (i = 0; i != hash_rxq_init_n; ++i) {
1171                         if (parser->queue[i].ibv_attr) {
1172                                 rte_free(parser->queue[i].ibv_attr);
1173                                 parser->queue[i].ibv_attr = NULL;
1174                         }
1175                 }
1176         }
1177         return ret;
1178 exit_enomem:
1179         for (i = 0; i != hash_rxq_init_n; ++i) {
1180                 if (parser->queue[i].ibv_attr) {
1181                         rte_free(parser->queue[i].ibv_attr);
1182                         parser->queue[i].ibv_attr = NULL;
1183                 }
1184         }
1185         rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1186                            NULL, "cannot allocate verbs spec attributes");
1187         return -rte_errno;
1188 exit_count_error:
1189         rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1190                            NULL, "cannot create counter");
1191         return -rte_errno;
1192 }
1193
1194 /**
1195  * Copy the specification created into the flow.
1196  *
1197  * @param parser
1198  *   Internal parser structure.
1199  * @param src
1200  *   Create specification.
1201  * @param size
1202  *   Size in bytes of the specification to copy.
1203  */
1204 static void
1205 mlx5_flow_create_copy(struct mlx5_flow_parse *parser, void *src,
1206                       unsigned int size)
1207 {
1208         unsigned int i;
1209         void *dst;
1210
1211         for (i = 0; i != hash_rxq_init_n; ++i) {
1212                 if (!parser->queue[i].ibv_attr)
1213                         continue;
1214                 /* Specification must be the same l3 type or none. */
1215                 if (parser->layer == HASH_RXQ_ETH ||
1216                     (hash_rxq_init[parser->layer].ip_version ==
1217                      hash_rxq_init[i].ip_version) ||
1218                     (hash_rxq_init[i].ip_version == 0)) {
1219                         dst = (void *)((uintptr_t)parser->queue[i].ibv_attr +
1220                                         parser->queue[i].offset);
1221                         memcpy(dst, src, size);
1222                         ++parser->queue[i].ibv_attr->num_of_specs;
1223                         parser->queue[i].offset += size;
1224                 }
1225         }
1226 }
1227
1228 /**
1229  * Convert Ethernet item to Verbs specification.
1230  *
1231  * @param item[in]
1232  *   Item specification.
1233  * @param default_mask[in]
1234  *   Default bit-masks to use when item->mask is not provided.
1235  * @param data[in, out]
1236  *   User structure.
1237  *
1238  * @return
1239  *   0 on success, a negative errno value otherwise and rte_errno is set.
1240  */
1241 static int
1242 mlx5_flow_create_eth(const struct rte_flow_item *item,
1243                      const void *default_mask,
1244                      struct mlx5_flow_data *data)
1245 {
1246         const struct rte_flow_item_eth *spec = item->spec;
1247         const struct rte_flow_item_eth *mask = item->mask;
1248         struct mlx5_flow_parse *parser = data->parser;
1249         const unsigned int eth_size = sizeof(struct ibv_flow_spec_eth);
1250         struct ibv_flow_spec_eth eth = {
1251                 .type = parser->inner | IBV_FLOW_SPEC_ETH,
1252                 .size = eth_size,
1253         };
1254
1255         /* Don't update layer for the inner pattern. */
1256         if (!parser->inner)
1257                 parser->layer = HASH_RXQ_ETH;
1258         if (spec) {
1259                 unsigned int i;
1260
1261                 if (!mask)
1262                         mask = default_mask;
1263                 memcpy(&eth.val.dst_mac, spec->dst.addr_bytes, ETHER_ADDR_LEN);
1264                 memcpy(&eth.val.src_mac, spec->src.addr_bytes, ETHER_ADDR_LEN);
1265                 eth.val.ether_type = spec->type;
1266                 memcpy(&eth.mask.dst_mac, mask->dst.addr_bytes, ETHER_ADDR_LEN);
1267                 memcpy(&eth.mask.src_mac, mask->src.addr_bytes, ETHER_ADDR_LEN);
1268                 eth.mask.ether_type = mask->type;
1269                 /* Remove unwanted bits from values. */
1270                 for (i = 0; i < ETHER_ADDR_LEN; ++i) {
1271                         eth.val.dst_mac[i] &= eth.mask.dst_mac[i];
1272                         eth.val.src_mac[i] &= eth.mask.src_mac[i];
1273                 }
1274                 eth.val.ether_type &= eth.mask.ether_type;
1275         }
1276         mlx5_flow_create_copy(parser, &eth, eth_size);
1277         return 0;
1278 }
1279
1280 /**
1281  * Convert VLAN item to Verbs specification.
1282  *
1283  * @param item[in]
1284  *   Item specification.
1285  * @param default_mask[in]
1286  *   Default bit-masks to use when item->mask is not provided.
1287  * @param data[in, out]
1288  *   User structure.
1289  *
1290  * @return
1291  *   0 on success, a negative errno value otherwise and rte_errno is set.
1292  */
1293 static int
1294 mlx5_flow_create_vlan(const struct rte_flow_item *item,
1295                       const void *default_mask,
1296                       struct mlx5_flow_data *data)
1297 {
1298         const struct rte_flow_item_vlan *spec = item->spec;
1299         const struct rte_flow_item_vlan *mask = item->mask;
1300         struct mlx5_flow_parse *parser = data->parser;
1301         struct ibv_flow_spec_eth *eth;
1302         const unsigned int eth_size = sizeof(struct ibv_flow_spec_eth);
1303
1304         if (spec) {
1305                 unsigned int i;
1306                 if (!mask)
1307                         mask = default_mask;
1308
1309                 for (i = 0; i != hash_rxq_init_n; ++i) {
1310                         if (!parser->queue[i].ibv_attr)
1311                                 continue;
1312
1313                         eth = (void *)((uintptr_t)parser->queue[i].ibv_attr +
1314                                        parser->queue[i].offset - eth_size);
1315                         eth->val.vlan_tag = spec->tci;
1316                         eth->mask.vlan_tag = mask->tci;
1317                         eth->val.vlan_tag &= eth->mask.vlan_tag;
1318                         /*
1319                          * From verbs perspective an empty VLAN is equivalent
1320                          * to a packet without VLAN layer.
1321                          */
1322                         if (!eth->mask.vlan_tag)
1323                                 goto error;
1324                 }
1325                 return 0;
1326         }
1327 error:
1328         return rte_flow_error_set(data->error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
1329                                   item, "VLAN cannot be empty");
1330 }
1331
1332 /**
1333  * Convert IPv4 item to Verbs specification.
1334  *
1335  * @param item[in]
1336  *   Item specification.
1337  * @param default_mask[in]
1338  *   Default bit-masks to use when item->mask is not provided.
1339  * @param data[in, out]
1340  *   User structure.
1341  *
1342  * @return
1343  *   0 on success, a negative errno value otherwise and rte_errno is set.
1344  */
1345 static int
1346 mlx5_flow_create_ipv4(const struct rte_flow_item *item,
1347                       const void *default_mask,
1348                       struct mlx5_flow_data *data)
1349 {
1350         const struct rte_flow_item_ipv4 *spec = item->spec;
1351         const struct rte_flow_item_ipv4 *mask = item->mask;
1352         struct mlx5_flow_parse *parser = data->parser;
1353         unsigned int ipv4_size = sizeof(struct ibv_flow_spec_ipv4_ext);
1354         struct ibv_flow_spec_ipv4_ext ipv4 = {
1355                 .type = parser->inner | IBV_FLOW_SPEC_IPV4_EXT,
1356                 .size = ipv4_size,
1357         };
1358
1359         /* Don't update layer for the inner pattern. */
1360         if (!parser->inner)
1361                 parser->layer = HASH_RXQ_IPV4;
1362         if (spec) {
1363                 if (!mask)
1364                         mask = default_mask;
1365                 ipv4.val = (struct ibv_flow_ipv4_ext_filter){
1366                         .src_ip = spec->hdr.src_addr,
1367                         .dst_ip = spec->hdr.dst_addr,
1368                         .proto = spec->hdr.next_proto_id,
1369                         .tos = spec->hdr.type_of_service,
1370                 };
1371                 ipv4.mask = (struct ibv_flow_ipv4_ext_filter){
1372                         .src_ip = mask->hdr.src_addr,
1373                         .dst_ip = mask->hdr.dst_addr,
1374                         .proto = mask->hdr.next_proto_id,
1375                         .tos = mask->hdr.type_of_service,
1376                 };
1377                 /* Remove unwanted bits from values. */
1378                 ipv4.val.src_ip &= ipv4.mask.src_ip;
1379                 ipv4.val.dst_ip &= ipv4.mask.dst_ip;
1380                 ipv4.val.proto &= ipv4.mask.proto;
1381                 ipv4.val.tos &= ipv4.mask.tos;
1382         }
1383         mlx5_flow_create_copy(parser, &ipv4, ipv4_size);
1384         return 0;
1385 }
1386
1387 /**
1388  * Convert IPv6 item to Verbs specification.
1389  *
1390  * @param item[in]
1391  *   Item specification.
1392  * @param default_mask[in]
1393  *   Default bit-masks to use when item->mask is not provided.
1394  * @param data[in, out]
1395  *   User structure.
1396  *
1397  * @return
1398  *   0 on success, a negative errno value otherwise and rte_errno is set.
1399  */
1400 static int
1401 mlx5_flow_create_ipv6(const struct rte_flow_item *item,
1402                       const void *default_mask,
1403                       struct mlx5_flow_data *data)
1404 {
1405         const struct rte_flow_item_ipv6 *spec = item->spec;
1406         const struct rte_flow_item_ipv6 *mask = item->mask;
1407         struct mlx5_flow_parse *parser = data->parser;
1408         unsigned int ipv6_size = sizeof(struct ibv_flow_spec_ipv6);
1409         struct ibv_flow_spec_ipv6 ipv6 = {
1410                 .type = parser->inner | IBV_FLOW_SPEC_IPV6,
1411                 .size = ipv6_size,
1412         };
1413
1414         /* Don't update layer for the inner pattern. */
1415         if (!parser->inner)
1416                 parser->layer = HASH_RXQ_IPV6;
1417         if (spec) {
1418                 unsigned int i;
1419                 uint32_t vtc_flow_val;
1420                 uint32_t vtc_flow_mask;
1421
1422                 if (!mask)
1423                         mask = default_mask;
1424                 memcpy(&ipv6.val.src_ip, spec->hdr.src_addr,
1425                        RTE_DIM(ipv6.val.src_ip));
1426                 memcpy(&ipv6.val.dst_ip, spec->hdr.dst_addr,
1427                        RTE_DIM(ipv6.val.dst_ip));
1428                 memcpy(&ipv6.mask.src_ip, mask->hdr.src_addr,
1429                        RTE_DIM(ipv6.mask.src_ip));
1430                 memcpy(&ipv6.mask.dst_ip, mask->hdr.dst_addr,
1431                        RTE_DIM(ipv6.mask.dst_ip));
1432                 vtc_flow_val = rte_be_to_cpu_32(spec->hdr.vtc_flow);
1433                 vtc_flow_mask = rte_be_to_cpu_32(mask->hdr.vtc_flow);
1434                 ipv6.val.flow_label =
1435                         rte_cpu_to_be_32((vtc_flow_val & IPV6_HDR_FL_MASK) >>
1436                                          IPV6_HDR_FL_SHIFT);
1437                 ipv6.val.traffic_class = (vtc_flow_val & IPV6_HDR_TC_MASK) >>
1438                                          IPV6_HDR_TC_SHIFT;
1439                 ipv6.val.next_hdr = spec->hdr.proto;
1440                 ipv6.val.hop_limit = spec->hdr.hop_limits;
1441                 ipv6.mask.flow_label =
1442                         rte_cpu_to_be_32((vtc_flow_mask & IPV6_HDR_FL_MASK) >>
1443                                          IPV6_HDR_FL_SHIFT);
1444                 ipv6.mask.traffic_class = (vtc_flow_mask & IPV6_HDR_TC_MASK) >>
1445                                           IPV6_HDR_TC_SHIFT;
1446                 ipv6.mask.next_hdr = mask->hdr.proto;
1447                 ipv6.mask.hop_limit = mask->hdr.hop_limits;
1448                 /* Remove unwanted bits from values. */
1449                 for (i = 0; i < RTE_DIM(ipv6.val.src_ip); ++i) {
1450                         ipv6.val.src_ip[i] &= ipv6.mask.src_ip[i];
1451                         ipv6.val.dst_ip[i] &= ipv6.mask.dst_ip[i];
1452                 }
1453                 ipv6.val.flow_label &= ipv6.mask.flow_label;
1454                 ipv6.val.traffic_class &= ipv6.mask.traffic_class;
1455                 ipv6.val.next_hdr &= ipv6.mask.next_hdr;
1456                 ipv6.val.hop_limit &= ipv6.mask.hop_limit;
1457         }
1458         mlx5_flow_create_copy(parser, &ipv6, ipv6_size);
1459         return 0;
1460 }
1461
1462 /**
1463  * Convert UDP item to Verbs specification.
1464  *
1465  * @param item[in]
1466  *   Item specification.
1467  * @param default_mask[in]
1468  *   Default bit-masks to use when item->mask is not provided.
1469  * @param data[in, out]
1470  *   User structure.
1471  *
1472  * @return
1473  *   0 on success, a negative errno value otherwise and rte_errno is set.
1474  */
1475 static int
1476 mlx5_flow_create_udp(const struct rte_flow_item *item,
1477                      const void *default_mask,
1478                      struct mlx5_flow_data *data)
1479 {
1480         const struct rte_flow_item_udp *spec = item->spec;
1481         const struct rte_flow_item_udp *mask = item->mask;
1482         struct mlx5_flow_parse *parser = data->parser;
1483         unsigned int udp_size = sizeof(struct ibv_flow_spec_tcp_udp);
1484         struct ibv_flow_spec_tcp_udp udp = {
1485                 .type = parser->inner | IBV_FLOW_SPEC_UDP,
1486                 .size = udp_size,
1487         };
1488
1489         /* Don't update layer for the inner pattern. */
1490         if (!parser->inner) {
1491                 if (parser->layer == HASH_RXQ_IPV4)
1492                         parser->layer = HASH_RXQ_UDPV4;
1493                 else
1494                         parser->layer = HASH_RXQ_UDPV6;
1495         }
1496         if (spec) {
1497                 if (!mask)
1498                         mask = default_mask;
1499                 udp.val.dst_port = spec->hdr.dst_port;
1500                 udp.val.src_port = spec->hdr.src_port;
1501                 udp.mask.dst_port = mask->hdr.dst_port;
1502                 udp.mask.src_port = mask->hdr.src_port;
1503                 /* Remove unwanted bits from values. */
1504                 udp.val.src_port &= udp.mask.src_port;
1505                 udp.val.dst_port &= udp.mask.dst_port;
1506         }
1507         mlx5_flow_create_copy(parser, &udp, udp_size);
1508         return 0;
1509 }
1510
1511 /**
1512  * Convert TCP item to Verbs specification.
1513  *
1514  * @param item[in]
1515  *   Item specification.
1516  * @param default_mask[in]
1517  *   Default bit-masks to use when item->mask is not provided.
1518  * @param data[in, out]
1519  *   User structure.
1520  *
1521  * @return
1522  *   0 on success, a negative errno value otherwise and rte_errno is set.
1523  */
1524 static int
1525 mlx5_flow_create_tcp(const struct rte_flow_item *item,
1526                      const void *default_mask,
1527                      struct mlx5_flow_data *data)
1528 {
1529         const struct rte_flow_item_tcp *spec = item->spec;
1530         const struct rte_flow_item_tcp *mask = item->mask;
1531         struct mlx5_flow_parse *parser = data->parser;
1532         unsigned int tcp_size = sizeof(struct ibv_flow_spec_tcp_udp);
1533         struct ibv_flow_spec_tcp_udp tcp = {
1534                 .type = parser->inner | IBV_FLOW_SPEC_TCP,
1535                 .size = tcp_size,
1536         };
1537
1538         /* Don't update layer for the inner pattern. */
1539         if (!parser->inner) {
1540                 if (parser->layer == HASH_RXQ_IPV4)
1541                         parser->layer = HASH_RXQ_TCPV4;
1542                 else
1543                         parser->layer = HASH_RXQ_TCPV6;
1544         }
1545         if (spec) {
1546                 if (!mask)
1547                         mask = default_mask;
1548                 tcp.val.dst_port = spec->hdr.dst_port;
1549                 tcp.val.src_port = spec->hdr.src_port;
1550                 tcp.mask.dst_port = mask->hdr.dst_port;
1551                 tcp.mask.src_port = mask->hdr.src_port;
1552                 /* Remove unwanted bits from values. */
1553                 tcp.val.src_port &= tcp.mask.src_port;
1554                 tcp.val.dst_port &= tcp.mask.dst_port;
1555         }
1556         mlx5_flow_create_copy(parser, &tcp, tcp_size);
1557         return 0;
1558 }
1559
1560 /**
1561  * Convert VXLAN item to Verbs specification.
1562  *
1563  * @param item[in]
1564  *   Item specification.
1565  * @param default_mask[in]
1566  *   Default bit-masks to use when item->mask is not provided.
1567  * @param data[in, out]
1568  *   User structure.
1569  *
1570  * @return
1571  *   0 on success, a negative errno value otherwise and rte_errno is set.
1572  */
1573 static int
1574 mlx5_flow_create_vxlan(const struct rte_flow_item *item,
1575                        const void *default_mask,
1576                        struct mlx5_flow_data *data)
1577 {
1578         const struct rte_flow_item_vxlan *spec = item->spec;
1579         const struct rte_flow_item_vxlan *mask = item->mask;
1580         struct mlx5_flow_parse *parser = data->parser;
1581         unsigned int size = sizeof(struct ibv_flow_spec_tunnel);
1582         struct ibv_flow_spec_tunnel vxlan = {
1583                 .type = parser->inner | IBV_FLOW_SPEC_VXLAN_TUNNEL,
1584                 .size = size,
1585         };
1586         union vni {
1587                 uint32_t vlan_id;
1588                 uint8_t vni[4];
1589         } id;
1590
1591         id.vni[0] = 0;
1592         parser->inner = IBV_FLOW_SPEC_INNER;
1593         if (spec) {
1594                 if (!mask)
1595                         mask = default_mask;
1596                 memcpy(&id.vni[1], spec->vni, 3);
1597                 vxlan.val.tunnel_id = id.vlan_id;
1598                 memcpy(&id.vni[1], mask->vni, 3);
1599                 vxlan.mask.tunnel_id = id.vlan_id;
1600                 /* Remove unwanted bits from values. */
1601                 vxlan.val.tunnel_id &= vxlan.mask.tunnel_id;
1602         }
1603         /*
1604          * Tunnel id 0 is equivalent as not adding a VXLAN layer, if only this
1605          * layer is defined in the Verbs specification it is interpreted as
1606          * wildcard and all packets will match this rule, if it follows a full
1607          * stack layer (ex: eth / ipv4 / udp), all packets matching the layers
1608          * before will also match this rule.
1609          * To avoid such situation, VNI 0 is currently refused.
1610          */
1611         if (!vxlan.val.tunnel_id)
1612                 return rte_flow_error_set(data->error, EINVAL,
1613                                           RTE_FLOW_ERROR_TYPE_ITEM,
1614                                           item,
1615                                           "VxLAN vni cannot be 0");
1616         mlx5_flow_create_copy(parser, &vxlan, size);
1617         return 0;
1618 }
1619
1620 /**
1621  * Convert mark/flag action to Verbs specification.
1622  *
1623  * @param parser
1624  *   Internal parser structure.
1625  * @param mark_id
1626  *   Mark identifier.
1627  *
1628  * @return
1629  *   0 on success, a negative errno value otherwise and rte_errno is set.
1630  */
1631 static int
1632 mlx5_flow_create_flag_mark(struct mlx5_flow_parse *parser, uint32_t mark_id)
1633 {
1634         unsigned int size = sizeof(struct ibv_flow_spec_action_tag);
1635         struct ibv_flow_spec_action_tag tag = {
1636                 .type = IBV_FLOW_SPEC_ACTION_TAG,
1637                 .size = size,
1638                 .tag_id = mlx5_flow_mark_set(mark_id),
1639         };
1640
1641         assert(parser->mark);
1642         mlx5_flow_create_copy(parser, &tag, size);
1643         return 0;
1644 }
1645
1646 /**
1647  * Convert count action to Verbs specification.
1648  *
1649  * @param dev
1650  *   Pointer to Ethernet device.
1651  * @param parser
1652  *   Pointer to MLX5 flow parser structure.
1653  *
1654  * @return
1655  *   0 on success, a negative errno value otherwise and rte_errno is set.
1656  */
1657 static int
1658 mlx5_flow_create_count(struct rte_eth_dev *dev __rte_unused,
1659                        struct mlx5_flow_parse *parser __rte_unused)
1660 {
1661 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
1662         struct priv *priv = dev->data->dev_private;
1663         unsigned int size = sizeof(struct ibv_flow_spec_counter_action);
1664         struct ibv_counter_set_init_attr init_attr = {0};
1665         struct ibv_flow_spec_counter_action counter = {
1666                 .type = IBV_FLOW_SPEC_ACTION_COUNT,
1667                 .size = size,
1668                 .counter_set_handle = 0,
1669         };
1670
1671         init_attr.counter_set_id = 0;
1672         parser->cs = mlx5_glue->create_counter_set(priv->ctx, &init_attr);
1673         if (!parser->cs) {
1674                 rte_errno = EINVAL;
1675                 return -rte_errno;
1676         }
1677         counter.counter_set_handle = parser->cs->handle;
1678         mlx5_flow_create_copy(parser, &counter, size);
1679 #endif
1680         return 0;
1681 }
1682
1683 /**
1684  * Complete flow rule creation with a drop queue.
1685  *
1686  * @param dev
1687  *   Pointer to Ethernet device.
1688  * @param parser
1689  *   Internal parser structure.
1690  * @param flow
1691  *   Pointer to the rte_flow.
1692  * @param[out] error
1693  *   Perform verbose error reporting if not NULL.
1694  *
1695  * @return
1696  *   0 on success, a negative errno value otherwise and rte_errno is set.
1697  */
1698 static int
1699 mlx5_flow_create_action_queue_drop(struct rte_eth_dev *dev,
1700                                    struct mlx5_flow_parse *parser,
1701                                    struct rte_flow *flow,
1702                                    struct rte_flow_error *error)
1703 {
1704         struct priv *priv = dev->data->dev_private;
1705         struct ibv_flow_spec_action_drop *drop;
1706         unsigned int size = sizeof(struct ibv_flow_spec_action_drop);
1707
1708         assert(priv->pd);
1709         assert(priv->ctx);
1710         flow->drop = 1;
1711         drop = (void *)((uintptr_t)parser->queue[HASH_RXQ_ETH].ibv_attr +
1712                         parser->queue[HASH_RXQ_ETH].offset);
1713         *drop = (struct ibv_flow_spec_action_drop){
1714                         .type = IBV_FLOW_SPEC_ACTION_DROP,
1715                         .size = size,
1716         };
1717         ++parser->queue[HASH_RXQ_ETH].ibv_attr->num_of_specs;
1718         parser->queue[HASH_RXQ_ETH].offset += size;
1719         flow->frxq[HASH_RXQ_ETH].ibv_attr =
1720                 parser->queue[HASH_RXQ_ETH].ibv_attr;
1721         if (parser->count)
1722                 flow->cs = parser->cs;
1723         if (!priv->dev->data->dev_started)
1724                 return 0;
1725         parser->queue[HASH_RXQ_ETH].ibv_attr = NULL;
1726         flow->frxq[HASH_RXQ_ETH].ibv_flow =
1727                 mlx5_glue->create_flow(priv->flow_drop_queue->qp,
1728                                        flow->frxq[HASH_RXQ_ETH].ibv_attr);
1729         if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
1730                 rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
1731                                    NULL, "flow rule creation failure");
1732                 goto error;
1733         }
1734         return 0;
1735 error:
1736         assert(flow);
1737         if (flow->frxq[HASH_RXQ_ETH].ibv_flow) {
1738                 claim_zero(mlx5_glue->destroy_flow
1739                            (flow->frxq[HASH_RXQ_ETH].ibv_flow));
1740                 flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
1741         }
1742         if (flow->frxq[HASH_RXQ_ETH].ibv_attr) {
1743                 rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
1744                 flow->frxq[HASH_RXQ_ETH].ibv_attr = NULL;
1745         }
1746         if (flow->cs) {
1747                 claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
1748                 flow->cs = NULL;
1749                 parser->cs = NULL;
1750         }
1751         return -rte_errno;
1752 }
1753
1754 /**
1755  * Create hash Rx queues when RSS is enabled.
1756  *
1757  * @param dev
1758  *   Pointer to Ethernet device.
1759  * @param parser
1760  *   Internal parser structure.
1761  * @param flow
1762  *   Pointer to the rte_flow.
1763  * @param[out] error
1764  *   Perform verbose error reporting if not NULL.
1765  *
1766  * @return
1767  *   0 on success, a negative errno value otherwise and rte_errno is set.
1768  */
1769 static int
1770 mlx5_flow_create_action_queue_rss(struct rte_eth_dev *dev,
1771                                   struct mlx5_flow_parse *parser,
1772                                   struct rte_flow *flow,
1773                                   struct rte_flow_error *error)
1774 {
1775         struct priv *priv = dev->data->dev_private;
1776         unsigned int i;
1777
1778         for (i = 0; i != hash_rxq_init_n; ++i) {
1779                 uint64_t hash_fields;
1780
1781                 if (!parser->queue[i].ibv_attr)
1782                         continue;
1783                 flow->frxq[i].ibv_attr = parser->queue[i].ibv_attr;
1784                 parser->queue[i].ibv_attr = NULL;
1785                 hash_fields = hash_rxq_init[i].hash_fields;
1786                 if (!priv->dev->data->dev_started)
1787                         continue;
1788                 flow->frxq[i].hrxq =
1789                         mlx5_hrxq_get(dev,
1790                                       parser->rss_conf.rss_key,
1791                                       parser->rss_conf.rss_key_len,
1792                                       hash_fields,
1793                                       parser->queues,
1794                                       parser->queues_n);
1795                 if (flow->frxq[i].hrxq)
1796                         continue;
1797                 flow->frxq[i].hrxq =
1798                         mlx5_hrxq_new(dev,
1799                                       parser->rss_conf.rss_key,
1800                                       parser->rss_conf.rss_key_len,
1801                                       hash_fields,
1802                                       parser->queues,
1803                                       parser->queues_n);
1804                 if (!flow->frxq[i].hrxq) {
1805                         return rte_flow_error_set(error, ENOMEM,
1806                                                   RTE_FLOW_ERROR_TYPE_HANDLE,
1807                                                   NULL,
1808                                                   "cannot create hash rxq");
1809                 }
1810         }
1811         return 0;
1812 }
1813
1814 /**
1815  * Complete flow rule creation.
1816  *
1817  * @param dev
1818  *   Pointer to Ethernet device.
1819  * @param parser
1820  *   Internal parser structure.
1821  * @param flow
1822  *   Pointer to the rte_flow.
1823  * @param[out] error
1824  *   Perform verbose error reporting if not NULL.
1825  *
1826  * @return
1827  *   0 on success, a negative errno value otherwise and rte_errno is set.
1828  */
1829 static int
1830 mlx5_flow_create_action_queue(struct rte_eth_dev *dev,
1831                               struct mlx5_flow_parse *parser,
1832                               struct rte_flow *flow,
1833                               struct rte_flow_error *error)
1834 {
1835         struct priv *priv = dev->data->dev_private;
1836         int ret;
1837         unsigned int i;
1838         unsigned int flows_n = 0;
1839
1840         assert(priv->pd);
1841         assert(priv->ctx);
1842         assert(!parser->drop);
1843         ret = mlx5_flow_create_action_queue_rss(dev, parser, flow, error);
1844         if (ret)
1845                 goto error;
1846         if (parser->count)
1847                 flow->cs = parser->cs;
1848         if (!priv->dev->data->dev_started)
1849                 return 0;
1850         for (i = 0; i != hash_rxq_init_n; ++i) {
1851                 if (!flow->frxq[i].hrxq)
1852                         continue;
1853                 flow->frxq[i].ibv_flow =
1854                         mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
1855                                                flow->frxq[i].ibv_attr);
1856                 if (!flow->frxq[i].ibv_flow) {
1857                         rte_flow_error_set(error, ENOMEM,
1858                                            RTE_FLOW_ERROR_TYPE_HANDLE,
1859                                            NULL, "flow rule creation failure");
1860                         goto error;
1861                 }
1862                 ++flows_n;
1863                 DRV_LOG(DEBUG, "port %u %p type %d QP %p ibv_flow %p",
1864                         dev->data->port_id,
1865                         (void *)flow, i,
1866                         (void *)flow->frxq[i].hrxq,
1867                         (void *)flow->frxq[i].ibv_flow);
1868         }
1869         if (!flows_n) {
1870                 rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE,
1871                                    NULL, "internal error in flow creation");
1872                 goto error;
1873         }
1874         for (i = 0; i != parser->queues_n; ++i) {
1875                 struct mlx5_rxq_data *q =
1876                         (*priv->rxqs)[parser->queues[i]];
1877
1878                 q->mark |= parser->mark;
1879         }
1880         return 0;
1881 error:
1882         ret = rte_errno; /* Save rte_errno before cleanup. */
1883         assert(flow);
1884         for (i = 0; i != hash_rxq_init_n; ++i) {
1885                 if (flow->frxq[i].ibv_flow) {
1886                         struct ibv_flow *ibv_flow = flow->frxq[i].ibv_flow;
1887
1888                         claim_zero(mlx5_glue->destroy_flow(ibv_flow));
1889                 }
1890                 if (flow->frxq[i].hrxq)
1891                         mlx5_hrxq_release(dev, flow->frxq[i].hrxq);
1892                 if (flow->frxq[i].ibv_attr)
1893                         rte_free(flow->frxq[i].ibv_attr);
1894         }
1895         if (flow->cs) {
1896                 claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
1897                 flow->cs = NULL;
1898                 parser->cs = NULL;
1899         }
1900         rte_errno = ret; /* Restore rte_errno. */
1901         return -rte_errno;
1902 }
1903
1904 /**
1905  * Convert a flow.
1906  *
1907  * @param dev
1908  *   Pointer to Ethernet device.
1909  * @param list
1910  *   Pointer to a TAILQ flow list.
1911  * @param[in] attr
1912  *   Flow rule attributes.
1913  * @param[in] pattern
1914  *   Pattern specification (list terminated by the END pattern item).
1915  * @param[in] actions
1916  *   Associated actions (list terminated by the END action).
1917  * @param[out] error
1918  *   Perform verbose error reporting if not NULL.
1919  *
1920  * @return
1921  *   A flow on success, NULL otherwise and rte_errno is set.
1922  */
1923 static struct rte_flow *
1924 mlx5_flow_list_create(struct rte_eth_dev *dev,
1925                       struct mlx5_flows *list,
1926                       const struct rte_flow_attr *attr,
1927                       const struct rte_flow_item items[],
1928                       const struct rte_flow_action actions[],
1929                       struct rte_flow_error *error)
1930 {
1931         struct mlx5_flow_parse parser = { .create = 1, };
1932         struct rte_flow *flow = NULL;
1933         unsigned int i;
1934         int ret;
1935
1936         ret = mlx5_flow_convert(dev, attr, items, actions, error, &parser);
1937         if (ret)
1938                 goto exit;
1939         flow = rte_calloc(__func__, 1,
1940                           sizeof(*flow) + parser.queues_n * sizeof(uint16_t),
1941                           0);
1942         if (!flow) {
1943                 rte_flow_error_set(error, ENOMEM,
1944                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1945                                    NULL,
1946                                    "cannot allocate flow memory");
1947                 return NULL;
1948         }
1949         /* Copy queues configuration. */
1950         flow->queues = (uint16_t (*)[])(flow + 1);
1951         memcpy(flow->queues, parser.queues, parser.queues_n * sizeof(uint16_t));
1952         flow->queues_n = parser.queues_n;
1953         flow->mark = parser.mark;
1954         /* Copy RSS configuration. */
1955         flow->rss_conf = parser.rss_conf;
1956         flow->rss_conf.rss_key = flow->rss_key;
1957         memcpy(flow->rss_key, parser.rss_key, parser.rss_conf.rss_key_len);
1958         /* finalise the flow. */
1959         if (parser.drop)
1960                 ret = mlx5_flow_create_action_queue_drop(dev, &parser, flow,
1961                                                          error);
1962         else
1963                 ret = mlx5_flow_create_action_queue(dev, &parser, flow, error);
1964         if (ret)
1965                 goto exit;
1966         TAILQ_INSERT_TAIL(list, flow, next);
1967         DRV_LOG(DEBUG, "port %u flow created %p", dev->data->port_id,
1968                 (void *)flow);
1969         return flow;
1970 exit:
1971         DRV_LOG(ERR, "port %u flow creation error: %s", dev->data->port_id,
1972                 error->message);
1973         for (i = 0; i != hash_rxq_init_n; ++i) {
1974                 if (parser.queue[i].ibv_attr)
1975                         rte_free(parser.queue[i].ibv_attr);
1976         }
1977         rte_free(flow);
1978         return NULL;
1979 }
1980
1981 /**
1982  * Validate a flow supported by the NIC.
1983  *
1984  * @see rte_flow_validate()
1985  * @see rte_flow_ops
1986  */
1987 int
1988 mlx5_flow_validate(struct rte_eth_dev *dev,
1989                    const struct rte_flow_attr *attr,
1990                    const struct rte_flow_item items[],
1991                    const struct rte_flow_action actions[],
1992                    struct rte_flow_error *error)
1993 {
1994         struct mlx5_flow_parse parser = { .create = 0, };
1995
1996         return mlx5_flow_convert(dev, attr, items, actions, error, &parser);
1997 }
1998
1999 /**
2000  * Create a flow.
2001  *
2002  * @see rte_flow_create()
2003  * @see rte_flow_ops
2004  */
2005 struct rte_flow *
2006 mlx5_flow_create(struct rte_eth_dev *dev,
2007                  const struct rte_flow_attr *attr,
2008                  const struct rte_flow_item items[],
2009                  const struct rte_flow_action actions[],
2010                  struct rte_flow_error *error)
2011 {
2012         struct priv *priv = dev->data->dev_private;
2013
2014         return mlx5_flow_list_create(dev, &priv->flows, attr, items, actions,
2015                                      error);
2016 }
2017
2018 /**
2019  * Destroy a flow in a list.
2020  *
2021  * @param dev
2022  *   Pointer to Ethernet device.
2023  * @param list
2024  *   Pointer to a TAILQ flow list.
2025  * @param[in] flow
2026  *   Flow to destroy.
2027  */
2028 static void
2029 mlx5_flow_list_destroy(struct rte_eth_dev *dev, struct mlx5_flows *list,
2030                        struct rte_flow *flow)
2031 {
2032         struct priv *priv = dev->data->dev_private;
2033         unsigned int i;
2034
2035         if (flow->drop || !flow->mark)
2036                 goto free;
2037         for (i = 0; i != flow->queues_n; ++i) {
2038                 struct rte_flow *tmp;
2039                 int mark = 0;
2040
2041                 /*
2042                  * To remove the mark from the queue, the queue must not be
2043                  * present in any other marked flow (RSS or not).
2044                  */
2045                 TAILQ_FOREACH(tmp, list, next) {
2046                         unsigned int j;
2047                         uint16_t *tqs = NULL;
2048                         uint16_t tq_n = 0;
2049
2050                         if (!tmp->mark)
2051                                 continue;
2052                         for (j = 0; j != hash_rxq_init_n; ++j) {
2053                                 if (!tmp->frxq[j].hrxq)
2054                                         continue;
2055                                 tqs = tmp->frxq[j].hrxq->ind_table->queues;
2056                                 tq_n = tmp->frxq[j].hrxq->ind_table->queues_n;
2057                         }
2058                         if (!tq_n)
2059                                 continue;
2060                         for (j = 0; (j != tq_n) && !mark; j++)
2061                                 if (tqs[j] == (*flow->queues)[i])
2062                                         mark = 1;
2063                 }
2064                 (*priv->rxqs)[(*flow->queues)[i]]->mark = mark;
2065         }
2066 free:
2067         if (flow->drop) {
2068                 if (flow->frxq[HASH_RXQ_ETH].ibv_flow)
2069                         claim_zero(mlx5_glue->destroy_flow
2070                                    (flow->frxq[HASH_RXQ_ETH].ibv_flow));
2071                 rte_free(flow->frxq[HASH_RXQ_ETH].ibv_attr);
2072         } else {
2073                 for (i = 0; i != hash_rxq_init_n; ++i) {
2074                         struct mlx5_flow *frxq = &flow->frxq[i];
2075
2076                         if (frxq->ibv_flow)
2077                                 claim_zero(mlx5_glue->destroy_flow
2078                                            (frxq->ibv_flow));
2079                         if (frxq->hrxq)
2080                                 mlx5_hrxq_release(dev, frxq->hrxq);
2081                         if (frxq->ibv_attr)
2082                                 rte_free(frxq->ibv_attr);
2083                 }
2084         }
2085         if (flow->cs) {
2086                 claim_zero(mlx5_glue->destroy_counter_set(flow->cs));
2087                 flow->cs = NULL;
2088         }
2089         TAILQ_REMOVE(list, flow, next);
2090         DRV_LOG(DEBUG, "port %u flow destroyed %p", dev->data->port_id,
2091                 (void *)flow);
2092         rte_free(flow);
2093 }
2094
2095 /**
2096  * Destroy all flows.
2097  *
2098  * @param dev
2099  *   Pointer to Ethernet device.
2100  * @param list
2101  *   Pointer to a TAILQ flow list.
2102  */
2103 void
2104 mlx5_flow_list_flush(struct rte_eth_dev *dev, struct mlx5_flows *list)
2105 {
2106         while (!TAILQ_EMPTY(list)) {
2107                 struct rte_flow *flow;
2108
2109                 flow = TAILQ_FIRST(list);
2110                 mlx5_flow_list_destroy(dev, list, flow);
2111         }
2112 }
2113
2114 /**
2115  * Create drop queue.
2116  *
2117  * @param dev
2118  *   Pointer to Ethernet device.
2119  *
2120  * @return
2121  *   0 on success, a negative errno value otherwise and rte_errno is set.
2122  */
2123 int
2124 mlx5_flow_create_drop_queue(struct rte_eth_dev *dev)
2125 {
2126         struct priv *priv = dev->data->dev_private;
2127         struct mlx5_hrxq_drop *fdq = NULL;
2128
2129         assert(priv->pd);
2130         assert(priv->ctx);
2131         fdq = rte_calloc(__func__, 1, sizeof(*fdq), 0);
2132         if (!fdq) {
2133                 DRV_LOG(WARNING,
2134                         "port %u cannot allocate memory for drop queue",
2135                         dev->data->port_id);
2136                 rte_errno = ENOMEM;
2137                 return -rte_errno;
2138         }
2139         fdq->cq = mlx5_glue->create_cq(priv->ctx, 1, NULL, NULL, 0);
2140         if (!fdq->cq) {
2141                 DRV_LOG(WARNING, "port %u cannot allocate CQ for drop queue",
2142                         dev->data->port_id);
2143                 rte_errno = errno;
2144                 goto error;
2145         }
2146         fdq->wq = mlx5_glue->create_wq
2147                 (priv->ctx,
2148                  &(struct ibv_wq_init_attr){
2149                         .wq_type = IBV_WQT_RQ,
2150                         .max_wr = 1,
2151                         .max_sge = 1,
2152                         .pd = priv->pd,
2153                         .cq = fdq->cq,
2154                  });
2155         if (!fdq->wq) {
2156                 DRV_LOG(WARNING, "port %u cannot allocate WQ for drop queue",
2157                         dev->data->port_id);
2158                 rte_errno = errno;
2159                 goto error;
2160         }
2161         fdq->ind_table = mlx5_glue->create_rwq_ind_table
2162                 (priv->ctx,
2163                  &(struct ibv_rwq_ind_table_init_attr){
2164                         .log_ind_tbl_size = 0,
2165                         .ind_tbl = &fdq->wq,
2166                         .comp_mask = 0,
2167                  });
2168         if (!fdq->ind_table) {
2169                 DRV_LOG(WARNING,
2170                         "port %u cannot allocate indirection table for drop"
2171                         " queue",
2172                         dev->data->port_id);
2173                 rte_errno = errno;
2174                 goto error;
2175         }
2176         fdq->qp = mlx5_glue->create_qp_ex
2177                 (priv->ctx,
2178                  &(struct ibv_qp_init_attr_ex){
2179                         .qp_type = IBV_QPT_RAW_PACKET,
2180                         .comp_mask =
2181                                 IBV_QP_INIT_ATTR_PD |
2182                                 IBV_QP_INIT_ATTR_IND_TABLE |
2183                                 IBV_QP_INIT_ATTR_RX_HASH,
2184                         .rx_hash_conf = (struct ibv_rx_hash_conf){
2185                                 .rx_hash_function =
2186                                         IBV_RX_HASH_FUNC_TOEPLITZ,
2187                                 .rx_hash_key_len = rss_hash_default_key_len,
2188                                 .rx_hash_key = rss_hash_default_key,
2189                                 .rx_hash_fields_mask = 0,
2190                                 },
2191                         .rwq_ind_tbl = fdq->ind_table,
2192                         .pd = priv->pd
2193                  });
2194         if (!fdq->qp) {
2195                 DRV_LOG(WARNING, "port %u cannot allocate QP for drop queue",
2196                         dev->data->port_id);
2197                 rte_errno = errno;
2198                 goto error;
2199         }
2200         priv->flow_drop_queue = fdq;
2201         return 0;
2202 error:
2203         if (fdq->qp)
2204                 claim_zero(mlx5_glue->destroy_qp(fdq->qp));
2205         if (fdq->ind_table)
2206                 claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
2207         if (fdq->wq)
2208                 claim_zero(mlx5_glue->destroy_wq(fdq->wq));
2209         if (fdq->cq)
2210                 claim_zero(mlx5_glue->destroy_cq(fdq->cq));
2211         if (fdq)
2212                 rte_free(fdq);
2213         priv->flow_drop_queue = NULL;
2214         return -rte_errno;
2215 }
2216
2217 /**
2218  * Delete drop queue.
2219  *
2220  * @param dev
2221  *   Pointer to Ethernet device.
2222  */
2223 void
2224 mlx5_flow_delete_drop_queue(struct rte_eth_dev *dev)
2225 {
2226         struct priv *priv = dev->data->dev_private;
2227         struct mlx5_hrxq_drop *fdq = priv->flow_drop_queue;
2228
2229         if (!fdq)
2230                 return;
2231         if (fdq->qp)
2232                 claim_zero(mlx5_glue->destroy_qp(fdq->qp));
2233         if (fdq->ind_table)
2234                 claim_zero(mlx5_glue->destroy_rwq_ind_table(fdq->ind_table));
2235         if (fdq->wq)
2236                 claim_zero(mlx5_glue->destroy_wq(fdq->wq));
2237         if (fdq->cq)
2238                 claim_zero(mlx5_glue->destroy_cq(fdq->cq));
2239         rte_free(fdq);
2240         priv->flow_drop_queue = NULL;
2241 }
2242
2243 /**
2244  * Remove all flows.
2245  *
2246  * @param dev
2247  *   Pointer to Ethernet device.
2248  * @param list
2249  *   Pointer to a TAILQ flow list.
2250  */
2251 void
2252 mlx5_flow_stop(struct rte_eth_dev *dev, struct mlx5_flows *list)
2253 {
2254         struct priv *priv = dev->data->dev_private;
2255         struct rte_flow *flow;
2256
2257         TAILQ_FOREACH_REVERSE(flow, list, mlx5_flows, next) {
2258                 unsigned int i;
2259                 struct mlx5_ind_table_ibv *ind_tbl = NULL;
2260
2261                 if (flow->drop) {
2262                         if (!flow->frxq[HASH_RXQ_ETH].ibv_flow)
2263                                 continue;
2264                         claim_zero(mlx5_glue->destroy_flow
2265                                    (flow->frxq[HASH_RXQ_ETH].ibv_flow));
2266                         flow->frxq[HASH_RXQ_ETH].ibv_flow = NULL;
2267                         DRV_LOG(DEBUG, "port %u flow %p removed",
2268                                 dev->data->port_id, (void *)flow);
2269                         /* Next flow. */
2270                         continue;
2271                 }
2272                 /* Verify the flow has not already been cleaned. */
2273                 for (i = 0; i != hash_rxq_init_n; ++i) {
2274                         if (!flow->frxq[i].ibv_flow)
2275                                 continue;
2276                         /*
2277                          * Indirection table may be necessary to remove the
2278                          * flags in the Rx queues.
2279                          * This helps to speed-up the process by avoiding
2280                          * another loop.
2281                          */
2282                         ind_tbl = flow->frxq[i].hrxq->ind_table;
2283                         break;
2284                 }
2285                 if (i == hash_rxq_init_n)
2286                         return;
2287                 if (flow->mark) {
2288                         assert(ind_tbl);
2289                         for (i = 0; i != ind_tbl->queues_n; ++i)
2290                                 (*priv->rxqs)[ind_tbl->queues[i]]->mark = 0;
2291                 }
2292                 for (i = 0; i != hash_rxq_init_n; ++i) {
2293                         if (!flow->frxq[i].ibv_flow)
2294                                 continue;
2295                         claim_zero(mlx5_glue->destroy_flow
2296                                    (flow->frxq[i].ibv_flow));
2297                         flow->frxq[i].ibv_flow = NULL;
2298                         mlx5_hrxq_release(dev, flow->frxq[i].hrxq);
2299                         flow->frxq[i].hrxq = NULL;
2300                 }
2301                 DRV_LOG(DEBUG, "port %u flow %p removed", dev->data->port_id,
2302                         (void *)flow);
2303         }
2304 }
2305
2306 /**
2307  * Add all flows.
2308  *
2309  * @param dev
2310  *   Pointer to Ethernet device.
2311  * @param list
2312  *   Pointer to a TAILQ flow list.
2313  *
2314  * @return
2315  *   0 on success, a negative errno value otherwise and rte_errno is set.
2316  */
2317 int
2318 mlx5_flow_start(struct rte_eth_dev *dev, struct mlx5_flows *list)
2319 {
2320         struct priv *priv = dev->data->dev_private;
2321         struct rte_flow *flow;
2322
2323         TAILQ_FOREACH(flow, list, next) {
2324                 unsigned int i;
2325
2326                 if (flow->drop) {
2327                         flow->frxq[HASH_RXQ_ETH].ibv_flow =
2328                                 mlx5_glue->create_flow
2329                                 (priv->flow_drop_queue->qp,
2330                                  flow->frxq[HASH_RXQ_ETH].ibv_attr);
2331                         if (!flow->frxq[HASH_RXQ_ETH].ibv_flow) {
2332                                 DRV_LOG(DEBUG,
2333                                         "port %u flow %p cannot be applied",
2334                                         dev->data->port_id, (void *)flow);
2335                                 rte_errno = EINVAL;
2336                                 return -rte_errno;
2337                         }
2338                         DRV_LOG(DEBUG, "port %u flow %p applied",
2339                                 dev->data->port_id, (void *)flow);
2340                         /* Next flow. */
2341                         continue;
2342                 }
2343                 for (i = 0; i != hash_rxq_init_n; ++i) {
2344                         if (!flow->frxq[i].ibv_attr)
2345                                 continue;
2346                         flow->frxq[i].hrxq =
2347                                 mlx5_hrxq_get(dev, flow->rss_conf.rss_key,
2348                                               flow->rss_conf.rss_key_len,
2349                                               hash_rxq_init[i].hash_fields,
2350                                               (*flow->queues),
2351                                               flow->queues_n);
2352                         if (flow->frxq[i].hrxq)
2353                                 goto flow_create;
2354                         flow->frxq[i].hrxq =
2355                                 mlx5_hrxq_new(dev, flow->rss_conf.rss_key,
2356                                               flow->rss_conf.rss_key_len,
2357                                               hash_rxq_init[i].hash_fields,
2358                                               (*flow->queues),
2359                                               flow->queues_n);
2360                         if (!flow->frxq[i].hrxq) {
2361                                 DRV_LOG(DEBUG,
2362                                         "port %u flow %p cannot be applied",
2363                                         dev->data->port_id, (void *)flow);
2364                                 rte_errno = EINVAL;
2365                                 return -rte_errno;
2366                         }
2367 flow_create:
2368                         flow->frxq[i].ibv_flow =
2369                                 mlx5_glue->create_flow(flow->frxq[i].hrxq->qp,
2370                                                        flow->frxq[i].ibv_attr);
2371                         if (!flow->frxq[i].ibv_flow) {
2372                                 DRV_LOG(DEBUG,
2373                                         "port %u flow %p cannot be applied",
2374                                         dev->data->port_id, (void *)flow);
2375                                 rte_errno = EINVAL;
2376                                 return -rte_errno;
2377                         }
2378                         DRV_LOG(DEBUG, "port %u flow %p applied",
2379                                 dev->data->port_id, (void *)flow);
2380                 }
2381                 if (!flow->mark)
2382                         continue;
2383                 for (i = 0; i != flow->queues_n; ++i)
2384                         (*priv->rxqs)[(*flow->queues)[i]]->mark = 1;
2385         }
2386         return 0;
2387 }
2388
2389 /**
2390  * Verify the flow list is empty
2391  *
2392  * @param dev
2393  *  Pointer to Ethernet device.
2394  *
2395  * @return the number of flows not released.
2396  */
2397 int
2398 mlx5_flow_verify(struct rte_eth_dev *dev)
2399 {
2400         struct priv *priv = dev->data->dev_private;
2401         struct rte_flow *flow;
2402         int ret = 0;
2403
2404         TAILQ_FOREACH(flow, &priv->flows, next) {
2405                 DRV_LOG(DEBUG, "port %u flow %p still referenced",
2406                         dev->data->port_id, (void *)flow);
2407                 ++ret;
2408         }
2409         return ret;
2410 }
2411
2412 /**
2413  * Enable a control flow configured from the control plane.
2414  *
2415  * @param dev
2416  *   Pointer to Ethernet device.
2417  * @param eth_spec
2418  *   An Ethernet flow spec to apply.
2419  * @param eth_mask
2420  *   An Ethernet flow mask to apply.
2421  * @param vlan_spec
2422  *   A VLAN flow spec to apply.
2423  * @param vlan_mask
2424  *   A VLAN flow mask to apply.
2425  *
2426  * @return
2427  *   0 on success, a negative errno value otherwise and rte_errno is set.
2428  */
2429 int
2430 mlx5_ctrl_flow_vlan(struct rte_eth_dev *dev,
2431                     struct rte_flow_item_eth *eth_spec,
2432                     struct rte_flow_item_eth *eth_mask,
2433                     struct rte_flow_item_vlan *vlan_spec,
2434                     struct rte_flow_item_vlan *vlan_mask)
2435 {
2436         struct priv *priv = dev->data->dev_private;
2437         const struct rte_flow_attr attr = {
2438                 .ingress = 1,
2439                 .priority = MLX5_CTRL_FLOW_PRIORITY,
2440         };
2441         struct rte_flow_item items[] = {
2442                 {
2443                         .type = RTE_FLOW_ITEM_TYPE_ETH,
2444                         .spec = eth_spec,
2445                         .last = NULL,
2446                         .mask = eth_mask,
2447                 },
2448                 {
2449                         .type = (vlan_spec) ? RTE_FLOW_ITEM_TYPE_VLAN :
2450                                 RTE_FLOW_ITEM_TYPE_END,
2451                         .spec = vlan_spec,
2452                         .last = NULL,
2453                         .mask = vlan_mask,
2454                 },
2455                 {
2456                         .type = RTE_FLOW_ITEM_TYPE_END,
2457                 },
2458         };
2459         struct rte_flow_action actions[] = {
2460                 {
2461                         .type = RTE_FLOW_ACTION_TYPE_RSS,
2462                 },
2463                 {
2464                         .type = RTE_FLOW_ACTION_TYPE_END,
2465                 },
2466         };
2467         struct rte_flow *flow;
2468         struct rte_flow_error error;
2469         unsigned int i;
2470         union {
2471                 struct rte_flow_action_rss rss;
2472                 struct {
2473                         const struct rte_eth_rss_conf *rss_conf;
2474                         uint16_t num;
2475                         uint16_t queue[RTE_MAX_QUEUES_PER_PORT];
2476                 } local;
2477         } action_rss;
2478
2479         if (!priv->reta_idx_n) {
2480                 rte_errno = EINVAL;
2481                 return -rte_errno;
2482         }
2483         for (i = 0; i != priv->reta_idx_n; ++i)
2484                 action_rss.local.queue[i] = (*priv->reta_idx)[i];
2485         action_rss.local.rss_conf = &priv->rss_conf;
2486         action_rss.local.num = priv->reta_idx_n;
2487         actions[0].conf = (const void *)&action_rss.rss;
2488         flow = mlx5_flow_list_create(dev, &priv->ctrl_flows, &attr, items,
2489                                      actions, &error);
2490         if (!flow)
2491                 return -rte_errno;
2492         return 0;
2493 }
2494
2495 /**
2496  * Enable a flow control configured from the control plane.
2497  *
2498  * @param dev
2499  *   Pointer to Ethernet device.
2500  * @param eth_spec
2501  *   An Ethernet flow spec to apply.
2502  * @param eth_mask
2503  *   An Ethernet flow mask to apply.
2504  *
2505  * @return
2506  *   0 on success, a negative errno value otherwise and rte_errno is set.
2507  */
2508 int
2509 mlx5_ctrl_flow(struct rte_eth_dev *dev,
2510                struct rte_flow_item_eth *eth_spec,
2511                struct rte_flow_item_eth *eth_mask)
2512 {
2513         return mlx5_ctrl_flow_vlan(dev, eth_spec, eth_mask, NULL, NULL);
2514 }
2515
2516 /**
2517  * Destroy a flow.
2518  *
2519  * @see rte_flow_destroy()
2520  * @see rte_flow_ops
2521  */
2522 int
2523 mlx5_flow_destroy(struct rte_eth_dev *dev,
2524                   struct rte_flow *flow,
2525                   struct rte_flow_error *error __rte_unused)
2526 {
2527         struct priv *priv = dev->data->dev_private;
2528
2529         mlx5_flow_list_destroy(dev, &priv->flows, flow);
2530         return 0;
2531 }
2532
2533 /**
2534  * Destroy all flows.
2535  *
2536  * @see rte_flow_flush()
2537  * @see rte_flow_ops
2538  */
2539 int
2540 mlx5_flow_flush(struct rte_eth_dev *dev,
2541                 struct rte_flow_error *error __rte_unused)
2542 {
2543         struct priv *priv = dev->data->dev_private;
2544
2545         mlx5_flow_list_flush(dev, &priv->flows);
2546         return 0;
2547 }
2548
2549 #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT
2550 /**
2551  * Query flow counter.
2552  *
2553  * @param cs
2554  *   the counter set.
2555  * @param counter_value
2556  *   returned data from the counter.
2557  *
2558  * @return
2559  *   0 on success, a negative errno value otherwise and rte_errno is set.
2560  */
2561 static int
2562 mlx5_flow_query_count(struct ibv_counter_set *cs,
2563                       struct mlx5_flow_counter_stats *counter_stats,
2564                       struct rte_flow_query_count *query_count,
2565                       struct rte_flow_error *error)
2566 {
2567         uint64_t counters[2];
2568         struct ibv_query_counter_set_attr query_cs_attr = {
2569                 .cs = cs,
2570                 .query_flags = IBV_COUNTER_SET_FORCE_UPDATE,
2571         };
2572         struct ibv_counter_set_data query_out = {
2573                 .out = counters,
2574                 .outlen = 2 * sizeof(uint64_t),
2575         };
2576         int err = mlx5_glue->query_counter_set(&query_cs_attr, &query_out);
2577
2578         if (err)
2579                 return rte_flow_error_set(error, err,
2580                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2581                                           NULL,
2582                                           "cannot read counter");
2583         query_count->hits_set = 1;
2584         query_count->bytes_set = 1;
2585         query_count->hits = counters[0] - counter_stats->hits;
2586         query_count->bytes = counters[1] - counter_stats->bytes;
2587         if (query_count->reset) {
2588                 counter_stats->hits = counters[0];
2589                 counter_stats->bytes = counters[1];
2590         }
2591         return 0;
2592 }
2593
2594 /**
2595  * Query a flows.
2596  *
2597  * @see rte_flow_query()
2598  * @see rte_flow_ops
2599  */
2600 int
2601 mlx5_flow_query(struct rte_eth_dev *dev __rte_unused,
2602                 struct rte_flow *flow,
2603                 enum rte_flow_action_type action __rte_unused,
2604                 void *data,
2605                 struct rte_flow_error *error)
2606 {
2607         if (flow->cs) {
2608                 int ret;
2609
2610                 ret = mlx5_flow_query_count(flow->cs,
2611                                             &flow->counter_stats,
2612                                             (struct rte_flow_query_count *)data,
2613                                             error);
2614                 if (ret)
2615                         return ret;
2616         } else {
2617                 return rte_flow_error_set(error, EINVAL,
2618                                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2619                                           NULL,
2620                                           "no counter found for flow");
2621         }
2622         return 0;
2623 }
2624 #endif
2625
2626 /**
2627  * Isolated mode.
2628  *
2629  * @see rte_flow_isolate()
2630  * @see rte_flow_ops
2631  */
2632 int
2633 mlx5_flow_isolate(struct rte_eth_dev *dev,
2634                   int enable,
2635                   struct rte_flow_error *error)
2636 {
2637         struct priv *priv = dev->data->dev_private;
2638
2639         if (dev->data->dev_started) {
2640                 rte_flow_error_set(error, EBUSY,
2641                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
2642                                    NULL,
2643                                    "port must be stopped first");
2644                 return -rte_errno;
2645         }
2646         priv->isolated = !!enable;
2647         if (enable)
2648                 priv->dev->dev_ops = &mlx5_dev_ops_isolate;
2649         else
2650                 priv->dev->dev_ops = &mlx5_dev_ops;
2651         return 0;
2652 }
2653
2654 /**
2655  * Convert a flow director filter to a generic flow.
2656  *
2657  * @param dev
2658  *   Pointer to Ethernet device.
2659  * @param fdir_filter
2660  *   Flow director filter to add.
2661  * @param attributes
2662  *   Generic flow parameters structure.
2663  *
2664  * @return
2665  *   0 on success, a negative errno value otherwise and rte_errno is set.
2666  */
2667 static int
2668 mlx5_fdir_filter_convert(struct rte_eth_dev *dev,
2669                          const struct rte_eth_fdir_filter *fdir_filter,
2670                          struct mlx5_fdir *attributes)
2671 {
2672         struct priv *priv = dev->data->dev_private;
2673         const struct rte_eth_fdir_input *input = &fdir_filter->input;
2674         const struct rte_eth_fdir_masks *mask =
2675                 &dev->data->dev_conf.fdir_conf.mask;
2676
2677         /* Validate queue number. */
2678         if (fdir_filter->action.rx_queue >= priv->rxqs_n) {
2679                 DRV_LOG(ERR, "port %u invalid queue number %d",
2680                         dev->data->port_id, fdir_filter->action.rx_queue);
2681                 rte_errno = EINVAL;
2682                 return -rte_errno;
2683         }
2684         attributes->attr.ingress = 1;
2685         attributes->items[0] = (struct rte_flow_item) {
2686                 .type = RTE_FLOW_ITEM_TYPE_ETH,
2687                 .spec = &attributes->l2,
2688                 .mask = &attributes->l2_mask,
2689         };
2690         switch (fdir_filter->action.behavior) {
2691         case RTE_ETH_FDIR_ACCEPT:
2692                 attributes->actions[0] = (struct rte_flow_action){
2693                         .type = RTE_FLOW_ACTION_TYPE_QUEUE,
2694                         .conf = &attributes->queue,
2695                 };
2696                 break;
2697         case RTE_ETH_FDIR_REJECT:
2698                 attributes->actions[0] = (struct rte_flow_action){
2699                         .type = RTE_FLOW_ACTION_TYPE_DROP,
2700                 };
2701                 break;
2702         default:
2703                 DRV_LOG(ERR, "port %u invalid behavior %d",
2704                         dev->data->port_id,
2705                         fdir_filter->action.behavior);
2706                 rte_errno = ENOTSUP;
2707                 return -rte_errno;
2708         }
2709         attributes->queue.index = fdir_filter->action.rx_queue;
2710         /* Handle L3. */
2711         switch (fdir_filter->input.flow_type) {
2712         case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
2713         case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
2714         case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
2715                 attributes->l3.ipv4.hdr = (struct ipv4_hdr){
2716                         .src_addr = input->flow.ip4_flow.src_ip,
2717                         .dst_addr = input->flow.ip4_flow.dst_ip,
2718                         .time_to_live = input->flow.ip4_flow.ttl,
2719                         .type_of_service = input->flow.ip4_flow.tos,
2720                         .next_proto_id = input->flow.ip4_flow.proto,
2721                 };
2722                 attributes->l3_mask.ipv4.hdr = (struct ipv4_hdr){
2723                         .src_addr = mask->ipv4_mask.src_ip,
2724                         .dst_addr = mask->ipv4_mask.dst_ip,
2725                         .time_to_live = mask->ipv4_mask.ttl,
2726                         .type_of_service = mask->ipv4_mask.tos,
2727                         .next_proto_id = mask->ipv4_mask.proto,
2728                 };
2729                 attributes->items[1] = (struct rte_flow_item){
2730                         .type = RTE_FLOW_ITEM_TYPE_IPV4,
2731                         .spec = &attributes->l3,
2732                         .mask = &attributes->l3_mask,
2733                 };
2734                 break;
2735         case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
2736         case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
2737         case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
2738                 attributes->l3.ipv6.hdr = (struct ipv6_hdr){
2739                         .hop_limits = input->flow.ipv6_flow.hop_limits,
2740                         .proto = input->flow.ipv6_flow.proto,
2741                 };
2742
2743                 memcpy(attributes->l3.ipv6.hdr.src_addr,
2744                        input->flow.ipv6_flow.src_ip,
2745                        RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
2746                 memcpy(attributes->l3.ipv6.hdr.dst_addr,
2747                        input->flow.ipv6_flow.dst_ip,
2748                        RTE_DIM(attributes->l3.ipv6.hdr.src_addr));
2749                 memcpy(attributes->l3_mask.ipv6.hdr.src_addr,
2750                        mask->ipv6_mask.src_ip,
2751                        RTE_DIM(attributes->l3_mask.ipv6.hdr.src_addr));
2752                 memcpy(attributes->l3_mask.ipv6.hdr.dst_addr,
2753                        mask->ipv6_mask.dst_ip,
2754                        RTE_DIM(attributes->l3_mask.ipv6.hdr.src_addr));
2755                 attributes->items[1] = (struct rte_flow_item){
2756                         .type = RTE_FLOW_ITEM_TYPE_IPV6,
2757                         .spec = &attributes->l3,
2758                         .mask = &attributes->l3_mask,
2759                 };
2760                 break;
2761         default:
2762                 DRV_LOG(ERR, "port %u invalid flow type%d",
2763                         dev->data->port_id, fdir_filter->input.flow_type);
2764                 rte_errno = ENOTSUP;
2765                 return -rte_errno;
2766         }
2767         /* Handle L4. */
2768         switch (fdir_filter->input.flow_type) {
2769         case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
2770                 attributes->l4.udp.hdr = (struct udp_hdr){
2771                         .src_port = input->flow.udp4_flow.src_port,
2772                         .dst_port = input->flow.udp4_flow.dst_port,
2773                 };
2774                 attributes->l4_mask.udp.hdr = (struct udp_hdr){
2775                         .src_port = mask->src_port_mask,
2776                         .dst_port = mask->dst_port_mask,
2777                 };
2778                 attributes->items[2] = (struct rte_flow_item){
2779                         .type = RTE_FLOW_ITEM_TYPE_UDP,
2780                         .spec = &attributes->l4,
2781                         .mask = &attributes->l4_mask,
2782                 };
2783                 break;
2784         case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
2785                 attributes->l4.tcp.hdr = (struct tcp_hdr){
2786                         .src_port = input->flow.tcp4_flow.src_port,
2787                         .dst_port = input->flow.tcp4_flow.dst_port,
2788                 };
2789                 attributes->l4_mask.tcp.hdr = (struct tcp_hdr){
2790                         .src_port = mask->src_port_mask,
2791                         .dst_port = mask->dst_port_mask,
2792                 };
2793                 attributes->items[2] = (struct rte_flow_item){
2794                         .type = RTE_FLOW_ITEM_TYPE_TCP,
2795                         .spec = &attributes->l4,
2796                         .mask = &attributes->l4_mask,
2797                 };
2798                 break;
2799         case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
2800                 attributes->l4.udp.hdr = (struct udp_hdr){
2801                         .src_port = input->flow.udp6_flow.src_port,
2802                         .dst_port = input->flow.udp6_flow.dst_port,
2803                 };
2804                 attributes->l4_mask.udp.hdr = (struct udp_hdr){
2805                         .src_port = mask->src_port_mask,
2806                         .dst_port = mask->dst_port_mask,
2807                 };
2808                 attributes->items[2] = (struct rte_flow_item){
2809                         .type = RTE_FLOW_ITEM_TYPE_UDP,
2810                         .spec = &attributes->l4,
2811                         .mask = &attributes->l4_mask,
2812                 };
2813                 break;
2814         case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
2815                 attributes->l4.tcp.hdr = (struct tcp_hdr){
2816                         .src_port = input->flow.tcp6_flow.src_port,
2817                         .dst_port = input->flow.tcp6_flow.dst_port,
2818                 };
2819                 attributes->l4_mask.tcp.hdr = (struct tcp_hdr){
2820                         .src_port = mask->src_port_mask,
2821                         .dst_port = mask->dst_port_mask,
2822                 };
2823                 attributes->items[2] = (struct rte_flow_item){
2824                         .type = RTE_FLOW_ITEM_TYPE_TCP,
2825                         .spec = &attributes->l4,
2826                         .mask = &attributes->l4_mask,
2827                 };
2828                 break;
2829         case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER:
2830         case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER:
2831                 break;
2832         default:
2833                 DRV_LOG(ERR, "port %u invalid flow type%d",
2834                         dev->data->port_id, fdir_filter->input.flow_type);
2835                 rte_errno = ENOTSUP;
2836                 return -rte_errno;
2837         }
2838         return 0;
2839 }
2840
2841 /**
2842  * Add new flow director filter and store it in list.
2843  *
2844  * @param dev
2845  *   Pointer to Ethernet device.
2846  * @param fdir_filter
2847  *   Flow director filter to add.
2848  *
2849  * @return
2850  *   0 on success, a negative errno value otherwise and rte_errno is set.
2851  */
2852 static int
2853 mlx5_fdir_filter_add(struct rte_eth_dev *dev,
2854                      const struct rte_eth_fdir_filter *fdir_filter)
2855 {
2856         struct priv *priv = dev->data->dev_private;
2857         struct mlx5_fdir attributes = {
2858                 .attr.group = 0,
2859                 .l2_mask = {
2860                         .dst.addr_bytes = "\x00\x00\x00\x00\x00\x00",
2861                         .src.addr_bytes = "\x00\x00\x00\x00\x00\x00",
2862                         .type = 0,
2863                 },
2864         };
2865         struct mlx5_flow_parse parser = {
2866                 .layer = HASH_RXQ_ETH,
2867         };
2868         struct rte_flow_error error;
2869         struct rte_flow *flow;
2870         int ret;
2871
2872         ret = mlx5_fdir_filter_convert(dev, fdir_filter, &attributes);
2873         if (ret)
2874                 return ret;
2875         ret = mlx5_flow_convert(dev, &attributes.attr, attributes.items,
2876                                 attributes.actions, &error, &parser);
2877         if (ret)
2878                 return ret;
2879         flow = mlx5_flow_list_create(dev, &priv->flows, &attributes.attr,
2880                                      attributes.items, attributes.actions,
2881                                      &error);
2882         if (flow) {
2883                 DRV_LOG(DEBUG, "port %u FDIR created %p", dev->data->port_id,
2884                         (void *)flow);
2885                 return 0;
2886         }
2887         return -rte_errno;
2888 }
2889
2890 /**
2891  * Delete specific filter.
2892  *
2893  * @param dev
2894  *   Pointer to Ethernet device.
2895  * @param fdir_filter
2896  *   Filter to be deleted.
2897  *
2898  * @return
2899  *   0 on success, a negative errno value otherwise and rte_errno is set.
2900  */
2901 static int
2902 mlx5_fdir_filter_delete(struct rte_eth_dev *dev,
2903                         const struct rte_eth_fdir_filter *fdir_filter)
2904 {
2905         struct priv *priv = dev->data->dev_private;
2906         struct mlx5_fdir attributes = {
2907                 .attr.group = 0,
2908         };
2909         struct mlx5_flow_parse parser = {
2910                 .create = 1,
2911                 .layer = HASH_RXQ_ETH,
2912         };
2913         struct rte_flow_error error;
2914         struct rte_flow *flow;
2915         unsigned int i;
2916         int ret;
2917
2918         ret = mlx5_fdir_filter_convert(dev, fdir_filter, &attributes);
2919         if (ret)
2920                 return ret;
2921         ret = mlx5_flow_convert(dev, &attributes.attr, attributes.items,
2922                                 attributes.actions, &error, &parser);
2923         if (ret)
2924                 goto exit;
2925         /*
2926          * Special case for drop action which is only set in the
2927          * specifications when the flow is created.  In this situation the
2928          * drop specification is missing.
2929          */
2930         if (parser.drop) {
2931                 struct ibv_flow_spec_action_drop *drop;
2932
2933                 drop = (void *)((uintptr_t)parser.queue[HASH_RXQ_ETH].ibv_attr +
2934                                 parser.queue[HASH_RXQ_ETH].offset);
2935                 *drop = (struct ibv_flow_spec_action_drop){
2936                         .type = IBV_FLOW_SPEC_ACTION_DROP,
2937                         .size = sizeof(struct ibv_flow_spec_action_drop),
2938                 };
2939                 parser.queue[HASH_RXQ_ETH].ibv_attr->num_of_specs++;
2940         }
2941         TAILQ_FOREACH(flow, &priv->flows, next) {
2942                 struct ibv_flow_attr *attr;
2943                 struct ibv_spec_header *attr_h;
2944                 void *spec;
2945                 struct ibv_flow_attr *flow_attr;
2946                 struct ibv_spec_header *flow_h;
2947                 void *flow_spec;
2948                 unsigned int specs_n;
2949
2950                 attr = parser.queue[HASH_RXQ_ETH].ibv_attr;
2951                 flow_attr = flow->frxq[HASH_RXQ_ETH].ibv_attr;
2952                 /* Compare first the attributes. */
2953                 if (memcmp(attr, flow_attr, sizeof(struct ibv_flow_attr)))
2954                         continue;
2955                 if (attr->num_of_specs == 0)
2956                         continue;
2957                 spec = (void *)((uintptr_t)attr +
2958                                 sizeof(struct ibv_flow_attr));
2959                 flow_spec = (void *)((uintptr_t)flow_attr +
2960                                      sizeof(struct ibv_flow_attr));
2961                 specs_n = RTE_MIN(attr->num_of_specs, flow_attr->num_of_specs);
2962                 for (i = 0; i != specs_n; ++i) {
2963                         attr_h = spec;
2964                         flow_h = flow_spec;
2965                         if (memcmp(spec, flow_spec,
2966                                    RTE_MIN(attr_h->size, flow_h->size)))
2967                                 goto wrong_flow;
2968                         spec = (void *)((uintptr_t)spec + attr_h->size);
2969                         flow_spec = (void *)((uintptr_t)flow_spec +
2970                                              flow_h->size);
2971                 }
2972                 /* At this point, the flow match. */
2973                 break;
2974 wrong_flow:
2975                 /* The flow does not match. */
2976                 continue;
2977         }
2978         ret = rte_errno; /* Save rte_errno before cleanup. */
2979         if (flow)
2980                 mlx5_flow_list_destroy(dev, &priv->flows, flow);
2981 exit:
2982         for (i = 0; i != hash_rxq_init_n; ++i) {
2983                 if (parser.queue[i].ibv_attr)
2984                         rte_free(parser.queue[i].ibv_attr);
2985         }
2986         rte_errno = ret; /* Restore rte_errno. */
2987         return -rte_errno;
2988 }
2989
2990 /**
2991  * Update queue for specific filter.
2992  *
2993  * @param dev
2994  *   Pointer to Ethernet device.
2995  * @param fdir_filter
2996  *   Filter to be updated.
2997  *
2998  * @return
2999  *   0 on success, a negative errno value otherwise and rte_errno is set.
3000  */
3001 static int
3002 mlx5_fdir_filter_update(struct rte_eth_dev *dev,
3003                         const struct rte_eth_fdir_filter *fdir_filter)
3004 {
3005         int ret;
3006
3007         ret = mlx5_fdir_filter_delete(dev, fdir_filter);
3008         if (ret)
3009                 return ret;
3010         return mlx5_fdir_filter_add(dev, fdir_filter);
3011 }
3012
3013 /**
3014  * Flush all filters.
3015  *
3016  * @param dev
3017  *   Pointer to Ethernet device.
3018  */
3019 static void
3020 mlx5_fdir_filter_flush(struct rte_eth_dev *dev)
3021 {
3022         struct priv *priv = dev->data->dev_private;
3023
3024         mlx5_flow_list_flush(dev, &priv->flows);
3025 }
3026
3027 /**
3028  * Get flow director information.
3029  *
3030  * @param dev
3031  *   Pointer to Ethernet device.
3032  * @param[out] fdir_info
3033  *   Resulting flow director information.
3034  */
3035 static void
3036 mlx5_fdir_info_get(struct rte_eth_dev *dev, struct rte_eth_fdir_info *fdir_info)
3037 {
3038         struct priv *priv = dev->data->dev_private;
3039         struct rte_eth_fdir_masks *mask =
3040                 &priv->dev->data->dev_conf.fdir_conf.mask;
3041
3042         fdir_info->mode = priv->dev->data->dev_conf.fdir_conf.mode;
3043         fdir_info->guarant_spc = 0;
3044         rte_memcpy(&fdir_info->mask, mask, sizeof(fdir_info->mask));
3045         fdir_info->max_flexpayload = 0;
3046         fdir_info->flow_types_mask[0] = 0;
3047         fdir_info->flex_payload_unit = 0;
3048         fdir_info->max_flex_payload_segment_num = 0;
3049         fdir_info->flex_payload_limit = 0;
3050         memset(&fdir_info->flex_conf, 0, sizeof(fdir_info->flex_conf));
3051 }
3052
3053 /**
3054  * Deal with flow director operations.
3055  *
3056  * @param dev
3057  *   Pointer to Ethernet device.
3058  * @param filter_op
3059  *   Operation to perform.
3060  * @param arg
3061  *   Pointer to operation-specific structure.
3062  *
3063  * @return
3064  *   0 on success, a negative errno value otherwise and rte_errno is set.
3065  */
3066 static int
3067 mlx5_fdir_ctrl_func(struct rte_eth_dev *dev, enum rte_filter_op filter_op,
3068                     void *arg)
3069 {
3070         struct priv *priv = dev->data->dev_private;
3071         enum rte_fdir_mode fdir_mode =
3072                 priv->dev->data->dev_conf.fdir_conf.mode;
3073
3074         if (filter_op == RTE_ETH_FILTER_NOP)
3075                 return 0;
3076         if (fdir_mode != RTE_FDIR_MODE_PERFECT &&
3077             fdir_mode != RTE_FDIR_MODE_PERFECT_MAC_VLAN) {
3078                 DRV_LOG(ERR, "port %u flow director mode %d not supported",
3079                         dev->data->port_id, fdir_mode);
3080                 rte_errno = EINVAL;
3081                 return -rte_errno;
3082         }
3083         switch (filter_op) {
3084         case RTE_ETH_FILTER_ADD:
3085                 return mlx5_fdir_filter_add(dev, arg);
3086         case RTE_ETH_FILTER_UPDATE:
3087                 return mlx5_fdir_filter_update(dev, arg);
3088         case RTE_ETH_FILTER_DELETE:
3089                 return mlx5_fdir_filter_delete(dev, arg);
3090         case RTE_ETH_FILTER_FLUSH:
3091                 mlx5_fdir_filter_flush(dev);
3092                 break;
3093         case RTE_ETH_FILTER_INFO:
3094                 mlx5_fdir_info_get(dev, arg);
3095                 break;
3096         default:
3097                 DRV_LOG(DEBUG, "port %u unknown operation %u",
3098                         dev->data->port_id, filter_op);
3099                 rte_errno = EINVAL;
3100                 return -rte_errno;
3101         }
3102         return 0;
3103 }
3104
3105 /**
3106  * Manage filter operations.
3107  *
3108  * @param dev
3109  *   Pointer to Ethernet device structure.
3110  * @param filter_type
3111  *   Filter type.
3112  * @param filter_op
3113  *   Operation to perform.
3114  * @param arg
3115  *   Pointer to operation-specific structure.
3116  *
3117  * @return
3118  *   0 on success, a negative errno value otherwise and rte_errno is set.
3119  */
3120 int
3121 mlx5_dev_filter_ctrl(struct rte_eth_dev *dev,
3122                      enum rte_filter_type filter_type,
3123                      enum rte_filter_op filter_op,
3124                      void *arg)
3125 {
3126         switch (filter_type) {
3127         case RTE_ETH_FILTER_GENERIC:
3128                 if (filter_op != RTE_ETH_FILTER_GET) {
3129                         rte_errno = EINVAL;
3130                         return -rte_errno;
3131                 }
3132                 *(const void **)arg = &mlx5_flow_ops;
3133                 return 0;
3134         case RTE_ETH_FILTER_FDIR:
3135                 return mlx5_fdir_ctrl_func(dev, filter_op, arg);
3136         default:
3137                 DRV_LOG(ERR, "port %u filter type (%d) not supported",
3138                         dev->data->port_id, filter_type);
3139                 rte_errno = ENOTSUP;
3140                 return -rte_errno;
3141         }
3142         return 0;
3143 }