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