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